shennian 0.4.69 → 0.4.71

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.
Files changed (88) hide show
  1. package/dist/publish-build-manifest.json +125 -70
  2. package/dist/src/agent-env.js +4 -4
  3. package/dist/src/agents/adapter.d.ts +7 -3
  4. package/dist/src/agents/auth-status.d.ts +4 -0
  5. package/dist/src/agents/auth-status.js +2 -0
  6. package/dist/src/agents/codex-protocol.d.ts +103 -0
  7. package/dist/src/agents/codex-protocol.js +3 -0
  8. package/dist/src/agents/codex-runtime.d.ts +91 -0
  9. package/dist/src/agents/codex-runtime.js +14 -0
  10. package/dist/src/agents/codex.d.ts +15 -91
  11. package/dist/src/agents/codex.js +2 -17
  12. package/dist/src/agents/command-spec.js +4 -3
  13. package/dist/src/agents/detect.js +1 -1
  14. package/dist/src/agents/manager.d.ts +4 -3
  15. package/dist/src/agents/manager.js +4 -4
  16. package/dist/src/agents/opencode.d.ts +4 -0
  17. package/dist/src/agents/opencode.js +1 -1
  18. package/dist/src/commands/agent-readiness.d.ts +17 -0
  19. package/dist/src/commands/agent-readiness.js +2 -0
  20. package/dist/src/commands/agent.js +2 -2
  21. package/dist/src/commands/daemon-instance-lock.js +1 -1
  22. package/dist/src/commands/daemon-process.d.ts +1 -0
  23. package/dist/src/commands/daemon-process.js +1 -1
  24. package/dist/src/commands/daemon-service-spec.d.ts +28 -0
  25. package/dist/src/commands/daemon-service-spec.js +1 -0
  26. package/dist/src/commands/daemon-start-wait.d.ts +1 -1
  27. package/dist/src/commands/daemon-start-wait.js +1 -1
  28. package/dist/src/commands/daemon-state.d.ts +57 -0
  29. package/dist/src/commands/daemon-state.js +1 -0
  30. package/dist/src/commands/daemon-windows.d.ts +8 -0
  31. package/dist/src/commands/daemon-windows.js +10 -10
  32. package/dist/src/commands/daemon.d.ts +4 -64
  33. package/dist/src/commands/daemon.js +13 -13
  34. package/dist/src/commands/upgrade.js +1 -1
  35. package/dist/src/daemon-ipc/agent-readiness.d.ts +14 -0
  36. package/dist/src/daemon-ipc/agent-readiness.js +1 -0
  37. package/dist/src/daemon-ipc/control.d.ts +1 -1
  38. package/dist/src/daemon-ipc/control.js +1 -1
  39. package/dist/src/index.js +3 -3
  40. package/dist/src/native-fusion/local-repository.d.ts +6 -1
  41. package/dist/src/native-fusion/local-repository.js +2 -2
  42. package/dist/src/native-fusion/service.d.ts +2 -0
  43. package/dist/src/native-fusion/service.js +2 -2
  44. package/dist/src/native-fusion/source-visibility-audit.d.ts +16 -0
  45. package/dist/src/native-fusion/source-visibility-audit.js +1 -0
  46. package/dist/src/native-fusion/source-visibility.d.ts +25 -0
  47. package/dist/src/native-fusion/source-visibility.js +1 -0
  48. package/dist/src/native-fusion/state.d.ts +1 -0
  49. package/dist/src/native-fusion/state.js +2 -2
  50. package/dist/src/native-fusion/types.d.ts +5 -0
  51. package/dist/src/room/managed-room-binding.d.ts +2 -0
  52. package/dist/src/room/managed-room-binding.js +1 -1
  53. package/dist/src/room/room-binding-client.d.ts +1 -0
  54. package/dist/src/room/room-binding-client.js +1 -1
  55. package/dist/src/runtime-distribution.d.ts +13 -0
  56. package/dist/src/runtime-distribution.js +1 -0
  57. package/dist/src/security/managed-agent-policy.d.ts +7 -0
  58. package/dist/src/security/managed-agent-policy.js +1 -1
  59. package/dist/src/session/handlers/agent-workspace-validation.d.ts +1 -0
  60. package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
  61. package/dist/src/session/handlers/agents.d.ts +7 -1
  62. package/dist/src/session/handlers/agents.js +1 -1
  63. package/dist/src/session/handlers/chat-context.d.ts +31 -0
  64. package/dist/src/session/handlers/chat-context.js +1 -0
  65. package/dist/src/session/handlers/chat-events.d.ts +1 -1
  66. package/dist/src/session/handlers/chat-events.js +2 -2
  67. package/dist/src/session/handlers/chat-session-lifecycle.d.ts +2 -2
  68. package/dist/src/session/handlers/chat-session-lifecycle.js +1 -1
  69. package/dist/src/session/handlers/chat.d.ts +3 -29
  70. package/dist/src/session/handlers/chat.js +1 -1
  71. package/dist/src/session/manager.js +2 -2
  72. package/dist/src/session/queue-helpers.js +2 -2
  73. package/dist/src/session/queue-message.d.ts +2 -0
  74. package/dist/src/session/queue.d.ts +7 -1
  75. package/dist/src/session/queue.js +1 -1
  76. package/dist/src/session/queued-chat-dispatch.d.ts +4 -1
  77. package/dist/src/session/queued-chat-dispatch.js +1 -1
  78. package/dist/src/session/store.d.ts +4 -2
  79. package/dist/src/session/store.js +2 -2
  80. package/dist/src/session/types.d.ts +1 -0
  81. package/dist/src/upgrade/engine.js +2 -2
  82. package/dist/src/upgrade/scheduler.js +1 -1
  83. package/dist/src/upgrade/updater-launcher.js +3 -3
  84. package/node_modules/@shennian/wire/dist/room.d.ts +2 -0
  85. package/node_modules/@shennian/wire/dist/session-sync.d.ts +2 -1
  86. package/node_modules/@shennian/wire/dist/session.d.ts +19 -1
  87. package/node_modules/@shennian/wire/dist/session.js +8 -0
  88. package/package.json +1 -1
@@ -0,0 +1,16 @@
1
+ /** No titles, message contents, Codex databases or deletion APIs are read. */
2
+ export declare function auditInternalNativeVisibility(root?: string): {
3
+ mode: "dry-run";
4
+ counts: {
5
+ knownInternalSources: number;
6
+ importedSources: number;
7
+ confirmedDuplicateProjections: number;
8
+ };
9
+ conflicts: string[];
10
+ confirmed: {
11
+ sourceKey: string;
12
+ canonicalSessionId: string;
13
+ importedSessionId: string;
14
+ }[];
15
+ actionsApplied: number;
16
+ };
@@ -0,0 +1 @@
1
+ import l from"node:fs";import d from"node:path";import{fileURLToPath as p}from"node:url";import{resolvePersonalSyncV1Path as S}from"../personal-sync/paths.js";import{knownInternalNativeSources as v,knownJournalInternalNativeSources as y}from"./source-visibility.js";function w(u=S()){function r(e,n){const o=d.join(u,e);return l.existsSync(o)?JSON.parse(l.readFileSync(o,"utf8")):n}const f=Object.values(r("session-index.json",{})),s=r("native-fusion-state.json",{}),a=Object.values(r("native-fusion/sources.json",{sources:{}}).sources),m=f.filter(e=>!!s.daemonInstallationId&&e.daemonInstallationId===s.daemonInstallationId),t=new Map,i=(e,n)=>{const o=t.get(e)??new Set;o.add(n),t.set(e,o)};for(const e of[...v(m),...y(s.daemonInstallationId??"")])i(`${e.agentType}:${e.sourceSessionKey}`,e.sessionId);for(const[e,n]of Object.entries(s.internalSourceOwners??{}))i(e,n.sessionId);const I=[...t].filter(([,e])=>e.size!==1).map(([e])=>e),c=a.flatMap(e=>{if(!s.daemonInstallationId||e.daemonInstallationId!==s.daemonInstallationId)return[];const n=`${e.agentType}:${e.sourceSessionKey}`,o=t.get(n);return!o||o.size!==1||o.has(e.sessionId)?[]:[{sourceKey:n,canonicalSessionId:[...o][0],importedSessionId:e.sessionId}]});return{mode:"dry-run",counts:{knownInternalSources:t.size,importedSources:a.length,confirmedDuplicateProjections:c.length},conflicts:I,confirmed:c,actionsApplied:0}}process.argv[1]&&d.resolve(process.argv[1])===p(import.meta.url)&&console.log(JSON.stringify(w(),null,2));export{w as auditInternalNativeVisibility};
@@ -0,0 +1,25 @@
1
+ import { type AgentType, type SessionMode } from '@shennian/wire';
2
+ type OwnerRecord = {
3
+ sessionId: string;
4
+ agentType: AgentType;
5
+ agentSessionId?: string | null;
6
+ modelId?: string | null;
7
+ sessionMode?: SessionMode;
8
+ nativeSessionVisibility?: 'user' | 'internal';
9
+ };
10
+ /** Only exact, persisted ownership is eligible. Titles/prompts/provider analytics are never evidence. */
11
+ export declare function knownInternalNativeSources(records: readonly OwnerRecord[]): Array<{
12
+ sessionId: string;
13
+ agentType: string;
14
+ sourceSessionKey: string;
15
+ }>;
16
+ /** Run history preserves rotated provider IDs that the current session index no longer carries. */
17
+ export declare function knownJournalInternalNativeSources(daemonInstallationId: string, directory?: string): ReturnType<typeof knownInternalNativeSources>;
18
+ /** The provider ID, not the transcript location or a message's Worker link, owns visibility. */
19
+ export declare function registerInternalNativeSource(sessionId: string, agentType: string, sourceSessionKey: string): void;
20
+ /** Read-only commit fence, including registrations made while a cooperative scan yielded. */
21
+ export declare function isInternalNativeSource(agentType: string, sourceSessionKey: string, options?: {
22
+ filePath?: string;
23
+ daemonInstallationId?: string;
24
+ }): boolean;
25
+ export {};
@@ -0,0 +1 @@
1
+ import a from"node:fs";import f from"node:path";import{createHash as S}from"node:crypto";import{resolveShennianPath as m}from"../config/index.js";import{parseRunJournalRecord as p}from"../session/run-recovery/schema.js";import{isInternalSession as I}from"@shennian/wire";import{getDaemonInstallationId as g}from"../personal-sync/identity.js";import{resolvePersonalSyncV1Path as v}from"../personal-sync/paths.js";import{loadNativeScannerState as h,saveNativeScannerState as w,validateNativeScannerState as y}from"./state.js";function x(i){return i.flatMap(n=>{if(!n.agentSessionId||!I({...n,id:n.sessionId}))return[];const o=n.agentType==="manager"?n.modelId:n.agentType;return!o||!["codex","claude","opencode"].includes(o)?[]:[{sessionId:n.sessionId,agentType:o,sourceSessionKey:n.agentSessionId}]})}function F(i,n=m("runtime","run-recovery","active")){if(!a.existsSync(n))return[];const o=[];for(const e of a.readdirSync(n))if(e.endsWith(".json"))try{const t=f.join(n,e);if(!a.lstatSync(t).isFile())continue;const r=p(JSON.parse(a.readFileSync(t,"utf8")));if(r.daemonInstallationId!==i)continue;const s=S("sha256").update(`${r.sessionId}\0${r.runId}`).digest("hex")+".json";if(e!==s)continue;o.push(...x([r]))}catch{}return o}const u=new Map;function z(i,n,o){if(!i||!o)throw new Error("internal_native_source_identity_required");if(!["codex","claude","opencode"].includes(n))return;const e=h(),t=`${n}:${o}`,r=e.internalSourceOwners?.[t];if(r&&r.sessionId!==i)throw new Error("internal_native_source_owner_conflict");r&&e.ignoredSources?.[t]||(e.ignoredSources={...e.ignoredSources,[t]:!0},e.internalSourceOwners={...e.internalSourceOwners,[t]:r??{sessionId:i,registeredAt:new Date().toISOString()}},w(e))}function D(i,n,o={}){const e=o.filePath??v("native-fusion-state.json");if(!a.existsSync(e))return u.delete(e),!1;const t=a.statSync(e),r=`${t.dev}:${t.ino}:${t.size}:${t.mtimeMs}:${t.ctimeMs}`,s=u.get(e),c=s?.signature===r?s.state:JSON.parse(a.readFileSync(e,"utf8")),l=o.daemonInstallationId??g();(s?.signature!==r||c.daemonInstallationId!==l)&&(y(c,l),u.size>32&&u.clear(),u.set(e,{signature:r,state:c}));const d=`${i}:${n}`;return c.ignoredSources?.[d]===!0||!!c.internalSourceOwners?.[d]}export{D as isInternalNativeSource,x as knownInternalNativeSources,F as knownJournalInternalNativeSources,z as registerInternalNativeSource};
@@ -1,3 +1,4 @@
1
1
  import { type NativeScannerState } from './types.js';
2
2
  export declare function loadNativeScannerState(): NativeScannerState;
3
3
  export declare function saveNativeScannerState(state: NativeScannerState): void;
