shennian 0.3.1 → 0.3.3
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/publish-build-manifest.json +291 -341
- package/dist/src/agents/codex.js +1 -1
- package/dist/src/agents/command-spec.js +2 -2
- package/dist/src/agents/detect.js +1 -1
- package/dist/src/agents/model-registry/discovery.js +2 -2
- package/dist/src/agents/model-registry/parsers.d.ts +1 -0
- package/dist/src/agents/model-registry/parsers.js +4 -4
- package/dist/src/agents/model-registry/service.js +1 -1
- package/dist/src/agents/native-capabilities.d.ts +10 -0
- package/dist/src/agents/native-capabilities.js +1 -0
- package/dist/src/agents/platform-instructions.js +5 -5
- package/dist/src/agents/runtime-compatibility.d.ts +11 -0
- package/dist/src/agents/runtime-compatibility.js +1 -0
- package/dist/src/agents/workbuddy.d.ts +44 -0
- package/dist/src/agents/workbuddy.js +3 -0
- package/dist/src/commands/daemon.d.ts +1 -0
- package/dist/src/commands/daemon.js +9 -9
- package/dist/src/commands/integration.d.ts +2 -0
- package/dist/src/commands/integration.js +1 -0
- package/dist/src/commands/manager.js +1 -2
- package/dist/src/commands/pair-browser.d.ts +43 -0
- package/dist/src/commands/pair-browser.js +1 -0
- package/dist/src/commands/pair.d.ts +2 -0
- package/dist/src/commands/pair.js +11 -8
- package/dist/src/commands/room.d.ts +13 -0
- package/dist/src/commands/room.js +4 -0
- package/dist/src/commands/upgrade.d.ts +3 -0
- package/dist/src/commands/upgrade.js +1 -1
- package/dist/src/config/index.d.ts +3 -1
- package/dist/src/config/index.js +2 -1
- package/dist/src/daemon-ipc/client.d.ts +8 -0
- package/dist/src/daemon-ipc/client.js +3 -0
- package/dist/src/daemon-ipc/paths.d.ts +7 -0
- package/dist/src/daemon-ipc/paths.js +1 -0
- package/dist/src/daemon-ipc/protocol.d.ts +30 -0
- package/dist/src/daemon-ipc/protocol.js +1 -0
- package/dist/src/daemon-ipc/secret.d.ts +3 -0
- package/dist/src/daemon-ipc/secret.js +3 -0
- package/dist/src/daemon-ipc/server.d.ts +13 -0
- package/dist/src/daemon-ipc/server.js +3 -0
- package/dist/src/index.js +2 -2
- package/dist/src/integrations/claude-room-plugin-lifecycle.d.ts +47 -0
- package/dist/src/integrations/claude-room-plugin-lifecycle.js +1 -0
- package/dist/src/integrations/codex-room-plugin-lifecycle.d.ts +49 -0
- package/dist/src/integrations/codex-room-plugin-lifecycle.js +1 -0
- package/dist/src/integrations/room-plugin-bundles.d.ts +23 -0
- package/dist/src/integrations/room-plugin-bundles.js +1 -0
- package/dist/src/integrations/room-plugin-lifecycle-common.d.ts +17 -0
- package/dist/src/integrations/room-plugin-lifecycle-common.js +1 -0
- package/dist/src/integrations/room-plugin-shared.d.ts +24 -0
- package/dist/src/integrations/room-plugin-shared.js +2 -0
- package/dist/src/integrations/room-session-hook.d.ts +30 -0
- package/dist/src/integrations/room-session-hook.js +2 -0
- package/dist/src/integrations/workbuddy-plugin-bundle.d.ts +15 -0
- package/dist/src/integrations/workbuddy-plugin-bundle.js +1 -0
- package/dist/src/integrations/workbuddy-plugin-lifecycle.d.ts +52 -0
- package/dist/src/integrations/workbuddy-plugin-lifecycle.js +2 -0
- package/dist/src/integrations/workbuddy-session-hook.d.ts +22 -0
- package/dist/src/integrations/workbuddy-session-hook.js +1 -0
- package/dist/src/manager/prompt.d.ts +1 -1
- package/dist/src/manager/prompt.js +1 -1
- package/dist/src/manager/retired-external-channel-compat.d.ts +78 -0
- package/dist/src/manager/retired-external-channel-compat.js +1 -0
- package/dist/src/manager/runtime.d.ts +1 -3
- package/dist/src/manager/runtime.js +7 -7
- package/dist/src/relay/client.d.ts +2 -0
- package/dist/src/relay/client.js +1 -1
- package/dist/src/room/activation-audit.d.ts +15 -0
- package/dist/src/room/activation-audit.js +2 -0
- package/dist/src/room/activation-policy.d.ts +8 -0
- package/dist/src/room/activation-policy.js +1 -0
- package/dist/src/room/activation-service.d.ts +25 -0
- package/dist/src/room/activation-service.js +2 -0
- package/dist/src/room/agent-tool.d.ts +62 -0
- package/dist/src/room/agent-tool.js +1 -0
- package/dist/src/room/attachment-cache.d.ts +40 -0
- package/dist/src/room/attachment-cache.js +2 -0
- package/dist/src/room/attachment-upload.d.ts +20 -0
- package/dist/src/room/attachment-upload.js +1 -0
- package/dist/src/room/authorized-action-coordinator.d.ts +40 -0
- package/dist/src/room/authorized-action-coordinator.js +1 -0
- package/dist/src/room/authorized-action-ipc.d.ts +11 -0
- package/dist/src/room/authorized-action-ipc.js +1 -0
- package/dist/src/room/device-authorization-client.d.ts +49 -0
- package/dist/src/room/device-authorization-client.js +1 -0
- package/dist/src/room/host-session-observation-ipc.d.ts +9 -0
- package/dist/src/room/host-session-observation-ipc.js +1 -0
- package/dist/src/room/host-session-observations.d.ts +54 -0
- package/dist/src/room/host-session-observations.js +2 -0
- package/dist/src/room/invite-bootstrap.d.ts +35 -0
- package/dist/src/room/invite-bootstrap.js +1 -0
- package/dist/src/room/invocation-token-ipc.d.ts +9 -0
- package/dist/src/room/invocation-token-ipc.js +1 -0
- package/dist/src/room/invocation-token.d.ts +53 -0
- package/dist/src/room/invocation-token.js +1 -0
- package/dist/src/room/jsonl-mirror.d.ts +73 -0
- package/dist/src/room/jsonl-mirror.js +6 -0
- package/dist/src/room/managed-room-binding.d.ts +42 -0
- package/dist/src/room/managed-room-binding.js +1 -0
- package/dist/src/room/managed-room-session.d.ts +143 -0
- package/dist/src/room/managed-room-session.js +3 -0
- package/dist/src/room/mirror-sync-service.d.ts +33 -0
- package/dist/src/room/mirror-sync-service.js +1 -0
- package/dist/src/room/operator-ipc.d.ts +11 -0
- package/dist/src/room/operator-ipc.js +1 -0
- package/dist/src/room/pending-authorized-actions.d.ts +69 -0
- package/dist/src/room/pending-authorized-actions.js +3 -0
- package/dist/src/room/room-action-client.d.ts +210 -0
- package/dist/src/room/room-action-client.js +1 -0
- package/dist/src/room/room-action-ipc.d.ts +33 -0
- package/dist/src/room/room-action-ipc.js +1 -0
- package/dist/src/room/room-action-schema.d.ts +3 -0
- package/dist/src/room/room-action-schema.js +1 -0
- package/dist/src/room/room-authorized-action-executor.d.ts +23 -0
- package/dist/src/room/room-authorized-action-executor.js +1 -0
- package/dist/src/room/room-binding-client.d.ts +51 -0
- package/dist/src/room/room-binding-client.js +1 -0
- package/dist/src/room/room-binding-ipc.d.ts +29 -0
- package/dist/src/room/room-binding-ipc.js +1 -0
- package/dist/src/room/session-registry-ipc.d.ts +14 -0
- package/dist/src/room/session-registry-ipc.js +1 -0
- package/dist/src/room/session-registry.d.ts +128 -0
- package/dist/src/room/session-registry.js +2 -0
- package/dist/src/room/tool-schema.d.ts +118 -0
- package/dist/src/room/tool-schema.js +1 -0
- package/dist/src/room/tool-server.d.ts +5 -0
- package/dist/src/room/tool-server.js +3 -0
- package/dist/src/session/handlers/agent-capabilities.d.ts +3 -0
- package/dist/src/session/handlers/agent-capabilities.js +1 -0
- package/dist/src/session/handlers/agent-config.js +1 -1
- package/dist/src/session/handlers/chat.js +2 -2
- package/dist/src/session/handlers/control.js +1 -1
- package/dist/src/session/handlers/fs.d.ts +1 -0
- package/dist/src/session/handlers/fs.js +1 -1
- package/dist/src/session/handlers/room-managed.d.ts +4 -0
- package/dist/src/session/handlers/room-managed.js +1 -0
- package/dist/src/session/manager.d.ts +18 -6
- package/dist/src/session/manager.js +1 -1
- package/dist/src/session/types.d.ts +5 -0
- package/dist/src/upgrade/engine.d.ts +14 -1
- package/dist/src/upgrade/engine.js +2 -2
- package/dist/src/upgrade/scheduler.d.ts +45 -0
- package/dist/src/upgrade/scheduler.js +1 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts +17 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.js +2 -0
- package/node_modules/@shennian/wire/dist/agent-capabilities.js.map +1 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts +41 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.js +3 -0
- package/node_modules/@shennian/wire/dist/agent-workspace.js.map +1 -0
- package/node_modules/@shennian/wire/dist/index.d.ts +3 -1
- package/node_modules/@shennian/wire/dist/index.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/index.js +3 -1
- package/node_modules/@shennian/wire/dist/index.js.map +1 -1
- package/node_modules/@shennian/wire/dist/machine.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/machine.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/methods.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/room.d.ts +112 -0
- package/node_modules/@shennian/wire/dist/room.d.ts.map +1 -0
- package/node_modules/@shennian/wire/dist/room.js +4 -0
- package/node_modules/@shennian/wire/dist/room.js.map +1 -0
- package/node_modules/@shennian/wire/dist/session.d.ts +15 -2
- package/node_modules/@shennian/wire/dist/session.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/session.js +1 -1
- package/node_modules/@shennian/wire/dist/session.js.map +1 -1
- package/package.json +3 -5
- package/dist/scripts/wechat-rpa-confirmation.mjs +0 -5
- package/dist/src/agents/pi-context.d.ts +0 -42
- package/dist/src/agents/pi-context.js +0 -12
- package/dist/src/agents/pi.d.ts +0 -70
- package/dist/src/agents/pi.js +0 -17
- package/dist/src/channels/base.d.ts +0 -144
- package/dist/src/channels/base.js +0 -1
- package/dist/src/channels/registry.d.ts +0 -8
- package/dist/src/channels/registry.js +0 -1
- package/dist/src/channels/reply-split.d.ts +0 -1
- package/dist/src/channels/reply-split.js +0 -10
- package/dist/src/channels/runtime.d.ts +0 -138
- package/dist/src/channels/runtime.js +0 -5
- package/dist/src/channels/secret-registry.d.ts +0 -35
- package/dist/src/channels/secret-registry.js +0 -1
- package/dist/src/channels/websocket.d.ts +0 -55
- package/dist/src/channels/websocket.js +0 -8
- package/dist/src/channels/wechat-channel/anchor.d.ts +0 -10
- package/dist/src/channels/wechat-channel/anchor.js +0 -1
- package/dist/src/channels/wechat-channel/automation-lane.d.ts +0 -35
- package/dist/src/channels/wechat-channel/automation-lane.js +0 -2
- package/dist/src/channels/wechat-channel/client.d.ts +0 -283
- package/dist/src/channels/wechat-channel/client.js +0 -1
- package/dist/src/channels/wechat-channel/cooldown.d.ts +0 -21
- package/dist/src/channels/wechat-channel/cooldown.js +0 -1
- package/dist/src/channels/wechat-channel/core/fixture-compare.d.ts +0 -52
- package/dist/src/channels/wechat-channel/core/fixture-compare.js +0 -1
- package/dist/src/channels/wechat-channel/core/media-action-plan.d.ts +0 -3
- package/dist/src/channels/wechat-channel/core/media-action-plan.js +0 -1
- package/dist/src/channels/wechat-channel/core/schema.d.ts +0 -67
- package/dist/src/channels/wechat-channel/core/schema.js +0 -1
- package/dist/src/channels/wechat-channel/core/trace-comparator.d.ts +0 -28
- package/dist/src/channels/wechat-channel/core/trace-comparator.js +0 -1
- package/dist/src/channels/wechat-channel/fingerprint.d.ts +0 -31
- package/dist/src/channels/wechat-channel/fingerprint.js +0 -1
- package/dist/src/channels/wechat-channel/helper-assets.d.ts +0 -103
- package/dist/src/channels/wechat-channel/helper-assets.js +0 -1
- package/dist/src/channels/wechat-channel/helper-client.d.ts +0 -87
- package/dist/src/channels/wechat-channel/helper-client.js +0 -3
- package/dist/src/channels/wechat-channel/helper-protocol.d.ts +0 -122
- package/dist/src/channels/wechat-channel/helper-protocol.js +0 -1
- package/dist/src/channels/wechat-channel/human-coordination.d.ts +0 -25
- package/dist/src/channels/wechat-channel/human-coordination.js +0 -1
- package/dist/src/channels/wechat-channel/index.d.ts +0 -21
- package/dist/src/channels/wechat-channel/index.js +0 -1
- package/dist/src/channels/wechat-channel/ledger.d.ts +0 -48
- package/dist/src/channels/wechat-channel/ledger.js +0 -2
- package/dist/src/channels/wechat-channel/media-cache-resolver.d.ts +0 -42
- package/dist/src/channels/wechat-channel/media-cache-resolver.js +0 -1
- package/dist/src/channels/wechat-channel/media-resolver.d.ts +0 -186
- package/dist/src/channels/wechat-channel/media-resolver.js +0 -1
- package/dist/src/channels/wechat-channel/message-key.d.ts +0 -19
- package/dist/src/channels/wechat-channel/message-key.js +0 -1
- package/dist/src/channels/wechat-channel/observer.d.ts +0 -171
- package/dist/src/channels/wechat-channel/observer.js +0 -7
- package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +0 -96
- package/dist/src/channels/wechat-channel/outbound-ledger.js +0 -2
- package/dist/src/channels/wechat-channel/outbound-sender.d.ts +0 -74
- package/dist/src/channels/wechat-channel/outbound-sender.js +0 -1
- package/dist/src/channels/wechat-channel/pacing.d.ts +0 -3
- package/dist/src/channels/wechat-channel/pacing.js +0 -1
- package/dist/src/channels/wechat-channel/preflight.d.ts +0 -46
- package/dist/src/channels/wechat-channel/preflight.js +0 -1
- package/dist/src/channels/wechat-channel/runner.d.ts +0 -43
- package/dist/src/channels/wechat-channel/runner.js +0 -1
- package/dist/src/channels/wechat-channel/runtime.d.ts +0 -50
- package/dist/src/channels/wechat-channel/runtime.js +0 -1
- package/dist/src/channels/wechat-channel/scheduler.d.ts +0 -74
- package/dist/src/channels/wechat-channel/scheduler.js +0 -1
- package/dist/src/channels/wechat-channel/vector-store.d.ts +0 -44
- package/dist/src/channels/wechat-channel/vector-store.js +0 -1
- package/dist/src/channels/wechat-rpa/macos-flow.d.ts +0 -55
- package/dist/src/channels/wechat-rpa/macos-flow.js +0 -1
- package/dist/src/channels/wechat-rpa/macos.d.ts +0 -11
- package/dist/src/channels/wechat-rpa/macos.js +0 -21
- package/dist/src/channels/wechat-rpa/normalizer.d.ts +0 -49
- package/dist/src/channels/wechat-rpa/normalizer.js +0 -7
- package/dist/src/channels/wechat-rpa/product-channel.d.ts +0 -76
- package/dist/src/channels/wechat-rpa/product-channel.js +0 -16
- package/dist/src/channels/wechat-rpa-session-sync.d.ts +0 -26
- package/dist/src/channels/wechat-rpa-session-sync.js +0 -1
- package/dist/src/channels/wechat-rpa.d.ts +0 -104
- package/dist/src/channels/wechat-rpa.js +0 -6
- package/dist/src/channels/wecom.d.ts +0 -51
- package/dist/src/channels/wecom.js +0 -4
- package/dist/src/commands/external-attachments.d.ts +0 -9
- package/dist/src/commands/external-attachments.js +0 -1
- package/dist/src/commands/external.d.ts +0 -2
- package/dist/src/commands/external.js +0 -1
- package/dist/src/commands/helper-runtime-official-download.d.ts +0 -80
- package/dist/src/commands/helper-runtime-official-download.js +0 -1
- package/dist/src/commands/runtime.d.ts +0 -120
- package/dist/src/commands/runtime.js +0 -1
- package/dist/src/commands/wechat/command.d.ts +0 -3
- package/dist/src/commands/wechat/command.js +0 -1
- package/dist/src/commands/wechat/direct.d.ts +0 -14
- package/dist/src/commands/wechat/direct.js +0 -2
- package/dist/src/commands/wechat/doctor.d.ts +0 -2
- package/dist/src/commands/wechat/doctor.js +0 -1
- package/dist/src/commands/wechat/ipc.d.ts +0 -9
- package/dist/src/commands/wechat/ipc.js +0 -1
- package/dist/src/commands/wechat/operations.d.ts +0 -3
- package/dist/src/commands/wechat/operations.js +0 -4
- package/dist/src/commands/wechat/output.d.ts +0 -7
- package/dist/src/commands/wechat/output.js +0 -4
- package/dist/src/commands/wechat/types.d.ts +0 -142
- package/dist/src/commands/wechat/types.js +0 -1
- package/dist/src/commands/wechat/utils.d.ts +0 -16
- package/dist/src/commands/wechat/utils.js +0 -1
- package/dist/src/commands/wechat.d.ts +0 -6
- package/dist/src/commands/wechat.js +0 -1
- package/dist/src/devtools/wechat-channel-action-smoke.d.ts +0 -105
- package/dist/src/devtools/wechat-channel-action-smoke.js +0 -10
- package/dist/src/devtools/wechat-channel-download-report.d.ts +0 -111
- package/dist/src/devtools/wechat-channel-download-report.js +0 -2
- package/dist/src/devtools/wechat-channel-markdown-report.d.ts +0 -6
- package/dist/src/devtools/wechat-channel-markdown-report.js +0 -5
- package/dist/src/devtools/wechat-channel-product-steps.d.ts +0 -9
- package/dist/src/devtools/wechat-channel-product-steps.js +0 -40
- package/dist/src/session/handlers/skills.d.ts +0 -7
- package/dist/src/session/handlers/skills.js +0 -1
- package/dist/src/session/handlers/wechat-helper-runtime.d.ts +0 -33
- package/dist/src/session/handlers/wechat-helper-runtime.js +0 -1
- package/dist/src/skills/registry.d.ts +0 -16
- package/dist/src/skills/registry.js +0 -15
- package/dist/src/skills/setup.d.ts +0 -11
- package/dist/src/skills/setup.js +0 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { RoomActivationMode, RoomMessageView } from '@shennian/wire';
|
|
2
|
+
type FetchLike = typeof fetch;
|
|
3
|
+
type BindingTarget = {
|
|
4
|
+
machineToken: string;
|
|
5
|
+
roomId: string;
|
|
6
|
+
bindingId: string;
|
|
7
|
+
};
|
|
8
|
+
export type RemoteRoomAgentStatus = {
|
|
9
|
+
bindingId: string;
|
|
10
|
+
roomId: string;
|
|
11
|
+
agentIdentityId: string;
|
|
12
|
+
agentMembershipId: string | null;
|
|
13
|
+
status: 'pending_approval' | 'active' | 'paused' | 'detached';
|
|
14
|
+
activationMode: RoomActivationMode;
|
|
15
|
+
lastDeliveredSequence: string;
|
|
16
|
+
lastActivatedSequence: string;
|
|
17
|
+
room: {
|
|
18
|
+
name: string;
|
|
19
|
+
status: string;
|
|
20
|
+
lastSequence: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type RemoteRoomJoinResult = {
|
|
24
|
+
outcome: 'joined' | 'pending_approval';
|
|
25
|
+
room: {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
webUrl: string;
|
|
29
|
+
};
|
|
30
|
+
agentIdentity: {
|
|
31
|
+
id: string;
|
|
32
|
+
displayName: string;
|
|
33
|
+
};
|
|
34
|
+
binding: {
|
|
35
|
+
id: string;
|
|
36
|
+
roomId: string;
|
|
37
|
+
agentIdentityId: string;
|
|
38
|
+
agentMembershipId: string | null;
|
|
39
|
+
status: 'pending_approval' | 'active' | 'paused';
|
|
40
|
+
activationMode: RoomActivationMode;
|
|
41
|
+
};
|
|
42
|
+
joinRequestId?: string;
|
|
43
|
+
idempotent: boolean;
|
|
44
|
+
};
|
|
45
|
+
export type RemoteRoomAttachmentCapability = {
|
|
46
|
+
attachmentId: string;
|
|
47
|
+
roomId: string;
|
|
48
|
+
safeName: string;
|
|
49
|
+
mimeType: string;
|
|
50
|
+
byteSize: string;
|
|
51
|
+
sha256: string;
|
|
52
|
+
downloadUrl: string;
|
|
53
|
+
expiresAt: string;
|
|
54
|
+
};
|
|
55
|
+
export type RemoteRoomAttachmentUpload = {
|
|
56
|
+
attachment: {
|
|
57
|
+
id: string;
|
|
58
|
+
roomId: string;
|
|
59
|
+
name: string;
|
|
60
|
+
mimeType: string;
|
|
61
|
+
byteSize: string;
|
|
62
|
+
sha256: string;
|
|
63
|
+
status: 'pending' | 'uploaded';
|
|
64
|
+
};
|
|
65
|
+
upload: {
|
|
66
|
+
method: 'PUT';
|
|
67
|
+
url: string;
|
|
68
|
+
headers: Record<string, string>;
|
|
69
|
+
expiresAt: string;
|
|
70
|
+
};
|
|
71
|
+
idempotent: boolean;
|
|
72
|
+
};
|
|
73
|
+
export type RemoteRoomCreateResult = {
|
|
74
|
+
outcome: 'created';
|
|
75
|
+
room: {
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
visibility: 'private';
|
|
79
|
+
joinPolicy: 'approval';
|
|
80
|
+
webUrl: string;
|
|
81
|
+
inviteUrl: string;
|
|
82
|
+
};
|
|
83
|
+
agentIdentity: {
|
|
84
|
+
id: string;
|
|
85
|
+
displayName: string;
|
|
86
|
+
};
|
|
87
|
+
binding: {
|
|
88
|
+
id: string;
|
|
89
|
+
roomId: string;
|
|
90
|
+
agentIdentityId: string;
|
|
91
|
+
agentMembershipId: string;
|
|
92
|
+
status: 'active' | 'paused';
|
|
93
|
+
activationMode: RoomActivationMode;
|
|
94
|
+
};
|
|
95
|
+
idempotent: boolean;
|
|
96
|
+
};
|
|
97
|
+
export type RemoteOperatorRoomCreateResult = {
|
|
98
|
+
outcome: 'created';
|
|
99
|
+
room: {
|
|
100
|
+
id: string;
|
|
101
|
+
name: string;
|
|
102
|
+
visibility: 'private';
|
|
103
|
+
joinPolicy: 'approval';
|
|
104
|
+
webUrl: string;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
export declare class RoomActionHttpError extends Error {
|
|
108
|
+
readonly code: string;
|
|
109
|
+
constructor(code: string, message: string);
|
|
110
|
+
}
|
|
111
|
+
export declare class HttpRoomActionClient {
|
|
112
|
+
private readonly fetchImpl;
|
|
113
|
+
private readonly baseUrl;
|
|
114
|
+
constructor(serverUrl: string, fetchImpl?: FetchLike);
|
|
115
|
+
createOperatorRoom(input: {
|
|
116
|
+
machineToken: string;
|
|
117
|
+
name: string;
|
|
118
|
+
}): Promise<RemoteOperatorRoomCreateResult>;
|
|
119
|
+
resolveNativeSession(input: {
|
|
120
|
+
machineToken: string;
|
|
121
|
+
runtimeAdapter: 'codex' | 'claude_code' | 'workbuddy';
|
|
122
|
+
sourceSessionKey: string;
|
|
123
|
+
}): Promise<{
|
|
124
|
+
nianSessionId: string;
|
|
125
|
+
created: boolean;
|
|
126
|
+
}>;
|
|
127
|
+
createRoom(input: {
|
|
128
|
+
machineToken: string;
|
|
129
|
+
bindingIntentId: string;
|
|
130
|
+
nianSessionId: string;
|
|
131
|
+
runtimeAdapter: 'codex' | 'claude_code' | 'workbuddy';
|
|
132
|
+
sessionRegistryKey: string;
|
|
133
|
+
name: string;
|
|
134
|
+
agentAlias: string;
|
|
135
|
+
agentDescription?: string;
|
|
136
|
+
activationCapability: 'managed' | 'idle_resume' | 'notify_only';
|
|
137
|
+
activationMode: RoomActivationMode;
|
|
138
|
+
}): Promise<RemoteRoomCreateResult>;
|
|
139
|
+
joinRoom(input: {
|
|
140
|
+
machineToken: string;
|
|
141
|
+
bindingIntentId: string;
|
|
142
|
+
nianSessionId: string;
|
|
143
|
+
runtimeAdapter: 'codex' | 'claude_code' | 'workbuddy';
|
|
144
|
+
sessionRegistryKey: string;
|
|
145
|
+
inviteToken: string;
|
|
146
|
+
message?: string;
|
|
147
|
+
agentAlias: string;
|
|
148
|
+
agentDescription?: string;
|
|
149
|
+
activationCapability: 'managed' | 'idle_resume' | 'notify_only';
|
|
150
|
+
activationMode: RoomActivationMode;
|
|
151
|
+
}): Promise<RemoteRoomJoinResult>;
|
|
152
|
+
status(target: BindingTarget): Promise<RemoteRoomAgentStatus>;
|
|
153
|
+
getAttachmentCapability(target: BindingTarget & {
|
|
154
|
+
attachmentId: string;
|
|
155
|
+
}): Promise<RemoteRoomAttachmentCapability>;
|
|
156
|
+
initializeAttachment(target: BindingTarget & {
|
|
157
|
+
clientUploadId: string;
|
|
158
|
+
name: string;
|
|
159
|
+
mediaKind: 'image' | 'audio' | 'file';
|
|
160
|
+
mimeType: string;
|
|
161
|
+
byteSize: number;
|
|
162
|
+
sha256: string;
|
|
163
|
+
}): Promise<RemoteRoomAttachmentUpload>;
|
|
164
|
+
completeAttachment(target: BindingTarget & {
|
|
165
|
+
attachmentId: string;
|
|
166
|
+
}): Promise<{
|
|
167
|
+
attachment: {
|
|
168
|
+
attachmentId: string;
|
|
169
|
+
mediaKind: 'image' | 'audio' | 'file';
|
|
170
|
+
name: string;
|
|
171
|
+
mimeType: string;
|
|
172
|
+
byteSize: string;
|
|
173
|
+
sha256: string;
|
|
174
|
+
status: 'ready';
|
|
175
|
+
};
|
|
176
|
+
idempotent: boolean;
|
|
177
|
+
}>;
|
|
178
|
+
read(target: BindingTarget & {
|
|
179
|
+
afterSequence: string;
|
|
180
|
+
limit: number;
|
|
181
|
+
}): Promise<{
|
|
182
|
+
messages: RoomMessageView[];
|
|
183
|
+
nextSequence: string;
|
|
184
|
+
hasMore: boolean;
|
|
185
|
+
historyFromSequence: string;
|
|
186
|
+
roomName: string;
|
|
187
|
+
}>;
|
|
188
|
+
send(target: BindingTarget & {
|
|
189
|
+
clientMessageId: string;
|
|
190
|
+
text: string;
|
|
191
|
+
mentionMembershipIds?: string[];
|
|
192
|
+
replyToMessageId?: string;
|
|
193
|
+
activationCauseMessageId?: string;
|
|
194
|
+
attachmentIds?: string[];
|
|
195
|
+
}): Promise<{
|
|
196
|
+
message: RoomMessageView;
|
|
197
|
+
idempotent: boolean;
|
|
198
|
+
}>;
|
|
199
|
+
mode(target: BindingTarget & {
|
|
200
|
+
activationMode: RoomActivationMode;
|
|
201
|
+
}): Promise<{
|
|
202
|
+
bindingId: string;
|
|
203
|
+
roomId: string;
|
|
204
|
+
status: 'active' | 'paused';
|
|
205
|
+
activationMode: RoomActivationMode;
|
|
206
|
+
idempotent: boolean;
|
|
207
|
+
}>;
|
|
208
|
+
private request;
|
|
209
|
+
}
|
|
210
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class c extends Error{code;constructor(e,o){super(o),this.code=e,this.name="RoomActionHttpError"}}class j{fetchImpl;baseUrl;constructor(e,o=fetch){this.fetchImpl=o,this.baseUrl=e.replace(/\/+$/,"")}async createOperatorRoom(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/operator/create`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({name:e.name}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await m(o);if(!o.ok)throw p(o.status,t);return I(t,e,this.baseUrl)}async resolveNativeSession(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/resolve-session`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({runtimeAdapter:e.runtimeAdapter,sourceSessionKey:e.sourceSessionKey}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await m(o);if(!o.ok)throw p(o.status,t);(!t||typeof t!="object")&&a();const n=t;return(typeof n.nianSessionId!="string"||!/^[A-Za-z0-9_.:@/-]{1,512}$/.test(n.nianSessionId)||typeof n.created!="boolean")&&a(),n}async createRoom(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/create`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,name:e.name,agentAlias:e.agentAlias,agentDescription:e.agentDescription,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await m(o);if(!o.ok)throw p(o.status,t);return g(t,e,this.baseUrl)}async joinRoom(e){let o;try{o=await this.fetchImpl(`${this.baseUrl}/api/rooms/actions/join`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,inviteToken:e.inviteToken,message:e.message,agentAlias:e.agentAlias,agentDescription:e.agentDescription,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}const t=await m(o);if(!o.ok)throw p(o.status,t);return v(t,e,this.baseUrl)}async status(e){const o=await this.request(e,"status");return b(o,e)}async getAttachmentCapability(e){const o=await this.request(e,`attachments/${encodeURIComponent(e.attachmentId)}/download-capability`);(!o||typeof o!="object")&&a();const t=o;return(t.attachmentId!==e.attachmentId||t.roomId!==e.roomId||typeof t.safeName!="string"||!S(t.safeName)||typeof t.mimeType!="string"||t.mimeType.length<1||t.mimeType.length>191||typeof t.byteSize!="string"||!d(t.byteSize)||typeof t.sha256!="string"||!/^[a-f0-9]{64}$/.test(t.sha256)||!h(t.downloadUrl)||typeof t.expiresAt!="string"||!Number.isFinite(Date.parse(t.expiresAt)))&&a(),t}async initializeAttachment(e){const o=await this.request(e,"attachments/init",{method:"POST",body:JSON.stringify({clientUploadId:e.clientUploadId,name:e.name,mediaKind:e.mediaKind,mimeType:e.mimeType,byteSize:e.byteSize,sha256:e.sha256})});(!o||typeof o!="object")&&a();const t=o,n=t.attachment,r=t.upload;return(!n||typeof n.id!="string"||n.roomId!==e.roomId||n.name.length<1||n.mimeType!==e.mimeType||n.byteSize!==String(e.byteSize)||n.sha256!==e.sha256||n.status!=="pending"&&n.status!=="uploaded"||!r||r.method!=="PUT"||!h(r.url)||!r.headers||r.headers["content-type"]!==e.mimeType||r.headers["x-oss-meta-sha256"]!==e.sha256||typeof r.expiresAt!="string"||Date.parse(r.expiresAt)<=Date.now()||typeof t.idempotent!="boolean")&&a(),t}async completeAttachment(e){const o=await this.request(e,`attachments/${encodeURIComponent(e.attachmentId)}/complete`,{method:"POST"});(!o||typeof o!="object")&&a();const t=o;typeof t.idempotent!="boolean"&&a();const n=t.attachment;return(!n||n.attachmentId!==e.attachmentId||n.mediaKind!=="image"&&n.mediaKind!=="audio"&&n.mediaKind!=="file"||typeof n.name!="string"||typeof n.mimeType!="string"||typeof n.byteSize!="string"||!d(n.byteSize)||typeof n.sha256!="string"||!/^[a-f0-9]{64}$/.test(n.sha256)||n.status!=="ready")&&a(),{attachment:n,idempotent:t.idempotent}}async read(e){const o=new URLSearchParams({after:e.afterSequence,limit:String(e.limit)}),t=await this.request(e,`messages?${o}`);(!t||typeof t!="object")&&a();const n=t;return(!Array.isArray(n.messages)||typeof n.nextSequence!="string"||!d(n.nextSequence)||typeof n.hasMore!="boolean"||typeof n.historyFromSequence!="string"||!d(n.historyFromSequence)||typeof n.roomName!="string")&&a(),{messages:n.messages.map(s=>l(s,e.roomId)),nextSequence:n.nextSequence,hasMore:n.hasMore,historyFromSequence:n.historyFromSequence,roomName:n.roomName}}async send(e){const o=await this.request(e,"messages",{method:"POST",body:JSON.stringify({clientMessageId:e.clientMessageId,text:e.text,mentionMembershipIds:e.mentionMembershipIds,replyToMessageId:e.replyToMessageId,activationCauseMessageId:e.activationCauseMessageId,attachmentIds:e.attachmentIds})});(!o||typeof o!="object")&&a();const t=o;return typeof t.idempotent!="boolean"&&a(),{message:l(t.message,e.roomId),idempotent:t.idempotent}}async mode(e){const o=await this.request(e,"mode",{method:"PATCH",body:JSON.stringify({activationMode:e.activationMode})});(!o||typeof o!="object")&&a();const t=o;return(t.bindingId!==e.bindingId||t.roomId!==e.roomId||t.status!=="active"&&t.status!=="paused"||!f(t.activationMode)||t.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&a(),t}async request(e,o,t={}){let n;try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(e.roomId)}/bindings/${encodeURIComponent(e.bindingId)}/${o}`,{...t,headers:{authorization:`Bearer ${e.machineToken}`,...t.body?{"content-type":"application/json"}:{}},signal:AbortSignal.timeout(1e4)})}catch{throw new c("room_action_server_unavailable","Shennian Room service is unavailable.")}if(!n.ok){let r=`room_action_http_${n.status}`;try{const s=await n.json();typeof s.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(s.error)&&(r=s.error)}catch{}throw new c(r,"Shennian Room action failed.")}try{return await n.json()}catch{a()}}}function b(i,e){(!i||typeof i!="object")&&a();const o=i,t=o.room;(o.bindingId!==e.bindingId||o.roomId!==e.roomId||typeof o.agentIdentityId!="string"||o.agentMembershipId!==null&&typeof o.agentMembershipId!="string"||o.status!=="pending_approval"&&o.status!=="active"&&o.status!=="paused"&&o.status!=="detached"||!f(o.activationMode)||typeof o.lastDeliveredSequence!="string"||!d(o.lastDeliveredSequence)||typeof o.lastActivatedSequence!="string"||!d(o.lastActivatedSequence)||!t||typeof t!="object")&&a(),(o.status==="pending_approval"&&o.agentMembershipId!==null||(o.status==="active"||o.status==="paused")&&typeof o.agentMembershipId!="string")&&a();const n=t;return(typeof n.name!="string"||typeof n.status!="string"||typeof n.lastSequence!="string"||!d(n.lastSequence))&&a(),o}function l(i,e){(!i||typeof i!="object")&&a();const o=i;if((typeof o.id!="string"||o.roomId!==e||typeof o.sequence!="string"||!d(o.sequence)||!o.author||typeof o.author.membershipId!="string"||!Array.isArray(o.attachments)||typeof o.createdAt!="string")&&a(),o.activationCause!=null){const t=o.activationCause;(typeof t.causeMessageId!="string"||typeof t.rootCauseMessageId!="string"||!Number.isInteger(t.hopCount)||t.hopCount<1||t.hopCount>32)&&a()}return o}function g(i,e,o){(!i||typeof i!="object")&&a();const t=i,n=t.room,r=t.agentIdentity,s=t.binding;return(t.outcome!=="created"||!n||typeof n.id!="string"||n.name!==e.name||n.visibility!=="private"||n.joinPolicy!=="approval"||!y(n.webUrl,o,`/spaces/${n.id}`)||!w(n.inviteUrl,o)||!r||typeof r.id!="string"||r.displayName!==e.agentAlias||!s||typeof s.id!="string"||s.roomId!==n.id||s.agentIdentityId!==r.id||typeof s.agentMembershipId!="string"||s.status!=="active"&&s.status!=="paused"||s.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&a(),t}function I(i,e,o){(!i||typeof i!="object")&&a();const t=i,n=t.room;return(t.outcome!=="created"||!n||typeof n.id!="string"||n.name!==e.name||n.visibility!=="private"||n.joinPolicy!=="approval"||!y(n.webUrl,o,`/spaces/${n.id}`))&&a(),t}function v(i,e,o){(!i||typeof i!="object")&&a();const t=i,n=t.room,r=t.agentIdentity,s=t.binding;return(t.outcome!=="joined"&&t.outcome!=="pending_approval"||!n||typeof n.id!="string"||typeof n.name!="string"||!y(n.webUrl,o,`/spaces/${n.id}`)||!r||typeof r.id!="string"||r.displayName!==e.agentAlias||!s||typeof s.id!="string"||s.roomId!==n.id||s.agentIdentityId!==r.id||s.activationMode!==e.activationMode||typeof t.idempotent!="boolean")&&a(),(t.outcome==="pending_approval"&&(s.status!=="pending_approval"||s.agentMembershipId!==null||typeof t.joinRequestId!="string")||t.outcome==="joined"&&(s.status!=="active"&&s.status!=="paused"||typeof s.agentMembershipId!="string"||t.joinRequestId!==void 0))&&a(),t}function d(i){return/^(0|[1-9]\d{0,19})$/.test(i)}function S(i){return i.length<=255&&i===i.trim()&&i!=="."&&i!==".."&&!/[\\/\0-\x1f\x7f]/.test(i)}function h(i){if(typeof i!="string")return!1;try{const e=new URL(i);return e.protocol==="https:"&&!e.username&&!e.password&&!e.hash}catch{return!1}}function f(i){return i==="auto_follow"||i==="mention_only"||i==="paused"}function a(){throw new c("invalid_room_action_response","Invalid Room action response.")}async function m(i){try{return await i.json()}catch{a()}}function p(i,e){let o=`room_action_http_${i}`;if(e&&typeof e=="object"){const t=e.error;typeof t=="string"&&/^[a-z0-9_-]{1,80}$/.test(t)&&(o=t)}return new c(o,"Shennian Room action failed.")}function y(i,e,o){return u(i,e,t=>t.pathname===o)}function w(i,e){return u(i,e,o=>/^\/spaces\/join\/[A-Za-z0-9_-]{43}$/.test(o.pathname))}function u(i,e,o){if(typeof i!="string")return!1;try{const t=new URL(i),n=new URL(e);return t.hostname===n.hostname&&(t.protocol==="https:"||n.protocol==="http:"&&t.protocol==="http:")&&!t.username&&!t.password&&!t.search&&!t.hash&&o(t)}catch{return!1}}export{j as HttpRoomActionClient,c as RoomActionHttpError};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DaemonIpcHandler } from '../daemon-ipc/server.js';
|
|
2
|
+
import { RoomInvocationTokenAuthority } from './invocation-token.js';
|
|
3
|
+
import type { RoomAttachmentCache } from './attachment-cache.js';
|
|
4
|
+
import { HttpRoomActionClient } from './room-action-client.js';
|
|
5
|
+
import { RoomSessionRegistry } from './session-registry.js';
|
|
6
|
+
import type { RoomAttachmentUploader } from './attachment-upload.js';
|
|
7
|
+
import type { RoomHostSessionObservationStore } from './host-session-observations.js';
|
|
8
|
+
type RoomMirrorWriter = {
|
|
9
|
+
append(input: {
|
|
10
|
+
messages: Awaited<ReturnType<HttpRoomActionClient['read']>>['messages'];
|
|
11
|
+
historyFromSequence: string;
|
|
12
|
+
roomName?: string | null;
|
|
13
|
+
}): unknown;
|
|
14
|
+
markAccessRevoked(): void;
|
|
15
|
+
search(input: {
|
|
16
|
+
query: string;
|
|
17
|
+
limit?: number;
|
|
18
|
+
}): unknown;
|
|
19
|
+
};
|
|
20
|
+
export declare function createRoomActionIpcHandlers(input: {
|
|
21
|
+
authority: RoomInvocationTokenAuthority;
|
|
22
|
+
registry: RoomSessionRegistry;
|
|
23
|
+
actionClient: Pick<HttpRoomActionClient, 'createRoom' | 'joinRoom' | 'read' | 'send' | 'mode' | 'status'>;
|
|
24
|
+
getMachineCredentials: () => {
|
|
25
|
+
machineId?: string;
|
|
26
|
+
machineToken?: string;
|
|
27
|
+
};
|
|
28
|
+
mirrorFactory?: (roomId: string) => RoomMirrorWriter;
|
|
29
|
+
attachmentCache?: Pick<RoomAttachmentCache, 'materialize'>;
|
|
30
|
+
attachmentUploader?: Pick<RoomAttachmentUploader, 'upload'>;
|
|
31
|
+
observations?: RoomHostSessionObservationStore;
|
|
32
|
+
}): Record<string, DaemonIpcHandler>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DaemonIpcError as a}from"../daemon-ipc/protocol.js";import{normalizeRoomActionParameters as R}from"./room-action-schema.js";function B(e){return{"room-action.execute":async o=>{const h=T(o),l=e.getMachineCredentials();if(!l.machineId?.trim()||!l.machineToken?.trim())throw new a("machine_not_authorized","This machine is not authorized yet.");const s=w(h.registryKey,"registryKey",64),A=w(h.invocationToken,"invocationToken",128),d=S(h.action),u=R(d,h.actionParameters);return e.registry.runExclusive(s,async()=>{let y;try{y=e.authority.consume({invocationToken:A,machineId:l.machineId,machineCredential:l.machineToken,registryKey:s,action:d,targetTool:"shennian_room",actionParameters:u})}catch(t){throw C(t)}const r=e.registry.getByRegistryKey(s),i=r?.binding;if(!r)throw new a("room_session_unavailable","The exact Agent session is unavailable.");if(d==="room.create"){if(i&&i.status!=="detached")throw new a("session_already_bound","This Agent session is already bound to a Room.");if(!y.bindingIntentId)throw new a("binding_intent_missing","Room create intent is missing.");const t=u,n=await e.actionClient.createRoom({machineToken:l.machineToken,bindingIntentId:y.bindingIntentId,nianSessionId:r.nianSessionId,runtimeAdapter:r.runtimeAdapter,sessionRegistryKey:s,name:t.name,agentAlias:t.agentAlias,agentDescription:t.agentDescription,activationCapability:_(r.capabilities),activationMode:t.activationMode});return e.registry.setBinding({registryKey:s,bindingId:n.binding.id,roomId:n.room.id,agentIdentityId:n.binding.agentIdentityId,agentMembershipId:n.binding.agentMembershipId,status:n.binding.status,activationMode:n.binding.activationMode}),g(n)}if(d==="room.join"){if(i&&i.status!=="detached")throw new a("session_already_bound","This Agent session is already bound to a Room.");if(!y.bindingIntentId)throw new a("binding_intent_missing","Room join intent is missing.");const t=u,n=await e.actionClient.joinRoom({machineToken:l.machineToken,bindingIntentId:y.bindingIntentId,nianSessionId:r.nianSessionId,runtimeAdapter:r.runtimeAdapter,sessionRegistryKey:s,inviteToken:k(t.inviteUrl),message:t.message,agentAlias:t.agentAlias,agentDescription:t.agentDescription,activationCapability:_(r.capabilities),activationMode:t.activationMode});return e.registry.setBinding({registryKey:s,bindingId:n.binding.id,roomId:n.room.id,agentIdentityId:n.binding.agentIdentityId,agentMembershipId:n.binding.agentMembershipId,status:n.binding.status,activationMode:n.binding.activationMode}),g(n)}if(!i)throw new a("room_not_bound","This Agent session is not bound to a Room.");if(d!=="room.status"&&(i.status==="detached"||i.status==="pending_approval"))throw new a(i.status==="pending_approval"?"room_binding_pending_approval":"room_binding_detached",i.status==="pending_approval"?"This Agent is waiting for Room approval.":"This Agent Room binding must be repaired before use.");const I={machineToken:l.machineToken,roomId:i.roomId,bindingId:i.bindingId};if(d==="room.status"){const t=await e.actionClient.status(I);e.registry.setBinding({registryKey:s,bindingId:t.bindingId,roomId:t.roomId,agentIdentityId:t.agentIdentityId,agentMembershipId:t.agentMembershipId,status:t.status,activationMode:t.activationMode}),t.status==="detached"&&e.mirrorFactory?.(t.roomId).markAccessRevoked();const n=e.registry.getByRegistryKey(s),c=n?.binding,m=e.observations?.getBySource(r);return g({...t,hostSession:{state:n?.lifecycleState??"closed",lastReportedEvent:m?.lastEventName??null,lastActiveAt:m?.lastActiveAt??null,lastIdleAt:m?.lastIdleAt??null,closedAt:m?.closedAt??null,closedConfirmed:m?.lifecycleState==="closed",activationCapability:_(r.capabilities)},localActivation:{queued:c?.activationQueue.length??0,inFlight:!!c?.activeActivation,pausedUntil:c?.loopBreaker.pausedUntil??null}})}if(d==="room.read"){const t=u;if(t.query){const b=e.mirrorFactory?.(i.roomId);if(!b)throw new a("room_mirror_unavailable","Room mirror is unavailable.");return g({source:"local_mirror",matches:b.search({query:t.query,limit:t.limit})})}const n=await e.actionClient.read({...I,afterSequence:t.afterSequence,limit:t.limit});e.mirrorFactory?.(i.roomId).append({messages:n.messages,historyFromSequence:n.historyFromSequence,roomName:n.roomName});const c=BigInt(n.nextSequence)>BigInt(i.lastDeliveredSequence)?n.nextSequence:i.lastDeliveredSequence;e.registry.advanceCursor({registryKey:s,cursor:"delivered",sequence:c});const m=[];for(const b of t.attachmentIds??[]){const v=n.messages.flatMap(p=>p.attachments).find(p=>p.attachmentId===b);if(!v||v.status!=="ready")throw new a("attachment_not_in_read_result","Requested attachment is not available in this read result.");if(!e.attachmentCache)throw new a("attachment_cache_unavailable","Room attachment cache is unavailable.");m.push({attachmentId:b,...await e.attachmentCache.materialize({...I,attachmentId:b,expected:{downloadRef:v.downloadRef,byteSize:v.byteSize,sha256:v.sha256}})})}return g({...n,materializedAttachments:m})}if(d==="room.send"){const t=u;let n;if(t.files?.length){const c=e.observations?.getBySource(r);if(!c?.workspacePath||!e.attachmentUploader)throw new a("room_attachment_upload_unavailable","The exact Agent workspace is unavailable for attachment upload.");n=await e.attachmentUploader.upload({...I,workspacePath:c.workspacePath,clientMessageId:t.clientMessageId,files:t.files})}return g(await e.actionClient.send({...I,clientMessageId:t.clientMessageId,text:t.text,mentionMembershipIds:t.mentionMembershipIds,replyToMessageId:t.replyToMessageId,attachmentIds:n,activationCauseMessageId:i.activeActivation?.causeMessageId}))}const M=u,f=await e.actionClient.mode({...I,...M});return e.registry.setBinding({registryKey:s,bindingId:i.bindingId,roomId:i.roomId,agentIdentityId:i.agentIdentityId,agentMembershipId:i.agentMembershipId,status:f.status,activationMode:f.activationMode}),g(f)})}}}function T(e){if(!e||Array.isArray(e)||typeof e!="object")throw new a("invalid_params","Room action parameters are required.");return e}function w(e,o,h){if(typeof e!="string"||!e.trim()||e.length>h)throw new a("invalid_params",`${o} is invalid.`);return e.trim()}function S(e){const o=w(e,"action",64);if(o!=="room.read"&&o!=="room.create"&&o!=="room.join"&&o!=="room.send"&&o!=="room.mode"&&o!=="room.status")throw new a("room_action_not_implemented","Room action is not available yet.");return o}function k(e){const o=new URL(e).pathname.split("/").at(-1);if(!o||!/^[A-Za-z0-9_-]{43}$/.test(o))throw new a("invalid_params","inviteUrl is invalid.");return o}function _(e){return e.canResumeIdleSession||e.canActivateWhileHostOpen?"idle_resume":"notify_only"}function C(e){return e&&typeof e=="object"&&"code"in e&&typeof e.code=="string"&&"message"in e&&typeof e.message=="string"?new a(e.code,e.message):new a("room_invocation_failed","Room invocation failed.")}function g(e){return JSON.parse(JSON.stringify(e))}export{B as createRoomActionIpcHandlers};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RoomInvocationAction } from './invocation-token.js';
|
|
2
|
+
import type { JsonValue } from './pending-authorized-actions.js';
|
|
3
|
+
export declare function normalizeRoomActionParameters(action: Exclude<RoomInvocationAction, 'room.bind'>, value: JsonValue | undefined): JsonValue;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DaemonIpcError as l}from"../daemon-ipc/protocol.js";function I(t,n){const e=h(n);switch(t){case"room.status":return d(e,[]),{};case"room.read":{d(e,["afterSequence","limit","attachmentIds","query"]);const s=o(e.query,"query",200),i=e.afterSequence??"0",a=e.limit??50;(typeof i!="string"||!/^(0|[1-9]\d{0,19})$/.test(i))&&r("afterSequence"),(typeof a!="number"||!Number.isInteger(a)||a<1||a>100)&&r("limit");const m=g(e.attachmentIds,"attachmentIds",10);return s&&(e.afterSequence!=null||m)&&r("parameters"),s?{query:s,limit:a}:{afterSequence:i,limit:a,...m?{attachmentIds:m}:{}}}case"room.send":{d(e,["clientMessageId","text","files","mentionMembershipIds","replyToMessageId"]);const s=c(e.clientMessageId,"clientMessageId",191),i=o(e.text,"text",2e4),a=u(e.files,"files",10);!i&&!a&&r("parameters");const m=g(e.mentionMembershipIds,"mentionMembershipIds",20),p=o(e.replyToMessageId,"replyToMessageId",191);return{clientMessageId:s,text:i??"",...a?{files:a}:{},...m?{mentionMembershipIds:m}:{},...p?{replyToMessageId:p}:{}}}case"room.mode":return d(e,["activationMode"]),{activationMode:f(e.activationMode)};case"room.create":return d(e,["name","agentAlias","agentDescription","activationMode"]),{name:c(e.name,"name",80),agentAlias:c(e.agentAlias,"agentAlias",80),...o(e.agentDescription,"agentDescription",1e3)?{agentDescription:o(e.agentDescription,"agentDescription",1e3)}:{},activationMode:f(e.activationMode??"auto_follow")};case"room.join":return d(e,["inviteUrl","agentAlias","agentDescription","message","activationMode"]),{inviteUrl:y(e.inviteUrl),agentAlias:c(e.agentAlias,"agentAlias",80),...o(e.agentDescription,"agentDescription",1e3)?{agentDescription:o(e.agentDescription,"agentDescription",1e3)}:{},activationMode:f(e.activationMode??"auto_follow"),...o(e.message,"message",500)?{message:o(e.message,"message",500)}:{}}}}function u(t,n,e){return t==null?void 0:((!Array.isArray(t)||t.length<1||t.length>e)&&r(n),t.map(i=>((typeof i!="string"||!i.trim()||i.length>4096||/[\0\r\n]/.test(i))&&r(n),i.trim())))}function h(t){return t==null?{}:((Array.isArray(t)||typeof t!="object")&&r("parameters"),t)}function d(t,n){const e=new Set(n);Object.keys(t).some(s=>!e.has(s))&&r("parameters")}function c(t,n,e){return(typeof t!="string"||!t.trim()||t.length>e||/[\0\r]/.test(t))&&r(n),t.trim()}function o(t,n,e){if(!(t==null||t===""))return c(t,n,e)}function g(t,n,e){if(t==null)return;(!Array.isArray(t)||t.length>e)&&r(n);const s=t.map(i=>c(i,n,191));return new Set(s).size!==s.length&&r(n),s.length>0?s:void 0}function f(t){if(t==="auto"||t==="auto_follow")return"auto_follow";if(t==="mention"||t==="mention_only")return"mention_only";if(t==="paused")return"paused";r("activationMode")}function y(t){const n=c(t,"inviteUrl",2048);let e;try{e=new URL(n)}catch{r("inviteUrl")}return(e.protocol!=="https:"||e.hostname!=="shennian.net"||!/^\/spaces\/join\/[A-Za-z0-9_-]{43}$/.test(e.pathname)||e.username||e.password||e.search||e.hash)&&r("inviteUrl"),e.toString()}function r(t){throw new l("invalid_params",`${t} is invalid.`)}export{I as normalizeRoomActionParameters};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AuthorizedActionExecutor } from './authorized-action-coordinator.js';
|
|
2
|
+
import type { RoomHostSessionObservationStore } from './host-session-observations.js';
|
|
3
|
+
import type { HttpRoomBindingClient } from './room-binding-client.js';
|
|
4
|
+
import type { JsonValue, PendingAuthorizedAction } from './pending-authorized-actions.js';
|
|
5
|
+
import type { RoomSessionRegistry } from './session-registry.js';
|
|
6
|
+
type Credentials = {
|
|
7
|
+
machineId: string;
|
|
8
|
+
machineToken: string;
|
|
9
|
+
};
|
|
10
|
+
export declare class RoomAuthorizedActionExecutor implements AuthorizedActionExecutor {
|
|
11
|
+
private readonly deps;
|
|
12
|
+
constructor(deps: {
|
|
13
|
+
registry: RoomSessionRegistry;
|
|
14
|
+
observations: RoomHostSessionObservationStore;
|
|
15
|
+
actionClient: Pick<HttpRoomBindingClient, 'resolveNativeSession' | 'createRoom' | 'joinRoom'>;
|
|
16
|
+
getMachineCredentials: () => {
|
|
17
|
+
machineId?: string;
|
|
18
|
+
machineToken?: string;
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
execute(action: PendingAuthorizedAction, claimed?: Credentials): Promise<JsonValue>;
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import g from"node:path";import{normalizeRoomActionParameters as f}from"./room-action-schema.js";class H{deps;constructor(e){this.deps=e}async execute(e,m){const s=I(m??this.deps.getMachineCredentials()),n=A(e),r=this.deps.observations.observe({machineId:s.machineId,runtimeAdapter:n.runtimeAdapter,sourceSessionKey:n.sourceSessionKey,hostContextHash:n.hostContextHash,workspaceHash:n.workspaceHash,workspacePath:n.workspacePath,lifecycleState:"active",eventName:"PreToolUse"}),c=await this.deps.actionClient.resolveNativeSession({machineToken:s.machineToken,runtimeAdapter:n.runtimeAdapter,sourceSessionKey:n.sourceSessionKey}),i=!!r.workspacePath,p=this.deps.registry.register({machineId:s.machineId,runtimeAdapter:n.runtimeAdapter,sourceSessionKey:n.sourceSessionKey,nianSessionId:c.nianSessionId,hostProcessIdentity:`${n.runtimeAdapter}:${r.hostContextHash}:${r.registrationEpoch}`,capabilities:{canIdentifySession:!0,canBindAutomatically:!0,canOpenEmbeddedRoomPage:!1,canResumeIdleSession:i,canActivateWhileHostOpen:!1}}),y=i?"idle_resume":"notify_only",l=`${n.action.replace(".","-")}:${e.id}`,h={machineToken:s.machineToken,bindingIntentId:l,nianSessionId:c.nianSessionId,runtimeAdapter:n.runtimeAdapter,sessionRegistryKey:p.registryKey,agentAlias:n.parameters.agentAlias,agentDescription:n.parameters.agentDescription,activationCapability:y,activationMode:n.parameters.activationMode},o=n.action==="room.create"?await this.deps.actionClient.createRoom({...h,name:n.parameters.name}):await this.deps.actionClient.joinRoom({...h,inviteToken:w(n.parameters.inviteUrl),message:n.parameters.message});return this.deps.registry.setBinding({registryKey:p.registryKey,bindingId:o.binding.id,roomId:o.room.id,agentIdentityId:o.binding.agentIdentityId,agentMembershipId:o.binding.agentMembershipId,status:o.binding.status,activationMode:o.binding.activationMode}),JSON.parse(JSON.stringify(o))}}function A(t){const e=t.canonicalActionPayload;(!e||Array.isArray(e)||typeof e!="object"||e.schemaVersion!==1)&&a();const m=k(e.runtimeAdapter),s=d(e.sourceSessionKey,1024),n=u(e.hostContextHash),r=e.workspaceHash==null?null:u(e.workspaceHash),c=S(e.workspacePath);e.lifecycleState!=="active"&&a(),(e.action!==t.actionType||e.action!=="room.create"&&e.action!=="room.join")&&a();const i=f(e.action,e.actionParameters);return(!i||Array.isArray(i)||typeof i!="object")&&a(),{runtimeAdapter:m,sourceSessionKey:s,hostContextHash:n,workspaceHash:r,workspacePath:c,action:e.action,parameters:{name:typeof i.name=="string"?i.name:"",inviteUrl:typeof i.inviteUrl=="string"?i.inviteUrl:"",agentAlias:d(i.agentAlias,80),...typeof i.agentDescription=="string"?{agentDescription:i.agentDescription}:{},activationMode:b(i.activationMode),...typeof i.message=="string"?{message:i.message}:{}}}}function I(t){if(!t.machineId?.trim()||!t.machineToken?.trim())throw new Error("machine_credentials_unavailable");return{machineId:t.machineId.trim(),machineToken:t.machineToken.trim()}}function k(t){return t!=="codex"&&t!=="claude_code"&&t!=="workbuddy"&&a(),t}function b(t){return t!=="auto_follow"&&t!=="mention_only"&&t!=="paused"&&a(),t}function d(t,e){return(typeof t!="string"||!t.trim()||t.length>e||/[\0\r\n]/.test(t))&&a(),t.trim()}function u(t){const e=d(t,64);return/^[a-f0-9]{64}$/.test(e)||a(),e}function S(t){if(t==null||t==="")return null;const e=d(t,4096);return g.isAbsolute(e)||a(),e}function w(t){const e=/^https:\/\/shennian\.net\/spaces\/join\/([A-Za-z0-9_-]{43})$/.exec(t);return e||a(),e[1]}function a(){throw new Error("invalid_room_authorized_action")}export{H as RoomAuthorizedActionExecutor};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { RoomActivationCapability, RoomActivationMode, RoomBindingStatus, RoomRuntimeAdapter } from '@shennian/wire';
|
|
2
|
+
import { HttpRoomActionClient } from './room-action-client.js';
|
|
3
|
+
type FetchLike = typeof fetch;
|
|
4
|
+
export type CreateRemoteRoomBindingInput = {
|
|
5
|
+
machineToken: string;
|
|
6
|
+
bindingIntentId: string;
|
|
7
|
+
roomId: string;
|
|
8
|
+
agentIdentityId: string;
|
|
9
|
+
nianSessionId: string;
|
|
10
|
+
runtimeAdapter: RoomRuntimeAdapter;
|
|
11
|
+
sessionRegistryKey: string;
|
|
12
|
+
activationCapability: RoomActivationCapability;
|
|
13
|
+
activationMode: RoomActivationMode;
|
|
14
|
+
};
|
|
15
|
+
export type RemoteRoomBinding = {
|
|
16
|
+
id: string;
|
|
17
|
+
roomId: string;
|
|
18
|
+
agentIdentityId: string;
|
|
19
|
+
agentMembershipId: string;
|
|
20
|
+
nianSessionId: string;
|
|
21
|
+
runtimeAdapter: RoomRuntimeAdapter;
|
|
22
|
+
activationCapability: RoomActivationCapability;
|
|
23
|
+
activationMode: RoomActivationMode;
|
|
24
|
+
status: RoomBindingStatus;
|
|
25
|
+
};
|
|
26
|
+
export declare class RoomBindingHttpError extends Error {
|
|
27
|
+
readonly code: string;
|
|
28
|
+
constructor(code: string, message: string);
|
|
29
|
+
}
|
|
30
|
+
export declare class HttpRoomBindingClient {
|
|
31
|
+
private readonly fetchImpl;
|
|
32
|
+
private readonly baseUrl;
|
|
33
|
+
private readonly actionClient;
|
|
34
|
+
constructor(serverUrl: string, fetchImpl?: FetchLike);
|
|
35
|
+
status: HttpRoomActionClient['status'];
|
|
36
|
+
getAttachmentCapability: HttpRoomActionClient['getAttachmentCapability'];
|
|
37
|
+
initializeAttachment: HttpRoomActionClient['initializeAttachment'];
|
|
38
|
+
completeAttachment: HttpRoomActionClient['completeAttachment'];
|
|
39
|
+
createRoom: HttpRoomActionClient['createRoom'];
|
|
40
|
+
createOperatorRoom: HttpRoomActionClient['createOperatorRoom'];
|
|
41
|
+
resolveNativeSession: HttpRoomActionClient['resolveNativeSession'];
|
|
42
|
+
joinRoom: HttpRoomActionClient['joinRoom'];
|
|
43
|
+
read: HttpRoomActionClient['read'];
|
|
44
|
+
send: HttpRoomActionClient['send'];
|
|
45
|
+
mode: HttpRoomActionClient['mode'];
|
|
46
|
+
create(input: CreateRemoteRoomBindingInput): Promise<{
|
|
47
|
+
binding: RemoteRoomBinding;
|
|
48
|
+
idempotent: boolean;
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{HttpRoomActionClient as r}from"./room-action-client.js";class o extends Error{code;constructor(t,e){super(e),this.code=t,this.name="RoomBindingHttpError"}}class l{fetchImpl;baseUrl;actionClient;constructor(t,e=fetch){this.fetchImpl=e,this.baseUrl=t.replace(/\/+$/,""),this.actionClient=new r(t,e)}status=t=>this.actionClient.status(t);getAttachmentCapability=t=>this.actionClient.getAttachmentCapability(t);initializeAttachment=t=>this.actionClient.initializeAttachment(t);completeAttachment=t=>this.actionClient.completeAttachment(t);createRoom=t=>this.actionClient.createRoom(t);createOperatorRoom=t=>this.actionClient.createOperatorRoom(t);resolveNativeSession=t=>this.actionClient.resolveNativeSession(t);joinRoom=t=>this.actionClient.joinRoom(t);read=t=>this.actionClient.read(t);send=t=>this.actionClient.send(t);mode=t=>this.actionClient.mode(t);async create(t){let e;try{e=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(t.roomId)}/bindings`,{method:"POST",headers:{authorization:`Bearer ${t.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:t.bindingIntentId,agentIdentityId:t.agentIdentityId,nianSessionId:t.nianSessionId,runtimeAdapter:t.runtimeAdapter,sessionRegistryKey:t.sessionRegistryKey,activationCapability:t.activationCapability,activationMode:t.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new o("room_binding_server_unavailable","Shennian Room service is unavailable.")}if(!e.ok){let s=`room_binding_http_${e.status}`;try{const a=await e.json();typeof a.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(a.error)&&(s=a.error)}catch{}throw new o(s,"Shennian Room binding request failed.")}let i;try{i=await e.json()}catch{throw new o("invalid_room_binding_response","Invalid Room binding response.")}return d(i,t)}}function d(n,t){if(!n||typeof n!="object")throw new o("invalid_room_binding_response","Invalid Room binding response.");const e=n,i=e.binding;if(!i||typeof i.id!="string"||typeof i.agentMembershipId!="string"||i.roomId!==t.roomId||i.agentIdentityId!==t.agentIdentityId||i.nianSessionId!==t.nianSessionId||i.runtimeAdapter!==t.runtimeAdapter||i.activationCapability!==t.activationCapability||i.activationMode!==t.activationMode||!["pending_approval","active","paused","detached"].includes(i.status??"")||typeof e.idempotent!="boolean")throw new o("invalid_room_binding_response","Room binding response does not match the request.");return{binding:i,idempotent:e.idempotent}}export{l as HttpRoomBindingClient,o as RoomBindingHttpError};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RoomActivationCapability, RoomActivationMode } from '@shennian/wire';
|
|
2
|
+
import type { DaemonIpcHandler } from '../daemon-ipc/server.js';
|
|
3
|
+
import type { JsonValue } from './pending-authorized-actions.js';
|
|
4
|
+
import { RoomInvocationTokenAuthority } from './invocation-token.js';
|
|
5
|
+
import { HttpRoomBindingClient } from './room-binding-client.js';
|
|
6
|
+
import { RoomSessionRegistry } from './session-registry.js';
|
|
7
|
+
import type { RoomJsonlMirror } from './jsonl-mirror.js';
|
|
8
|
+
import type { RoomAttachmentCache } from './attachment-cache.js';
|
|
9
|
+
import type { RoomAttachmentUploader } from './attachment-upload.js';
|
|
10
|
+
import type { RoomHostSessionObservationStore } from './host-session-observations.js';
|
|
11
|
+
export declare function createRoomBindingIpcHandlers(input: {
|
|
12
|
+
authority: RoomInvocationTokenAuthority;
|
|
13
|
+
registry: RoomSessionRegistry;
|
|
14
|
+
bindingClient: HttpRoomBindingClient;
|
|
15
|
+
getMachineCredentials: () => {
|
|
16
|
+
machineId?: string;
|
|
17
|
+
machineToken?: string;
|
|
18
|
+
};
|
|
19
|
+
mirrorFactory?: (roomId: string) => Pick<RoomJsonlMirror, 'append' | 'markAccessRevoked' | 'search'>;
|
|
20
|
+
attachmentCache?: Pick<RoomAttachmentCache, 'materialize'>;
|
|
21
|
+
attachmentUploader?: Pick<RoomAttachmentUploader, 'upload'>;
|
|
22
|
+
observations?: RoomHostSessionObservationStore;
|
|
23
|
+
}): Record<string, DaemonIpcHandler>;
|
|
24
|
+
export declare function buildRoomBindingActionParameters(input: {
|
|
25
|
+
roomId: string;
|
|
26
|
+
agentIdentityId: string;
|
|
27
|
+
activationCapability?: RoomActivationCapability;
|
|
28
|
+
activationMode?: RoomActivationMode;
|
|
29
|
+
}): JsonValue;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DaemonIpcError as a}from"../daemon-ipc/protocol.js";import{createRoomActionIpcHandlers as b}from"./room-action-ipc.js";function _(n){return{...b({authority:n.authority,registry:n.registry,actionClient:n.bindingClient,getMachineCredentials:n.getMachineCredentials,mirrorFactory:n.mirrorFactory,attachmentCache:n.attachmentCache,attachmentUploader:n.attachmentUploader,observations:n.observations}),"room-binding.execute":async i=>{const e=v(i),r=n.getMachineCredentials();if(!r.machineId?.trim()||!r.machineToken?.trim())throw new a("machine_not_authorized","This machine is not authorized yet.");const l=c(e.invocationToken,"invocationToken",128),m=c(e.registryKey,"registryKey",64),d=c(e.roomId,"roomId",191),s=c(e.agentIdentityId,"agentIdentityId",191),g=p(e.activationCapability),y=u(e.activationMode),h=f({roomId:d,agentIdentityId:s,activationCapability:g,activationMode:y});return n.registry.runExclusive(m,async()=>{const o=n.authority.consume({invocationToken:l,machineId:r.machineId,machineCredential:r.machineToken,registryKey:m,action:"room.bind",targetTool:"shennian_room",actionParameters:h});if(!o.bindingIntentId)throw new a("binding_intent_missing","Room Binding intent is missing.");const t=await n.bindingClient.create({machineToken:r.machineToken,bindingIntentId:o.bindingIntentId,roomId:d,agentIdentityId:s,nianSessionId:o.nianSessionId,runtimeAdapter:o.runtimeAdapter,sessionRegistryKey:o.registryKey,activationCapability:g,activationMode:y}),I=n.registry.setBinding({registryKey:m,bindingId:t.binding.id,roomId:d,agentIdentityId:s,agentMembershipId:t.binding.agentMembershipId,status:t.binding.status,activationMode:t.binding.activationMode});return{binding:{id:t.binding.id,roomId:d,agentIdentityId:s,agentMembershipId:t.binding.agentMembershipId,nianSessionId:o.nianSessionId,runtimeAdapter:o.runtimeAdapter,activationCapability:g,activationMode:t.binding.activationMode,status:t.binding.status},idempotent:t.idempotent,panelContextKey:I.panelContextKey}})}}}function f(n){return{roomId:n.roomId,agentIdentityId:n.agentIdentityId,activationCapability:n.activationCapability??"notify_only",activationMode:n.activationMode??"auto_follow"}}function v(n){if(!n||Array.isArray(n)||typeof n!="object")throw new a("invalid_params","Room Binding parameters are required.");return n}function c(n,i,e){if(typeof n!="string"||!n.trim()||n.length>e)throw new a("invalid_params",`${i} is invalid.`);return n.trim()}function p(n){const i=n??"notify_only";if(i!=="managed"&&i!=="idle_resume"&&i!=="notify_only")throw new a("invalid_params","activationCapability is invalid.");return i}function u(n){const i=n??"auto_follow";if(i!=="auto_follow"&&i!=="mention_only"&&i!=="paused")throw new a("invalid_params","activationMode is invalid.");return i}export{f as buildRoomBindingActionParameters,_ as createRoomBindingIpcHandlers};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DaemonIpcHandler } from '../daemon-ipc/server.js';
|
|
2
|
+
import type { RoomHostSessionObservationStore } from './host-session-observations.js';
|
|
3
|
+
import type { HttpRoomActionClient } from './room-action-client.js';
|
|
4
|
+
import { RoomSessionRegistry } from './session-registry.js';
|
|
5
|
+
export declare function createRoomSessionRegistryIpcHandlers(input: {
|
|
6
|
+
registry: RoomSessionRegistry;
|
|
7
|
+
observations?: RoomHostSessionObservationStore;
|
|
8
|
+
sessionResolver?: Pick<HttpRoomActionClient, 'resolveNativeSession'>;
|
|
9
|
+
getMachineCredentials?: () => {
|
|
10
|
+
machineId?: string;
|
|
11
|
+
machineToken?: string;
|
|
12
|
+
};
|
|
13
|
+
getMachineId?: () => string | undefined;
|
|
14
|
+
}): Record<string, DaemonIpcHandler>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DaemonIpcError as o}from"../daemon-ipc/protocol.js";function I(e){return{"room-session.register":t=>{const i=h(t),s=u(e).machineId?.trim();if(!s)throw new o("machine_not_authorized","This machine is not authorized yet.");const n=e.registry.register({machineId:s,runtimeAdapter:f(i.runtimeAdapter),sourceSessionKey:c(i.sourceSessionKey,"sourceSessionKey",1024),nianSessionId:c(i.nianSessionId,"nianSessionId",512),hostProcessIdentity:c(i.hostProcessIdentity,"hostProcessIdentity",512),capabilities:S(i.capabilities)});return m(n)},"room-session.resolve":async t=>{const i=h(t),s=u(e),n=s.machineId?.trim();if(!n)throw new o("machine_not_authorized","This machine is not authorized yet.");const a=f(i.runtimeAdapter),d=c(i.sourceSessionKey,"sourceSessionKey",1024),y=e.registry.getBySource({machineId:n,runtimeAdapter:a,sourceSessionKey:d});if(y)return m(y);if(!s.machineToken?.trim())throw new o("machine_not_authorized","This machine is not authorized yet.");const r=e.observations?.getBySource({machineId:n,runtimeAdapter:a,sourceSessionKey:d});if(!r||r.lifecycleState==="closed")throw new o("room_session_not_observed","The exact native Agent session has not been observed on this machine.");if(!e.sessionResolver)throw new o("room_session_not_found","Native Agent session is not registered.");const g=await e.sessionResolver.resolveNativeSession({machineToken:s.machineToken,runtimeAdapter:a,sourceSessionKey:d}),p=!!r.workspacePath,l=e.registry.register({machineId:n,runtimeAdapter:a,sourceSessionKey:d,nianSessionId:g.nianSessionId,hostProcessIdentity:`${a}:${r.hostContextHash}:${r.registrationEpoch}`,capabilities:{canIdentifySession:!0,canBindAutomatically:!0,canOpenEmbeddedRoomPage:!1,canResumeIdleSession:p,canActivateWhileHostOpen:!1}});return r.lifecycleState==="idle"&&e.registry.updateLifecycle(l.registryKey,"inactive"),m(e.registry.getByRegistryKey(l.registryKey))}}}function u(e){return e.getMachineCredentials?.()??{machineId:e.getMachineId?.()}}function m(e){return{registryKey:e.registryKey,nianSessionId:e.nianSessionId,panelContextKey:e.panelContextKey,runtimeAdapter:e.runtimeAdapter,registrationEpoch:e.registrationEpoch,lifecycleState:e.lifecycleState,capabilities:e.capabilities,binding:e.binding,lastSeenAt:e.lastSeenAt}}function h(e){if(!e||Array.isArray(e)||typeof e!="object")throw new o("invalid_params","Room session parameters are required.");return e}function c(e,t,i){if(typeof e!="string"||!e.trim()||e.length>i)throw new o("invalid_params",`${t} is invalid.`);return e.trim()}function f(e){const t=c(e,"runtimeAdapter",32);if(t!=="codex"&&t!=="claude_code"&&t!=="workbuddy")throw new o("invalid_params","runtimeAdapter is unsupported.");return t}function S(e){const t=h(e),i=["canIdentifySession","canBindAutomatically","canOpenEmbeddedRoomPage","canResumeIdleSession","canActivateWhileHostOpen"],s={};for(const n of i){if(typeof t[n]!="boolean")throw new o("invalid_params",`${n} must be boolean.`);s[n]=t[n]}return s}export{I as createRoomSessionRegistryIpcHandlers};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { RoomActivationMode, RoomBindingStatus, RoomRuntimeAdapter } from '@shennian/wire';
|
|
2
|
+
export type RoomSessionCapabilities = {
|
|
3
|
+
canIdentifySession: boolean;
|
|
4
|
+
canBindAutomatically: boolean;
|
|
5
|
+
canOpenEmbeddedRoomPage: boolean;
|
|
6
|
+
canResumeIdleSession: boolean;
|
|
7
|
+
canActivateWhileHostOpen: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type RoomSessionBindingState = {
|
|
10
|
+
bindingId: string;
|
|
11
|
+
roomId: string;
|
|
12
|
+
agentIdentityId: string;
|
|
13
|
+
agentMembershipId: string | null;
|
|
14
|
+
status: RoomBindingStatus;
|
|
15
|
+
activationMode: RoomActivationMode;
|
|
16
|
+
lastDeliveredSequence: string;
|
|
17
|
+
lastActivatedSequence: string;
|
|
18
|
+
activationQueue: RoomActivationQueueItem[];
|
|
19
|
+
activeActivation: RoomActivationQueueItem | null;
|
|
20
|
+
loopBreaker: {
|
|
21
|
+
windowStartedAt: string | null;
|
|
22
|
+
activationCount: number;
|
|
23
|
+
pausedUntil: string | null;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
export type RoomActivationQueueItem = {
|
|
27
|
+
causeMessageId: string;
|
|
28
|
+
rootCauseMessageId: string;
|
|
29
|
+
sequence: string;
|
|
30
|
+
hopCount: number;
|
|
31
|
+
enqueuedAt: string;
|
|
32
|
+
attempts: number;
|
|
33
|
+
};
|
|
34
|
+
export type RoomSessionRegistration = {
|
|
35
|
+
schemaVersion: 1;
|
|
36
|
+
registryKey: string;
|
|
37
|
+
machineId: string;
|
|
38
|
+
runtimeAdapter: RoomRuntimeAdapter;
|
|
39
|
+
sourceSessionKey: string;
|
|
40
|
+
nianSessionId: string;
|
|
41
|
+
panelContextKey: string;
|
|
42
|
+
hostProcessIdentity: string;
|
|
43
|
+
registrationEpoch: number;
|
|
44
|
+
lifecycleState: 'active' | 'inactive' | 'closed';
|
|
45
|
+
capabilities: RoomSessionCapabilities;
|
|
46
|
+
binding: RoomSessionBindingState | null;
|
|
47
|
+
registeredAt: string;
|
|
48
|
+
lastSeenAt: string;
|
|
49
|
+
updatedAt: string;
|
|
50
|
+
};
|
|
51
|
+
type RegisterInput = {
|
|
52
|
+
machineId: string;
|
|
53
|
+
runtimeAdapter: RoomRuntimeAdapter;
|
|
54
|
+
sourceSessionKey: string;
|
|
55
|
+
nianSessionId: string;
|
|
56
|
+
hostProcessIdentity: string;
|
|
57
|
+
capabilities: RoomSessionCapabilities;
|
|
58
|
+
now?: Date;
|
|
59
|
+
};
|
|
60
|
+
export declare class RoomSessionRegistryError extends Error {
|
|
61
|
+
readonly code: string;
|
|
62
|
+
constructor(code: string, message: string);
|
|
63
|
+
}
|
|
64
|
+
export declare class RoomSessionRegistry {
|
|
65
|
+
readonly filePath: string;
|
|
66
|
+
private state;
|
|
67
|
+
private readonly mutexTails;
|
|
68
|
+
constructor(filePath?: string);
|
|
69
|
+
register(input: RegisterInput): RoomSessionRegistration;
|
|
70
|
+
getBySource(input: Pick<RegisterInput, 'machineId' | 'runtimeAdapter' | 'sourceSessionKey'>): RoomSessionRegistration | null;
|
|
71
|
+
getByNianSessionId(nianSessionId: string): RoomSessionRegistration | null;
|
|
72
|
+
getByRegistryKey(registryKey: string): RoomSessionRegistration | null;
|
|
73
|
+
list(): RoomSessionRegistration[];
|
|
74
|
+
setBinding(input: {
|
|
75
|
+
registryKey: string;
|
|
76
|
+
bindingId: string;
|
|
77
|
+
roomId: string;
|
|
78
|
+
agentIdentityId: string;
|
|
79
|
+
agentMembershipId: string | null;
|
|
80
|
+
status: RoomBindingStatus;
|
|
81
|
+
activationMode?: RoomActivationMode;
|
|
82
|
+
now?: Date;
|
|
83
|
+
}): RoomSessionRegistration;
|
|
84
|
+
detachBinding(registryKey: string, now?: Date): RoomSessionRegistration;
|
|
85
|
+
advanceCursor(input: {
|
|
86
|
+
registryKey: string;
|
|
87
|
+
cursor: 'delivered' | 'activated';
|
|
88
|
+
sequence: string;
|
|
89
|
+
now?: Date;
|
|
90
|
+
}): RoomSessionRegistration;
|
|
91
|
+
enqueueActivation(registryKey: string, item: RoomActivationQueueItem, now?: Date): RoomSessionRegistration;
|
|
92
|
+
dequeueActivation(registryKey: string, causeMessageId: string, now?: Date): RoomSessionRegistration;
|
|
93
|
+
markActivationDispatching(registryKey: string, causeMessageId: string, now?: Date): RoomSessionRegistration;
|
|
94
|
+
clearActiveActivation(registryKey: string, now?: Date): RoomSessionRegistration;
|
|
95
|
+
retryActiveActivation(input: {
|
|
96
|
+
registryKey: string;
|
|
97
|
+
maxAttempts: number;
|
|
98
|
+
pauseMs: number;
|
|
99
|
+
now?: Date;
|
|
100
|
+
}): {
|
|
101
|
+
queued: boolean;
|
|
102
|
+
attempts: number;
|
|
103
|
+
};
|
|
104
|
+
claimActivation(input: {
|
|
105
|
+
registryKey: string;
|
|
106
|
+
windowMs: number;
|
|
107
|
+
maxActivations: number;
|
|
108
|
+
pauseMs: number;
|
|
109
|
+
now?: Date;
|
|
110
|
+
}): {
|
|
111
|
+
allowed: boolean;
|
|
112
|
+
pausedUntil: string | null;
|
|
113
|
+
newlyPaused?: boolean;
|
|
114
|
+
};
|
|
115
|
+
updateLifecycle(registryKey: string, lifecycleState: 'active' | 'inactive' | 'closed', now?: Date): RoomSessionRegistration;
|
|
116
|
+
runExclusive<T>(registryKey: string, operation: () => Promise<T>): Promise<T>;
|
|
117
|
+
private requireRecord;
|
|
118
|
+
private requireBoundRecord;
|
|
119
|
+
private touchAndPersist;
|
|
120
|
+
private load;
|
|
121
|
+
private persist;
|
|
122
|
+
}
|
|
123
|
+
export declare function buildRoomSessionRegistryKey(input: {
|
|
124
|
+
machineId: string;
|
|
125
|
+
runtimeAdapter: RoomRuntimeAdapter;
|
|
126
|
+
sourceSessionKey: string;
|
|
127
|
+
}): string;
|
|
128
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import y from"node:crypto";import c from"node:fs";import b from"node:path";import{resolveShennianPath as S}from"../config/index.js";const _=500,R=/^[A-Za-z0-9_.:@/-]{1,512}$/,q=new Set(["codex","claude_code","workbuddy"]),p=new Set(["pending_approval","active","paused","detached"]),I=new Set(["auto_follow","mention_only","paused"]);class o extends Error{code;constructor(e,t){super(t),this.code=e,this.name="RoomSessionRegistryError"}}class T{filePath;state;mutexTails=new Map;constructor(e=S("runtime","room-session-registry.json")){this.filePath=e,this.state=this.load()}register(e){r(e.machineId,"machine_id"),v(e.runtimeAdapter),w(e.sourceSessionKey),r(e.nianSessionId,"nian_session_id"),r(e.hostProcessIdentity,"host_process_identity"),A(e.capabilities);const t=m(e),s=(e.now??new Date).toISOString(),n=this.state.records[t];if(Object.values(this.state.records).find(g=>g.registryKey!==t&&g.nianSessionId===e.nianSessionId&&g.lifecycleState!=="closed"))throw new o("nian_session_already_registered","This Shennian session is already registered to another native Agent session.");const u=!!(n&&n.hostProcessIdentity!==e.hostProcessIdentity),l={schemaVersion:1,registryKey:t,machineId:e.machineId,runtimeAdapter:e.runtimeAdapter,sourceSessionKey:e.sourceSessionKey,nianSessionId:e.nianSessionId,panelContextKey:e.nianSessionId,hostProcessIdentity:e.hostProcessIdentity,registrationEpoch:n?n.registrationEpoch+(u?1:0):1,lifecycleState:"active",capabilities:{...e.capabilities},binding:n?.binding??null,registeredAt:n?.registeredAt??s,lastSeenAt:s,updatedAt:s};return this.state.records[t]=l,this.persist(),d(l)}getBySource(e){const t=this.state.records[m(e)];return t?d(t):null}getByNianSessionId(e){r(e,"nian_session_id");const t=Object.values(this.state.records).find(s=>s.nianSessionId===e&&s.lifecycleState!=="closed");return t?d(t):null}getByRegistryKey(e){if(!/^[a-f0-9]{64}$/.test(e))throw new o("invalid_registry_key","Invalid Room session registry key.");const t=this.state.records[e];return t?d(t):null}list(){return Object.values(this.state.records).sort((e,t)=>e.registeredAt.localeCompare(t.registeredAt)).map(d)}setBinding(e){const t=this.requireRecord(e.registryKey);for(const[n,a]of Object.entries({binding_id:e.bindingId,room_id:e.roomId,agent_identity_id:e.agentIdentityId}))r(a,n);if(!p.has(e.status))throw new o("invalid_binding_status","Invalid binding status.");if(e.status==="pending_approval"&&e.agentMembershipId!==null||(e.status==="active"||e.status==="paused")&&e.agentMembershipId===null)throw new o("invalid_agent_membership_id","Pending Room bindings cannot claim an Agent membership.");e.agentMembershipId!==null&&r(e.agentMembershipId,"agent_membership_id");const s=e.activationMode??"auto_follow";if(!I.has(s))throw new o("invalid_activation_mode","Invalid activation mode.");if(t.binding&&t.binding.status!=="detached"&&(t.binding.bindingId!==e.bindingId||t.binding.roomId!==e.roomId))throw new o("session_already_bound","An Agent session can have only one active Room binding.");return t.binding={bindingId:e.bindingId,roomId:e.roomId,agentIdentityId:e.agentIdentityId,agentMembershipId:e.agentMembershipId,status:e.status,activationMode:s,lastDeliveredSequence:t.binding?.lastDeliveredSequence??"0",lastActivatedSequence:t.binding?.lastActivatedSequence??"0",activationQueue:t.binding?.activationQueue??[],activeActivation:t.binding?.activeActivation??null,loopBreaker:t.binding?.loopBreaker??{windowStartedAt:null,activationCount:0,pausedUntil:null}},this.touchAndPersist(t,e.now),d(t)}detachBinding(e,t=new Date){const s=this.requireRecord(e);return s.binding&&(s.binding.status="detached",s.binding.activationMode="paused",s.binding.activationQueue=[]),this.touchAndPersist(s,t),d(s)}advanceCursor(e){const t=this.requireBoundRecord(e.registryKey);h(e.sequence);const s=e.cursor==="delivered"?"lastDeliveredSequence":"lastActivatedSequence";if(BigInt(e.sequence)<BigInt(t.binding[s]))throw new o("cursor_regression","Room cursor cannot move backwards.");return t.binding[s]=e.sequence,this.touchAndPersist(t,e.now),d(t)}enqueueActivation(e,t,s=new Date){const n=this.requireBoundRecord(e);f(t);const a=n.binding.activationQueue;if(!a.some(u=>u.causeMessageId===t.causeMessageId)){if(a.length>=_)throw new o("activation_queue_full","Agent activation queue is full.");a.push(d(t))}return this.touchAndPersist(n,s),d(n)}dequeueActivation(e,t,s=new Date){const n=this.requireBoundRecord(e);return n.binding.activationQueue=n.binding.activationQueue.filter(a=>a.causeMessageId!==t),this.touchAndPersist(n,s),d(n)}markActivationDispatching(e,t,s=new Date){const n=this.requireBoundRecord(e),a=n.binding.activationQueue.find(u=>u.causeMessageId===t);if(!a)throw new o("activation_not_found","Agent activation is unavailable.");return n.binding.activeActivation=d(a),n.binding.activationQueue=n.binding.activationQueue.filter(u=>u.causeMessageId!==t),this.touchAndPersist(n,s),d(n)}clearActiveActivation(e,t=new Date){const s=this.requireBoundRecord(e);return s.binding.activeActivation=null,this.touchAndPersist(s,t),d(s)}retryActiveActivation(e){const t=this.requireBoundRecord(e.registryKey),s=t.binding.activeActivation;if(!s)return{queued:!1,attempts:0};const n=e.now??new Date,a={...s,attempts:s.attempts+1};return t.binding.activeActivation=null,a.attempts<e.maxAttempts?(t.binding.activationQueue.some(u=>u.causeMessageId===a.causeMessageId)||t.binding.activationQueue.unshift(a),this.touchAndPersist(t,n),{queued:!0,attempts:a.attempts}):(t.binding.loopBreaker.pausedUntil=new Date(n.getTime()+e.pauseMs).toISOString(),this.touchAndPersist(t,n),{queued:!1,attempts:a.attempts})}claimActivation(e){const t=this.requireBoundRecord(e.registryKey),s=e.now??new Date,n=t.binding.loopBreaker;return n.pausedUntil&&Date.parse(n.pausedUntil)>s.getTime()?{allowed:!1,pausedUntil:n.pausedUntil,newlyPaused:!1}:((!n.windowStartedAt||s.getTime()-Date.parse(n.windowStartedAt)>=e.windowMs)&&(n.windowStartedAt=s.toISOString(),n.activationCount=0,n.pausedUntil=null),n.activationCount>=e.maxActivations?(n.pausedUntil=new Date(s.getTime()+e.pauseMs).toISOString(),this.touchAndPersist(t,s),{allowed:!1,pausedUntil:n.pausedUntil,newlyPaused:!0}):(n.activationCount+=1,this.touchAndPersist(t,s),{allowed:!0,pausedUntil:null}))}updateLifecycle(e,t,s=new Date){const n=this.requireRecord(e);return n.lifecycleState=t,t==="closed"&&n.binding&&(n.binding.status="detached",n.binding.activationMode="paused",n.binding.activationQueue=[]),this.touchAndPersist(n,s),d(n)}async runExclusive(e,t){this.requireRecord(e);const s=this.mutexTails.get(e)??Promise.resolve();let n;const a=new Promise(l=>{n=l}),u=s.then(()=>a);this.mutexTails.set(e,u),await s;try{return await t()}finally{n(),this.mutexTails.get(e)===u&&this.mutexTails.delete(e)}}requireRecord(e){const t=this.state.records[e];if(!t)throw new o("session_registration_not_found","Agent session is not registered.");return t}requireBoundRecord(e){const t=this.requireRecord(e);if(!t.binding||t.binding.status!=="active"&&t.binding.status!=="paused")throw new o("session_not_bound","Agent session has no active Room binding.");return t}touchAndPersist(e,t=new Date){e.updatedAt=t.toISOString(),this.persist()}load(){try{const e=c.lstatSync(this.filePath);if(!e.isFile()||e.isSymbolicLink())throw new o("unsafe_session_registry","Room session registry is not a regular file.");process.platform!=="win32"&&(e.mode&63)!==0&&c.chmodSync(this.filePath,384);const t=JSON.parse(c.readFileSync(this.filePath,"utf8"));return P(t)}catch(e){if(B(e))return{schemaVersion:1,records:{}};throw e instanceof o?e:new o("corrupt_session_registry","Room Agent session registry is corrupt.")}}persist(){const e=b.dirname(this.filePath);c.mkdirSync(e,{recursive:!0,mode:448}),process.platform!=="win32"&&c.chmodSync(e,448);const t=`${this.filePath}.tmp-${process.pid}-${y.randomBytes(6).toString("hex")}`;try{if(c.writeFileSync(t,`${JSON.stringify(this.state,null,2)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"}),process.platform!=="win32"&&c.chmodSync(t,384),process.platform==="win32"&&c.existsSync(this.filePath)){const s=c.lstatSync(this.filePath);if(!s.isFile()||s.isSymbolicLink())throw new o("unsafe_session_registry","Refusing to replace an unsafe Room session registry.");c.unlinkSync(this.filePath)}c.renameSync(t,this.filePath),process.platform!=="win32"&&c.chmodSync(this.filePath,384)}finally{try{c.unlinkSync(t)}catch{}}}}function m(i){return r(i.machineId,"machine_id"),v(i.runtimeAdapter),w(i.sourceSessionKey),y.createHash("sha256").update(`${i.machineId}\0${i.runtimeAdapter}\0${i.sourceSessionKey}`,"utf8").digest("hex")}function P(i){if(!i||typeof i!="object"||i.schemaVersion!==1)throw new o("corrupt_session_registry","Unsupported Room session registry.");const e=i.records;if(!e||typeof e!="object"||Array.isArray(e))throw new o("corrupt_session_registry","Room session records are invalid.");const t={};for(const[s,n]of Object.entries(e)){if(M(n),s!==n.registryKey||s!==m(n))throw new o("corrupt_session_registry","Room session registry key mismatch.");t[s]={...n,binding:n.binding?{...n.binding,activeActivation:n.binding.activeActivation??null}:null}}return{schemaVersion:1,records:t}}function M(i){if(!i||i.schemaVersion!==1)throw new o("corrupt_session_registry","Invalid registration.");if(r(i.machineId,"machine_id"),v(i.runtimeAdapter),w(i.sourceSessionKey),r(i.nianSessionId,"nian_session_id"),r(i.hostProcessIdentity,"host_process_identity"),i.panelContextKey!==i.nianSessionId)throw new o("corrupt_session_registry","Invalid panel context.");if(!Number.isInteger(i.registrationEpoch)||i.registrationEpoch<1)throw new o("corrupt_session_registry","Invalid registration epoch.");A(i.capabilities),i.binding&&x(i.binding)}function x(i){if(r(i.bindingId,"binding_id"),r(i.roomId,"room_id"),r(i.agentIdentityId,"agent_identity_id"),!p.has(i.status))throw new o("corrupt_session_registry","Invalid binding status.");if(i.status==="pending_approval"&&i.agentMembershipId!==null||(i.status==="active"||i.status==="paused")&&i.agentMembershipId===null)throw new o("corrupt_session_registry","Invalid Agent membership.");if(i.agentMembershipId!==null&&r(i.agentMembershipId,"agent_membership_id"),!I.has(i.activationMode))throw new o("corrupt_session_registry","Invalid activation mode.");if(h(i.lastDeliveredSequence),h(i.lastActivatedSequence),!Array.isArray(i.activationQueue)||i.activationQueue.length>_)throw new o("corrupt_session_registry","Invalid activation queue.");i.activationQueue.forEach(f),i.activeActivation!=null&&f(i.activeActivation)}function f(i){if(r(i.causeMessageId,"cause_message_id"),r(i.rootCauseMessageId,"root_cause_message_id"),h(i.sequence),!Number.isInteger(i.hopCount)||i.hopCount<0||i.hopCount>32)throw new o("invalid_hop_count","Invalid Agent activation hop count.");if(!Number.isInteger(i.attempts)||i.attempts<0||i.attempts>100)throw new o("invalid_activation_attempts","Invalid Agent activation attempts.");if(!Number.isFinite(new Date(i.enqueuedAt).getTime()))throw new o("invalid_activation_time","Invalid Agent activation time.")}function A(i){if(!i||["canIdentifySession","canBindAutomatically","canOpenEmbeddedRoomPage","canResumeIdleSession","canActivateWhileHostOpen"].some(t=>typeof i[t]!="boolean"))throw new o("invalid_session_capabilities","Invalid Agent session capabilities.")}function v(i){if(!q.has(i))throw new o("invalid_runtime_adapter","Unsupported Room runtime adapter.")}function w(i){if(!i||i.length>1024||/[\0\r\n]/.test(i))throw new o("invalid_source_session_key","Invalid native Agent session key.")}function r(i,e){if(!R.test(i))throw new o(`invalid_${e}`,`Invalid ${e}.`)}function h(i){if(!/^(0|[1-9]\d{0,19})$/.test(i))throw new o("invalid_room_sequence","Invalid Room sequence.")}function d(i){return structuredClone(i)}function B(i){return typeof i=="object"&&i!==null&&"code"in i&&i.code==="ENOENT"}export{T as RoomSessionRegistry,o as RoomSessionRegistryError,m as buildRoomSessionRegistryKey};
|