@skaile/workspaces 1.14.1 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/NOTICE +13 -0
  3. package/dist/app-sdk/index.js +1 -1
  4. package/dist/{asset-feeds-ZQLJ2DCP.js → asset-feeds-MWEMXMZA.js} +5 -5
  5. package/dist/{asset-feeds-ZQLJ2DCP.js.map → asset-feeds-MWEMXMZA.js.map} +1 -1
  6. package/dist/asset-manager/index.js +5 -5
  7. package/dist/asset-manager/installer.js +1 -1
  8. package/dist/bridge/drivers/claude-sdk.js +1 -1
  9. package/dist/bridge/drivers/codex.js +1 -1
  10. package/dist/bridge/drivers/continue.js +2 -2
  11. package/dist/bridge/drivers/echo.js +1 -1
  12. package/dist/bridge/drivers/gemini.js +3 -3
  13. package/dist/bridge/drivers/goose.js +2 -2
  14. package/dist/bridge/drivers/omp.js +1 -1
  15. package/dist/bridge/drivers/opencode.js +2 -2
  16. package/dist/bridge/drivers/qwen.js +3 -3
  17. package/dist/bridge/index.js +2 -2
  18. package/dist/channels/adapters/msteams/activity.d.ts +70 -0
  19. package/dist/channels/adapters/msteams/activity.d.ts.map +1 -0
  20. package/dist/channels/adapters/msteams/client.d.ts +46 -0
  21. package/dist/channels/adapters/msteams/client.d.ts.map +1 -0
  22. package/dist/channels/adapters/msteams/index.d.ts +81 -0
  23. package/dist/channels/adapters/msteams/index.d.ts.map +1 -0
  24. package/dist/channels/adapters/msteams/jwt.d.ts +27 -0
  25. package/dist/channels/adapters/msteams/jwt.d.ts.map +1 -0
  26. package/dist/channels/adapters/msteams.d.ts +2 -0
  27. package/dist/channels/adapters/msteams.js +595 -0
  28. package/dist/channels/adapters/msteams.js.map +1 -0
  29. package/dist/channels/index.d.ts +2 -0
  30. package/dist/channels/index.js +1069 -0
  31. package/dist/channels/index.js.map +1 -0
  32. package/dist/channels/src/adapter.d.ts +54 -0
  33. package/dist/channels/src/adapter.d.ts.map +1 -0
  34. package/dist/channels/src/dedupe.d.ts +67 -0
  35. package/dist/channels/src/dedupe.d.ts.map +1 -0
  36. package/dist/channels/src/egress/output-mirror.d.ts +63 -0
  37. package/dist/channels/src/egress/output-mirror.d.ts.map +1 -0
  38. package/dist/channels/src/egress/vendor/auto-close-streaming.d.ts +26 -0
  39. package/dist/channels/src/egress/vendor/auto-close-streaming.d.ts.map +1 -0
  40. package/dist/channels/src/egress/vendor/chunked-message-stream.d.ts +79 -0
  41. package/dist/channels/src/egress/vendor/chunked-message-stream.d.ts.map +1 -0
  42. package/dist/channels/src/egress/vendor/markdown-to-mrkdwn.d.ts +21 -0
  43. package/dist/channels/src/egress/vendor/markdown-to-mrkdwn.d.ts.map +1 -0
  44. package/dist/channels/src/egress/vendor/message-stream.d.ts +57 -0
  45. package/dist/channels/src/egress/vendor/message-stream.d.ts.map +1 -0
  46. package/dist/channels/src/engine.d.ts +125 -0
  47. package/dist/channels/src/engine.d.ts.map +1 -0
  48. package/dist/channels/src/format/adaptive-card.d.ts +17 -0
  49. package/dist/channels/src/format/adaptive-card.d.ts.map +1 -0
  50. package/dist/channels/src/format/mrkdwn.d.ts +4 -0
  51. package/dist/channels/src/format/mrkdwn.d.ts.map +1 -0
  52. package/dist/channels/src/format/types.d.ts +9 -0
  53. package/dist/channels/src/format/types.d.ts.map +1 -0
  54. package/dist/channels/src/index.d.ts +17 -0
  55. package/dist/channels/src/index.d.ts.map +1 -0
  56. package/dist/channels/src/mention/lookup-tool.d.ts +23 -0
  57. package/dist/channels/src/mention/lookup-tool.d.ts.map +1 -0
  58. package/dist/channels/src/mention/normalize.d.ts +27 -0
  59. package/dist/channels/src/mention/normalize.d.ts.map +1 -0
  60. package/dist/channels/src/mention/render.d.ts +10 -0
  61. package/dist/channels/src/mention/render.d.ts.map +1 -0
  62. package/dist/channels/src/ports.d.ts +71 -0
  63. package/dist/channels/src/ports.d.ts.map +1 -0
  64. package/dist/channels/src/types.d.ts +169 -0
  65. package/dist/channels/src/types.d.ts.map +1 -0
  66. package/dist/{chunk-A7GDV5BV.js → chunk-2BQBWWFX.js} +2 -2
  67. package/dist/{chunk-A7GDV5BV.js.map → chunk-2BQBWWFX.js.map} +1 -1
  68. package/dist/{chunk-MWE7DEGC.js → chunk-344DEXZS.js} +3 -3
  69. package/dist/{chunk-MWE7DEGC.js.map → chunk-344DEXZS.js.map} +1 -1
  70. package/dist/{chunk-CC6LFFTI.js → chunk-6ZLMG5GR.js} +4 -4
  71. package/dist/{chunk-CC6LFFTI.js.map → chunk-6ZLMG5GR.js.map} +1 -1
  72. package/dist/{chunk-T2H2ZCU4.js → chunk-73HV7RV3.js} +3 -3
  73. package/dist/{chunk-T2H2ZCU4.js.map → chunk-73HV7RV3.js.map} +1 -1
  74. package/dist/{chunk-P5VLR3L7.js → chunk-BI2NKPA4.js} +8 -4
  75. package/dist/chunk-BI2NKPA4.js.map +1 -0
  76. package/dist/{chunk-IIGWJE5T.js → chunk-DPUZJI45.js} +3 -3
  77. package/dist/{chunk-IIGWJE5T.js.map → chunk-DPUZJI45.js.map} +1 -1
  78. package/dist/chunk-F2IBDVBP.js +72 -0
  79. package/dist/chunk-F2IBDVBP.js.map +1 -0
  80. package/dist/{chunk-G73FOLLO.js → chunk-F3ET4UGP.js} +3 -3
  81. package/dist/{chunk-G73FOLLO.js.map → chunk-F3ET4UGP.js.map} +1 -1
  82. package/dist/{chunk-ZWPXSHMW.js → chunk-HA53HVIS.js} +336 -100
  83. package/dist/chunk-HA53HVIS.js.map +1 -0
  84. package/dist/{chunk-HLIN4HRK.js → chunk-LTQOZIJO.js} +2 -2
  85. package/dist/{chunk-HLIN4HRK.js.map → chunk-LTQOZIJO.js.map} +1 -1
  86. package/dist/{chunk-CS6NFRNQ.js → chunk-MJEUK6VJ.js} +2 -2
  87. package/dist/{chunk-CS6NFRNQ.js.map → chunk-MJEUK6VJ.js.map} +1 -1
  88. package/dist/{chunk-AF2NTM4B.js → chunk-NRXVS7E4.js} +6 -6
  89. package/dist/{chunk-AF2NTM4B.js.map → chunk-NRXVS7E4.js.map} +1 -1
  90. package/dist/{chunk-UDUFMVJD.js → chunk-RADBQ5XJ.js} +7 -7
  91. package/dist/{chunk-UDUFMVJD.js.map → chunk-RADBQ5XJ.js.map} +1 -1
  92. package/dist/{chunk-TSB46BHR.js → chunk-RDE43ORT.js} +4 -4
  93. package/dist/{chunk-TSB46BHR.js.map → chunk-RDE43ORT.js.map} +1 -1
  94. package/dist/{chunk-4RI4TNMO.js → chunk-SELNYOEO.js} +2 -2
  95. package/dist/{chunk-4RI4TNMO.js.map → chunk-SELNYOEO.js.map} +1 -1
  96. package/dist/{chunk-KECY74AL.js → chunk-SRWIVMJI.js} +4 -4
  97. package/dist/{chunk-KECY74AL.js.map → chunk-SRWIVMJI.js.map} +1 -1
  98. package/dist/{chunk-VK24PIAB.js → chunk-TFIFNDT2.js} +3 -3
  99. package/dist/{chunk-VK24PIAB.js.map → chunk-TFIFNDT2.js.map} +1 -1
  100. package/dist/{chunk-NIZNN42B.js → chunk-XW3SWH7C.js} +3 -3
  101. package/dist/{chunk-NIZNN42B.js.map → chunk-XW3SWH7C.js.map} +1 -1
  102. package/dist/{chunk-BIAA3N2A.js → chunk-Z6NGK5YC.js} +3 -3
  103. package/dist/{chunk-BIAA3N2A.js.map → chunk-Z6NGK5YC.js.map} +1 -1
  104. package/dist/cli/index.js +41 -41
  105. package/dist/connectors/config.js +1 -1
  106. package/dist/connectors/index.js +1 -1
  107. package/dist/core/index.js +1 -1
  108. package/dist/deploy/index.js +1 -1
  109. package/dist/{ensure-sources-O7X3LYLG.js → ensure-sources-QGL44IRI.js} +8 -8
  110. package/dist/{ensure-sources-O7X3LYLG.js.map → ensure-sources-QGL44IRI.js.map} +1 -1
  111. package/dist/factory-assets/connectors/box.js +1 -1
  112. package/dist/factory-assets/connectors/deploy.js +1 -1
  113. package/dist/factory-assets/connectors/devserver.js +1 -1
  114. package/dist/factory-assets/connectors/flow/adapter.js +1 -1
  115. package/dist/factory-assets/connectors/flow/engine.js +1 -1
  116. package/dist/factory-assets/connectors/flow/run-flow.js +2 -2
  117. package/dist/factory-assets/connectors/flow.js +1 -1
  118. package/dist/factory-assets/connectors/git.js +1 -1
  119. package/dist/factory-assets/connectors/gmail.js +1 -1
  120. package/dist/factory-assets/connectors/googledrive.js +1 -1
  121. package/dist/factory-assets/connectors/local.js +1 -1
  122. package/dist/factory-assets/connectors/mattermost.js +1 -1
  123. package/dist/factory-assets/connectors/memory.js +1 -1
  124. package/dist/factory-assets/connectors/minio.js +1 -1
  125. package/dist/factory-assets/connectors/postgres.js +1 -1
  126. package/dist/factory-assets/connectors/s3.js +1 -1
  127. package/dist/factory-assets/connectors/sharepoint.js +1 -1
  128. package/dist/factory-assets/connectors/sqlite.js +1 -1
  129. package/dist/factory-assets/connectors/static-server.js +1 -1
  130. package/dist/factory-assets/connectors/tunnel.js +1 -1
  131. package/dist/factory-assets/connectors/webdav.js +1 -1
  132. package/dist/factory-assets/connectors/xstate-store.js +1 -1
  133. package/dist/factory-assets/connectors/xstate.js +1 -1
  134. package/dist/{flows-TIUWM7SZ.js → flows-FHWBCLXF.js} +3 -3
  135. package/dist/{flows-TIUWM7SZ.js.map → flows-FHWBCLXF.js.map} +1 -1
  136. package/dist/{helpers-DNTGJSA5.js → helpers-FMWODXTW.js} +8 -8
  137. package/dist/{helpers-DNTGJSA5.js.map → helpers-FMWODXTW.js.map} +1 -1
  138. package/dist/library/index.js +4 -4
  139. package/dist/library/install.js +1 -1
  140. package/dist/{library-publish-XKQN6RTR.js → library-publish-7YDHQGBN.js} +10 -10
  141. package/dist/{library-publish-XKQN6RTR.js.map → library-publish-7YDHQGBN.js.map} +1 -1
  142. package/dist/{open-library-2BWIUK4F.js → open-library-O6T3ELPK.js} +9 -9
  143. package/dist/{open-library-2BWIUK4F.js.map → open-library-O6T3ELPK.js.map} +1 -1
  144. package/dist/{paths-KOKCMBL5.js → paths-5QJJBAND.js} +7 -7
  145. package/dist/{paths-KOKCMBL5.js.map → paths-5QJJBAND.js.map} +1 -1
  146. package/dist/{plugin-store-QMJ2B3VM.js → plugin-store-ZBJZ7F6D.js} +3 -3
  147. package/dist/{plugin-store-QMJ2B3VM.js.map → plugin-store-ZBJZ7F6D.js.map} +1 -1
  148. package/dist/{project-4NPDM7R3.js → project-HAMLHLD5.js} +9 -9
  149. package/dist/{project-4NPDM7R3.js.map → project-HAMLHLD5.js.map} +1 -1
  150. package/dist/runner/index.js +8 -8
  151. package/dist/runner/src/serve.d.ts +138 -1
  152. package/dist/runner/src/serve.d.ts.map +1 -1
  153. package/dist/sdk/asset-manager.js +5 -5
  154. package/dist/sdk/bridge.js +2 -2
  155. package/dist/sdk/core.js +1 -1
  156. package/dist/sdk/flow.js +1 -1
  157. package/dist/sdk/index.js +8 -8
  158. package/dist/sdk/runner.js +8 -8
  159. package/dist/sdk/session.js +2 -2
  160. package/dist/sdk/transport/ws.js +1 -1
  161. package/dist/sdk/transport.js +1 -1
  162. package/dist/sdk/types.js +1 -1
  163. package/dist/session/index.js +2 -2
  164. package/dist/session/src/dispatcher.d.ts.map +1 -1
  165. package/dist/{setup-TNHKXCBL.js → setup-OJC74Q2Q.js} +5 -5
  166. package/dist/{setup-TNHKXCBL.js.map → setup-OJC74Q2Q.js.map} +1 -1
  167. package/dist/{source-HVMQJZU7.js → source-ITDH4367.js} +10 -10
  168. package/dist/{source-HVMQJZU7.js.map → source-ITDH4367.js.map} +1 -1
  169. package/dist/{source-manifest-publish-JN62UMZD.js → source-manifest-publish-RMHC7R6M.js} +11 -11
  170. package/dist/{source-manifest-publish-JN62UMZD.js.map → source-manifest-publish-RMHC7R6M.js.map} +1 -1
  171. package/dist/transport/index.js +1 -1
  172. package/dist/transport/ws.js +1 -1
  173. package/dist/tui/index.js +8 -8
  174. package/dist/types/index.js +1 -1
  175. package/dist/types/src/events.d.ts +74 -1
  176. package/dist/types/src/events.d.ts.map +1 -1
  177. package/dist/types/src/flow.d.ts +34 -0
  178. package/dist/types/src/flow.d.ts.map +1 -1
  179. package/dist/types/src/index.d.ts +2 -2
  180. package/dist/types/src/index.d.ts.map +1 -1
  181. package/dist/types/src/protocol.d.ts +6 -0
  182. package/dist/types/src/protocol.d.ts.map +1 -1
  183. package/dist/types/src/version.d.ts +23 -1
  184. package/dist/types/src/version.d.ts.map +1 -1
  185. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  186. package/dist/workspace-plugin/adapters/omp.js +3 -3
  187. package/dist/workspace-plugin/index.js +1 -1
  188. package/package.json +15 -2
  189. package/dist/chunk-P5VLR3L7.js.map +0 -1
  190. package/dist/chunk-ZWPXSHMW.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#447](https://github.com/skaile-ai/workspaces/pull/447) [`8498b81`](https://github.com/skaile-ai/workspaces/commit/8498b81c267ae640d752446066b39fee915b4f3f) Thanks [@peteralbert](https://github.com/peteralbert)! - New `channels` module — chat-app integration core (rollout step 1 of the
