@code-yeongyu/senpi 2026.10.10-4 → 2026.10.10-6

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 (130) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/bundle/chunks/{anthropic-messages-OE3QBX4P.js → anthropic-messages-DUULMQBF.js} +1 -1
  3. package/dist/bundle/chunks/{app-server-command-N3L2LNP7.js → app-server-command-GJ5NXQSY.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-3A3C5VVO.js → chunk-3OGEJMZ7.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-J5MUMVWB.js → chunk-64ZVBCTL.js} +8 -7
  6. package/dist/bundle/chunks/{chunk-MP2DMTI7.js → chunk-C7LEZMWS.js} +124 -124
  7. package/dist/bundle/chunks/{chunk-ZSYRWQWG.js → chunk-JMI5OCIJ.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-ODYQK5XJ.js → chunk-TALS4X7S.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-7GVD54RM.js → chunk-U3IL5N76.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-H67EVDWG.js → chunk-URQSNRHZ.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-H4UIUFU5.js → chunk-VGYIPYOK.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-M2IHGL3M.js → chunk-VW74BGIC.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-4TK7VCZZ.js → chunk-WKMUAG23.js} +1 -1
  14. package/dist/bundle/chunks/chunk-YG5UO3E4.js +7 -0
  15. package/dist/bundle/chunks/chunk-YV2XQFXG.js +14 -0
  16. package/dist/bundle/chunks/{chunk-Z7MMKKIY.js → chunk-ZYHIRFGT.js} +1 -1
  17. package/dist/bundle/chunks/{cli-main-CHDR33FZ.js → cli-main-SZ54SQLA.js} +1 -1
  18. package/dist/bundle/chunks/{help-fast-path-EHRZEBRO.js → help-fast-path-W5W3FYYM.js} +1 -1
  19. package/dist/bundle/chunks/{host-command-VATE7HRG.js → host-command-YG2FIDPN.js} +1 -1
  20. package/dist/bundle/chunks/{host-lifecycle-GC3GIR2N.js → host-lifecycle-5AV4JXDQ.js} +1 -1
  21. package/dist/bundle/chunks/{interactive-mode-RVEM62WX.js → interactive-mode-SCNDQ4R6.js} +1 -1
  22. package/dist/bundle/chunks/{list-tips-IIRFXBTO.js → list-tips-BXAA4FG5.js} +1 -1
  23. package/dist/bundle/chunks/{multi-session-host-CFND7CXH.js → multi-session-host-ZDZMPNP5.js} +7 -6
  24. package/dist/bundle/chunks/{package-manager-cli-NWNECBF7.js → package-manager-cli-4LMYHHKH.js} +1 -1
  25. package/dist/bundle/chunks/{rotation-stream-C5BM7TMM.js → rotation-stream-E3XKSST7.js} +1 -1
  26. package/dist/bundle/chunks/{rpc-mode-JQFUDLNB.js → rpc-mode-ZFNFREN5.js} +1 -1
  27. package/dist/bundle/chunks/{schedule-command-EQ4PQCRP.js → schedule-command-K6CTAB4T.js} +1 -1
  28. package/dist/bundle/chunks/{session-control-endpoint-HMB5T5VD.js → session-control-endpoint-MVSYBGM3.js} +1 -1
  29. package/dist/bundle/chunks/{session-picker-O7OESJWU.js → session-picker-TNXWY5QY.js} +1 -1
  30. package/dist/bundle/chunks/session-worker.js +224 -222
  31. package/dist/bundle/cli.js +1 -1
  32. package/dist/bundle/index.js +1 -1
  33. package/dist/bundle/rpc-entry.js +1 -1
  34. package/dist/bundle/runtime-manifest.json +1 -1
  35. package/dist/core/agent-session-runtime.d.ts +6 -0
  36. package/dist/core/agent-session-runtime.js +18 -0
  37. package/dist/core/agent-session.js +5 -2
  38. package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.js +3 -2
  39. package/dist/core/extensions/builtin/anthropic-subscription/options.js +11 -2
  40. package/dist/core/extensions/builtin/anthropic-subscription/session-reattach.js +4 -1
  41. package/dist/core/extensions/builtin/anthropic-subscription/session-sync.js +3 -0
  42. package/dist/core/extensions/builtin/anthropic-subscription/settings.d.ts +5 -0
  43. package/dist/core/extensions/builtin/anthropic-subscription/settings.js +11 -0
  44. package/dist/core/extensions/builtin/anthropic-subscription/stream.d.ts +1 -0
  45. package/dist/core/extensions/builtin/anthropic-subscription/stream.js +17 -1
  46. package/dist/core/extensions/builtin/compaction/lane-policy.d.ts +20 -12
  47. package/dist/core/extensions/builtin/compaction/lane-policy.js +39 -34
  48. package/dist/core/extensions/builtin/html-render/bootstrap.d.ts +15 -0
  49. package/dist/core/extensions/builtin/html-render/bootstrap.js +123 -0
  50. package/dist/core/extensions/builtin/html-render/images.d.ts +16 -0
  51. package/dist/core/extensions/builtin/html-render/images.js +155 -0
  52. package/dist/core/extensions/builtin/html-render/index.d.ts +3 -0
  53. package/dist/core/extensions/builtin/html-render/index.js +5 -0
  54. package/dist/core/extensions/builtin/html-render/tool.d.ts +19 -0
  55. package/dist/core/extensions/builtin/html-render/tool.js +74 -0
  56. package/dist/core/extensions/builtin/index.js +4 -0
  57. package/dist/core/extensions/builtin/mcp/auth/catalog-identity.d.ts +4 -0
  58. package/dist/core/extensions/builtin/mcp/auth/catalog-identity.js +41 -0
  59. package/dist/core/extensions/builtin/mcp/auth/legacy-lock.d.ts +3 -0
  60. package/dist/core/extensions/builtin/mcp/auth/legacy-lock.js +39 -0
  61. package/dist/core/extensions/builtin/mcp/auth/legacy-migration.d.ts +14 -0
  62. package/dist/core/extensions/builtin/mcp/auth/legacy-migration.js +91 -0
  63. package/dist/core/extensions/builtin/mcp/auth/oauth-refresh.js +1 -1
  64. package/dist/core/extensions/builtin/mcp/auth/token-store.d.ts +1 -0
  65. package/dist/core/extensions/builtin/mcp/auth/token-store.js +19 -90
  66. package/dist/core/extensions/builtin/mcp/catalog-cache.d.ts +7 -3
  67. package/dist/core/extensions/builtin/mcp/catalog-cache.js +61 -12
  68. package/dist/core/extensions/builtin/mcp/catalog.d.ts +3 -1
  69. package/dist/core/extensions/builtin/mcp/catalog.js +2 -0
  70. package/dist/core/extensions/builtin/mcp/connection-types.d.ts +2 -0
  71. package/dist/core/extensions/builtin/mcp/expose/call.d.ts +12 -0
  72. package/dist/core/extensions/builtin/mcp/expose/call.js +60 -0
  73. package/dist/core/extensions/builtin/mcp/expose/proxy.js +16 -3
  74. package/dist/core/extensions/builtin/mcp/expose/register.d.ts +3 -1
  75. package/dist/core/extensions/builtin/mcp/expose/register.js +41 -50
  76. package/dist/core/extensions/builtin/mcp/expose/session.d.ts +4 -0
  77. package/dist/core/extensions/builtin/mcp/expose/session.js +5 -1
  78. package/dist/core/extensions/builtin/mcp/expose/tier-b.js +15 -4
  79. package/dist/core/extensions/builtin/mcp/index.js +5 -26
  80. package/dist/core/extensions/builtin/mcp/invocation.d.ts +42 -0
  81. package/dist/core/extensions/builtin/mcp/invocation.js +118 -0
  82. package/dist/core/extensions/builtin/mcp/service-connection.d.ts +3 -0
  83. package/dist/core/extensions/builtin/mcp/service-connection.js +6 -0
  84. package/dist/core/extensions/builtin/mcp/service-register.d.ts +4 -0
  85. package/dist/core/extensions/builtin/mcp/service-register.js +45 -1
  86. package/dist/core/extensions/builtin/mcp/service-tools-changed.js +26 -3
  87. package/dist/core/extensions/builtin/mcp/service-types.d.ts +6 -0
  88. package/dist/core/extensions/builtin/mcp/service.js +83 -49
  89. package/dist/core/extensions/builtin/mcp/shared-connection.js +17 -4
  90. package/dist/core/extensions/builtin/mcp/sharing-policy.js +1 -0
  91. package/dist/core/extensions/builtin/mcp/startup-race.js +47 -9
  92. package/dist/core/extensions/builtin/permission-system/dispatch-metadata.d.ts +8 -0
  93. package/dist/core/extensions/builtin/permission-system/dispatch-metadata.js +23 -0
  94. package/dist/core/extensions/builtin/permission-system/dispatch-policy.d.ts +14 -0
  95. package/dist/core/extensions/builtin/permission-system/dispatch-policy.js +53 -0
  96. package/dist/core/extensions/builtin/permission-system/dispatch.d.ts +33 -0
  97. package/dist/core/extensions/builtin/permission-system/dispatch.js +106 -0
  98. package/dist/core/extensions/builtin/permission-system/index.js +64 -17
  99. package/dist/core/extensions/builtin/permission-system/prompt.d.ts +1 -1
  100. package/dist/core/extensions/builtin/permission-system/prompt.js +3 -1
  101. package/dist/core/extensions/builtin/permission-system/service.d.ts +11 -1
  102. package/dist/core/extensions/builtin/permission-system/service.js +14 -4
  103. package/dist/core/extensions/builtin/ttsr/detectors/collapse-near-duplicates.d.ts +1 -0
  104. package/dist/core/extensions/builtin/ttsr/detectors/collapse-near-duplicates.js +24 -5
  105. package/dist/index.d.ts +1 -1
  106. package/dist/index.js +1 -1
  107. package/dist/modes/interactive/interactive-mode.js +21 -4
  108. package/dist/modes/rpc/host-reservations.d.ts +1 -1
  109. package/dist/modes/rpc/host-reservations.js +9 -3
  110. package/dist/modes/rpc/rpc-client.js +14 -2
  111. package/dist/modes/rpc/rpc-request-deadline.d.ts +8 -0
  112. package/dist/modes/rpc/rpc-request-deadline.js +10 -0
  113. package/dist/modes/rpc/rpc-types.d.ts +7 -4
  114. package/dist/modes/rpc/session-binding.js +15 -1
  115. package/dist/modes/rpc/session-command-router.d.ts +1 -0
  116. package/dist/modes/rpc/session-command-router.js +16 -0
  117. package/dist/modes/rpc/session-registry-attach.js +8 -2
  118. package/dist/modes/rpc/session-registry.js +5 -7
  119. package/dist/modes/rpc/session-teardown.d.ts +6 -1
  120. package/dist/modes/rpc/session-teardown.js +26 -7
  121. package/dist/modes/rpc/session-worker-client.d.ts +2 -0
  122. package/dist/modes/rpc/session-worker-client.js +6 -0
  123. package/dist/modes/rpc/session-worker-protocol.d.ts +4 -0
  124. package/dist/modes/rpc/session-worker.js +6 -0
  125. package/dist/modes/rpc/worker-session-registry.js +6 -1
  126. package/docs/providers.md +3 -2
  127. package/docs/rpc.md +26 -10
  128. package/package.json +6 -6
  129. package/dist/bundle/chunks/chunk-RADHRQ4K.js +0 -7
  130. package/dist/bundle/chunks/chunk-USRAHAW4.js +0 -14
