agor-live 0.12.2 → 0.12.3
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/core/api/index.d.cts +4 -4
- package/dist/core/api/index.d.ts +4 -4
- package/dist/core/{board-DCNkcsyf.d.cts → board-ByCag4EG.d.cts} +8 -1
- package/dist/core/{board-C-PU8jok.d.ts → board-CZuyMRpr.d.ts} +8 -1
- package/dist/core/claude/index.cjs +46 -5
- package/dist/core/claude/index.js +51 -21
- package/dist/core/{client-CGO13BG6.d.ts → client-BoLj-jqT.d.ts} +30 -5
- package/dist/core/{client-DKbFqX_X.d.cts → client-gnSCmSyL.d.cts} +30 -5
- package/dist/core/config/browser.d.cts +1 -1
- package/dist/core/config/browser.d.ts +1 -1
- package/dist/core/config/index.cjs +60 -4
- package/dist/core/config/index.d.cts +6 -5
- package/dist/core/config/index.d.ts +6 -5
- package/dist/core/config/index.js +64 -20
- package/dist/core/{config-manager-DGBdhxtZ.d.ts → config-manager-BLDGbZHT.d.ts} +16 -2
- package/dist/core/{config-manager-sCgziLkz.d.cts → config-manager-CsBk-Rh2.d.cts} +16 -2
- package/dist/core/db/index.cjs +332 -60
- package/dist/core/db/index.d.cts +33 -7
- package/dist/core/db/index.d.ts +33 -7
- package/dist/core/db/index.js +338 -77
- package/dist/core/drizzle/postgres/meta/_journal.json +1 -1
- package/dist/core/drizzle/sqlite/meta/_journal.json +1 -1
- package/dist/core/{feathers-B0zjReEk.d.ts → feathers-CYMJeMWB.d.ts} +1 -1
- package/dist/core/{feathers-C1uChqXy.d.cts → feathers-Cyk1lpAM.d.cts} +1 -1
- package/dist/core/gateway/index.cjs +137 -12
- package/dist/core/gateway/index.d.cts +22 -6
- package/dist/core/gateway/index.d.ts +22 -6
- package/dist/core/gateway/index.js +137 -12
- package/dist/core/{gateway-Dy9fVyiS.d.ts → gateway-B4CaePYV.d.ts} +2 -2
- package/dist/core/{gateway-DGNtjRnd.d.cts → gateway-C2NOdrxu.d.cts} +2 -2
- package/dist/core/git/index.d.cts +2 -2
- package/dist/core/git/index.d.ts +2 -2
- package/dist/core/index.cjs +226 -48
- package/dist/core/index.d.cts +8 -8
- package/dist/core/index.d.ts +8 -8
- package/dist/core/index.js +230 -64
- package/dist/core/mcp/index.cjs +24 -2
- package/dist/core/mcp/index.js +26 -4
- package/dist/core/seed/index.cjs +83 -13
- package/dist/core/seed/index.js +88 -29
- package/dist/core/{session-Bt9i9089.d.cts → session-BJbTzw3y.d.cts} +17 -1
- package/dist/core/{session-Da9rf6n5.d.ts → session-DLVkt-jY.d.ts} +17 -1
- package/dist/core/templates/session-context.d.cts +1 -1
- package/dist/core/templates/session-context.d.ts +1 -1
- package/dist/core/types/index.d.cts +6 -6
- package/dist/core/types/index.d.ts +6 -6
- package/dist/core/{types-D_wAaaE3.d.cts → types-Ddri21rw.d.cts} +18 -0
- package/dist/core/{types-D_wAaaE3.d.ts → types-Ddri21rw.d.ts} +18 -0
- package/dist/core/unix/index.cjs +63 -6
- package/dist/core/unix/index.d.cts +4 -3
- package/dist/core/unix/index.d.ts +4 -3
- package/dist/core/unix/index.js +68 -22
- package/dist/core/{user-DT1Qzfep.d.ts → user-B77oCF14.d.ts} +1 -1
- package/dist/core/{user-C5id0Zhj.d.cts → user-LBRon9n1.d.cts} +1 -1
- package/dist/core/utils/permission-mode-mapper.d.cts +1 -1
- package/dist/core/utils/permission-mode-mapper.d.ts +1 -1
- package/dist/core/utils/url.cjs +22 -0
- package/dist/core/utils/url.d.cts +45 -1
- package/dist/core/utils/url.d.ts +45 -1
- package/dist/core/utils/url.js +18 -0
- package/dist/daemon/index.js +168 -38
- package/dist/daemon/mcp/routes.js +5 -5
- package/dist/daemon/services/gateway.d.ts +9 -0
- package/dist/daemon/services/gateway.js +73 -6
- package/dist/daemon/services/repos.js +1 -0
- package/dist/daemon/services/thread-session-map.d.ts +6 -0
- package/dist/daemon/services/thread-session-map.js +9 -0
- package/dist/executor/cli.d.ts +0 -0
- package/dist/executor/cli.d.ts.map +0 -0
- package/dist/executor/cli.js +0 -0
- package/dist/executor/commands/git.d.ts +0 -0
- package/dist/executor/commands/git.d.ts.map +1 -1
- package/dist/executor/commands/git.js +3 -2
- package/dist/executor/commands/index.d.ts +0 -0
- package/dist/executor/commands/index.d.ts.map +0 -0
- package/dist/executor/commands/index.js +0 -0
- package/dist/executor/commands/unix.d.ts +0 -0
- package/dist/executor/commands/unix.d.ts.map +0 -0
- package/dist/executor/commands/unix.js +0 -0
- package/dist/executor/commands/zellij.d.ts +0 -0
- package/dist/executor/commands/zellij.d.ts.map +0 -0
- package/dist/executor/commands/zellij.js +0 -0
- package/dist/executor/config.d.ts +0 -0
- package/dist/executor/config.d.ts.map +0 -0
- package/dist/executor/config.js +0 -0
- package/dist/executor/db/feathers-repositories.d.ts +0 -0
- package/dist/executor/db/feathers-repositories.d.ts.map +0 -0
- package/dist/executor/db/feathers-repositories.js +0 -0
- package/dist/executor/handlers/sdk/base-executor.d.ts +0 -0
- package/dist/executor/handlers/sdk/base-executor.d.ts.map +0 -0
- package/dist/executor/handlers/sdk/base-executor.js +0 -0
- package/dist/executor/handlers/sdk/claude.d.ts +0 -0
- package/dist/executor/handlers/sdk/claude.d.ts.map +0 -0
- package/dist/executor/handlers/sdk/claude.js +0 -0
- package/dist/executor/handlers/sdk/codex.d.ts +0 -0
- package/dist/executor/handlers/sdk/codex.d.ts.map +0 -0
- package/dist/executor/handlers/sdk/codex.js +0 -0
- package/dist/executor/handlers/sdk/gemini.d.ts +0 -0
- package/dist/executor/handlers/sdk/gemini.d.ts.map +0 -0
- package/dist/executor/handlers/sdk/gemini.js +0 -0
- package/dist/executor/handlers/sdk/opencode.d.ts +0 -0
- package/dist/executor/handlers/sdk/opencode.d.ts.map +0 -0
- package/dist/executor/handlers/sdk/opencode.js +0 -0
- package/dist/executor/handlers/sdk/tool-registry.d.ts +0 -0
- package/dist/executor/handlers/sdk/tool-registry.d.ts.map +0 -0
- package/dist/executor/handlers/sdk/tool-registry.js +0 -0
- package/dist/executor/index.d.ts +0 -0
- package/dist/executor/index.d.ts.map +0 -0
- package/dist/executor/index.js +0 -0
- package/dist/executor/payload-types.d.ts +8 -0
- package/dist/executor/payload-types.d.ts.map +1 -1
- package/dist/executor/payload-types.js +2 -0
- package/dist/executor/permissions/permission-manager.d.ts +0 -0
- package/dist/executor/permissions/permission-manager.d.ts.map +0 -0
- package/dist/executor/permissions/permission-manager.js +0 -0
- package/dist/executor/permissions/permission-service.d.ts +0 -0
- package/dist/executor/permissions/permission-service.d.ts.map +0 -0
- package/dist/executor/permissions/permission-service.js +0 -0
- package/dist/executor/sdk-handlers/base/index.d.ts +0 -0
- package/dist/executor/sdk-handlers/base/index.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/base/index.js +0 -0
- package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts +0 -0
- package/dist/executor/sdk-handlers/base/mcp-scoping.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/base/mcp-scoping.js +0 -0
- package/dist/executor/sdk-handlers/base/normalizer.interface.d.ts +0 -0
- package/dist/executor/sdk-handlers/base/normalizer.interface.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/base/normalizer.interface.js +0 -0
- package/dist/executor/sdk-handlers/base/tool.interface.d.ts +0 -0
- package/dist/executor/sdk-handlers/base/tool.interface.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/base/tool.interface.js +0 -0
- package/dist/executor/sdk-handlers/base/types.d.ts +0 -0
- package/dist/executor/sdk-handlers/base/types.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/base/types.js +0 -0
- package/dist/executor/sdk-handlers/claude/claude-tool.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/claude-tool.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/claude-tool.js +0 -0
- package/dist/executor/sdk-handlers/claude/import/load-session.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/import/load-session.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/import/load-session.js +0 -0
- package/dist/executor/sdk-handlers/claude/import/message-converter.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/import/message-converter.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/import/message-converter.js +0 -0
- package/dist/executor/sdk-handlers/claude/import/task-extractor.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/import/task-extractor.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/import/task-extractor.js +0 -0
- package/dist/executor/sdk-handlers/claude/import/transcript-parser.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/import/transcript-parser.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/import/transcript-parser.js +0 -0
- package/dist/executor/sdk-handlers/claude/index.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/index.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/index.js +0 -0
- package/dist/executor/sdk-handlers/claude/message-builder.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/message-builder.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/message-builder.js +0 -0
- package/dist/executor/sdk-handlers/claude/message-processor.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/message-processor.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/message-processor.js +0 -0
- package/dist/executor/sdk-handlers/claude/models.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/models.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/models.js +0 -0
- package/dist/executor/sdk-handlers/claude/normalizer.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/normalizer.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/normalizer.js +0 -0
- package/dist/executor/sdk-handlers/claude/permissions/permission-hooks.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/permissions/permission-hooks.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/permissions/permission-hooks.js +0 -0
- package/dist/executor/sdk-handlers/claude/prompt-service.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/prompt-service.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/prompt-service.js +0 -0
- package/dist/executor/sdk-handlers/claude/query-builder.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/query-builder.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/query-builder.js +0 -0
- package/dist/executor/sdk-handlers/claude/safe-message-service.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/safe-message-service.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/safe-message-service.js +0 -0
- package/dist/executor/sdk-handlers/claude/session-context.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/session-context.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/session-context.js +0 -0
- package/dist/executor/sdk-handlers/claude/thinking-detector.d.ts +0 -0
- package/dist/executor/sdk-handlers/claude/thinking-detector.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/claude/thinking-detector.js +0 -0
- package/dist/executor/sdk-handlers/codex/codex-tool.d.ts +0 -0
- package/dist/executor/sdk-handlers/codex/codex-tool.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/codex/codex-tool.js +0 -0
- package/dist/executor/sdk-handlers/codex/index.d.ts +0 -0
- package/dist/executor/sdk-handlers/codex/index.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/codex/index.js +0 -0
- package/dist/executor/sdk-handlers/codex/models.d.ts +0 -0
- package/dist/executor/sdk-handlers/codex/models.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/codex/models.js +0 -0
- package/dist/executor/sdk-handlers/codex/normalizer.d.ts +0 -0
- package/dist/executor/sdk-handlers/codex/normalizer.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/codex/normalizer.js +0 -0
- package/dist/executor/sdk-handlers/codex/prompt-service.d.ts +0 -0
- package/dist/executor/sdk-handlers/codex/prompt-service.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/codex/prompt-service.js +0 -0
- package/dist/executor/sdk-handlers/codex/usage.d.ts +0 -0
- package/dist/executor/sdk-handlers/codex/usage.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/codex/usage.js +0 -0
- package/dist/executor/sdk-handlers/gemini/conversation-converter.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/conversation-converter.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/conversation-converter.js +0 -0
- package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/gemini-tool.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/gemini-tool.js +0 -0
- package/dist/executor/sdk-handlers/gemini/index.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/index.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/index.js +0 -0
- package/dist/executor/sdk-handlers/gemini/models.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/models.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/models.js +0 -0
- package/dist/executor/sdk-handlers/gemini/normalizer.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/normalizer.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/normalizer.js +0 -0
- package/dist/executor/sdk-handlers/gemini/permission-mapper.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/permission-mapper.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/permission-mapper.js +0 -0
- package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/prompt-service.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/prompt-service.js +0 -0
- package/dist/executor/sdk-handlers/gemini/usage.d.ts +0 -0
- package/dist/executor/sdk-handlers/gemini/usage.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/gemini/usage.js +0 -0
- package/dist/executor/sdk-handlers/models.d.ts +0 -0
- package/dist/executor/sdk-handlers/models.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/models.js +0 -0
- package/dist/executor/sdk-handlers/normalizer-factory.d.ts +0 -0
- package/dist/executor/sdk-handlers/normalizer-factory.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/normalizer-factory.js +0 -0
- package/dist/executor/sdk-handlers/opencode/index.d.ts +0 -0
- package/dist/executor/sdk-handlers/opencode/index.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/opencode/index.js +0 -0
- package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts +0 -0
- package/dist/executor/sdk-handlers/opencode/opencode-tool.d.ts.map +0 -0
- package/dist/executor/sdk-handlers/opencode/opencode-tool.js +0 -0
- package/dist/executor/services/feathers-client.d.ts +0 -0
- package/dist/executor/services/feathers-client.d.ts.map +0 -0
- package/dist/executor/services/feathers-client.js +0 -0
- package/dist/executor/types/sdk-response.d.ts +0 -0
- package/dist/executor/types/sdk-response.d.ts.map +0 -0
- package/dist/executor/types/sdk-response.js +0 -0
- package/dist/executor/types/token-usage.d.ts +0 -0
- package/dist/executor/types/token-usage.d.ts.map +0 -0
- package/dist/executor/types/token-usage.js +0 -0
- package/dist/executor/types.d.ts +0 -0
- package/dist/executor/types.d.ts.map +0 -0
- package/dist/executor/types.js +0 -0
- package/dist/ui/assets/{_basePickBy-a0JoJgXO.js → _basePickBy-DM-YlwQP.js} +1 -1
- package/dist/ui/assets/_basePickBy-DM-YlwQP.js.gz +0 -0
- package/dist/ui/assets/{_baseUniq-IFulW561.js → _baseUniq-w9wJK0j5.js} +1 -1
- package/dist/ui/assets/_baseUniq-w9wJK0j5.js.gz +0 -0
- package/dist/ui/assets/{arc-Dj6SyPh6.js → arc-CVXkw1SJ.js} +1 -1
- package/dist/ui/assets/arc-CVXkw1SJ.js.gz +0 -0
- package/dist/ui/assets/{architectureDiagram-VXUJARFQ-CjXOzrje.js → architectureDiagram-VXUJARFQ-CevjfWlW.js} +1 -1
- package/dist/ui/assets/{architectureDiagram-VXUJARFQ-CjXOzrje.js.gz → architectureDiagram-VXUJARFQ-CevjfWlW.js.gz} +0 -0
- package/dist/ui/assets/{blockDiagram-VD42YOAC-IFpdwkfg.js → blockDiagram-VD42YOAC-b9JU-Vzx.js} +1 -1
- package/dist/ui/assets/{blockDiagram-VD42YOAC-IFpdwkfg.js.gz → blockDiagram-VD42YOAC-b9JU-Vzx.js.gz} +0 -0
- package/dist/ui/assets/{c4Diagram-YG6GDRKO-qL4Ujfnz.js → c4Diagram-YG6GDRKO-j7VSccDF.js} +1 -1
- package/dist/ui/assets/c4Diagram-YG6GDRKO-j7VSccDF.js.gz +0 -0
- package/dist/ui/assets/channel-BNIBtjaQ.js +1 -0
- package/dist/ui/assets/{chunk-4BX2VUAB-CH6tu0mB.js → chunk-4BX2VUAB-D_codqcR.js} +1 -1
- package/dist/ui/assets/{chunk-55IACEB6-DDAZjWTD.js → chunk-55IACEB6-nQq1kviw.js} +1 -1
- package/dist/ui/assets/{chunk-B4BG7PRW-BDSu72O0.js → chunk-B4BG7PRW-DlVxaJL9.js} +1 -1
- package/dist/ui/assets/chunk-B4BG7PRW-DlVxaJL9.js.gz +0 -0
- package/dist/ui/assets/{chunk-DI55MBZ5-C7merGRo.js → chunk-DI55MBZ5-Dw95m49m.js} +1 -1
- package/dist/ui/assets/chunk-DI55MBZ5-Dw95m49m.js.gz +0 -0
- package/dist/ui/assets/{chunk-FMBD7UC4-DX20G6ZX.js → chunk-FMBD7UC4-Bnk79OV8.js} +1 -1
- package/dist/ui/assets/{chunk-QN33PNHL-BvT3a5aI.js → chunk-QN33PNHL-sqjI-sXo.js} +1 -1
- package/dist/ui/assets/{chunk-QZHKN3VN-oo-Lxdo7.js → chunk-QZHKN3VN-T7CEGHh9.js} +1 -1
- package/dist/ui/assets/{chunk-TZMSLE5B-BV4XHxKb.js → chunk-TZMSLE5B-ok9YQuUI.js} +1 -1
- package/dist/ui/assets/chunk-TZMSLE5B-ok9YQuUI.js.gz +0 -0
- package/dist/ui/assets/classDiagram-2ON5EDUG-DeHTLUto.js +1 -0
- package/dist/ui/assets/classDiagram-v2-WZHVMYZB-DeHTLUto.js +1 -0
- package/dist/ui/assets/clone-BObtDhw7.js +1 -0
- package/dist/ui/assets/{cose-bilkent-S5V4N54A-BA6VY55u.js → cose-bilkent-S5V4N54A-BtanJFqC.js} +1 -1
- package/dist/ui/assets/cose-bilkent-S5V4N54A-BtanJFqC.js.gz +0 -0
- package/dist/ui/assets/{dagre-6UL2VRFP-DiuqdLez.js → dagre-6UL2VRFP-CIJlfoaz.js} +1 -1
- package/dist/ui/assets/dagre-6UL2VRFP-CIJlfoaz.js.gz +0 -0
- package/dist/ui/assets/{diagram-PSM6KHXK-DU4u6xZN.js → diagram-PSM6KHXK-DhKlHuZN.js} +1 -1
- package/dist/ui/assets/diagram-PSM6KHXK-DhKlHuZN.js.gz +0 -0
- package/dist/ui/assets/{diagram-QEK2KX5R-CltgMeel.js → diagram-QEK2KX5R-BbwaTbd7.js} +1 -1
- package/dist/ui/assets/diagram-QEK2KX5R-BbwaTbd7.js.gz +0 -0
- package/dist/ui/assets/{diagram-S2PKOQOG-SkvAVcTN.js → diagram-S2PKOQOG-Dx1rRlHZ.js} +1 -1
- package/dist/ui/assets/diagram-S2PKOQOG-Dx1rRlHZ.js.gz +0 -0
- package/dist/ui/assets/{erDiagram-Q2GNP2WA-DJTHxEdE.js → erDiagram-Q2GNP2WA-w60Up3Mg.js} +1 -1
- package/dist/ui/assets/erDiagram-Q2GNP2WA-w60Up3Mg.js.gz +0 -0
- package/dist/ui/assets/{flowDiagram-NV44I4VS-BwrFtsSc.js → flowDiagram-NV44I4VS-yvyTqNEi.js} +1 -1
- package/dist/ui/assets/flowDiagram-NV44I4VS-yvyTqNEi.js.gz +0 -0
- package/dist/ui/assets/{ganttDiagram-LVOFAZNH-BnGmdiBB.js → ganttDiagram-LVOFAZNH-NBBWMpCB.js} +1 -1
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-NBBWMpCB.js.gz +0 -0
- package/dist/ui/assets/{gitGraphDiagram-NY62KEGX-V6mHZ2jy.js → gitGraphDiagram-NY62KEGX-Dc0qrZJi.js} +1 -1
- package/dist/ui/assets/gitGraphDiagram-NY62KEGX-Dc0qrZJi.js.gz +0 -0
- package/dist/ui/assets/{graph-3Ks94Pqc.js → graph-RIZM2qth.js} +1 -1
- package/dist/ui/assets/graph-RIZM2qth.js.gz +0 -0
- package/dist/ui/assets/{index-Dl_jng3-.js → index-BcHc8U_m.js} +240 -240
- package/dist/ui/assets/index-BcHc8U_m.js.gz +0 -0
- package/dist/ui/assets/index-BjxbtAmt.css +1 -0
- package/dist/ui/assets/index-BjxbtAmt.css.gz +0 -0
- package/dist/ui/assets/{infoDiagram-ER5ION4S-DUuNVOek.js → infoDiagram-ER5ION4S-Co1qQ3-G.js} +1 -1
- package/dist/ui/assets/{journeyDiagram-XKPGCS4Q-D-N__rLx.js → journeyDiagram-XKPGCS4Q-QaBi_wAx.js} +1 -1
- package/dist/ui/assets/journeyDiagram-XKPGCS4Q-QaBi_wAx.js.gz +0 -0
- package/dist/ui/assets/{kanban-definition-3W4ZIXB7-DsPDRbRp.js → kanban-definition-3W4ZIXB7-B3k5rpP3.js} +1 -1
- package/dist/ui/assets/kanban-definition-3W4ZIXB7-B3k5rpP3.js.gz +0 -0
- package/dist/ui/assets/{layout-TuyQIiWI.js → layout-YqNNovOM.js} +1 -1
- package/dist/ui/assets/layout-YqNNovOM.js.gz +0 -0
- package/dist/ui/assets/{linear-CQUCx9aD.js → linear-DpjTIW7z.js} +1 -1
- package/dist/ui/assets/linear-DpjTIW7z.js.gz +0 -0
- package/dist/ui/assets/{mermaid.core-HQwFIIbn.js → mermaid.core-D-fYaKXC.js} +5 -5
- package/dist/ui/assets/mermaid.core-D-fYaKXC.js.gz +0 -0
- package/dist/ui/assets/{mindmap-definition-VGOIOE7T-DlR4HpYx.js → mindmap-definition-VGOIOE7T-CddQalgD.js} +1 -1
- package/dist/ui/assets/mindmap-definition-VGOIOE7T-CddQalgD.js.gz +0 -0
- package/dist/ui/assets/{pieDiagram-ADFJNKIX-OfCYTJ7S.js → pieDiagram-ADFJNKIX-BCPzhaBq.js} +1 -1
- package/dist/ui/assets/pieDiagram-ADFJNKIX-BCPzhaBq.js.gz +0 -0
- package/dist/ui/assets/{quadrantDiagram-AYHSOK5B--irB7LvR.js → quadrantDiagram-AYHSOK5B-DrdJW-2E.js} +1 -1
- package/dist/ui/assets/quadrantDiagram-AYHSOK5B-DrdJW-2E.js.gz +0 -0
- package/dist/ui/assets/{requirementDiagram-UZGBJVZJ-iPensRLV.js → requirementDiagram-UZGBJVZJ-dV0cdx6D.js} +1 -1
- package/dist/ui/assets/requirementDiagram-UZGBJVZJ-dV0cdx6D.js.gz +0 -0
- package/dist/ui/assets/{sankeyDiagram-TZEHDZUN-BSidESLx.js → sankeyDiagram-TZEHDZUN-SLmqiy7a.js} +1 -1
- package/dist/ui/assets/sankeyDiagram-TZEHDZUN-SLmqiy7a.js.gz +0 -0
- package/dist/ui/assets/{sequenceDiagram-WL72ISMW-BUE46svP.js → sequenceDiagram-WL72ISMW-CyH5EbRm.js} +1 -1
- package/dist/ui/assets/sequenceDiagram-WL72ISMW-CyH5EbRm.js.gz +0 -0
- package/dist/ui/assets/{stateDiagram-FKZM4ZOC-BJ2azfLs.js → stateDiagram-FKZM4ZOC-DbtBIYM6.js} +1 -1
- package/dist/ui/assets/stateDiagram-FKZM4ZOC-DbtBIYM6.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-DOAHUeXQ.js +1 -0
- package/dist/ui/assets/{timeline-definition-IT6M3QCI-YfwKc8ip.js → timeline-definition-IT6M3QCI-CzdpjKni.js} +1 -1
- package/dist/ui/assets/timeline-definition-IT6M3QCI-CzdpjKni.js.gz +0 -0
- package/dist/ui/assets/{treemap-KMMF4GRG-DMpxEEn1.js → treemap-KMMF4GRG-D_MXp3HZ.js} +1 -1
- package/dist/ui/assets/treemap-KMMF4GRG-D_MXp3HZ.js.gz +0 -0
- package/dist/ui/assets/{xychartDiagram-PRI3JC2R-Bn_I2TeN.js → xychartDiagram-PRI3JC2R-BMwyKz4M.js} +1 -1
- package/dist/ui/assets/xychartDiagram-PRI3JC2R-BMwyKz4M.js.gz +0 -0
- package/dist/ui/index.html +2 -2
- package/package.json +1 -1
- package/dist/ui/assets/_basePickBy-a0JoJgXO.js.gz +0 -0
- package/dist/ui/assets/_baseUniq-IFulW561.js.gz +0 -0
- package/dist/ui/assets/arc-Dj6SyPh6.js.gz +0 -0
- package/dist/ui/assets/c4Diagram-YG6GDRKO-qL4Ujfnz.js.gz +0 -0
- package/dist/ui/assets/channel-4SJF66Rh.js +0 -1
- package/dist/ui/assets/chunk-B4BG7PRW-BDSu72O0.js.gz +0 -0
- package/dist/ui/assets/chunk-DI55MBZ5-C7merGRo.js.gz +0 -0
- package/dist/ui/assets/chunk-TZMSLE5B-BV4XHxKb.js.gz +0 -0
- package/dist/ui/assets/classDiagram-2ON5EDUG-BLjqJ_M9.js +0 -1
- package/dist/ui/assets/classDiagram-v2-WZHVMYZB-BLjqJ_M9.js +0 -1
- package/dist/ui/assets/clone-DjR0SEZ0.js +0 -1
- package/dist/ui/assets/cose-bilkent-S5V4N54A-BA6VY55u.js.gz +0 -0
- package/dist/ui/assets/dagre-6UL2VRFP-DiuqdLez.js.gz +0 -0
- package/dist/ui/assets/diagram-PSM6KHXK-DU4u6xZN.js.gz +0 -0
- package/dist/ui/assets/diagram-QEK2KX5R-CltgMeel.js.gz +0 -0
- package/dist/ui/assets/diagram-S2PKOQOG-SkvAVcTN.js.gz +0 -0
- package/dist/ui/assets/erDiagram-Q2GNP2WA-DJTHxEdE.js.gz +0 -0
- package/dist/ui/assets/flowDiagram-NV44I4VS-BwrFtsSc.js.gz +0 -0
- package/dist/ui/assets/ganttDiagram-LVOFAZNH-BnGmdiBB.js.gz +0 -0
- package/dist/ui/assets/gitGraphDiagram-NY62KEGX-V6mHZ2jy.js.gz +0 -0
- package/dist/ui/assets/graph-3Ks94Pqc.js.gz +0 -0
- package/dist/ui/assets/index-CoHRmHKF.css +0 -1
- package/dist/ui/assets/index-CoHRmHKF.css.gz +0 -0
- package/dist/ui/assets/index-Dl_jng3-.js.gz +0 -0
- package/dist/ui/assets/journeyDiagram-XKPGCS4Q-D-N__rLx.js.gz +0 -0
- package/dist/ui/assets/kanban-definition-3W4ZIXB7-DsPDRbRp.js.gz +0 -0
- package/dist/ui/assets/layout-TuyQIiWI.js.gz +0 -0
- package/dist/ui/assets/linear-CQUCx9aD.js.gz +0 -0
- package/dist/ui/assets/mermaid.core-HQwFIIbn.js.gz +0 -0
- package/dist/ui/assets/mindmap-definition-VGOIOE7T-DlR4HpYx.js.gz +0 -0
- package/dist/ui/assets/pieDiagram-ADFJNKIX-OfCYTJ7S.js.gz +0 -0
- package/dist/ui/assets/quadrantDiagram-AYHSOK5B--irB7LvR.js.gz +0 -0
- package/dist/ui/assets/requirementDiagram-UZGBJVZJ-iPensRLV.js.gz +0 -0
- package/dist/ui/assets/sankeyDiagram-TZEHDZUN-BSidESLx.js.gz +0 -0
- package/dist/ui/assets/sequenceDiagram-WL72ISMW-BUE46svP.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-FKZM4ZOC-BJ2azfLs.js.gz +0 -0
- package/dist/ui/assets/stateDiagram-v2-4FDKWEC3-B9Lx1w-S.js +0 -1
- package/dist/ui/assets/timeline-definition-IT6M3QCI-YfwKc8ip.js.gz +0 -0
- package/dist/ui/assets/treemap-KMMF4GRG-DMpxEEn1.js.gz +0 -0
- package/dist/ui/assets/xychartDiagram-PRI3JC2R-Bn_I2TeN.js.gz +0 -0
|
@@ -1,8 +1,52 @@
|
|
|
1
|
+
import { a as SessionID, B as BoardID } from '../id-BwPJtWxW.cjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* URL normalization utilities
|
|
3
5
|
*
|
|
4
6
|
* Provides shared helpers for validating and normalizing user-provided URLs.
|
|
5
7
|
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate a session URL for external/user-facing links
|
|
11
|
+
*
|
|
12
|
+
* Prefers board slug over short ID for cleaner URLs. Falls back to short ID if slug unavailable.
|
|
13
|
+
*
|
|
14
|
+
* @param sessionId - Session ID (full UUID)
|
|
15
|
+
* @param boardId - Board ID (required for URL generation)
|
|
16
|
+
* @param boardSlug - Board slug (optional, preferred for cleaner URLs)
|
|
17
|
+
* @param baseUrl - Base URL from config (e.g., "https://agor.example.com")
|
|
18
|
+
* @returns Session URL or null if boardId is missing
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* getSessionUrl('abc12345-...', 'board456-...', 'my-board', 'https://agor.example.com')
|
|
23
|
+
* // => 'https://agor.example.com/b/my-board/abc12345'
|
|
24
|
+
*
|
|
25
|
+
* getSessionUrl('abc12345-...', 'board456-...', undefined, 'https://agor.example.com')
|
|
26
|
+
* // => 'https://agor.example.com/b/board456/abc12345' (falls back to short ID)
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function getSessionUrl(sessionId: SessionID, boardId: BoardID | null | undefined, boardSlug: string | null | undefined, baseUrl: string): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Generate a board URL for external/user-facing links
|
|
32
|
+
*
|
|
33
|
+
* Prefers board slug over short ID for cleaner URLs. Falls back to short ID if slug unavailable.
|
|
34
|
+
*
|
|
35
|
+
* @param boardId - Board ID (full UUID)
|
|
36
|
+
* @param boardSlug - Board slug (optional, preferred for cleaner URLs)
|
|
37
|
+
* @param baseUrl - Base URL from config (e.g., "https://agor.example.com")
|
|
38
|
+
* @returns Board URL
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* getBoardUrl('board456-...', 'my-board', 'https://agor.example.com')
|
|
43
|
+
* // => 'https://agor.example.com/b/my-board'
|
|
44
|
+
*
|
|
45
|
+
* getBoardUrl('board456-...', undefined, 'https://agor.example.com')
|
|
46
|
+
* // => 'https://agor.example.com/b/board456' (falls back to short ID)
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare function getBoardUrl(boardId: BoardID, boardSlug: string | null | undefined, baseUrl: string): string;
|
|
6
50
|
/**
|
|
7
51
|
* Normalize an optional HTTP(S) URL string.
|
|
8
52
|
*
|
|
@@ -17,4 +61,4 @@
|
|
|
17
61
|
*/
|
|
18
62
|
declare function normalizeOptionalHttpUrl(value: unknown, fieldName?: string): string | undefined;
|
|
19
63
|
|
|
20
|
-
export { normalizeOptionalHttpUrl };
|
|
64
|
+
export { getBoardUrl, getSessionUrl, normalizeOptionalHttpUrl };
|
package/dist/core/utils/url.d.ts
CHANGED
|
@@ -1,8 +1,52 @@
|
|
|
1
|
+
import { a as SessionID, B as BoardID } from '../id-BwPJtWxW.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* URL normalization utilities
|
|
3
5
|
*
|
|
4
6
|
* Provides shared helpers for validating and normalizing user-provided URLs.
|
|
5
7
|
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate a session URL for external/user-facing links
|
|
11
|
+
*
|
|
12
|
+
* Prefers board slug over short ID for cleaner URLs. Falls back to short ID if slug unavailable.
|
|
13
|
+
*
|
|
14
|
+
* @param sessionId - Session ID (full UUID)
|
|
15
|
+
* @param boardId - Board ID (required for URL generation)
|
|
16
|
+
* @param boardSlug - Board slug (optional, preferred for cleaner URLs)
|
|
17
|
+
* @param baseUrl - Base URL from config (e.g., "https://agor.example.com")
|
|
18
|
+
* @returns Session URL or null if boardId is missing
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* getSessionUrl('abc12345-...', 'board456-...', 'my-board', 'https://agor.example.com')
|
|
23
|
+
* // => 'https://agor.example.com/b/my-board/abc12345'
|
|
24
|
+
*
|
|
25
|
+
* getSessionUrl('abc12345-...', 'board456-...', undefined, 'https://agor.example.com')
|
|
26
|
+
* // => 'https://agor.example.com/b/board456/abc12345' (falls back to short ID)
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function getSessionUrl(sessionId: SessionID, boardId: BoardID | null | undefined, boardSlug: string | null | undefined, baseUrl: string): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Generate a board URL for external/user-facing links
|
|
32
|
+
*
|
|
33
|
+
* Prefers board slug over short ID for cleaner URLs. Falls back to short ID if slug unavailable.
|
|
34
|
+
*
|
|
35
|
+
* @param boardId - Board ID (full UUID)
|
|
36
|
+
* @param boardSlug - Board slug (optional, preferred for cleaner URLs)
|
|
37
|
+
* @param baseUrl - Base URL from config (e.g., "https://agor.example.com")
|
|
38
|
+
* @returns Board URL
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* getBoardUrl('board456-...', 'my-board', 'https://agor.example.com')
|
|
43
|
+
* // => 'https://agor.example.com/b/my-board'
|
|
44
|
+
*
|
|
45
|
+
* getBoardUrl('board456-...', undefined, 'https://agor.example.com')
|
|
46
|
+
* // => 'https://agor.example.com/b/board456' (falls back to short ID)
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
declare function getBoardUrl(boardId: BoardID, boardSlug: string | null | undefined, baseUrl: string): string;
|
|
6
50
|
/**
|
|
7
51
|
* Normalize an optional HTTP(S) URL string.
|
|
8
52
|
*
|
|
@@ -17,4 +61,4 @@
|
|
|
17
61
|
*/
|
|
18
62
|
declare function normalizeOptionalHttpUrl(value: unknown, fieldName?: string): string | undefined;
|
|
19
63
|
|
|
20
|
-
export { normalizeOptionalHttpUrl };
|
|
64
|
+
export { getBoardUrl, getSessionUrl, normalizeOptionalHttpUrl };
|
package/dist/core/utils/url.js
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
+
// src/lib/ids.ts
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
function shortId(uuid, length = 8) {
|
|
4
|
+
const cleanUuid = uuid.replace(/-/g, "");
|
|
5
|
+
return cleanUuid.slice(0, Math.min(length, 32));
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
// src/utils/url.ts
|
|
9
|
+
function getSessionUrl(sessionId, boardId, boardSlug, baseUrl) {
|
|
10
|
+
if (!boardId) return null;
|
|
11
|
+
const boardParam = boardSlug || shortId(boardId);
|
|
12
|
+
return `${baseUrl}/b/${boardParam}/${shortId(sessionId)}`;
|
|
13
|
+
}
|
|
14
|
+
function getBoardUrl(boardId, boardSlug, baseUrl) {
|
|
15
|
+
const boardParam = boardSlug || shortId(boardId);
|
|
16
|
+
return `${baseUrl}/b/${boardParam}`;
|
|
17
|
+
}
|
|
2
18
|
function normalizeOptionalHttpUrl(value, fieldName = "value") {
|
|
3
19
|
if (value === null || value === void 0) {
|
|
4
20
|
return void 0;
|
|
@@ -24,5 +40,7 @@ function normalizeOptionalHttpUrl(value, fieldName = "value") {
|
|
|
24
40
|
}
|
|
25
41
|
}
|
|
26
42
|
export {
|
|
43
|
+
getBoardUrl,
|
|
44
|
+
getSessionUrl,
|
|
27
45
|
normalizeOptionalHttpUrl
|
|
28
46
|
};
|
package/dist/daemon/index.js
CHANGED
|
@@ -543,7 +543,7 @@ function setupMCPRoutes(app) {
|
|
|
543
543
|
// Session tools
|
|
544
544
|
{
|
|
545
545
|
name: "agor_sessions_list",
|
|
546
|
-
description: "List all sessions accessible to the current user",
|
|
546
|
+
description: "List all sessions accessible to the current user. Each session includes a `url` field with a clickable link to view the session in the UI.",
|
|
547
547
|
inputSchema: {
|
|
548
548
|
type: "object",
|
|
549
549
|
properties: {
|
|
@@ -569,7 +569,7 @@ function setupMCPRoutes(app) {
|
|
|
569
569
|
},
|
|
570
570
|
{
|
|
571
571
|
name: "agor_sessions_get",
|
|
572
|
-
description: "Get detailed information about a specific session, including genealogy and current state",
|
|
572
|
+
description: "Get detailed information about a specific session, including genealogy and current state. The response includes a `url` field with a clickable link to view the session in the UI.",
|
|
573
573
|
inputSchema: {
|
|
574
574
|
type: "object",
|
|
575
575
|
properties: {
|
|
@@ -906,7 +906,7 @@ function setupMCPRoutes(app) {
|
|
|
906
906
|
},
|
|
907
907
|
notes: {
|
|
908
908
|
type: ["string", "null"],
|
|
909
|
-
description: "Freeform notes about the worktree. Pass null or empty string to clear."
|
|
909
|
+
description: "Freeform notes about the worktree (markdown supported). Pass null or empty string to clear."
|
|
910
910
|
},
|
|
911
911
|
boardId: {
|
|
912
912
|
type: ["string", "null"],
|
|
@@ -1034,7 +1034,7 @@ function setupMCPRoutes(app) {
|
|
|
1034
1034
|
// Board tools
|
|
1035
1035
|
{
|
|
1036
1036
|
name: "agor_boards_get",
|
|
1037
|
-
description: "Get information about a board, including zones and layout",
|
|
1037
|
+
description: "Get information about a board, including zones and layout. The response includes a `url` field with a clickable link to view the board in the UI.",
|
|
1038
1038
|
inputSchema: {
|
|
1039
1039
|
type: "object",
|
|
1040
1040
|
properties: {
|
|
@@ -1048,7 +1048,7 @@ function setupMCPRoutes(app) {
|
|
|
1048
1048
|
},
|
|
1049
1049
|
{
|
|
1050
1050
|
name: "agor_boards_list",
|
|
1051
|
-
description: "List all boards accessible to the current user",
|
|
1051
|
+
description: "List all boards accessible to the current user. Each board includes a `url` field with a clickable link to view the board in the UI.",
|
|
1052
1052
|
inputSchema: {
|
|
1053
1053
|
type: "object",
|
|
1054
1054
|
properties: {
|
|
@@ -5113,6 +5113,9 @@ var GatewayService = class {
|
|
|
5113
5113
|
async refreshChannelState() {
|
|
5114
5114
|
const channels = await this.channelRepo.findAll();
|
|
5115
5115
|
this.hasActiveChannels = channels.some((ch) => ch.enabled);
|
|
5116
|
+
console.log(
|
|
5117
|
+
`[gateway] refreshChannelState: found ${channels.length} channels, ${channels.filter((ch) => ch.enabled).length} enabled`
|
|
5118
|
+
);
|
|
5116
5119
|
}
|
|
5117
5120
|
/**
|
|
5118
5121
|
* Send a debug/system message to the platform thread (fire-and-forget).
|
|
@@ -5187,7 +5190,17 @@ var GatewayService = class {
|
|
|
5187
5190
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5188
5191
|
} : void 0,
|
|
5189
5192
|
tasks: [],
|
|
5190
|
-
message_count: 0
|
|
5193
|
+
message_count: 0,
|
|
5194
|
+
// Denormalized gateway metadata (immutable snapshot at creation time)
|
|
5195
|
+
// Avoids N+1 lookups when rendering board cards
|
|
5196
|
+
custom_context: {
|
|
5197
|
+
gateway_source: {
|
|
5198
|
+
channel_id: channel.id,
|
|
5199
|
+
channel_name: channel.name,
|
|
5200
|
+
channel_type: channel.channel_type,
|
|
5201
|
+
thread_id: data.thread_id
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5191
5204
|
});
|
|
5192
5205
|
sessionId = session.session_id;
|
|
5193
5206
|
created = true;
|
|
@@ -5199,11 +5212,17 @@ var GatewayService = class {
|
|
|
5199
5212
|
status: "active",
|
|
5200
5213
|
metadata: data.metadata ?? null
|
|
5201
5214
|
});
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5215
|
+
let sessionUrl = null;
|
|
5216
|
+
try {
|
|
5217
|
+
const sessionsService2 = this.app.service("sessions");
|
|
5218
|
+
const sessionWithUrl = await sessionsService2.get(sessionId, { user });
|
|
5219
|
+
sessionUrl = sessionWithUrl.url || null;
|
|
5220
|
+
} catch (error) {
|
|
5221
|
+
console.warn("[gateway] Failed to fetch session URL:", error);
|
|
5222
|
+
}
|
|
5223
|
+
const sessionIdShort = sessionId.substring(0, 8);
|
|
5224
|
+
const message = sessionUrl ? `Session created: ${sessionUrl}` : `Session ${sessionIdShort} created, sending prompt to agent...`;
|
|
5225
|
+
this.sendDebugMessage(channel, data.thread_id, message);
|
|
5207
5226
|
}
|
|
5208
5227
|
await this.channelRepo.updateLastMessage(channel.id);
|
|
5209
5228
|
try {
|
|
@@ -5239,6 +5258,9 @@ var GatewayService = class {
|
|
|
5239
5258
|
if (!mapping) {
|
|
5240
5259
|
return { routed: false };
|
|
5241
5260
|
}
|
|
5261
|
+
console.log(
|
|
5262
|
+
`[gateway] Found mapping: channel=${mapping.channel_id.substring(0, 8)}, thread=${mapping.thread_id}`
|
|
5263
|
+
);
|
|
5242
5264
|
const channel = await this.channelRepo.findById(mapping.channel_id);
|
|
5243
5265
|
if (!channel || !channel.enabled) {
|
|
5244
5266
|
return { routed: false };
|
|
@@ -5287,6 +5309,51 @@ var GatewayService = class {
|
|
|
5287
5309
|
await this.startChannelListener(channel);
|
|
5288
5310
|
}
|
|
5289
5311
|
}
|
|
5312
|
+
/**
|
|
5313
|
+
* Start or stop a Socket Mode listener for a single channel based on its enabled state
|
|
5314
|
+
* (public wrapper for hook usage)
|
|
5315
|
+
*/
|
|
5316
|
+
async startListenerForChannel(channelId) {
|
|
5317
|
+
const channel = await this.channelRepo.findById(channelId);
|
|
5318
|
+
if (!channel) {
|
|
5319
|
+
console.warn(`[gateway] Cannot manage listener: channel ${channelId} not found`);
|
|
5320
|
+
return;
|
|
5321
|
+
}
|
|
5322
|
+
if (!channel.enabled) {
|
|
5323
|
+
await this.stopChannelListener(channelId);
|
|
5324
|
+
console.log(`[gateway] Stopped listener for disabled channel ${channel.name}`);
|
|
5325
|
+
return;
|
|
5326
|
+
}
|
|
5327
|
+
if (!hasConnector(channel.channel_type)) {
|
|
5328
|
+
console.warn(`[gateway] No connector for channel type: ${channel.channel_type}`);
|
|
5329
|
+
await this.stopChannelListener(channelId);
|
|
5330
|
+
return;
|
|
5331
|
+
}
|
|
5332
|
+
if (!channel.config.app_token) {
|
|
5333
|
+
console.log(`[gateway] Skipping listener for channel ${channel.name} (no app_token)`);
|
|
5334
|
+
await this.stopChannelListener(channelId);
|
|
5335
|
+
return;
|
|
5336
|
+
}
|
|
5337
|
+
await this.startChannelListener(channel);
|
|
5338
|
+
}
|
|
5339
|
+
/**
|
|
5340
|
+
* Stop a Socket Mode listener for a single channel
|
|
5341
|
+
*/
|
|
5342
|
+
async stopChannelListener(channelId) {
|
|
5343
|
+
const connector = this.activeListeners.get(channelId);
|
|
5344
|
+
if (!connector) {
|
|
5345
|
+
return;
|
|
5346
|
+
}
|
|
5347
|
+
try {
|
|
5348
|
+
if (connector.stopListening) {
|
|
5349
|
+
await connector.stopListening();
|
|
5350
|
+
}
|
|
5351
|
+
this.activeListeners.delete(channelId);
|
|
5352
|
+
console.log(`[gateway] Listener stopped for channel ${channelId.substring(0, 8)}`);
|
|
5353
|
+
} catch (error) {
|
|
5354
|
+
console.error(`[gateway] Error stopping listener for ${channelId}:`, error);
|
|
5355
|
+
}
|
|
5356
|
+
}
|
|
5290
5357
|
/**
|
|
5291
5358
|
* Start a Socket Mode listener for a single channel
|
|
5292
5359
|
*/
|
|
@@ -6126,6 +6193,7 @@ Use a different slug with: --slug custom/name`
|
|
|
6126
6193
|
branch: data.ref,
|
|
6127
6194
|
sourceBranch: data.sourceBranch,
|
|
6128
6195
|
createBranch: data.createBranch,
|
|
6196
|
+
refType: data.refType,
|
|
6129
6197
|
// Unix group isolation (only when RBAC is enabled)
|
|
6130
6198
|
initUnixGroup: rbacEnabled,
|
|
6131
6199
|
othersAccess: worktree.others_fs_access || "read",
|
|
@@ -7642,6 +7710,7 @@ var TerminalsService = class {
|
|
|
7642
7710
|
import { PAGINATION as PAGINATION9 } from "@agor/core/config";
|
|
7643
7711
|
import { ThreadSessionMapRepository as ThreadSessionMapRepository2 } from "@agor/core/db";
|
|
7644
7712
|
var ThreadSessionMapService = class extends DrizzleService {
|
|
7713
|
+
threadMapRepo;
|
|
7645
7714
|
constructor(db) {
|
|
7646
7715
|
const repo = new ThreadSessionMapRepository2(db);
|
|
7647
7716
|
super(repo, {
|
|
@@ -7652,6 +7721,14 @@ var ThreadSessionMapService = class extends DrizzleService {
|
|
|
7652
7721
|
max: PAGINATION9.MAX_LIMIT
|
|
7653
7722
|
}
|
|
7654
7723
|
});
|
|
7724
|
+
this.threadMapRepo = repo;
|
|
7725
|
+
}
|
|
7726
|
+
/**
|
|
7727
|
+
* Find all thread-session mappings for a worktree
|
|
7728
|
+
* Used by UI to identify gateway-created sessions
|
|
7729
|
+
*/
|
|
7730
|
+
async findByWorktree(worktreeId) {
|
|
7731
|
+
return this.threadMapRepo.findByWorktree(worktreeId);
|
|
7655
7732
|
}
|
|
7656
7733
|
};
|
|
7657
7734
|
function createThreadSessionMapService(db) {
|
|
@@ -11015,6 +11092,22 @@ ${possiblePaths.map((p) => ` - ${p}`).join("\n")}`
|
|
|
11015
11092
|
gw.refreshChannelState().catch(
|
|
11016
11093
|
(err) => console.warn("[gateway] Failed to refresh channel state:", err)
|
|
11017
11094
|
);
|
|
11095
|
+
const channel = context.result;
|
|
11096
|
+
if (channel?.id) {
|
|
11097
|
+
gw.startListenerForChannel(channel.id).catch(
|
|
11098
|
+
(err) => console.warn(`[gateway] Failed to manage listener for channel ${channel.id}:`, err)
|
|
11099
|
+
);
|
|
11100
|
+
}
|
|
11101
|
+
return context;
|
|
11102
|
+
};
|
|
11103
|
+
const stopGatewayChannelListener = async (context) => {
|
|
11104
|
+
const gw = context.app.service("gateway");
|
|
11105
|
+
const channelId = context.id;
|
|
11106
|
+
if (channelId) {
|
|
11107
|
+
gw.stopChannelListener(channelId).catch(
|
|
11108
|
+
(err) => console.warn(`[gateway] Failed to stop listener for channel ${channelId}:`, err)
|
|
11109
|
+
);
|
|
11110
|
+
}
|
|
11018
11111
|
return context;
|
|
11019
11112
|
};
|
|
11020
11113
|
app.service("gateway-channels").hooks({
|
|
@@ -11049,7 +11142,7 @@ ${possiblePaths.map((p) => ` - ${p}`).join("\n")}`
|
|
|
11049
11142
|
],
|
|
11050
11143
|
create: [refreshGatewayChannelState],
|
|
11051
11144
|
patch: [refreshGatewayChannelState],
|
|
11052
|
-
remove: [refreshGatewayChannelState]
|
|
11145
|
+
remove: [stopGatewayChannelListener, refreshGatewayChannelState]
|
|
11053
11146
|
}
|
|
11054
11147
|
});
|
|
11055
11148
|
app.service("thread-session-map").hooks({
|
|
@@ -12294,13 +12387,17 @@ ${possiblePaths.map((p) => ` - ${p}`).join("\n")}`
|
|
|
12294
12387
|
const id = params.route?.id;
|
|
12295
12388
|
if (!id) throw new Error("Session ID required");
|
|
12296
12389
|
const session = await sessionsService.get(id, params);
|
|
12297
|
-
if (session.status !== SessionStatus5.RUNNING && session.status !== SessionStatus5.AWAITING_PERMISSION) {
|
|
12390
|
+
if (session.status !== SessionStatus5.RUNNING && session.status !== SessionStatus5.AWAITING_PERMISSION && session.status !== SessionStatus5.STOPPING) {
|
|
12298
12391
|
return {
|
|
12299
12392
|
success: false,
|
|
12300
|
-
reason: `Session
|
|
12393
|
+
reason: `Session cannot be stopped (status: ${session.status})`
|
|
12301
12394
|
};
|
|
12302
12395
|
}
|
|
12303
|
-
|
|
12396
|
+
const isRetry = session.status === SessionStatus5.STOPPING;
|
|
12397
|
+
if (isRetry) {
|
|
12398
|
+
console.log(`\u{1F501} [Daemon] Retry stop request for session ${id.substring(0, 8)}`);
|
|
12399
|
+
}
|
|
12400
|
+
let targetTasksArray = [];
|
|
12304
12401
|
const runningResult = await tasksService.find({
|
|
12305
12402
|
query: {
|
|
12306
12403
|
session_id: id,
|
|
@@ -12319,33 +12416,66 @@ ${possiblePaths.map((p) => ` - ${p}`).join("\n")}`
|
|
|
12319
12416
|
});
|
|
12320
12417
|
const awaitingFindResult = awaitingResult;
|
|
12321
12418
|
const awaitingTasks = isPaginated(awaitingFindResult) ? awaitingFindResult.data : awaitingFindResult;
|
|
12322
|
-
|
|
12323
|
-
if (
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
try {
|
|
12331
|
-
await tasksService.patch(latestTask.task_id, {
|
|
12332
|
-
status: TaskStatus3.STOPPING
|
|
12419
|
+
targetTasksArray = [...runningTasks, ...awaitingTasks];
|
|
12420
|
+
if (isRetry && targetTasksArray.length === 0) {
|
|
12421
|
+
const stoppingResult = await tasksService.find({
|
|
12422
|
+
query: {
|
|
12423
|
+
session_id: id,
|
|
12424
|
+
status: TaskStatus3.STOPPING,
|
|
12425
|
+
$limit: 10
|
|
12426
|
+
}
|
|
12333
12427
|
});
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
// Prevent new prompts during stop
|
|
12340
|
-
},
|
|
12341
|
-
params
|
|
12342
|
-
);
|
|
12343
|
-
} catch (error) {
|
|
12428
|
+
const stoppingFindResult = stoppingResult;
|
|
12429
|
+
const stoppingTasks = isPaginated(stoppingFindResult) ? stoppingFindResult.data : stoppingFindResult;
|
|
12430
|
+
targetTasksArray = stoppingTasks;
|
|
12431
|
+
}
|
|
12432
|
+
if (targetTasksArray.length === 0) {
|
|
12344
12433
|
return {
|
|
12345
12434
|
success: false,
|
|
12346
|
-
reason:
|
|
12435
|
+
reason: isRetry ? "No active or stopping tasks found" : "No running tasks found"
|
|
12347
12436
|
};
|
|
12348
12437
|
}
|
|
12438
|
+
targetTasksArray.sort((a, b) => {
|
|
12439
|
+
const timeA = new Date(a.started_at || a.created_at).getTime();
|
|
12440
|
+
const timeB = new Date(b.started_at || b.created_at).getTime();
|
|
12441
|
+
return timeB - timeA;
|
|
12442
|
+
});
|
|
12443
|
+
const latestTask = targetTasksArray[0];
|
|
12444
|
+
let didTransitionToStopping = false;
|
|
12445
|
+
if (!isRetry) {
|
|
12446
|
+
try {
|
|
12447
|
+
await tasksService.patch(latestTask.task_id, {
|
|
12448
|
+
status: TaskStatus3.STOPPING
|
|
12449
|
+
});
|
|
12450
|
+
await app.service("sessions").patch(
|
|
12451
|
+
id,
|
|
12452
|
+
{
|
|
12453
|
+
status: SessionStatus5.STOPPING,
|
|
12454
|
+
ready_for_prompt: false
|
|
12455
|
+
// Prevent new prompts during stop
|
|
12456
|
+
},
|
|
12457
|
+
params
|
|
12458
|
+
);
|
|
12459
|
+
didTransitionToStopping = true;
|
|
12460
|
+
} catch (error) {
|
|
12461
|
+
return {
|
|
12462
|
+
success: false,
|
|
12463
|
+
reason: `Failed to update status: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
12464
|
+
};
|
|
12465
|
+
}
|
|
12466
|
+
} else {
|
|
12467
|
+
try {
|
|
12468
|
+
await app.service("sessions").patch(
|
|
12469
|
+
id,
|
|
12470
|
+
{
|
|
12471
|
+
ready_for_prompt: false
|
|
12472
|
+
},
|
|
12473
|
+
params
|
|
12474
|
+
);
|
|
12475
|
+
} catch (error) {
|
|
12476
|
+
console.warn(`\u26A0\uFE0F [Daemon] Failed to re-assert ready_for_prompt on retry:`, error);
|
|
12477
|
+
}
|
|
12478
|
+
}
|
|
12349
12479
|
const { handleStopWithAck: handleStopWithAck2 } = await Promise.resolve().then(() => (init_handle_stop(), handle_stop_exports));
|
|
12350
12480
|
const result = await handleStopWithAck2(
|
|
12351
12481
|
app,
|
|
@@ -12353,7 +12483,7 @@ ${possiblePaths.map((p) => ` - ${p}`).join("\n")}`
|
|
|
12353
12483
|
latestTask.task_id,
|
|
12354
12484
|
params
|
|
12355
12485
|
);
|
|
12356
|
-
if (!result.success) {
|
|
12486
|
+
if (!result.success && didTransitionToStopping) {
|
|
12357
12487
|
try {
|
|
12358
12488
|
await tasksService.patch(latestTask.task_id, {
|
|
12359
12489
|
status: TaskStatus3.RUNNING
|
|
@@ -96,7 +96,7 @@ function setupMCPRoutes(app) {
|
|
|
96
96
|
// Session tools
|
|
97
97
|
{
|
|
98
98
|
name: "agor_sessions_list",
|
|
99
|
-
description: "List all sessions accessible to the current user",
|
|
99
|
+
description: "List all sessions accessible to the current user. Each session includes a `url` field with a clickable link to view the session in the UI.",
|
|
100
100
|
inputSchema: {
|
|
101
101
|
type: "object",
|
|
102
102
|
properties: {
|
|
@@ -122,7 +122,7 @@ function setupMCPRoutes(app) {
|
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
name: "agor_sessions_get",
|
|
125
|
-
description: "Get detailed information about a specific session, including genealogy and current state",
|
|
125
|
+
description: "Get detailed information about a specific session, including genealogy and current state. The response includes a `url` field with a clickable link to view the session in the UI.",
|
|
126
126
|
inputSchema: {
|
|
127
127
|
type: "object",
|
|
128
128
|
properties: {
|
|
@@ -459,7 +459,7 @@ function setupMCPRoutes(app) {
|
|
|
459
459
|
},
|
|
460
460
|
notes: {
|
|
461
461
|
type: ["string", "null"],
|
|
462
|
-
description: "Freeform notes about the worktree. Pass null or empty string to clear."
|
|
462
|
+
description: "Freeform notes about the worktree (markdown supported). Pass null or empty string to clear."
|
|
463
463
|
},
|
|
464
464
|
boardId: {
|
|
465
465
|
type: ["string", "null"],
|
|
@@ -587,7 +587,7 @@ function setupMCPRoutes(app) {
|
|
|
587
587
|
// Board tools
|
|
588
588
|
{
|
|
589
589
|
name: "agor_boards_get",
|
|
590
|
-
description: "Get information about a board, including zones and layout",
|
|
590
|
+
description: "Get information about a board, including zones and layout. The response includes a `url` field with a clickable link to view the board in the UI.",
|
|
591
591
|
inputSchema: {
|
|
592
592
|
type: "object",
|
|
593
593
|
properties: {
|
|
@@ -601,7 +601,7 @@ function setupMCPRoutes(app) {
|
|
|
601
601
|
},
|
|
602
602
|
{
|
|
603
603
|
name: "agor_boards_list",
|
|
604
|
-
description: "List all boards accessible to the current user",
|
|
604
|
+
description: "List all boards accessible to the current user. Each board includes a `url` field with a clickable link to view the board in the UI.",
|
|
605
605
|
inputSchema: {
|
|
606
606
|
type: "object",
|
|
607
607
|
properties: {
|
|
@@ -89,6 +89,15 @@ declare class GatewayService {
|
|
|
89
89
|
* the gateway's create() method (same path as webhook POST).
|
|
90
90
|
*/
|
|
91
91
|
startListeners(): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Start or stop a Socket Mode listener for a single channel based on its enabled state
|
|
94
|
+
* (public wrapper for hook usage)
|
|
95
|
+
*/
|
|
96
|
+
startListenerForChannel(channelId: string): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Stop a Socket Mode listener for a single channel
|
|
99
|
+
*/
|
|
100
|
+
stopChannelListener(channelId: string): Promise<void>;
|
|
92
101
|
/**
|
|
93
102
|
* Start a Socket Mode listener for a single channel
|
|
94
103
|
*/
|
|
@@ -27,6 +27,9 @@ var GatewayService = class {
|
|
|
27
27
|
async refreshChannelState() {
|
|
28
28
|
const channels = await this.channelRepo.findAll();
|
|
29
29
|
this.hasActiveChannels = channels.some((ch) => ch.enabled);
|
|
30
|
+
console.log(
|
|
31
|
+
`[gateway] refreshChannelState: found ${channels.length} channels, ${channels.filter((ch) => ch.enabled).length} enabled`
|
|
32
|
+
);
|
|
30
33
|
}
|
|
31
34
|
/**
|
|
32
35
|
* Send a debug/system message to the platform thread (fire-and-forget).
|
|
@@ -101,7 +104,17 @@ var GatewayService = class {
|
|
|
101
104
|
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
102
105
|
} : void 0,
|
|
103
106
|
tasks: [],
|
|
104
|
-
message_count: 0
|
|
107
|
+
message_count: 0,
|
|
108
|
+
// Denormalized gateway metadata (immutable snapshot at creation time)
|
|
109
|
+
// Avoids N+1 lookups when rendering board cards
|
|
110
|
+
custom_context: {
|
|
111
|
+
gateway_source: {
|
|
112
|
+
channel_id: channel.id,
|
|
113
|
+
channel_name: channel.name,
|
|
114
|
+
channel_type: channel.channel_type,
|
|
115
|
+
thread_id: data.thread_id
|
|
116
|
+
}
|
|
117
|
+
}
|
|
105
118
|
});
|
|
106
119
|
sessionId = session.session_id;
|
|
107
120
|
created = true;
|
|
@@ -113,11 +126,17 @@ var GatewayService = class {
|
|
|
113
126
|
status: "active",
|
|
114
127
|
metadata: data.metadata ?? null
|
|
115
128
|
});
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
129
|
+
let sessionUrl = null;
|
|
130
|
+
try {
|
|
131
|
+
const sessionsService2 = this.app.service("sessions");
|
|
132
|
+
const sessionWithUrl = await sessionsService2.get(sessionId, { user });
|
|
133
|
+
sessionUrl = sessionWithUrl.url || null;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.warn("[gateway] Failed to fetch session URL:", error);
|
|
136
|
+
}
|
|
137
|
+
const sessionIdShort = sessionId.substring(0, 8);
|
|
138
|
+
const message = sessionUrl ? `Session created: ${sessionUrl}` : `Session ${sessionIdShort} created, sending prompt to agent...`;
|
|
139
|
+
this.sendDebugMessage(channel, data.thread_id, message);
|
|
121
140
|
}
|
|
122
141
|
await this.channelRepo.updateLastMessage(channel.id);
|
|
123
142
|
try {
|
|
@@ -153,6 +172,9 @@ var GatewayService = class {
|
|
|
153
172
|
if (!mapping) {
|
|
154
173
|
return { routed: false };
|
|
155
174
|
}
|
|
175
|
+
console.log(
|
|
176
|
+
`[gateway] Found mapping: channel=${mapping.channel_id.substring(0, 8)}, thread=${mapping.thread_id}`
|
|
177
|
+
);
|
|
156
178
|
const channel = await this.channelRepo.findById(mapping.channel_id);
|
|
157
179
|
if (!channel || !channel.enabled) {
|
|
158
180
|
return { routed: false };
|
|
@@ -201,6 +223,51 @@ var GatewayService = class {
|
|
|
201
223
|
await this.startChannelListener(channel);
|
|
202
224
|
}
|
|
203
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Start or stop a Socket Mode listener for a single channel based on its enabled state
|
|
228
|
+
* (public wrapper for hook usage)
|
|
229
|
+
*/
|
|
230
|
+
async startListenerForChannel(channelId) {
|
|
231
|
+
const channel = await this.channelRepo.findById(channelId);
|
|
232
|
+
if (!channel) {
|
|
233
|
+
console.warn(`[gateway] Cannot manage listener: channel ${channelId} not found`);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (!channel.enabled) {
|
|
237
|
+
await this.stopChannelListener(channelId);
|
|
238
|
+
console.log(`[gateway] Stopped listener for disabled channel ${channel.name}`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (!hasConnector(channel.channel_type)) {
|
|
242
|
+
console.warn(`[gateway] No connector for channel type: ${channel.channel_type}`);
|
|
243
|
+
await this.stopChannelListener(channelId);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (!channel.config.app_token) {
|
|
247
|
+
console.log(`[gateway] Skipping listener for channel ${channel.name} (no app_token)`);
|
|
248
|
+
await this.stopChannelListener(channelId);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
await this.startChannelListener(channel);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Stop a Socket Mode listener for a single channel
|
|
255
|
+
*/
|
|
256
|
+
async stopChannelListener(channelId) {
|
|
257
|
+
const connector = this.activeListeners.get(channelId);
|
|
258
|
+
if (!connector) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
if (connector.stopListening) {
|
|
263
|
+
await connector.stopListening();
|
|
264
|
+
}
|
|
265
|
+
this.activeListeners.delete(channelId);
|
|
266
|
+
console.log(`[gateway] Listener stopped for channel ${channelId.substring(0, 8)}`);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error(`[gateway] Error stopping listener for ${channelId}:`, error);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
204
271
|
/**
|
|
205
272
|
* Start a Socket Mode listener for a single channel
|
|
206
273
|
*/
|
|
@@ -711,6 +711,7 @@ Use a different slug with: --slug custom/name`
|
|
|
711
711
|
branch: data.ref,
|
|
712
712
|
sourceBranch: data.sourceBranch,
|
|
713
713
|
createBranch: data.createBranch,
|
|
714
|
+
refType: data.refType,
|
|
714
715
|
// Unix group isolation (only when RBAC is enabled)
|
|
715
716
|
initUnixGroup: rbacEnabled,
|
|
716
717
|
othersAccess: worktree.others_fs_access || "read",
|
|
@@ -10,7 +10,13 @@ import { DrizzleService } from '../adapters/drizzle.js';
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
declare class ThreadSessionMapService extends DrizzleService<ThreadSessionMap, Partial<ThreadSessionMap>> {
|
|
13
|
+
private threadMapRepo;
|
|
13
14
|
constructor(db: Database);
|
|
15
|
+
/**
|
|
16
|
+
* Find all thread-session mappings for a worktree
|
|
17
|
+
* Used by UI to identify gateway-created sessions
|
|
18
|
+
*/
|
|
19
|
+
findByWorktree(worktreeId: string): Promise<ThreadSessionMap[]>;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* Service factory function
|