@tangle-network/agent-app 0.43.55 → 0.43.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DesignCanvas-UNL34LS2.js +12 -0
- package/dist/DesignCanvasEditor-FJIVYOA2.js +13 -0
- package/dist/IntakeInterview-3ZIQMZS6.js +8 -0
- package/dist/InvitationsPanel-CJ7DR4F7.js +8 -0
- package/dist/MembersPanel-BB4OD2KB.js +8 -0
- package/dist/{TimelineEditor-I35SJJAJ.js → TimelineEditor-2ECKSU6P.js} +3 -3
- package/dist/{VaultPane-DrQ_tH6c.d.ts → VaultPane-BDP6SB_K.d.ts} +1 -0
- package/dist/{access-BZ81Btt5.d.ts → access-490O6aOU.d.ts} +16 -1
- package/dist/app-auth/index.d.ts +6 -1
- package/dist/app-auth/index.js +3 -3
- package/dist/app-auth/index.js.map +1 -1
- package/dist/{apply-Gk4raT2j.d.ts → apply-6wlMOLf8.d.ts} +30 -1
- package/dist/assets/index.d.ts +41 -0
- package/dist/assets/index.js +1 -1
- package/dist/assistant/index.d.ts +26 -6
- package/dist/assistant/index.js +13 -12
- package/dist/assistant/index.js.map +1 -1
- package/dist/{attachment-validation-D0csjCvz.d.ts → attachment-validation-tPRp-PP1.d.ts} +7 -1
- package/dist/{auth-DuptSkWh.d.ts → auth-_FU8w01b.d.ts} +4 -1
- package/dist/billing/index.d.ts +8 -0
- package/dist/billing/index.js +1 -1
- package/dist/brand/index.d.ts +2 -0
- package/dist/brand/index.js.map +1 -1
- package/dist/brand-extraction/index.d.ts +3 -0
- package/dist/brand-extraction/index.js.map +1 -1
- package/dist/catalog/index.d.ts +2 -0
- package/dist/catalog/index.js +1 -1
- package/dist/chat-routes/index.d.ts +41 -10
- package/dist/chat-routes/index.js +15 -15
- package/dist/chat-routes/index.js.map +1 -1
- package/dist/chat-store/index.d.ts +18 -4
- package/dist/chat-store/index.js +4 -4
- package/dist/chat-store/index.js.map +1 -1
- package/dist/{chunk-H5FM75MR.js → chunk-22GLESKE.js} +3 -3
- package/dist/chunk-22GLESKE.js.map +1 -0
- package/dist/{chunk-WEBBJBDH.js → chunk-2DRYTJHI.js} +1 -1
- package/dist/chunk-2DRYTJHI.js.map +1 -0
- package/dist/{chunk-7EVZUIHW.js → chunk-3EJ6SFJI.js} +1 -1
- package/dist/chunk-3EJ6SFJI.js.map +1 -0
- package/dist/{chunk-HRJJH3RX.js → chunk-3OFQFW5K.js} +4 -4
- package/dist/chunk-3OFQFW5K.js.map +1 -0
- package/dist/{chunk-7SUPA2YT.js → chunk-4KKXZQPT.js} +2 -2
- package/dist/chunk-4KKXZQPT.js.map +1 -0
- package/dist/{chunk-5PTGEJZL.js → chunk-5SD6HT2V.js} +1 -1
- package/dist/chunk-5SD6HT2V.js.map +1 -0
- package/dist/{chunk-7C64WKAH.js → chunk-5SXS3YAB.js} +2 -2
- package/dist/{chunk-L2TG5DBW.js → chunk-5TESA4SN.js} +1 -1
- package/dist/chunk-5TESA4SN.js.map +1 -0
- package/dist/{chunk-63CE7FEZ.js → chunk-6XIAPIW6.js} +1 -1
- package/dist/chunk-6XIAPIW6.js.map +1 -0
- package/dist/{chunk-MFRCM32T.js → chunk-7CTIUCQ4.js} +1 -1
- package/dist/chunk-7CTIUCQ4.js.map +1 -0
- package/dist/{chunk-6KVH5SP5.js → chunk-7YW6EBDX.js} +2 -2
- package/dist/chunk-7YW6EBDX.js.map +1 -0
- package/dist/{chunk-ZXNXAQAH.js → chunk-AP2UXKUK.js} +1 -1
- package/dist/chunk-AP2UXKUK.js.map +1 -0
- package/dist/{chunk-K63OWUDJ.js → chunk-BPSV5AA2.js} +2 -2
- package/dist/chunk-BPSV5AA2.js.map +1 -0
- package/dist/{chunk-MFI4ZM7W.js → chunk-BT4QFCTB.js} +1 -1
- package/dist/chunk-BT4QFCTB.js.map +1 -0
- package/dist/{chunk-ZYBWGSAZ.js → chunk-BVKQKGRK.js} +1 -1
- package/dist/chunk-BVKQKGRK.js.map +1 -0
- package/dist/{chunk-RVUISYUE.js → chunk-C3NSB66C.js} +7 -7
- package/dist/chunk-C3NSB66C.js.map +1 -0
- package/dist/{chunk-BQV42AFK.js → chunk-CCVWR33L.js} +1 -1
- package/dist/chunk-CCVWR33L.js.map +1 -0
- package/dist/{chunk-MCJSS6SM.js → chunk-CQZSAR77.js} +1 -1
- package/dist/chunk-CQZSAR77.js.map +1 -0
- package/dist/{chunk-3SVAA3MA.js → chunk-DJ4VJIH5.js} +1 -1
- package/dist/chunk-DJ4VJIH5.js.map +1 -0
- package/dist/{chunk-XKBIYSSM.js → chunk-DTSPS2HV.js} +3 -3
- package/dist/chunk-DTSPS2HV.js.map +1 -0
- package/dist/{chunk-4QN75UHX.js → chunk-E7N67FYI.js} +8 -8
- package/dist/chunk-E7N67FYI.js.map +1 -0
- package/dist/{chunk-2QI7XV2T.js → chunk-FBVLEGEG.js} +1 -1
- package/dist/{chunk-2QI7XV2T.js.map → chunk-FBVLEGEG.js.map} +1 -1
- package/dist/{chunk-5RMIUJDI.js → chunk-FKCB5FTD.js} +1 -1
- package/dist/chunk-FKCB5FTD.js.map +1 -0
- package/dist/{chunk-EEPJGZJW.js → chunk-GPBRL2XR.js} +1 -1
- package/dist/chunk-GPBRL2XR.js.map +1 -0
- package/dist/{chunk-G3HCU7TA.js → chunk-GXE6KHTS.js} +1 -1
- package/dist/chunk-GXE6KHTS.js.map +1 -0
- package/dist/{chunk-65P3HJY3.js → chunk-HCOROIRT.js} +1 -1
- package/dist/chunk-HCOROIRT.js.map +1 -0
- package/dist/{chunk-54GSK2KK.js → chunk-HYTIHYNV.js} +2 -2
- package/dist/chunk-HYTIHYNV.js.map +1 -0
- package/dist/{chunk-5MG74GVQ.js → chunk-IG46XCZM.js} +3 -3
- package/dist/chunk-IG46XCZM.js.map +1 -0
- package/dist/{chunk-ND3XEGBE.js → chunk-JDEGS53O.js} +1 -1
- package/dist/chunk-JDEGS53O.js.map +1 -0
- package/dist/{chunk-7W5XSTUF.js → chunk-JML7WKWU.js} +1 -1
- package/dist/chunk-JML7WKWU.js.map +1 -0
- package/dist/{chunk-Q4TKVF3L.js → chunk-JTLYXUEV.js} +1 -1
- package/dist/chunk-JTLYXUEV.js.map +1 -0
- package/dist/{chunk-CCRVDLV3.js → chunk-JWBZ74TW.js} +2 -2
- package/dist/chunk-JWBZ74TW.js.map +1 -0
- package/dist/{chunk-ZU5GNSOJ.js → chunk-K3LIPKFV.js} +3 -3
- package/dist/chunk-K3LIPKFV.js.map +1 -0
- package/dist/{chunk-GQRL6VNU.js → chunk-LGBO24FL.js} +1 -1
- package/dist/chunk-LGBO24FL.js.map +1 -0
- package/dist/{chunk-SWUVTGMR.js → chunk-MEUNTJL5.js} +3 -3
- package/dist/{chunk-SWUVTGMR.js.map → chunk-MEUNTJL5.js.map} +1 -1
- package/dist/{chunk-YNALYIQ3.js → chunk-NLSSFLLS.js} +1 -1
- package/dist/chunk-NLSSFLLS.js.map +1 -0
- package/dist/{chunk-HFC4BTWJ.js → chunk-PTUMBMVH.js} +1 -1
- package/dist/chunk-PTUMBMVH.js.map +1 -0
- package/dist/{chunk-R4NOKZMD.js → chunk-ROLFDOMJ.js} +3 -3
- package/dist/{chunk-NYATNLRK.js → chunk-RT5RKAFX.js} +1 -1
- package/dist/chunk-RT5RKAFX.js.map +1 -0
- package/dist/{chunk-GNL3MG5J.js → chunk-S564OFTL.js} +2 -2
- package/dist/{chunk-GUSCYE3S.js → chunk-TQOFR6XY.js} +1 -1
- package/dist/chunk-TQOFR6XY.js.map +1 -0
- package/dist/{chunk-47C6PJCW.js → chunk-TZO3SOUL.js} +1 -1
- package/dist/chunk-TZO3SOUL.js.map +1 -0
- package/dist/{chunk-YGUNTIT5.js → chunk-UKTYKG57.js} +1 -1
- package/dist/chunk-UKTYKG57.js.map +1 -0
- package/dist/{chunk-23LUHHHN.js → chunk-VCOD5AOR.js} +1 -1
- package/dist/chunk-VCOD5AOR.js.map +1 -0
- package/dist/{chunk-5I72FRZY.js → chunk-VOJB7MVG.js} +2 -2
- package/dist/{chunk-XWJXZ6WE.js → chunk-VTWKH4YU.js} +2 -2
- package/dist/chunk-VTWKH4YU.js.map +1 -0
- package/dist/{chunk-4K7BZYO7.js → chunk-VWAEWOWK.js} +3 -3
- package/dist/chunk-VWAEWOWK.js.map +1 -0
- package/dist/{chunk-M2EBUDZ7.js → chunk-VWOPOLVO.js} +2 -2
- package/dist/chunk-VWOPOLVO.js.map +1 -0
- package/dist/{chunk-BN2USWIR.js → chunk-VYECQAGM.js} +2 -2
- package/dist/chunk-VYECQAGM.js.map +1 -0
- package/dist/{chunk-SIXYZ2FB.js → chunk-YJMCRXQQ.js} +1 -1
- package/dist/chunk-YJMCRXQQ.js.map +1 -0
- package/dist/{chunk-PJC4NXPA.js → chunk-YKBDH2UY.js} +3 -3
- package/dist/chunk-YKBDH2UY.js.map +1 -0
- package/dist/{chunk-XAWFPMAR.js → chunk-YKOM4ZLQ.js} +1 -1
- package/dist/chunk-YKOM4ZLQ.js.map +1 -0
- package/dist/{chunk-TKVJE63N.js → chunk-YRMLYFVR.js} +3 -3
- package/dist/chunk-YRMLYFVR.js.map +1 -0
- package/dist/{chunk-USYXHDKE.js → chunk-YZ6KQULN.js} +2 -2
- package/dist/{command-stack-B_-WNfZU.d.ts → command-stack-TNPWJCzW.d.ts} +14 -2
- package/dist/{completion-Kaqp_tWk.d.ts → completion-CvcNUz07.d.ts} +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/{contract-KfqJh_au.d.ts → contract-TjB68uqA.d.ts} +17 -0
- package/dist/design-canvas/drizzle.d.ts +10 -2
- package/dist/design-canvas/drizzle.js.map +1 -1
- package/dist/design-canvas/index.d.ts +29 -11
- package/dist/design-canvas/index.js +1070 -17
- package/dist/design-canvas/index.js.map +1 -1
- package/dist/design-canvas-react/engine.d.ts +42 -6
- package/dist/design-canvas-react/engine.js +4 -4
- package/dist/design-canvas-react/index.d.ts +12 -7
- package/dist/design-canvas-react/index.js +11 -11
- package/dist/design-canvas-react/index.js.map +1 -1
- package/dist/design-canvas-react/lazy.d.ts +4 -4
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/durable-chat/index.d.ts +46 -1
- package/dist/durable-chat/index.js +3 -3
- package/dist/eval/index.d.ts +1 -1
- package/dist/{export-presets-DAsU5Wal.d.ts → export-presets-mgVulRaV.d.ts} +10 -1
- package/dist/{flow-types-Cb_AblZs.d.ts → flow-types-CqomVAUN.d.ts} +1 -0
- package/dist/harness/index.d.ts +5 -0
- package/dist/harness/index.js +1 -1
- package/dist/index.d.ts +10 -18
- package/dist/index.js +30 -231
- package/dist/intakes/api.d.ts +3 -2
- package/dist/intakes/api.js +3 -3
- package/dist/intakes/api.js.map +1 -1
- package/dist/intakes/drizzle.d.ts +10 -2
- package/dist/intakes/drizzle.js +3 -3
- package/dist/intakes/drizzle.js.map +1 -1
- package/dist/intakes/index.d.ts +2 -2
- package/dist/intakes/index.js +2 -2
- package/dist/intakes-react/index.d.ts +2 -1
- package/dist/intakes-react/index.js +2 -2
- package/dist/intakes-react/lazy.d.ts +2 -1
- package/dist/intakes-react/lazy.js +1 -1
- package/dist/intakes-react/lazy.js.map +1 -1
- package/dist/integrations/index.d.ts +4 -0
- package/dist/integrations/index.js +1 -1
- package/dist/interactions/index.d.ts +13 -2
- package/dist/interactions/index.js +2 -2
- package/dist/{invitations-CZ5G2tIn.d.ts → invitations-DoYMvXea.d.ts} +11 -1
- package/dist/{invitations-schema-DaMO4hZE.d.ts → invitations-schema-_fI7HkJP.d.ts} +5 -1
- package/dist/knowledge/index.d.ts +2 -0
- package/dist/knowledge/index.js +1 -1
- package/dist/knowledge-loop/index.d.ts +4 -1
- package/dist/knowledge-loop/index.js +1 -1
- package/dist/{lazy-C7LiVeFt.d.ts → lazy-DrkVyDpe.d.ts} +2 -2
- package/dist/{mcp-BHfIoGLW.d.ts → mcp-BjPqQ-3C.d.ts} +4 -2
- package/dist/{mcp-rpc-DLw_r9PQ.d.ts → mcp-rpc-BfUOsalw.d.ts} +3 -0
- package/dist/missions/index.d.ts +25 -0
- package/dist/missions/index.js +1 -1
- package/dist/{model-Bzi5i63l.d.ts → model-C8U0HZxL.d.ts} +1 -0
- package/dist/{model-dF2h4xT9.d.ts → model-DmdkIteM.d.ts} +19 -0
- package/dist/{model-BBwyOuWG.d.ts → model-DnfO_PdJ.d.ts} +25 -1
- package/dist/model-resolution/index.d.ts +10 -0
- package/dist/model-resolution/index.js.map +1 -1
- package/dist/{operations-DLIvvD00.d.ts → operations-ByJ6yXOW.d.ts} +20 -2
- package/dist/{parts-1sRYSPjF.d.ts → parts-n9XUon0a.d.ts} +29 -1
- package/dist/plans/index.d.ts +6 -0
- package/dist/plans/index.js +1 -1
- package/dist/platform/index.d.ts +24 -2
- package/dist/platform/index.js +3 -3
- package/dist/platform/index.js.map +1 -1
- package/dist/preflight/index.d.ts +3 -0
- package/dist/preflight/index.js +1 -1
- package/dist/preset-cloudflare/index.d.ts +4 -1
- package/dist/preset-cloudflare/index.js +2 -2
- package/dist/redact/index.d.ts +5 -0
- package/dist/redact/index.js +1 -1
- package/dist/{roles-BC1n4t37.d.ts → roles-B4nU3jDi.d.ts} +12 -0
- package/dist/run/index.d.ts +3 -0
- package/dist/run/index.js +1 -1
- package/dist/run/index.js.map +1 -1
- package/dist/runtime/index.d.ts +11 -4
- package/dist/runtime/index.js +4 -4
- package/dist/sandbox/index.d.ts +96 -3
- package/dist/sandbox/index.js +6 -6
- package/dist/{sandbox-terminal-BIIC__CP.d.ts → sandbox-terminal-ChNEdHF8.d.ts} +5 -0
- package/dist/sequences/drizzle.d.ts +11 -1
- package/dist/sequences/drizzle.js +1 -1
- package/dist/sequences/drizzle.js.map +1 -1
- package/dist/sequences/index.d.ts +32 -7
- package/dist/sequences/index.js +1562 -47
- package/dist/sequences/index.js.map +1 -1
- package/dist/sequences-react/index.d.ts +32 -2
- package/dist/sequences-react/index.js +3 -3
- package/dist/sequences-react/index.js.map +1 -1
- package/dist/{sso-CNOsARMJ.d.ts → sso-Cm00S61u.d.ts} +13 -0
- package/dist/{stale-turn-lock-C8Na1cFZ.d.ts → stale-turn-lock-DucQzvXu.d.ts} +2 -0
- package/dist/store/index.d.ts +5 -0
- package/dist/store/index.js.map +1 -1
- package/dist/{store-gckrNq-g.d.ts → store-B7LLlk9p.d.ts} +22 -1
- package/dist/{store-CFyxgTlD.d.ts → store-CqfDtnPQ.d.ts} +8 -2
- package/dist/stream/index.d.ts +10 -4
- package/dist/stream/index.js +4 -4
- package/dist/{stream-normalizer-DWvtmY6F.d.ts → stream-normalizer-C3M--r6y.d.ts} +17 -1
- package/dist/studio/index.d.ts +37 -0
- package/dist/studio/index.js +1 -1
- package/dist/studio-react/index.d.ts +3 -0
- package/dist/studio-react/index.js +1 -1
- package/dist/studio-react/index.js.map +1 -1
- package/dist/tangle/index.d.ts +3 -0
- package/dist/tangle/index.js +1 -1
- package/dist/teams/drizzle.d.ts +8 -4
- package/dist/teams/drizzle.js +1 -1
- package/dist/teams/drizzle.js.map +1 -1
- package/dist/teams/index.d.ts +4 -2
- package/dist/teams/index.js +3 -3
- package/dist/teams/invitations-api.d.ts +10 -4
- package/dist/teams/invitations-api.js +4 -4
- package/dist/teams/invitations-api.js.map +1 -1
- package/dist/teams/members-api.d.ts +4 -2
- package/dist/teams/members-api.js +3 -3
- package/dist/teams/resend.d.ts +5 -4
- package/dist/teams/resend.js +1 -1
- package/dist/teams/resend.js.map +1 -1
- package/dist/teams-react/index.d.ts +7 -2
- package/dist/teams-react/index.js +3 -3
- package/dist/teams-react/lazy.d.ts +5 -2
- package/dist/teams-react/lazy.js +2 -2
- package/dist/teams-react/lazy.js.map +1 -1
- package/dist/theme/index.d.ts +2 -0
- package/dist/theme/index.js +1 -1
- package/dist/theme/tailwind-preset.d.ts +1 -0
- package/dist/theme/tailwind-preset.js.map +1 -1
- package/dist/theme-contract/cli.js +1 -1
- package/dist/theme-contract/index.d.ts +3 -0
- package/dist/theme-contract/index.js +1 -1
- package/dist/tools/index.d.ts +13 -6
- package/dist/tools/index.js +3 -3
- package/dist/trace/index.d.ts +6 -1
- package/dist/trace/index.js +2 -2
- package/dist/{turn-buffer-C9mEgoop.d.ts → turn-buffer-DGnAPKwa.d.ts} +6 -0
- package/dist/turn-stream/index.d.ts +28 -2
- package/dist/turn-stream/index.js +1 -1
- package/dist/turn-stream/index.js.map +1 -1
- package/dist/{types-BEOvc_ue.d.ts → types-CBRyqijY.d.ts} +10 -0
- package/dist/vault/index.d.ts +1 -1
- package/dist/vault/lazy.d.ts +3 -2
- package/dist/vault/lazy.js.map +1 -1
- package/dist/web/index.d.ts +4 -0
- package/dist/web/index.js +1 -1
- package/dist/web-react/index.d.ts +51 -8
- package/dist/web-react/index.js +9 -9
- package/dist/web-react/terminal.d.ts +2 -2
- package/dist/web-react/terminal.js +1 -1
- package/package.json +3 -2
- package/dist/DesignCanvas-5DJAFDNC.js +0 -12
- package/dist/DesignCanvasEditor-XUJZARSN.js +0 -13
- package/dist/IntakeInterview-WHVKMNQW.js +0 -8
- package/dist/InvitationsPanel-XUUWZBPV.js +0 -8
- package/dist/MembersPanel-FOVHWUQ3.js +0 -8
- package/dist/chunk-23LUHHHN.js.map +0 -1
- package/dist/chunk-3SVAA3MA.js.map +0 -1
- package/dist/chunk-47C6PJCW.js.map +0 -1
- package/dist/chunk-4K7BZYO7.js.map +0 -1
- package/dist/chunk-4QN75UHX.js.map +0 -1
- package/dist/chunk-54GSK2KK.js.map +0 -1
- package/dist/chunk-5MG74GVQ.js.map +0 -1
- package/dist/chunk-5PTGEJZL.js.map +0 -1
- package/dist/chunk-5RMIUJDI.js.map +0 -1
- package/dist/chunk-63CE7FEZ.js.map +0 -1
- package/dist/chunk-65P3HJY3.js.map +0 -1
- package/dist/chunk-6KVH5SP5.js.map +0 -1
- package/dist/chunk-7EVZUIHW.js.map +0 -1
- package/dist/chunk-7SUPA2YT.js.map +0 -1
- package/dist/chunk-7W5XSTUF.js.map +0 -1
- package/dist/chunk-BN2USWIR.js.map +0 -1
- package/dist/chunk-BQV42AFK.js.map +0 -1
- package/dist/chunk-CCRVDLV3.js.map +0 -1
- package/dist/chunk-EEPJGZJW.js.map +0 -1
- package/dist/chunk-G3HCU7TA.js.map +0 -1
- package/dist/chunk-GQRL6VNU.js.map +0 -1
- package/dist/chunk-GUSCYE3S.js.map +0 -1
- package/dist/chunk-H5FM75MR.js.map +0 -1
- package/dist/chunk-HFC4BTWJ.js.map +0 -1
- package/dist/chunk-HRJJH3RX.js.map +0 -1
- package/dist/chunk-K63OWUDJ.js.map +0 -1
- package/dist/chunk-L2TG5DBW.js.map +0 -1
- package/dist/chunk-M2EBUDZ7.js.map +0 -1
- package/dist/chunk-MCJSS6SM.js.map +0 -1
- package/dist/chunk-MFI4ZM7W.js.map +0 -1
- package/dist/chunk-MFRCM32T.js.map +0 -1
- package/dist/chunk-ND3XEGBE.js.map +0 -1
- package/dist/chunk-NEOV2NQ3.js +0 -1617
- package/dist/chunk-NEOV2NQ3.js.map +0 -1
- package/dist/chunk-NYATNLRK.js.map +0 -1
- package/dist/chunk-PJC4NXPA.js.map +0 -1
- package/dist/chunk-Q4TKVF3L.js.map +0 -1
- package/dist/chunk-RVUISYUE.js.map +0 -1
- package/dist/chunk-SIXYZ2FB.js.map +0 -1
- package/dist/chunk-TKVJE63N.js.map +0 -1
- package/dist/chunk-WEBBJBDH.js.map +0 -1
- package/dist/chunk-WFMUDX5J.js +0 -1092
- package/dist/chunk-WFMUDX5J.js.map +0 -1
- package/dist/chunk-XAWFPMAR.js.map +0 -1
- package/dist/chunk-XKBIYSSM.js.map +0 -1
- package/dist/chunk-XWJXZ6WE.js.map +0 -1
- package/dist/chunk-YGUNTIT5.js.map +0 -1
- package/dist/chunk-YNALYIQ3.js.map +0 -1
- package/dist/chunk-ZU5GNSOJ.js.map +0 -1
- package/dist/chunk-ZXNXAQAH.js.map +0 -1
- package/dist/chunk-ZYBWGSAZ.js.map +0 -1
- /package/dist/{DesignCanvas-5DJAFDNC.js.map → DesignCanvas-UNL34LS2.js.map} +0 -0
- /package/dist/{DesignCanvasEditor-XUJZARSN.js.map → DesignCanvasEditor-FJIVYOA2.js.map} +0 -0
- /package/dist/{IntakeInterview-WHVKMNQW.js.map → IntakeInterview-3ZIQMZS6.js.map} +0 -0
- /package/dist/{InvitationsPanel-XUUWZBPV.js.map → InvitationsPanel-CJ7DR4F7.js.map} +0 -0
- /package/dist/{MembersPanel-FOVHWUQ3.js.map → MembersPanel-BB4OD2KB.js.map} +0 -0
- /package/dist/{TimelineEditor-I35SJJAJ.js.map → TimelineEditor-2ECKSU6P.js.map} +0 -0
- /package/dist/{chunk-7C64WKAH.js.map → chunk-5SXS3YAB.js.map} +0 -0
- /package/dist/{chunk-R4NOKZMD.js.map → chunk-ROLFDOMJ.js.map} +0 -0
- /package/dist/{chunk-GNL3MG5J.js.map → chunk-S564OFTL.js.map} +0 -0
- /package/dist/{chunk-5I72FRZY.js.map → chunk-VOJB7MVG.js.map} +0 -0
- /package/dist/{chunk-USYXHDKE.js.map → chunk-YZ6KQULN.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/redact/index.ts"],"sourcesContent":["/**\n * PII redaction — two complementary modes.\n *\n * 1. ONE-WAY scrub (`redactForIngestion`): for production trace payloads. Tool\n * args + results (and once, the LLM span's prompt) cross the wire into the\n * ingestion store, which also feeds the analyst-loop's LLM prompts, so\n * personal identifiers MUST be stripped before they leave the request path.\n * Destructive — the original is gone, replaced by a sentinel.\n *\n * 2. REVERSIBLE redaction (`buildRedactedDocument` / `revealSpan`): for the UI.\n * A document is split into text + redacted segments; each redacted original\n * is kept ENCRYPTED (via a caller-supplied `encrypt` seam → `agent-app/crypto`)\n * so a viewer can reveal a single span on demand, gated by an authorization\n * callback and an audit hook. The mask is presentation; the original is\n * recoverable by an authorized reveal, not lost.\n *\n * Discipline: cheap deterministic string patterns + well-known sensitive object\n * keys (value replaced, key kept, so the shape stays debuggable); recurse arrays\n * + plain objects only; NEVER throw on the one-way path.\n */\n\n/** A named PII pattern. `pattern` is matched case-insensitively at the string\n * level; keep it non-global (global instances are derived where needed). */\nexport interface RedactionPattern {\n kind: string\n pattern: RegExp\n /** Optional predicate over each match — the pattern fires only when it returns\n * true. For matches a regex alone can't decide (e.g. a Luhn check on a\n * card-number candidate). When set, the value is scanned globally and the\n * first match that passes wins; when absent, a plain `pattern.test` decides. */\n validate?: (match: string) => boolean\n}\n\n/** The default deterministic patterns. Extend via the `extraPatterns` /\n * `patterns` options rather than forking this module (the seam that lets a\n * product add e.g. a credit-card matcher without a local copy). */\nexport const DEFAULT_REDACTION_PATTERNS: readonly RedactionPattern[] = [\n { kind: 'ssn', pattern: /\\d{3}-\\d{2}-\\d{4}/ },\n { kind: 'ein', pattern: /\\d{2}-\\d{7}/ },\n]\n\nconst SENSITIVE_KEYS = new Set([\n 'ssn',\n 'ein',\n 'password',\n 'apikey',\n 'token',\n 'secret',\n 'authorization',\n 'email',\n 'phone',\n])\n\nexport interface RedactForIngestionOptions {\n /** Extra patterns appended to {@link DEFAULT_REDACTION_PATTERNS} for the\n * string-level scrub (e.g. credit-card). Additive — defaults still apply. */\n extraPatterns?: readonly RedactionPattern[]\n /** Extra sensitive object-key names (case-insensitive) added to the built-in\n * set, e.g. the snake_case `api_key` an intake form uses. Additive. */\n extraSensitiveKeys?: readonly string[]\n /**\n * How a matched string is rewritten:\n * - `'collapse'` (default) — the whole string becomes `[REDACTED:<kind>]` on\n * the first matching pattern. Safest for telemetry: nothing of the original\n * survives.\n * - `'mask-spans'` — only the matched substrings are replaced (each with\n * `[REDACTED:<kind>]`), preserving surrounding text. Use when a downstream\n * reader needs the non-PII context (e.g. an analyst loop reading prose).\n */\n stringMode?: 'collapse' | 'mask-spans'\n}\n\nfunction redactString(value: string, patterns: readonly RedactionPattern[]): string {\n for (const { kind, pattern, validate } of patterns) {\n if (!validate) {\n if (pattern.test(value)) return `[REDACTED:${kind}]`\n continue\n }\n const g = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`)\n for (const m of value.matchAll(g)) {\n if (m[0].length > 0 && validate(m[0])) return `[REDACTED:${kind}]`\n }\n }\n return value\n}\n\n/**\n * Replace only the PII substrings in `text`, preserving everything around them\n * (the `mask-spans` string mode). Built on {@link detectSpans} so matching,\n * non-overlap, and `validate` predicates behave identically to the reversible\n * path. Each span becomes `[REDACTED:<kind>]`.\n */\nexport function maskSpans(\n text: string,\n patterns: readonly RedactionPattern[] = DEFAULT_REDACTION_PATTERNS,\n): string {\n const spans = detectSpans(text, patterns)\n if (spans.length === 0) return text\n let out = ''\n let pos = 0\n for (const s of spans) {\n if (s.start > pos) out += text.slice(pos, s.start)\n out += `[REDACTED:${s.kind}]`\n pos = s.end\n }\n if (pos < text.length) out += text.slice(pos)\n return out\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object') return false\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\n/**\n * One-way PII scrub for telemetry/ingestion. Backward-compatible: called with no\n * options it behaves exactly as before (SSN/EIN strings + sensitive object keys\n * → sentinels). `extraPatterns` lets a product add matchers (e.g. credit-card)\n * without forking this module.\n */\nexport function redactForIngestion(value: unknown, options: RedactForIngestionOptions = {}): unknown {\n const patterns = options.extraPatterns\n ? [...DEFAULT_REDACTION_PATTERNS, ...options.extraPatterns]\n : DEFAULT_REDACTION_PATTERNS\n const sensitiveKeys = options.extraSensitiveKeys\n ? new Set([...SENSITIVE_KEYS, ...options.extraSensitiveKeys.map((k) => k.toLowerCase())])\n : SENSITIVE_KEYS\n const maskString =\n options.stringMode === 'mask-spans'\n ? (s: string) => maskSpans(s, patterns)\n : (s: string) => redactString(s, patterns)\n // Cycle guard: a payload with a circular reference would otherwise recurse\n // forever. On re-encountering an object/array, return it untouched to break\n // the cycle (the same value was already redacted on its first visit).\n const seen = new WeakSet<object>()\n const walk = (v: unknown): unknown => {\n if (typeof v === 'string') return maskString(v)\n if (Array.isArray(v)) {\n if (seen.has(v)) return v\n seen.add(v)\n return v.map(walk)\n }\n if (isPlainObject(v)) {\n if (seen.has(v)) return v\n seen.add(v)\n const out: Record<string, unknown> = {}\n for (const [k, val] of Object.entries(v)) {\n out[k] = sensitiveKeys.has(k.toLowerCase()) ? '[REDACTED:field]' : walk(val)\n }\n return out\n }\n return v\n }\n return walk(value)\n}\n\n// ── Reversible document redaction (the UI path) ─────────────────────────────\n\n/** A detected PII span in a source string. */\nexport interface RedactionSpan {\n /** Stable within a document (index-derived) — used for reveal + audit. */\n id: string\n kind: string\n start: number\n end: number\n text: string\n}\n\n/**\n * Find non-overlapping PII spans in `text`. Matches every pattern, sorts by\n * position, and drops overlaps (first match wins). Deterministic — no ids that\n * vary per call.\n */\nexport function detectSpans(\n text: string,\n patterns: readonly RedactionPattern[] = DEFAULT_REDACTION_PATTERNS,\n): RedactionSpan[] {\n const raw: Array<{ kind: string; start: number; end: number; text: string }> = []\n for (const { kind, pattern, validate } of patterns) {\n const g = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`)\n for (const m of text.matchAll(g)) {\n if (m.index === undefined || m[0].length === 0) continue\n if (validate && !validate(m[0])) continue\n raw.push({ kind, start: m.index, end: m.index + m[0].length, text: m[0] })\n }\n }\n raw.sort((a, b) => a.start - b.start || b.end - a.end)\n const spans: RedactionSpan[] = []\n let cursor = -1\n let i = 0\n for (const s of raw) {\n if (s.start < cursor) continue // overlaps an earlier (higher-priority) span\n spans.push({ id: `span-${i++}`, ...s })\n cursor = s.end\n }\n return spans\n}\n\n/** A redacted document segment: literal text, or a masked span with the\n * original kept ENCRYPTED for an authorized reveal. */\nexport type RedactedDocSegment =\n | { type: 'text'; text: string }\n | { type: 'redacted'; id: string; kind: string; cipher: string }\n\nexport interface RedactedDocument {\n segments: RedactedDocSegment[]\n}\n\nexport interface BuildRedactedDocumentOptions {\n /** Encrypt one original span value. Wire it to `agent-app/crypto`\n * (`encryptWithKey` / `createFieldCrypto`). The cipher is what's stored. */\n encrypt: (plaintext: string) => string | Promise<string>\n /** Patterns to detect (default: {@link DEFAULT_REDACTION_PATTERNS}). */\n patterns?: readonly RedactionPattern[]\n}\n\n/**\n * Split `text` into text + redacted segments, encrypting each redacted span's\n * original. The result carries NO plaintext PII — only the masked structure and\n * ciphertext — so it is safe to ship to a client; reveal happens server-side via\n * {@link revealSpan}.\n */\nexport async function buildRedactedDocument(\n text: string,\n options: BuildRedactedDocumentOptions,\n): Promise<RedactedDocument> {\n const spans = detectSpans(text, options.patterns)\n const segments: RedactedDocSegment[] = []\n let pos = 0\n for (const span of spans) {\n if (span.start > pos) segments.push({ type: 'text', text: text.slice(pos, span.start) })\n segments.push({ type: 'redacted', id: span.id, kind: span.kind, cipher: await options.encrypt(span.text) })\n pos = span.end\n }\n if (pos < text.length) segments.push({ type: 'text', text: text.slice(pos) })\n return { segments }\n}\n\nexport interface RevealSpanOptions {\n /** Decrypt a span cipher. Wire to `agent-app/crypto` (`decryptWithKey`). */\n decrypt: (cipher: string) => string | Promise<string>\n /** Authorization gate — return false to deny the reveal (fail-closed). */\n canReveal: (segment: { id: string; kind: string }) => boolean | Promise<boolean>\n /** Audit hook — invoked only on a granted reveal (the caller records who/when). */\n onReveal?: (segment: { id: string; kind: string }) => void | Promise<void>\n}\n\nexport interface RevealResult {\n ok: boolean\n value?: string\n /** `not_found` | `forbidden` when `ok` is false. */\n reason?: string\n}\n\n/**\n * Reveal one redacted span's original, gated + audited. Fail-closed: an unknown\n * id or a denied `canReveal` returns `{ ok: false }` and never decrypts; a\n * granted reveal decrypts, fires `onReveal` for the audit trail, and returns the\n * value.\n */\nexport async function revealSpan(\n doc: RedactedDocument,\n spanId: string,\n options: RevealSpanOptions,\n): Promise<RevealResult> {\n const seg = doc.segments.find((s): s is Extract<RedactedDocSegment, { type: 'redacted' }> =>\n s.type === 'redacted' && s.id === spanId,\n )\n if (!seg) return { ok: false, reason: 'not_found' }\n const allowed = await options.canReveal({ id: seg.id, kind: seg.kind })\n if (!allowed) return { ok: false, reason: 'forbidden' }\n const value = await options.decrypt(seg.cipher)\n if (options.onReveal) await options.onReveal({ id: seg.id, kind: seg.kind })\n return { ok: true, value }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/teams/roles.ts"],"sourcesContent":["/**\n * Pure role algebra for the teams capability — the tenancy/membership model\n * shared across the fleet. Zero dependencies: no drizzle, no env, no react, no\n * I/O. The DB layer (`./teams/drizzle`), the members API (`./teams/members-api`)\n * and the React surface (`./teams-react`) all build on these functions; this\n * leaf imports nothing back, so a consumer can pull just the role math.\n *\n * Two role ladders, deliberately distinct:\n * - Organization roles rank the tenant (who owns/administers the org and its\n * billing). An org owner/admin is an owner of every workspace under it.\n * - Workspace roles rank a single workspace. They are the access primitive\n * every route checks via `hasWorkspaceRole(actual, minimum)`.\n *\n * `resolveWorkspaceRole` is the bridge: it folds the org role and the\n * per-workspace role into the one effective workspace role a request runs at.\n */\n\nexport const WORKSPACE_ROLES = ['viewer', 'editor', 'admin', 'owner'] as const\nexport type WorkspaceRole = typeof WORKSPACE_ROLES[number]\n\nexport const ASSIGNABLE_WORKSPACE_ROLES = ['viewer', 'editor', 'admin'] as const\nexport type AssignableWorkspaceRole = typeof ASSIGNABLE_WORKSPACE_ROLES[number]\n\nexport const ORGANIZATION_ROLES = ['owner', 'admin', 'member', 'billing'] as const\nexport type OrganizationRole = typeof ORGANIZATION_ROLES[number]\n\nexport type WorkspaceCollaborationAccess = 'read' | 'write'\nexport type SandboxWorkspaceRole = 'owner' | 'admin' | 'developer' | 'viewer'\n\nexport const WORKSPACE_ROLE_RANK: Record<WorkspaceRole, number> = {\n viewer: 0,\n editor: 1,\n admin: 2,\n owner: 3,\n}\n\nexport const ORGANIZATION_ROLE_RANK: Record<OrganizationRole, number> = {\n member: 0,\n billing: 1,\n admin: 2,\n owner: 3,\n}\n\n/** True when `actual` is at least `minimum` on the workspace ladder. */\nexport function hasWorkspaceRole(actual: WorkspaceRole, minimum: WorkspaceRole): boolean {\n return WORKSPACE_ROLE_RANK[actual] >= WORKSPACE_ROLE_RANK[minimum]\n}\n\n/** True when `actual` is at least `minimum` on the organization ladder. */\nexport function hasOrganizationRole(actual: OrganizationRole, minimum: OrganizationRole): boolean {\n return ORGANIZATION_ROLE_RANK[actual] >= ORGANIZATION_ROLE_RANK[minimum]\n}\n\nexport function isAssignableWorkspaceRole(value: unknown): value is AssignableWorkspaceRole {\n return typeof value === 'string' && ASSIGNABLE_WORKSPACE_ROLES.includes(value as AssignableWorkspaceRole)\n}\n\n/** Org owners and admins are workspace owners across the whole org. */\nexport function organizationRoleGrantsWorkspaceOwner(role: OrganizationRole | string | null | undefined): boolean {\n return role === 'owner' || role === 'admin'\n}\n\n/**\n * The effective workspace role a request runs at: org owner/admin → owner of\n * every workspace; otherwise the explicit per-workspace role (or null = no\n * access). This is the single fold every access check goes through.\n */\nexport function resolveWorkspaceRole(\n organizationRole: OrganizationRole | string | null | undefined,\n workspaceRole: WorkspaceRole | null | undefined,\n): WorkspaceRole | null {\n return organizationRoleGrantsWorkspaceOwner(organizationRole) ? 'owner' : workspaceRole ?? null\n}\n\n/**\n * Whether `actorRole` may set/clear a member currently at `targetRole`. Owners\n * can manage anyone; everyone else can only manage members strictly below\n * their own rank (an admin cannot demote another admin or an owner).\n */\nexport function canManageWorkspaceMemberRole(actorRole: WorkspaceRole, targetRole: WorkspaceRole): boolean {\n return actorRole === 'owner' || !hasWorkspaceRole(targetRole, actorRole)\n}\n\nexport function workspaceRoleToCollaborationAccess(role: WorkspaceRole): WorkspaceCollaborationAccess {\n return role === 'viewer' ? 'read' : 'write'\n}\n\nexport function workspaceRoleToSandboxRole(role: WorkspaceRole): SandboxWorkspaceRole {\n const mapping: Record<WorkspaceRole, SandboxWorkspaceRole> = {\n owner: 'owner',\n admin: 'admin',\n editor: 'developer',\n viewer: 'viewer',\n }\n return mapping[role]\n}\n"],"mappings":";AAiBO,IAAM,kBAAkB,CAAC,UAAU,UAAU,SAAS,OAAO;AAG7D,IAAM,6BAA6B,CAAC,UAAU,UAAU,OAAO;AAG/D,IAAM,qBAAqB,CAAC,SAAS,SAAS,UAAU,SAAS;AAMjE,IAAM,sBAAqD;AAAA,EAChE,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AACT;AAEO,IAAM,yBAA2D;AAAA,EACtE,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AACT;AAGO,SAAS,iBAAiB,QAAuB,SAAiC;AACvF,SAAO,oBAAoB,MAAM,KAAK,oBAAoB,OAAO;AACnE;AAGO,SAAS,oBAAoB,QAA0B,SAAoC;AAChG,SAAO,uBAAuB,MAAM,KAAK,uBAAuB,OAAO;AACzE;AAEO,SAAS,0BAA0B,OAAkD;AAC1F,SAAO,OAAO,UAAU,YAAY,2BAA2B,SAAS,KAAgC;AAC1G;AAGO,SAAS,qCAAqC,MAA6D;AAChH,SAAO,SAAS,WAAW,SAAS;AACtC;AAOO,SAAS,qBACd,kBACA,eACsB;AACtB,SAAO,qCAAqC,gBAAgB,IAAI,UAAU,iBAAiB;AAC7F;AAOO,SAAS,6BAA6B,WAA0B,YAAoC;AACzG,SAAO,cAAc,WAAW,CAAC,iBAAiB,YAAY,SAAS;AACzE;AAEO,SAAS,mCAAmC,MAAmD;AACpG,SAAO,SAAS,WAAW,SAAS;AACtC;AAEO,SAAS,2BAA2B,MAA2C;AACpF,QAAM,UAAuD;AAAA,IAC3D,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACA,SAAO,QAAQ,IAAI;AACrB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/web-react/sandbox-terminal.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\n\nexport interface SandboxTerminalConnection {\n runtimeUrl: string | null\n sidecarUrl: string | null\n token: string | null\n expiresAt: string | null\n status: string\n error: string | null\n loading: boolean\n sandboxId?: string\n}\n\nexport interface SandboxTerminalConnectionResponse {\n runtimeUrl?: string\n sidecarUrl?: string\n token?: string\n expiresAt?: string\n status?: string\n error?: string\n sandboxId?: string\n}\n\nexport interface UseSandboxTerminalConnectionOptions {\n workspaceId: string\n connectionUrl?: string | ((workspaceId: string) => string)\n fetcher?: typeof fetch\n provisionPollIntervalMs?: number\n provisionPollTimeoutMs?: number\n tokenRefreshSkewMs?: number\n}\n\nexport interface UseSandboxTerminalConnectionResult extends SandboxTerminalConnection {\n connect: () => Promise<void>\n}\n\nconst DEFAULT_PROVISION_POLL_INTERVAL_MS = 2_000\nconst DEFAULT_PROVISION_POLL_TIMEOUT_MS = 90_000\nconst DEFAULT_TOKEN_REFRESH_SKEW_MS = 120_000\n\nconst EMPTY_CONNECTION: SandboxTerminalConnection = {\n runtimeUrl: null,\n sidecarUrl: null,\n token: null,\n expiresAt: null,\n status: 'idle',\n error: null,\n loading: false,\n}\n\nexport function useSandboxTerminalConnection(opts: UseSandboxTerminalConnectionOptions): UseSandboxTerminalConnectionResult {\n const [conn, setConn] = useState<SandboxTerminalConnection>(EMPTY_CONNECTION)\n const mountedRef = useRef(false)\n const generationRef = useRef(0)\n const fetcher = opts.fetcher ?? fetch\n const pollIntervalMs = opts.provisionPollIntervalMs ?? DEFAULT_PROVISION_POLL_INTERVAL_MS\n const pollTimeoutMs = opts.provisionPollTimeoutMs ?? DEFAULT_PROVISION_POLL_TIMEOUT_MS\n const refreshSkewMs = opts.tokenRefreshSkewMs ?? DEFAULT_TOKEN_REFRESH_SKEW_MS\n\n const connectionUrl = useCallback(() => {\n if (typeof opts.connectionUrl === 'function') return opts.connectionUrl(opts.workspaceId)\n return opts.connectionUrl ?? `/api/workspaces/${encodeURIComponent(opts.workspaceId)}/sandbox/connection`\n }, [opts.connectionUrl, opts.workspaceId])\n\n const connect = useCallback(async () => {\n const generation = generationRef.current + 1\n generationRef.current = generation\n const isCurrent = () => mountedRef.current && generationRef.current === generation\n const setCurrentConn: typeof setConn = (value) => {\n if (!isCurrent()) return\n setConn(value)\n }\n\n setCurrentConn((current) => ({ ...current, loading: true, error: null }))\n const deadline = Date.now() + pollTimeoutMs\n while (isCurrent()) {\n try {\n const res = await fetcher(connectionUrl())\n const data = (await res.json()) as SandboxTerminalConnectionResponse\n if (!isCurrent()) return\n const runtimeUrl = data.runtimeUrl ?? data.sidecarUrl\n if (res.ok && runtimeUrl && data.token && data.expiresAt) {\n setCurrentConn({\n runtimeUrl,\n sidecarUrl: data.sidecarUrl ?? runtimeUrl,\n token: data.token,\n expiresAt: data.expiresAt,\n status: data.status ?? 'running',\n error: null,\n loading: false,\n ...(data.sandboxId ? { sandboxId: data.sandboxId } : {}),\n })\n return\n }\n if (res.ok) {\n setCurrentConn({\n runtimeUrl: null,\n sidecarUrl: null,\n token: null,\n expiresAt: null,\n loading: false,\n error: 'Sandbox connection response is missing required fields',\n status: data.status ?? 'error',\n ...(data.sandboxId ? { sandboxId: data.sandboxId } : {}),\n })\n return\n }\n if (res.status === 503 && Date.now() < deadline) {\n setCurrentConn((current) => ({\n ...current,\n loading: true,\n status: data.status ?? 'provisioning',\n error: null,\n }))\n await sleep(pollIntervalMs)\n continue\n }\n setCurrentConn((current) => ({\n ...current,\n runtimeUrl: null,\n sidecarUrl: null,\n token: null,\n expiresAt: null,\n loading: false,\n error: data.error ?? 'Sandbox not available',\n status: data.status ?? 'error',\n }))\n return\n } catch (err) {\n if (!isCurrent()) return\n if (Date.now() < deadline) {\n await sleep(pollIntervalMs)\n continue\n }\n setCurrentConn((current) => ({\n ...current,\n runtimeUrl: null,\n sidecarUrl: null,\n token: null,\n expiresAt: null,\n loading: false,\n error: err instanceof Error ? err.message : 'Connection failed',\n }))\n return\n }\n }\n }, [connectionUrl, fetcher, pollIntervalMs, pollTimeoutMs])\n\n useEffect(() => {\n mountedRef.current = true\n return () => {\n mountedRef.current = false\n generationRef.current += 1\n }\n }, [])\n\n useEffect(() => {\n void connect()\n }, [connect])\n\n useEffect(() => {\n if (!conn.runtimeUrl || !conn.token || !conn.expiresAt) return\n const refreshAt = Date.parse(conn.expiresAt) - Date.now() - refreshSkewMs\n if (!Number.isFinite(refreshAt)) {\n setConn((current) => ({\n ...current,\n runtimeUrl: null,\n sidecarUrl: null,\n token: null,\n expiresAt: null,\n status: 'error',\n error: 'Sandbox token expiry is invalid',\n }))\n return\n }\n const timer = window.setTimeout(() => {\n void connect()\n }, Math.max(1_000, refreshAt))\n return () => window.clearTimeout(timer)\n }, [conn.runtimeUrl, conn.token, conn.expiresAt, connect, refreshSkewMs])\n\n return { ...conn, connect }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => window.setTimeout(resolve, ms))\n}\n\nconst DEFAULT_TERMINAL_CID_KEY = 'agent-app:terminal-connection-id'\n\nfunction newConnectionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') return crypto.randomUUID()\n return `cid-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`\n}\n\n/**\n * Stable-per-tab, unique-per-client terminal connection id.\n *\n * Persists in `sessionStorage` so a reload in the same tab reuses the id (the\n * sidecar restores the same PTY session via `TerminalView.connectionId`), while\n * separate tabs/windows each get a distinct id. Pass the result as\n * `TerminalView`'s `connectionId`. Without it (e.g. gtm-agent today) every tab\n * shares one connection id and their reconnects evict each other.\n *\n * Falls back to an ephemeral id when `sessionStorage` is unavailable (SSR,\n * privacy mode) — still unique per call, just not reload-stable.\n */\nexport function tabTerminalConnectionId(storageKey: string = DEFAULT_TERMINAL_CID_KEY): string {\n try {\n const store = globalThis.sessionStorage\n const existing = store?.getItem(storageKey)\n if (existing) return existing\n const id = newConnectionId()\n store?.setItem(storageKey, id)\n return id\n } catch {\n return newConnectionId()\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/interactions/sidecar.ts","../src/interactions/route.ts"],"sourcesContent":["/**\n * Server-side client for the sandbox sidecar's generic interaction routes\n * (`GET/POST {runtimeUrl}/agents/sessions/{sessionId}/interactions`). The\n * pinned sandbox SDK exposes only the question-specific `session().answer()`\n * convenience; these raw calls are backend-agnostic (question/permission/plan,\n * any harness) and carry explicit outcomes (accepted/declined).\n *\n * Server-only: the sidecar bearer must never reach browser code. The caller\n * supplies the connection as a structural value (runtime URL + bearer +\n * session id) — no sandbox-SDK import, so any box-resolution strategy works.\n */\n\nimport type { InteractionData, InteractionOutcome, InteractionRequestWire } from './contract'\n\nexport interface SidecarInteractionsError {\n code: string\n message: string\n /** Upstream HTTP status; 0 when the sidecar was unreachable. */\n status: number\n}\n\nexport type SidecarInteractionsResult<T> =\n | { succeeded: true; value: T }\n | { succeeded: false; error: SidecarInteractionsError }\n\n/** Where and how to reach one session's interaction registry. */\nexport interface SidecarInteractionsConnection {\n runtimeUrl: string\n authToken?: string\n /** The sidecar agent-session id (the chat thread's session). */\n sessionId: string\n /** Request deadline. A pending interaction means the box is up and the\n * sidecar responsive; a short default keeps a wedged runtime from stalling\n * the answering request. */\n timeoutMs?: number\n /** Injection seam for tests; defaults to global fetch. */\n fetchImpl?: typeof fetch\n}\n\nconst DEFAULT_TIMEOUT_MS = 5_000\n\n/** Strips bearer tokens / key material before an upstream message is logged\n * or surfaced. */\nfunction sanitizeUpstreamMessage(input: unknown): string {\n const message = input instanceof Error ? input.message : String(input)\n return message\n .replace(/Bearer\\s+[^\\s]+/gi, 'Bearer [redacted]')\n .replace(/\\b(?:sk|pk|tc)[_-][A-Za-z0-9_-]{8,}\\b/g, '[redacted-key]')\n}\n\nasync function interactionsFetch(\n connection: SidecarInteractionsConnection,\n init: { method: 'GET' } | { method: 'POST'; body: Record<string, unknown> },\n): Promise<SidecarInteractionsResult<Record<string, unknown>>> {\n const doFetch = connection.fetchImpl ?? fetch\n const url = `${connection.runtimeUrl.replace(/\\/$/, '')}/agents/sessions/${encodeURIComponent(connection.sessionId)}/interactions`\n let response: Response\n try {\n response = await doFetch(url, {\n method: init.method,\n headers: {\n ...(connection.authToken ? { Authorization: `Bearer ${connection.authToken}` } : {}),\n ...(init.method === 'POST' ? { 'Content-Type': 'application/json' } : {}),\n },\n ...(init.method === 'POST' ? { body: JSON.stringify(init.body) } : {}),\n signal: AbortSignal.timeout(connection.timeoutMs ?? DEFAULT_TIMEOUT_MS),\n })\n } catch (err) {\n return {\n succeeded: false,\n error: { code: 'UPSTREAM_UNREACHABLE', message: sanitizeUpstreamMessage(err), status: 0 },\n }\n }\n const raw = await response.text().catch(() => '')\n let parsed: Record<string, unknown> = {}\n try {\n parsed = raw ? (JSON.parse(raw) as Record<string, unknown>) : {}\n } catch {\n // Non-JSON error bodies (proxy 502 pages) fall through to the status check.\n }\n if (!response.ok) {\n const upstreamError = (parsed.error ?? {}) as { code?: unknown; message?: unknown }\n return {\n succeeded: false,\n error: {\n code: typeof upstreamError.code === 'string' && upstreamError.code ? upstreamError.code : 'UPSTREAM_ERROR',\n message: sanitizeUpstreamMessage(\n typeof upstreamError.message === 'string' && upstreamError.message\n ? upstreamError.message\n : `sidecar interactions ${init.method} failed (${response.status})`,\n ),\n status: response.status,\n },\n }\n }\n return { succeeded: true, value: parsed }\n}\n\n/** Outstanding (unanswered) interactions for the session — the sidecar's\n * registry is authoritative, so this is the reconnect/reload source of truth. */\nexport async function listSessionInteractions(\n connection: SidecarInteractionsConnection,\n): Promise<SidecarInteractionsResult<InteractionRequestWire[]>> {\n const result = await interactionsFetch(connection, { method: 'GET' })\n if (!result.succeeded) return result\n const data = result.value.data as { interactions?: unknown } | undefined\n if (!Array.isArray(data?.interactions)) {\n return {\n succeeded: false,\n error: { code: 'MALFORMED_RESPONSE', message: 'sidecar list returned no interactions array', status: 200 },\n }\n }\n return { succeeded: true, value: data.interactions as InteractionRequestWire[] }\n}\n\n/** Resolves one interaction. `data` is required by the sidecar only for\n * `accepted` outcomes and is validated fail-closed against the answerSpec\n * (400 INVALID_INTERACTION_ANSWER on mismatch). */\nexport async function respondToSessionInteraction(\n connection: SidecarInteractionsConnection,\n response: { id: string; outcome: InteractionOutcome; data?: InteractionData },\n): Promise<SidecarInteractionsResult<void>> {\n const result = await interactionsFetch(connection, {\n method: 'POST',\n body: {\n id: response.id,\n outcome: response.outcome,\n ...(response.data ? { data: response.data } : {}),\n },\n })\n if (!result.succeeded) return result\n return { succeeded: true, value: undefined }\n}\n","/**\n * Framework-neutral interaction-answer endpoints, lifted out of the per-app\n * route files (gtm `api.chat.interactions`, legal `api.chat.interactions`,\n * tax `api.sessions.$id.interactions` — three byte-similar forks):\n *\n * list(request) — GET: outstanding asks for a live turn (reload restore)\n * answer(request) — POST `{ id, outcome, data? }`: resolve one ask\n *\n * The product supplies ONE seam, `resolveConnection`: authenticate the caller,\n * authorize the thread/session, and resolve the sidecar connection. Everything\n * behind the seam is mechanism the forks kept re-fixing:\n *\n * - body validation (safe field keys, typed values),\n * - sidecar error → client contract mapping (every \"the ask is gone\" shape\n * becomes 410 so the card flips to its expired state),\n * - duplicate resolution: after answering, every other outstanding ask with\n * the same content signature (a re-emitted duplicate) gets the same answer,\n * - unblock verification: re-list and fail loud (503 INTERACTION_STILL_PENDING)\n * when the sidecar accepted the POST but the ask is still open,\n * - best-effort list: sidecar failures return `{ interactions: [],\n * unavailable }` so a reload restore never breaks the live stream.\n *\n * Handlers return web-standard `Response`s (Workers, Node 18+, Deno) — no\n * router import anywhere.\n */\n\nimport {\n interactionFromWireRequest,\n isSafeInteractionFieldKey,\n questionInteractionContentSignature,\n type InteractionData,\n type InteractionRequestWire,\n} from './contract'\nimport {\n listSessionInteractions,\n respondToSessionInteraction,\n type SidecarInteractionsConnection,\n type SidecarInteractionsError,\n} from './sidecar'\n\n// A client resolves an ask by answering (`accepted`) or refusing (`declined`).\n// Withdrawal (`cancelled`) is an agent/broker outcome delivered via the\n// `interaction.cancel` event, never a client POST, so it is not accepted here.\nexport type InteractionClientOutcome = 'accepted' | 'declined'\n\nexport type InteractionAnswerBodyValidation =\n | { ok: true; id: string; outcome: InteractionClientOutcome; data?: InteractionData }\n | { ok: false; error: string }\n\n/** Validates the client POST body: `{ id, outcome, data? }` with\n * identifier-safe field keys and primitive/string-array values only. */\nexport function validateInteractionAnswerBody(body: Record<string, unknown>): InteractionAnswerBodyValidation {\n const id = typeof body.id === 'string' && body.id ? body.id : null\n if (!id) return { ok: false, error: 'Missing interaction id' }\n const outcome = body.outcome\n if (outcome !== 'accepted' && outcome !== 'declined') {\n return { ok: false, error: 'Invalid outcome: expected accepted or declined' }\n }\n if (body.data === undefined) return { ok: true, id, outcome }\n if (!body.data || typeof body.data !== 'object' || Array.isArray(body.data)) {\n return { ok: false, error: 'Invalid data: expected an object of field values' }\n }\n const data: InteractionData = {}\n for (const [key, value] of Object.entries(body.data)) {\n if (!isSafeInteractionFieldKey(key)) {\n return { ok: false, error: 'Invalid data: field names must contain only letters, numbers, underscores, or hyphens' }\n }\n const validValue =\n typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ||\n (Array.isArray(value) && value.every((item) => typeof item === 'string'))\n if (!validValue) {\n return { ok: false, error: 'Invalid data: field values must be strings, numbers, booleans, or string arrays' }\n }\n data[key] = value as InteractionData[string]\n }\n return { ok: true, id, outcome, data }\n}\n\nexport type InteractionRouteLogger = Pick<Console, 'warn' | 'error'>\n\n/** Sidecar error → the client-actionable contract. Every \"the ask is gone\"\n * shape maps to 410 so the card flips to its expired state — a raw 404/409\n * must never surface. */\nexport function mapInteractionRespondFailure(\n error: SidecarInteractionsError,\n logger: InteractionRouteLogger = console,\n): Response {\n if (error.code === 'INVALID_INTERACTION_ANSWER') {\n return Response.json(\n { code: 'INVALID_INTERACTION_ANSWER', error: 'This question needs an answer from the card above — pick one of the listed options.' },\n { status: 400 },\n )\n }\n if (error.status === 404) {\n return Response.json(\n { code: 'INTERACTION_EXPIRED', error: 'This question is no longer waiting for an answer.' },\n { status: 410 },\n )\n }\n if (error.status === 501 || error.code === 'NOT_IMPLEMENTED') {\n return Response.json(\n { code: 'INTERACTIONS_UNSUPPORTED', error: 'This agent backend cannot accept answers this way.' },\n { status: 501 },\n )\n }\n logger.error('[interactions] respond failed:', error)\n return Response.json(\n { code: 'INTERACTION_UPSTREAM_FAILED', error: 'Could not reach the agent. Try again.' },\n { status: 503 },\n )\n}\n\n/** The product seam's verdict for one request. `response` short-circuits with\n * a product-authored Response (401/404/429…); `unavailable` means the caller\n * is fine but the sandbox runtime is not reachable — the factory shapes that\n * per intent (empty list for `list`, 503 for `answer`). */\nexport type InteractionConnectionResolution =\n | { ok: true; connection: SidecarInteractionsConnection }\n | { ok: false; response: Response }\n | { ok: false; unavailable: string }\n\nexport interface ResolveInteractionConnectionArgs {\n request: Request\n intent: 'list' | 'answer'\n /** The parsed, validated POST body (answer intent only) so the resolver can\n * read product routing fields (workspaceId/threadId) without re-parsing. */\n body?: Record<string, unknown>\n}\n\nexport interface BeforeInteractionAnswerArgs {\n request: Request\n /** Original parsed body, including product routing fields. */\n body: Record<string, unknown>\n /** Shared validation result; products never need to parse the answer again. */\n answer: Extract<InteractionAnswerBodyValidation, { ok: true }>\n connection: SidecarInteractionsConnection\n /** The route's single authoritative pre-answer sidecar snapshot. */\n outstanding: InteractionRequestWire[]\n answeredRequest?: InteractionRequestWire\n /** Content-identical questions that the shared route will also answer. */\n duplicateRequests: InteractionRequestWire[]\n}\n\nexport interface DurableInteractionRouteArgs extends BeforeInteractionAnswerArgs {\n /** Caller-created opaque identifier, stable across an ambiguous retry. */\n attemptKey: string\n}\n\n/** Crash-recoverable persistence lifecycle for the answer route. The product\n * binds this structural port to `/durable-chat` (or an equivalent durable\n * store). Existing `beforeAnswer` behavior remains independent and unchanged. */\nexport interface DurableInteractionRoutePersistence<TPrepared = unknown> {\n guarantee: 'reconciled' | 'best-effort'\n prepare(args: DurableInteractionRouteArgs): TPrepared | Promise<TPrepared>\n /** Resolve an ambiguous retry (for example, the sidecar says the ask is\n * already gone). Only `settled:true` permits the route to report success. */\n reconcile(args: DurableInteractionRouteArgs & { prepared: TPrepared }):\n | { settled: boolean }\n | Promise<{ settled: boolean }>\n /** Record the authority acknowledgement before terminal projection. */\n acknowledge(args: DurableInteractionRouteArgs & {\n prepared: TPrepared\n duplicateIds: string[]\n }): void | Promise<void>\n /** Idempotently materialize terminal status and accepted values. */\n finalize(args: DurableInteractionRouteArgs & {\n prepared: TPrepared\n duplicateIds: string[]\n }): void | Promise<void>\n fail?(args: DurableInteractionRouteArgs & { prepared: TPrepared; error: unknown }): void | Promise<void>\n}\n\nexport interface InteractionAnswerRouteOptions {\n /** Authenticate + authorize the caller and resolve the sidecar connection.\n * This is the only product-supplied step: session auth, workspace/thread\n * access, rate limiting, and box resolution all live here. */\n resolveConnection: (args: ResolveInteractionConnectionArgs) => Promise<InteractionConnectionResolution>\n /** Product persistence seam that runs before the answer can unblock and\n * finalize the agent turn. A throw aborts the request before any answer POST. */\n beforeAnswer?: (args: BeforeInteractionAnswerArgs) => void | Promise<void>\n /** Additive crash-recoverable settlement. When configured, POST requires an\n * `attemptKey`; accepted values are finalized only after sidecar ack. */\n durable?: DurableInteractionRoutePersistence\n logger?: InteractionRouteLogger\n}\n\nexport interface InteractionAnswerRoute {\n /** GET — outstanding interactions for a live turn. Failures return an empty\n * list with an explicit `unavailable` code: the caller is a best-effort\n * reload restore, and the live/replayed stream must stay untouched when the\n * sidecar cannot answer. */\n list: (request: Request) => Promise<Response>\n /** POST `{ id, outcome, data?, ...productFields }` — resolve one ask, answer\n * content-identical duplicates the same way, then re-list to prove the run\n * actually unblocked. */\n answer: (request: Request) => Promise<Response>\n}\n\nexport function createInteractionAnswerRoute(options: InteractionAnswerRouteOptions): InteractionAnswerRoute {\n const logger = options.logger ?? console\n\n async function list(request: Request): Promise<Response> {\n const resolution = await options.resolveConnection({ request, intent: 'list' })\n if (!resolution.ok) {\n if ('response' in resolution) return resolution.response\n return Response.json({ interactions: [], unavailable: resolution.unavailable })\n }\n const result = await listSessionInteractions(resolution.connection)\n if (!result.succeeded) {\n logger.warn('[interactions] list failed:', result.error)\n return Response.json({ interactions: [], unavailable: result.error.code })\n }\n return Response.json({ interactions: result.value })\n }\n\n async function answer(request: Request): Promise<Response> {\n const body = await request.json().catch(() => null) as Record<string, unknown> | null\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\n return Response.json({ error: 'Invalid JSON body' }, { status: 400 })\n }\n const validation = validateInteractionAnswerBody(body)\n if (!validation.ok) return Response.json({ error: validation.error }, { status: 400 })\n const attemptKey = typeof body.attemptKey === 'string' ? body.attemptKey.trim() : ''\n if (options.durable && !attemptKey) {\n return Response.json({ error: 'Missing attemptKey for durable interaction answer' }, { status: 400 })\n }\n\n const resolution = await options.resolveConnection({ request, intent: 'answer', body })\n if (!resolution.ok) {\n if ('response' in resolution) return resolution.response\n return mapInteractionRespondFailure(\n { code: resolution.unavailable, message: 'sandbox runtime unavailable', status: 0 },\n logger,\n )\n }\n const connection = resolution.connection\n const answerPayload = {\n outcome: validation.outcome,\n ...(validation.data ? { data: validation.data } : {}),\n }\n\n // Snapshot the answered ask's content signature BEFORE resolving it, so any\n // content-identical duplicates still outstanding afterwards (the agent may\n // have re-emitted the same question N times) can be answered the same way.\n const before = await listSessionInteractions(connection)\n if (!before.succeeded && (options.beforeAnswer || options.durable)) {\n return mapInteractionRespondFailure(before.error, logger)\n }\n const answeredRequest = before.succeeded ? before.value.find((item) => item.id === validation.id) : undefined\n if (options.beforeAnswer && !options.durable && !answeredRequest) {\n return mapInteractionRespondFailure(\n { code: 'NOT_FOUND', message: 'interaction not found', status: 404 },\n logger,\n )\n }\n const answeredSignature = answeredRequest\n ? questionInteractionContentSignature(interactionFromWireRequest(answeredRequest))\n : null\n const duplicateRequests = before.succeeded && answeredSignature\n ? before.value.filter((item) => item.id !== validation.id && (\n questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n ))\n : []\n\n const lifecycleArgs: BeforeInteractionAnswerArgs = {\n request,\n body,\n answer: validation,\n connection,\n outstanding: before.succeeded ? before.value : [],\n ...(answeredRequest ? { answeredRequest } : {}),\n duplicateRequests,\n }\n\n if (options.beforeAnswer && answeredRequest) {\n try {\n await options.beforeAnswer(lifecycleArgs)\n } catch (error) {\n logger.error('[interactions] beforeAnswer failed:', error)\n return Response.json(\n { code: 'INTERACTION_BEFORE_ANSWER_FAILED', error: 'Could not save the answer. Try again.' },\n { status: 503 },\n )\n }\n }\n\n let prepared: unknown\n const durableArgs = options.durable\n ? { ...lifecycleArgs, attemptKey }\n : null\n if (options.durable && durableArgs) {\n try {\n prepared = await options.durable.prepare(durableArgs)\n } catch (error) {\n logger.error('[interactions] durable prepare failed:', error)\n return Response.json(\n { code: 'INTERACTION_PREPARE_FAILED', error: 'Could not prepare the answer. Try again.' },\n { status: 503 },\n )\n }\n if (!answeredRequest) {\n let reconciled: { settled: boolean }\n try {\n reconciled = await options.durable.reconcile({ ...durableArgs, prepared })\n } catch (error) {\n logger.error('[interactions] durable reconcile failed:', error)\n reconciled = { settled: false }\n }\n if (reconciled.settled) return Response.json({ ok: true, idempotent: true })\n return Response.json(\n { code: 'INTERACTION_RECONCILIATION_PENDING', error: 'The answer status is still being checked. Retry with the same attempt.' },\n { status: 503 },\n )\n }\n }\n\n const result = await respondToSessionInteraction(connection, { id: validation.id, ...answerPayload })\n if (!result.succeeded) {\n if (options.durable && durableArgs) {\n let reconciled: { settled: boolean }\n try {\n reconciled = await options.durable.reconcile({ ...durableArgs, prepared })\n } catch {\n reconciled = { settled: false }\n }\n if (reconciled.settled) return Response.json({ ok: true, idempotent: true })\n if (result.error.status === 404) {\n return Response.json(\n { code: 'INTERACTION_RECONCILIATION_PENDING', error: 'The answer status is still being checked. Retry with the same attempt.' },\n { status: 503 },\n )\n }\n try {\n await options.durable.fail?.({ ...durableArgs, prepared, error: result.error })\n } catch {\n // The upstream failure remains authoritative; a persistence cleanup\n // failure must not replace its client-facing mapping.\n }\n }\n return mapInteractionRespondFailure(result.error, logger)\n }\n\n let remaining = await listSessionInteractions(connection)\n const acknowledgedDuplicateIds: string[] = []\n if (remaining.succeeded && answeredSignature) {\n const remainingDuplicates = remaining.value.filter((item) => {\n if (item.id === validation.id) return false\n return questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n })\n for (const duplicate of remainingDuplicates) {\n const duplicateResult = await respondToSessionInteraction(connection, { id: duplicate.id, ...answerPayload })\n if (!duplicateResult.succeeded) break\n acknowledgedDuplicateIds.push(duplicate.id)\n }\n if (remainingDuplicates.length > 0) remaining = await listSessionInteractions(connection)\n }\n\n // Prove the run actually unblocked: neither the answered id nor any\n // content-duplicate may still be outstanding. If one is, the sidecar\n // accepted the POST but did not release the run — report it rather than\n // tell the user it was answered.\n if (remaining.succeeded && remaining.value.some((item) => item.id === validation.id || (\n answeredSignature && questionInteractionContentSignature(interactionFromWireRequest(item)) === answeredSignature\n ))) {\n logger.error('[interactions] respond returned ok but interaction is still pending:', {\n sessionId: connection.sessionId,\n interactionId: validation.id,\n })\n return Response.json(\n { code: 'INTERACTION_STILL_PENDING', error: 'The agent did not accept the answer. Try answering again.' },\n { status: 503 },\n )\n }\n\n if (options.durable && durableArgs) {\n try {\n await options.durable.acknowledge({\n ...durableArgs,\n prepared,\n duplicateIds: acknowledgedDuplicateIds,\n })\n await options.durable.finalize({\n ...durableArgs,\n prepared,\n duplicateIds: acknowledgedDuplicateIds,\n })\n } catch (error) {\n logger.error('[interactions] durable finalize failed:', error)\n return Response.json(\n { code: 'INTERACTION_FINALIZE_FAILED', error: 'The answer was accepted but is still being saved. Retry to reconcile it.' },\n { status: 503 },\n )\n }\n }\n\n return Response.json({ ok: true })\n }\n\n return { list, answer }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tools/auth.ts","../src/tools/mcp.ts","../src/tools/mcp-rpc.ts"],"sourcesContent":["import type { AppToolContext } from './types'\n\n/**\n * Header names carrying the server-set per-turn context + the capability token.\n * Defaults are product-neutral (`X-Agent-App-*`); a product that already ships\n * a header convention (e.g. `X-Acme-User-Id`) passes its own.\n */\nexport interface ToolHeaderNames {\n userId: string\n workspaceId: string\n threadId: string\n}\n\nexport const DEFAULT_HEADER_NAMES: ToolHeaderNames = {\n userId: 'X-Agent-App-User-Id',\n workspaceId: 'X-Agent-App-Workspace-Id',\n threadId: 'X-Agent-App-Thread-Id',\n}\n\nexport interface AuthenticateOptions {\n /** Verify the bearer capability token belongs to `userId`. The product's\n * HMAC/JWT impl — the seam that keeps token crypto out of this package. */\n verifyToken: (userId: string, bearer: string) => Promise<boolean>\n headerNames?: ToolHeaderNames\n}\n\nexport type ToolAuthResult =\n | { ok: true; ctx: AppToolContext }\n | { ok: false; response: Response }\n\n/**\n * Recover + verify the trusted context for a tool request. The user comes from\n * a server-set header and the bearer token MUST verify against THAT user; the\n * workspace comes from a header too — never from tool args — so the model can\n * neither forge identity nor target another workspace. Fail-closed: any missing\n * credential or a token minted for another user yields a 401/400 Response.\n */\nexport async function authenticateToolRequest(request: Request, opts: AuthenticateOptions): Promise<ToolAuthResult> {\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n const userId = request.headers.get(h.userId)?.trim()\n const workspaceId = request.headers.get(h.workspaceId)?.trim()\n const threadId = request.headers.get(h.threadId)?.trim() || null\n const bearer = request.headers.get('authorization')?.match(/^Bearer\\s+(.+)$/i)?.[1]\n\n if (!userId || !bearer) {\n return { ok: false, response: Response.json({ error: 'Missing capability credentials' }, { status: 401 }) }\n }\n if (!(await opts.verifyToken(userId, bearer))) {\n return { ok: false, response: Response.json({ error: 'Invalid capability token' }, { status: 401 }) }\n }\n if (!workspaceId) {\n return { ok: false, response: Response.json({ error: 'Missing workspace context' }, { status: 400 }) }\n }\n return { ok: true, ctx: { userId, workspaceId, threadId } }\n}\n\n/** Read a tool's argument object from the request body, tolerant of MCP host\n * aliases (`args` / `arguments`) or a bare body. Returns null on non-JSON. */\nexport async function readToolArgs<T>(request: Request): Promise<T | null> {\n let body: { args?: T; arguments?: T }\n try {\n body = (await request.json()) as typeof body\n } catch {\n return null\n }\n return (body.args ?? body.arguments ?? (body as T)) as T\n}\n","import type { AppToolContext } from './types'\nimport type { AppToolName } from './openai'\nimport type { AppToolDefinition } from './registry'\nimport type { ToolHeaderNames } from './auth'\nimport { DEFAULT_HEADER_NAMES } from './auth'\n\n/** Default route path each app tool is served at. A product mounts its routes\n * at these paths (or supplies its own via {@link BuildMcpServerOptions.paths}). */\nexport const DEFAULT_APP_TOOL_PATHS: Record<AppToolName, string> = {\n submit_proposal: '/api/tools/propose',\n schedule_followup: '/api/tools/followup',\n render_ui: '/api/tools/render-ui',\n add_citation: '/api/tools/citation',\n}\n\n/** The portable MCP server entry the sandbox SDK accepts (transport + url +\n * headers). Matches `AgentProfileMcpServer` structurally without importing the\n * sandbox SDK — products spread it into their profile's `mcp` map. */\nexport interface AppToolMcpServer {\n transport: 'http'\n url: string\n headers: Record<string, string>\n enabled: true\n metadata: { description: string }\n}\n\nexport interface BuildHttpMcpServerOptions {\n /** Route path on the app the sandbox POSTs to (e.g. `/api/tools/propose`). */\n path: string\n /** App base URL the sandbox reaches back to (no trailing slash required). */\n baseUrl: string\n /** Per-user capability token, baked into the Authorization header. */\n token: string\n ctx: AppToolContext\n /** Tool description the model sees. */\n description: string\n headerNames?: ToolHeaderNames\n}\n\n/**\n * Build ONE HTTP MCP server entry — the generic agent→app bridge. The\n * capability token + the user/workspace/thread ids ride in server-set headers\n * (never tool args), so the model can't forge identity or target another\n * workspace. Workspace/thread headers are omitted when their `ctx` value is\n * empty/null (e.g. an integration-invoke bridge that's user-scoped only). Used\n * directly for non-app-tool bridges (integration_invoke) and via\n * {@link buildAppToolMcpServer} for the four app tools.\n */\nexport function buildHttpMcpServer(opts: BuildHttpMcpServerOptions): AppToolMcpServer {\n const base = opts.baseUrl.replace(/\\/+$/, '')\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n return {\n transport: 'http',\n url: `${base}${opts.path}`,\n headers: {\n Authorization: `Bearer ${opts.token}`,\n [h.userId]: opts.ctx.userId,\n ...(opts.ctx.workspaceId ? { [h.workspaceId]: opts.ctx.workspaceId } : {}),\n ...(opts.ctx.threadId ? { [h.threadId]: opts.ctx.threadId } : {}),\n 'Content-Type': 'application/json',\n },\n enabled: true,\n metadata: { description: opts.description },\n }\n}\n\n/** Options for a per-document/scoped MCP channel entry (design-canvas,\n * sequences, …). The capability token + path scope ONE resource; the document\n * id lives in the path, never a tool argument. */\nexport interface ScopedMcpServerEntryOptions {\n /** App base URL the sandbox reaches back to (trailing slash tolerated). */\n baseUrl: string\n /** Product route serving the resource's MCP handler — id is part of the path. */\n path: string\n /** Capability token the product minted for this (user, resource) scope. With\n * no token there is no entry to build — omit the server instead. */\n token: string\n /** Override the channel's default tool-server description. */\n description?: string\n /** Identity headers for products whose route recovers the user via\n * `authenticateToolRequest`. Omit when the bearer token is self-contained. */\n ctx?: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\n/**\n * Build the `AgentProfileMcpServer`-shaped entry for a scoped, per-resource MCP\n * channel. The shared mechanism behind the per-domain entry builders\n * (`buildDesignCanvasMcpServerEntry`, `buildSequencesMcpServerEntry`): same\n * token/path guards, same description default, same ctx-vs-self-contained-token\n * branching. The domain is two parameters — `label` (for guard messages) and\n * `defaultDescription` — never baked.\n *\n * The no-`ctx` branch is a GENUINE behavioral path, not a shortcut: it emits a\n * self-contained-token entry with ONLY `Authorization` + `Content-Type`.\n * Routing it through {@link buildHttpMcpServer} would unconditionally write a\n * `userId` identity header (here `undefined`), so it stays a distinct branch.\n */\nexport function buildScopedMcpServerEntry(\n opts: ScopedMcpServerEntryOptions & { label: string; defaultDescription: string },\n): AppToolMcpServer {\n if (opts.token.trim().length === 0) {\n throw new Error(`${opts.label} requires a capability token — omit the MCP server when none is available`)\n }\n if (!opts.path.startsWith('/')) {\n throw new Error(`${opts.label} path must start with \"/\" (got \"${opts.path}\")`)\n }\n const description = opts.description ?? opts.defaultDescription\n\n if (opts.ctx) {\n return buildHttpMcpServer({\n path: opts.path,\n baseUrl: opts.baseUrl,\n token: opts.token,\n ctx: opts.ctx,\n description,\n headerNames: opts.headerNames ?? DEFAULT_HEADER_NAMES,\n })\n }\n\n return {\n transport: 'http',\n url: `${opts.baseUrl.replace(/\\/+$/, '')}${opts.path}`,\n headers: {\n Authorization: `Bearer ${opts.token}`,\n 'Content-Type': 'application/json',\n },\n enabled: true,\n metadata: { description },\n }\n}\n\nexport interface BuildMcpServerOptions {\n /** A built-in app tool name, or a product-registered {@link AppToolDefinition}.\n * A custom tool supplies its route via `AppToolDefinition.path` (or `paths`). */\n tool: AppToolName | AppToolDefinition\n baseUrl: string\n token: string\n ctx: AppToolContext\n description: string\n headerNames?: ToolHeaderNames\n paths?: Partial<Record<string, string>>\n}\n\n/** Build one app-tool MCP server entry — a thin wrapper over\n * {@link buildHttpMcpServer} that resolves the tool's route path. Built-ins map\n * through {@link DEFAULT_APP_TOOL_PATHS}; a custom tool uses its own `path`\n * (or a `paths` override). */\nexport function buildAppToolMcpServer(opts: BuildMcpServerOptions): AppToolMcpServer {\n const path =\n typeof opts.tool === 'string'\n ? opts.paths?.[opts.tool] ?? DEFAULT_APP_TOOL_PATHS[opts.tool]\n : opts.paths?.[opts.tool.name] ?? opts.tool.path\n if (!path) {\n const name = typeof opts.tool === 'string' ? opts.tool : opts.tool.name\n throw new Error(`buildAppToolMcpServer: tool \"${name}\" has no route path — set AppToolDefinition.path or pass it via opts.paths`)\n }\n return buildHttpMcpServer({\n path,\n baseUrl: opts.baseUrl,\n token: opts.token,\n ctx: opts.ctx,\n description: opts.description,\n headerNames: opts.headerNames,\n })\n}\n","/**\n * Generic streamable-HTTP JSON-RPC 2.0 envelope for a tools-only MCP server.\n * Stateless, Workers-compatible: no session table, no SSE — every request gets\n * a single `application/json` response, which the streamable-HTTP transport\n * explicitly permits for tools-only servers.\n *\n * Protocol surface:\n * initialize → echo client's protocolVersion if supported, else latest\n * ping → empty result {}\n * notifications/* (no `id`) → 202 with no body\n * tools/list → tool manifest\n * tools/call → run + surface execution failures as isError text results\n * anything else → -32601\n *\n * Execution failures (argument shape, validation, store throws) become `isError`\n * tool results carrying the thrown message verbatim — the model reads WHY and\n * retries. Protocol misuse becomes a JSON-RPC error object.\n */\n\nexport const MCP_PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'] as const\nexport type McpProtocolVersion = (typeof MCP_PROTOCOL_VERSIONS)[number]\n\nconst LATEST_PROTOCOL_VERSION: McpProtocolVersion = MCP_PROTOCOL_VERSIONS[0]\n\nexport interface McpServerInfo {\n name: string\n version: string\n}\n\n/** One tool entry in the registry the handler owns. */\nexport interface McpToolDefinition<TEnv = Record<string, never>> {\n name: string\n description: string\n /** JSON Schema for the `params.arguments` object. */\n inputSchema: Record<string, unknown>\n /** Receive validated (Record) args + the env the handler threaded; throw to\n * surface an isError result — never throw for protocol/framing issues. */\n run(args: Record<string, unknown>, env: TEnv): Promise<unknown>\n}\n\nexport interface CreateMcpToolHandlerOptions<TEnv = Record<string, never>> {\n serverInfo: McpServerInfo\n /** Full tool list; order IS the tools/list order. */\n tools: McpToolDefinition<TEnv>[]\n /** Per-request environment threaded into every `run` call. If your tools are\n * stateless (or carry state through closure) pass an empty builder:\n * `() => ({} as TEnv)`. */\n buildEnv(request: Request): TEnv | Promise<TEnv>\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype JsonRpcId = string | number | null\n\ninterface ToolCallContent {\n content: Array<{ type: 'text'; text: string }>\n isError?: true\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction rpcResult(id: JsonRpcId, result: unknown): Response {\n return Response.json({ jsonrpc: '2.0', id, result })\n}\n\nfunction rpcError(id: JsonRpcId, code: number, message: string, status = 200): Response {\n return Response.json({ jsonrpc: '2.0', id, error: { code, message } }, { status })\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Build a request handler for a tools-only MCP server. The returned function\n * accepts a standard `Request` and resolves to a `Response` — mount it on any\n * Cloudflare Worker route or Remix `loader`.\n *\n * The handler calls `buildEnv` exactly ONCE per `tools/call` request (after\n * the tool is found, before `run`) — non-`tools/call` paths skip it entirely\n * so metadata requests do not pay env-build cost.\n */\nexport function createMcpToolHandler<TEnv = Record<string, never>>(\n opts: CreateMcpToolHandlerOptions<TEnv>,\n): (request: Request) => Promise<Response> {\n const toolMap = new Map<string, McpToolDefinition<TEnv>>()\n for (const tool of opts.tools) {\n if (toolMap.has(tool.name)) throw new Error(`duplicate MCP tool name: ${tool.name}`)\n toolMap.set(tool.name, tool)\n }\n\n return async (request: Request): Promise<Response> => {\n if (request.method !== 'POST') {\n return new Response('MCP server accepts JSON-RPC 2.0 over POST only', {\n status: 405,\n headers: { Allow: 'POST' },\n })\n }\n\n let body: unknown\n try {\n body = await request.json()\n } catch {\n return rpcError(null, -32700, 'Parse error: request body is not valid JSON', 400)\n }\n\n if (Array.isArray(body)) {\n return rpcError(null, -32600, 'Invalid request: JSON-RPC batching is not supported', 400)\n }\n if (!isRecord(body) || body.jsonrpc !== '2.0' || typeof body.method !== 'string') {\n return rpcError(\n null,\n -32600,\n 'Invalid request: expected a JSON-RPC 2.0 object with jsonrpc \"2.0\" and a string method',\n 400,\n )\n }\n\n const method = body.method\n const params = isRecord(body.params) ? body.params : {}\n\n // Notifications have no `id` — acknowledge without a JSON-RPC body.\n if (!('id' in body) || body.id === undefined) {\n return new Response(null, { status: 202 })\n }\n const id = body.id as JsonRpcId\n\n switch (method) {\n case 'initialize': {\n const requested = typeof params.protocolVersion === 'string' ? params.protocolVersion : undefined\n const protocolVersion =\n requested !== undefined && (MCP_PROTOCOL_VERSIONS as readonly string[]).includes(requested)\n ? requested\n : LATEST_PROTOCOL_VERSION\n return rpcResult(id, {\n protocolVersion,\n capabilities: { tools: { listChanged: false } },\n serverInfo: opts.serverInfo,\n })\n }\n\n case 'ping':\n return rpcResult(id, {})\n\n case 'tools/list':\n return rpcResult(id, {\n tools: opts.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n })\n\n case 'tools/call': {\n const name = params.name\n if (typeof name !== 'string' || name.length === 0) {\n return rpcError(id, -32602, 'tools/call requires params.name (string)')\n }\n const tool = toolMap.get(name)\n if (!tool) {\n return rpcError(\n id,\n -32602,\n `Unknown tool: ${name}. Available tools: ${opts.tools.map((t) => t.name).join(', ')}`,\n )\n }\n if (params.arguments !== undefined && !isRecord(params.arguments)) {\n return rpcError(id, -32602, 'tools/call params.arguments must be an object when provided')\n }\n const args = isRecord(params.arguments) ? params.arguments : {}\n let env: TEnv\n try {\n env = await opts.buildEnv(request)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed to build env: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n try {\n const result = await tool.run(args, env)\n const payload: ToolCallContent = { content: [{ type: 'text', text: JSON.stringify(result) }] }\n return rpcResult(id, payload)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n }\n\n default:\n return rpcError(id, -32601, `Method not found: ${method}`)\n }\n }\n}\n"],"mappings":"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","names":[]}
|