4
+ export declare function validateNativeScannerState(state: NativeScannerState, daemonInstallationId: string): void;
@@ -1,2 +1,2 @@
1
- import l from"node:crypto";import r from"node:fs";import y from"node:path";import{resolvePersonalSyncV1Path as p}from"../personal-sync/paths.js";import{getDaemonInstallationId as a}from"../session/store.js";import{readPersonalDataEpochMarker as S}from"../personal-sync/epoch.js";import{NATIVE_SCANNER_STATE_SCHEMA_VERSION as f}from"./types.js";function u(){return p("native-fusion-state.json")}function I(){const e=u(),i=a();if(!r.existsSync(e)){const o=S()?.epochStartedAt,t={schemaVersion:f,fusionEpochMs:o?Date.parse(o):Date.now(),daemonInstallationId:i,files:{}};return d(e,t),t}let n;try{n=JSON.parse(r.readFileSync(e,"utf8"))}catch(o){throw new Error(`native fusion v1 state is unreadable: ${e}`,{cause:o})}return s(n,i),n}function N(e){const i=a();s(e,i);const n=u();if(r.existsSync(n)){const o=JSON.parse(r.readFileSync(n,"utf8"));if(s(o,i),o.fusionEpochMs!==e.fusionEpochMs)throw new Error("native fusion epoch is immutable")}d(n,e)}function s(e,i){if(!e||e.schemaVersion!==f||!Number.isSafeInteger(e.fusionEpochMs)||e.fusionEpochMs<=0||e.daemonInstallationId!==i||!e.files||typeof e.files!="object"||Array.isArray(e.files)||e.ignoredSources!==void 0&&(typeof e.ignoredSources!="object"||e.ignoredSources===null||Array.isArray(e.ignoredSources)||Object.entries(e.ignoredSources).some(([n,o])=>!n||o!==!0)))throw new Error("invalid native fusion v1 state");for(const n of Object.values(e.files)){if(n.daemonInstallationId!==i)throw new Error("native fusion cursor belongs to another daemon installation");if(n.sources!==void 0&&(!Array.isArray(n.sources)||n.sources.some(o=>!o||!["codex","claude","opencode"].includes(o.agentType)||typeof o.sourceSessionKey!="string"||!o.sourceSessionKey)))throw new Error("native fusion cursor has invalid source metadata")}}function d(e,i){const n=y.dirname(e);r.mkdirSync(n,{recursive:!0,mode:448});const o=`${e}.tmp-${process.pid}-${l.randomBytes(6).toString("hex")}`;let t;try{if(t=r.openSync(o,"wx",384),r.writeFileSync(t,`${JSON.stringify(i,null,2)}
2
- `,"utf8"),r.fsyncSync(t),r.closeSync(t),t=void 0,r.renameSync(o,e),process.platform!=="win32"){const c=r.openSync(n,"r");try{r.fsyncSync(c)}finally{r.closeSync(c)}}}finally{t!==void 0&&r.closeSync(t);try{r.unlinkSync(o)}catch{}}}export{I as loadNativeScannerState,N as saveNativeScannerState};
1
+ import S from"node:crypto";import o from"node:fs";import p from"node:path";import{readPersonalDataEpochMarker as y}from"../personal-sync/epoch.js";import{getDaemonInstallationId as u}from"../personal-sync/identity.js";import{resolvePersonalSyncV1Path as m}from"../personal-sync/paths.js";import{NATIVE_SCANNER_STATE_SCHEMA_VERSION as f}from"./types.js";function d(){return m("native-fusion-state.json")}function I(){const e=d(),s=u();if(!o.existsSync(e)){const r=y()?.epochStartedAt,i={schemaVersion:f,fusionEpochMs:r?Date.parse(r):Date.now(),daemonInstallationId:s,files:{}};return l(e,i),i}let n;try{n=JSON.parse(o.readFileSync(e,"utf8"))}catch(r){throw new Error(`native fusion v1 state is unreadable: ${e}`,{cause:r})}return c(n,s),n}function b(e){const s=u();c(e,s);const n=d();if(o.existsSync(n)){const r=JSON.parse(o.readFileSync(n,"utf8"));if(c(r,s),r.fusionEpochMs!==e.fusionEpochMs)throw new Error("native fusion epoch is immutable");e.ignoredSources={...e.ignoredSources,...r.ignoredSources};for(const[i,t]of Object.entries(r.internalSourceOwners??{})){const a=e.internalSourceOwners?.[i];if(a&&a.sessionId!==t.sessionId)throw new Error("internal_native_source_owner_conflict")}e.internalSourceOwners={...e.internalSourceOwners,...r.internalSourceOwners}}l(n,e)}function c(e,s){if(!e||e.schemaVersion!==f||!Number.isSafeInteger(e.fusionEpochMs)||e.fusionEpochMs<=0||e.daemonInstallationId!==s||!e.files||typeof e.files!="object"||Array.isArray(e.files)||e.ignoredSources!==void 0&&(typeof e.ignoredSources!="object"||e.ignoredSources===null||Array.isArray(e.ignoredSources)||Object.entries(e.ignoredSources).some(([n,r])=>!n||r!==!0)))throw new Error("invalid native fusion v1 state");if(e.internalSourceOwners!==void 0&&(!e.internalSourceOwners||typeof e.internalSourceOwners!="object"||Array.isArray(e.internalSourceOwners)||Object.entries(e.internalSourceOwners).some(([n,r])=>!/^(codex|claude|opencode):.+$/.test(n)||!r||typeof r.sessionId!="string"||!r.sessionId||typeof r.registeredAt!="string"||!Number.isFinite(Date.parse(r.registeredAt)))))throw new Error("invalid internal native source ownership");for(const n of Object.values(e.files)){if(n.daemonInstallationId!==s)throw new Error("native fusion cursor belongs to another daemon installation");if(n.sources!==void 0&&(!Array.isArray(n.sources)||n.sources.some(r=>!r||!["codex","claude","opencode"].includes(r.agentType)||typeof r.sourceSessionKey!="string"||!r.sourceSessionKey)))throw new Error("native fusion cursor has invalid source metadata")}}function l(e,s){const n=p.dirname(e);o.mkdirSync(n,{recursive:!0,mode:448});const r=`${e}.tmp-${process.pid}-${S.randomBytes(6).toString("hex")}`;let i;try{if(i=o.openSync(r,"wx",384),o.writeFileSync(i,`${JSON.stringify(s,null,2)}
2
+ `,"utf8"),o.fsyncSync(i),o.closeSync(i),i=void 0,o.renameSync(r,e),process.platform!=="win32"){const t=o.openSync(n,"r");try{o.fsyncSync(t)}finally{o.closeSync(t)}}}finally{i!==void 0&&o.closeSync(i);try{o.unlinkSync(r)}catch{}}}export{I as loadNativeScannerState,b as saveNativeScannerState,c as validateNativeScannerState};
@@ -24,6 +24,11 @@ export type NativeScannerState = {
24
24
  files: Record<string, NativeFileCursor>;
25
25
  /** Provider-native sessions that are internal implementation details, never personal chats. */
26
26
  ignoredSources?: Record<string, true>;
27
+ /** Durable provenance for internal sources; retained after runs and sessions retire. */
28
+ internalSourceOwners?: Record<string, {
29
+ sessionId: string;
30
+ registeredAt: string;
31
+ }>;
27
32
  codexWindowsPathParserFixed?: boolean;
28
33
  codexAppContextWrapperFixed?: boolean;
29
34
  };
@@ -26,6 +26,7 @@ export type ManagedRoomBinder = {
26
26
  status: 'pending_approval' | 'active' | 'paused' | 'detached';
27
27
  activationMode: 'auto_follow' | 'mention_only' | 'paused';
28
28
  };
29
+ resumeSequence: string;
29
30
  idempotent: boolean;
30
31
  }>;
31
32
  restart(input: ManagedRoomRestartInput): Promise<{
@@ -56,6 +57,7 @@ export declare class TrustedManagedRoomBinder implements ManagedRoomBinder {
56
57
  });
57
58
  bind(input: ManagedRoomBindInput): Promise<{
58
59
  binding: import("./room-binding-client.js").RemoteRoomBinding;
60
+ resumeSequence: string;
59
61
  idempotent: boolean;
60
62
  }>;