@@ -1,2 +1,2 @@
1
1
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
2
- import{classifyCredentialFailure,isCommittedRotationOutput,isRotationStreamStart,rendezvousOrder,resolveConfigValue,rotationErrorFromEvent,runCredentialFailover}from"./chunk-4TK7VCZZ.js";import{activeModelBlockUntil,discoverEnvSlots,modelBlockKey,pruneModelBlocks,withModelBlock}from"./chunk-F6EQ7EV3.js";import"./chunk-JEZWV7JW.js";import{acquireHalfOpenLease}from"./chunk-S2TCHQTE.js";import"./chunk-7X72IACK.js";import"./chunk-KUPQO7MC.js";import"./chunk-ODYQK5XJ.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-6WCOSBI7.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import{listSlots}from"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";import{createHash,randomUUID}from"node:crypto";async function releaseLeaseIfModelBlocked(repository,providerId,lane,slotName,leaseId,until){until!==void 0&&await repository.mutateSlotState(providerId,lane,slotName,current=>{if(current?.lease?.id!==leaseId)return current;let{lease:_released,...rest}=current;return rest})}function overlayState(slot,state){return state?{...slot,...state.blockedUntil===void 0?{}:{blockedUntil:state.blockedUntil},...state.blockReason===void 0?{}:{blockReason:state.blockReason},...state.failureCount===void 0?{}:{failureCount:state.failureCount},...state.lease===void 0?{}:{lease:state.lease}}:slot}function overlayModelBlock(slot,until){return until===void 0||slot.blockedUntil!==void 0&&slot.blockedUntil>=until?slot:{...slot,blockedUntil:until,blockReason:slot.blockReason??"rate_limit"}}async function listRotationSlots(sources,options={}){let acquireLeases=options.acquireLeases!==!1,modelId=options.modelId,now=sources.now??Date.now,{providerId,credential,env,repository}=sources,policySlots=[];for(let[name,ref]of Object.entries(sources.policy?.slots??{})){let envVarName=ref.env??`models.json:${name}`,key=ref.env!==void 0?env(ref.env):ref.value!==void 0?await resolveConfigValue(ref.value,{}):void 0;key&&policySlots.push({name,envVarName,key,source:"env"})}if(credential){let state=await repository.listSlots(providerId,"stored"),slots=[];for(let slot of listSlots(credential)){let persisted=state[slot.name],storedRevision=await repository.storedCredentialRevision(providerId,slot.name,{key:slot.key,access:slot.access,refresh:slot.refresh}),applicable=persisted?.credentialRevision===storedRevision?persisted:void 0,modelUntil=activeModelBlockUntil(applicable?.modelBlocks,modelId,now());if(acquireLeases&&modelUntil===void 0&&applicable?.blockedUntil!==void 0&&applicable.blockedUntil<=now()){let lease=await acquireHalfOpenLease(repository,providerId,"stored",slot.name,{now:(sources.now??Date.now)()});if(!lease)continue;let leasedState=(await repository.listSlots(providerId,"stored"))[slot.name],leasedApplicable=leasedState?.credentialRevision===storedRevision?leasedState:void 0,leasedModelUntil=activeModelBlockUntil(leasedApplicable?.modelBlocks,modelId,now());await releaseLeaseIfModelBlocked(repository,providerId,"stored",slot.name,lease.leaseId,leasedModelUntil),slots.push(overlayModelBlock(overlayState({name:slot.name,lane:"stored",pinned:credential.pinned===slot.name,storedRevision},leasedApplicable),leasedModelUntil));continue}slots.push(overlayModelBlock(overlayState({name:slot.name,lane:"stored",pinned:credential.pinned===slot.name,storedRevision},applicable),modelUntil))}if(policySlots.length===0)return slots;let namedSources={...sources,credential:void 0,policy:{...sources.policy,slots:{}}},namedSlots=await listEnvRotationSlots(namedSources,policySlots,acquireLeases,modelId);return[...slots,...namedSlots]}let envSlots=[...discoverEnvSlots(providerId,env),...policySlots];return listEnvRotationSlots(sources,envSlots,acquireLeases,modelId)}async function listEnvRotationSlots(sources,envSlots,acquireLeases,modelId){if(envSlots.length===0)return[];let{providerId,repository}=sources,now=sources.now??Date.now,state=await repository.listSlots(providerId,"env"),slots=[];for(let slot of envSlots){let persisted=state[slot.name],revision=await repository.envCredentialRevision(slot.envVarName,slot.key),applicable=persisted?.credentialRevision===revision?persisted:void 0,modelUntil=activeModelBlockUntil(applicable?.modelBlocks,modelId,now());if(acquireLeases&&modelUntil===void 0&&applicable?.blockedUntil!==void 0&&applicable.blockedUntil<=now()){let lease=await acquireHalfOpenLease(repository,providerId,"env",slot.name,{now:(sources.now??Date.now)()});if(!lease)continue;let leasedState=(await repository.listSlots(providerId,"env"))[slot.name];applicable=leasedState?.credentialRevision===revision?leasedState:void 0,modelUntil=activeModelBlockUntil(applicable?.modelBlocks,modelId,now()),await releaseLeaseIfModelBlocked(repository,providerId,"env",slot.name,lease.leaseId,modelUntil)}slots.push(overlayModelBlock(overlayState({name:slot.name,lane:"env",envKey:slot.key,envVarName:slot.envVarName},applicable),modelUntil))}return slots}var sha256SlotHasher=input=>createHash("sha256").update(input).digest().readBigUInt64BE(0);function modelBlockPatch(family,modelId,blockedUntil,current,now,credentialRevision){let sameMaterial=current!==void 0&&current.credentialRevision===credentialRevision,{stateVersion:_stateVersion,...kept}=sameMaterial?current:{stateVersion:0};return{...kept,lease:void 0,...credentialRevision===void 0?{}:{credentialRevision},modelBlocks:withModelBlock(sameMaterial?current.modelBlocks:void 0,modelBlockKey(family,modelId),blockedUntil,now)}}function blockPatch(block,current,now,credentialRevision,policy,modelId){if(block.reason==="rate_limit"&&block.modelFamily!==void 0&&modelId!==void 0){let blockedUntil=now+Math.min(policy?.cooldownCapMs??block.cooldownMs,block.cooldownMs);return modelBlockPatch(block.modelFamily,modelId,blockedUntil,current,now,credentialRevision)}let failureCount=(current?.failureCount??0)+1,liveModelBlocks=current?.credentialRevision===credentialRevision?pruneModelBlocks(current?.modelBlocks,now):void 0,base={failureCount,...credentialRevision===void 0?{}:{credentialRevision},...current?.lastSuccessAt===void 0?{}:{lastSuccessAt:current.lastSuccessAt},...liveModelBlocks===void 0?{}:{modelBlocks:liveModelBlocks}};return block.reason==="rate_limit"?{...base,blockedUntil:now+Math.min(policy?.cooldownCapMs??block.cooldownMs,block.cooldownMs),blockReason:"rate_limit"}:{...base,blockReason:block.reason}}function streamWithCredentialRotation(options){let{sources,runAttempt}=options,hasher=options.hasher??sha256SlotHasher,affinityKey=options.affinityKey??randomUUID(),useAffinity=sources.policy?.affinity!==!1,now=sources.now??Date.now;return runCredentialFailover({listSlots:()=>listRotationSlots(sources,options.modelId===void 0?{}:{modelId:options.modelId}),select:candidates=>{let pinned=candidates.find(candidate=>candidate.pinned===!0);if(pinned)return pinned;let winner=(useAffinity?rendezvousOrder(affinityKey,candidates,hasher):candidates)[0];if(!winner)throw new Error("credential rotation selected from an empty candidate set");return winner},runAttempt,isCommittedOutput:isCommittedRotationOutput,isStreamStart:isRotationStreamStart,errorFromEvent:rotationErrorFromEvent,classify:(error,context)=>classifyCredentialFailure(error,{...context,nowMs:now(),cooldownBaseMs:sources.policy?.cooldownBaseMs,cooldownCapMs:sources.policy?.cooldownCapMs}),onSuccess:async slot=>{await sources.repository.mutateSlotState(sources.providerId,slot.lane,slot.name,current=>current?{...current,lastSuccessAt:now(),lease:void 0,blockedUntil:void 0,blockReason:void 0,modelBlocks:pruneModelBlocks(current.modelBlocks,now(),options.modelId)}:void 0)},persistBlock:async(slot,block)=>{let revision=slot.lane==="env"&&slot.envVarName!==void 0&&slot.envKey!==void 0?await sources.repository.envCredentialRevision(slot.envVarName,slot.envKey):slot.storedRevision;await sources.repository.mutateSlotState(sources.providerId,slot.lane,slot.name,current=>blockPatch(block,current,now(),revision,sources.policy,options.modelId))},now})}export{listRotationSlots,sha256SlotHasher,streamWithCredentialRotation};
2
+ import{classifyCredentialFailure,isCommittedRotationOutput,isRotationStreamStart,rendezvousOrder,resolveConfigValue,rotationErrorFromEvent,runCredentialFailover}from"./chunk-WKMUAG23.js";import{activeModelBlockUntil,discoverEnvSlots,modelBlockKey,pruneModelBlocks,withModelBlock}from"./chunk-F6EQ7EV3.js";import"./chunk-JEZWV7JW.js";import{acquireHalfOpenLease}from"./chunk-S2TCHQTE.js";import"./chunk-7X72IACK.js";import"./chunk-KUPQO7MC.js";import"./chunk-TALS4X7S.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-6WCOSBI7.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import{listSlots}from"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";import{createHash,randomUUID}from"node:crypto";async function releaseLeaseIfModelBlocked(repository,providerId,lane,slotName,leaseId,until){until!==void 0&&await repository.mutateSlotState(providerId,lane,slotName,current=>{if(current?.lease?.id!==leaseId)return current;let{lease:_released,...rest}=current;return rest})}function overlayState(slot,state){return state?{...slot,...state.blockedUntil===void 0?{}:{blockedUntil:state.blockedUntil},...state.blockReason===void 0?{}:{blockReason:state.blockReason},...state.failureCount===void 0?{}:{failureCount:state.failureCount},...state.lease===void 0?{}:{lease:state.lease}}:slot}function overlayModelBlock(slot,until){return until===void 0||slot.blockedUntil!==void 0&&slot.blockedUntil>=until?slot:{...slot,blockedUntil:until,blockReason:slot.blockReason??"rate_limit"}}async function listRotationSlots(sources,options={}){let acquireLeases=options.acquireLeases!==!1,modelId=options.modelId,now=sources.now??Date.now,{providerId,credential,env,repository}=sources,policySlots=[];for(let[name,ref]of Object.entries(sources.policy?.slots??{})){let envVarName=ref.env??`models.json:${name}`,key=ref.env!==void 0?env(ref.env):ref.value!==void 0?await resolveConfigValue(ref.value,{}):void 0;key&&policySlots.push({name,envVarName,key,source:"env"})}if(credential){let state=await repository.listSlots(providerId,"stored"),slots=[];for(let slot of listSlots(credential)){let persisted=state[slot.name],storedRevision=await repository.storedCredentialRevision(providerId,slot.name,{key:slot.key,access:slot.access,refresh:slot.refresh}),applicable=persisted?.credentialRevision===storedRevision?persisted:void 0,modelUntil=activeModelBlockUntil(applicable?.modelBlocks,modelId,now());if(acquireLeases&&modelUntil===void 0&&applicable?.blockedUntil!==void 0&&applicable.blockedUntil<=now()){let lease=await acquireHalfOpenLease(repository,providerId,"stored",slot.name,{now:(sources.now??Date.now)()});if(!lease)continue;let leasedState=(await repository.listSlots(providerId,"stored"))[slot.name],leasedApplicable=leasedState?.credentialRevision===storedRevision?leasedState:void 0,leasedModelUntil=activeModelBlockUntil(leasedApplicable?.modelBlocks,modelId,now());await releaseLeaseIfModelBlocked(repository,providerId,"stored",slot.name,lease.leaseId,leasedModelUntil),slots.push(overlayModelBlock(overlayState({name:slot.name,lane:"stored",pinned:credential.pinned===slot.name,storedRevision},leasedApplicable),leasedModelUntil));continue}slots.push(overlayModelBlock(overlayState({name:slot.name,lane:"stored",pinned:credential.pinned===slot.name,storedRevision},applicable),modelUntil))}if(policySlots.length===0)return slots;let namedSources={...sources,credential:void 0,policy:{...sources.policy,slots:{}}},namedSlots=await listEnvRotationSlots(namedSources,policySlots,acquireLeases,modelId);return[...slots,...namedSlots]}let envSlots=[...discoverEnvSlots(providerId,env),...policySlots];return listEnvRotationSlots(sources,envSlots,acquireLeases,modelId)}async function listEnvRotationSlots(sources,envSlots,acquireLeases,modelId){if(envSlots.length===0)return[];let{providerId,repository}=sources,now=sources.now??Date.now,state=await repository.listSlots(providerId,"env"),slots=[];for(let slot of envSlots){let persisted=state[slot.name],revision=await repository.envCredentialRevision(slot.envVarName,slot.key),applicable=persisted?.credentialRevision===revision?persisted:void 0,modelUntil=activeModelBlockUntil(applicable?.modelBlocks,modelId,now());if(acquireLeases&&modelUntil===void 0&&applicable?.blockedUntil!==void 0&&applicable.blockedUntil<=now()){let lease=await acquireHalfOpenLease(repository,providerId,"env",slot.name,{now:(sources.now??Date.now)()});if(!lease)continue;let leasedState=(await repository.listSlots(providerId,"env"))[slot.name];applicable=leasedState?.credentialRevision===revision?leasedState:void 0,modelUntil=activeModelBlockUntil(applicable?.modelBlocks,modelId,now()),await releaseLeaseIfModelBlocked(repository,providerId,"env",slot.name,lease.leaseId,modelUntil)}slots.push(overlayModelBlock(overlayState({name:slot.name,lane:"env",envKey:slot.key,envVarName:slot.envVarName},applicable),modelUntil))}return slots}var sha256SlotHasher=input=>createHash("sha256").update(input).digest().readBigUInt64BE(0);function modelBlockPatch(family,modelId,blockedUntil,current,now,credentialRevision){let sameMaterial=current!==void 0&&current.credentialRevision===credentialRevision,{stateVersion:_stateVersion,...kept}=sameMaterial?current:{stateVersion:0};return{...kept,lease:void 0,...credentialRevision===void 0?{}:{credentialRevision},modelBlocks:withModelBlock(sameMaterial?current.modelBlocks:void 0,modelBlockKey(family,modelId),blockedUntil,now)}}function blockPatch(block,current,now,credentialRevision,policy,modelId){if(block.reason==="rate_limit"&&block.modelFamily!==void 0&&modelId!==void 0){let blockedUntil=now+Math.min(policy?.cooldownCapMs??block.cooldownMs,block.cooldownMs);return modelBlockPatch(block.modelFamily,modelId,blockedUntil,current,now,credentialRevision)}let failureCount=(current?.failureCount??0)+1,liveModelBlocks=current?.credentialRevision===credentialRevision?pruneModelBlocks(current?.modelBlocks,now):void 0,base={failureCount,...credentialRevision===void 0?{}:{credentialRevision},...current?.lastSuccessAt===void 0?{}:{lastSuccessAt:current.lastSuccessAt},...liveModelBlocks===void 0?{}:{modelBlocks:liveModelBlocks}};return block.reason==="rate_limit"?{...base,blockedUntil:now+Math.min(policy?.cooldownCapMs??block.cooldownMs,block.cooldownMs),blockReason:"rate_limit"}:{...base,blockReason:block.reason}}function streamWithCredentialRotation(options){let{sources,runAttempt}=options,hasher=options.hasher??sha256SlotHasher,affinityKey=options.affinityKey??randomUUID(),useAffinity=sources.policy?.affinity!==!1,now=sources.now??Date.now;return runCredentialFailover({listSlots:()=>listRotationSlots(sources,options.modelId===void 0?{}:{modelId:options.modelId}),select:candidates=>{let pinned=candidates.find(candidate=>candidate.pinned===!0);if(pinned)return pinned;let winner=(useAffinity?rendezvousOrder(affinityKey,candidates,hasher):candidates)[0];if(!winner)throw new Error("credential rotation selected from an empty candidate set");return winner},runAttempt,isCommittedOutput:isCommittedRotationOutput,isStreamStart:isRotationStreamStart,errorFromEvent:rotationErrorFromEvent,classify:(error,context)=>classifyCredentialFailure(error,{...context,nowMs:now(),cooldownBaseMs:sources.policy?.cooldownBaseMs,cooldownCapMs:sources.policy?.cooldownCapMs}),onSuccess:async slot=>{await sources.repository.mutateSlotState(sources.providerId,slot.lane,slot.name,current=>current?{...current,lastSuccessAt:now(),lease:void 0,blockedUntil:void 0,blockReason:void 0,modelBlocks:pruneModelBlocks(current.modelBlocks,now(),options.modelId)}:void 0)},persistBlock:async(slot,block)=>{let revision=slot.lane==="env"&&slot.envVarName!==void 0&&slot.envKey!==void 0?await sources.repository.envCredentialRevision(slot.envVarName,slot.envKey):slot.storedRevision;await sources.repository.mutateSlotState(sources.providerId,slot.lane,slot.name,current=>blockPatch(block,current,now(),revision,sources.policy,options.modelId))},now})}export{listRotationSlots,sha256SlotHasher,streamWithCredentialRotation};
@@ -1,2 +1,2 @@
1
1
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
2
- import{runRpcMode}from"./chunk-USRAHAW4.js";import"./chunk-H4UIUFU5.js";import"./chunk-J5MUMVWB.js";import"./chunk-ZSYRWQWG.js";import"./chunk-JABBHOD5.js";import"./chunk-IZOTKUWG.js";import"./chunk-ZJHRDQCH.js";import"./chunk-F6EQ7EV3.js";import"./chunk-JEZWV7JW.js";import"./chunk-S2TCHQTE.js";import"./chunk-7X72IACK.js";import"./chunk-KUPQO7MC.js";import"./chunk-YU2P3CAR.js";import"./chunk-CIRZTP7W.js";import"./chunk-YI7SPFDN.js";import"./chunk-HB35RBP4.js";import"./chunk-RRU5LXMS.js";import"./chunk-MH2BFYGN.js";import"./chunk-26UBFF6N.js";import"./chunk-ODYQK5XJ.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-CWLCGRUS.js";import"./chunk-6WCOSBI7.js";import"./chunk-KRNXUTZJ.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-PELNNWGO.js";import"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";export{runRpcMode};
2
+ import{runRpcMode}from"./chunk-YV2XQFXG.js";import"./chunk-VGYIPYOK.js";import"./chunk-64ZVBCTL.js";import"./chunk-JMI5OCIJ.js";import"./chunk-JABBHOD5.js";import"./chunk-IZOTKUWG.js";import"./chunk-ZJHRDQCH.js";import"./chunk-F6EQ7EV3.js";import"./chunk-JEZWV7JW.js";import"./chunk-S2TCHQTE.js";import"./chunk-7X72IACK.js";import"./chunk-KUPQO7MC.js";import"./chunk-YU2P3CAR.js";import"./chunk-CIRZTP7W.js";import"./chunk-YI7SPFDN.js";import"./chunk-HB35RBP4.js";import"./chunk-RRU5LXMS.js";import"./chunk-MH2BFYGN.js";import"./chunk-26UBFF6N.js";import"./chunk-TALS4X7S.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-CWLCGRUS.js";import"./chunk-6WCOSBI7.js";import"./chunk-KRNXUTZJ.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-PELNNWGO.js";import"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";export{runRpcMode};
@@ -1,5 +1,5 @@
1
1
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
2
- import{RUNNER_HEARTBEAT_INTERVAL_MS,RUNNER_HEARTBEAT_STALE_MS,acquireSessionDeliveryLock,cancelScheduledJob,claimOccurrence,formatScheduledMessage,isCancelled,isOwnerAmong,listScheduledJobs,liveRunners,liveSessionHolders,nextRecurringDueAt,ownRunnerIdentity,pruneTombstones,readJobFile,rearmRecurringJob,removeRunnerLease,restoreAbandonedSchedule,restorePending,scheduleDir,settleOccurrence,writeRunnerLease}from"./chunk-QNAG7FYM.js";import"./chunk-U5KVIAHJ.js";import{killWindowsProcessTree}from"./chunk-JEZWV7JW.js";import{resolveCliMainPath}from"./chunk-3A3C5VVO.js";import"./chunk-CIRZTP7W.js";import"./chunk-RADHRQ4K.js";import"./chunk-YI7SPFDN.js";import"./chunk-U3VOXCGP.js";import{APP_NAME,getAgentDir,isBunBinary}from"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-IKOFCODM.js";import{mkdirSync,watch}from"node:fs";import{join as join2}from"node:path";import{spawn}from"node:child_process";import{existsSync}from"node:fs";async function deferWhileSessionOpen(job){if(job.sessionFile===null||!existsSync(job.sessionFile))return;let holders=await liveSessionHolders(job.sessionFile,job.sessionId);if(holders.length!==0)return`session is open in pid ${holders.map(holder=>holder.pid).join(", ")}; waiting until it closes`}var STDERR_TAIL_CHARS=2e3,POSIX_GATE='IFS= read -r _ <&3 || exit 75; exec 3<&-; exec "$0" "$@"';function killTree(pid){if(process.platform==="win32"){killWindowsProcessTree(pid);return}try{process.kill(-pid,"SIGKILL")}catch{}}function runDeliveryProcess(launch,timeoutMs,context={}){return new Promise(resolve=>{let posix=process.platform!=="win32",child=posix?spawn("/bin/sh",["-c",POSIX_GATE,launch.command,...launch.args],{cwd:launch.cwd,env:launch.env,stdio:["pipe","ignore","pipe","pipe"],detached:!0}):spawn(launch.command,[...launch.args],{cwd:launch.cwd,env:launch.env,stdio:["pipe","ignore","pipe"],windowsHide:!0,windowsVerbatimArguments:launch.windowsVerbatimArguments===!0}),stderr="",failure,timer=setTimeout(()=>{failure??=`delivery timed out after ${Math.round(timeoutMs/1e3)}s`,child.pid!==void 0&&killTree(child.pid)},timeoutMs);child.stderr?.on("data",chunk=>{stderr=(stderr+chunk.toString("utf8")).slice(-STDERR_TAIL_CHARS)}),child.stdin?.on("error",()=>{});let gate=posix?child.stdio[3]:null;gate?.on("error",()=>{}),child.on("error",error=>{failure??=error.message}),child.on("close",(code,signal)=>{if(clearTimeout(timer),failure!==void 0)resolve({ok:!1,error:failure});else if(code===0)resolve({ok:!0});else{let status=code===null?`signal ${signal}`:`exit code ${code}`;resolve({ok:!1,error:stderr.trim()?`${status}: ${stderr.trim()}`:status})}});let pid=child.pid;pid!==void 0&&Promise.resolve(context.onSpawn?.(pid)).then(()=>{gate!=null&&"end"in gate&&gate.end(`go
2
+ import{RUNNER_HEARTBEAT_INTERVAL_MS,RUNNER_HEARTBEAT_STALE_MS,acquireSessionDeliveryLock,cancelScheduledJob,claimOccurrence,formatScheduledMessage,isCancelled,isOwnerAmong,listScheduledJobs,liveRunners,liveSessionHolders,nextRecurringDueAt,ownRunnerIdentity,pruneTombstones,readJobFile,rearmRecurringJob,removeRunnerLease,restoreAbandonedSchedule,restorePending,scheduleDir,settleOccurrence,writeRunnerLease}from"./chunk-QNAG7FYM.js";import"./chunk-U5KVIAHJ.js";import{killWindowsProcessTree}from"./chunk-JEZWV7JW.js";import{resolveCliMainPath}from"./chunk-3OGEJMZ7.js";import"./chunk-CIRZTP7W.js";import"./chunk-YG5UO3E4.js";import"./chunk-YI7SPFDN.js";import"./chunk-U3VOXCGP.js";import{APP_NAME,getAgentDir,isBunBinary}from"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-IKOFCODM.js";import{mkdirSync,watch}from"node:fs";import{join as join2}from"node:path";import{spawn}from"node:child_process";import{existsSync}from"node:fs";async function deferWhileSessionOpen(job){if(job.sessionFile===null||!existsSync(job.sessionFile))return;let holders=await liveSessionHolders(job.sessionFile,job.sessionId);if(holders.length!==0)return`session is open in pid ${holders.map(holder=>holder.pid).join(", ")}; waiting until it closes`}var STDERR_TAIL_CHARS=2e3,POSIX_GATE='IFS= read -r _ <&3 || exit 75; exec 3<&-; exec "$0" "$@"';function killTree(pid){if(process.platform==="win32"){killWindowsProcessTree(pid);return}try{process.kill(-pid,"SIGKILL")}catch{}}function runDeliveryProcess(launch,timeoutMs,context={}){return new Promise(resolve=>{let posix=process.platform!=="win32",child=posix?spawn("/bin/sh",["-c",POSIX_GATE,launch.command,...launch.args],{cwd:launch.cwd,env:launch.env,stdio:["pipe","ignore","pipe","pipe"],detached:!0}):spawn(launch.command,[...launch.args],{cwd:launch.cwd,env:launch.env,stdio:["pipe","ignore","pipe"],windowsHide:!0,windowsVerbatimArguments:launch.windowsVerbatimArguments===!0}),stderr="",failure,timer=setTimeout(()=>{failure??=`delivery timed out after ${Math.round(timeoutMs/1e3)}s`,child.pid!==void 0&&killTree(child.pid)},timeoutMs);child.stderr?.on("data",chunk=>{stderr=(stderr+chunk.toString("utf8")).slice(-STDERR_TAIL_CHARS)}),child.stdin?.on("error",()=>{});let gate=posix?child.stdio[3]:null;gate?.on("error",()=>{}),child.on("error",error=>{failure??=error.message}),child.on("close",(code,signal)=>{if(clearTimeout(timer),failure!==void 0)resolve({ok:!1,error:failure});else if(code===0)resolve({ok:!0});else{let status=code===null?`signal ${signal}`:`exit code ${code}`;resolve({ok:!1,error:stderr.trim()?`${status}: ${stderr.trim()}`:status})}});let pid=child.pid;pid!==void 0&&Promise.resolve(context.onSpawn?.(pid)).then(()=>{gate!=null&&"end"in gate&&gate.end(`go
3
3
  `),child.stdin?.end(launch.stdin??"")},error=>{failure??=`could not register the delivery: ${error instanceof Error?error.message:String(error)}`,killTree(pid)})})}function eventEnv(event){return{...process.env,SENPI_SCHEDULE_ID:event.id,SENPI_SCHEDULE_SESSION_ID:event.sessionId,SENPI_SCHEDULE_SESSION_FILE:event.sessionFile??"",SENPI_SCHEDULE_CWD:event.cwd}}function execHookDelivery(command,timeoutMs){let shell=process.platform==="win32"?{command:process.env.ComSpec??"cmd.exe",args:["/d","/s","/c",`"${command}"`],windowsVerbatimArguments:!0}:{command:"/bin/sh",args:["-c",command]};return(event,context)=>runDeliveryProcess({...shell,env:eventEnv(event),stdin:`${JSON.stringify(event)}
4
4
  `,cwd:process.cwd()},timeoutMs,context)}function sessionResumeDelivery(senpi,timeoutMs){return async(event,context)=>existsSync(event.cwd)?event.sessionFile!==null&&!existsSync(event.sessionFile)?{ok:!1,error:`session file no longer exists: ${event.sessionFile}`}:runDeliveryProcess({command:senpi.command,args:[...senpi.args,"-p","--session",event.sessionFile??event.sessionId,event.message],cwd:event.cwd,env:eventEnv(event)},timeoutMs,context):{ok:!1,error:`working directory no longer exists: ${event.cwd}`}}import{join}from"node:path";var DEFERRED_RETRY_MS=15e3,ABANDONED_OCCURRENCE_ERROR="the runner exited while delivering this occurrence; outcome unknown, not retried";async function recoverAbandoned(options,records){let firing=records.filter(record=>record.state==="firing");if(firing.length===0)return{events:[],restoredDueAt:[]};let runners=await(options.runners??(()=>liveRunners(options.dir)))(),events=[],restoredDueAt=[];for(let record of firing){if(record.owner===void 0||record.occurrence===void 0||record.owner.pid===options.owner.pid&&record.owner.processStartedAtMs===options.owner.processStartedAtMs||isOwnerAmong(record.owner,runners))continue;let restored=await restoreAbandonedSchedule(options.dir,record.job,record.occurrence,options.now());restored!==void 0&&restoredDueAt.push(restored.dueAt),await settleOccurrence(options.dir,record.file,record.job,record.occurrence,{ok:!1,error:ABANDONED_OCCURRENCE_ERROR}),events.push({event:"abandoned",id:record.job.id,sessionId:record.job.sessionId,occurrence:record.occurrence,error:ABANDONED_OCCURRENCE_ERROR})}return{events,restoredDueAt}}async function freshPendingJob(options,id){let job=await readJobFile(join(options.dir,"pending",`${id}.json`),id).catch(error=>{if(!(error instanceof Error&&"code"in error&&error.code==="ENOENT"))throw error});if(!(job===void 0||job.dueAt>options.now()||await isCancelled(options.dir,id)))return job}async function fireOne(options,listed){let lock=await acquireSessionDeliveryLock(options.dir,listed.sessionId,{maxDeliveryMs:options.deliveryTimeoutMs});if(!lock.acquired){let holder=lock.heldByPid===void 0?"another runner":`process ${lock.heldByPid}`;return{event:"deferred",id:listed.id,sessionId:listed.sessionId,reason:`${holder} is delivering to this session`}}try{let job=await freshPendingJob(options,listed.id);if(job===void 0)return;let deferReason=await options.shouldDefer?.(job);return deferReason!==void 0?{event:"deferred",id:job.id,sessionId:job.sessionId,reason:deferReason}:await deliverClaimed(options,job,pid=>lock.attachDelivery(pid))}finally{await lock.release()}}async function deliverClaimed(options,job,onSpawn){let record=await claimOccurrence(options.dir,job,options.owner);if(record===void 0)return;let occurrence=job.fireCount+1,firedAt=options.now(),nextDueAt;if(job.everyMs!==null){nextDueAt=nextRecurringDueAt(job.dueAt,job.everyMs,firedAt);try{await rearmRecurringJob(options.dir,{...job,fireCount:occurrence,lastFiredAt:firedAt,dueAt:nextDueAt})}catch(error){throw await restorePending(options.dir,record,job.id),error}}let result;try{result=await options.deliver({type:"scheduled_prompt",id:job.id,sessionId:job.sessionId,sessionFile:job.sessionFile,cwd:job.cwd,prompt:job.prompt,message:formatScheduledMessage(job,firedAt),dueAt:job.dueAt,firedAt,everyMs:job.everyMs,fireCount:occurrence},{onSpawn})}catch(error){result={ok:!1,error:error instanceof Error?error.message:String(error)}}return await settleOccurrence(options.dir,record,{...job,fireCount:occurrence,lastFiredAt:firedAt},occurrence,result),{event:"fired",id:job.id,sessionId:job.sessionId,occurrence,outcome:result.ok?"delivered":"failed",...result.ok?{}:{error:result.error},firedAt,dueAt:job.dueAt,...nextDueAt===void 0||await isCancelled(options.dir,job.id)?{}:{nextDueAt}}}async function runDueJobs(options){let listing=await listScheduledJobs(options.dir),events=listing.invalid.map(invalid=>({event:"invalid",...invalid})),recovery=await recoverAbandoned(options,listing.jobs);events.push(...recovery.events),await pruneTombstones(options.dir,listing,options.now());let nextDueAt,noteNext=dueAt=>{nextDueAt=nextDueAt===void 0?dueAt:Math.min(nextDueAt,dueAt)};for(let dueAt of recovery.restoredDueAt)noteNext(dueAt);let bySession=new Map;for(let{state,job}of listing.jobs){if(state!=="pending")continue;if(job.dueAt>options.now()){noteNext(job.dueAt);continue}if(await isCancelled(options.dir,job.id))continue;let queue=bySession.get(job.sessionId)??[];queue.push(job),bySession.set(job.sessionId,queue)}let queues=[...bySession.values()],workers=Math.max(1,Math.min(options.concurrency??4,queues.length)),next=0;return await Promise.all(Array.from({length:workers},async()=>{for(;next<queues.length;){let queue=queues[next++]??[];for(let job of queue){let event;try{event=await fireOne(options,job)}catch(error){let message=error instanceof Error?error.message:String(error);events.push({event:"error",id:job.id,sessionId:job.sessionId,error:message}),noteNext(options.now()+DEFERRED_RETRY_MS);break}if(event!==void 0&&(events.push(event),event.event==="fired"&&event.nextDueAt!==void 0&&noteNext(event.nextDueAt),event.event==="deferred")){noteNext(options.now()+DEFERRED_RETRY_MS);break}}}})),{events,nextDueAt}}function writeLine(value){process.stdout.write(`${JSON.stringify(value)}
5
5
  `)}function resolveDelivery(options){let timeoutMs=options.timeoutSeconds*1e3;return options.exec!==void 0?{deliver:execHookDelivery(options.exec,timeoutMs),shouldDefer:void 0}:{deliver:sessionResumeDelivery({command:process.execPath,args:isBunBinary?[]:[...process.execArgv,resolveCliMainPath()]},timeoutMs),shouldDefer:deferWhileSessionOpen}}function reporter(){let deferred=new Map,invalid=new Map;return result=>{let ok=!0,stillInvalid=new Set;for(let event of result.events){if(event.event==="deferred"){if(deferred.get(event.id)===event.reason)continue;deferred.set(event.id,event.reason)}else if(event.event==="invalid"){if(stillInvalid.add(event.file),invalid.get(event.file)===event.error)continue;invalid.set(event.file,event.error)}else event.event==="fired"?(deferred.delete(event.id),event.outcome==="failed"&&(ok=!1)):event.event==="error"&&(ok=!1);writeLine(event)}for(let file of invalid.keys())stillInvalid.has(file)||invalid.delete(file);return ok}}async function guardedPass(pass){try{return await pass()}catch(error){return{events:[{event:"error",error:error instanceof Error?error.message:String(error)}],nextDueAt:void 0}}}async function runPasses(dir,options){let plan=resolveDelivery(options),owner=ownRunnerIdentity(),startedAt=Date.now(),lease=()=>writeRunnerLease(dir,{startedAt,watch:options.watch,exec:options.exec??null},Date.now()),report=reporter(),pass=()=>runDueJobs({dir,now:Date.now,deliver:plan.deliver,owner,concurrency:options.concurrency,deliveryTimeoutMs:options.timeoutSeconds*1e3,shouldDefer:plan.shouldDefer});await lease();let leaseFailing=!1,heartbeat=setInterval(()=>{lease().then(()=>{leaseFailing=!1},error=>{leaseFailing||writeLine({event:"lease_error",error:error instanceof Error?error.message:String(error)}),leaseFailing=!0})},RUNNER_HEARTBEAT_INTERVAL_MS),watcher,stopping=!1,wake,stop=()=>{stopping=!0,wake?.()};try{if(!options.watch)return report(await guardedPass(pass))?0:1;process.on("SIGTERM",stop),process.on("SIGINT",stop);let pendingDir=join2(dir,"pending");for(mkdirSync(pendingDir,{recursive:!0,mode:448}),watcher=watch(pendingDir,()=>wake?.()),writeLine({event:"watching",pid:process.pid,dir,pollSeconds:options.pollSeconds});!stopping;){let rescan=!1,woken=new Promise(resolve=>{wake=()=>{rescan=!0,resolve()}}),result=await guardedPass(pass);if(report(result),stopping)break;if(rescan)continue;let untilDue=result.nextDueAt===void 0?Number.POSITIVE_INFINITY:result.nextDueAt-Date.now(),waitMs=Math.max(0,Math.min(options.pollSeconds*1e3,untilDue)),timer;await Promise.race([woken,new Promise(resolve=>timer=setTimeout(resolve,waitMs))]),clearTimeout(timer)}return writeLine({event:"stopped",pid:process.pid}),0}finally{clearInterval(heartbeat),watcher?.close(),process.off("SIGTERM",stop),process.off("SIGINT",stop),await removeRunnerLease(dir)}}var EXIT_OK=0,EXIT_FAILED=1,EXIT_USAGE=2,DEFAULT_POLL_SECONDS=60,DEFAULT_TIMEOUT_SECONDS=900,DEFAULT_CONCURRENCY=4,USAGE=`usage: ${APP_NAME} schedule <list|cancel|run> [options]
@@ -1,3 +1,3 @@
1
1
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
2
- import{WakeScheduler,answeredUiRequestId,availableModelsData,buildRpcSessionState,interruptRunningTurn,onProcessContinue,rpcCommandShapeError,settledQuestionStatus,unansweredQuestionIds,unsupportedThinkingLevel,watchInbox}from"./chunk-ZSYRWQWG.js";import"./chunk-JABBHOD5.js";import{acquireHostEnsureLock,gcHostEndpoints,tuiSocketName}from"./chunk-H67EVDWG.js";import{engineBuildIdentity}from"./chunk-ZJHRDQCH.js";import"./chunk-KUPQO7MC.js";import{MAX_SOCKET_PATH_BYTES,authenticateSocket,createDaemonDirectories,createHostDaemonPaths,createSocketSecret,socketSecretPath,thisProcessStartTime,writeHostRegistration}from"./chunk-RADHRQ4K.js";import{MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,serializeJsonLine}from"./chunk-YI7SPFDN.js";import"./chunk-RRU5LXMS.js";import"./chunk-ODYQK5XJ.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import{VERSION}from"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-6WCOSBI7.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";import{randomUUID}from"node:crypto";import{rm as rm2}from"node:fs/promises";import{chmod}from"node:fs/promises";import{createServer}from"node:net";async function listenControlSocket(socketPath,secret,handlers){let clients=new Set,nextConnection=0,server=createServer(socket=>{clients.add(socket),socket.once("close",()=>clients.delete(socket)),socket.on("error",()=>socket.destroy()),authenticateSocket(socket,secret,()=>acceptConnection(socket,++nextConnection,handlers))});return await new Promise((resolve,reject)=>{server.once("error",reject),server.listen(socketPath,()=>{server.off("error",reject),resolve()})}),server.on("error",error=>handlers.listenerError(error)),await chmod(socketPath,384),{close:()=>closeServer(server,clients)}}function acceptConnection(socket,id,handlers){let connection={id,send:record=>{socket.destroyed||socket.write(serializeJsonLine(record))}},detach=attachJsonlLineReader(socket,line=>{answer(connection,line,handlers)},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>connection.send(failure(void 0,"parse","RPC line exceeds the size limit."))});socket.once("close",()=>{detach(),handlers.closed(connection)})}async function answer(connection,line,handlers){let parsed;try{parsed=JSON.parse(line)}catch{connection.send(failure(void 0,"parse","Invalid JSON."));return}let shapeError=rpcCommandShapeError(parsed);if(shapeError!==void 0||!isCommand(parsed)){connection.send(failure(void 0,"parse",shapeError??"RPC command needs a string `type`."));return}connection.send(await handlers.command(connection,parsed))}function isCommand(value){return typeof value=="object"&&value!==null&&"type"in value&&typeof value.type=="string"}function failure(id,command,error){return{...id===void 0?{}:{id},type:"response",command,success:!1,error}}function success(id,command,data){return{...id===void 0?{}:{id},type:"response",command,success:!0,...data===void 0?{}:{data}}}function closeServer(server,clients){for(let client of clients)client.destroy();return new Promise(resolve=>server.close(()=>resolve()))}var SESSION_CONTROL_COMMANDS=["get_available_models","get_available_thinking_levels","set_model","set_thinking_level","interrupt"];async function runSessionControlCommand(session,controls,command){let{id,type}=command;switch(type){case"get_available_models":return success(id,type,await availableModelsData(session));case"get_available_thinking_levels":return success(id,type,{levels:session.getAvailableThinkingLevels()});case"set_model":return await setModel(session,controls,command);case"set_thinking_level":{let level=session.getAvailableThinkingLevels().find(candidate=>candidate===command.level);return level===void 0?failure(id,type,unsupportedThinkingLevel(command.level)):(controls.selectThinkingLevel(level,command.scope!=="turn"),success(id,type))}case"interrupt":return success(id,type,await interruptRunningTurn(session,command.turnId,()=>controls.interruptTurn()));default:return}}async function setModel(session,controls,command){let{id,type}=command,model=(await session.modelRegistry.getAvailable()).find(candidate=>candidate.provider===command.provider&&candidate.id===command.modelId);if(model===void 0)return failure(id,type,`Model not found: ${String(command.provider)}/${String(command.modelId)}`);try{let change=await controls.selectModel(model);return success(id,type,{...model,systemPromptName:change?.systemPromptName})}catch(error){return failure(id,type,error instanceof Error?error.message:String(error))}}var TUI_CONTROL_CAPABILITY="tui_control",TUI_CONTROL_COMMANDS=["get_protocol_info","list_sessions","get_state","get_messages","set_session_name","subscribe","wake","extension_ui_response",...SESSION_CONTROL_COMMANDS];async function runControlCommand(context,connection,command){let{id,type}=command,{session}=context;switch(type){case"get_protocol_info":{let build=engineBuildIdentity();return success(id,type,{protocolVersion:1,serverVersion:VERSION,capabilities:[TUI_CONTROL_CAPABILITY],mode:"tui",instanceId:context.instanceId,generation:0,engineVersion:build.text,engineOrdinal:build.ordinal,commands:TUI_CONTROL_COMMANDS})}case"list_sessions":return success(id,type,{sessions:[sessionRow(session)]});case"get_state":return success(id,type,{...buildRpcSessionState(session),turn_epoch:session.externalAdmission.turnEpoch,blocking_question:context.surface.blockingQuestion(),compacting:session.isCompacting,editor_has_draft:context.surface.draftHold()!==void 0,state_version:context.feed.stateVersion});case"get_messages":return success(id,type,{messages:session.messages});case"set_session_name":{let name=typeof command.name=="string"?command.name.trim():"";return name===""?failure(id,type,"Session name cannot be empty"):(session.setSessionName(name),success(id,type))}case"subscribe":{let cursor=typeof command.cursor=="number"?command.cursor:void 0;return success(id,type,{cursor:context.feed.subscribe(connection.id,cursor,connection.send)})}case"wake":{let ids=Array.isArray(command.delivery_ids)?command.delivery_ids.filter(entry=>typeof entry=="string"):void 0,result=await context.wake(ids);return success(id,type,{admitted:result.admitted??[]})}case"extension_ui_response":return answerQuestion(context.surface,command);default:return await runSessionControlCommand(session,context.surface,command)??failure(id,type,"unsupported")}}function sessionRow(session){let manager=session.sessionManager,created=manager.getHeader()?.timestamp??null,last=manager.getEntries().at(-1);return{sessionId:session.sessionId,sessionPath:session.sessionFile??null,session_file:session.sessionFile??null,kind:"interactive",surface:"tui",cwd:manager.getCwd(),name:session.sessionName??null,created_at:created,updated_at:last?.timestamp??created,attachments:1}}function answerQuestion(surface,command){let frameId=command.id,requestId=answeredUiRequestId(command),request=requestId===void 0?void 0:surface.pendingQuestion(requestId);if(requestId===void 0||request===void 0)return failure(frameId,"extension_ui_response","unknown_request");let response=questionResponse(command,request.questions);return response==="question_incomplete"?failure(frameId,"extension_ui_response",response):response===void 0||!surface.answerQuestion(requestId,response)?failure(frameId,"extension_ui_response","invalid_response"):success(frameId,"extension_ui_response")}function questionResponse(command,questions){if(command.cancelled===!0)return{status:"cancelled",answers:{},unanswered:[]};let answers=command.answers;if(typeof answers!="object"||answers===null||Array.isArray(answers))return;let parsed={};for(let[question,value]of Object.entries(answers)){if(typeof value!="object"||value===null||!("selected"in value)||!Array.isArray(value.selected))return;let selected=value.selected.filter(entry=>typeof entry=="string"),text="text"in value&&typeof value.text=="string"?value.text:void 0;parsed[question]=text===void 0?{selected}:{selected,text}}let comment=typeof command.comment=="string"?command.comment:void 0,status=settledQuestionStatus(parsed,comment);if(status===void 0)return"question_incomplete";let unanswered=unansweredQuestionIds(questions,parsed);return{status,resolvedBy:"control_endpoint",answers:parsed,unanswered,...comment===void 0?{}:{comment}}}var ControlFeed=class{constructor(){this.seq=0,this.stateVersionValue=0,this.ring=[],this.subscribers=new Map}get stateVersion(){return this.stateVersionValue}publish(kind,data={}){kind==="state"&&(this.stateVersionValue+=1);let event={type:"session_control_event",seq:++this.seq,kind,data:kind==="state"?{...data,state_version:this.stateVersionValue}:data};this.ring.push(event),this.ring.length>256&&this.ring.shift();for(let send of this.subscribers.values())send(event)}subscribe(connection,cursor,send){if(this.subscribers.set(connection,send),cursor!==void 0)for(let event of this.ring)event.seq>cursor&&send(event);return this.seq}unsubscribe(connection){this.subscribers.delete(connection)}clear(){this.subscribers.clear()}};import{createHash}from"node:crypto";import{rmSync}from"node:fs";import{chmod as chmod2,lstat,mkdir,realpath,rm}from"node:fs/promises";import{dirname,join}from"node:path";var PRIVATE_DIRECTORY_MODE=448,REGISTRY_LOCK_WAIT_MS=5e3;async function resolveTuiSocket(agentDir,instanceId){let name=tuiSocketName(instanceId),primary=join(agentDir,"rpc","tui",name);if(Buffer.byteLength(primary)<=MAX_SOCKET_PATH_BYTES)return await makePrivateDirectory(dirname(primary)),primary;let root=join("/tmp",`senpi-rpc-${createHash("sha256").update(agentDir).digest("hex").slice(0,8)}`),tuiRoot=join(root,"tui");await makePrivateDirectory(tuiRoot);for(let directory of[root,tuiRoot])await assertPrivateDirectory(directory);let fallback=join(tuiRoot,name);if(Buffer.byteLength(fallback)>MAX_SOCKET_PATH_BYTES)throw new Error(`socket path ${fallback} exceeds ${MAX_SOCKET_PATH_BYTES} bytes`);return fallback}async function makePrivateDirectory(directory){await mkdir(directory,{recursive:!0,mode:PRIVATE_DIRECTORY_MODE}),await chmod2(directory,PRIVATE_DIRECTORY_MODE)}async function assertPrivateDirectory(directory){let stat=await lstat(await realpath(directory)),ownedByUs=process.getuid===void 0||stat.uid===process.getuid();if(!stat.isDirectory()||!ownedByUs||(stat.mode&63)!==0)throw new Error(`alt_root_unsafe: ${directory} is not a private directory of this user`)}async function registerTuiEndpoint(options){let paths=createHostDaemonPaths({socket:options.socket,agentDir:options.agentDir}),release=await acquireHostEnsureLock(options.socket,REGISTRY_LOCK_WAIT_MS);try{await writeHostRegistration(paths,{record:{pid:process.pid,processStartTime:await thisProcessStartTime()},socket:options.socket,instanceId:options.instanceId,generation:0,launchProfileId:"tui",build:engineBuildIdentity()},{fresh:!0}),await createDaemonDirectories(paths,{kind:"tui"})}finally{await release()}return{paths,socket:options.socket}}async function unregisterTuiEndpoint(entry){let release=await acquireHostEnsureLock(entry.socket,REGISTRY_LOCK_WAIT_MS).catch(()=>{});try{await rm(entry.socket,{force:!0}),await rm(socketSecretPath(entry.socket),{force:!0}),await rm(entry.paths.dir,{recursive:!0,force:!0})}finally{await release?.()}}function unregisterTuiEndpointSync(entry){rmSync(entry.socket,{force:!0}),rmSync(socketSecretPath(entry.socket),{force:!0}),rmSync(entry.paths.dir,{recursive:!0,force:!0})}var REPORT_TEXT_LIMIT=4e3;function activateControlEndpoint(parts){let{context,feed,wake}=parts,{session,surface}=context;session.externalAdmission.setEditorSource(()=>editorHold(context));let unsubscribeSession=session.subscribe(event=>{event.type==="agent_start"?feed.publish("state"):event.type==="agent_idle"?(feed.publish("completion",{turn_epoch:session.externalAdmission.turnEpoch}),feed.publish("state"),wake("idle")):event.type==="agent_end"||event.type==="queue_update"||event.type==="compaction_start"||event.type==="compaction_end"?feed.publish("state"):event.type==="message_end"&&event.message.role==="assistant"&&feed.publish("report",{text:assistantText(event.message).slice(0,REPORT_TEXT_LIMIT)})}),unsubscribeEmitted=session.externalAdmission.onEmitted(()=>{wake("emitted")}),unsubscribeInputs=session.externalAdmission.onInputsSettled(()=>queueMicrotask(()=>{wake("submission")})),stopContinue=onProcessContinue(()=>{wake("continue")}),exitCleanup=()=>unregisterTuiEndpointSync(parts.entry);process.once("exit",exitCleanup);let disposing,dispose=()=>(disposing??=(async()=>{process.removeListener("exit",exitCleanup),unsubscribeSession(),unsubscribeEmitted(),unsubscribeInputs(),stopContinue(),parts.stopInbox(),parts.scheduler.dispose(),feed.clear(),session.externalAdmission.setEditorSource(void 0),await parts.server.close(),await sessionReferenced(parts.options,surface)||await session.sessionManager.discardHeaderOnlyFile(),await unregisterTuiEndpoint(parts.entry)})(),disposing);return{socket:parts.entry.socket,wake:reason=>{wake(reason)},noteState:()=>feed.publish("state"),noteQuestions:()=>feed.publish("question",{pending:[...surface.pendingQuestionIds()]}),dispose}}function editorHold(context){let hold=context.surface.draftHold(),revision=context.editorRevision();return hold===void 0?{revision}:{hold_reason:hold,revision}}async function sessionReferenced(options,surface){if(options.isSessionReferenced===void 0)return!1;try{return await options.isSessionReferenced()}catch(error){return surface.notice(`control endpoint kept the session file: ${error instanceof Error?error.message:String(error)}`),!0}}function assistantText(message){return message.role!=="assistant"?"":message.content.flatMap(part=>part.type==="text"?[part.text]:[]).join(`
2
+ import{WakeScheduler,answeredUiRequestId,availableModelsData,buildRpcSessionState,interruptRunningTurn,onProcessContinue,rpcCommandShapeError,settledQuestionStatus,unansweredQuestionIds,unsupportedThinkingLevel,watchInbox}from"./chunk-JMI5OCIJ.js";import"./chunk-JABBHOD5.js";import{acquireHostEnsureLock,gcHostEndpoints,tuiSocketName}from"./chunk-URQSNRHZ.js";import{engineBuildIdentity}from"./chunk-ZJHRDQCH.js";import"./chunk-KUPQO7MC.js";import{MAX_SOCKET_PATH_BYTES,authenticateSocket,createDaemonDirectories,createHostDaemonPaths,createSocketSecret,socketSecretPath,thisProcessStartTime,writeHostRegistration}from"./chunk-YG5UO3E4.js";import{MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,serializeJsonLine}from"./chunk-YI7SPFDN.js";import"./chunk-RRU5LXMS.js";import"./chunk-TALS4X7S.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import{VERSION}from"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-6WCOSBI7.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";import{randomUUID}from"node:crypto";import{rm as rm2}from"node:fs/promises";import{chmod}from"node:fs/promises";import{createServer}from"node:net";async function listenControlSocket(socketPath,secret,handlers){let clients=new Set,nextConnection=0,server=createServer(socket=>{clients.add(socket),socket.once("close",()=>clients.delete(socket)),socket.on("error",()=>socket.destroy()),authenticateSocket(socket,secret,()=>acceptConnection(socket,++nextConnection,handlers))});return await new Promise((resolve,reject)=>{server.once("error",reject),server.listen(socketPath,()=>{server.off("error",reject),resolve()})}),server.on("error",error=>handlers.listenerError(error)),await chmod(socketPath,384),{close:()=>closeServer(server,clients)}}function acceptConnection(socket,id,handlers){let connection={id,send:record=>{socket.destroyed||socket.write(serializeJsonLine(record))}},detach=attachJsonlLineReader(socket,line=>{answer(connection,line,handlers)},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>connection.send(failure(void 0,"parse","RPC line exceeds the size limit."))});socket.once("close",()=>{detach(),handlers.closed(connection)})}async function answer(connection,line,handlers){let parsed;try{parsed=JSON.parse(line)}catch{connection.send(failure(void 0,"parse","Invalid JSON."));return}let shapeError=rpcCommandShapeError(parsed);if(shapeError!==void 0||!isCommand(parsed)){connection.send(failure(void 0,"parse",shapeError??"RPC command needs a string `type`."));return}connection.send(await handlers.command(connection,parsed))}function isCommand(value){return typeof value=="object"&&value!==null&&"type"in value&&typeof value.type=="string"}function failure(id,command,error){return{...id===void 0?{}:{id},type:"response",command,success:!1,error}}function success(id,command,data){return{...id===void 0?{}:{id},type:"response",command,success:!0,...data===void 0?{}:{data}}}function closeServer(server,clients){for(let client of clients)client.destroy();return new Promise(resolve=>server.close(()=>resolve()))}var SESSION_CONTROL_COMMANDS=["get_available_models","get_available_thinking_levels","set_model","set_thinking_level","interrupt"];async function runSessionControlCommand(session,controls,command){let{id,type}=command;switch(type){case"get_available_models":return success(id,type,await availableModelsData(session));case"get_available_thinking_levels":return success(id,type,{levels:session.getAvailableThinkingLevels()});case"set_model":return await setModel(session,controls,command);case"set_thinking_level":{let level=session.getAvailableThinkingLevels().find(candidate=>candidate===command.level);return level===void 0?failure(id,type,unsupportedThinkingLevel(command.level)):(controls.selectThinkingLevel(level,command.scope!=="turn"),success(id,type))}case"interrupt":return success(id,type,await interruptRunningTurn(session,command.turnId,()=>controls.interruptTurn()));default:return}}async function setModel(session,controls,command){let{id,type}=command,model=(await session.modelRegistry.getAvailable()).find(candidate=>candidate.provider===command.provider&&candidate.id===command.modelId);if(model===void 0)return failure(id,type,`Model not found: ${String(command.provider)}/${String(command.modelId)}`);try{let change=await controls.selectModel(model);return success(id,type,{...model,systemPromptName:change?.systemPromptName})}catch(error){return failure(id,type,error instanceof Error?error.message:String(error))}}var TUI_CONTROL_CAPABILITY="tui_control",TUI_CONTROL_COMMANDS=["get_protocol_info","list_sessions","get_state","get_messages","set_session_name","subscribe","wake","extension_ui_response",...SESSION_CONTROL_COMMANDS];async function runControlCommand(context,connection,command){let{id,type}=command,{session}=context;switch(type){case"get_protocol_info":{let build=engineBuildIdentity();return success(id,type,{protocolVersion:1,serverVersion:VERSION,capabilities:[TUI_CONTROL_CAPABILITY],mode:"tui",instanceId:context.instanceId,generation:0,engineVersion:build.text,engineOrdinal:build.ordinal,commands:TUI_CONTROL_COMMANDS})}case"list_sessions":return success(id,type,{sessions:[sessionRow(session)]});case"get_state":return success(id,type,{...buildRpcSessionState(session),turn_epoch:session.externalAdmission.turnEpoch,blocking_question:context.surface.blockingQuestion(),compacting:session.isCompacting,editor_has_draft:context.surface.draftHold()!==void 0,state_version:context.feed.stateVersion});case"get_messages":return success(id,type,{messages:session.messages});case"set_session_name":{let name=typeof command.name=="string"?command.name.trim():"";return name===""?failure(id,type,"Session name cannot be empty"):(session.setSessionName(name),success(id,type))}case"subscribe":{let cursor=typeof command.cursor=="number"?command.cursor:void 0;return success(id,type,{cursor:context.feed.subscribe(connection.id,cursor,connection.send)})}case"wake":{let ids=Array.isArray(command.delivery_ids)?command.delivery_ids.filter(entry=>typeof entry=="string"):void 0,result=await context.wake(ids);return success(id,type,{admitted:result.admitted??[]})}case"extension_ui_response":return answerQuestion(context.surface,command);default:return await runSessionControlCommand(session,context.surface,command)??failure(id,type,"unsupported")}}function sessionRow(session){let manager=session.sessionManager,created=manager.getHeader()?.timestamp??null,last=manager.getEntries().at(-1);return{sessionId:session.sessionId,sessionPath:session.sessionFile??null,session_file:session.sessionFile??null,kind:"interactive",surface:"tui",cwd:manager.getCwd(),name:session.sessionName??null,created_at:created,updated_at:last?.timestamp??created,attachments:1}}function answerQuestion(surface,command){let frameId=command.id,requestId=answeredUiRequestId(command),request=requestId===void 0?void 0:surface.pendingQuestion(requestId);if(requestId===void 0||request===void 0)return failure(frameId,"extension_ui_response","unknown_request");let response=questionResponse(command,request.questions);return response==="question_incomplete"?failure(frameId,"extension_ui_response",response):response===void 0||!surface.answerQuestion(requestId,response)?failure(frameId,"extension_ui_response","invalid_response"):success(frameId,"extension_ui_response")}function questionResponse(command,questions){if(command.cancelled===!0)return{status:"cancelled",answers:{},unanswered:[]};let answers=command.answers;if(typeof answers!="object"||answers===null||Array.isArray(answers))return;let parsed={};for(let[question,value]of Object.entries(answers)){if(typeof value!="object"||value===null||!("selected"in value)||!Array.isArray(value.selected))return;let selected=value.selected.filter(entry=>typeof entry=="string"),text="text"in value&&typeof value.text=="string"?value.text:void 0;parsed[question]=text===void 0?{selected}:{selected,text}}let comment=typeof command.comment=="string"?command.comment:void 0,status=settledQuestionStatus(parsed,comment);if(status===void 0)return"question_incomplete";let unanswered=unansweredQuestionIds(questions,parsed);return{status,resolvedBy:"control_endpoint",answers:parsed,unanswered,...comment===void 0?{}:{comment}}}var ControlFeed=class{constructor(){this.seq=0,this.stateVersionValue=0,this.ring=[],this.subscribers=new Map}get stateVersion(){return this.stateVersionValue}publish(kind,data={}){kind==="state"&&(this.stateVersionValue+=1);let event={type:"session_control_event",seq:++this.seq,kind,data:kind==="state"?{...data,state_version:this.stateVersionValue}:data};this.ring.push(event),this.ring.length>256&&this.ring.shift();for(let send of this.subscribers.values())send(event)}subscribe(connection,cursor,send){if(this.subscribers.set(connection,send),cursor!==void 0)for(let event of this.ring)event.seq>cursor&&send(event);return this.seq}unsubscribe(connection){this.subscribers.delete(connection)}clear(){this.subscribers.clear()}};import{createHash}from"node:crypto";import{rmSync}from"node:fs";import{chmod as chmod2,lstat,mkdir,realpath,rm}from"node:fs/promises";import{dirname,join}from"node:path";var PRIVATE_DIRECTORY_MODE=448,REGISTRY_LOCK_WAIT_MS=5e3;async function resolveTuiSocket(agentDir,instanceId){let name=tuiSocketName(instanceId),primary=join(agentDir,"rpc","tui",name);if(Buffer.byteLength(primary)<=MAX_SOCKET_PATH_BYTES)return await makePrivateDirectory(dirname(primary)),primary;let root=join("/tmp",`senpi-rpc-${createHash("sha256").update(agentDir).digest("hex").slice(0,8)}`),tuiRoot=join(root,"tui");await makePrivateDirectory(tuiRoot);for(let directory of[root,tuiRoot])await assertPrivateDirectory(directory);let fallback=join(tuiRoot,name);if(Buffer.byteLength(fallback)>MAX_SOCKET_PATH_BYTES)throw new Error(`socket path ${fallback} exceeds ${MAX_SOCKET_PATH_BYTES} bytes`);return fallback}async function makePrivateDirectory(directory){await mkdir(directory,{recursive:!0,mode:PRIVATE_DIRECTORY_MODE}),await chmod2(directory,PRIVATE_DIRECTORY_MODE)}async function assertPrivateDirectory(directory){let stat=await lstat(await realpath(directory)),ownedByUs=process.getuid===void 0||stat.uid===process.getuid();if(!stat.isDirectory()||!ownedByUs||(stat.mode&63)!==0)throw new Error(`alt_root_unsafe: ${directory} is not a private directory of this user`)}async function registerTuiEndpoint(options){let paths=createHostDaemonPaths({socket:options.socket,agentDir:options.agentDir}),release=await acquireHostEnsureLock(options.socket,REGISTRY_LOCK_WAIT_MS);try{await writeHostRegistration(paths,{record:{pid:process.pid,processStartTime:await thisProcessStartTime()},socket:options.socket,instanceId:options.instanceId,generation:0,launchProfileId:"tui",build:engineBuildIdentity()},{fresh:!0}),await createDaemonDirectories(paths,{kind:"tui"})}finally{await release()}return{paths,socket:options.socket}}async function unregisterTuiEndpoint(entry){let release=await acquireHostEnsureLock(entry.socket,REGISTRY_LOCK_WAIT_MS).catch(()=>{});try{await rm(entry.socket,{force:!0}),await rm(socketSecretPath(entry.socket),{force:!0}),await rm(entry.paths.dir,{recursive:!0,force:!0})}finally{await release?.()}}function unregisterTuiEndpointSync(entry){rmSync(entry.socket,{force:!0}),rmSync(socketSecretPath(entry.socket),{force:!0}),rmSync(entry.paths.dir,{recursive:!0,force:!0})}var REPORT_TEXT_LIMIT=4e3;function activateControlEndpoint(parts){let{context,feed,wake}=parts,{session,surface}=context;session.externalAdmission.setEditorSource(()=>editorHold(context));let unsubscribeSession=session.subscribe(event=>{event.type==="agent_start"?feed.publish("state"):event.type==="agent_idle"?(feed.publish("completion",{turn_epoch:session.externalAdmission.turnEpoch}),feed.publish("state"),wake("idle")):event.type==="agent_end"||event.type==="queue_update"||event.type==="compaction_start"||event.type==="compaction_end"?feed.publish("state"):event.type==="message_end"&&event.message.role==="assistant"&&feed.publish("report",{text:assistantText(event.message).slice(0,REPORT_TEXT_LIMIT)})}),unsubscribeEmitted=session.externalAdmission.onEmitted(()=>{wake("emitted")}),unsubscribeInputs=session.externalAdmission.onInputsSettled(()=>queueMicrotask(()=>{wake("submission")})),stopContinue=onProcessContinue(()=>{wake("continue")}),exitCleanup=()=>unregisterTuiEndpointSync(parts.entry);process.once("exit",exitCleanup);let disposing,dispose=()=>(disposing??=(async()=>{process.removeListener("exit",exitCleanup),unsubscribeSession(),unsubscribeEmitted(),unsubscribeInputs(),stopContinue(),parts.stopInbox(),parts.scheduler.dispose(),feed.clear(),session.externalAdmission.setEditorSource(void 0),await parts.server.close(),await sessionReferenced(parts.options,surface)||await session.sessionManager.discardHeaderOnlyFile(),await unregisterTuiEndpoint(parts.entry)})(),disposing);return{socket:parts.entry.socket,wake:reason=>{wake(reason)},noteState:()=>feed.publish("state"),noteQuestions:()=>feed.publish("question",{pending:[...surface.pendingQuestionIds()]}),dispose}}function editorHold(context){let hold=context.surface.draftHold(),revision=context.editorRevision();return hold===void 0?{revision}:{hold_reason:hold,revision}}async function sessionReferenced(options,surface){if(options.isSessionReferenced===void 0)return!1;try{return await options.isSessionReferenced()}catch(error){return surface.notice(`control endpoint kept the session file: ${error instanceof Error?error.message:String(error)}`),!0}}function assistantText(message){return message.role!=="assistant"?"":message.content.flatMap(part=>part.type==="text"?[part.text]:[]).join(`
3
3
  `)}async function registerSessionControlEndpoint(context,options){let cleanups=[];try{let endpoint=await openEndpoint(context,options,cleanups);return{registration:{status:"registered",socket:endpoint.socket,dispose:endpoint.dispose},endpoint}}catch(error){for(let cleanup of cleanups.reverse())await Promise.resolve(cleanup()).catch(()=>{});let reason=errorText(error);return context.surface.notice(`control endpoint unavailable: ${reason}`),{registration:{status:"failed",reason}}}}async function openEndpoint(context,options,cleanups){let{session,agentDir,surface}=context;thisProcessStartTime();let headerDurable=session.sessionManager.persistHeaderNow();headerDurable.catch(()=>{});let instanceId=randomUUID(),socket=await resolveTuiSocket(agentDir,instanceId);cleanups.push(()=>rm2(socket,{force:!0}),()=>rm2(socketSecretPath(socket),{force:!0}));let secret=await createSocketSecret(socketSecretPath(socket)),feed=new ControlFeed,scheduler=new WakeScheduler(async event=>(await session.extensionRunner.emit(event),await options.drain(event)??{admitted:[]}),error=>surface.notice(`control endpoint drain failed: ${errorText(error)}`));cleanups.push(()=>scheduler.dispose());let wake=(reason,ids)=>scheduler.request(reason,ids),commandContext={instanceId,session,surface,feed,wake:ids=>wake("command",ids)},server=await listenControlSocket(socket,secret,{command:(connection,command)=>runControlCommand(commandContext,connection,command),closed:connection=>feed.unsubscribe(connection.id),listenerError:error=>surface.notice(`control endpoint listener failed: ${error.message}`)});cleanups.push(()=>server.close()),await headerDurable;let entry=await registerTuiEndpoint({agentDir,socket,instanceId});cleanups.push(()=>unregisterTuiEndpoint(entry));let inbox=await watchInbox(options.inboxDir,()=>{wake("inbox")},error=>surface.notice(`control endpoint inbox watch failed: ${errorText(error)}`));cleanups.push(()=>inbox.stop());let endpoint=activateControlEndpoint({context,options,entry,server,scheduler,feed,stopInbox:inbox.stop,wake});return endpoint.wake("inbox"),inbox.armed.then(()=>endpoint.wake("inbox")),setImmediate(()=>{gcHostEndpoints(agentDir,{kinds:["tui"]}).catch(error=>surface.notice(`control endpoint gc of dead terminals failed: ${errorText(error)}`))}),endpoint}function errorText(error){return error instanceof Error?error.message:String(error)}export{registerSessionControlEndpoint};
@@ -1,2 +1,2 @@
1
1
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
2
- import{SessionSelectorComponent,createStartupTui,startStartupTui}from"./chunk-Z7MMKKIY.js";import"./chunk-H4UIUFU5.js";import{KeybindingsManager}from"./chunk-M2IHGL3M.js";import{setKeybindings}from"./chunk-J5MUMVWB.js";import"./chunk-JABBHOD5.js";import"./chunk-QMRJYMNH.js";import"./chunk-7X72IACK.js";import"./chunk-YU2P3CAR.js";import"./chunk-26UBFF6N.js";import"./chunk-ODYQK5XJ.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import"./chunk-ZOFZRJSL.js";import"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-6WCOSBI7.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-PELNNWGO.js";import"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";async function selectSession(currentSessionsLoader,allSessionsLoader,settingsManager){let ui=await createStartupTui(settingsManager);return new Promise(resolve=>{let keybindings=KeybindingsManager.create();setKeybindings(keybindings);let resolved=!1,selector=new SessionSelectorComponent(currentSessionsLoader,allSessionsLoader,path=>{resolved||(resolved=!0,ui.stop(),resolve(path))},()=>{resolved||(resolved=!0,ui.stop(),resolve(null))},()=>{ui.stop(),process.exit(0)},()=>ui.requestRender(),{showRenameHint:!1,keybindings});ui.addChild(selector),ui.setFocus(selector.getSessionList()),startStartupTui(ui,settingsManager)})}export{selectSession};
2
+ import{SessionSelectorComponent,createStartupTui,startStartupTui}from"./chunk-ZYHIRFGT.js";import"./chunk-VGYIPYOK.js";import{KeybindingsManager}from"./chunk-VW74BGIC.js";import{setKeybindings}from"./chunk-64ZVBCTL.js";import"./chunk-JABBHOD5.js";import"./chunk-QMRJYMNH.js";import"./chunk-7X72IACK.js";import"./chunk-YU2P3CAR.js";import"./chunk-26UBFF6N.js";import"./chunk-TALS4X7S.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-KC5TT7DH.js";import"./chunk-ZOFZRJSL.js";import"./chunk-463OK2Y4.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-RKJNJ3GI.js";import"./chunk-6WCOSBI7.js";import"./chunk-YOPVJDSU.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-2WEI2XTZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-45SZOLCU.js";import"./chunk-PELNNWGO.js";import"./chunk-XL5KIYQF.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";async function selectSession(currentSessionsLoader,allSessionsLoader,settingsManager){let ui=await createStartupTui(settingsManager);return new Promise(resolve=>{let keybindings=KeybindingsManager.create();setKeybindings(keybindings);let resolved=!1,selector=new SessionSelectorComponent(currentSessionsLoader,allSessionsLoader,path=>{resolved||(resolved=!0,ui.stop(),resolve(path))},()=>{resolved||(resolved=!0,ui.stop(),resolve(null))},()=>{ui.stop(),process.exit(0)},()=>ui.requestRender(),{showRenameHint:!1,keybindings});ui.addChild(selector),ui.setFocus(selector.getSessionList()),startStartupTui(ui,settingsManager)})}export{selectSession};