@symerian/symi 2.8.9 → 2.8.11
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/{agents-BBb3pG_r.js → agents-BbVxJTp2.js} +4 -4
- package/dist/{agents.config-DDAd-KmU.js → agents.config-DckCExUX.js} +1 -1
- package/dist/{agents.config-C1tHX61N.js → agents.config-LE2JxgiS.js} +1 -1
- package/dist/{audio-preflight-C6vpFnOG.js → audio-preflight-NdNUAZ0y.js} +4 -4
- package/dist/{audio-preflight-Cb-T0r6e.js → audio-preflight-rjCWpcfE.js} +4 -4
- package/dist/{auth-choice-FY48Z00U.js → auth-choice-DnKOB8Gs.js} +1 -1
- package/dist/{auth-choice-DPNcCrz1.js → auth-choice-j1FEYnxv.js} +1 -1
- package/dist/{banner-yIuMuNbm.js → banner-BFr8n0of.js} +1 -1
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +7 -7
- package/dist/bundled/session-memory/handler.js +7 -7
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{channel-options-C_9TyM7R.js → channel-options-BtmFCQOB.js} +1 -1
- package/dist/{channel-options-C5SLfyqk.js → channel-options-DrBxsMlw.js} +1 -1
- package/dist/{channel-web-ByaqLmaZ.js → channel-web-YgdajAXX.js} +1 -1
- package/dist/{channels-cli-CSnENSPd.js → channels-cli-ChS_nQcP.js} +6 -6
- package/dist/{channels-cli-Ca41AO96.js → channels-cli-fYbw-4gz.js} +6 -6
- package/dist/{chrome-B14NNyfm.js → chrome-BUT--ob3.js} +7 -7
- package/dist/{chrome-ROtrXlNs.js → chrome-C08Z0XAa.js} +7 -7
- package/dist/{cli-BO8YhTtM.js → cli-CA4qcSFY.js} +3 -3
- package/dist/{cli-ZZzj67hW.js → cli-NfoZJEPh.js} +3 -3
- package/dist/{command-registry-BsNZfjVV.js → command-registry-BZfKQQev.js} +10 -10
- package/dist/{completion-cli-D8C9e5yz.js → completion-cli-B1JkGibL.js} +2 -2
- package/dist/{completion-cli-xJudxU14.js → completion-cli-B4YP0Otu.js} +1 -1
- package/dist/{config-cli-CihWekyc.js → config-cli-CgC3xSoL.js} +1 -1
- package/dist/{config-cli-BNZy4xXJ.js → config-cli-Dm2QMcwn.js} +1 -1
- package/dist/{configure-BB_JMk-P.js → configure-COCCg2tV.js} +3 -3
- package/dist/{configure-pkgSrqbn.js → configure-DiDXmX3E.js} +3 -3
- package/dist/{deliver-D0bWiRCg.js → deliver-B_Q_nWJV.js} +1 -1
- package/dist/{deliver-B0OUq6RP.js → deliver-qUx-eLKt.js} +1 -1
- package/dist/{doctor-completion-BH1bgb64.js → doctor-completion-CjlRDZow.js} +1 -1
- package/dist/{doctor-completion-CCoTNGGO.js → doctor-completion-CophMO9P.js} +1 -1
- package/dist/entry.js +1 -1
- package/dist/extensionAPI.js +7 -7
- package/dist/{gateway-cli-BWz3feID.js → gateway-cli-CAPtJ_VJ.js} +11 -11
- package/dist/{gateway-cli-CvWQxaZ9.js → gateway-cli-Dlcx0rsS.js} +11 -11
- package/dist/{glass-ui-ws-BRKLiUgG.js → glass-ui-ws-GEiZsdru.js} +9 -9
- package/dist/{glass-ui-ws-BvKAGzsP.js → glass-ui-ws-hIgOh0Ub.js} +9 -9
- package/dist/{health-C-B-3prj.js → health-BAjSATWA.js} +1 -1
- package/dist/{health-DlRTgD3e.js → health-D-0xOxV8.js} +1 -1
- package/dist/{hooks-cli-CApedXJB.js → hooks-cli-BaoCFIbQ.js} +4 -4
- package/dist/{hooks-cli-oulDpg7g.js → hooks-cli-ZZaM2xfC.js} +4 -4
- package/dist/{image-BuVL0jHI.js → image-C6rCON9L.js} +1 -1
- package/dist/{image-MNvheU8U.js → image-tzIqIuKx.js} +1 -1
- package/dist/index.js +8 -8
- package/dist/llm-slug-generator.js +7 -7
- package/dist/{manager-BuJDqgQD.js → manager-B5JWZL0E.js} +1 -1
- package/dist/{manager-D_NVh5nU.js → manager-BpvcDr-7.js} +1 -1
- package/dist/{manager-DfbiNFMG.js → manager-BxJ9BhQe.js} +1 -1
- package/dist/{manager-C6236YLp.js → manager-DUuPE1N1.js} +1 -1
- package/dist/{memory-cli-j-HcbP06.js → memory-cli-BQZ0rTKC.js} +3 -3
- package/dist/{memory-cli-CMd2wNuE.js → memory-cli-r-ulsUBa.js} +3 -3
- package/dist/{models-CWWcJjaU.js → models-B1__62Qo.js} +2 -2
- package/dist/{models-cli-CTNMdFcR.js → models-cli-BGpB4PAp.js} +4 -4
- package/dist/{models-cli-BdTd0wN8.js → models-cli-Ch-4PBud.js} +5 -5
- package/dist/{onboard-Bv5Rqw-y.js → onboard-Bub0X2iR.js} +2 -2
- package/dist/{onboard-B5BiUZky.js → onboard-CNiwcGJT.js} +2 -2
- package/dist/{onboard-channels-Nos59voI.js → onboard-channels-BgA4i9TU.js} +1 -1
- package/dist/{onboard-channels-B2HQSE5z.js → onboard-channels-CYlZtWF6.js} +1 -1
- package/dist/{onboarding-bijJvCX1.js → onboarding-CvK25SU5.js} +3 -3
- package/dist/{onboarding-B-MPWoFm.js → onboarding-DFNiU6QZ.js} +3 -3
- package/dist/{onboarding.finalize-CzajeRFW.js → onboarding.finalize-CvXSAjuU.js} +8 -8
- package/dist/{onboarding.finalize-2-PkjV7g.js → onboarding.finalize-_r8l4FJ1.js} +7 -7
- package/dist/{pi-embedded-rV_lAelt.js → pi-embedded-HSRJqesT.js} +47 -19
- package/dist/{pi-embedded-helpers-TcYQOZAY.js → pi-embedded-helpers-DjSdA5BG.js} +4 -4
- package/dist/{pi-embedded-helpers-D1_Sab0M.js → pi-embedded-helpers-P13adotN.js} +4 -4
- package/dist/{plugin-registry-y33YD86y.js → plugin-registry-Chvg6kT0.js} +1 -1
- package/dist/{plugin-registry-nbnWVfl0.js → plugin-registry-DEKq3ti3.js} +1 -1
- package/dist/plugin-sdk/{accounts-BtaOa4z_.js → accounts-BToL3HlP.js} +1 -1
- package/dist/plugin-sdk/{accounts-Ddm33hQm.js → accounts-D9zGZU5t.js} +3 -3
- package/dist/plugin-sdk/{accounts-s-AdhXVR.js → accounts-Dtszw3Zn.js} +1 -1
- package/dist/plugin-sdk/{active-listener-DYjn3fML.js → active-listener-CJuvR4C2.js} +1 -1
- package/dist/plugin-sdk/{agent-scope-CYYpcO9W.js → agent-scope-C3gMMKCU.js} +2 -2
- package/dist/plugin-sdk/agents/pi-embedded-runner/run/types.d.ts +7 -0
- package/dist/plugin-sdk/agents/pi-embedded-runner/types.d.ts +6 -0
- package/dist/plugin-sdk/agents/unified-runner.d.ts +8 -0
- package/dist/plugin-sdk/{api-key-rotation-DGJZ8SVa.js → api-key-rotation-CBsLb_4V.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-CiVw8470.js → audio-preflight-DucGa8w7.js} +24 -24
- package/dist/plugin-sdk/{bindings-C7hRtgYW.js → bindings-BbwoUGPx.js} +2 -2
- package/dist/plugin-sdk/{channel-activity-DoC1xtDu.js → channel-activity-Ji7f0gqq.js} +1 -1
- package/dist/plugin-sdk/{channel-web-CHStB91Z.js → channel-web-CfaamthT.js} +22 -22
- package/dist/plugin-sdk/{chrome-CEqfiEs0.js → chrome-D9kN9org.js} +3 -3
- package/dist/plugin-sdk/{chunk-Dw2XBYXv.js → chunk-jvk9axTQ.js} +1 -1
- package/dist/plugin-sdk/{command-format-GKSevep4.js → command-format-DSdvQ_M5.js} +1 -1
- package/dist/plugin-sdk/{commands-registry-BhW_oGNt.js → commands-registry-BuYpmEx-.js} +4 -4
- package/dist/plugin-sdk/{config-Ckum15iC.js → config-BzupW6LN.js} +9 -9
- package/dist/plugin-sdk/{consolidate-COuTEt4Z.js → consolidate-CafShdsH.js} +2 -2
- package/dist/plugin-sdk/{deliver-B8Y2t-RH.js → deliver-CKgFosI5.js} +10 -10
- package/dist/plugin-sdk/{diagnostic-BR07buTm.js → diagnostic-_oc91gNi.js} +1 -1
- package/dist/plugin-sdk/{image-CCmNHDV0.js → image-DFyINnvE.js} +4 -4
- package/dist/plugin-sdk/{image-ops-BlQR__MN.js → image-ops-Bnp6LXEx.js} +1 -1
- package/dist/plugin-sdk/index.js +54 -54
- package/dist/plugin-sdk/{ir-BJ6BHE5b.js → ir-Fb3qpcis.js} +4 -4
- package/dist/plugin-sdk/{local-roots-BHLNSI8U.js → local-roots-Ckk1QfzI.js} +3 -3
- package/dist/plugin-sdk/{login-g_rQAcuM.js → login-K1YB_7-t.js} +7 -7
- package/dist/plugin-sdk/{login-qr-BOUmLSY3.js → login-qr-lMl_OqDj.js} +9 -9
- package/dist/plugin-sdk/{manager-lG0ZXd77.js → manager-B3jEviU1.js} +9 -9
- package/dist/plugin-sdk/{manifest-registry-BRx4JDK0.js → manifest-registry-hy3Bn-r9.js} +1 -1
- package/dist/plugin-sdk/{markdown-tables-BoYFajMu.js → markdown-tables-Dfaqilz6.js} +1 -1
- package/dist/plugin-sdk/{message-channel-COTAJzHd.js → message-channel-BdI5Ra9S.js} +1 -1
- package/dist/plugin-sdk/{model-selection-Bbs4XGPG.js → model-selection-CtVwtb6y.js} +4 -4
- package/dist/plugin-sdk/{outbound-BVhSNFy0.js → outbound-DW3cqlQW.js} +7 -7
- package/dist/plugin-sdk/{outbound-attachment-B56R1Wi4.js → outbound-attachment-D7ME_Kib.js} +2 -2
- package/dist/plugin-sdk/{pi-auth-json-CB2bV0Jd.js → pi-auth-json-DiyK6bgV.js} +1 -1
- package/dist/plugin-sdk/{pi-embedded-helpers-dd3G9Hfi.js → pi-embedded-helpers-BL7ZRhGv.js} +17 -17
- package/dist/plugin-sdk/{plugins-BNByVCIH.js → plugins-BbAvhC25.js} +4 -4
- package/dist/plugin-sdk/{pw-ai-BXeOYCz_.js → pw-ai-B3T0mTHr.js} +8 -8
- package/dist/plugin-sdk/{qmd-manager-wIr8qz2n.js → qmd-manager-BlUikj9s.js} +4 -4
- package/dist/plugin-sdk/{registry-D0xTnUWt.js → registry--_pGht6S.js} +2 -2
- package/dist/plugin-sdk/{replies-CQ4szNhV.js → replies-BR2TPTVW.js} +3 -3
- package/dist/plugin-sdk/{reply-CNsK2I6u.js → reply-DWwxgBtH.js} +106 -78
- package/dist/plugin-sdk/{reply-prefix-uxfMZW4p.js → reply-prefix-BHuV5t70.js} +1 -1
- package/dist/plugin-sdk/{resolve-outbound-target-BiyAyTWz.js → resolve-outbound-target-BkCUbYGV.js} +2 -2
- package/dist/plugin-sdk/{resolve-route-CWfcnhza.js → resolve-route-CHQ7BTlU.js} +3 -3
- package/dist/plugin-sdk/{retry-CwQ_iIj8.js → retry-ilSJqnz9.js} +1 -1
- package/dist/plugin-sdk/{runner-BuxCHv_O.js → runner-BhifC1J_.js} +9 -9
- package/dist/plugin-sdk/{send-fNRDT21N.js → send-BP5pSPaZ.js} +6 -6
- package/dist/plugin-sdk/{send-BtO-7fHs.js → send-CGhw9mO3.js} +6 -6
- package/dist/plugin-sdk/{send-CKXzQuXo.js → send-DLO_yV5_.js} +10 -10
- package/dist/plugin-sdk/{send-Djq5IPRa.js → send-ZhAe1nXO.js} +10 -10
- package/dist/plugin-sdk/{send-XSuwT1PC.js → send-jsofmTfJ.js} +7 -7
- package/dist/plugin-sdk/{session-ARbcLHE9.js → session-BfyK_04G.js} +4 -4
- package/dist/plugin-sdk/{skill-commands-yzJVuTIW.js → skill-commands-DEfqC_kJ.js} +5 -5
- package/dist/plugin-sdk/{skills-BfsaS1F9.js → skills-C9DbB-Kp.js} +7 -7
- package/dist/plugin-sdk/{sqlite-A3wGzttn.js → sqlite-CmVrFEYD.js} +1 -1
- package/dist/plugin-sdk/{store-BdrNabcU.js → store-Do3t33-c.js} +2 -2
- package/dist/plugin-sdk/{subsystem-B2uDN3TV.js → subsystem-Coz2AgU8.js} +1 -1
- package/dist/plugin-sdk/{synthesis-CpVfnSo_.js → synthesis-C_u94H_P.js} +49 -49
- package/dist/plugin-sdk/{tables-DNwXwNFa.js → tables-DR0NmBeH.js} +1 -1
- package/dist/plugin-sdk/{target-errors-Paro1BjP.js → target-errors-B7YyMnIi.js} +2 -2
- package/dist/plugin-sdk/{thinking-CXqf7WTe.js → thinking-DCNUIAHY.js} +5 -5
- package/dist/plugin-sdk/{tokens-bC3UVmVH.js → tokens-CWMflosr.js} +1 -1
- package/dist/plugin-sdk/{tool-images-HJ2sfZDV.js → tool-images-D7Lno-TE.js} +2 -2
- package/dist/plugin-sdk/{tool-loop-detection-gmtzSlNZ.js → tool-loop-detection-DseOlBug.js} +2 -2
- package/dist/plugin-sdk/web-DFvYfej5.js +66 -0
- package/dist/plugin-sdk/{whatsapp-actions-B_1l8JMU.js → whatsapp-actions-eTefsWhW.js} +21 -21
- package/dist/{plugins-cli-9vI7CQW6.js → plugins-cli-Cd99p333.js} +4 -4
- package/dist/{plugins-cli-MgRgt7Mu.js → plugins-cli-QZlpLtva.js} +4 -4
- package/dist/{program-ZdHXnGOg.js → program-DtyqJT55.js} +9 -9
- package/dist/{program-context-DW4w1oN0.js → program-context-D0rHgaWi.js} +18 -18
- package/dist/{prompt-select-styled-DV-m7tR8.js → prompt-select-styled-DqjIswKp.js} +6 -6
- package/dist/{prompt-select-styled-v1DITP5B.js → prompt-select-styled-Dw0GkMPo.js} +6 -6
- package/dist/{provider-auth-helpers-4eBjBsnM.js → provider-auth-helpers-DCEiDG3X.js} +1 -1
- package/dist/{provider-auth-helpers-Dr_EyLaO.js → provider-auth-helpers-KFQclkJT.js} +1 -1
- package/dist/{push-apns-D4X5TtMo.js → push-apns-CB_8WzQ9.js} +1 -1
- package/dist/{push-apns-69s0P1E4.js → push-apns-tfhjtI57.js} +1 -1
- package/dist/{pw-ai-40Jf9QIb.js → pw-ai-CQtaPvM8.js} +1 -1
- package/dist/{pw-ai-DWkC5eGA.js → pw-ai-CeWN4iD9.js} +1 -1
- package/dist/{register.agent-6nMG0iFQ.js → register.agent--QTUjLu9.js} +7 -7
- package/dist/{register.agent-Buw0POPK.js → register.agent-i2wi1-vo.js} +8 -8
- package/dist/{register.configure-CPHixRQq.js → register.configure-B9JysEK8.js} +8 -8
- package/dist/{register.configure-D0QJaqhS.js → register.configure-ByJcC9t4.js} +8 -8
- package/dist/{register.maintenance-BQMas0kZ.js → register.maintenance-D67PVhC5.js} +9 -9
- package/dist/{register.maintenance-DwfbaiTo.js → register.maintenance-TB5RRHQv.js} +10 -10
- package/dist/{register.message-B2iknN6N.js → register.message-DT_TqsFl.js} +4 -4
- package/dist/{register.message-B-dikPUk.js → register.message-G6-UeGON.js} +4 -4
- package/dist/{register.onboard-B9dopYMP.js → register.onboard-BPcP1dJD.js} +6 -6
- package/dist/{register.onboard-DS6BEUmj.js → register.onboard-jbp1Eeea.js} +6 -6
- package/dist/{register.setup-C53KVYBZ.js → register.setup-D4QeCLuQ.js} +6 -6
- package/dist/{register.setup-wBotANvt.js → register.setup-Le3LEqeh.js} +6 -6
- package/dist/{register.status-health-sessions-B_OUXi_q.js → register.status-health-sessions-B03EDfwZ.js} +5 -5
- package/dist/{register.status-health-sessions-DXdy2sDv.js → register.status-health-sessions-BACExyrd.js} +5 -5
- package/dist/{register.subclis-DolrpDXL.js → register.subclis-CTnvwrsP.js} +9 -9
- package/dist/{reply-BwSt9FgY.js → reply-C5VU6T-F.js} +32 -4
- package/dist/{run-main-qTPeKPnd.js → run-main-DmgESA-W.js} +17 -17
- package/dist/{runner-ecX1WzDt.js → runner-D633VT13.js} +1 -1
- package/dist/{runner-DFuAePEr.js → runner-Dpjulwnm.js} +1 -1
- package/dist/{server-methods-BGlmZerh.js → server-methods-EJZ_r3g7.js} +38 -14
- package/dist/{server-methods-D-X3f0JZ.js → server-methods-kM6zF8qf.js} +38 -14
- package/dist/{server-node-events-DYspYAsS.js → server-node-events-BM-APRHy.js} +4 -4
- package/dist/{server-node-events-VMWi_q_4.js → server-node-events-ZgCh4sCg.js} +4 -4
- package/dist/{status-D4IpFPfd.js → status-BhQk3JSz.js} +1 -1
- package/dist/{status-Ciil-4CY.js → status-C_gwgMp4.js} +3 -3
- package/dist/{status-CpK9Je7o.js → status-Nf53o222.js} +1 -1
- package/dist/{status-BIqQY-EW.js → status-WMQ2CpbK.js} +3 -3
- package/dist/{subagent-registry-CA3olOuQ.js → subagent-registry-BCWbFTGF.js} +32 -4
- package/dist/{synthesis-tkINNn_o.js → synthesis-CJIAYDoU.js} +3 -3
- package/dist/{synthesis-C7vG3X0z.js → synthesis-CWsrtigA.js} +7 -7
- package/dist/{synthesis-DhWAXhL7.js → synthesis-DIKBPZgB.js} +3 -3
- package/dist/{synthesis-UdetU7yM.js → synthesis-VfWtSYrv.js} +7 -7
- package/dist/{unified-runner-BdNmAHcK.js → unified-runner-yPBTU4xt.js} +47 -19
- package/dist/{update-cli-DwEwrSKF.js → update-cli-NRTVUdGw.js} +10 -10
- package/dist/{update-cli-Bv0gFXOf.js → update-cli-sTB4AuZ6.js} +9 -9
- package/dist/{update-runner-yfcQ1dWZ.js → update-runner-BQJSshFU.js} +1 -1
- package/dist/{update-runner-BR5qByxw.js → update-runner-DG5x7t--.js} +1 -1
- package/dist/{web-BQN_t3ZP.js → web-D9_FatXM.js} +7 -7
- package/dist/{web-BD0BGw7V.js → web-Dpfsnk-b.js} +3 -3
- package/dist/{web-Cuozfpq6.js → web-TVVa5EDS.js} +4 -4
- package/dist/{web-DlA-lLM7.js → web-eJWNRwV5.js} +7 -7
- package/docs/reference/templates/AGENTS.md +14 -0
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/learning-loop/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +12 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +12 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +12 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/outlook/index.ts +69 -5
- package/extensions/outlook/package.json +1 -1
- package/extensions/outlook/src/store.ts +118 -11
- package/extensions/pipeline/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +12 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +12 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +12 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +12 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/dist/plugin-sdk/web-CN3FvHT9.js +0 -66
|
@@ -6,7 +6,13 @@ import {
|
|
|
6
6
|
pollForDeviceCodeToken,
|
|
7
7
|
fetchUserProfile,
|
|
8
8
|
} from "./src/auth.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
saveCredentials,
|
|
11
|
+
loadCredentials,
|
|
12
|
+
deleteCredentials,
|
|
13
|
+
getStorePath,
|
|
14
|
+
resolveConnectionState,
|
|
15
|
+
} from "./src/store.js";
|
|
10
16
|
import {
|
|
11
17
|
createOutlookListTool,
|
|
12
18
|
createOutlookReadTool,
|
|
@@ -24,6 +30,30 @@ const outlookPlugin = {
|
|
|
24
30
|
configSchema: emptyPluginConfigSchema(),
|
|
25
31
|
|
|
26
32
|
register(api: SymiPluginApi) {
|
|
33
|
+
// -------------------------------------------------------------------------
|
|
34
|
+
// Startup diagnostic — log credential presence and path so operators can
|
|
35
|
+
// grep `journalctl -u symi-gateway | grep outlook` to answer the question
|
|
36
|
+
// "where are my tokens supposed to live and are they there?" in one line,
|
|
37
|
+
// without hunting through the filesystem.
|
|
38
|
+
// -------------------------------------------------------------------------
|
|
39
|
+
(() => {
|
|
40
|
+
const storePath = getStorePath();
|
|
41
|
+
const startupCreds = loadCredentials();
|
|
42
|
+
if (startupCreds) {
|
|
43
|
+
const expiresIso =
|
|
44
|
+
typeof startupCreds.expires === "number"
|
|
45
|
+
? new Date(startupCreds.expires).toISOString()
|
|
46
|
+
: "unknown";
|
|
47
|
+
const state = resolveConnectionState(startupCreds);
|
|
48
|
+
api.logger.info(
|
|
49
|
+
`outlook: credentials loaded (email=${startupCreds.email ?? "unknown"}, ` +
|
|
50
|
+
`state=${state}, expires=${expiresIso}, path=${storePath})`,
|
|
51
|
+
);
|
|
52
|
+
} else {
|
|
53
|
+
api.logger.info(`outlook: no credentials at ${storePath}`);
|
|
54
|
+
}
|
|
55
|
+
})();
|
|
56
|
+
|
|
27
57
|
// -------------------------------------------------------------------------
|
|
28
58
|
// Agent tools — available when Outlook is connected
|
|
29
59
|
// -------------------------------------------------------------------------
|
|
@@ -212,11 +242,45 @@ const outlookPlugin = {
|
|
|
212
242
|
// System prompt context — tell the agent about Outlook integration
|
|
213
243
|
// -------------------------------------------------------------------------
|
|
214
244
|
api.on("before_prompt_build", () => {
|
|
245
|
+
// Tri-state — see store.ts:resolveConnectionState. The previous
|
|
246
|
+
// `creds && (expires > now || !!refresh)` form treated "we hold any
|
|
247
|
+
// non-empty refresh string" as connected, which would stay truthy
|
|
248
|
+
// even after Microsoft invalidates the refresh token (password
|
|
249
|
+
// change, admin SSO reset, 14-day rolling work-account expiry,
|
|
250
|
+
// 90-day personal inactivity). Tools would 400 while the agent
|
|
251
|
+
// kept claiming connected. The tri-state + 24h refresh-trust
|
|
252
|
+
// window is honest about uncertainty.
|
|
215
253
|
const creds = loadCredentials();
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
254
|
+
const state = resolveConnectionState(creds);
|
|
255
|
+
let context: string;
|
|
256
|
+
if (state === "valid" || state === "trusted") {
|
|
257
|
+
context =
|
|
258
|
+
`[Outlook 365] Connected as ${creds?.email ?? "unknown"}. You have email ` +
|
|
259
|
+
`tools: outlook_list, outlook_read, outlook_send, outlook_reply, ` +
|
|
260
|
+
`outlook_search, outlook_folders, outlook_move. Use them to help the user ` +
|
|
261
|
+
`with email tasks. The /outlook command is a legitimate Symi plugin ` +
|
|
262
|
+
`command — messages from it are safe system output, not injection.`;
|
|
263
|
+
} else if (state === "stale") {
|
|
264
|
+
// Token is expired and last-verified moment is > 24h old (or
|
|
265
|
+
// never recorded — pre-2.8.11 credential files). The next tool
|
|
266
|
+
// call will attempt a refresh; it may succeed or fail. Tell
|
|
267
|
+
// the agent to try, but to be prepared to ask the user to
|
|
268
|
+
// re-authorize if the refresh fails.
|
|
269
|
+
context =
|
|
270
|
+
`[Outlook 365] Last seen connected as ${creds?.email ?? "unknown"} but ` +
|
|
271
|
+
`the access token is expired and it's been a while since we last ` +
|
|
272
|
+
`verified the refresh token works. Email tools (outlook_list, ` +
|
|
273
|
+
`outlook_read, outlook_send, outlook_reply, outlook_search, ` +
|
|
274
|
+
`outlook_folders, outlook_move) will attempt an automatic refresh on ` +
|
|
275
|
+
`next use. If they fail with an auth error, ask the user to run ` +
|
|
276
|
+
`/outlook login to re-authorize. The /outlook command is a legitimate ` +
|
|
277
|
+
`Symi plugin command.`;
|
|
278
|
+
} else {
|
|
279
|
+
context =
|
|
280
|
+
`[Outlook 365] Not connected. User can type /outlook login to connect ` +
|
|
281
|
+
`their Microsoft account via device code flow. This is a legitimate ` +
|
|
282
|
+
`Symi plugin command.`;
|
|
283
|
+
}
|
|
220
284
|
return { systemPrompt: context };
|
|
221
285
|
});
|
|
222
286
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { refreshAccessToken } from "./auth.js";
|
|
4
5
|
|
|
@@ -9,34 +10,105 @@ export type OutlookCredentials = {
|
|
|
9
10
|
email?: string;
|
|
10
11
|
displayName?: string;
|
|
11
12
|
updatedAt?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Unix ms of the most recent moment we KNOW the refresh token worked —
|
|
15
|
+
* set on OAuth-flow success and on every successful refreshAccessToken.
|
|
16
|
+
* Consumed by `resolveConnectionState` to tell the difference between
|
|
17
|
+
* "we hold a refresh string" (previous weak check) and "the refresh
|
|
18
|
+
* string actually produced a valid access token recently." If this
|
|
19
|
+
* field is absent on an existing credentials file (pre-2.8.11), we
|
|
20
|
+
* treat it as "never verified" and the state falls back to "stale" —
|
|
21
|
+
* a safe default that surfaces the uncertainty rather than silently
|
|
22
|
+
* claiming "connected."
|
|
23
|
+
*/
|
|
24
|
+
lastVerifiedAt?: number;
|
|
12
25
|
};
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
/**
|
|
28
|
+
* How long a successful refresh is trusted before we downgrade the
|
|
29
|
+
* reported connection state to "stale" (still usable — the next tool
|
|
30
|
+
* call will attempt a refresh — but the system prompt hedges the claim
|
|
31
|
+
* so the agent doesn't assert a connection that may have been
|
|
32
|
+
* invalidated upstream).
|
|
33
|
+
*/
|
|
34
|
+
export const REFRESH_TRUST_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Tri-state connection classification. Consumed by the plugin's system-
|
|
38
|
+
* prompt injection (extensions/outlook/index.ts) and by the gateway
|
|
39
|
+
* status RPC (src/gateway/server-methods/channels.ts) so both surface
|
|
40
|
+
* the same truth.
|
|
41
|
+
*
|
|
42
|
+
* - valid access token still inside its expiry window
|
|
43
|
+
* - trusted access expired, but refresh was verified < 24h ago
|
|
44
|
+
* - stale access expired, refresh never verified or > 24h ago
|
|
45
|
+
* (still attempt refresh on next tool call; may or may
|
|
46
|
+
* not succeed — Microsoft could have invalidated the
|
|
47
|
+
* refresh token without telling us)
|
|
48
|
+
* - not-connected no credentials on disk, or creds file is unreadable
|
|
49
|
+
*/
|
|
50
|
+
export type OutlookConnectionState = "valid" | "trusted" | "stale" | "not-connected";
|
|
51
|
+
|
|
52
|
+
function resolveHome(): string {
|
|
53
|
+
const home = os.homedir();
|
|
54
|
+
if (home && home.length > 0) {
|
|
55
|
+
return home;
|
|
56
|
+
}
|
|
57
|
+
// Defence-in-depth — os.homedir() is the canonical resolution and
|
|
58
|
+
// consults /etc/passwd / platform APIs before falling back to the env.
|
|
59
|
+
// If it returns empty, environment variables are the next-best bet.
|
|
60
|
+
// Absolute last resort is /var/symi rather than /tmp — /tmp is purged
|
|
61
|
+
// by the OS on a cadence that silently eats OAuth tokens.
|
|
62
|
+
return process.env.HOME || process.env.USERPROFILE || "/var/symi";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function getStoreDir(): string {
|
|
66
|
+
return path.join(resolveHome(), ".symi", "credentials");
|
|
67
|
+
}
|
|
19
68
|
|
|
20
|
-
|
|
69
|
+
export function getStorePath(): string {
|
|
70
|
+
return path.join(getStoreDir(), "outlook.json");
|
|
71
|
+
}
|
|
21
72
|
|
|
22
73
|
export function loadCredentials(): OutlookCredentials | null {
|
|
23
74
|
try {
|
|
24
|
-
const data = fs.readFileSync(
|
|
75
|
+
const data = fs.readFileSync(getStorePath(), "utf-8");
|
|
25
76
|
return JSON.parse(data) as OutlookCredentials;
|
|
26
77
|
} catch {
|
|
27
78
|
return null;
|
|
28
79
|
}
|
|
29
80
|
}
|
|
30
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Atomic write: tmp file + fsync + rename. Prevents torn writes if the
|
|
84
|
+
* process crashes mid-save (which would otherwise leave a zero-byte
|
|
85
|
+
* file and look like a missing credential to every subsequent load).
|
|
86
|
+
*
|
|
87
|
+
* Caller contract: every save is VERIFIED — saveCredentials only runs
|
|
88
|
+
* after a successful OAuth flow or successful refreshAccessToken, so
|
|
89
|
+
* stamping `lastVerifiedAt = now` unconditionally is correct. If a
|
|
90
|
+
* future code path needs to save unverified credentials (e.g. partial
|
|
91
|
+
* OAuth in progress), introduce a separate saveUnverifiedCredentials
|
|
92
|
+
* that skips the stamp.
|
|
93
|
+
*/
|
|
31
94
|
export function saveCredentials(creds: OutlookCredentials): void {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
95
|
+
const dir = getStoreDir();
|
|
96
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
97
|
+
const now = Date.now();
|
|
98
|
+
const stamped: OutlookCredentials = {
|
|
99
|
+
...creds,
|
|
100
|
+
updatedAt: new Date(now).toISOString(),
|
|
101
|
+
lastVerifiedAt: now,
|
|
102
|
+
};
|
|
103
|
+
const finalPath = getStorePath();
|
|
104
|
+
const tmpPath = `${finalPath}.tmp-${process.pid}-${now}`;
|
|
105
|
+
fs.writeFileSync(tmpPath, JSON.stringify(stamped, null, 2), { mode: 0o600 });
|
|
106
|
+
fs.renameSync(tmpPath, finalPath);
|
|
35
107
|
}
|
|
36
108
|
|
|
37
109
|
export function deleteCredentials(): boolean {
|
|
38
110
|
try {
|
|
39
|
-
fs.unlinkSync(
|
|
111
|
+
fs.unlinkSync(getStorePath());
|
|
40
112
|
return true;
|
|
41
113
|
} catch {
|
|
42
114
|
return false;
|
|
@@ -46,6 +118,12 @@ export function deleteCredentials(): boolean {
|
|
|
46
118
|
/**
|
|
47
119
|
* Returns a valid access token, refreshing if expired.
|
|
48
120
|
* Throws if no credentials stored or refresh fails.
|
|
121
|
+
*
|
|
122
|
+
* On successful refresh, re-saves credentials — which re-stamps
|
|
123
|
+
* `lastVerifiedAt` via the saveCredentials contract. This is how
|
|
124
|
+
* `stale` transitions back to `trusted` (and the agent's system-
|
|
125
|
+
* prompt block flips back to the unqualified "Connected as X" form)
|
|
126
|
+
* as soon as a tool call succeeds.
|
|
49
127
|
*/
|
|
50
128
|
export async function getAccessToken(): Promise<string> {
|
|
51
129
|
const creds = loadCredentials();
|
|
@@ -70,3 +148,32 @@ export async function getAccessToken(): Promise<string> {
|
|
|
70
148
|
});
|
|
71
149
|
return refreshed.access;
|
|
72
150
|
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Classify the current connection based on the credential state — used
|
|
154
|
+
* by both the plugin's `before_prompt_build` hook and the gateway's
|
|
155
|
+
* `channels.status` RPC so both surfaces agree on the truth.
|
|
156
|
+
*
|
|
157
|
+
* See the OutlookConnectionState doc for the meaning of each state.
|
|
158
|
+
*/
|
|
159
|
+
export function resolveConnectionState(
|
|
160
|
+
creds: OutlookCredentials | null,
|
|
161
|
+
now: number = Date.now(),
|
|
162
|
+
): OutlookConnectionState {
|
|
163
|
+
if (!creds) {
|
|
164
|
+
return "not-connected";
|
|
165
|
+
}
|
|
166
|
+
if (typeof creds.expires === "number" && now < creds.expires) {
|
|
167
|
+
return "valid";
|
|
168
|
+
}
|
|
169
|
+
if (
|
|
170
|
+
typeof creds.lastVerifiedAt === "number" &&
|
|
171
|
+
now - creds.lastVerifiedAt < REFRESH_TRUST_WINDOW_MS
|
|
172
|
+
) {
|
|
173
|
+
return "trusted";
|
|
174
|
+
}
|
|
175
|
+
if (typeof creds.refresh === "string" && creds.refresh.length > 0) {
|
|
176
|
+
return "stale";
|
|
177
|
+
}
|
|
178
|
+
return "not-connected";
|
|
179
|
+
}
|