61
63
  restart(input: ManagedRoomRestartInput): Promise<{
@@ -1 +1 @@
1
- import{roomRuntimeAdapterForAgent as I}from"@shennian/wire";import y from"node:crypto";class b{deps;constructor(e){this.deps=e}async bind(e){const{machineId:t,machineToken:i}=this.deps.getMachineCredentials();if(!t||!i)throw new Error("Machine is not paired with Shennian.");const s=g(e.agentType),o=this.deps.hostProcessIdentity(),d=this.deps.registry.register({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,nianSessionId:e.nianSessionId,hostProcessIdentity:o,capabilities:{canIdentifySession:!0,canBindAutomatically:!0,canOpenEmbeddedRoomPage:!1,canResumeIdleSession:!0,canActivateWhileHostOpen:!0}}),n=await this.deps.bindingClient.create({machineToken:i,bindingIntentId:e.assignmentIntentId,roomId:e.roomId,agentIdentityId:e.agentIdentityId,nianSessionId:e.nianSessionId,runtimeAdapter:s,sessionRegistryKey:d.registryKey,activationCapability:"managed",activationMode:e.activationMode??"auto_follow"});this.deps.registry.setBinding({registryKey:d.registryKey,bindingId:n.binding.id,roomId:n.binding.roomId,agentIdentityId:n.binding.agentIdentityId,agentMembershipId:n.binding.agentMembershipId,status:n.binding.status,activationMode:n.binding.activationMode,replaceOwner:!0});const r=await this.resolveServerOwnedWorkspace({machineToken:i,roomId:n.binding.roomId,bindingId:n.binding.id,agentIdentityId:e.agentIdentityId});return this.deps.observations.observe({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,hostContextHash:c(o),workspaceHash:c(r),workspacePath:r,lifecycleState:"active",eventName:"ManagedBind"}),n}async restart(e){const{machineId:t,machineToken:i}=this.deps.getMachineCredentials();if(!t||!i)throw new Error("Machine is not paired with Shennian.");const s=g(e.agentType),o=this.deps.hostProcessIdentity(),d=this.deps.registry.register({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,nianSessionId:e.nianSessionId,hostProcessIdentity:o,capabilities:{canIdentifySession:!0,canBindAutomatically:!0,canOpenEmbeddedRoomPage:!1,canResumeIdleSession:!0,canActivateWhileHostOpen:!0}}),n=await this.deps.bindingClient.restart({machineToken:i,bindingId:e.bindingId,previousNianSessionId:e.previousNianSessionId,roomId:e.roomId,agentIdentityId:e.agentIdentityId,nianSessionId:e.nianSessionId,runtimeAdapter:s,sessionRegistryKey:d.registryKey});this.deps.registry.setBinding({registryKey:d.registryKey,bindingId:n.binding.id,roomId:n.binding.roomId,agentIdentityId:n.binding.agentIdentityId,agentMembershipId:n.binding.agentMembershipId,status:n.binding.status,activationMode:n.binding.activationMode,replaceOwner:!0,initialSequence:n.resumeSequence});const r=await this.resolveServerOwnedWorkspace({machineToken:i,roomId:n.binding.roomId,bindingId:n.binding.id,agentIdentityId:e.agentIdentityId});return this.deps.observations.observe({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,hostContextHash:c(o),workspaceHash:c(r),workspacePath:r,lifecycleState:"active",eventName:"ManagedRestart"}),n}async resolveServerOwnedWorkspace(e){const t=await this.deps.bindingClient.status(e),i=t.managedWorkspacePath?.trim(),s=t.agent?.sessionMode;if(t.agentIdentityId!==e.agentIdentityId||s!=="standard"&&s!=="manager"||!i)throw new Error("managed_room_workspace_unavailable");return i}}function c(a){return y.createHash("sha256").update(a,"utf8").digest("hex")}function g(a){const e=I(a);if(e)return e;throw new Error(`Agent ${a} does not support managed Room binding.`)}export{b as TrustedManagedRoomBinder};
1
+ import{roomRuntimeAdapterForAgent as I}from"@shennian/wire";import y from"node:crypto";class b{deps;constructor(e){this.deps=e}async bind(e){const{machineId:t,machineToken:i}=this.deps.getMachineCredentials();if(!t||!i)throw new Error("Machine is not paired with Shennian.");const s=g(e.agentType),o=this.deps.hostProcessIdentity(),d=this.deps.registry.register({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,nianSessionId:e.nianSessionId,hostProcessIdentity:o,capabilities:{canIdentifySession:!0,canBindAutomatically:!0,canOpenEmbeddedRoomPage:!1,canResumeIdleSession:!0,canActivateWhileHostOpen:!0}}),n=await this.deps.bindingClient.create({machineToken:i,bindingIntentId:e.assignmentIntentId,roomId:e.roomId,agentIdentityId:e.agentIdentityId,nianSessionId:e.nianSessionId,runtimeAdapter:s,sessionRegistryKey:d.registryKey,activationCapability:"managed",activationMode:e.activationMode??"auto_follow"});this.deps.registry.setBinding({registryKey:d.registryKey,bindingId:n.binding.id,roomId:n.binding.roomId,agentIdentityId:n.binding.agentIdentityId,agentMembershipId:n.binding.agentMembershipId,status:n.binding.status,activationMode:n.binding.activationMode,replaceOwner:!0,initialSequence:n.resumeSequence});const r=await this.resolveServerOwnedWorkspace({machineToken:i,roomId:n.binding.roomId,bindingId:n.binding.id,agentIdentityId:e.agentIdentityId});return this.deps.observations.observe({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,hostContextHash:c(o),workspaceHash:c(r),workspacePath:r,lifecycleState:"active",eventName:"ManagedBind"}),n}async restart(e){const{machineId:t,machineToken:i}=this.deps.getMachineCredentials();if(!t||!i)throw new Error("Machine is not paired with Shennian.");const s=g(e.agentType),o=this.deps.hostProcessIdentity(),d=this.deps.registry.register({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,nianSessionId:e.nianSessionId,hostProcessIdentity:o,capabilities:{canIdentifySession:!0,canBindAutomatically:!0,canOpenEmbeddedRoomPage:!1,canResumeIdleSession:!0,canActivateWhileHostOpen:!0}}),n=await this.deps.bindingClient.restart({machineToken:i,bindingId:e.bindingId,previousNianSessionId:e.previousNianSessionId,roomId:e.roomId,agentIdentityId:e.agentIdentityId,nianSessionId:e.nianSessionId,runtimeAdapter:s,sessionRegistryKey:d.registryKey});this.deps.registry.setBinding({registryKey:d.registryKey,bindingId:n.binding.id,roomId:n.binding.roomId,agentIdentityId:n.binding.agentIdentityId,agentMembershipId:n.binding.agentMembershipId,status:n.binding.status,activationMode:n.binding.activationMode,replaceOwner:!0,initialSequence:n.resumeSequence});const r=await this.resolveServerOwnedWorkspace({machineToken:i,roomId:n.binding.roomId,bindingId:n.binding.id,agentIdentityId:e.agentIdentityId});return this.deps.observations.observe({machineId:t,runtimeAdapter:s,sourceSessionKey:e.sourceSessionKey,hostContextHash:c(o),workspaceHash:c(r),workspacePath:r,lifecycleState:"active",eventName:"ManagedRestart"}),n}async resolveServerOwnedWorkspace(e){const t=await this.deps.bindingClient.status(e),i=t.managedWorkspacePath?.trim(),s=t.agent?.sessionMode;if(t.agentIdentityId!==e.agentIdentityId||s!=="standard"&&s!=="manager"||!i)throw new Error("managed_room_workspace_unavailable");return i}}function c(a){return y.createHash("sha256").update(a,"utf8").digest("hex")}function g(a){const e=I(a);if(e)return e;throw new Error(`Agent ${a} does not support managed Room binding.`)}export{b as TrustedManagedRoomBinder};
@@ -50,6 +50,7 @@ export declare class HttpRoomBindingClient {
50
50
  pause: HttpRoomActionClient['pause'];
51
51
  create(input: CreateRemoteRoomBindingInput): Promise<{
52
52
  binding: RemoteRoomBinding;
53
+ resumeSequence: string;
53
54
  idempotent: boolean;
54
55
  }>;
55
56
  restart(input: RestartRemoteRoomBindingInput): Promise<{
@@ -1 +1 @@
1
- import{HttpRoomActionClient as r}from"./room-action-client.js";class o extends Error{code;constructor(e,n){super(n),this.code=e,this.name="RoomBindingHttpError"}}class l{fetchImpl;baseUrl;actionClient;constructor(e,n=fetch){this.fetchImpl=n,this.baseUrl=e.replace(/\/+$/,""),this.actionClient=new r(e,n)}status=e=>this.actionClient.status(e);getAttachmentCapability=e=>this.actionClient.getAttachmentCapability(e);initializeAttachment=e=>this.actionClient.initializeAttachment(e);completeAttachment=e=>this.actionClient.completeAttachment(e);createRoom=e=>this.actionClient.createRoom(e);createOperatorRoom=e=>this.actionClient.createOperatorRoom(e);resolveNativeSession=e=>this.actionClient.resolveNativeSession(e);joinRoom=e=>this.actionClient.joinRoom(e);read=e=>this.actionClient.read(e);send=e=>this.actionClient.send(e);mode=e=>this.actionClient.mode(e);pause=e=>this.actionClient.pause(e);async create(e){let n;try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(e.roomId)}/bindings`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,agentIdentityId:e.agentIdentityId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new o("room_binding_server_unavailable","Shennian Room service is unavailable.")}if(!n.ok){let i=`room_binding_http_${n.status}`;try{const s=await n.json();typeof s.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(s.error)&&(i=s.error)}catch{}throw new o(i,"Shennian Room binding request failed.")}let t;try{t=await n.json()}catch{throw new o("invalid_room_binding_response","Invalid Room binding response.")}return d(t,e)}async restart(e){let n;try{n=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(e.roomId)}/bindings/${encodeURIComponent(e.bindingId)}/session`,{method:"PATCH",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({agentIdentityId:e.agentIdentityId,previousNianSessionId:e.previousNianSessionId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey}),signal:AbortSignal.timeout(1e4)})}catch{throw new o("room_binding_server_unavailable","Shennian Room service is unavailable.")}const t=await n.json().catch(()=>null);if(!n.ok){const s=t&&typeof t.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(t.error)?t.error:`room_binding_http_${n.status}`;throw new o(s,"Shennian Room restart request failed.")}const i=t;if(!i?.binding||i.binding.id!==e.bindingId||i.binding.roomId!==e.roomId||i.binding.agentIdentityId!==e.agentIdentityId||i.binding.nianSessionId!==e.nianSessionId||i.binding.runtimeAdapter!==e.runtimeAdapter||typeof i.binding.agentMembershipId!="string"||typeof i.resumeSequence!="string"||!/^(0|[1-9]\d{0,19})$/.test(i.resumeSequence)||typeof i.idempotent!="boolean")throw new o("invalid_room_binding_response","Invalid Room restart response.");return{binding:i.binding,resumeSequence:i.resumeSequence,idempotent:i.idempotent}}}function d(a,e){if(!a||typeof a!="object")throw new o("invalid_room_binding_response","Invalid Room binding response.");const n=a,t=n.binding;if(!t||typeof t.id!="string"||typeof t.agentMembershipId!="string"||t.roomId!==e.roomId||t.agentIdentityId!==e.agentIdentityId||t.nianSessionId!==e.nianSessionId||t.runtimeAdapter!==e.runtimeAdapter||t.activationCapability!==e.activationCapability||!c(t.activationMode,e)||!["pending_approval","active","paused","detached"].includes(t.status??"")||typeof n.idempotent!="boolean")throw new o("invalid_room_binding_response","Room binding response does not match the request.");return{binding:t,idempotent:n.idempotent}}function c(a,e){return a===e.activationMode}export{l as HttpRoomBindingClient,o as RoomBindingHttpError};
1
+ import{HttpRoomActionClient as r}from"./room-action-client.js";class o extends Error{code;constructor(e,t){super(t),this.code=e,this.name="RoomBindingHttpError"}}class l{fetchImpl;baseUrl;actionClient;constructor(e,t=fetch){this.fetchImpl=t,this.baseUrl=e.replace(/\/+$/,""),this.actionClient=new r(e,t)}status=e=>this.actionClient.status(e);getAttachmentCapability=e=>this.actionClient.getAttachmentCapability(e);initializeAttachment=e=>this.actionClient.initializeAttachment(e);completeAttachment=e=>this.actionClient.completeAttachment(e);createRoom=e=>this.actionClient.createRoom(e);createOperatorRoom=e=>this.actionClient.createOperatorRoom(e);resolveNativeSession=e=>this.actionClient.resolveNativeSession(e);joinRoom=e=>this.actionClient.joinRoom(e);read=e=>this.actionClient.read(e);send=e=>this.actionClient.send(e);mode=e=>this.actionClient.mode(e);pause=e=>this.actionClient.pause(e);async create(e){let t;try{t=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(e.roomId)}/bindings`,{method:"POST",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({bindingIntentId:e.bindingIntentId,agentIdentityId:e.agentIdentityId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey,activationCapability:e.activationCapability,activationMode:e.activationMode}),signal:AbortSignal.timeout(1e4)})}catch{throw new o("room_binding_server_unavailable","Shennian Room service is unavailable.")}if(!t.ok){let i=`room_binding_http_${t.status}`;try{const s=await t.json();typeof s.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(s.error)&&(i=s.error)}catch{}throw new o(i,"Shennian Room binding request failed.")}let n;try{n=await t.json()}catch{throw new o("invalid_room_binding_response","Invalid Room binding response.")}return d(n,e)}async restart(e){let t;try{t=await this.fetchImpl(`${this.baseUrl}/api/rooms/${encodeURIComponent(e.roomId)}/bindings/${encodeURIComponent(e.bindingId)}/session`,{method:"PATCH",headers:{authorization:`Bearer ${e.machineToken}`,"content-type":"application/json"},body:JSON.stringify({agentIdentityId:e.agentIdentityId,previousNianSessionId:e.previousNianSessionId,nianSessionId:e.nianSessionId,runtimeAdapter:e.runtimeAdapter,sessionRegistryKey:e.sessionRegistryKey}),signal:AbortSignal.timeout(1e4)})}catch{throw new o("room_binding_server_unavailable","Shennian Room service is unavailable.")}const n=await t.json().catch(()=>null);if(!t.ok){const s=n&&typeof n.error=="string"&&/^[a-z0-9_-]{1,80}$/.test(n.error)?n.error:`room_binding_http_${t.status}`;throw new o(s,"Shennian Room restart request failed.")}const i=n;if(!i?.binding||i.binding.id!==e.bindingId||i.binding.roomId!==e.roomId||i.binding.agentIdentityId!==e.agentIdentityId||i.binding.nianSessionId!==e.nianSessionId||i.binding.runtimeAdapter!==e.runtimeAdapter||typeof i.binding.agentMembershipId!="string"||typeof i.resumeSequence!="string"||!/^(0|[1-9]\d{0,19})$/.test(i.resumeSequence)||typeof i.idempotent!="boolean")throw new o("invalid_room_binding_response","Invalid Room restart response.");return{binding:i.binding,resumeSequence:i.resumeSequence,idempotent:i.idempotent}}}function d(a,e){if(!a||typeof a!="object")throw new o("invalid_room_binding_response","Invalid Room binding response.");const t=a,n=t.binding;if(!n||typeof n.id!="string"||typeof n.agentMembershipId!="string"||n.roomId!==e.roomId||n.agentIdentityId!==e.agentIdentityId||n.nianSessionId!==e.nianSessionId||n.runtimeAdapter!==e.runtimeAdapter||n.activationCapability!==e.activationCapability||!c(n.activationMode,e)||!["pending_approval","active","paused","detached"].includes(n.status??"")||typeof t.resumeSequence!="string"||!/^(0|[1-9]\d{0,19})$/.test(t.resumeSequence)||typeof t.idempotent!="boolean")throw new o("invalid_room_binding_response","Room binding response does not match the request.");return{binding:n,resumeSequence:t.resumeSequence,idempotent:t.idempotent}}function c(a,e){return a===e.activationMode}export{l as HttpRoomBindingClient,o as RoomBindingHttpError};
@@ -0,0 +1,13 @@
1
+ export type CliDistribution = {
2
+ source: 'desktop-managed' | 'global-cli';
3
+ cliVersion: string;
4
+ desktopVersion?: string;
5
+ updateOwner: 'desktop' | 'cli';
6
+ };
7
+ export declare const DESKTOP_UPGRADE_REQUIRED = "desktop_update_required: This Client is included in Shennian Desktop. Update Desktop in Settings \u2192 Version & Updates. Do not install or upgrade a separate npm Client.";
8
+ /** Read our own package, not argv, PATH, daemon state or inherited Agent env. */
9
+ export declare function readCliDistribution(startFile?: string): CliDistribution;
10
+ export declare function isDesktopDistribution(): boolean;
11
+ export declare function assertStandaloneUpgrade(distribution?: CliDistribution): void;
12
+ /** The private Agent PATH uses signed package resources, not a user's shell alias. */
13
+ export declare function desktopCommandDirectory(startFile?: string): string | null;
@@ -0,0 +1 @@
1
+ import s from"node:fs";import e from"node:path";import{fileURLToPath as u}from"node:url";const m="desktop_update_required: This Client is included in Shennian Desktop. Update Desktop in Settings \u2192 Version & Updates. Do not install or upgrade a separate npm Client.";function d(t=u(import.meta.url)){let n=e.dirname(t);for(let i=0;i<7;i++){const r=e.join(n,"package.json");if(s.existsSync(r)){const o=JSON.parse(s.readFileSync(r,"utf8"));if(o.name==="shennian"){const a=o.shennianDistribution!==void 0;if(a&&o.shennianDistribution?.source!=="desktop-managed")throw new Error("Invalid Shennian distribution metadata. Repair the Desktop installation.");return{source:a?"desktop-managed":"global-cli",cliVersion:o.version??"unknown",...a?{desktopVersion:o.shennianDistribution?.desktopVersion}:{},updateOwner:a?"desktop":"cli"}}}const p=e.dirname(n);if(p===n)break;n=p}throw new Error("Cannot identify the Shennian CLI installation.")}function k(){return d().source==="desktop-managed"}function h(t=d()){if(t.updateOwner==="desktop")throw new Error(m)}function D(t=u(import.meta.url)){if(d(t).source!=="desktop-managed")return null;let n=e.dirname(t);for(let i=0;i<7;i++){const r=e.join(n,"package.json");if(s.existsSync(r)&&JSON.parse(s.readFileSync(r,"utf8")).name==="shennian")return e.join(e.dirname(n),"bin");n=e.dirname(n)}throw new Error("Desktop command directory is unavailable.")}export{m as DESKTOP_UPGRADE_REQUIRED,h as assertStandaloneUpgrade,D as desktopCommandDirectory,k as isDesktopDistribution,d as readCliDistribution};
@@ -57,3 +57,10 @@ export type ManagedAgentPolicyCompileInput = ManagedAgentRuntimeResolutionInput
57
57
  * user's authorization ceiling while each adapter applies what it supports.
58
58
  */
59
59
  export declare function compileManagedAgentPolicy(input: ManagedAgentPolicyCompileInput): Promise<ManagedAgentPolicyCompileResult>;
60
+ export declare function validateManagedAgentWorkDir(rawWorkDir: string, resolver: ManagedAgentPolicyCompileInput['resolveWorkDir']): Promise<{
61
+ ok: true;
62
+ workDir: string;
63
+ } | {
64
+ ok: false;
65
+ errorCode: 'managed_agent_workdir_invalid' | 'managed_agent_workdir_unavailable';
66
+ }>;
@@ -1 +1 @@
1
- import c from"node:fs/promises";import o from"node:path";import{managedAgentExecutionMode as y,parseManagedAgentPermissionPolicy as b,resolveManagedAgentEffectivePermissionPolicy as k}from"@shennian/wire";import{getManagedAgentBaseEnvKeys as _,getManagedAgentProviderEnvKeys as u,getManagedAgentSessionEnvKeys as d}from"../agent-env.js";import{collectPolicyEnforcementGaps as w,resolveManagedAgentRuntimeProtection as P,resolveManagedAgentSecurityProfile as x}from"./managed-agent-runtime.js";import{resolveProtectedShennianDirectories as C}from"./managed-agent-credential-paths.js";function V(e){return!!(e&&(e.executionMode==="native-full"||e.requestedPolicy.executionMode==="native-full"))}function I(e){return{...e.enforcement,effectivePolicy:{version:e.adapterPolicy.version,executionMode:e.executionMode??"restricted",fileAccess:e.adapterPolicy.fileAccess,externalCapabilities:{...e.adapterPolicy.externalCapabilities}}}}async function z(e){const r=b(e.policy);if(!r)return{ok:!1,errorCode:"managed_agent_policy_invalid"};const t=y(r);if((t==="native-full"||r.fileAccess==="host-full")&&!e.hostFullAccessConfirmed)return{ok:!1,errorCode:"managed_agent_host_full_confirmation_required"};const n=await h(e.workDir,e.resolveWorkDir);if(!n.ok)return n;if(await D(n.workDir))return{ok:!1,errorCode:"managed_agent_workdir_invalid"};const a=A(e),i=P(a),l=x(a),s=t==="restricted"?w(r,l):{unavailableCapabilities:[],overgrantedCapabilities:[]},v=g([...t==="restricted"&&i.level!=="hard"?["runtime.hardIsolation"]:[],...t==="restricted"?i.unsupportedCapabilities:[],...s.unavailableCapabilities,...s.overgrantedCapabilities]),p=k(r,i),m={level:i.level,effectivePolicy:p,unsupportedCapabilities:v,runtimeVersion:i.runtimeVersion,platform:i.platform,...i.executableFingerprint?{executableFingerprint:i.executableFingerprint}:{}};return{ok:!0,value:{requestedPolicy:F(r),executionMode:t,enforcement:m,adapterPolicy:{version:r.version,workDir:n.workDir,fileAccess:r.fileAccess,externalCapabilities:{...r.externalCapabilities},denySensitiveFiles:!0,failClosed:!0},environmentPolicy:{inheritDaemonEnv:!1,loadLoginShell:!1,providerEnvKeys:[...u(e.agentType)],sessionEnvKeys:[...d(e.agentType)],shellSubprocess:{inherit:"none",allowedEnvKeys:g([..._(e.platform),...d(e.agentType)]),deniedEnvKeys:[...u(e.agentType)]}}}}}function A(e){return{agentType:e.agentType,runtimeVersion:e.runtimeVersion,platform:e.platform,isWsl:e.isWsl,executableFingerprint:e.executableFingerprint,requireExecutableFingerprint:e.requireExecutableFingerprint,securityDeclaration:e.securityDeclaration}}async function h(e,r){const t=e.trim();if(!t||!o.isAbsolute(t))return{ok:!1,errorCode:"managed_agent_workdir_invalid"};try{const n=await(r??M)(t);return!n||!o.isAbsolute(n)?{ok:!1,errorCode:"managed_agent_workdir_invalid"}:{ok:!0,workDir:o.normalize(n)}}catch{return{ok:!1,errorCode:"managed_agent_workdir_unavailable"}}}async function M(e){const r=await c.realpath(e);if(!(await c.stat(r)).isDirectory())throw new Error("managed_agent_workdir_not_directory");return r}async function D(e){return C().some(t=>E(e,t,process.platform))}function E(e,r,t){const n=l=>{const s=o.resolve(l);return t==="win32"?s.toLowerCase():s},a=n(e),i=n(r);return f(a,i)||f(i,a)}function f(e,r){const t=o.relative(e,r);return t===""||!t.startsWith("..")&&!o.isAbsolute(t)}function F(e){return{...e,externalCapabilities:{...e.externalCapabilities}}}function g(e){return[...new Set(e)]}export{z as compileManagedAgentPolicy,V as isManagedAgentNativeFull,I as resolveManagedAgentAdapterEnforcement};
1
+ import c from"node:fs/promises";import a from"node:path";import{managedAgentExecutionMode as y,parseManagedAgentPermissionPolicy as b,resolveManagedAgentEffectivePermissionPolicy as _}from"@shennian/wire";import{getManagedAgentBaseEnvKeys as k,getManagedAgentProviderEnvKeys as u,getManagedAgentSessionEnvKeys as d}from"../agent-env.js";import{collectPolicyEnforcementGaps as x,resolveManagedAgentRuntimeProtection as P,resolveManagedAgentSecurityProfile as w}from"./managed-agent-runtime.js";import{resolveProtectedShennianDirectories as A}from"./managed-agent-credential-paths.js";function V(e){return!!(e&&(e.executionMode==="native-full"||e.requestedPolicy.executionMode==="native-full"))}function z(e){return{...e.enforcement,effectivePolicy:{version:e.adapterPolicy.version,executionMode:e.executionMode??"restricted",fileAccess:e.adapterPolicy.fileAccess,externalCapabilities:{...e.adapterPolicy.externalCapabilities}}}}async function I(e){const r=b(e.policy);if(!r)return{ok:!1,errorCode:"managed_agent_policy_invalid"};const t=y(r);if((t==="native-full"||r.fileAccess==="host-full")&&!e.hostFullAccessConfirmed)return{ok:!1,errorCode:"managed_agent_host_full_confirmation_required"};const o=await h(e.workDir,e.resolveWorkDir);if(!o.ok)return o;const i=C(e),n=P(i),l=w(i),s=t==="restricted"?x(r,l):{unavailableCapabilities:[],overgrantedCapabilities:[]},v=g([...t==="restricted"&&n.level!=="hard"?["runtime.hardIsolation"]:[],...t==="restricted"?n.unsupportedCapabilities:[],...s.unavailableCapabilities,...s.overgrantedCapabilities]),p=_(r,n),m={level:n.level,effectivePolicy:p,unsupportedCapabilities:v,runtimeVersion:n.runtimeVersion,platform:n.platform,...n.executableFingerprint?{executableFingerprint:n.executableFingerprint}:{}};return{ok:!0,value:{requestedPolicy:F(r),executionMode:t,enforcement:m,adapterPolicy:{version:r.version,workDir:o.workDir,fileAccess:r.fileAccess,externalCapabilities:{...r.externalCapabilities},denySensitiveFiles:!0,failClosed:!0},environmentPolicy:{inheritDaemonEnv:!1,loadLoginShell:!1,providerEnvKeys:[...u(e.agentType)],sessionEnvKeys:[...d(e.agentType)],shellSubprocess:{inherit:"none",allowedEnvKeys:g([...k(e.platform),...d(e.agentType)]),deniedEnvKeys:[...u(e.agentType)]}}}}}function C(e){return{agentType:e.agentType,runtimeVersion:e.runtimeVersion,platform:e.platform,isWsl:e.isWsl,executableFingerprint:e.executableFingerprint,requireExecutableFingerprint:e.requireExecutableFingerprint,securityDeclaration:e.securityDeclaration}}async function h(e,r){const t=e.trim();if(!t||!a.isAbsolute(t))return{ok:!1,errorCode:"managed_agent_workdir_invalid"};try{const o=await(r??M)(t);if(!o||!a.isAbsolute(o))return{ok:!1,errorCode:"managed_agent_workdir_invalid"};const i=a.normalize(o);return await E(i)?{ok:!1,errorCode:"managed_agent_workdir_invalid"}:{ok:!0,workDir:i}}catch{return{ok:!1,errorCode:"managed_agent_workdir_unavailable"}}}async function M(e){const r=await c.realpath(e);if(!(await c.stat(r)).isDirectory())throw new Error("managed_agent_workdir_not_directory");return r}async function E(e){return A().some(t=>D(e,t,process.platform))}function D(e,r,t){const o=l=>{const s=a.resolve(l);return t==="win32"?s.toLowerCase():s},i=o(e),n=o(r);return f(i,n)||f(n,i)}function f(e,r){const t=a.relative(e,r);return t===""||!t.startsWith("..")&&!a.isAbsolute(t)}function F(e){return{...e,externalCapabilities:{...e.externalCapabilities}}}function g(e){return[...new Set(e)]}export{I as compileManagedAgentPolicy,V as isManagedAgentNativeFull,z as resolveManagedAgentAdapterEnforcement,h as validateManagedAgentWorkDir};
@@ -18,6 +18,7 @@ type ValidationDependencies = {
18
18
  registerPiSession?: () => Promise<PiValidationSession>;
19
19
  createAdapter?: (type: AgentType) => AgentAdapter | null;
20
20
  resolveWorkDir?: (workDir: string) => Promise<string>;
21
+ validateWorkDir?: (workDir: string) => Promise<boolean>;
21
22
  timeoutMs?: number;
22
23
  cleanupNativeSession?: (agentType: AgentType, sessionId: string, workDir: string) => void;
23
24
  ignoreNativeSession?: (agentType: AgentType, sessionId: string) => void;
@@ -1 +1 @@
1
- import{registerPiValidationSession as I}from"./pi-validation-session.js";import y from"node:fs/promises";import{randomUUID as S}from"node:crypto";import{isAvailableAgentType as A}from"@shennian/wire";import{createAgent as C}from"../../agents/adapter.js";import{buildManagedAgentEnv as b}from"../../agents/config-status.js";import{ManagerModeAdapter as D}from"../../agents/manager.js";import{NativeSessionLifecycleRegistry as N}from"../native-session-lifecycle.js";const M="\u8BF7\u56DE\u590D hello\uFF0C\u7528\u4E8E\u786E\u8BA4\u4F60\u5DF2\u51C6\u5907\u597D\u3002",T=6e4,x=new N;async function O(e,r={}){try{return await L(e,r)}catch(t){const i=t instanceof Error?t.message:"";return{ok:!1,errorCode:i==="agent_validation_cleanup_failed"?i:k(t,"start")}}}async function L(e,r){if(!A(e.runtimeAdapter)||e.runtimeAdapter==="manager"||e.runtimeAdapter==="pi"||e.runtimeAdapter==="openclaw")return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};if(e.sessionMode==="manager"&&!["codex","claude","pi-coding-agent"].includes(e.runtimeAdapter))return{ok:!1,errorCode:"agent_validation_manager_unavailable"};let t;try{t=await(r.resolveWorkDir??P)(e.workDir)}catch(o){return{ok:!1,errorCode:R(o)}}const i=(r.createAdapter??C)(e.runtimeAdapter);if(!i)return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};const n=e.sessionMode==="manager"?new D(i,e.runtimeAdapter):i;let s=`agent-validation-${S()}`,l,u="",f="",m=null,c=null;const E=new Promise(o=>{c=o}),p=o=>{o.agentSessionId&&(u=o.agentSessionId,r.ignoreNativeSession?.(e.runtimeAdapter,u)),o.state==="delta"&&!o.thinking&&o.text&&(f+=o.text),o.state==="final"?(o.text&&(f+=o.text),c?.({kind:"final"})):(o.state==="error"||o.state==="aborted")&&c?.({kind:"error",error:o.message??o.state})},v=o=>c?.({kind:"error",error:o});n.on("agentEvent",p),n.on("error",v);const h=async()=>{e.runtimeAdapter==="pi-coding-agent"&&(l=await(r.registerPiSession??I)(),s=l.sessionId),n.configure?.({sessionId:s,env:b(e.runtimeAdapter)});try{await n.start(s,t,null,{persistNativeSession:!1})}catch(a){return{ok:!1,errorCode:k(a,"start")}}const o=new Promise(a=>{m=setTimeout(()=>a({kind:"timeout"}),r.timeoutMs??T)}),_=n.send(M,e.modelId??void 0).then(()=>E).catch(a=>({kind:"error",error:a})),d=await Promise.race([_,o]);return d.kind==="timeout"?{ok:!1,errorCode:"agent_validation_response_timeout"}:d.kind==="error"?{ok:!1,errorCode:k(d.error,"response")}:f.toLowerCase().includes("hello")?{ok:!0}:{ok:!1,errorCode:"agent_validation_response_mismatch"}};let w,g=!1;try{w=await h()}finally{m&&clearTimeout(m),n.removeListener("agentEvent",p),n.removeListener("error",v);try{await n.stop()}catch{l&&(g=!0)}finally{await l?.dispose().catch(()=>{g=!0})}u&&(r.cleanupNativeSession??((_,d,a)=>{x.execute(_,d,{workDir:a}).catch(()=>{})}))(e.runtimeAdapter,u,t)}return g?{ok:!1,errorCode:"agent_validation_cleanup_failed"}:w}async function H(e,r){const t=V(r.params);if(!t){e.client.sendRes({type:"res",id:r.id,ok:!1,error:"agent_validation_invalid_configuration"});return}const i=await O(t,{ignoreNativeSession:(n,s)=>{e.nativeFusion?.ignoreNativeSource(n,s)}});e.client.sendRes(i.ok?{type:"res",id:r.id,ok:!0,payload:{ready:!0}}:{type:"res",id:r.id,ok:!1,error:i.errorCode})}async function P(e){const r=e.trim();if(!r)throw Object.assign(new Error("workdir_required"),{code:"EINVAL"});const t=await y.realpath(r);if(!(await y.stat(t)).isDirectory())throw Object.assign(new Error("workdir_not_directory"),{code:"ENOTDIR"});return t}function R(e){const r=W(e);return r==="ENOENT"?"agent_validation_workdir_not_found":r==="ENOTDIR"?"agent_validation_workdir_not_directory":r==="EACCES"||r==="EPERM"?"agent_validation_workdir_unavailable":"agent_validation_workdir_invalid"}function k(e,r){const t=e instanceof Error?e.message:String(e);return t==="agent_validation_server_upgrade_required"?t:/model.*(?:not found|unavailable|unsupported|invalid)|unknown model/i.test(t)?"agent_validation_model_unavailable":/not found|enoent|command .* missing|is .* installed/i.test(t)?"agent_validation_runtime_unavailable":/unauth|authentication|not logged|login required|api key|token.*missing|forbidden|401|403/i.test(t)?"agent_validation_runtime_auth_required":r==="start"?"agent_validation_start_failed":"agent_validation_response_failed"}function W(e){return typeof e=="object"&&e&&"code"in e?String(e.code):""}function V(e){const r=typeof e.runtimeAdapter=="string"?e.runtimeAdapter:"",t=typeof e.workDir=="string"?e.workDir:"",i=e.sessionMode==="manager"?"manager":"standard";return!A(r)||!t.trim()?null:{runtimeAdapter:r,workDir:t,sessionMode:i,modelId:typeof e.modelId=="string"?e.modelId:null}}export{H as handleAgentWorkspaceValidation,O as validateAgentWorkspaceConfiguration};
1
+ import{registerPiValidationSession as I}from"./pi-validation-session.js";import y from"node:fs/promises";import b from"node:path";import{randomUUID as C}from"node:crypto";import{isAvailableAgentType as E}from"@shennian/wire";import{createAgent as N}from"../../agents/adapter.js";import{buildManagedAgentEnv as S}from"../../agents/config-status.js";import{ManagerModeAdapter as T}from"../../agents/manager.js";import{NativeSessionLifecycleRegistry as O}from"../native-session-lifecycle.js";import{validateManagedAgentWorkDir as M}from"../../security/managed-agent-policy.js";const x="\u8BF7\u56DE\u590D hello\uFF0C\u7528\u4E8E\u786E\u8BA4\u4F60\u5DF2\u51C6\u5907\u597D\u3002",R=6e4,W=new O;async function L(e,r={}){try{return await P(e,r)}catch(t){const a=t instanceof Error?t.message:"";return{ok:!1,errorCode:a==="agent_validation_cleanup_failed"?a:v(t,"start")}}}async function P(e,r){if(!E(e.runtimeAdapter)||e.runtimeAdapter==="manager"||e.runtimeAdapter==="pi"||e.runtimeAdapter==="openclaw")return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};if(e.sessionMode==="manager"&&!["codex","claude","pi-coding-agent"].includes(e.runtimeAdapter))return{ok:!1,errorCode:"agent_validation_manager_unavailable"};if(!b.isAbsolute(e.workDir.trim()))return{ok:!1,errorCode:"agent_validation_workdir_invalid"};let t;try{t=await(r.resolveWorkDir??U)(e.workDir)}catch(i){return{ok:!1,errorCode:V(i)}}if(!(r.validateWorkDir?await r.validateWorkDir(t):(await M(t,async()=>t)).ok))return{ok:!1,errorCode:"agent_validation_workdir_invalid"};const s=(r.createAdapter??N)(e.runtimeAdapter);if(!s)return{ok:!1,errorCode:"agent_validation_runtime_unavailable"};const o=e.sessionMode==="manager"?new T(s,e.runtimeAdapter):s;let f=`agent-validation-${C()}`,l,u="",m="",_=null,c=null;const D=new Promise(i=>{c=i}),p=i=>{i.agentSessionId&&(u=i.agentSessionId,r.ignoreNativeSession?.(e.runtimeAdapter,u)),i.state==="delta"&&!i.thinking&&i.text&&(m+=i.text),i.state==="final"?(i.text&&(m+=i.text),c?.({kind:"final"})):(i.state==="error"||i.state==="aborted")&&c?.({kind:"error",error:i.message??i.state})},w=i=>c?.({kind:"error",error:i});o.on("agentEvent",p),o.on("error",w);const h=async()=>{e.runtimeAdapter==="pi-coding-agent"&&(l=await(r.registerPiSession??I)(),f=l.sessionId),o.configure?.({sessionId:f,env:S(e.runtimeAdapter)});try{await o.start(f,t,null,{persistNativeSession:!1})}catch(n){return{ok:!1,errorCode:v(n,"start")}}const i=new Promise(n=>{_=setTimeout(()=>n({kind:"timeout"}),r.timeoutMs??R)}),k=o.send(x,e.modelId??void 0).then(()=>D).catch(n=>({kind:"error",error:n})),d=await Promise.race([k,i]);return d.kind==="timeout"?{ok:!1,errorCode:"agent_validation_response_timeout"}:d.kind==="error"?{ok:!1,errorCode:v(d.error,"response")}:m.toLowerCase().includes("hello")?{ok:!0}:{ok:!1,errorCode:"agent_validation_response_mismatch"}};let A,g=!1;try{A=await h()}finally{_&&clearTimeout(_),o.removeListener("agentEvent",p),o.removeListener("error",w);try{await o.stop()}catch{l&&(g=!0)}finally{await l?.dispose().catch(()=>{g=!0})}u&&(r.cleanupNativeSession??((k,d,n)=>{W.execute(k,d,{workDir:n}).catch(()=>{})}))(e.runtimeAdapter,u,t)}return g?{ok:!1,errorCode:"agent_validation_cleanup_failed"}:A}async function Y(e,r){const t=j(r.params);if(!t){e.client.sendRes({type:"res",id:r.id,ok:!1,error:"agent_validation_invalid_configuration"});return}const a=await L(t,{ignoreNativeSession:(s,o)=>{e.nativeFusion?.ignoreNativeSource(s,o)}});e.client.sendRes(a.ok?{type:"res",id:r.id,ok:!0,payload:{ready:!0}}:{type:"res",id:r.id,ok:!1,error:a.errorCode})}async function U(e){const r=e.trim();if(!r)throw Object.assign(new Error("workdir_required"),{code:"EINVAL"});const t=await y.realpath(r);if(!(await y.stat(t)).isDirectory())throw Object.assign(new Error("workdir_not_directory"),{code:"ENOTDIR"});return t}function V(e){const r=F(e);return r==="ENOENT"?"agent_validation_workdir_not_found":r==="ENOTDIR"?"agent_validation_workdir_not_directory":r==="EACCES"||r==="EPERM"?"agent_validation_workdir_unavailable":"agent_validation_workdir_invalid"}function v(e,r){const t=e instanceof Error?e.message:String(e);return t==="agent_validation_server_upgrade_required"?t:/model.*(?:not found|unavailable|unsupported|invalid)|unknown model/i.test(t)?"agent_validation_model_unavailable":/quota|insufficient.*(?:credit|balance)|billing|rate.?limit|\b429\b/i.test(t)?"agent_validation_quota_exceeded":/not found|enoent|command .* missing|is .* installed/i.test(t)?"agent_validation_runtime_unavailable":/unauth|authentication|not logged|login required|api key|token.*missing|forbidden|401|403/i.test(t)?"agent_validation_runtime_auth_required":/ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT|network|fetch failed|connection.*(?:failed|closed|refused)/i.test(t)?"agent_validation_network_failed":r==="start"?"agent_validation_start_failed":"agent_validation_response_failed"}function F(e){return typeof e=="object"&&e&&"code"in e?String(e.code):""}function j(e){const r=typeof e.runtimeAdapter=="string"?e.runtimeAdapter:"",t=typeof e.workDir=="string"?e.workDir:"",a=e.sessionMode==="manager"?"manager":"standard";return!E(r)||!t.trim()?null:{runtimeAdapter:r,workDir:t,sessionMode:a,modelId:typeof e.modelId=="string"?e.modelId:null}}export{Y as handleAgentWorkspaceValidation,L as validateAgentWorkspaceConfiguration};
@@ -1,5 +1,11 @@
1
- import type { ReqFrame } from '@shennian/wire';
1
+ import type { AgentInfo, ReqFrame } from '@shennian/wire';
2
2
  import type { SessionManagerRuntime } from '../types.js';
3
+ /** Shared discovery path for the App refresh and local CLI. Never sends a model prompt. */
4
+ export declare function scanMachineAgents(refresh?: boolean): Promise<{
5
+ detectedAgents: import("../../agents/detect.js").DetectedAgent[];
6
+ agents: AgentInfo[];
7
+ agentList: import("@shennian/wire").AgentType[];
8
+ }>;
3
9
  export declare function refreshMachineAgents(runtime: SessionManagerRuntime, req?: ReqFrame): Promise<void>;
4
10
  export declare function handleModelsRefresh(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
5
11
  export declare function handleAgentsRefresh(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
@@ -1 +1 @@
1
- import{SERVERS as l}from"../../region.js";import{loadConfig as h}from"../../config/index.js";import{detectAgents as d}from"../../agents/detect.js";import{refreshAgentInfos as g}from"../../agents/model-registry.js";import{resetCommandSpecCache as m}from"../../agents/command-spec.js";import{clearAcpCapabilityCache as y}from"../../agents/acp/capability-cache.js";const i=new WeakMap;async function f(e,t){const s=h(),c=s.serverUrl??l.cn.url,o=await d({serverUrl:c,authToken:s.machineToken??s.accessToken}),p=o.map(n=>n.type);try{const n=o.length===0?[]:await g(o,{serverUrl:c,authToken:s.machineToken??s.accessToken}),a={agentList:p,agents:n};t&&e.client.sendRes({type:"res",id:t.id,ok:!0,payload:a});const r=JSON.stringify(a);i.get(e.client)!==r&&(i.set(e.client,r),e.client.sendEvent({type:"event",event:"machine.agents",payload:a}))}catch(n){if(!t)return;e.client.sendRes({type:"res",id:t.id,ok:!1,error:n instanceof Error?n.message:String(n)})}}async function u(e,t){await f(e,t)}async function v(e,t){m(),y(),e.reloadCustomAgents(),await f(e,t)}export{v as handleAgentsRefresh,u as handleModelsRefresh,f as refreshMachineAgents};
1
+ import{SERVERS as p}from"../../region.js";import{loadConfig as l}from"../../config/index.js";import{detectAgents as g}from"../../agents/detect.js";import{refreshAgentInfos as d}from"../../agents/model-registry.js";import{resetCommandSpecCache as r}from"../../agents/command-spec.js";import{clearAcpCapabilityCache as c}from"../../agents/acp/capability-cache.js";const i=new WeakMap;async function h(e=!1){e&&(r(),c());const t=l(),n={serverUrl:t.serverUrl??p.cn.url,authToken:t.machineToken??t.accessToken},s=await g(n),a=s.length?await d(s,n):[];return{detectedAgents:s,agents:a,agentList:s.map(o=>o.type)}}async function f(e,t){try{const{agentList:n,agents:s}=await h(),a={agentList:n,agents:s};t&&e.client.sendRes({type:"res",id:t.id,ok:!0,payload:a});const o=JSON.stringify(a);i.get(e.client)!==o&&(i.set(e.client,o),e.client.sendEvent({type:"event",event:"machine.agents",payload:a}))}catch(n){if(!t)return;e.client.sendRes({type:"res",id:t.id,ok:!1,error:n instanceof Error?n.message:String(n)})}}async function C(e,t){await f(e,t)}async function R(e,t){r(),c(),e.reloadCustomAgents(),await f(e,t)}export{R as handleAgentsRefresh,C as handleModelsRefresh,f as refreshMachineAgents,h as scanMachineAgents};
@@ -0,0 +1,31 @@
1
+ import { type AgentType, type SessionMode } from '@shennian/wire';
2
+ import type { AgentSendContext } from '../../agents/adapter.js';
3
+ import type { ManagedRoomPromptSnapshot } from '../../room/managed-prompt-composer.js';
4
+ import type { CompiledManagedAgentPolicy } from '../../security/managed-agent-policy.js';
5
+ import type { SessionManagerRuntime } from '../types.js';
6
+ export type ChatSendExecutionContext = (AgentSendContext & {
7
+ source: 'room_activation';
8
+ /** Local-only snapshot produced by RoomActivationService; never accepted from Relay input. */
9
+ managedAgentPolicy: CompiledManagedAgentPolicy;
10
+ managedRoomPromptSnapshot: ManagedRoomPromptSnapshot;
11
+ }) | {
12
+ /** A Worker event may reuse the Room's current permission ceiling, but it
13
+ * is a private Manager continuation and must never receive Room tools. */
14
+ source: 'manager_event';
15
+ managedAgentPolicy: CompiledManagedAgentPolicy;
16
+ managedRoomPolicyVersion: string;
17
+ managedRuntimePolicyHash: string | null;
18
+ };
19
+ export declare function validateManagedRoomExecutionContext(context: ChatSendExecutionContext, systemPrompt: string | null | undefined, managedRoomContextToken: string | null | undefined): void;
20
+ export declare function sendSessionUpdateEvent(runtime: SessionManagerRuntime, input: {
21
+ sessionId: string;
22
+ agentType: AgentType;
23
+ sessionMode?: SessionMode;
24
+ managerConfig?: import('@shennian/wire').ManagerConfig | null;
25
+ workDir: string;
26
+ agentSessionId?: string | null;
27
+ modelId?: string;
28
+ managerDefaultWorkerAgentType?: AgentType | null;
29
+ managerDefaultWorkerModelId?: string | null;
30
+ }): void;
31
+ export declare function resolveNativeSessionVisibility(sessionId: string, agentType: AgentType, sessionMode: SessionMode, managed: boolean): 'user' | 'internal';
@@ -0,0 +1 @@
1
+ import{isInternalSession as a}from"@shennian/wire";import{createHash as t}from"node:crypto";import{listSessionRecords as d,recordSession as m}from"../store.js";function f(o,e,n){if(o.source!=="room_activation")throw new Error("managed_room_execution_context_required");if(!o.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const r=o.managedRoomPromptSnapshot;if(!r)throw new Error("managed_room_prompt_snapshot_missing");if(!e?.trim())throw new Error("managed_room_prompt_incomplete");if(!n||!/^mrc_[A-Za-z0-9_-]{43}$/.test(n))throw new Error("managed_room_context_unavailable");const s=t("sha256").update(JSON.stringify({requestedPolicy:o.managedAgentPolicy.requestedPolicy,enforcement:o.managedAgentPolicy.enforcement})).digest("hex"),i=t("sha256").update(o.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(r.runtimePermissionPolicyHash!==s||r.resolvedWorkDirHash!==i||r.enforcementLevel!==o.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function y(o,e){const n=m({sessionId:e.sessionId,agentType:e.agentType,sessionMode:e.sessionMode,managerConfig:e.managerConfig,workDir:e.workDir,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,managerDefaultWorkerAgentType:e.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:e.managerDefaultWorkerModelId});o.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e.sessionId,agentType:e.agentType,nativeSessionVisibility:n.nativeSessionVisibility,sessionMode:e.sessionMode,managerConfig:e.managerConfig,agentSessionId:e.agentSessionId??null,modelId:e.modelId??null,workDir:e.workDir,status:"active",externalChannel:null}}})}function _(o,e,n,r){const s=d().find(i=>i.sessionId===o);return r||a({...s,id:o})||a({id:o,agentType:e,sessionMode:n,nativeSessionVisibility:s?.nativeSessionVisibility})?"internal":"user"}export{_ as resolveNativeSessionVisibility,y as sendSessionUpdateEvent,f as validateManagedRoomExecutionContext};
@@ -1,5 +1,5 @@
1
- import type { AgentAdapter } from '../../agents/adapter.js';
2
1
  import { type AgentType } from '@shennian/wire';
2
+ import type { AgentAdapter } from '../../agents/adapter.js';
3
3
  import type { SessionManagerRuntime } from '../types.js';
4
4
  export declare function getNativeSourceAgentType(agentType: AgentType, modelId?: string | null): string;
5
5
  export declare function bindAdapterEvents(runtime: SessionManagerRuntime, sessionId: string, agentType: AgentType, adapter: AgentAdapter): void;
@@ -1,2 +1,2 @@
1
- import{createHash as x}from"node:crypto";import{buildApprovalPendingPayload as E}from"@shennian/wire";import{reportLog as $}from"../../log-reporter.js";import{appendMessage as g,recordSession as f,upsertMessage as b}from"../store.js";import{requestSessionIndexPublish as p}from"../index-publisher.js";import{writeToolDetail as k}from"../tool-detail-store.js";import{refreshMachineAgents as y}from"./agents.js";function q(a,e){const n=e?.managedRoomContextToken;!e||!n||(e.managedRoomContextToken=null,a.revokeManagedRoomContextToken?.(n))}function M(a){const e=a.indexOf(`
2
- `),n=e>0?Math.min(e,80):Math.min(a.length,80);return a.slice(0,n)}function S(a,e,n){return`${a}:${x("sha256").update(`${e}\0${n??""}`).digest("hex")}`}function w(a,e,n={}){if(a.state==="tool-call"||a.state==="tool-result"){const u={runId:a.runId,sourceSeq:a.seq};return{state:a.state,runId:a.runId,seq:a.seq,sessionId:e,detailRef:u,status:a.state==="tool-call"?"running":"completed",detailAvailable:!0,...a.durationMs!==void 0?{durationMs:a.durationMs}:{},...a.name?{name:a.name}:{},...a.source?{source:a.source}:{},...a.agentSessionId?{agentSessionId:a.agentSessionId}:{},...n}}return{...a,sessionId:e,...n}}const D=3e4;function _(a){return a.state==="heartbeat"?a.runPhase??null:a.state==="tool-call"||a.state==="tool-result"?"tool_running":a.state==="approval-pending"?"waiting_approval":a.state==="delta"?a.thinking?"thinking":"streaming_text":a.state==="init"||a.state==="start"?"thinking":null}function P(a,e){return a!=="manager"?a:e==="claude"?"claude":"codex"}function F(a,e,n,u){let I=null;function h(t,r={}){a.client.sendAgentEvent({type:"event",event:"agent",payload:w(t,e,r),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}function R(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function T(t){if(!t.currentRunId||!t.currentRunPhase)return;const r=t.heartbeatSeq++;a.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:t.currentRunId,seq:r,runPhase:t.currentRunPhase},seq:r,id:`agent-heartbeat-${t.currentRunId}-${r}-${Date.now()}`})}function A(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{T(t)},D),t.heartbeatTimer.unref?.())}function d(t){const r=t?.pendingTextEvent;!t||!r||!r.text||(g(e,{id:`agent-${r.runId}-${r.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:r.text}),p(a.client),h({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),t.pendingTextEvent=null)}u.on("agentEvent",t=>{t.errorCode==="acp_auth_required"&&y(a).catch(()=>{});const r=a.sessions.get(e),c=_(t),i=t.state==="final"||t.state==="error"||t.state==="aborted";if(r&&(r.nextEventSeq=t.seq+1,i||(r.currentRunId=t.runId),!i&&c&&(r.currentRunPhase=c,A(r)),t.agentSessionId&&(r.agentSessionId=t.agentSessionId),r.journalRunId)){const o={agentSessionId:t.agentSessionId??r.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...i?{}:{phase:c==="waiting_approval"?"waiting_approval":"running"}};a.runJournal?.update(e,r.journalRunId,o)}if(a.managerRuntime?.noteAgentEvent(e,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&$({level:"info",sessionId:e,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:n}});let s=!1;if(t.state==="tool-call"||t.state==="tool-result"){const o=t.toolCallId?`agent-tool-${x("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;k({sessionId:e,toolCallId:o,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?b:g)(e,{id:o,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:o,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),s=!0}else t.state==="approval-pending"?(g(e,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:E({...t.approval,permission:t.permission})}),s=!0,r&&f({sessionId:e,agentType:n,workDir:r.workDir,agentSessionId:r.agentSessionId,attentionId:S("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&(g(e,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:t.message}),s=!0);s&&p(a.client);const l=`${e}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&a.runTextAcc.set(l,(a.runTextAcc.get(l)??"")+t.text),t.agentSessionId&&t.agentSessionId!==I&&(I=t.agentSessionId,a.nativeFusion?.noteManagedSourceSession(e,P(n,t.source),t.agentSessionId),r&&f({sessionId:e,agentType:n,workDir:r.workDir,agentSessionId:t.agentSessionId}),a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:n,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const o=t.text??"";if(!o)return;r?.pendingTextEvent&&r.pendingTextEvent.runId!==t.runId&&d(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=o,r.pendingTextEvent.seq=t.seq);return}let m={};if(t.state==="final"){d(r);const o=a.runTextAcc.get(l)??"";o&&(m={messageSummary:M(o)}),a.runTextAcc.delete(l)}else t.state==="error"||t.state==="aborted"?(d(r),a.runTextAcc.delete(l)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&d(r);i&&r?.currentRunId===t.runId&&(q(a,r),r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,R(r),a.chatQueue?.noteTerminal(e),f({sessionId:e,agentType:n,workDir:r.workDir,agentSessionId:r.agentSessionId,status:t.state==="final"?"completed":"failed",attentionId:S("terminal",t.runId),lastActivityAt:new Date().toISOString()}),p(a.client),r.journalRunId&&(a.runJournal?.remove(e,r.journalRunId),a.recoveryBarrier?.end(e),r.journalRunId=null)),h(t,m)}),u.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${n}: ${t.message}`);const r=a.sessions.get(e);q(a,r),r?.journalRunId&&(a.runJournal?.update(e,r.journalRunId,{phase:"terminal"}),a.runJournal?.remove(e,r.journalRunId),a.recoveryBarrier?.end(e),r.journalRunId=null),a.sessions.delete(e),a.chatQueue?.noteTerminal(e),a.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:t.message,runId:"",seq:0}})})}export{F as bindAdapterEvents,P as getNativeSourceAgentType};
1
+ import{buildApprovalPendingPayload as b}from"@shennian/wire";import{createHash as x}from"node:crypto";import{reportLog as $}from"../../log-reporter.js";import{registerInternalNativeSource as k}from"../../native-fusion/source-visibility.js";import{requestSessionIndexPublish as f}from"../index-publisher.js";import{appendMessage as g,recordSession as p,upsertMessage as M}from"../store.js";import{writeToolDetail as w}from"../tool-detail-store.js";import{refreshMachineAgents as y}from"./agents.js";function S(a,e){const n=e?.managedRoomContextToken;!e||!n||(e.managedRoomContextToken=null,a.revokeManagedRoomContextToken?.(n))}function D(a){const e=a.indexOf(`
2
+ `),n=e>0?Math.min(e,80):Math.min(a.length,80);return a.slice(0,n)}function q(a,e,n){return`${a}:${x("sha256").update(`${e}\0${n??""}`).digest("hex")}`}function _(a,e,n={}){if(a.state==="tool-call"||a.state==="tool-result"){const u={runId:a.runId,sourceSeq:a.seq};return{state:a.state,runId:a.runId,seq:a.seq,sessionId:e,detailRef:u,status:a.state==="tool-call"?"running":"completed",detailAvailable:!0,...a.durationMs!==void 0?{durationMs:a.durationMs}:{},...a.name?{name:a.name}:{},...a.source?{source:a.source}:{},...a.agentSessionId?{agentSessionId:a.agentSessionId}:{},...n}}return{...a,sessionId:e,...n}}const P=3e4;function C(a){return a.state==="heartbeat"?a.runPhase??null:a.state==="tool-call"||a.state==="tool-result"?"tool_running":a.state==="approval-pending"?"waiting_approval":a.state==="delta"?a.thinking?"thinking":"streaming_text":a.state==="init"||a.state==="start"?"thinking":null}function R(a,e){return a!=="manager"?a:e==="claude"?"claude":"codex"}function Q(a,e,n,u){let I=null;function h(t,r={}){a.client.sendAgentEvent({type:"event",event:"agent",payload:_(t,e,r),seq:t.seq,id:`agent-evt-${t.runId}-${t.seq}`})}function T(t){t?.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null)}function A(t){if(!t.currentRunId||!t.currentRunPhase)return;const r=t.heartbeatSeq++;a.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"heartbeat",sessionId:e,runId:t.currentRunId,seq:r,runPhase:t.currentRunPhase},seq:r,id:`agent-heartbeat-${t.currentRunId}-${r}-${Date.now()}`})}function E(t){!t||t.heartbeatTimer||(t.heartbeatTimer=setInterval(()=>{A(t)},P),t.heartbeatTimer.unref?.())}function i(t){const r=t?.pendingTextEvent;!t||!r||!r.text||(g(e,{id:`agent-${r.runId}-${r.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:r.text}),f(a.client),h({state:"delta",runId:r.runId,seq:r.seq,text:r.text,thinking:r.thinking||void 0}),t.pendingTextEvent=null)}u.on("agentEvent",t=>{t.errorCode==="acp_auth_required"&&y(a).catch(()=>{});const r=a.sessions.get(e),c=C(t),d=t.state==="final"||t.state==="error"||t.state==="aborted";if(r&&(r.nextEventSeq=t.seq+1,d||(r.currentRunId=t.runId),!d&&c&&(r.currentRunPhase=c,E(r)),t.agentSessionId&&(r.agentSessionId=t.agentSessionId),r.journalRunId)){const o={agentSessionId:t.agentSessionId??r.agentSessionId,providerRunId:t.runId||null,lastObservedEventSeq:t.seq,...d?{}:{phase:c==="waiting_approval"?"waiting_approval":"running"}};a.runJournal?.update(e,r.journalRunId,o)}if(a.managerRuntime?.noteAgentEvent(e,t),t.state==="delta"&&t.thinking)return;t.state!=="delta"&&$({level:"info",sessionId:e,wsEvent:`agent.${t.state}`,wsDirection:"out",metadata:{runId:t.runId,seq:t.seq,agentType:n}});let s=!1;if(t.state==="tool-call"||t.state==="tool-result"){const o=t.toolCallId?`agent-tool-${x("sha256").update(`${t.runId}\0${t.toolCallId}`).digest("hex")}`:`agent-${t.runId}-${t.seq}`;w({sessionId:e,toolCallId:o,detailRevision:t.seq,ts:Date.now(),name:t.name??"tool",...t.args!==void 0?{args:t.args}:{},...t.result!==void 0?{result:t.result}:{},status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq}}),(t.toolCallId?M:g)(e,{id:o,sessionId:e,role:"agent",ts:Date.now(),payload:JSON.stringify({v:1,type:t.state==="tool-call"?"tool_use":"tool_result",name:t.name,toolCallId:o,status:t.toolStatus??(t.state==="tool-call"?"running":"completed"),...t.durationMs!==void 0?{durationMs:t.durationMs}:{},detailRef:{runId:t.runId,sourceSeq:t.seq},detailRevision:t.seq,detailAvailable:!0,resultOmitted:t.state==="tool-result"})}),s=!0}else t.state==="approval-pending"?(g(e,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:b({...t.approval,permission:t.permission})}),s=!0,r&&p({sessionId:e,agentType:n,workDir:r.workDir,agentSessionId:r.agentSessionId,attentionId:q("approval",t.runId,t.seq)})):(t.state==="error"||t.state==="aborted")&&t.message&&(g(e,{id:`agent-${t.runId||"run"}-${t.seq}`,sessionId:e,role:"agent",ts:Date.now(),payload:t.message}),s=!0);s&&f(a.client);const l=`${e}:${t.runId}`;if(t.state==="delta"&&!t.thinking&&t.text&&a.runTextAcc.set(l,(a.runTextAcc.get(l)??"")+t.text),t.agentSessionId&&t.agentSessionId!==I&&(r?.nativeSessionVisibility==="internal"&&k(e,R(n,t.source)??n,t.agentSessionId),I=t.agentSessionId,a.nativeFusion?.noteManagedSourceSession(e,R(n,t.source),t.agentSessionId),r&&p({sessionId:e,agentType:n,workDir:r.workDir,agentSessionId:t.agentSessionId}),a.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:e,agentType:n,agentSessionId:t.agentSessionId}}})),t.state==="delta"){const o=t.text??"";if(!o)return;r?.pendingTextEvent&&r.pendingTextEvent.runId!==t.runId&&i(r),r&&!r.pendingTextEvent&&(r.pendingTextEvent={runId:t.runId,seq:t.seq,text:"",thinking:!1}),r?.pendingTextEvent&&(r.pendingTextEvent.text+=o,r.pendingTextEvent.seq=t.seq);return}let m={};if(t.state==="final"){i(r);const o=a.runTextAcc.get(l)??"";o&&(m={messageSummary:D(o)}),a.runTextAcc.delete(l)}else t.state==="error"||t.state==="aborted"?(i(r),a.runTextAcc.delete(l)):(t.state==="tool-call"||t.state==="tool-result"||t.state==="approval-pending")&&i(r);d&&r?.currentRunId===t.runId&&(S(a,r),r.currentRunId=null,r.currentRunPhase=null,r.nextEventSeq=0,T(r),a.chatQueue?.noteTerminal(e),p({sessionId:e,agentType:n,workDir:r.workDir,agentSessionId:r.agentSessionId,status:t.state==="final"?"completed":"failed",attentionId:q("terminal",t.runId),lastActivityAt:new Date().toISOString()}),f(a.client),r.journalRunId&&(a.runJournal?.remove(e,r.journalRunId),a.recoveryBarrier?.end(e),r.journalRunId=null)),h(t,m)}),u.on("error",t=>{console.error(`[chat.send] adapter error sessionId=${e} agentType=${n}: ${t.message}`);const r=a.sessions.get(e);S(a,r),r?.journalRunId&&(a.runJournal?.update(e,r.journalRunId,{phase:"terminal"}),a.runJournal?.remove(e,r.journalRunId),a.recoveryBarrier?.end(e),r.journalRunId=null),a.sessions.delete(e),a.chatQueue?.noteTerminal(e),a.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:e,message:t.message,runId:"",seq:0}})})}export{Q as bindAdapterEvents,R as getNativeSourceAgentType};
@@ -1,7 +1,7 @@
1
- import type { AgentAdapter, AgentSendContext, AgentSendResult } from '../../agents/adapter.js';
2
1
  import type { AgentType, ChatAttachmentMeta, ExternalChannelSessionStatus, SessionMode } from '@shennian/wire';