8
+ 2026-08-07 channels design): `ChannelEngine` with host ports (SessionPort,
9
+ IdentityPort, BindingStore, CredentialPort, IngressHost), the ChannelAdapter
10
+ interface, a streaming egress pipeline (throttled serialized edit queues,
11
+ frozen-boundary fence-safe chunking, markdown auto-close — vendored from
12
+ CopilotKit under MIT with attribution), mention normalization onto the
13
+ existing Mention union, markdown→Adaptive-Card formatting, and the MS Teams
14
+ adapter (Bot Framework ingress + JWT validation, raw-fetch provider client,
15
+ ackDeadlineMs 15000). New subpaths: `@skaile/workspaces/channels`,
16
+ `@skaile/workspaces/channels/msteams`.
17
+
18
+ - [#446](https://github.com/skaile-ai/workspaces/pull/446) [`5771268`](https://github.com/skaile-ai/workspaces/commit/5771268483403133f0a74de04c2d69d803955495) Thanks [@peteralbert](https://github.com/peteralbert)! - Protocol 3.7.0 — acknowledge `connector_mutate`, and stop dropping flow mutates that lose the wake race.
19
+
20
+ A `connector_mutate { id: "flow", … }` arriving before the flow connector was registered resolved to a bare dispatch, threw `Connector not found: "flow"`, and the throw was swallowed into a `serverLog.warn`. The host could not detect it at all, because the protocol had no `connector_mutate` result message. Seen in production as the ~2 ms race between an inbox approval and the bootstrap `flow.hydrate` on wake, and as a `cancel` against a session whose flow connector detached after a deploy.
21
+
22
+ Three additive changes:
23
+
24
+ - **Opt-in acknowledgement.** `ConnectorMutateCommand` gains `requestId?: string`. When set, the runner emits exactly one new `connector_mutate_response` event — `{ requestId, ok, result?, error?, code?, reconciled? }`, with `code` one of `connector_unavailable` / `rejected` / `op_failed` / `session_unavailable` — on every terminal path, including the previously swallowed one. When absent, nothing is emitted, so a 3.6 host sees byte-identical behaviour. The existing non-fatal `error` event on the reject path is unchanged.
25
+ - **Flow-connector readiness wait.** A flow-targeted op that resolves to a dispatch against an unregistered connector now waits for the connector to appear, re-plans, and dispatches, instead of failing. Bounded by `SKAILE_FLOW_MUTATE_CONNECTOR_WAIT_MS`, default 8000 ms; on expiry the ack carries `connector_unavailable`.
26
+ - **Hydrate-time reconciliation.** `flow.hydrate` accepts `payload.pendingDecisions: PendingGateDecision[]`, replayed in the same handler invocation that creates the connector — so there is no second command to race — and reported back as `reconciled: { applied, skipped }`. A decision that no longer applies is a structured skip (`not_parked` / `already_decided` / `unknown_node` / `payload_invalid`), never a throw; a replayed input response is validated against the node's own `inputSchema` and never logged or echoed.
27
+
28
+ `connector_mutate_response` is registered as a transient dispatcher type, so acks are never persisted as chat messages. `handleConnectorQuery` is untouched.
29
+
3
30
  ## 1.14.1
4
31
 
5
32
  ### Patch Changes
package/NOTICE ADDED
@@ -0,0 +1,13 @@
1
+ @skaile/workspaces
2
+ Copyright (c) Skaile. Licensed under the Apache License, Version 2.0.
3
+
4
+ This package contains vendored third-party code:
5
+
6
+ - channels/src/egress/vendor/markdown-to-mrkdwn.ts
7
+ - channels/src/egress/vendor/auto-close-streaming.ts
8
+ - channels/src/egress/vendor/message-stream.ts
9
+ - channels/src/egress/vendor/chunked-message-stream.ts
10
+ Vendored from CopilotKit (https://github.com/CopilotKit/CopilotKit)
11
+ @ 66fef88b249e9cac2d76a238678c19d3ce6b2913,
12
+ Copyright (c) Atai Barkai, licensed under the MIT License.
13
+ Modifications: platform-neutral adaptation for @skaile/workspaces/channels.
@@ -1,4 +1,4 @@
1
- import { PROTOCOL_VERSION_STRING } from '../chunk-TSB46BHR.js';
1
+ import { PROTOCOL_VERSION_STRING } from '../chunk-RDE43ORT.js';
2
2
  import '../chunk-NSBPE2FW.js';
3
3
  import * as z from 'zod';
4
4
 
@@ -1,6 +1,7 @@
1
1
  import { assignDomain, buildDomainIndex, DOMAIN_MD_FILENAME, parseDomainMd } from './chunk-MZV6WCF3.js';
2
2
  import './chunk-JXT46QFC.js';
3
3
  import './chunk-5NZ56R63.js';
4
+ import './chunk-K5GBV4SA.js';
4
5
  import './chunk-ZAP2BDHG.js';
5
6
  import { factoryAssetRoots } from './chunk-7J7LQP6T.js';
6
7
  import { scanRepo } from './chunk-ISA7R7PK.js';
@@ -9,7 +10,6 @@ import { walkDir, parseFrontmatter } from './chunk-BQCGFPHW.js';
9
10
  import './chunk-GEEW6SY2.js';
10
11
  import './chunk-F3HNW354.js';
11
12
  import './chunk-MENCWIHW.js';
12
- import './chunk-K5GBV4SA.js';
13
13
  import './chunk-JB35MVBN.js';
14
14
  import './chunk-IRORTHGA.js';
15
15
  import './chunk-NSBPE2FW.js';
@@ -64,7 +64,7 @@ async function libraryAssets() {
64
64
  const domains = [];
65
65
  try {
66
66
  const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([
67
- import('./open-library-2BWIUK4F.js'),
67
+ import('./open-library-O6T3ELPK.js'),
68
68
  import('./library/index.js'),
69
69
  import('./core/index.js')
70
70
  ]);
@@ -97,7 +97,7 @@ async function libraryAssets() {
97
97
  async function storeAssets(projectDir) {
98
98
  const notes = [];
99
99
  try {
100
- const { resolveCatalogSource } = await import('./open-library-2BWIUK4F.js');
100
+ const { resolveCatalogSource } = await import('./open-library-O6T3ELPK.js');
101
101
  const { source, close } = await resolveCatalogSource({ projectDir });
102
102
  try {
103
103
  const assets = await source.listAssets();
@@ -201,5 +201,5 @@ function dedupeBySlug(domains) {
201
201
  }
202
202
 
203
203
  export { gatherAssetFeeds };
204
- //# sourceMappingURL=asset-feeds-ZQLJ2DCP.js.map
205
- //# sourceMappingURL=asset-feeds-ZQLJ2DCP.js.map
204
+ //# sourceMappingURL=asset-feeds-MWEMXMZA.js.map
205
+ //# sourceMappingURL=asset-feeds-MWEMXMZA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-ZQLJ2DCP.js","sourcesContent":["/**\n * asset-feeds.ts — gather installable assets from every feed the manage TUI\n * surfaces.\n *\n * Four feeds, normalized into `CatalogEntry`:\n * - **Project sources** — `skaile.yaml` `sources:` entries (scanned via\n * `AssetManager.search()`; the new `sources:` field is merged into the\n * legacy repositories map in `AssetManager.loadConfig`).\n * - **Local libraries** — user authoring places from `LocalIndex` (filesystem\n * scan of each library's `path`).\n * - **Factory assets** — the bundled first-party `factory-assets` tree\n * (`factoryAssetRoots()`), scanned from disk. Always present; no network.\n * - **Remote store** — the configured catalog source when `catalog.url` is\n * not `local`. Failures are non-fatal — they surface as notes.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n parseFrontmatter,\n scanRepo,\n walkDir,\n} from \"@skaile/workspaces/core\";\nimport {\n assignDomain,\n buildDomainIndex,\n DOMAIN_MD_FILENAME,\n type DomainMd,\n parseDomainMd,\n} from \"@skaile/workspaces/discovery\";\n\n/** One non-fatal note returned to the caller for surfacing in the UI. */\nexport interface FeedNote {\n feed: \"sources\" | \"libraries\" | \"store\" | \"factory\";\n message: string;\n}\n\n/**\n * Which feed an asset came from. This is the top-level grouping axis in the\n * manage TUI (\"where is this skill coming from?\") and is intentionally distinct\n * from `publisher` (asset-intrinsic identity): the same publisher can legitimately\n * appear under more than one origin (e.g. a github repo you added as a `source`\n * that is also listed in the remote `store`).\n */\nexport type AssetOrigin = \"source\" | \"library\" | \"factory\" | \"store\";\n\n/** A catalog entry tagged with the feed it was gathered from. */\nexport interface OriginEntry {\n origin: AssetOrigin;\n entry: CatalogEntry;\n /**\n * Second-level grouping label for the manage tree. Defaults (when unset) to the\n * entry's `publisher`; the source feed sets it to the source's short repo name\n * so the Sources band groups by source — \"which repo did this come from\" — not\n * by the asset-intrinsic publisher.\n */\n group?: string;\n}\n\nexport interface AssetFeedResult {\n entries: OriginEntry[];\n /**\n * Display-only domain metadata, keyed (by the consumer) on `slug`. Populated\n * from the store's `catalog.listDomains` when the connected catalog source\n * exposes it; empty otherwise. The manage TUI joins `entry.domainSlug` → a\n * domain for grouping headers, descriptions, and relation badges.\n */\n domains: CatalogDomain[];\n notes: FeedNote[];\n}\n\n// ── Domain stamping (on-disk feeds) ──────────────────────────────────────────\n//\n// `scanRepo` (the source / library / factory scan path) does not read the\n// `DOMAIN.md` sidecars, so its entries arrive with no `domainSlug` and render\n// flat under their publisher band. We re-derive the grouping here from the\n// root's `DOMAIN.md` files (the same sidecars the remote store computes\n// server-side), and fall back to the repo/source name for any entry no domain\n// claims so it still groups instead of landing in the synthetic \"no domain\" pile.\n\n/** Repo-relative POSIX path (DOMAIN.md slugs are matched whole-segment, `/`-joined). */\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** Parse every `DOMAIN.md` sidecar under `root` into a {@link DomainMd}. */\nfunction loadDomainMds(root: string): DomainMd[] {\n const out: DomainMd[] = [];\n for (const { path: filePath, name } of walkDir(root)) {\n if (name !== DOMAIN_MD_FILENAME) continue;\n try {\n const { data } = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n out.push(parseDomainMd(toPosix(path.relative(root, filePath)), data));\n } catch {}\n }\n return out;\n}\n\n/**\n * Stamp `domainSlug` onto every entry scanned from `root` using the root's\n * `DOMAIN.md` sidecars. Returns the `CatalogDomain` registry for the real\n * domains, plus a synthetic fallback domain when any entry used the fallback.\n * Mutates `entries` in place (sets `entry.domainSlug`).\n *\n * `synthesizeFallback` (default true): entries no domain claims fall back to\n * `fallbackSlug` (the repo/source name). Pass `false` when the caller already\n * groups these entries one level up (e.g. the source feed groups by source\n * node) — unmatched entries then get no domain (`\"\"`) and hang directly under\n * that parent, instead of nesting under a same-named fallback domain.\n */\nfunction stampDomains(\n root: string,\n fallbackSlug: string,\n entries: CatalogEntry[],\n synthesizeFallback = true,\n): CatalogDomain[] {\n const domainMds = loadDomainMds(root);\n const assignables = entries.map((entry) => ({\n entry,\n ref: `${entry.kind}:${entry.name}`,\n relativePath: toPosix(path.relative(root, entry.source)),\n }));\n\n let usedFallback = false;\n for (const a of assignables) {\n const slug = assignDomain(a.relativePath, domainMds);\n if (slug) a.entry.domainSlug = slug;\n else if (synthesizeFallback) {\n a.entry.domainSlug = fallbackSlug;\n usedFallback = true;\n } else a.entry.domainSlug = \"\";\n }\n\n const { index } = buildDomainIndex(assignables, domainMds);\n const catalog: CatalogDomain[] = Object.values(index).map((d) => ({\n slug: d.slug,\n title: d.title,\n ...(d.description ? { description: d.description } : {}),\n ...(d.relation ? { relation: d.relation } : {}),\n ...(d.order !== undefined ? { order: d.order } : {}),\n ...(d.recommended[0] ? { recommendedRef: d.recommended[0] } : {}),\n }));\n if (usedFallback) catalog.push({ slug: fallbackSlug, title: fallbackSlug });\n return catalog;\n}\n\n/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/cache/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and grouped under the bare library\n * name (`group: <name>`) so the manage TUI shows a clean `<name>` band — no\n * `library:` prefix and no redundant same-named fallback domain (mirrors the\n * source feed).\n */\nasync function libraryAssets(): Promise<{\n entries: OriginEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n import(\"@skaile/workspaces/core\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n // Authoring libraries are the rows that are NOT source clones. index.db\n // rows predating the cache migration still carry the legacy\n // ~/.skaile/sources path, so exclude both roots.\n const newRoot = getGlobalCacheDir();\n const legacyRoot = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter(\n (l) => !l.path.startsWith(newRoot) && !l.path.startsWith(legacyRoot),\n );\n const entries: OriginEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n // Scan + group under the bare library name. `synthesizeFallback: false`\n // (as the source feed does) keeps domainless assets directly under the\n // library band instead of a redundant same-named fallback domain.\n const libEntries = [...scanRepo(lib.path, lib.name)];\n domains.push(...stampDomains(lib.path, lib.name, libEntries, false));\n for (const entry of libEntries) entries.push({ origin: \"library\", entry, group: lib.name });\n }\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n notes.push({\n feed: \"libraries\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/**\n * Pull a (best-effort) snapshot of the connected remote store catalog.\n *\n * - Returns no entries when the resolved catalog is local-only or the host\n * is unreachable (the failure becomes a note, not an exception).\n * - Maps `CatalogAsset` → `CatalogEntry`, carrying `publisher`, `repo`, and\n * `category` straight through and using `source = \"store://<id>\"`; per-file\n * `source` paths are not available for remote assets so the canonical ref is\n * a stable placeholder.\n */\nasync function storeAssets(projectDir: string): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n try {\n const { resolveCatalogSource } = await import(\"./open-library.ts\");\n const { source, close } = await resolveCatalogSource({ projectDir });\n try {\n const assets = await source.listAssets();\n const entries: CatalogEntry[] = assets.map((a) => ({\n name: a.name,\n kind: (a.kind as AssetKind) ?? \"skill\",\n description: a.description ?? \"\",\n source: `store://${a.id}`,\n publisher: a.publisher,\n repo: a.repo,\n domainSlug: a.domainSlug,\n category: a.category,\n version: a.version,\n requires: [],\n dependencies: [],\n }));\n // Domains are optional on the catalog source — only the store backend\n // (post Part 4 `catalog.listDomains`) exposes them. Duck-type the call so\n // older sources and the local catalog degrade to no domains, not an error.\n const domains = await loadDomains(source);\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Local-only catalog throws a recognizable message — silence it; absence\n // is the user's choice, not an error.\n if (!/local/i.test(msg)) {\n notes.push({ feed: \"store\", message: msg });\n }\n return { entries: [], domains: [], notes };\n }\n}\n\n/** Optional `listDomains` capability — returns `[]` when the source lacks it. */\nasync function loadDomains(source: unknown): Promise<CatalogDomain[]> {\n const fn = (source as { listDomains?: () => Promise<CatalogDomain[]> }).listDomains;\n if (typeof fn !== \"function\") return [];\n const domains = await fn.call(source);\n return Array.isArray(domains) ? domains : [];\n}\n\n/** The slice of `AssetManager` the source feed needs (kept narrow for tests). */\ninterface AssetManagerLike {\n search: () => CatalogEntry[];\n searchRepoRoots: () => { repoName: string; root: string }[];\n}\n\n/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map, then stamps\n * `DOMAIN.md`-derived domain grouping onto the scanned entries via\n * `searchRepoRoots()`.\n */\nfunction sourceAssets(am: AssetManagerLike): { entries: OriginEntry[]; domains: CatalogDomain[] } {\n // The bundled factory tree is injected into the repositories map as an implicit\n // source, so `am.search()` returns it too. It has its own `factory` origin band,\n // so drop it here — otherwise the same first-party skills list twice under Sources.\n const factoryPrefixes = factoryAssetRoots().map((r) => (r.endsWith(path.sep) ? r : r + path.sep));\n const isFactoryPath = (p: string) =>\n factoryPrefixes.some((fp) => p === fp.slice(0, -1) || p.startsWith(fp));\n\n const all = am.search().filter((e) => !isFactoryPath(e.source));\n const entries: OriginEntry[] = [];\n const domains: CatalogDomain[] = [];\n // Group each source's entries under the source node (its short repo name), not\n // the publisher: under Sources the navigational question is \"which repo did\n // this come from\". Each entry's `source` (absolute manifest path) lives under\n // exactly one declared root, so group + stamp by prefix. The cache slug is\n // URL-keyed `github.com/<org>/<repo>` — take the trailing segment.\n for (const { repoName, root } of am.searchRepoRoots()) {\n if (isFactoryPath(root)) continue;\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n const owned = all.filter((e) => e.source === root || e.source.startsWith(prefix));\n if (owned.length === 0) continue;\n const sourceName = repoName.split(\"/\").pop() || repoName;\n // No synthetic fallback domain — the source node already groups these, so a\n // same-named fallback would just nest the source under itself.\n domains.push(...stampDomains(root, sourceName, owned, false));\n for (const entry of owned) entries.push({ origin: \"source\", entry, group: sourceName });\n }\n return { entries, domains };\n}\n\n/**\n * Factory-asset feed: scan the bundled first-party `factory-assets` tree(s)\n * resolved by `factoryAssetRoots()` (the `SKAILE_FACTORY_ASSETS_DIR` override\n * layer ahead of the bundled tree). Synchronous, no network — the entries are\n * the built-in skills / connectors / bundles that ship with `@skaile/workspaces`.\n * `factoryAssetRoots()` already dedupes, so the env override pointing at the\n * bundled dir collapses to one root.\n */\nfunction factoryAssets(): { entries: CatalogEntry[]; domains: CatalogDomain[]; notes: FeedNote[] } {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n const rootEntries = [...scanRepo(root, \"skaile-factory\")];\n domains.push(...stampDomains(root, \"skaile-factory\", rootEntries));\n entries.push(...rootEntries);\n }\n return { entries, domains, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/** Tag a flat entry list with a single origin. */\nfunction tag(origin: AssetOrigin, entries: CatalogEntry[]): OriginEntry[] {\n return entries.map((entry) => ({ origin, entry }));\n}\n\n/**\n * Run all feeds and return a single normalized result.\n *\n * Feeds run in parallel where possible — the store fetch is the slow one\n * (one HTTP call) and is fired alongside the local library walk. The factory\n * scan is local + synchronous, so it runs inline.\n */\nexport async function gatherAssetFeeds(\n am: AssetManagerLike,\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = factoryAssets();\n const src = sourceAssets(am);\n return {\n entries: [\n ...src.entries,\n ...libs.entries,\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n // Store domains first (server-curated), then the on-disk feeds; dedupe by\n // slug, first-wins, so a store-served domain shadows a same-slug local one.\n domains: dedupeBySlug([...store.domains, ...src.domains, ...libs.domains, ...factory.domains]),\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n\n/** First-wins dedupe of a domain list by `slug`. */\nfunction dedupeBySlug(domains: CatalogDomain[]): CatalogDomain[] {\n const seen = new Set<string>();\n const out: CatalogDomain[] = [];\n for (const d of domains) {\n if (seen.has(d.slug)) continue;\n seen.add(d.slug);\n out.push(d);\n }\n return out;\n}\n"]}
1
+ {"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-MWEMXMZA.js","sourcesContent":["/**\n * asset-feeds.ts — gather installable assets from every feed the manage TUI\n * surfaces.\n *\n * Four feeds, normalized into `CatalogEntry`:\n * - **Project sources** — `skaile.yaml` `sources:` entries (scanned via\n * `AssetManager.search()`; the new `sources:` field is merged into the\n * legacy repositories map in `AssetManager.loadConfig`).\n * - **Local libraries** — user authoring places from `LocalIndex` (filesystem\n * scan of each library's `path`).\n * - **Factory assets** — the bundled first-party `factory-assets` tree\n * (`factoryAssetRoots()`), scanned from disk. Always present; no network.\n * - **Remote store** — the configured catalog source when `catalog.url` is\n * not `local`. Failures are non-fatal — they surface as notes.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n parseFrontmatter,\n scanRepo,\n walkDir,\n} from \"@skaile/workspaces/core\";\nimport {\n assignDomain,\n buildDomainIndex,\n DOMAIN_MD_FILENAME,\n type DomainMd,\n parseDomainMd,\n} from \"@skaile/workspaces/discovery\";\n\n/** One non-fatal note returned to the caller for surfacing in the UI. */\nexport interface FeedNote {\n feed: \"sources\" | \"libraries\" | \"store\" | \"factory\";\n message: string;\n}\n\n/**\n * Which feed an asset came from. This is the top-level grouping axis in the\n * manage TUI (\"where is this skill coming from?\") and is intentionally distinct\n * from `publisher` (asset-intrinsic identity): the same publisher can legitimately\n * appear under more than one origin (e.g. a github repo you added as a `source`\n * that is also listed in the remote `store`).\n */\nexport type AssetOrigin = \"source\" | \"library\" | \"factory\" | \"store\";\n\n/** A catalog entry tagged with the feed it was gathered from. */\nexport interface OriginEntry {\n origin: AssetOrigin;\n entry: CatalogEntry;\n /**\n * Second-level grouping label for the manage tree. Defaults (when unset) to the\n * entry's `publisher`; the source feed sets it to the source's short repo name\n * so the Sources band groups by source — \"which repo did this come from\" — not\n * by the asset-intrinsic publisher.\n */\n group?: string;\n}\n\nexport interface AssetFeedResult {\n entries: OriginEntry[];\n /**\n * Display-only domain metadata, keyed (by the consumer) on `slug`. Populated\n * from the store's `catalog.listDomains` when the connected catalog source\n * exposes it; empty otherwise. The manage TUI joins `entry.domainSlug` → a\n * domain for grouping headers, descriptions, and relation badges.\n */\n domains: CatalogDomain[];\n notes: FeedNote[];\n}\n\n// ── Domain stamping (on-disk feeds) ──────────────────────────────────────────\n//\n// `scanRepo` (the source / library / factory scan path) does not read the\n// `DOMAIN.md` sidecars, so its entries arrive with no `domainSlug` and render\n// flat under their publisher band. We re-derive the grouping here from the\n// root's `DOMAIN.md` files (the same sidecars the remote store computes\n// server-side), and fall back to the repo/source name for any entry no domain\n// claims so it still groups instead of landing in the synthetic \"no domain\" pile.\n\n/** Repo-relative POSIX path (DOMAIN.md slugs are matched whole-segment, `/`-joined). */\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** Parse every `DOMAIN.md` sidecar under `root` into a {@link DomainMd}. */\nfunction loadDomainMds(root: string): DomainMd[] {\n const out: DomainMd[] = [];\n for (const { path: filePath, name } of walkDir(root)) {\n if (name !== DOMAIN_MD_FILENAME) continue;\n try {\n const { data } = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n out.push(parseDomainMd(toPosix(path.relative(root, filePath)), data));\n } catch {}\n }\n return out;\n}\n\n/**\n * Stamp `domainSlug` onto every entry scanned from `root` using the root's\n * `DOMAIN.md` sidecars. Returns the `CatalogDomain` registry for the real\n * domains, plus a synthetic fallback domain when any entry used the fallback.\n * Mutates `entries` in place (sets `entry.domainSlug`).\n *\n * `synthesizeFallback` (default true): entries no domain claims fall back to\n * `fallbackSlug` (the repo/source name). Pass `false` when the caller already\n * groups these entries one level up (e.g. the source feed groups by source\n * node) — unmatched entries then get no domain (`\"\"`) and hang directly under\n * that parent, instead of nesting under a same-named fallback domain.\n */\nfunction stampDomains(\n root: string,\n fallbackSlug: string,\n entries: CatalogEntry[],\n synthesizeFallback = true,\n): CatalogDomain[] {\n const domainMds = loadDomainMds(root);\n const assignables = entries.map((entry) => ({\n entry,\n ref: `${entry.kind}:${entry.name}`,\n relativePath: toPosix(path.relative(root, entry.source)),\n }));\n\n let usedFallback = false;\n for (const a of assignables) {\n const slug = assignDomain(a.relativePath, domainMds);\n if (slug) a.entry.domainSlug = slug;\n else if (synthesizeFallback) {\n a.entry.domainSlug = fallbackSlug;\n usedFallback = true;\n } else a.entry.domainSlug = \"\";\n }\n\n const { index } = buildDomainIndex(assignables, domainMds);\n const catalog: CatalogDomain[] = Object.values(index).map((d) => ({\n slug: d.slug,\n title: d.title,\n ...(d.description ? { description: d.description } : {}),\n ...(d.relation ? { relation: d.relation } : {}),\n ...(d.order !== undefined ? { order: d.order } : {}),\n ...(d.recommended[0] ? { recommendedRef: d.recommended[0] } : {}),\n }));\n if (usedFallback) catalog.push({ slug: fallbackSlug, title: fallbackSlug });\n return catalog;\n}\n\n/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/cache/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and grouped under the bare library\n * name (`group: <name>`) so the manage TUI shows a clean `<name>` band — no\n * `library:` prefix and no redundant same-named fallback domain (mirrors the\n * source feed).\n */\nasync function libraryAssets(): Promise<{\n entries: OriginEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n import(\"@skaile/workspaces/core\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n // Authoring libraries are the rows that are NOT source clones. index.db\n // rows predating the cache migration still carry the legacy\n // ~/.skaile/sources path, so exclude both roots.\n const newRoot = getGlobalCacheDir();\n const legacyRoot = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter(\n (l) => !l.path.startsWith(newRoot) && !l.path.startsWith(legacyRoot),\n );\n const entries: OriginEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n // Scan + group under the bare library name. `synthesizeFallback: false`\n // (as the source feed does) keeps domainless assets directly under the\n // library band instead of a redundant same-named fallback domain.\n const libEntries = [...scanRepo(lib.path, lib.name)];\n domains.push(...stampDomains(lib.path, lib.name, libEntries, false));\n for (const entry of libEntries) entries.push({ origin: \"library\", entry, group: lib.name });\n }\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n notes.push({\n feed: \"libraries\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/**\n * Pull a (best-effort) snapshot of the connected remote store catalog.\n *\n * - Returns no entries when the resolved catalog is local-only or the host\n * is unreachable (the failure becomes a note, not an exception).\n * - Maps `CatalogAsset` → `CatalogEntry`, carrying `publisher`, `repo`, and\n * `category` straight through and using `source = \"store://<id>\"`; per-file\n * `source` paths are not available for remote assets so the canonical ref is\n * a stable placeholder.\n */\nasync function storeAssets(projectDir: string): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n try {\n const { resolveCatalogSource } = await import(\"./open-library.ts\");\n const { source, close } = await resolveCatalogSource({ projectDir });\n try {\n const assets = await source.listAssets();\n const entries: CatalogEntry[] = assets.map((a) => ({\n name: a.name,\n kind: (a.kind as AssetKind) ?? \"skill\",\n description: a.description ?? \"\",\n source: `store://${a.id}`,\n publisher: a.publisher,\n repo: a.repo,\n domainSlug: a.domainSlug,\n category: a.category,\n version: a.version,\n requires: [],\n dependencies: [],\n }));\n // Domains are optional on the catalog source — only the store backend\n // (post Part 4 `catalog.listDomains`) exposes them. Duck-type the call so\n // older sources and the local catalog degrade to no domains, not an error.\n const domains = await loadDomains(source);\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Local-only catalog throws a recognizable message — silence it; absence\n // is the user's choice, not an error.\n if (!/local/i.test(msg)) {\n notes.push({ feed: \"store\", message: msg });\n }\n return { entries: [], domains: [], notes };\n }\n}\n\n/** Optional `listDomains` capability — returns `[]` when the source lacks it. */\nasync function loadDomains(source: unknown): Promise<CatalogDomain[]> {\n const fn = (source as { listDomains?: () => Promise<CatalogDomain[]> }).listDomains;\n if (typeof fn !== \"function\") return [];\n const domains = await fn.call(source);\n return Array.isArray(domains) ? domains : [];\n}\n\n/** The slice of `AssetManager` the source feed needs (kept narrow for tests). */\ninterface AssetManagerLike {\n search: () => CatalogEntry[];\n searchRepoRoots: () => { repoName: string; root: string }[];\n}\n\n/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map, then stamps\n * `DOMAIN.md`-derived domain grouping onto the scanned entries via\n * `searchRepoRoots()`.\n */\nfunction sourceAssets(am: AssetManagerLike): { entries: OriginEntry[]; domains: CatalogDomain[] } {\n // The bundled factory tree is injected into the repositories map as an implicit\n // source, so `am.search()` returns it too. It has its own `factory` origin band,\n // so drop it here — otherwise the same first-party skills list twice under Sources.\n const factoryPrefixes = factoryAssetRoots().map((r) => (r.endsWith(path.sep) ? r : r + path.sep));\n const isFactoryPath = (p: string) =>\n factoryPrefixes.some((fp) => p === fp.slice(0, -1) || p.startsWith(fp));\n\n const all = am.search().filter((e) => !isFactoryPath(e.source));\n const entries: OriginEntry[] = [];\n const domains: CatalogDomain[] = [];\n // Group each source's entries under the source node (its short repo name), not\n // the publisher: under Sources the navigational question is \"which repo did\n // this come from\". Each entry's `source` (absolute manifest path) lives under\n // exactly one declared root, so group + stamp by prefix. The cache slug is\n // URL-keyed `github.com/<org>/<repo>` — take the trailing segment.\n for (const { repoName, root } of am.searchRepoRoots()) {\n if (isFactoryPath(root)) continue;\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n const owned = all.filter((e) => e.source === root || e.source.startsWith(prefix));\n if (owned.length === 0) continue;\n const sourceName = repoName.split(\"/\").pop() || repoName;\n // No synthetic fallback domain — the source node already groups these, so a\n // same-named fallback would just nest the source under itself.\n domains.push(...stampDomains(root, sourceName, owned, false));\n for (const entry of owned) entries.push({ origin: \"source\", entry, group: sourceName });\n }\n return { entries, domains };\n}\n\n/**\n * Factory-asset feed: scan the bundled first-party `factory-assets` tree(s)\n * resolved by `factoryAssetRoots()` (the `SKAILE_FACTORY_ASSETS_DIR` override\n * layer ahead of the bundled tree). Synchronous, no network — the entries are\n * the built-in skills / connectors / bundles that ship with `@skaile/workspaces`.\n * `factoryAssetRoots()` already dedupes, so the env override pointing at the\n * bundled dir collapses to one root.\n */\nfunction factoryAssets(): { entries: CatalogEntry[]; domains: CatalogDomain[]; notes: FeedNote[] } {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n const rootEntries = [...scanRepo(root, \"skaile-factory\")];\n domains.push(...stampDomains(root, \"skaile-factory\", rootEntries));\n entries.push(...rootEntries);\n }\n return { entries, domains, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/** Tag a flat entry list with a single origin. */\nfunction tag(origin: AssetOrigin, entries: CatalogEntry[]): OriginEntry[] {\n return entries.map((entry) => ({ origin, entry }));\n}\n\n/**\n * Run all feeds and return a single normalized result.\n *\n * Feeds run in parallel where possible — the store fetch is the slow one\n * (one HTTP call) and is fired alongside the local library walk. The factory\n * scan is local + synchronous, so it runs inline.\n */\nexport async function gatherAssetFeeds(\n am: AssetManagerLike,\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = factoryAssets();\n const src = sourceAssets(am);\n return {\n entries: [\n ...src.entries,\n ...libs.entries,\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n // Store domains first (server-curated), then the on-disk feeds; dedupe by\n // slug, first-wins, so a store-served domain shadows a same-slug local one.\n domains: dedupeBySlug([...store.domains, ...src.domains, ...libs.domains, ...factory.domains]),\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n\n/** First-wins dedupe of a domain list by `slug`. */\nfunction dedupeBySlug(domains: CatalogDomain[]): CatalogDomain[] {\n const seen = new Set<string>();\n const out: CatalogDomain[] = [];\n for (const d of domains) {\n if (seen.has(d.slug)) continue;\n seen.add(d.slug);\n out.push(d);\n }\n return out;\n}\n"]}
@@ -1,12 +1,13 @@
1
- export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, NON_DEPLOYABLE_KINDS, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, softDepName } from '../chunk-IIGWJE5T.js';
2
- import '../chunk-MWE7DEGC.js';
3
- import '../chunk-MZV6WCF3.js';
4
- import '../chunk-JXT46QFC.js';
1
+ export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, NON_DEPLOYABLE_KINDS, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, softDepName } from '../chunk-DPUZJI45.js';
2
+ import '../chunk-344DEXZS.js';
5
3
  import '../chunk-UKJMQZV6.js';
6
4
  import '../chunk-R7FOF242.js';
5
+ import '../chunk-MZV6WCF3.js';
6
+ import '../chunk-JXT46QFC.js';
7
7
  export { createScaffold, deployAll, installAgent, removeAsset } from '../chunk-STQOPWPS.js';
8
8
  export { BUILT_IN_FRAGMENTS, loadPromptExtensions, resolveFragments } from '../chunk-CGYEHQOX.js';
9
9
  import '../chunk-5NZ56R63.js';
10
+ import '../chunk-K5GBV4SA.js';
10
11
  import '../chunk-ZAP2BDHG.js';
11
12
  import '../chunk-7J7LQP6T.js';
12
13
  import '../chunk-ISA7R7PK.js';
@@ -15,7 +16,6 @@ import '../chunk-BQCGFPHW.js';
15
16
  import '../chunk-GEEW6SY2.js';
16
17
  import '../chunk-F3HNW354.js';
17
18
  import '../chunk-MENCWIHW.js';
18
- import '../chunk-K5GBV4SA.js';
19
19
  import '../chunk-JB35MVBN.js';
20
20
  export { appendHistory, clearHistory, getRecentHistory, loadHistory } from '../chunk-KTBKW2FI.js';
21
21
  import '../chunk-UQ6LFBPZ.js';
@@ -1,6 +1,7 @@
1
1
  export { createScaffold, deployAll, deployAsset, removeAsset } from '../chunk-STQOPWPS.js';
2
2
  import '../chunk-CGYEHQOX.js';
3
3
  import '../chunk-5NZ56R63.js';
4
+ import '../chunk-K5GBV4SA.js';
4
5
  import '../chunk-ZAP2BDHG.js';
5
6
  import '../chunk-7J7LQP6T.js';
6
7
  import '../chunk-ISA7R7PK.js';
@@ -9,7 +10,6 @@ import '../chunk-BQCGFPHW.js';
9
10
  import '../chunk-GEEW6SY2.js';
10
11
  import '../chunk-F3HNW354.js';
11
12
  import '../chunk-MENCWIHW.js';
12
- import '../chunk-K5GBV4SA.js';
13
13
  import '../chunk-JB35MVBN.js';
14
14
  import '../chunk-IEX5YV4R.js';
15
15
  import '../chunk-IRORTHGA.js';
@@ -2,7 +2,7 @@ import { SUPPORTED_CLOUDS, buildClaudeCloudEnv } from '../../chunk-ISQWMBKD.js';
2
2
  import { dispatchCapability } from '../../chunk-RRVQAE5D.js';
3
3
  import { fetchProviderModels } from '../../chunk-BMQKMOQY.js';
4
4
  import { AuthError, classifyClaudeSdkError, reclassifyAuthAsAccountUnavailable, AccountUnavailableError } from '../../chunk-GAH4YRCI.js';
5
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
5
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
6
6
  import '../../chunk-6E6PKKAD.js';
7
7
  import '../../chunk-JB35MVBN.js';
8
8
  import '../../chunk-NSBPE2FW.js';
@@ -1,6 +1,6 @@
1
1
  import { fetchProviderModels } from '../../chunk-BMQKMOQY.js';
2
2
  import { classifyGenericErrorMessage } from '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
3
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-JB35MVBN.js';
6
6
  import '../../chunk-NSBPE2FW.js';
@@ -1,6 +1,6 @@
1
- import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-NIZNN42B.js';
1
+ import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-XW3SWH7C.js';
2
2
  import '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
3
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-JB35MVBN.js';
6
6
  import '../../chunk-NSBPE2FW.js';
@@ -1,5 +1,5 @@
1
1
  import { dispatchCapability } from '../../chunk-RRVQAE5D.js';
2
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
2
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
3
3
  import '../../chunk-6E6PKKAD.js';
4
4
  import '../../chunk-JB35MVBN.js';
5
5
  import '../../chunk-NSBPE2FW.js';
@@ -1,8 +1,8 @@
1
- export { GeminiDriver, GeminiFamilyDriver, geminiDriverTarget } from '../../chunk-CC6LFFTI.js';
2
- import '../../chunk-NIZNN42B.js';
1
+ export { GeminiDriver, GeminiFamilyDriver, geminiDriverTarget } from '../../chunk-6ZLMG5GR.js';
2
+ import '../../chunk-XW3SWH7C.js';
3
3
  import '../../chunk-BMQKMOQY.js';
4
4
  import '../../chunk-GAH4YRCI.js';
5
- import '../../chunk-HLIN4HRK.js';
5
+ import '../../chunk-LTQOZIJO.js';
6
6
  import '../../chunk-6E6PKKAD.js';
7
7
  import '../../chunk-JB35MVBN.js';
8
8
  import '../../chunk-NSBPE2FW.js';
@@ -1,6 +1,6 @@
1
- import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-NIZNN42B.js';
1
+ import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-XW3SWH7C.js';
2
2
  import '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
3
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-JB35MVBN.js';
6
6
  import '../../chunk-NSBPE2FW.js';
@@ -1,5 +1,5 @@
1
1
  import { classifyGenericErrorMessage } from '../../chunk-GAH4YRCI.js';
2
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
2
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
3
3
  import '../../chunk-6E6PKKAD.js';
4
4
  import '../../chunk-JB35MVBN.js';
5
5
  import '../../chunk-NSBPE2FW.js';
@@ -1,6 +1,6 @@
1
- import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-NIZNN42B.js';
1
+ import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-XW3SWH7C.js';
2
2
  import '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
3
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-JB35MVBN.js';
6
6
  import '../../chunk-NSBPE2FW.js';
@@ -1,8 +1,8 @@
1
- import { GeminiFamilyDriver } from '../../chunk-CC6LFFTI.js';
2
- import '../../chunk-NIZNN42B.js';
1
+ import { GeminiFamilyDriver } from '../../chunk-6ZLMG5GR.js';
2
+ import '../../chunk-XW3SWH7C.js';
3
3
  import { fetchProviderModels } from '../../chunk-BMQKMOQY.js';
4
4
  import '../../chunk-GAH4YRCI.js';
5
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HLIN4HRK.js';
5
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-LTQOZIJO.js';
6
6
  import '../../chunk-6E6PKKAD.js';
7
7
  import '../../chunk-JB35MVBN.js';
8
8
  import '../../chunk-NSBPE2FW.js';
@@ -1,9 +1,9 @@
1
- export { BridgeRuntime, EventNormalizer, createRuntime, detectFileChange, detectFileChanges, summarizeToolCall, summarizeToolResult, validateApiKey } from '../chunk-G73FOLLO.js';
1
+ export { BridgeRuntime, EventNormalizer, createRuntime, detectFileChange, detectFileChanges, summarizeToolCall, summarizeToolResult, validateApiKey } from '../chunk-F3ET4UGP.js';
2
2
  export { CLOUD_SECRET_ENV_KEYS, SUPPORTED_CLOUDS, buildClaudeCloudEnv } from '../chunk-ISQWMBKD.js';
3
3
  export { dispatchCapability, filterRenderCapabilities, renderFallback } from '../chunk-RRVQAE5D.js';
4
4
  export { STATIC_MODELS, fetchProviderModels, getModels, getStaticModels } from '../chunk-BMQKMOQY.js';
5
5
  export { AccountUnavailableError, AuthError, classifyClaudeSdkError, reclassifyAuthAsAccountUnavailable } from '../chunk-GAH4YRCI.js';
6
- export { AgentDriver, BUILTIN_DRIVER_CATALOG, DRIVER_CATALOG, createDriver, getBridgeLogger, listDrivers, listModelsForDriver, registerBuiltinDrivers } from '../chunk-HLIN4HRK.js';
6
+ export { AgentDriver, BUILTIN_DRIVER_CATALOG, DRIVER_CATALOG, createDriver, getBridgeLogger, listDrivers, listModelsForDriver, registerBuiltinDrivers } from '../chunk-LTQOZIJO.js';
7
7
  import '../chunk-6E6PKKAD.js';
8
8
  import '../chunk-JB35MVBN.js';
9
9
  import '../chunk-NSBPE2FW.js';
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Minimal hand-rolled Bot Framework activity types and their normalization
3
+ * into the channels core's {@link ChannelMessage} (spec §7.1.2). No botbuilder:
4
+ * only the fields the adapter actually reads are typed.
5
+ */
6
+ import type { IdentityPort } from "../../src/ports.js";
7
+ import type { ChannelActor, ChannelMessage, ConversationKey } from "../../src/types.js";
8
+ /** A Bot Framework activity, reduced to the fields the Teams adapter consumes. */
9
+ export type TeamsActivity = {
10
+ /** "message", "messageReaction", "conversationUpdate", … */
11
+ type: string;
12
+ id: string;
13
+ timestamp?: string;
14
+ serviceUrl: string;
15
+ /** Always "msteams" for Teams traffic. */
16
+ channelId: string;
17
+ from: {
18
+ id: string;
19
+ name?: string;
20
+ aadObjectId?: string;
21
+ };
22
+ conversation: {
23
+ id: string;
24
+ tenantId?: string;
25
+ conversationType?: string;
26
+ };
27
+ /** The bot the activity was addressed to. */
28
+ recipient: {
29
+ id: string;
30
+ name?: string;
31
+ };
32
+ text?: string;
33
+ entities?: Array<{
34
+ type: string;
35
+ mentioned?: {
36
+ id: string;
37
+ name?: string;
38
+ };
39
+ text?: string;
40
+ }>;
41
+ replyToId?: string;
42
+ /** Action.Submit payload, e.g. `{ option }` from a question card. */
43
+ value?: unknown;
44
+ channelData?: {
45
+ tenant?: {
46
+ id: string;
47
+ };
48
+ };
49
+ };
50
+ /**
51
+ * `"19:x@thread;messageid=123"` → key `msteams:19:x@thread/123`; no messageid →
52
+ * channel-level key.
53
+ */
54
+ export declare function conversationKeyFromActivity(a: TeamsActivity): ConversationKey;
55
+ /** Teams tenant id — `conversation.tenantId` with the channelData fallback. */
56
+ export declare function tenantIdOfActivity(a: TeamsActivity): string | undefined;
57
+ /** The sending user as a {@link ChannelActor} (AAD object id preferred as externalId). */
58
+ export declare function actorOfActivity(a: TeamsActivity): ChannelActor;
59
+ /**
60
+ * Normalizes a message activity into a ChannelMessage (spec §7.1.2):
61
+ * payload { type:"prompt", prompt: textWithMentionTokensStripped },
62
+ * meta.channel { platform:"msteams", conversationKey, eventId: a.id, tenantId,
63
+ * actor, messageRef }, meta.mentions via normalize (bot recipient id ⇒ isBot
64
+ * entity). A text-less Action.Submit (question-card answer) uses its `option`
65
+ * as the prompt. Returns null for non-message activities and for the bot's own
66
+ * messages (a.from.id === a.recipient.id — the adapter-level loop filter,
67
+ * spec §8).
68
+ */
69
+ export declare function activityToChannelMessage(a: TeamsActivity, identity: IdentityPort): Promise<ChannelMessage | null>;
70
+ //# sourceMappingURL=activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../../channels/adapters/msteams/activity.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAc,MAAM,oBAAoB,CAAC;AAMpG,kFAAkF;AAClF,MAAM,MAAM,aAAa,GAAG;IAC1B,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3E,6CAA6C;IAC7C,SAAS,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CAC3C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,aAAa,GAAG,eAAe,CAQ7E;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,CAAC,EAAE,aAAa,GAAG,YAAY,CAO9D;AA0CD;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC5C,CAAC,EAAE,aAAa,EAChB,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA2ChC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The shared bottom-layer Bot Framework REST client (spec §4.1) — written once
3
+ * here, reused by the later agent-side tool-face step. Raw fetch only; no
4
+ * botbuilder.
5
+ */
6
+ /** Options for {@link MsTeamsClient}. */
7
+ export type MsTeamsClientOptions = {
8
+ appId: string;
9
+ clientSecret: string;
10
+ /** Default "https://login.microsoftonline.com/botframework.com" — injectable for mocks. */
11
+ loginBaseUrl?: string;
12
+ fetchImpl?: typeof fetch;
13
+ now?: () => number;
14
+ };
15
+ /** A failed connector-service call, with the HTTP status for callers to branch on. */
16
+ export declare class MsTeamsApiError extends Error {
17
+ readonly status: number;
18
+ constructor(status: number, message: string);
19
+ }
20
+ /**
21
+ * Minimal Bot Framework connector-service client: client_credentials token
22
+ * acquisition (cached) plus activity post/update against a channel-provided
23
+ * serviceUrl. Honors 429 Retry-After with jittered backoff, max 3 tries.
24
+ */
25
+ export declare class MsTeamsClient {
26
+ private readonly opts;
27
+ private readonly fetchImpl;
28
+ private readonly now;
29
+ private token?;
30
+ constructor(opts: MsTeamsClientOptions);
31
+ /** client_credentials token for scope https://api.botframework.com/.default; cached until exp-60s. */
32
+ getToken(): Promise<string>;
33
+ /** POST {serviceUrl}/v3/conversations/{conversationId}/activities[/{replyToId}] → { id }. */
34
+ postActivity(serviceUrl: string, conversationId: string, activity: Record<string, unknown>, replyToId?: string): Promise<{
35
+ id: string;
36
+ }>;
37
+ /** PUT {serviceUrl}/v3/conversations/{conversationId}/activities/{activityId}. Same retry policy. */
38
+ updateActivity(serviceUrl: string, conversationId: string, activityId: string, activity: Record<string, unknown>): Promise<void>;
39
+ private activitiesUrl;
40
+ /**
41
+ * Authorized JSON request honoring 429 Retry-After with jittered backoff,
42
+ * max 3 tries. One 401 forces a fresh token and a single immediate retry.
43
+ */
44
+ private request;
45
+ }
46
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../channels/adapters/msteams/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,yCAAyC;AACzC,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,2FAA2F;IAC3F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAEF,sFAAsF;AACtF,qBAAa,eAAgB,SAAQ,KAAK;IAEtC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;CAKlB;AAID;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAuB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,KAAK,CAAC,CAAuC;gBAEzC,IAAI,EAAE,oBAAoB;IAMtC,sGAAsG;IAChG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAsBjC,6FAA6F;IACvF,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAW1B,qGAAqG;IAC/F,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC;IAKhB,OAAO,CAAC,aAAa;IAKrB;;;OAGG;YACW,OAAO;CA6BtB"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * MS Teams {@link ChannelAdapter}: Bot Framework webhook ingress (JWT-verified,
3
+ * fast-acked) + connector-service egress via {@link MsTeamsClient}. Raw fetch
4
+ * only — no botbuilder. Identity stays with the engine: the adapter only tags
5
+ * `isBot` mention entities and never resolves users itself (Decision 16).
6
+ */
7
+ import type { AdapterContext, ChannelAdapter } from "../../src/adapter.js";
8
+ import type { ActorQuery, ChannelActor, ConversationHealth, ConversationKey, MessageRef, OutboundMessage, ReplyTarget, SurfaceCapabilities } from "../../src/types.js";
9
+ export * from "./activity.js";
10
+ export * from "./client.js";
11
+ export * from "./jwt.js";
12
+ /** Options for {@link MsTeamsAdapter}. */
13
+ export type MsTeamsAdapterOptions = {
14
+ /** Skaile's multi-tenant Entra app id (non-secret; the secret comes via CredentialPort). */
15
+ appId: string;
16
+ /** Default "/channels/msteams/messages". */
17
+ ingressPath?: string;
18
+ openIdMetadataUrl?: string;
19
+ loginBaseUrl?: string;
20
+ fetchImpl?: typeof fetch;
21
+ };
22
+ /**
23
+ * The MS Teams adapter (spec §6, plan Task 10). Webhook-style: `start` only
24
+ * registers the ingress route — there is no outbound socket. Egress posting
25
+ * requires the conversation to have been seen on ingress (serviceUrl + tenant
26
+ * are remembered per conversationKey; Bot Framework provides no directory).
27
+ */
28
+ export declare class MsTeamsAdapter implements ChannelAdapter {
29
+ readonly platform: "msteams";
30
+ readonly capabilities: SurfaceCapabilities;
31
+ private readonly opts;
32
+ private ctx?;
33
+ /** tenantId → lazily-created provider client (promise-cached to collapse races). */
34
+ private readonly clients;
35
+ /** Ingress-observed conversation facts, keyed by conversationKey (thread AND channel level). */
36
+ private readonly conversations;
37
+ /** Ingress-observed actors by externalId — the lookupActor roster. */
38
+ private readonly roster;
39
+ /** post() idempotency: dedupeKey → prior ref, TTL {@link DEDUPE_TTL_MS}. */
40
+ private readonly posted;
41
+ constructor(opts: MsTeamsAdapterOptions);
42
+ /** Registers the ingress route on the host; no connection is opened. */
43
+ start(ctx: AdapterContext): Promise<void>;
44
+ /** Drops the context and per-tenant clients; the host owns route teardown. */
45
+ stop(): Promise<void>;
46
+ /**
47
+ * The Bot Framework messaging endpoint. Guarded by a `Promise.race` at
48
+ * `ackDeadlineMs - 1000`: if processing overruns, Teams still gets its 200
49
+ * and at-least-once redelivery covers the rest.
50
+ */
51
+ readonly handleRequest: (req: Request) => Promise<Response>;
52
+ private processRequest;
53
+ /** Records serviceUrl + tenant under the thread key AND its channel-level key. */
54
+ private rememberConversation;
55
+ /** Grows the lookupActor roster from the sender and mention entities (bot excluded). */
56
+ private rememberActors;
57
+ /** Maps a messageReaction activity onto InboundReaction events (one per emoji). */
58
+ private forwardReactions;
59
+ /** Posts a message; a repeated `dedupeKey` returns the prior ref with no second side effect. */
60
+ post(target: ReplyTarget, msg: OutboundMessage, dedupeKey: string): Promise<MessageRef>;
61
+ /** Replaces a previously posted activity's content in place. */
62
+ update(ref: MessageRef, msg: OutboundMessage): Promise<void>;
63
+ /** Native Teams typing indicator — fire-and-forget, never deduped. */
64
+ indicateTyping(target: ReplyTarget): Promise<void>;
65
+ /** Preflight: a typing probe proves the bot can post; 403/404 → actionable problem. */
66
+ verifyConversation(key: ConversationKey): Promise<ConversationHealth>;
67
+ /** Resolves from the ingress-observed roster only (Graph lookup is platform glue, later). */
68
+ lookupActor(query: ActorQuery): Promise<ChannelActor | undefined>;
69
+ /** Decision 11: Adaptive Card for questions with options; markdown text otherwise. */
70
+ private buildActivity;
71
+ /** serviceUrl + native conversation id for a target — threadRef.raw first, ingress memory else. */
72
+ private resolveTarget;
73
+ /** Conversation facts under the exact key, falling back to its channel-level key. */
74
+ private infoFor;
75
+ /** One MsTeamsClient per tenant, built from CredentialPort (kind must be "msteams"). */
76
+ private clientForConversation;
77
+ private clientForTenant;
78
+ /** Live dedupe hit for `key`, sweeping expired entries opportunistically. */
79
+ private dedupeGet;
80
+ }
81
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../channels/adapters/msteams/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,eAAe,EAEf,UAAU,EACV,eAAe,EACf,WAAW,EACX,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAa5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AAiBzB,0CAA0C;AAC1C,MAAM,MAAM,qBAAqB,GAAG;IAClC,4FAA4F;IAC5F,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B,CAAC;AASF;;;;;GAKG;AACH,qBAAa,cAAe,YAAW,cAAc;IACnD,QAAQ,CAAC,QAAQ,EAAG,SAAS,CAAU;IACvC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAYxC;IAEF,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,GAAG,CAAC,CAAiB;IAC7B,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6C;IACrE,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgD;IAC9E,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6D;gBAExE,IAAI,EAAE,qBAAqB;IAIvC,wEAAwE;IAClE,KAAK,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/C,8EAA8E;IACxE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,GAAU,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAU9D;YAEY,cAAc;IA0C5B,kFAAkF;IAClF,OAAO,CAAC,oBAAoB;IAQ5B,wFAAwF;IACxF,OAAO,CAAC,cAAc;IAgBtB,mFAAmF;YACrE,gBAAgB;IA6B9B,gGAAgG;IAC1F,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAqB7F,gEAAgE;IAC1D,MAAM,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAelE,sEAAsE;IAChE,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxD,uFAAuF;IACjF,kBAAkB,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAmB3E,6FAA6F;IACvF,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAWvE,sFAAsF;IACtF,OAAO,CAAC,aAAa;IAoBrB,mGAAmG;IACnG,OAAO,CAAC,aAAa;IAgBrB,qFAAqF;IACrF,OAAO,CAAC,OAAO;IAOf,wFAAwF;IACxF,OAAO,CAAC,qBAAqB;IAY7B,OAAO,CAAC,eAAe;IAuBvB,6EAA6E;IAC7E,OAAO,CAAC,SAAS;CAOlB"}
@@ -0,0 +1,27 @@
1
+ /** Options for {@link validateBotFrameworkJwt}. */
2
+ export type JwtValidationOptions = {
3
+ /** The Skaile-published multi-tenant Entra app id — the expected `aud`. */
4
+ appId: string;
5
+ /** Default "https://login.botframework.com/v1/.well-known/openidconfiguration". */
6
+ openIdMetadataUrl?: string;
7
+ /** Default 300_000 (5 min). */
8
+ clockSkewMs?: number;
9
+ fetchImpl?: typeof fetch;
10
+ now?: () => number;
11
+ };
12
+ /** Outcome of {@link validateBotFrameworkJwt} — `reason` is safe to log, never secret. */
13
+ export type JwtValidationResult = {
14
+ ok: true;
15
+ } | {
16
+ ok: false;
17
+ reason: string;
18
+ };
19
+ /**
20
+ * Validates a Bot Framework channel→bot JWT (RS256 via the published JWKS):
21
+ * Bearer present, alg RS256, iss "https://api.botframework.com", aud === appId,
22
+ * exp/nbf within skew, serviceurl claim === the activity's serviceUrl.
23
+ * JWKS keys cached in-module by kid for 24h; an unknown kid forces one
24
+ * rate-limited refetch (key rotation) before the token is rejected.
25
+ */
26
+ export declare function validateBotFrameworkJwt(authorizationHeader: string | undefined, activityServiceUrl: string, opts: JwtValidationOptions): Promise<JwtValidationResult>;
27
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../../channels/adapters/msteams/jwt.ts"],"names":[],"mappings":"AAuBA,mDAAmD;AACnD,MAAM,MAAM,oBAAoB,GAAG;IACjC,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,CAAC;AAEF,0FAA0F;AAC1F,MAAM,MAAM,mBAAmB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA0E/E;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,mBAAmB,EAAE,MAAM,GAAG,SAAS,EACvC,kBAAkB,EAAE,MAAM,EAC1B,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAkD9B"}
@@ -0,0 +1,2 @@
1
+ // Auto-generated by _scripts/emit-dts-sidecars.ts — do not edit by hand.
2
+ export * from "./msteams/index.js";