shennian 0.3.1 → 0.3.2
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 +273 -343
- 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/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/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 +23 -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/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-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 +208 -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 +114 -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/manager.d.ts +16 -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/index.d.ts +2 -1
- package/node_modules/@shennian/wire/dist/index.d.ts.map +1 -1
- package/node_modules/@shennian/wire/dist/index.js +2 -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 +2 -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 @@
|
|
|
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}}),l=i?"idle_resume":"notify_only",y=`${n.action.replace(".","-")}:${e.id}`,h={machineToken:s.machineToken,bindingIntentId:y,nianSessionId:c.nianSessionId,runtimeAdapter:n.runtimeAdapter,sessionRegistryKey:p.registryKey,agentAlias:n.parameters.agentAlias,activationCapability:l,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),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};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { JsonValue } from './pending-authorized-actions.js';
|
|
2
|
+
import type { RoomInvocationAction } from './invocation-token.js';
|
|
3
|
+
export declare const SHENNIAN_ROOM_TOOL_NAME = "shennian_room";
|
|
4
|
+
export declare const SHENNIAN_ROOM_TOOL: {
|
|
5
|
+
readonly name: "shennian_room";
|
|
6
|
+
readonly title: "Shennian Room";
|
|
7
|
+
readonly description: "Create, join, read, search, send to, configure, or inspect the single Shennian Room bound to this Agent session.";
|
|
8
|
+
readonly inputSchema: {
|
|
9
|
+
readonly type: "object";
|
|
10
|
+
readonly additionalProperties: false;
|
|
11
|
+
readonly required: readonly ["action"];
|
|
12
|
+
readonly properties: {
|
|
13
|
+
readonly action: {
|
|
14
|
+
readonly type: "string";
|
|
15
|
+
readonly enum: readonly ["create", "join", "read", "send", "mode", "status"];
|
|
16
|
+
readonly description: "The Room action to perform.";
|
|
17
|
+
};
|
|
18
|
+
readonly name: {
|
|
19
|
+
readonly type: "string";
|
|
20
|
+
readonly minLength: 1;
|
|
21
|
+
readonly maxLength: 80;
|
|
22
|
+
};
|
|
23
|
+
readonly agentAlias: {
|
|
24
|
+
readonly type: "string";
|
|
25
|
+
readonly minLength: 1;
|
|
26
|
+
readonly maxLength: 80;
|
|
27
|
+
};
|
|
28
|
+
readonly inviteUrl: {
|
|
29
|
+
readonly type: "string";
|
|
30
|
+
readonly format: "uri";
|
|
31
|
+
readonly maxLength: 2048;
|
|
32
|
+
};
|
|
33
|
+
readonly message: {
|
|
34
|
+
readonly type: "string";
|
|
35
|
+
readonly maxLength: 500;
|
|
36
|
+
};
|
|
37
|
+
readonly activationMode: {
|
|
38
|
+
readonly type: "string";
|
|
39
|
+
readonly enum: readonly ["auto", "auto_follow", "mention", "mention_only", "paused"];
|
|
40
|
+
};
|
|
41
|
+
readonly afterSequence: {
|
|
42
|
+
readonly type: "string";
|
|
43
|
+
readonly pattern: "^(0|[1-9]\\d{0,19})$";
|
|
44
|
+
};
|
|
45
|
+
readonly limit: {
|
|
46
|
+
readonly type: "integer";
|
|
47
|
+
readonly minimum: 1;
|
|
48
|
+
readonly maximum: 100;
|
|
49
|
+
};
|
|
50
|
+
readonly query: {
|
|
51
|
+
readonly type: "string";
|
|
52
|
+
readonly minLength: 1;
|
|
53
|
+
readonly maxLength: 200;
|
|
54
|
+
};
|
|
55
|
+
readonly attachmentIds: {
|
|
56
|
+
readonly type: "array";
|
|
57
|
+
readonly maxItems: 10;
|
|
58
|
+
readonly uniqueItems: true;
|
|
59
|
+
readonly items: {
|
|
60
|
+
readonly type: "string";
|
|
61
|
+
readonly minLength: 1;
|
|
62
|
+
readonly maxLength: 191;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
readonly clientMessageId: {
|
|
66
|
+
readonly type: "string";
|
|
67
|
+
readonly minLength: 1;
|
|
68
|
+
readonly maxLength: 191;
|
|
69
|
+
};
|
|
70
|
+
readonly text: {
|
|
71
|
+
readonly type: "string";
|
|
72
|
+
readonly minLength: 1;
|
|
73
|
+
readonly maxLength: 20000;
|
|
74
|
+
};
|
|
75
|
+
readonly files: {
|
|
76
|
+
readonly type: "array";
|
|
77
|
+
readonly description: "Up to 10 files inside the current Agent workspace to upload privately with this message.";
|
|
78
|
+
readonly minItems: 1;
|
|
79
|
+
readonly maxItems: 10;
|
|
80
|
+
readonly items: {
|
|
81
|
+
readonly type: "string";
|
|
82
|
+
readonly minLength: 1;
|
|
83
|
+
readonly maxLength: 4096;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
readonly mentionMembershipIds: {
|
|
87
|
+
readonly type: "array";
|
|
88
|
+
readonly maxItems: 20;
|
|
89
|
+
readonly uniqueItems: true;
|
|
90
|
+
readonly items: {
|
|
91
|
+
readonly type: "string";
|
|
92
|
+
readonly minLength: 1;
|
|
93
|
+
readonly maxLength: 191;
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
readonly replyToMessageId: {
|
|
97
|
+
readonly type: "string";
|
|
98
|
+
readonly minLength: 1;
|
|
99
|
+
readonly maxLength: 191;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
export declare function normalizeRoomToolInput(value: unknown): {
|
|
105
|
+
action: Exclude<RoomInvocationAction, 'room.bind'>;
|
|
106
|
+
actionParameters: JsonValue;
|
|
107
|
+
registryKey?: string;
|
|
108
|
+
invocationToken?: string;
|
|
109
|
+
authorizedActionId?: string;
|
|
110
|
+
};
|
|
111
|
+
export declare class RoomToolInputError extends Error {
|
|
112
|
+
readonly code: string;
|
|
113
|
+
constructor(code: string, message: string);
|
|
114
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{normalizeRoomActionParameters as c}from"./room-action-schema.js";const d="shennian_room",l={name:d,title:"Shennian Room",description:"Create, join, read, search, send to, configure, or inspect the single Shennian Room bound to this Agent session.",inputSchema:{type:"object",additionalProperties:!1,required:["action"],properties:{action:{type:"string",enum:["create","join","read","send","mode","status"],description:"The Room action to perform."},name:{type:"string",minLength:1,maxLength:80},agentAlias:{type:"string",minLength:1,maxLength:80},inviteUrl:{type:"string",format:"uri",maxLength:2048},message:{type:"string",maxLength:500},activationMode:{type:"string",enum:["auto","auto_follow","mention","mention_only","paused"]},afterSequence:{type:"string",pattern:"^(0|[1-9]\\d{0,19})$"},limit:{type:"integer",minimum:1,maximum:100},query:{type:"string",minLength:1,maxLength:200},attachmentIds:{type:"array",maxItems:10,uniqueItems:!0,items:{type:"string",minLength:1,maxLength:191}},clientMessageId:{type:"string",minLength:1,maxLength:191},text:{type:"string",minLength:1,maxLength:2e4},files:{type:"array",description:"Up to 10 files inside the current Agent workspace to upload privately with this message.",minItems:1,maxItems:10,items:{type:"string",minLength:1,maxLength:4096}},mentionMembershipIds:{type:"array",maxItems:20,uniqueItems:!0,items:{type:"string",minLength:1,maxLength:191}},replyToMessageId:{type:"string",minLength:1,maxLength:191}}}},u=new Map([["create","room.create"],["join","room.join"],["read","room.read"],["send","room.send"],["mode","room.mode"],["status","room.status"]]);function f(o){(!o||typeof o!="object"||Array.isArray(o))&&g();const t=o,n=typeof t.action=="string"?u.get(t.action):void 0;n||g();const i=t._shennianRegistryKey,r=t._shennianInvocationToken,s=t._shennianAuthorizedActionId,a=Object.keys(t).filter(e=>e.startsWith("_shennian"));if(typeof s=="string"&&/^[A-Za-z0-9_-]{8,128}$/.test(s)&&a.length===1){const e=Object.fromEntries(Object.entries(t).filter(([m])=>m!=="action"&&m!=="_shennianAuthorizedActionId"));return{action:n,actionParameters:c(n,e),authorizedActionId:s}}if(typeof i!="string"||!/^[a-f0-9]{64}$/.test(i)||typeof r!="string"||!/^sni_v1_[A-Za-z0-9_-]{40,80}$/.test(r)||a.some(e=>e!=="_shennianRegistryKey"&&e!=="_shennianInvocationToken"))throw new p("session_context_required","The current Agent session is not connected to Shennian Room yet.");const h=Object.fromEntries(Object.entries(t).filter(([e])=>e!=="action"&&e!=="_shennianRegistryKey"&&e!=="_shennianInvocationToken"));return{action:n,actionParameters:c(n,h),registryKey:i,invocationToken:r}}class p extends Error{code;constructor(t,n){super(n),this.code=t,this.name="RoomToolInputError"}}function g(){throw new p("invalid_tool_input","Invalid Shennian Room tool input.")}export{p as RoomToolInputError,l as SHENNIAN_ROOM_TOOL,d as SHENNIAN_ROOM_TOOL_NAME,f as normalizeRoomToolInput};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { callDaemonIpc } from '../daemon-ipc/client.js';
|
|
2
|
+
import type { JsonValue } from './pending-authorized-actions.js';
|
|
3
|
+
export declare function executeRoomTool(rawInput: unknown, invoke?: typeof callDaemonIpc): Promise<JsonValue>;
|
|
4
|
+
export declare function handleRoomToolRpc(value: unknown, invoke?: typeof callDaemonIpc): Promise<Record<string, unknown> | null>;
|
|
5
|
+
export declare function runRoomToolServer(input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream): Promise<void>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import f from"node:readline";import{callDaemonIpc as u}from"../daemon-ipc/client.js";import{DaemonIpcError as l}from"../daemon-ipc/protocol.js";import{normalizeRoomToolInput as m,RoomToolInputError as d,SHENNIAN_ROOM_TOOL as p,SHENNIAN_ROOM_TOOL_NAME as y}from"./tool-schema.js";async function h(t,r=u){const o=m(t);return o.authorizedActionId?r({method:"authorized-action.wait",params:{id:o.authorizedActionId,timeoutMs:12e4},timeoutMs:135e3}):r({method:"room-action.execute",params:{registryKey:o.registryKey,invocationToken:o.invocationToken,action:o.action,actionParameters:o.actionParameters},timeoutMs:o.action==="room.read"?65e3:15e3})}async function g(t,r=u){if(!t||typeof t!="object"||Array.isArray(t))return a(null,-32600,"Invalid Request");const o=t,e=I(o.id);if(o.jsonrpc!=="2.0"||typeof o.method!="string")return a(e,-32600,"Invalid Request");if(o.method.startsWith("notifications/"))return null;if(o.method==="initialize")return s(e,{protocolVersion:O(o.params),capabilities:{tools:{listChanged:!1}},serverInfo:{name:"shennian-room",version:"1.0.0"}});if(o.method==="ping")return s(e,{});if(o.method==="tools/list")return s(e,{tools:[p]});if(o.method!=="tools/call")return a(e,-32601,"Method not found");const i=N(o.params);if(!i||i.name!==y)return a(e,-32602,"Invalid params");try{const n=await h(i.arguments,r);return s(e,{content:[{type:"text",text:JSON.stringify(n)}],structuredContent:n,isError:!1})}catch(n){const c=R(n);return s(e,{content:[{type:"text",text:JSON.stringify(c)}],structuredContent:c,isError:!0})}}async function E(t=process.stdin,r=process.stdout){const o=f.createInterface({input:t,crlfDelay:1/0});for await(const e of o){if(!e.trim())continue;let i;try{i=JSON.parse(e)}catch{r.write(`${JSON.stringify(a(null,-32700,"Parse error"))}
|
|
2
|
+
`);continue}const n=await g(i);n&&r.write(`${JSON.stringify(n)}
|
|
3
|
+
`)}}function I(t){return typeof t=="string"||typeof t=="number"||t===null?t:null}function O(t){if(t&&typeof t=="object"){const r=t.protocolVersion;if(typeof r=="string"&&/^\d{4}-\d{2}-\d{2}$/.test(r))return r}return"2025-06-18"}function N(t){if(!t||typeof t!="object"||Array.isArray(t))return null;const r=t;return typeof r.name=="string"?{name:r.name,arguments:r.arguments??{}}:null}function R(t){return t instanceof d||t instanceof l?{ok:!1,error:{code:t.code,message:t.message}}:{ok:!1,error:{code:"room_tool_failed",message:"Shennian Room action failed."}}}function s(t,r){return{jsonrpc:"2.0",id:t,result:r}}function a(t,r,o){return{jsonrpc:"2.0",id:t,error:{code:r,message:o}}}export{h as executeRoomTool,g as handleRoomToolRpc,E as runRoomToolServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isNativeCapabilityProvider as o,listAgentNativeCapabilities as n}from"../../agents/native-capabilities.js";async function c(s,t){const i=typeof t.params.agentType=="string"?t.params.agentType:"",e=typeof t.params.workDir=="string"?t.params.workDir:process.cwd(),a=o(i),p={supported:a,agentType:i,capabilities:a?n({agentType:i,workDir:e}):[]};s.client.sendRes({type:"res",id:t.id,ok:!0,payload:p})}export{c as handleAgentCapabilitiesList};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mkdir as y}from"node:fs/promises";import{createAgent as w}from"../../agents/adapter.js";import{buildManagedAgentEnv as h,deleteManagedAgentProviderConfig as A,getAgentConfigSummary as s,upsertManagedAgentProviderConfig as E}from"../../agents/config-status.js";import{resolveShennianPath as T}from"../../config/index.js";import{handleAgentsRefresh as C}from"./agents.js";const k=3e4,R="\u8FD9\u662F\u4E00\u6B21\u795E\u5FF5\u8FDE\u63A5\u6D4B\u8BD5\u3002\u8BF7\u53EA\u56DE\u590D OK\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002",p=T("tmp","agent-config-test");function c(
|
|
1
|
+
import{mkdir as y}from"node:fs/promises";import{createAgent as w}from"../../agents/adapter.js";import{buildManagedAgentEnv as h,deleteManagedAgentProviderConfig as A,getAgentConfigSummary as s,upsertManagedAgentProviderConfig as E}from"../../agents/config-status.js";import{resolveShennianPath as T}from"../../config/index.js";import{handleAgentsRefresh as C}from"./agents.js";const k=3e4,R="\u8FD9\u662F\u4E00\u6B21\u795E\u5FF5\u8FDE\u63A5\u6D4B\u8BD5\u3002\u8BF7\u53EA\u56DE\u590D OK\uFF0C\u4E0D\u8981\u89E3\u91CA\u3002",p=T("tmp","agent-config-test");function c(t){if(t==="codex"||t==="claude")return t;throw new Error("Only Codex, Claude Code, and Nian provider config are supported")}async function O(t,e){const n=c(e.params.agent);t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{agent:n,config:s(n)}})}async function G(t,e){const n=c(e.params.agent),r=typeof e.params.baseUrl=="string"?e.params.baseUrl.trim():void 0,o=typeof e.params.token=="string"?e.params.token.trim():void 0;if(!r&&!o)throw new Error("Base URL or token is required");E({agent:n,baseUrl:r,token:o}),t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{agent:n,config:s(n)}}),await m(t)}async function N(t,e){const n=c(e.params.agent);A(n),t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{agent:n,config:s(n)}}),await m(t)}async function $(t,e){const n=c(e.params.agent),r=s(n);try{const o=await x(n);t.client.sendRes({type:"res",id:e.id,ok:!0,payload:{agent:n,config:s(n),test:o}})}catch(o){t.client.sendRes({type:"res",id:e.id,ok:!1,payload:{agent:n,config:r},error:o instanceof Error?o.message:String(o)})}}async function x(t){const e=w(t);if(!e)throw new Error(`Unsupported agent: ${t}`);const n=`agent-test-${t}-${Date.now()}`;await y(p,{recursive:!0});let r=!1,o=()=>{};const g=new Promise((d,i)=>{const l=setTimeout(()=>{r||(r=!0,i(new Error("Agent test timed out after 30 seconds")))},k);function u(a){r||(r=!0,clearTimeout(l),d(a))}function f(a){r||(r=!0,clearTimeout(l),i(a))}o=f,e.on("agentEvent",a=>{if(a.state==="delta"&&a.text&&!a.thinking){u({mode:"agent-run",reply:a.text.slice(0,120)});return}if(a.state==="final"){u({mode:"agent-run"});return}a.state==="error"&&f(new Error(a.message||"Agent test failed"))}),e.on("error",f)});try{e.configure?.({sessionId:n,env:_(t)}),await e.start(n,p,null);const d=e.send(R).catch(i=>{o(i instanceof Error?i:new Error(String(i)))});return await Promise.race([g,d.then(()=>g)])}finally{e.removeAllListeners(),await e.stop().catch(()=>{})}}async function m(t){const e={type:"req",id:`agent-config-refresh-${Date.now()}`,method:"agents.refresh",params:{}};await C(t,e)}function _(t){return t==="codex"||t==="claude"?h(t):{}}export{_ as getManagedEnvForAgent,N as handleAgentConfigClear,O as handleAgentConfigGet,$ as handleAgentConfigTest,G as handleAgentConfigUpsert};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
`),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function ee(t,e,a={}){if(t.state==="tool-call"||t.state==="tool-result"){const s={runId:t.runId,sourceSeq:t.seq};return{state:t.state,runId:t.runId,seq:t.seq,sessionId:e,detailRef:s,...t.name?{name:t.name}:{},...t.source?{source:t.source}:{},...t.agentSessionId?{agentSessionId:t.agentSessionId}:{},...a}}return{...t,sessionId:e,...a}}const te=3e4;function ne(t){return t.state==="heartbeat"?t.runPhase??null:t.state==="tool-call"||t.state==="tool-result"?"tool_running":t.state==="approval-pending"?"waiting_approval":t.state==="delta"?t.thinking?"thinking":"streaming_text":t.state==="init"||t.state==="start"?"thinking":null}function ae(t,e){const a=e instanceof Error?e.message:String(e);return t==="pi"?X(a):`Agent send failed: ${a}`}function B(t,e){return t!=="manager"?t:e==="claude"?"claude":"codex"}function L(t,e,a){t.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:e.sessionId,message:e,session:{id:e.sessionId,agentType:a.agentType,agentSessionId:a.agentSessionId??null,modelId:a.modelId??null,workDir:a.workDir,status:"active",externalChannel:H(t,e.sessionId,a.agentType)}}})}function re(t,e){v({sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e.sessionId,agentType:e.agentType,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,workDir:e.workDir,status:"active",externalChannel:H(t,e.sessionId,e.agentType)}}})}function se(t){if(!t||typeof t!="object")return null;const e=t;return{configured:e.configured===void 0?void 0:!!e.configured,connected:!!e.connected,type:typeof e.type=="string"?e.type:null,channelId:typeof e.channelId=="string"?e.channelId:null,name:typeof e.name=="string"?e.name:null,canReply:e.canReply===void 0||e.canReply===null?null:!!e.canReply,systemPrompt:typeof e.systemPrompt=="string"?e.systemPrompt:null,wechatRpaSource:typeof e.wechatRpaSource=="string"?e.wechatRpaSource:null,wechatRpaGroups:Array.isArray(e.wechatRpaGroups)?e.wechatRpaGroups.map(a=>({name:String(a?.name||"").trim()})).filter(a=>a.name):null,pollIntervalMs:Number.isFinite(e.pollIntervalMs)?Number(e.pollIntervalMs):null,recentLimit:Number.isFinite(e.recentLimit)?Number(e.recentLimit):null,idleSeconds:Number.isFinite(e.idleSeconds)?Number(e.idleSeconds):null,forceForeground:e.forceForeground===void 0||e.forceForeground===null?null:!!e.forceForeground,noRestore:e.noRestore===void 0||e.noRestore===null?null:!!e.noRestore,downloadAttachments:e.downloadAttachments===void 0||e.downloadAttachments===null?null:!!e.downloadAttachments,downloadAttachmentsDir:typeof e.downloadAttachmentsDir=="string"?e.downloadAttachmentsDir:null}}function oe(t){return!!(t?.configured??t?.connected)}function z(t){return K(t)}function W(t,e,a){return oe(e)?{...Q()?.getInjectedEnv(t,null,process.cwd(),"external")??{},SHENNIAN_EXTERNAL_SESSION_ID:t,SHENNIAN_MANAGER_SESSION_ID:t,...a?.trim()?{SHENNIAN_EXTERNAL_REPLY_TARGET:a.trim()}:{}}:{}}function le(t,e,a,s,d){t.configure?.({sessionId:e,externalChannel:s??null,env:{...z(a),...W(e,s,d)}})}function H(t,e,a){const s=t.sessions.get(e);return s?.externalChannel?s.externalChannel:a==="manager"?t.managerRuntime?.getExternalChannelStatus(e)??null:null}function ie(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?U(a)??e:e}function de(t,e,a,s){let d=null;function f(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:ee(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function l(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function i(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function S(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{i(n)},te),n.heartbeatTimer.unref?.())}function E(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(f({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const r=t.sessions.get(e),T=ne(n),R=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,R||(r.currentRunId=n.runId),!R&&T&&(r.currentRunPhase=T,S(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&x({level:"info",sessionId:e,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}}),n.state==="delta"&&n.text&&!n.thinking?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:O(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.message});const h=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(h,(t.runTextAcc.get(h)??"")+n.text),n.agentSessionId&&n.agentSessionId!==d&&(d=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,B(a,n.source),n.agentSessionId),r&&v({sessionId:e,agentType:a,workDir:r.workDir,agentSessionId:n.agentSessionId}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const p=n.text??"";if(!p)return;const b=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==b)&&E(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:b}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=p,r.pendingTextEvent.seq=n.seq);return}let m={};if(n.state==="final"){E(r);const p=t.runTextAcc.get(h)??"";p&&(m={messageSummary:Z(p)}),t.runTextAcc.delete(h)}else n.state==="error"||n.state==="aborted"?(E(r),t.runTextAcc.delete(h)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&E(r);R&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,l(r),t.chatQueue?.noteTerminal(e)),f(n,m)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${a}: ${n.message}`),t.sessions.delete(e),t.chatQueue?.noteTerminal(e),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:n.message,runId:"",seq:0}})})}function ce(t,e){if(t.processedReqIds.add(e),t.processedReqIds.size>1e3){const a=t.processedReqIds.values().next().value;t.processedReqIds.delete(a)}}async function q(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}async function ue(t,e,a,s,d,f,l){t.evictIdleSessions();const i=j(a);if(!i)throw new Error(`Unsupported agent: ${a}`);le(i,e,a,f,l),await i.start(e,s,d);const S={adapter:i,workDir:s,agentType:a,agentSessionId:d??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:f??null,externalReplyTarget:l??null,externalChannelEnv:{...z(a),...W(e,f,l)}};return t.sessions.set(e,S),de(t,e,a,i),S}function ge(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const d=a.nextEventSeq;t.runTextAcc.delete(`${e}:${s}`),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:e,runId:s,seq:d},seq:d,id:`agent-evt-${s}-${d}`}),t.chatQueue?.noteTerminal(e)}async function Te(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}ce(t,e.id);const{sessionId:a,text:s,agentType:d,workDir:f,agentSessionId:l,modelId:i,managerDefaultWorkerAgentType:S,managerDefaultWorkerModelId:E,reasoningEffort:n,clientMessageId:r,sessionListProjection:T,waitForDispatch:R,responseId:h}=e.params,m=h||e.id;J(T);const p=se(e.params.externalChannel),b=typeof e.params.replyTarget=="string"?e.params.replyTarget.trim():"";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:"sessionId and text are required"});return}const u=d;u==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,S??null,E??null);const y=(u==="claude"||u==="codex")&&typeof n=="string"&&n.trim()?n.trim():void 0,I=t.resolvePath(ie(u,f||F.homedir(),l)||F.homedir()),D=I,$=Y(e.params.attachments),g=$?.length?await V({text:s,attachments:$,workDir:I}):{text:s,attachments:$,localized:!1};let o=t.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==u||o.workDir!==I||JSON.stringify(o.externalChannel??null)!==JSON.stringify(p??null)){t.sessions.delete(a);try{await q(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}else if(l&&o.agentSessionId!==l)try{await o.adapter.resume(l),o.agentSessionId=l}catch{t.sessions.delete(a);try{await q(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}}if(!o)try{o=await ue(t,a,u,I,l,p,b)}catch(c){const w=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${d}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${d} workDir=${I} agentSessionId=${l??""}: ${w}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:w,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:w});return}t.managerRuntime?.notifyWeChatRpaSessionBinding({sessionId:a,workDir:I,agentType:u,agentSessionId:o.agentSessionId??l??null,modelId:i??null,externalChannel:p});const N={id:r??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:G(g.text,g.attachments)};x({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:u,modelId:i,reasoningEffort:y}});const P=()=>{re(t,{sessionId:a,agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i}),o.currentRunId||(o.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:u,sourceAgentType:B(u,i),canonicalMessageId:r??null,sourceSessionKey:o.agentSessionId??l??null,text:g.text}),A(a,N),L(t,N,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i})},C=async(c,w)=>{const k=ae(u,c);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${d} workDir=${I} agentSessionId=${o.agentSessionId??l??""}: ${k}`),t.sessions.delete(a);try{await q(o)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:k,runId:"",seq:0}}),!w){const _={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:k};A(a,_),L(t,_,{agentType:u,workDir:D,agentSessionId:o.agentSessionId??l??null,modelId:i})}w&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:m,ok:!1,error:k}))};if(R){try{const c=g.attachments;c?.length?await o.adapter.send(g.text,i,y,c):y?await o.adapter.send(g.text,i,y):await o.adapter.send(g.text,i),x({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(c){await C(c,!0);return}P(),t.client.sendRes({type:"res",id:m,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),x({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}P(),t.client.sendRes({type:"res",id:m,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),x({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const M=g.attachments;(M?.length?o.adapter.send(g.text,i,y,M):y?o.adapter.send(g.text,i,y):o.adapter.send(g.text,i)).then(()=>{x({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(c=>{C(c,!1)})}async function be(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}ge(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{be as handleChatAbort,Te as handleChatSend};
|
|
1
|
+
import z from"node:os";import{createAgent as O}from"../../agents/adapter.js";import{buildApprovalPendingPayload as j,buildUserMessagePayload as H}from"@shennian/wire";import{reportLog as E}from"../../log-reporter.js";import{lookupClaudeTranscriptCwd as U}from"../../native-fusion/parsers.js";import{appendMessage as A,recordSession as B}from"../store.js";import{mergeProjectedSessions as G}from"../projection.js";import{buildManagedAgentEnv as J}from"../../agents/config-status.js";import{materializeRemoteChatAttachments as Q}from"../remote-attachments.js";function K(t){if(!Array.isArray(t))return;const e=t.map(a=>{if(!a||typeof a!="object")return null;const s=a,i=typeof s.path=="string"?s.path:"",f=typeof s.name=="string"?s.name:"",l=typeof s.mimeType=="string"?s.mimeType:"";if(!i||!f||!l)return null;const d=typeof s.previewData=="string"&&s.previewData.trim()?s.previewData.trim():void 0;return{path:i,name:f,mimeType:l,kind:l.startsWith("image/")?"image":"file",...d?{previewData:d}:{}}}).filter(a=>a!=null);return e.length?e:void 0}function V(t){const e=t.indexOf(`
|
|
2
|
+
`),a=e>0?Math.min(e,80):Math.min(t.length,80);return t.slice(0,a)}function Y(t,e,a={}){if(t.state==="tool-call"||t.state==="tool-result"){const s={runId:t.runId,sourceSeq:t.seq};return{state:t.state,runId:t.runId,seq:t.seq,sessionId:e,detailRef:s,...t.name?{name:t.name}:{},...t.source?{source:t.source}:{},...t.agentSessionId?{agentSessionId:t.agentSessionId}:{},...a}}return{...t,sessionId:e,...a}}const X=3e4;function Z(t){return t.state==="heartbeat"?t.runPhase??null:t.state==="tool-call"||t.state==="tool-result"?"tool_running":t.state==="approval-pending"?"waiting_approval":t.state==="delta"?t.thinking?"thinking":"streaming_text":t.state==="init"||t.state==="start"?"thinking":null}function ee(t,e){return`Agent send failed: ${e instanceof Error?e.message:String(e)}`}function _(t,e){return t!=="manager"?t:e==="claude"?"claude":"codex"}function L(t,e,a){t.client.sendEvent({type:"event",event:"session.message",payload:{sessionId:e.sessionId,message:e,session:{id:e.sessionId,agentType:a.agentType,agentSessionId:a.agentSessionId??null,modelId:a.modelId??null,workDir:a.workDir,status:"active",externalChannel:null}}})}function te(t,e){B({sessionId:e.sessionId,agentType:e.agentType,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e.sessionId,agentType:e.agentType,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,workDir:e.workDir,status:"active",externalChannel:null}}})}function Ie(t){if(!t||typeof t!="object")return null;const e=t;return{configured:e.configured===void 0?void 0:!!e.configured,connected:!!e.connected,type:typeof e.type=="string"?e.type:null,channelId:typeof e.channelId=="string"?e.channelId:null,name:typeof e.name=="string"?e.name:null,canReply:e.canReply===void 0||e.canReply===null?null:!!e.canReply,systemPrompt:typeof e.systemPrompt=="string"?e.systemPrompt:null,wechatRpaSource:typeof e.wechatRpaSource=="string"?e.wechatRpaSource:null,wechatRpaGroups:Array.isArray(e.wechatRpaGroups)?e.wechatRpaGroups.map(a=>({name:String(a?.name||"").trim()})).filter(a=>a.name):null,pollIntervalMs:Number.isFinite(e.pollIntervalMs)?Number(e.pollIntervalMs):null,recentLimit:Number.isFinite(e.recentLimit)?Number(e.recentLimit):null,idleSeconds:Number.isFinite(e.idleSeconds)?Number(e.idleSeconds):null,forceForeground:e.forceForeground===void 0||e.forceForeground===null?null:!!e.forceForeground,noRestore:e.noRestore===void 0||e.noRestore===null?null:!!e.noRestore,downloadAttachments:e.downloadAttachments===void 0||e.downloadAttachments===null?null:!!e.downloadAttachments,downloadAttachmentsDir:typeof e.downloadAttachmentsDir=="string"?e.downloadAttachmentsDir:null}}function we(t){return!!(t?.configured??t?.connected)}function W(t){return J(t)}function v(t,e,a){return{}}function ne(t,e,a,s,i){t.configure?.({sessionId:e,externalChannel:s??null,env:{...W(a),...v(e,s,i)}})}function Se(t,e,a){return null}function ae(t,e,a){if(t!=="claude"||!a)return e;const s=e.trim();return!!s&&s.startsWith("-")&&!s.includes("/")?U(a)??e:e}function re(t,e,a,s){let i=null;function f(n,r={}){t.client.sendAgentEvent({type:"event",event:"agent",payload:Y(n,e,r),seq:n.seq,id:`agent-evt-${n.runId}-${n.seq}`})}function l(n){n?.heartbeatTimer&&(clearInterval(n.heartbeatTimer),n.heartbeatTimer=null)}function d(n){if(!n.currentRunId||!n.currentRunPhase)return;const r=n.heartbeatSeq++;t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:n.currentRunId,seq:r,runPhase:n.currentRunPhase},seq:r,id:`agent-heartbeat-${n.currentRunId}-${r}-${Date.now()}`})}function I(n){!n||n.heartbeatTimer||(n.heartbeatTimer=setInterval(()=>{d(n)},X),n.heartbeatTimer.unref?.())}function w(n){const r=n?.pendingTextEvent;!n||!r||!r.text||(f({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),n.pendingTextEvent=null)}s.on("agentEvent",n=>{const r=t.sessions.get(e),R=Z(n),T=n.state==="final"||n.state==="error"||n.state==="aborted";r&&(r.nextEventSeq=n.seq+1,T||(r.currentRunId=n.runId),!T&&R&&(r.currentRunPhase=R,I(r)),n.agentSessionId&&(r.agentSessionId=n.agentSessionId)),t.managerRuntime?.noteAgentEvent(e,n),n.state!=="delta"&&E({level:"info",sessionId:e,wsEvent:`agent.${n.state}`,wsDirection:"out",metadata:{runId:n.runId,seq:n.seq,agentType:a}}),n.state==="delta"&&n.text&&!n.thinking?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.text}):n.state==="tool-call"||n.state==="tool-result"?A(e,{id:`agent-${n.runId}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:n.state==="tool-call"?"tool_use":"tool_result",name:n.name,status:n.state==="tool-call"?"running":"completed",detailRef:{runId:n.runId,sourceSeq:n.seq},args:n.args,result:n.result})}):n.state==="approval-pending"?A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:j(n.approval)}):(n.state==="error"||n.state==="aborted")&&n.message&&A(e,{id:`agent-${n.runId||"run"}-${n.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:n.message});const m=`${e}:${n.runId}`;if(n.state==="delta"&&!n.thinking&&n.text&&t.runTextAcc.set(m,(t.runTextAcc.get(m)??"")+n.text),n.agentSessionId&&n.agentSessionId!==i&&(i=n.agentSessionId,t.nativeFusion?.noteManagedSourceSession(e,_(a,n.source),n.agentSessionId),r&&B({sessionId:e,agentType:a,workDir:r.workDir,agentSessionId:n.agentSessionId}),t.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:a,agentSessionId:n.agentSessionId}}})),n.state==="delta"){const h=n.text??"";if(!h)return;const b=!!n.thinking;r?.pendingTextEvent&&(r.pendingTextEvent.runId!==n.runId||r.pendingTextEvent.thinking!==b)&&w(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:n.runId,seq:n.seq,text:"",thinking:b}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=h,r.pendingTextEvent.seq=n.seq);return}let p={};if(n.state==="final"){w(r);const h=t.runTextAcc.get(m)??"";h&&(p={messageSummary:V(h)}),t.runTextAcc.delete(m)}else n.state==="error"||n.state==="aborted"?(w(r),t.runTextAcc.delete(m)):(n.state==="tool-call"||n.state==="tool-result"||n.state==="approval-pending")&&w(r);T&&r?.currentRunId===n.runId&&(r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,l(r),t.chatQueue?.noteTerminal(e)),f(n,p)}),s.on("error",n=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${a}: ${n.message}`),t.sessions.delete(e),t.chatQueue?.noteTerminal(e),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:n.message,runId:"",seq:0}})})}function se(t,e){if(t.processedReqIds.add(e),t.processedReqIds.size>1e3){const a=t.processedReqIds.values().next().value;t.processedReqIds.delete(a)}}async function q(t){t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),t.adapter.removeAllListeners(),await t.adapter.stop().catch(()=>{})}async function oe(t,e,a,s,i,f,l){t.evictIdleSessions();const d=O(a);if(!d)throw new Error(`Unsupported agent: ${a}`);ne(d,e,a,f,l),await d.start(e,s,i);const I={adapter:d,workDir:s,agentType:a,agentSessionId:i??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:f??null,externalReplyTarget:l??null,externalChannelEnv:{...W(a),...v(e,f,l)}};return t.sessions.set(e,I),re(t,e,a,d),I}function le(t,e){const a=t.sessions.get(e),s=a?.currentRunId;if(!a||!s)return;const i=a.nextEventSeq;t.runTextAcc.delete(`${e}:${s}`),a.pendingTextEvent=null,a.currentRunId=null,a.currentRunPhase=null,a.nextEventSeq=0,a.heartbeatTimer&&(clearInterval(a.heartbeatTimer),a.heartbeatTimer=null),t.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:e,runId:s,seq:i},seq:i,id:`agent-evt-${s}-${i}`}),t.chatQueue?.noteTerminal(e)}async function xe(t,e){if(t.processedReqIds.has(e.id)){t.client.sendRes({type:"res",id:e.id,ok:!0});return}se(t,e.id);const{sessionId:a,text:s,agentType:i,workDir:f,agentSessionId:l,modelId:d,managerDefaultWorkerAgentType:I,managerDefaultWorkerModelId:w,reasoningEffort:n,clientMessageId:r,sessionListProjection:R,waitForDispatch:T,responseId:m}=e.params,p=m||e.id;G(R);const h=null,b="";if(!a||!s){t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:p,ok:!1,error:"sessionId and text are required"});return}const u=i;u==="manager"&&t.managerRuntime?.setManagerWorkerDefaults(a,I??null,w??null);const y=(u==="claude"||u==="codex"||u==="workbuddy")&&typeof n=="string"&&n.trim()?n.trim():void 0,S=t.resolvePath(ae(u,f||z.homedir(),l)||z.homedir()),$=S,D=K(e.params.attachments),g=D?.length?await Q({text:s,attachments:D,workDir:S}):{text:s,attachments:D,localized:!1};let o=t.sessions.get(a);if(o){if(o.lastActiveAt=Date.now(),o.agentType!==u||o.workDir!==S||JSON.stringify(o.externalChannel??null)!==JSON.stringify(h??null)){t.sessions.delete(a);try{await q(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}else if(l&&o.agentSessionId!==l)try{await o.adapter.resume(l),o.agentSessionId=l}catch{t.sessions.delete(a);try{await q(o)}catch{t.processedReqIds.delete(e.id)}o=void 0}}if(!o)try{o=await oe(t,a,u,S,l,h,b)}catch(c){const x=c instanceof Error&&c.message.startsWith("Unsupported agent:")?c.message:`Failed to start ${i}: ${c instanceof Error?c.message:String(c)}`;console.error(`[chat.send] start failed reqId=${e.id} sessionId=${a} agentType=${i} workDir=${S} agentSessionId=${l??""}: ${x}`),t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:x,runId:"",seq:0}}),t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:p,ok:!1,error:x});return}const P={id:r??`user-${e.id}`,sessionId:a,role:"user",ts:Date.now(),payload:H(g.text,g.attachments)};E({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:e.id,agentType:u,modelId:d,reasoningEffort:y}});const C=()=>{te(t,{sessionId:a,agentType:u,workDir:$,agentSessionId:o.agentSessionId??l??null,modelId:d}),o.currentRunId||(o.nextEventSeq=0),t.nativeFusion?.registerManagedSend({sessionId:a,agentType:u,sourceAgentType:_(u,d),canonicalMessageId:r??null,sourceSessionKey:o.agentSessionId??l??null,text:g.text}),A(a,P),L(t,P,{agentType:u,workDir:$,agentSessionId:o.agentSessionId??l??null,modelId:d})},M=async(c,x)=>{const k=ee(u,c);console.error(`[chat.send] send failed reqId=${e.id} sessionId=${a} agentType=${i} workDir=${S} agentSessionId=${o.agentSessionId??l??""}: ${k}`),t.sessions.delete(a);try{await q(o)}catch{}if(t.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:k,runId:"",seq:0}}),!x){const N={id:`agent-error-${e.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:k};A(a,N),L(t,N,{agentType:u,workDir:$,agentSessionId:o.agentSessionId??l??null,modelId:d})}x&&(t.processedReqIds.delete(e.id),t.client.sendRes({type:"res",id:p,ok:!1,error:k}))};if(T){try{const c=g.attachments;c?.length?await o.adapter.send(g.text,d,y,c):y?await o.adapter.send(g.text,d,y):await o.adapter.send(g.text,d),E({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}catch(c){await M(c,!0);return}C(),t.client.sendRes({type:"res",id:p,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),E({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});return}C(),t.client.sendRes({type:"res",id:p,ok:!0,...g.localized?{payload:{localizedAttachments:!0}}:{}}),E({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:e.id,ok:!0}});const F=g.attachments;(F?.length?o.adapter.send(g.text,d,y,F):y?o.adapter.send(g.text,d,y):o.adapter.send(g.text,d)).then(()=>{E({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:e.id}})}).catch(c=>{M(c,!1)})}async function Ee(t,e){const{sessionId:a}=e.params,s=t.sessions.get(a);if(s){try{await s.adapter.stop()}catch{}le(t,a),t.activityPublisher?.publish(a,null)}t.client.sendRes({type:"res",id:e.id,ok:!0})}export{Ee as handleChatAbort,xe as handleChatSend};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{SERVERS as r}from"../../region.js";import{loadConfig as
|
|
1
|
+
import{SERVERS as r}from"../../region.js";import{loadConfig as i,saveConfig as p}from"../../config/index.js";async function f(o,t){const n=await Promise.all(Object.keys(r).map(async a=>{const{url:s,label:c}=r[a],d=performance.now();try{const l=new AbortController,u=setTimeout(()=>l.abort(),5e3);return await fetch(`${s}/health`,{signal:l.signal}),clearTimeout(u),{region:a,url:s,label:c,latencyMs:Math.round(performance.now()-d)}}catch{return{region:a,url:s,label:c,latencyMs:null}}}));o.client.sendRes({type:"res",id:t.id,ok:!0,payload:{current:"cn",servers:n}})}async function m(o,t){const e=t.params.region;if(e!=="cn"&&e!=="global"){o.client.sendRes({type:"res",id:t.id,ok:!1,error:'region must be "cn" or "global"'});return}const n=i();n.serverUrl=r[e].url,p(n),o.client.sendRes({type:"res",id:t.id,ok:!0,payload:{region:e,url:r[e].url}}),setTimeout(()=>process.exit(0),500)}async function h(o,t){const e=t.params.policy;if(e!=="none"&&e!=="patch"){o.client.sendRes({type:"res",id:t.id,ok:!1,error:'policy must be "none" or "patch"'});return}const n=i();n.autoUpgrade=e,p(n),o.upgradePolicyController?.setPolicy(e),o.client.sendEvent({type:"event",event:"machine.upgrade-policy",payload:{policy:e}}),o.client.sendRes({type:"res",id:t.id,ok:!0,payload:{autoUpgrade:e}})}export{f as handleRegionProbe,m as handleRegionSwitch,h as handleUpgradeSetPolicy};
|
|
@@ -5,6 +5,7 @@ export declare function handleFsRead(runtime: SessionManagerRuntime, req: ReqFra
|
|
|
5
5
|
export declare function handleFsWrite(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
|
|
6
6
|
export declare function handleFsRename(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
|
|
7
7
|
export declare function handleFsExportMarkdownPdf(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
|
|
8
|
+
export declare function handleFsExportMarkdownPdfSetup(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
|
|
8
9
|
export declare function handleFsArchiveZip(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
|
|
9
10
|
export declare function handleFsTransfer(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
|
|
10
11
|
export declare function handleFsTransferStart(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
|