3
- import type { ActiveSession, SessionManagerRuntime } from '../types.js';
2
+ import type { AgentAdapter, AgentSendContext, AgentSendResult } from '../../agents/adapter.js';
4
3
  import type { CompiledManagedAgentPolicy } from '../../security/managed-agent-policy.js';
4
+ import type { ActiveSession, SessionManagerRuntime } from '../types.js';
5
5
  export declare function rememberProcessedReqId(runtime: SessionManagerRuntime, reqId: string): void;
6
6
  export declare function disposeSession(runtime: SessionManagerRuntime, session: ActiveSession): Promise<void>;
7
7
  export declare function sendAdapterTurn(adapter: AgentAdapter, text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[], systemPrompt?: string | null, context?: AgentSendContext): Promise<void | AgentSendResult>;
@@ -1 +1 @@
1
- import{createAgent as v}from"../../agents/adapter.js";import{ManagerModeAdapter as R}from"../../agents/manager.js";import{bindAdapterEvents as A}from"./chat-events.js";import{configureAdapterForSession as w,externalChannelEnv as h,managedProviderEnv as q,revokeManagedRoomContextToken as b}from"./chat-adapter-config.js";function E(r,e){if(r.processedReqIds.add(e),r.processedReqIds.size>1e3){const n=r.processedReqIds.values().next().value;r.processedReqIds.delete(n)}}async function C(r,e){b(r,e),e.heartbeatTimer&&(clearInterval(e.heartbeatTimer),e.heartbeatTimer=null),e.adapter.removeAllListeners(),await e.adapter.stop().catch(()=>{})}function k(r,e,n,a,t,u,l){return l?r.send(e,n,a,t,u,l):u?.trim()?r.send(e,n,a,t,u):t?.length?r.send(e,n,a,t):a?r.send(e,n,a):r.send(e,n)}function M(r,e,n,a,t,u,l){return r.prepareSend?r.prepareSend(e,n,a,t,u,l):Promise.resolve()}async function P(r,e,n,a,t,u,l,c,s,d="user"){r.evictIdleSessions();const p=v(n);if(!p)throw new Error(`Unsupported agent: ${n}`);const o=a==="manager"&&n!=="manager"?new R(p,n):p;w(o,e,n,l,c,null,s,r.managedRoomExecutor),d==="internal"?await o.start(e,t,u,{nativeSessionVisibility:d}):await o.start(e,t,u);const f={adapter:o,workDir:t,agentType:n,sessionMode:a,nativeSessionVisibility:d,agentSessionId:u??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:l??null,externalReplyTarget:c??null,externalChannelEnv:{...q(n),...h(e,l,c)},managedRoomContextToken:null,journalRunId:null};return r.sessions.set(e,f),A(r,e,n,o),f}export{P as createActiveSession,C as disposeSession,M as prepareAdapterTurn,E as rememberProcessedReqId,k as sendAdapterTurn};
1
+ import{createAgent as A}from"../../agents/adapter.js";import{ManagerModeAdapter as h}from"../../agents/manager.js";import{registerInternalNativeSource as q}from"../../native-fusion/source-visibility.js";import{recordSession as w}from"../store.js";import{configureAdapterForSession as x,externalChannelEnv as E,managedProviderEnv as S,revokeManagedRoomContextToken as b}from"./chat-adapter-config.js";import{bindAdapterEvents as C}from"./chat-events.js";function M(n,r){if(n.processedReqIds.add(r),n.processedReqIds.size>1e3){const e=n.processedReqIds.values().next().value;n.processedReqIds.delete(e)}}async function N(n,r){b(n,r),r.heartbeatTimer&&(clearInterval(r.heartbeatTimer),r.heartbeatTimer=null),r.adapter.removeAllListeners(),await r.adapter.stop().catch(()=>{})}function U(n,r,e,u,a,t,l){return l?n.send(r,e,u,a,t,l):t?.trim()?n.send(r,e,u,a,t):a?.length?n.send(r,e,u,a):u?n.send(r,e,u):n.send(r,e)}function $(n,r,e,u,a,t,l){return n.prepareSend?n.prepareSend(r,e,u,a,t,l):Promise.resolve()}async function B(n,r,e,u,a,t,l,d,R,o="user"){n.evictIdleSessions();const p=A(e);if(!p)throw new Error(`Unsupported agent: ${e}`);const c=u==="manager"&&e!=="manager"?new h(p,e):p;x(c,r,e,l,d,null,R,n.managedRoomExecutor),w({sessionId:r,agentType:e,sessionMode:u,workDir:a,agentSessionId:t,nativeSessionVisibility:o}),c.on("nativeSession",(v,m)=>{o==="internal"&&q(r,v,m),w({sessionId:r,agentType:e,workDir:a,agentSessionId:m,nativeSessionVisibility:o})}),o==="internal"&&(e==="codex"||e==="manager")?await c.start(r,a,t,{nativeSessionVisibility:o}):await c.start(r,a,t);const f={adapter:c,workDir:a,agentType:e,sessionMode:u,nativeSessionVisibility:o,agentSessionId:t??null,lastActiveAt:Date.now(),currentRunId:null,currentRunPhase:null,nextEventSeq:0,heartbeatSeq:0,heartbeatTimer:null,pendingTextEvent:null,externalChannel:l??null,externalReplyTarget:d??null,externalChannelEnv:{...S(e),...E(r,l,d)},managedRoomContextToken:null,journalRunId:null};return n.sessions.set(r,f),C(n,r,e,c),f}export{B as createActiveSession,N as disposeSession,$ as prepareAdapterTurn,M as rememberProcessedReqId,U as sendAdapterTurn};
@@ -1,32 +1,6 @@
1
- import type { AgentSendContext } from '../../agents/adapter.js';
2
- import { type ReqFrame, type AgentType, type SessionMode } from '@shennian/wire';
1
+ import { type ReqFrame } from '@shennian/wire';
3
2
  import type { SessionManagerRuntime } from '../types.js';
4
- import type { CompiledManagedAgentPolicy } from '../../security/managed-agent-policy.js';
5
- import { type ManagedRoomPromptSnapshot } from '../../room/managed-prompt-composer.js';
6
- export type ChatSendExecutionContext = (AgentSendContext & {
7
- source: 'room_activation';
8
- /** Local-only snapshot produced by RoomActivationService; never accepted from Relay input. */
9
- managedAgentPolicy: CompiledManagedAgentPolicy;
10
- managedRoomPromptSnapshot: ManagedRoomPromptSnapshot;
11
- }) | {
12
- /** A Worker event may reuse the Room's current permission ceiling, but it
13
- * is a private Manager continuation and must never receive Room tools. */
14
- source: 'manager_event';
15
- managedAgentPolicy: CompiledManagedAgentPolicy;
16
- managedRoomPolicyVersion: string;
17
- managedRuntimePolicyHash: string | null;
18
- };
19
- export declare function validateManagedRoomExecutionContext(context: ChatSendExecutionContext, systemPrompt: string | null | undefined, managedRoomContextToken: string | null | undefined): void;
20
- export declare function sendSessionUpdateEvent(runtime: SessionManagerRuntime, input: {
21
- sessionId: string;
22
- agentType: AgentType;
23
- sessionMode?: SessionMode;
24
- managerConfig?: import('@shennian/wire').ManagerConfig | null;
25
- workDir: string;
26
- agentSessionId?: string | null;
27
- modelId?: string;
28
- managerDefaultWorkerAgentType?: AgentType | null;
29
- managerDefaultWorkerModelId?: string | null;
30
- }): void;
3
+ import { type ChatSendExecutionContext } from './chat-context.js';
4
+ export { sendSessionUpdateEvent, validateManagedRoomExecutionContext, type ChatSendExecutionContext, } from './chat-context.js';
31
5
  export declare function handleChatSend(runtime: SessionManagerRuntime, req: ReqFrame, context?: ChatSendExecutionContext): Promise<void>;
32
6
  export declare function handleChatAbort(runtime: SessionManagerRuntime, req: ReqFrame): Promise<void>;
@@ -1 +1 @@
1
- import de from"node:os";import{createHash as Q,randomUUID as Ae}from"node:crypto";import{buildUserMessagePayload as le}from"@shennian/wire";import{reportLog as T}from"../../log-reporter.js";import{appendMessage as ce,getDaemonInstallationId as ge,getMessageDeliveryStatus as Me,recordSession as Ee,upsertMessage as _}from"../store.js";import{mergeProjectedSessions as De}from"../projection.js";import{parsePersonalAttachmentReferences as Te}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as be,markAttachmentReferences as Ce}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as R}from"../index-publisher.js";import{getPersonalSyncIdentity as $e}from"../../personal-sync/epoch.js";import{isTrustedManagerEvent as xe}from"../manager-event-authority.js";import{buildManagedAgentPermissionPrompt as We}from"../../room/managed-prompt-composer.js";import{getNativeSourceAgentType as qe}from"./chat-events.js";import{configureAdapterForSession as ue,maybeResolveClaudeImportedWorkDir as je,replaceManagedRoomContextToken as me,revokeManagedRoomContextToken as pe}from"./chat-adapter-config.js";import{createActiveSession as Fe,disposeSession as x,prepareAdapterTurn as Be,rememberProcessedReqId as Je,sendAdapterTurn as fe}from"./chat-session-lifecycle.js";function Oe(e,n,o){if(e.source!=="room_activation")throw new Error("managed_room_execution_context_required");if(!e.managedAgentPolicy)throw new Error("managed_agent_policy_missing");const l=e.managedRoomPromptSnapshot;if(!l)throw new Error("managed_room_prompt_snapshot_missing");if(!n?.trim())throw new Error("managed_room_prompt_incomplete");if(!o||!/^mrc_[A-Za-z0-9_-]{43}$/.test(o))throw new Error("managed_room_context_unavailable");const a=Q("sha256").update(JSON.stringify({requestedPolicy:e.managedAgentPolicy.requestedPolicy,enforcement:e.managedAgentPolicy.enforcement})).digest("hex"),b=Q("sha256").update(e.managedAgentPolicy.adapterPolicy.workDir).digest("hex");if(l.runtimePermissionPolicyHash!==a||l.resolvedWorkDirHash!==b||l.enforcementLevel!==e.managedAgentPolicy.enforcement.level)throw new Error("managed_room_prompt_snapshot_mismatch")}function ye(e,n){return`Agent send failed: ${n instanceof Error?n.message:String(n)}`}function He(e,n){Ee({sessionId:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,workDir:n.workDir,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,managerDefaultWorkerAgentType:n.managerDefaultWorkerAgentType,managerDefaultWorkerModelId:n.managerDefaultWorkerModelId}),e.client.sendEvent({type:"event",event:"session.update",payload:{session:{id:n.sessionId,agentType:n.agentType,sessionMode:n.sessionMode,managerConfig:n.managerConfig,agentSessionId:n.agentSessionId??null,modelId:n.modelId??null,workDir:n.workDir,status:"active",externalChannel:null}}})}function ze(e,n){const o=e.sessions.get(n),l=o?.currentRunId;if(!o||!l)return;const a=o.nextEventSeq;e.runTextAcc.delete(`${n}:${l}`),pe(e,o),o.pendingTextEvent=null,o.currentRunId=null,o.currentRunPhase=null,o.nextEventSeq=0,o.heartbeatTimer&&(clearInterval(o.heartbeatTimer),o.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:n,runId:l,seq:a},seq:a,id:`agent-evt-${l}-${a}`}),o.journalRunId&&(e.runJournal?.remove(n,o.journalRunId),e.recoveryBarrier?.end(n),o.journalRunId=null),e.chatQueue?.noteTerminal(n)}async function dn(e,n,o){const l=o?n.params.managedRoomContextToken??null:null;let a=!1;try{await Ne(e,n,o,()=>{a=!0})}finally{l&&!a&&e.revokeManagedRoomContextToken?.(l)}}async function Ne(e,n,o,l){if(e.processedReqIds.has(n.id)){e.client.sendRes({type:"res",id:n.id,ok:!0});return}const{sessionId:a,text:b,agentType:A,sessionMode:ve,managerConfig:Z,workDir:he,agentSessionId:m,modelId:h,systemPrompt:G,managerDefaultWorkerAgentType:W,managerDefaultWorkerModelId:q,reasoningEffort:j,clientMessageId:Ie,sessionListProjection:_e,waitForDispatch:X,responseId:Re,managedRoomContextToken:I,suppressExternalOwnerEcho:we,queuedBatchItems:F,managedWorkerParentSessionId:u,managerWorkerRoomOrigin:B,managerWorkerNativeFull:J,managedRecoverySource:M}=n.params,c=Re||n.id,Y=n.params;if((Y.managerEventId||Y.managerEventRoomOrigin||u||B||J||M)&&!xe(n))throw new Error("manager_event_source_untrusted");De(_e);const C=null,O="";if(o?.source==="room_activation"&&(Oe(o,G,I),A==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(o?.source==="manager_event"){if(!o.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(!I||!/^mrc_[A-Za-z0-9_-]{43}$/.test(I))throw new Error("managed_room_context_unavailable")}if(Je(e,n.id),!a||!b){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(a)&&await e.recoveryBarrier.wait(a);const d=A,w=d==="manager"||ve==="manager"?"manager":"standard";w==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(a,W??null,q??null);const E=(d==="claude"||d==="codex"||d==="workbuddy"||d==="pi-coding-agent"||d.startsWith("acp:"))&&typeof j=="string"&&j.trim()?j.trim():void 0,f=e.resolvePath(je(d,he||de.homedir(),m)||de.homedir()),y=o?.managedAgentPolicy??(u?e.managerRuntime?.getManagedAgentPolicyForWorker(u,f)??null:null);if(u&&!J&&!y)throw new Error("managed_worker_permission_context_unavailable");const H=d==="codex"&&(o?.source==="room_activation"||o?.source==="manager_event"||u)?"internal":"user",z=u&&y?We({requestedPolicy:y.requestedPolicy,enforcement:y.enforcement,resolvedWorkDir:y.adapterPolicy.workDir}):G??null,ke=f,$=Te(n.params.attachments);$?.length&&be(f,$);const p={text:b,attachments:$,localized:!1};let t=e.sessions.get(a);if(t){if(t.lastActiveAt=Date.now(),t.agentType!==d||(t.sessionMode??(t.agentType==="manager"?"manager":"standard"))!==w||t.workDir!==f||(t.nativeSessionVisibility??"user")!==H||JSON.stringify(t.externalChannel??null)!==JSON.stringify(C??null)){e.sessions.delete(a);try{await x(e,t)}catch{e.processedReqIds.delete(n.id)}t=void 0}else if(m&&t.agentSessionId!==m)try{await t.adapter.resume(m),t.agentSessionId=m}catch{e.sessions.delete(a);try{await x(e,t)}catch{e.processedReqIds.delete(n.id)}t=void 0}}if(!t)try{t=await Fe(e,a,d,w,f,m,C,O,y,H)}catch(r){const i=r instanceof Error&&r.message.startsWith("Unsupported agent:")?r.message:`Failed to start ${A}: ${r instanceof Error?r.message:String(r)}`;console.error(`[chat.send] start failed reqId=${n.id} sessionId=${a} agentType=${A} workDir=${f} agentSessionId=${m??""}: ${i}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:i,runId:"",seq:0}}),e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:i});return}const g={id:Ie??`user-${n.id}`,sessionId:a,role:"user",ts:Date.now(),payload:le(p.text,p.attachments)},ee=Array.isArray(F)&&F.length>0?F.map(r=>({id:r.clientMessageId??r.id,sessionId:a,role:M==="manager_event"||n.params.scheduledDelivery===!0?"agent":"user",ts:M==="manager_event"?Date.parse(r.createdAt):g.ts,payload:le(r.text,r.attachments)})):null,k=ee??[g],N=Me(a,g.id),ne=N.state==="queued";if(N.state!=="not_found"&&!ne){e.client.sendRes({type:"res",id:c,ok:!0,payload:N});return}if(X){(o?.source==="room_activation"||o?.source==="manager_event")&&ue(t.adapter,a,d,C,O,I,o.managedAgentPolicy,e.managedRoomExecutor);try{await Be(t.adapter,p.text,h,E,p.attachments,z,o?.source==="room_activation"?{source:"room_activation"}:o?.source==="manager_event"?{source:"managed_private"}:void 0)}catch(r){e.processedReqIds.delete(n.id),e.sessions.delete(a),await x(e,t),e.client.sendRes({type:"res",id:c,ok:!1,error:r instanceof Error?r.message:String(r)});return}}T({level:"info",sessionId:a,wsEvent:"chat.send.start",metadata:{reqId:n.id,agentType:d,sessionMode:w,managerConfig:Z??null,modelId:h,managerDefaultWorkerAgentType:W??null,managerDefaultWorkerModelId:q??null,reasoningEffort:E,...o?.source==="room_activation"?{managedRoomPromptSnapshot:o.managedRoomPromptSnapshot}:{}}});const S=(r,i)=>({...$e(ge()),sessionId:a,clientMessageId:g.id,messageId:g.id,deliveryState:r,bodyRevision:i,committedAt:new Date(g.ts).toISOString()}),U=r=>{e.nativeFusion?.registerManagedSend({sessionId:a,agentType:d,sourceAgentType:qe(d,h),canonicalMessageId:g.id,sourceSessionKey:t.agentSessionId??m??null,text:p.text,managedEchoPolicy:r?.deliveryMode==="external_owner_queue"&&!we?"import_following":"suppress_following",externalRunId:r?.deliveryMode==="external_owner_queue"?`codex-external-${r.queuedSubmissionId??g.id}`:null})},ae=()=>{t.currentRunId||(t.currentRunId=`dispatch:${n.id}`,t.currentRunPhase="thinking",t.nextEventSeq=0)},oe=()=>{if(!e.runJournal||t.journalRunId)return;const r=`run:${Ae()}`;e.runJournal.begin({daemonInstallationId:ge(),sessionId:a,runId:r,clientMessageId:g.id,agentType:d,sessionMode:w,workDir:f,agentSessionId:t.agentSessionId??m??null,modelId:h??null,reasoningEffort:E??null,nativeSessionVisibility:H,providerRunId:null,source:M==="manager_event"?"manager_event":o?.source==="room_activation"?M==="managed_direct"?"managed_direct":"managed_room":u?"manager_worker":"personal",parentSessionId:u??null,managerWorkerNativeFull:J===!0,roomContextRegistryKey:typeof n.params.roomContextRegistryKey=="string"?n.params.roomContextRegistryKey:null,activationCauseMessageId:typeof n.params.activationCauseMessageId=="string"?n.params.activationCauseMessageId:null,rootCauseMessageId:typeof n.params.rootCauseMessageId=="string"?n.params.rootCauseMessageId:null,activationSequence:typeof n.params.activationSequence=="string"?n.params.activationSequence:null,activationHopCount:typeof n.params.activationHopCount=="number"?n.params.activationHopCount:null,managedPolicyVersion:o?.source==="room_activation"?o.managedRoomPromptSnapshot.managedRoomPolicyVersion:o?.source==="manager_event"?o.managedRoomPolicyVersion:null,managedRuntimePolicyHash:(o?.source==="room_activation"?o.managedRoomPromptSnapshot.runtimePermissionPolicyHash:o?.source==="manager_event"?o.managedRuntimePolicyHash:null)??(y?Q("sha256").update(JSON.stringify({requestedPolicy:y.requestedPolicy,enforcement:y.enforcement})).digest("hex"):null)}),t.journalRunId=r},re=()=>{if(U(),ne){let r=0;for(const[i,s]of k.entries()){const v=_(a,s,"queued");i===0&&(r=v)}return S("queued",r)}try{He(e,{sessionId:a,agentType:d,sessionMode:w,managerConfig:Z??null,workDir:ke,agentSessionId:t.agentSessionId??m??null,modelId:h,managerDefaultWorkerAgentType:W??null,managerDefaultWorkerModelId:q??null});let r=0;for(const[i,s]of k.entries()){const v=ee?_(a,s,"committed"):ce(a,s,"committed");i===0&&(r=v)}return Ce(f,$??[]),R(e.client),S("committed",r)}catch(r){throw e.nativeFusion?.cancelManagedSend?.(g.id),r}},te=r=>{t.journalRunId&&e.runJournal?.update(a,t.journalRunId,{deliveryMode:r?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:r?.deliveryMode==="external_owner_queue"?`codex-external-${r.queuedSubmissionId??g.id}`:null})},se=r=>{t.currentRunId||(t.nextEventSeq=0),te(r),U(r);const i=r?.deliveryMode==="external_owner_queue"?"queued":"executing";let s=0;for(const[v,D]of k.entries()){const P=_(a,D,i);v===0&&(s=P)}return R(e.client),S(i,s)},V=async(r,i)=>{e.nativeFusion?.cancelManagedSend?.(g.id);const s=ye(d,r);if(console.error(`[chat.send] send failed reqId=${n.id} sessionId=${a} agentType=${A} workDir=${f} agentSessionId=${t.agentSessionId??m??""}: ${s}`),t.adapter.hasPendingAuthenticationRetry?.()===!0){i&&e.client.sendRes({type:"res",id:c,ok:!0,payload:S("queued",0)});return}e.sessions.delete(a),t.journalRunId&&(e.runJournal?.update(a,t.journalRunId,{phase:"terminal"}),e.runJournal?.remove(a,t.journalRunId),e.recoveryBarrier?.end(a),t.journalRunId=null);try{await x(e,t)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:a,message:s,runId:"",seq:0}}),!i){const D={id:`agent-error-${n.id}-${Date.now()}`,sessionId:a,role:"agent",ts:Date.now(),payload:s};ce(a,D),R(e.client)}i&&(e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:s}))};if(X){try{re()}catch(s){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${s instanceof Error?s.message:String(s)}`});return}oe(),ae();let r;try{(o?.source==="room_activation"||o?.source==="manager_event")&&(me(e,t,I),l());const s=p.attachments;u&&e.managerRuntime?.prepareWorkerTurnOrigin(a,B),r=await fe(t.adapter,p.text,h,E,s,z,o?.source==="room_activation"?{source:"room_activation"}:o?.source==="manager_event"?{source:"managed_private"}:void 0),T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}catch(s){if(u&&e.managerRuntime?.prepareWorkerTurnOrigin(a),t.adapter.hasPendingAuthenticationRetry?.()){let P=0;for(const[K,L]of k.entries()){const Pe=_(a,L,"queued");K===0&&(P=Pe)}R(e.client),await V(s,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:S("queued",P)});return}let v=0;for(const[P,K]of k.entries()){const L=_(a,K,"failed");P===0&&(v=L)}R(e.client);const D=ye(d,s);await V(s,!1),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...S("failed",v),failureMessage:D}});return}const i=se(r??void 0);e.client.sendRes({type:"res",id:c,ok:!0,payload:{...i,...p.localized?{localizedAttachments:!0}:{},...r?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:r.deliveryMode,queuedSubmissionId:r.queuedSubmissionId}:{}}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});return}let ie;try{ie=re()}catch(r){e.processedReqIds.delete(n.id),e.client.sendRes({type:"res",id:c,ok:!1,error:`Durable message commit failed: ${r instanceof Error?r.message:String(r)}`});return}oe(),ae(),(o?.source==="room_activation"||o?.source==="manager_event")&&(ue(t.adapter,a,d,C,O,I,o.managedAgentPolicy,e.managedRoomExecutor),me(e,t,I),l()),se(),e.client.sendRes({type:"res",id:c,ok:!0,payload:{...ie,...p.localized?{localizedAttachments:!0}:{}}}),T({level:"info",sessionId:a,wsEvent:"chat.send.res",metadata:{reqId:n.id,ok:!0}});const Se=p.attachments;u&&e.managerRuntime?.prepareWorkerTurnOrigin(a,B),fe(t.adapter,p.text,h,E,Se,z,o?.source==="room_activation"?{source:"room_activation"}:o?.source==="manager_event"?{source:"managed_private"}:void 0).then(r=>{if(r?.deliveryMode==="external_owner_queue"){te(r),U(r);for(const i of k)_(a,i,"queued");R(e.client)}T({level:"info",sessionId:a,wsEvent:"chat.send.done",metadata:{reqId:n.id}})}).catch(r=>{u&&e.managerRuntime?.prepareWorkerTurnOrigin(a),_(a,g,t.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),R(e.client),V(r,!1)})}async function ln(e,n){const{sessionId:o,discardPending:l}=n.params,a=e.sessions.get(o);if(a){a.journalRunId&&e.runJournal?.markAborted(o,a.journalRunId),pe(e,a);try{await a.adapter.stop()}catch{e.client.sendRes({type:"res",id:n.id,ok:!1,error:"agent_stop_failed"});return}ze(e,o),e.activityPublisher?.publish(o,null)}l===!0&&e.chatQueue?.purgeSession(o),e.client.sendRes({type:"res",id:n.id,ok:!0})}export{ln as handleChatAbort,dn as handleChatSend,He as sendSessionUpdateEvent,Oe as validateManagedRoomExecutionContext};
1
+ import{buildUserMessagePayload as ie}from"@shennian/wire";import{createHash as Me,randomUUID as Ae}from"node:crypto";import de from"node:os";import{reportLog as b}from"../../log-reporter.js";import{getPersonalSyncIdentity as Pe}from"../../personal-sync/epoch.js";import{buildManagedAgentPermissionPrompt as Ee}from"../../room/managed-prompt-composer.js";import{parsePersonalAttachmentReferences as De}from"../attachment-reference.js";import{assertFinishedAttachmentReferences as be,markAttachmentReferences as Te}from"../attachment-transfer-store.js";import{requestSessionIndexPublish as _}from"../index-publisher.js";import{isTrustedManagerEvent as xe}from"../manager-event-authority.js";import{mergeProjectedSessions as Ce}from"../projection.js";import{appendMessage as le,getDaemonInstallationId as ce,getMessageDeliveryStatus as $e,upsertMessage as S}from"../store.js";import{configureAdapterForSession as ue,maybeResolveClaudeImportedWorkDir as We,replaceManagedRoomContextToken as ge,revokeManagedRoomContextToken as me}from"./chat-adapter-config.js";import{resolveNativeSessionVisibility as qe,sendSessionUpdateEvent as je,validateManagedRoomExecutionContext as Fe}from"./chat-context.js";import{getNativeSourceAgentType as Be}from"./chat-events.js";import{createActiveSession as Je,disposeSession as C,prepareAdapterTurn as Oe,rememberProcessedReqId as ze,sendAdapterTurn as pe}from"./chat-session-lifecycle.js";import{sendSessionUpdateEvent as mn,validateManagedRoomExecutionContext as pn}from"./chat-context.js";function fe(e,o){return`Agent send failed: ${o instanceof Error?o.message:String(o)}`}function Ue(e,o){const t=e.sessions.get(o),u=t?.currentRunId;if(!t||!u)return;const n=t.nextEventSeq;e.runTextAcc.delete(`${o}:${u}`),me(e,t),t.pendingTextEvent=null,t.currentRunId=null,t.currentRunPhase=null,t.nextEventSeq=0,t.heartbeatTimer&&(clearInterval(t.heartbeatTimer),t.heartbeatTimer=null),e.client.sendAgentEvent({type:"event",event:"agent",payload:{state:"aborted",sessionId:o,runId:u,seq:n},seq:n,id:`agent-evt-${u}-${n}`}),t.journalRunId&&(e.runJournal?.remove(o,t.journalRunId),e.recoveryBarrier?.end(o),t.journalRunId=null),e.chatQueue?.noteTerminal(o)}async function ln(e,o,t){const u=t?o.params.managedRoomContextToken??null:null;let n=!1;try{await He(e,o,t,()=>{n=!0})}finally{u&&!n&&e.revokeManagedRoomContextToken?.(u)}}async function He(e,o,t,u){if(e.processedReqIds.has(o.id)){e.client.sendRes({type:"res",id:o.id,ok:!0});return}const{sessionId:n,text:Q,agentType:A,sessionMode:ye,managerConfig:L,workDir:ve,agentSessionId:m,modelId:h,systemPrompt:Z,managerDefaultWorkerAgentType:$,managerDefaultWorkerModelId:W,reasoningEffort:q,clientMessageId:he,sessionListProjection:Ie,waitForDispatch:G,responseId:Re,managedRoomContextToken:I,suppressExternalOwnerEcho:_e,queuedBatchItems:j,managedWorkerParentSessionId:g,managerWorkerRoomOrigin:F,managerWorkerNativeFull:B,managedRecoverySource:P}=o.params,l=Re||o.id,X=o.params;if((X.managerEventId||X.managerEventRoomOrigin||g||F||B||P)&&!xe(o))throw new Error("manager_event_source_untrusted");Ce(Ie);const T=null,J="";if(t?.source==="room_activation"&&(Fe(t,Z,I),A==="manager"))throw new Error("managed_agent_manager_mode_unsupported");if(t?.source==="manager_event"){if(!t.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(!I||!/^mrc_[A-Za-z0-9_-]{43}$/.test(I))throw new Error("managed_room_context_unavailable")}if(ze(e,o.id),!n||!Q){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:"sessionId and text are required"});return}if(e.recoveryBarrier?.isDispatchFrozen()){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:"upgrade_in_progress"});return}e.recoveryBarrier?.isRecovering(n)&&await e.recoveryBarrier.wait(n);const d=A,R=d==="manager"||ye==="manager"?"manager":"standard";R==="manager"&&e.managerRuntime?.setManagerWorkerDefaults(n,$??null,W??null);const E=(d==="claude"||d==="codex"||d==="workbuddy"||d==="pi-coding-agent"||d.startsWith("acp:"))&&typeof q=="string"&&q.trim()?q.trim():void 0,y=e.resolvePath(We(d,ve||de.homedir(),m)||de.homedir()),f=t?.managedAgentPolicy??(g?e.managerRuntime?.getManagedAgentPolicyForWorker(g,y)??null:null);if(g&&!B&&!f)throw new Error("managed_worker_permission_context_unavailable");const O=qe(n,d,R,!!(f||g||t)),z=g&&f?Ee({requestedPolicy:f.requestedPolicy,enforcement:f.enforcement,resolvedWorkDir:f.adapterPolicy.workDir}):Z??null,Se=y,x=De(o.params.attachments);x?.length&&be(y,x);const p={text:Q,attachments:x,localized:!1};let r=e.sessions.get(n);if(r){if(r.lastActiveAt=Date.now(),r.agentType!==d||(r.sessionMode??(r.agentType==="manager"?"manager":"standard"))!==R||r.workDir!==y||(r.nativeSessionVisibility??"user")!==O||JSON.stringify(r.externalChannel??null)!==JSON.stringify(T??null)){e.sessions.delete(n);try{await C(e,r)}catch{e.processedReqIds.delete(o.id)}r=void 0}else if(m&&r.agentSessionId!==m)try{await r.adapter.resume(m),r.agentSessionId=m}catch{e.sessions.delete(n);try{await C(e,r)}catch{e.processedReqIds.delete(o.id)}r=void 0}}if(!r)try{r=await Je(e,n,d,R,y,m,T,J,f,O)}catch(a){const i=a instanceof Error&&a.message.startsWith("Unsupported agent:")?a.message:`Failed to start ${A}: ${a instanceof Error?a.message:String(a)}`;console.error(`[chat.send] start failed reqId=${o.id} sessionId=${n} agentType=${A} workDir=${y} agentSessionId=${m??""}: ${i}`),e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:i,runId:"",seq:0}}),e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:i});return}const c={id:he??`user-${o.id}`,sessionId:n,role:"user",ts:Date.now(),payload:ie(p.text,p.attachments)},Y=Array.isArray(j)&&j.length>0?j.map(a=>({id:a.clientMessageId??a.id,sessionId:n,role:P==="manager_event"||o.params.scheduledDelivery===!0?"agent":"user",ts:P==="manager_event"?Date.parse(a.createdAt):c.ts,payload:ie(a.text,a.attachments)})):null,k=Y??[c],U=$e(n,c.id),ee=U.state==="queued";if(U.state!=="not_found"&&!ee){e.client.sendRes({type:"res",id:l,ok:!0,payload:U});return}if(G){(t?.source==="room_activation"||t?.source==="manager_event")&&ue(r.adapter,n,d,T,J,I,t.managedAgentPolicy,e.managedRoomExecutor);try{await Oe(r.adapter,p.text,h,E,p.attachments,z,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0)}catch(a){e.processedReqIds.delete(o.id),e.sessions.delete(n),await C(e,r),e.client.sendRes({type:"res",id:l,ok:!1,error:a instanceof Error?a.message:String(a)});return}}b({level:"info",sessionId:n,wsEvent:"chat.send.start",metadata:{reqId:o.id,agentType:d,sessionMode:R,managerConfig:L??null,modelId:h,managerDefaultWorkerAgentType:$??null,managerDefaultWorkerModelId:W??null,reasoningEffort:E,...t?.source==="room_activation"?{managedRoomPromptSnapshot:t.managedRoomPromptSnapshot}:{}}});const w=(a,i)=>({...Pe(ce()),sessionId:n,clientMessageId:c.id,messageId:c.id,deliveryState:a,bodyRevision:i,committedAt:new Date(c.ts).toISOString()}),H=a=>{e.nativeFusion?.registerManagedSend({sessionId:n,agentType:d,sourceAgentType:Be(d,h),canonicalMessageId:c.id,sourceSessionKey:r.agentSessionId??m??null,text:p.text,managedEchoPolicy:a?.deliveryMode==="external_owner_queue"&&!_e?"import_following":"suppress_following",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??c.id}`:null})},ne=()=>{r.currentRunId||(r.currentRunId=`dispatch:${o.id}`,r.currentRunPhase="thinking",r.nextEventSeq=0)},ae=()=>{if(!e.runJournal||r.journalRunId)return;const a=`run:${Ae()}`;e.runJournal.begin({daemonInstallationId:ce(),sessionId:n,runId:a,clientMessageId:c.id,agentType:d,sessionMode:R,workDir:y,agentSessionId:r.agentSessionId??m??null,modelId:h??null,reasoningEffort:E??null,nativeSessionVisibility:O,providerRunId:null,source:P==="manager_event"?"manager_event":t?.source==="room_activation"?P==="managed_direct"?"managed_direct":"managed_room":g?"manager_worker":"personal",parentSessionId:g??null,managerWorkerNativeFull:B===!0,roomContextRegistryKey:typeof o.params.roomContextRegistryKey=="string"?o.params.roomContextRegistryKey:null,activationCauseMessageId:typeof o.params.activationCauseMessageId=="string"?o.params.activationCauseMessageId:null,rootCauseMessageId:typeof o.params.rootCauseMessageId=="string"?o.params.rootCauseMessageId:null,activationSequence:typeof o.params.activationSequence=="string"?o.params.activationSequence:null,activationHopCount:typeof o.params.activationHopCount=="number"?o.params.activationHopCount:null,managedPolicyVersion:t?.source==="room_activation"?t.managedRoomPromptSnapshot.managedRoomPolicyVersion:t?.source==="manager_event"?t.managedRoomPolicyVersion:null,managedRuntimePolicyHash:(t?.source==="room_activation"?t.managedRoomPromptSnapshot.runtimePermissionPolicyHash:t?.source==="manager_event"?t.managedRuntimePolicyHash:null)??(f?Me("sha256").update(JSON.stringify({requestedPolicy:f.requestedPolicy,enforcement:f.enforcement})).digest("hex"):null)}),r.journalRunId=a},oe=()=>{if(H(),ee){let a=0;for(const[i,s]of k.entries()){const v=S(n,s,"queued");i===0&&(a=v)}return w("queued",a)}try{je(e,{sessionId:n,agentType:d,sessionMode:R,managerConfig:L??null,workDir:Se,agentSessionId:r.agentSessionId??m??null,modelId:h,managerDefaultWorkerAgentType:$??null,managerDefaultWorkerModelId:W??null});let a=0;for(const[i,s]of k.entries()){const v=Y?S(n,s,"committed"):le(n,s,"committed");i===0&&(a=v)}return Te(y,x??[]),_(e.client),w("committed",a)}catch(a){throw e.nativeFusion?.cancelManagedSend?.(c.id),a}},te=a=>{r.journalRunId&&e.runJournal?.update(n,r.journalRunId,{deliveryMode:a?.deliveryMode==="external_owner_queue"?"external_owner_queue":"direct",externalRunId:a?.deliveryMode==="external_owner_queue"?`codex-external-${a.queuedSubmissionId??c.id}`:null})},re=a=>{r.currentRunId||(r.nextEventSeq=0),te(a),H(a);const i=a?.deliveryMode==="external_owner_queue"?"queued":"executing";let s=0;for(const[v,D]of k.entries()){const M=S(n,D,i);v===0&&(s=M)}return _(e.client),w(i,s)},N=async(a,i)=>{e.nativeFusion?.cancelManagedSend?.(c.id);const s=fe(d,a);if(console.error(`[chat.send] send failed reqId=${o.id} sessionId=${n} agentType=${A} workDir=${y} agentSessionId=${r.agentSessionId??m??""}: ${s}`),r.adapter.hasPendingAuthenticationRetry?.()===!0){i&&e.client.sendRes({type:"res",id:l,ok:!0,payload:w("queued",0)});return}e.sessions.delete(n),r.journalRunId&&(e.runJournal?.update(n,r.journalRunId,{phase:"terminal"}),e.runJournal?.remove(n,r.journalRunId),e.recoveryBarrier?.end(n),r.journalRunId=null);try{await C(e,r)}catch{}if(e.client.sendEvent({type:"event",event:"agent",payload:{state:"error",sessionId:n,message:s,runId:"",seq:0}}),!i){const D={id:`agent-error-${o.id}-${Date.now()}`,sessionId:n,role:"agent",ts:Date.now(),payload:s};le(n,D),_(e.client)}i&&(e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:s}))};if(G){try{oe()}catch(s){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:`Durable message commit failed: ${s instanceof Error?s.message:String(s)}`});return}ae(),ne();let a;try{(t?.source==="room_activation"||t?.source==="manager_event")&&(ge(e,r,I),u());const s=p.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(n,F),a=await pe(r.adapter,p.text,h,E,s,z,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0),b({level:"info",sessionId:n,wsEvent:"chat.send.done",metadata:{reqId:o.id}})}catch(s){if(g&&e.managerRuntime?.prepareWorkerTurnOrigin(n),r.adapter.hasPendingAuthenticationRetry?.()){let M=0;for(const[V,K]of k.entries()){const we=S(n,K,"queued");V===0&&(M=we)}_(e.client),await N(s,!1),e.client.sendRes({type:"res",id:l,ok:!0,payload:w("queued",M)});return}let v=0;for(const[M,V]of k.entries()){const K=S(n,V,"failed");M===0&&(v=K)}_(e.client);const D=fe(d,s);await N(s,!1),e.client.sendRes({type:"res",id:l,ok:!0,payload:{...w("failed",v),failureMessage:D}});return}const i=re(a??void 0);e.client.sendRes({type:"res",id:l,ok:!0,payload:{...i,...p.localized?{localizedAttachments:!0}:{},...a?.deliveryMode==="external_owner_queue"?{queued:!0,deliveryMode:a.deliveryMode,queuedSubmissionId:a.queuedSubmissionId}:{}}}),b({level:"info",sessionId:n,wsEvent:"chat.send.res",metadata:{reqId:o.id,ok:!0}});return}let se;try{se=oe()}catch(a){e.processedReqIds.delete(o.id),e.client.sendRes({type:"res",id:l,ok:!1,error:`Durable message commit failed: ${a instanceof Error?a.message:String(a)}`});return}ae(),ne(),(t?.source==="room_activation"||t?.source==="manager_event")&&(ue(r.adapter,n,d,T,J,I,t.managedAgentPolicy,e.managedRoomExecutor),ge(e,r,I),u()),re(),e.client.sendRes({type:"res",id:l,ok:!0,payload:{...se,...p.localized?{localizedAttachments:!0}:{}}}),b({level:"info",sessionId:n,wsEvent:"chat.send.res",metadata:{reqId:o.id,ok:!0}});const ke=p.attachments;g&&e.managerRuntime?.prepareWorkerTurnOrigin(n,F),pe(r.adapter,p.text,h,E,ke,z,t?.source==="room_activation"?{source:"room_activation"}:t?.source==="manager_event"?{source:"managed_private"}:void 0).then(a=>{if(a?.deliveryMode==="external_owner_queue"){te(a),H(a);for(const i of k)S(n,i,"queued");_(e.client)}b({level:"info",sessionId:n,wsEvent:"chat.send.done",metadata:{reqId:o.id}})}).catch(a=>{g&&e.managerRuntime?.prepareWorkerTurnOrigin(n),S(n,c,r.adapter.hasPendingAuthenticationRetry?.()?"queued":"failed"),_(e.client),N(a,!1)})}async function cn(e,o){const{sessionId:t,discardPending:u}=o.params,n=e.sessions.get(t);if(n){n.journalRunId&&e.runJournal?.markAborted(t,n.journalRunId),me(e,n);try{await n.adapter.stop()}catch{e.client.sendRes({type:"res",id:o.id,ok:!1,error:"agent_stop_failed"});return}Ue(e,t),e.activityPublisher?.publish(t,null)}u===!0&&e.chatQueue?.purgeSession(t),e.client.sendRes({type:"res",id:o.id,ok:!0})}export{cn as handleChatAbort,ln as handleChatSend,mn as sendSessionUpdateEvent,pn as validateManagedRoomExecutionContext};