@skaile/workspaces 0.41.6 → 0.42.1

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 (172) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/{asset-feeds-FKD5AB2R.js → asset-feeds-UPJJGR3O.js} +8 -8
  3. package/dist/{asset-feeds-FKD5AB2R.js.map → asset-feeds-UPJJGR3O.js.map} +1 -1
  4. package/dist/asset-manager/index.js +6 -6
  5. package/dist/asset-manager/installer.js +5 -5
  6. package/dist/bridge/drivers/claude-sdk.js +112 -7
  7. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  8. package/dist/bridge/drivers/codex.js +1 -1
  9. package/dist/bridge/drivers/continue.js +2 -2
  10. package/dist/bridge/drivers/echo.js +1 -1
  11. package/dist/bridge/drivers/gemini.js +3 -3
  12. package/dist/bridge/drivers/goose.js +2 -2
  13. package/dist/bridge/drivers/omp.js +1 -1
  14. package/dist/bridge/drivers/opencode.js +2 -2
  15. package/dist/bridge/drivers/qwen.js +3 -3
  16. package/dist/bridge/index.js +2 -2
  17. package/dist/bridge/src/drivers/claude-sdk.d.ts +6 -0
  18. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  19. package/dist/bridge/src/drivers/sanitize-assistant-text.d.ts +53 -0
  20. package/dist/bridge/src/drivers/sanitize-assistant-text.d.ts.map +1 -0
  21. package/dist/{chunk-J4RF5ABK.js → chunk-2BEDUMTA.js} +3 -3
  22. package/dist/{chunk-J4RF5ABK.js.map → chunk-2BEDUMTA.js.map} +1 -1
  23. package/dist/{chunk-5VJVSYXX.js → chunk-3HUUP3JC.js} +41 -3
  24. package/dist/chunk-3HUUP3JC.js.map +1 -0
  25. package/dist/{chunk-SBGHNXJD.js → chunk-3K2CYDBT.js} +17 -7
  26. package/dist/chunk-3K2CYDBT.js.map +1 -0
  27. package/dist/{chunk-2XFTGANB.js → chunk-4HKLAUHJ.js} +5 -5
  28. package/dist/{chunk-2XFTGANB.js.map → chunk-4HKLAUHJ.js.map} +1 -1
  29. package/dist/{chunk-5IXCNMMU.js → chunk-5C3QJSOD.js} +3 -3
  30. package/dist/{chunk-5IXCNMMU.js.map → chunk-5C3QJSOD.js.map} +1 -1
  31. package/dist/{chunk-TNYWP6EQ.js → chunk-5VMVNQGB.js} +6 -6
  32. package/dist/{chunk-TNYWP6EQ.js.map → chunk-5VMVNQGB.js.map} +1 -1
  33. package/dist/{chunk-B5PEERRZ.js → chunk-6IDBWPK2.js} +7 -4
  34. package/dist/chunk-6IDBWPK2.js.map +1 -0
  35. package/dist/{chunk-3KX5W3ZU.js → chunk-7WLJW457.js} +4 -4
  36. package/dist/{chunk-3KX5W3ZU.js.map → chunk-7WLJW457.js.map} +1 -1
  37. package/dist/{chunk-ZJ27BHIH.js → chunk-BXYMGZCI.js} +3 -3
  38. package/dist/{chunk-ZJ27BHIH.js.map → chunk-BXYMGZCI.js.map} +1 -1
  39. package/dist/{chunk-2ZI2FFFN.js → chunk-F5Q2RMH4.js} +229 -76
  40. package/dist/chunk-F5Q2RMH4.js.map +1 -0
  41. package/dist/{chunk-2JCUYKUN.js → chunk-G6FJZG4C.js} +2 -2
  42. package/dist/{chunk-2JCUYKUN.js.map → chunk-G6FJZG4C.js.map} +1 -1
  43. package/dist/{chunk-NQDJQ7WB.js → chunk-GJI6FZ56.js} +8 -4
  44. package/dist/chunk-GJI6FZ56.js.map +1 -0
  45. package/dist/{chunk-JAOXG3LL.js → chunk-HVCZLD5Z.js} +4 -4
  46. package/dist/{chunk-JAOXG3LL.js.map → chunk-HVCZLD5Z.js.map} +1 -1
  47. package/dist/{chunk-IODU6UDT.js → chunk-JZQFZ55W.js} +2 -2
  48. package/dist/{chunk-IODU6UDT.js.map → chunk-JZQFZ55W.js.map} +1 -1
  49. package/dist/{chunk-MO2VGW6U.js → chunk-K5TROTFK.js} +3 -3
  50. package/dist/{chunk-MO2VGW6U.js.map → chunk-K5TROTFK.js.map} +1 -1
  51. package/dist/{chunk-MVXXAXDW.js → chunk-KYQNWFJV.js} +3 -3
  52. package/dist/{chunk-MVXXAXDW.js.map → chunk-KYQNWFJV.js.map} +1 -1
  53. package/dist/{chunk-KM6DCR7A.js → chunk-OCAQH66V.js} +2 -2
  54. package/dist/{chunk-KM6DCR7A.js.map → chunk-OCAQH66V.js.map} +1 -1
  55. package/dist/{chunk-HZXOCRLD.js → chunk-OMAK7GNL.js} +78 -39
  56. package/dist/chunk-OMAK7GNL.js.map +1 -0
  57. package/dist/{chunk-X4FCLBI7.js → chunk-R4H6EJW5.js} +7 -5
  58. package/dist/chunk-R4H6EJW5.js.map +1 -0
  59. package/dist/{chunk-U3TV7SRR.js → chunk-RSK6FDMV.js} +3 -3
  60. package/dist/{chunk-U3TV7SRR.js.map → chunk-RSK6FDMV.js.map} +1 -1
  61. package/dist/{chunk-TB342H55.js → chunk-SURALYSM.js} +4 -4
  62. package/dist/{chunk-TB342H55.js.map → chunk-SURALYSM.js.map} +1 -1
  63. package/dist/{chunk-4NZD7423.js → chunk-WJ3RP2FS.js} +3 -3
  64. package/dist/{chunk-4NZD7423.js.map → chunk-WJ3RP2FS.js.map} +1 -1
  65. package/dist/{chunk-4ZACMAT3.js → chunk-Z3GAAIJK.js} +4 -4
  66. package/dist/{chunk-4ZACMAT3.js.map → chunk-Z3GAAIJK.js.map} +1 -1
  67. package/dist/cli/index.js +34 -34
  68. package/dist/connectors/config.js +5 -5
  69. package/dist/connectors/index.js +7 -7
  70. package/dist/connectors/rclone.js +1 -1
  71. package/dist/connectors/src/connector-manager.d.ts +17 -0
  72. package/dist/connectors/src/connector-manager.d.ts.map +1 -1
  73. package/dist/connectors/src/connector-types.d.ts +26 -0
  74. package/dist/connectors/src/connector-types.d.ts.map +1 -1
  75. package/dist/connectors/src/fleet-health-gate.d.ts +53 -36
  76. package/dist/connectors/src/fleet-health-gate.d.ts.map +1 -1
  77. package/dist/connectors/src/fleet-utils.d.ts +11 -2
  78. package/dist/connectors/src/fleet-utils.d.ts.map +1 -1
  79. package/dist/connectors/src/index.d.ts +3 -3
  80. package/dist/connectors/src/index.d.ts.map +1 -1
  81. package/dist/connectors/src/materialized-connectors.d.ts.map +1 -1
  82. package/dist/connectors/src/mount-placeholder.d.ts +19 -0
  83. package/dist/connectors/src/mount-placeholder.d.ts.map +1 -1
  84. package/dist/connectors/src/rclone-process-manager.d.ts +36 -2
  85. package/dist/connectors/src/rclone-process-manager.d.ts.map +1 -1
  86. package/dist/core/index.js +4 -4
  87. package/dist/core/manifest.js +1 -1
  88. package/dist/core/runtime-assets.js +3 -3
  89. package/dist/core/src/index.d.ts +1 -1
  90. package/dist/core/src/index.d.ts.map +1 -1
  91. package/dist/core/src/manifest.d.ts +11 -0
  92. package/dist/core/src/manifest.d.ts.map +1 -1
  93. package/dist/core/src/workspace-config.d.ts +2 -0
  94. package/dist/core/src/workspace-config.d.ts.map +1 -1
  95. package/dist/core/workspace-config.js +2 -2
  96. package/dist/deploy/index.js +4 -4
  97. package/dist/discovery/index.js +2 -2
  98. package/dist/{ensure-sources-EWK7EXKN.js → ensure-sources-TZHDV3BF.js} +8 -8
  99. package/dist/{ensure-sources-EWK7EXKN.js.map → ensure-sources-TZHDV3BF.js.map} +1 -1
  100. package/dist/factory-assets/connectors/deploy.js +7 -7
  101. package/dist/factory-assets/connectors/devserver.js +7 -7
  102. package/dist/factory-assets/connectors/flow/adapter.js +7 -7
  103. package/dist/factory-assets/connectors/flow/engine.js +4 -4
  104. package/dist/factory-assets/connectors/flow/run-flow.js +8 -8
  105. package/dist/factory-assets/connectors/flow.js +7 -7
  106. package/dist/factory-assets/connectors/git.js +7 -7
  107. package/dist/factory-assets/connectors/gmail.js +7 -7
  108. package/dist/factory-assets/connectors/googledrive/driver.d.ts.map +1 -1
  109. package/dist/factory-assets/connectors/googledrive.js +7 -7
  110. package/dist/factory-assets/connectors/local.js +7 -7
  111. package/dist/factory-assets/connectors/mattermost.js +7 -7
  112. package/dist/factory-assets/connectors/memory.js +7 -7
  113. package/dist/factory-assets/connectors/minio.js +7 -7
  114. package/dist/factory-assets/connectors/postgres.js +7 -7
  115. package/dist/factory-assets/connectors/s3.js +7 -7
  116. package/dist/factory-assets/connectors/sharepoint/driver.d.ts.map +1 -1
  117. package/dist/factory-assets/connectors/sharepoint.js +7 -7
  118. package/dist/factory-assets/connectors/sqlite.js +7 -7
  119. package/dist/factory-assets/connectors/static-server.js +7 -7
  120. package/dist/factory-assets/connectors/tunnel.js +7 -7
  121. package/dist/factory-assets/connectors/webdav/driver.d.ts.map +1 -1
  122. package/dist/factory-assets/connectors/webdav.js +7 -7
  123. package/dist/factory-assets/connectors/xstate-store.js +7 -7
  124. package/dist/factory-assets/connectors/xstate.js +7 -7
  125. package/dist/{flows-3MBK2PDN.js → flows-KTBCZ5GQ.js} +3 -3
  126. package/dist/{flows-3MBK2PDN.js.map → flows-KTBCZ5GQ.js.map} +1 -1
  127. package/dist/library/index.js +6 -6
  128. package/dist/library/install.js +4 -4
  129. package/dist/{open-library-QSIPFN5N.js → open-library-EV7UCOFU.js} +9 -9
  130. package/dist/{open-library-QSIPFN5N.js.map → open-library-EV7UCOFU.js.map} +1 -1
  131. package/dist/{paths-KNLBYALO.js → paths-7H5CSBLQ.js} +7 -7
  132. package/dist/{paths-KNLBYALO.js.map → paths-7H5CSBLQ.js.map} +1 -1
  133. package/dist/{plugin-store-CL6CTREE.js → plugin-store-LGLN2QUX.js} +6 -6
  134. package/dist/{plugin-store-CL6CTREE.js.map → plugin-store-LGLN2QUX.js.map} +1 -1
  135. package/dist/runner/index.js +11 -11
  136. package/dist/runner/src/fleet-health-flag-dispatcher.d.ts +3 -2
  137. package/dist/runner/src/fleet-health-flag-dispatcher.d.ts.map +1 -1
  138. package/dist/runner/src/mcp-prompt.d.ts +8 -0
  139. package/dist/runner/src/mcp-prompt.d.ts.map +1 -0
  140. package/dist/runner/src/resource-handler.d.ts +1 -1
  141. package/dist/runner/src/resource-handler.d.ts.map +1 -1
  142. package/dist/runner/src/resources.d.ts +6 -0
  143. package/dist/runner/src/resources.d.ts.map +1 -1
  144. package/dist/runner/src/session-builder.d.ts.map +1 -1
  145. package/dist/sdk/asset-manager.js +6 -6
  146. package/dist/sdk/bridge.js +2 -2
  147. package/dist/sdk/core.js +4 -4
  148. package/dist/sdk/flow.js +4 -4
  149. package/dist/sdk/index.js +11 -11
  150. package/dist/sdk/runner.js +11 -11
  151. package/dist/sdk/session.js +1 -1
  152. package/dist/session/index.js +1 -1
  153. package/dist/session/src/dispatcher.d.ts +8 -0
  154. package/dist/session/src/dispatcher.d.ts.map +1 -1
  155. package/dist/{setup-345XOCH3.js → setup-EVNPECSY.js} +8 -8
  156. package/dist/{setup-345XOCH3.js.map → setup-EVNPECSY.js.map} +1 -1
  157. package/dist/{store-client-W3HKRE46.js → store-client-4XN7IB3R.js} +7 -7
  158. package/dist/{store-client-W3HKRE46.js.map → store-client-4XN7IB3R.js.map} +1 -1
  159. package/dist/tui/index.js +11 -11
  160. package/dist/types/src/events.d.ts +1 -1
  161. package/dist/types/src/events.d.ts.map +1 -1
  162. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  163. package/dist/workspace-plugin/adapters/omp.js +3 -3
  164. package/dist/workspace-plugin/index.js +1 -1
  165. package/package.json +1 -1
  166. package/dist/chunk-2ZI2FFFN.js.map +0 -1
  167. package/dist/chunk-5VJVSYXX.js.map +0 -1
  168. package/dist/chunk-B5PEERRZ.js.map +0 -1
  169. package/dist/chunk-HZXOCRLD.js.map +0 -1
  170. package/dist/chunk-NQDJQ7WB.js.map +0 -1
  171. package/dist/chunk-SBGHNXJD.js.map +0 -1
  172. package/dist/chunk-X4FCLBI7.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,88 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.42.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#193](https://github.com/skaile-ai/workspaces/pull/193) [`baba456`](https://github.com/skaile-ai/workspaces/commit/baba4560efb4e710a89600552643cf06b1c4dac4) Thanks [@peteralbert](https://github.com/peteralbert)! - ConnectorManager now rejects two filesystem-face connectors that resolve to the
8
+ **same** absolute mount target. Previously both bound silently — one shadowing
9
+ the other, order-dependent — making the misconfig impossible to diagnose from the
10
+ runtime. Setup now throws a clear error naming both connector ids and the shared
11
+ path; a nested-target overlap (e.g. `/skaile` vs `/skaile/workspace`) is logged
12
+ as a warning. Distinct targets, including the per-id default `.mounts/<id>`, are
13
+ unaffected.
14
+
15
+ ## 0.42.0
16
+
17
+ ### Minor Changes
18
+
19
+ - [#187](https://github.com/skaile-ai/workspaces/pull/187) [`67b88c7`](https://github.com/skaile-ai/workspaces/commit/67b88c75be6ef0aae6a20f28e62de412c7a998d1) Thanks [@peteralbert](https://github.com/peteralbert)! - Runner reads CONNECTOR.md/MCP.md body and injects preset custom instructions into the agent system prompt. `ConnectorDeclaration` and `McpServerDeclaration` gain an optional `instructions` field populated from the materialized markdown body. Connector instructions are emitted eagerly in the `## Connectors` system-prompt section; MCP server instructions in a new `## MCP server guidance` section. When the body is empty (today's platform output) no block is added — safe to ship ahead of the platform side.
20
+
21
+ - [#186](https://github.com/skaile-ai/workspaces/pull/186) [`83c7f9c`](https://github.com/skaile-ai/workspaces/commit/83c7f9c4651aea27df0db220f4e9ff9ce80be89a) Thanks [@peteralbert](https://github.com/peteralbert)! - Fix the rclone VFS stale-tail read bug at the source ([#183](https://github.com/skaile-ai/workspaces/issues/183)). A writable
22
+ rclone-backed mount (SharePoint / OneDrive / WebDAV / Google Drive) can serve a
23
+ **non-truncated** VFS cache item after a remote file is replaced by a _shorter_
24
+ version: the read returns `[new bytes][leftover tail of the older, longer
25
+ version]`, and `statSync` reports the inflated size, so the on-disk length is no
26
+ signal. This used to be masked by the `text/html` `</html>`-truncation heuristic
27
+ removed in 0.41.6.
28
+
29
+ The read path now gates the served bytes against the **authoritative remote
30
+ size** instead of any content heuristic:
31
+
32
+ - `RcloneProcessManager.statSize(handle, relPath)` queries the `operations/stat`
33
+ rc endpoint, which resolves the object against the backend directly and so
34
+ returns the true remote size, bypassing the VFS cache. New exported helpers
35
+ `fetchAuthoritativeSize` (and the internal `_operationsStatTarget`) back it.
36
+ - The `sharepoint` / `webdav` / `googledrive` connectors attach an
37
+ `authoritativeSize(relPath)` hook (new `AuthoritativeSizeProvider` type) to
38
+ their `ConnectorHandle.state`, wired to `statSize`.
39
+ - `handleMountResourceRequest` (now async) duck-types that hook and truncates
40
+ the read to the authoritative size — slicing the Buffer _before_ any utf-8
41
+ decode, so multibyte content is never split mid-character. Absent hook (local
42
+ mounts) or `null` (object missing / rc call failed) ⇒ on-disk bytes served
43
+ unchanged.
44
+
45
+ Other candidate fixes were rejected: `vfs/forget` + re-read (re-downloads on
46
+ every changed read), tuning `--vfs-cache-mode`/`--dir-cache-time` (per-read
47
+ latency, doesn't address the non-truncation), and write-path `O_TRUNC` (our
48
+ write path already truncates via FUSE; the bug is on remote-side rewrites).
49
+ Fleet-managed mounts have no in-container rc server, so the host fleet remains
50
+ responsible for their invalidation — a documented follow-up.
51
+
52
+ All additions are new exports; no public surface was removed.
53
+
54
+ ### Patch Changes
55
+
56
+ - [#189](https://github.com/skaile-ai/workspaces/pull/189) [`81e2da1`](https://github.com/skaile-ai/workspaces/commit/81e2da1a8a1cce5ebca4252afa4e7e2366e1da64) Thanks [@peteralbert](https://github.com/peteralbert)! - Fleet read-only mount barrier now tracks the actual mount state across three surfaces instead of two. A `healthy` fleet-health verdict lifts the connect-time not-ready barrier (previously a late-arriving live bind that propagated under the barrier stayed masked even after it went healthy), and a connector that only had the static boot-time barrier is promoted to a health gate when a fleet verdict arrives, so the authoritative platform signal can lift it. A new `degraded` verdict (live and readable but writes failing) downgrades the barrier to a read-only-readable surface — the live content stays visible while writes are blocked — via the new `MountPlaceholderBarrier.exposeReadOnly` (read-only self-bind, chmod fallback) instead of masking the whole workspace with an opaque tmpfs. The not-live/unreadable `error` verdict keeps the opaque mask. The fleet-health flag dispatcher forwards `degraded` distinctly rather than collapsing it to `error`.
57
+
58
+ - [#190](https://github.com/skaile-ai/workspaces/pull/190) [`b862087`](https://github.com/skaile-ai/workspaces/commit/b8620870f88876cd4fbd023896aecf18a12b31f8) Thanks [@peteralbert](https://github.com/peteralbert)! - Stop an agent assistant message from swallowing the conversation ([#841](https://github.com/skaile-ai/workspaces/issues/841)). A
59
+ single agent `text` block could run three things together: verbatim
60
+ `[function_calls]…[invoke name="Bash"]…[/antml:invoke]` tool-call XML (the same call
61
+ was _also_ executed as a structured tool_use), the genuine answer, and a
62
+ hallucinated `[User]: "…"` follow-up turn — so the user's real next message
63
+ never became its own prompt and the chat looked garbled.
64
+
65
+ Two-part fix:
66
+
67
+ - **Prompt shape (primary).** `enrichPromptWithHistory` (session dispatcher) no
68
+ longer renders prior turns as a bare `[User]:` / `[Assistant]:` transcript,
69
+ which the model latched onto and auto-completed. History is now emitted as
70
+ read-only `<turn role="…">…</turn>` elements inside `<conversation_history>`
71
+ with an explicit "do not continue this — it is context, not a turn to extend"
72
+ instruction, removing the completion affordance.
73
+
74
+ - **Emit-point sanitizer (defense-in-depth).** A new pure
75
+ `sanitizeAssistantText` (bridge, beside `scrub-transcript.ts`) strips leaked
76
+ `[function_calls]…[/function_calls]` / `[invoke]…[/antml:invoke]` blocks and trailing
77
+ fabricated `[User]:` / `[Assistant]:` role turns from assistant text before it
78
+ is emitted/persisted. It is conservative — only clearly-leaked control markup
79
+ is removed; mid-prose bracketed text survives. It runs at every claude-sdk
80
+ emit point that produces durable assistant text: the final `result.summary`
81
+ (the single persisted copy of the answer), per-text-block mapping, and the
82
+ streaming path. For streaming, `streamingSafeSanitize` holds back any trailing
83
+ partial marker and the forwarded `_textDelta` carries the sanitized suffix, so
84
+ a marker split across deltas is never half-emitted into the stored transcript.
85
+
3
86
  ## 0.41.6
4
87
 
5
88
  ### Patch Changes
@@ -1,9 +1,9 @@
1
- import './chunk-MVXXAXDW.js';
1
+ import './chunk-KYQNWFJV.js';
2
2
  import './chunk-ZAP2BDHG.js';
3
- import { factoryAssetRoots } from './chunk-JAOXG3LL.js';
4
- import { scanRepo } from './chunk-NQDJQ7WB.js';
3
+ import { factoryAssetRoots } from './chunk-HVCZLD5Z.js';
4
+ import { scanRepo } from './chunk-GJI6FZ56.js';
5
5
  import './chunk-DZCK7GRW.js';
6
- import './chunk-B5PEERRZ.js';
6
+ import './chunk-6IDBWPK2.js';
7
7
  import './chunk-GEEW6SY2.js';
8
8
  import './chunk-XGCXFX7X.js';
9
9
  import './chunk-O4JH3KUE.js';
@@ -17,7 +17,7 @@ async function libraryAssets() {
17
17
  const notes = [];
18
18
  try {
19
19
  const [{ openLibraryManager }, { skaileHomeDir }] = await Promise.all([
20
- import('./open-library-QSIPFN5N.js'),
20
+ import('./open-library-EV7UCOFU.js'),
21
21
  import('./library/index.js')
22
22
  ]);
23
23
  const { manager, close } = await openLibraryManager();
@@ -46,7 +46,7 @@ async function libraryAssets() {
46
46
  async function storeAssets(projectDir) {
47
47
  const notes = [];
48
48
  try {
49
- const { resolveCatalogSource } = await import('./open-library-QSIPFN5N.js');
49
+ const { resolveCatalogSource } = await import('./open-library-EV7UCOFU.js');
50
50
  const { source, close } = await resolveCatalogSource({ projectDir });
51
51
  try {
52
52
  const assets = await source.listAssets();
@@ -120,5 +120,5 @@ async function gatherAssetFeeds(am, projectDir) {
120
120
  }
121
121
 
122
122
  export { gatherAssetFeeds };
123
- //# sourceMappingURL=asset-feeds-FKD5AB2R.js.map
124
- //# sourceMappingURL=asset-feeds-FKD5AB2R.js.map
123
+ //# sourceMappingURL=asset-feeds-UPJJGR3O.js.map
124
+ //# sourceMappingURL=asset-feeds-UPJJGR3O.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-FKD5AB2R.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 } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n scanRepo,\n} from \"@skaile/workspaces/core\";\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\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/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and tagged with\n * `repository = \"library:<name>\"` so the manage TUI groups them into their\n * own headers.\n */\nasync function libraryAssets(): Promise<{ entries: CatalogEntry[]; notes: FeedNote[] }> {\n const notes: FeedNote[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n const sourcesDir = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter((l) => !l.path.startsWith(sourcesDir));\n const entries: CatalogEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n for (const e of scanRepo(lib.path, `library:${lib.name}`)) {\n entries.push(e);\n }\n }\n return { entries, 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: [], 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/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map. Provided as a\n * function rather than an inline call so the caller can supply a fresh\n * `AssetManager` instance.\n */\nfunction sourceAssets(am: { search: () => CatalogEntry[] }): CatalogEntry[] {\n return am.search();\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[]; notes: FeedNote[] } {\n const notes: FeedNote[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n for (const e of scanRepo(root, \"skaile-factory\")) entries.push(e);\n }\n return { entries, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], 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: { search: () => CatalogEntry[] },\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = factoryAssets();\n return {\n entries: [\n ...tag(\"source\", sourceAssets(am)),\n ...tag(\"library\", libs.entries),\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n domains: store.domains,\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n"]}
1
+ {"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-UPJJGR3O.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 } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n scanRepo,\n} from \"@skaile/workspaces/core\";\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\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/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and tagged with\n * `repository = \"library:<name>\"` so the manage TUI groups them into their\n * own headers.\n */\nasync function libraryAssets(): Promise<{ entries: CatalogEntry[]; notes: FeedNote[] }> {\n const notes: FeedNote[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n const sourcesDir = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter((l) => !l.path.startsWith(sourcesDir));\n const entries: CatalogEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n for (const e of scanRepo(lib.path, `library:${lib.name}`)) {\n entries.push(e);\n }\n }\n return { entries, 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: [], 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/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map. Provided as a\n * function rather than an inline call so the caller can supply a fresh\n * `AssetManager` instance.\n */\nfunction sourceAssets(am: { search: () => CatalogEntry[] }): CatalogEntry[] {\n return am.search();\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[]; notes: FeedNote[] } {\n const notes: FeedNote[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n for (const e of scanRepo(root, \"skaile-factory\")) entries.push(e);\n }\n return { entries, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], 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: { search: () => CatalogEntry[] },\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = factoryAssets();\n return {\n entries: [\n ...tag(\"source\", sourceAssets(am)),\n ...tag(\"library\", libs.entries),\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n domains: store.domains,\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n"]}
@@ -1,11 +1,11 @@
1
- export { AssetManager, parseCanonicalLockKey } from '../chunk-TNYWP6EQ.js';
2
- export { createScaffold, deployAll, installAgent, removeAsset } from '../chunk-TB342H55.js';
3
- import '../chunk-MVXXAXDW.js';
1
+ export { AssetManager, parseCanonicalLockKey } from '../chunk-5VMVNQGB.js';
2
+ export { createScaffold, deployAll, installAgent, removeAsset } from '../chunk-SURALYSM.js';
3
+ import '../chunk-KYQNWFJV.js';
4
4
  import '../chunk-ZAP2BDHG.js';
5
- import '../chunk-JAOXG3LL.js';
6
- import '../chunk-NQDJQ7WB.js';
5
+ import '../chunk-HVCZLD5Z.js';
6
+ import '../chunk-GJI6FZ56.js';
7
7
  import '../chunk-DZCK7GRW.js';
8
- import '../chunk-B5PEERRZ.js';
8
+ import '../chunk-6IDBWPK2.js';
9
9
  import '../chunk-GEEW6SY2.js';
10
10
  import '../chunk-XGCXFX7X.js';
11
11
  import '../chunk-O4JH3KUE.js';
@@ -1,10 +1,10 @@
1
- export { createScaffold, deployAll, deployAsset, removeAsset } from '../chunk-TB342H55.js';
2
- import '../chunk-MVXXAXDW.js';
1
+ export { createScaffold, deployAll, deployAsset, removeAsset } from '../chunk-SURALYSM.js';
2
+ import '../chunk-KYQNWFJV.js';
3
3
  import '../chunk-ZAP2BDHG.js';
4
- import '../chunk-JAOXG3LL.js';
5
- import '../chunk-NQDJQ7WB.js';
4
+ import '../chunk-HVCZLD5Z.js';
5
+ import '../chunk-GJI6FZ56.js';
6
6
  import '../chunk-DZCK7GRW.js';
7
- import '../chunk-B5PEERRZ.js';
7
+ import '../chunk-6IDBWPK2.js';
8
8
  import '../chunk-GEEW6SY2.js';
9
9
  import '../chunk-XGCXFX7X.js';
10
10
  import '../chunk-O4JH3KUE.js';
@@ -1,7 +1,7 @@
1
1
  import { dispatchCapability } from '../../chunk-RRVQAE5D.js';
2
2
  import { fetchProviderModels } from '../../chunk-BMQKMOQY.js';
3
3
  import { AuthError, classifyClaudeSdkError, reclassifyAuthAsAccountUnavailable, AccountUnavailableError } from '../../chunk-GAH4YRCI.js';
4
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-KM6DCR7A.js';
4
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-OCAQH66V.js';
5
5
  import '../../chunk-6E6PKKAD.js';
6
6
  import '../../chunk-JB35MVBN.js';
7
7
  import '../../chunk-NSBPE2FW.js';
@@ -12,6 +12,97 @@ import { homedir } from 'os';
12
12
  import { join } from 'path';
13
13
  import * as zNS from 'zod';
14
14
 
15
+ // bridge/src/drivers/sanitize-assistant-text.ts
16
+ var NS = "(?:[a-z][a-z0-9]*:)?";
17
+ var FUNCTION_CALL_BLOCK = new RegExp(
18
+ `\\[\\s*${NS}function_calls\\s*\\][\\s\\S]*?\\[\\s*/\\s*${NS}function_calls\\s*\\]`,
19
+ "gi"
20
+ );
21
+ var INVOKE_BLOCK = new RegExp(
22
+ `\\[\\s*${NS}invoke\\b[\\s\\S]*?\\[\\s*/\\s*${NS}invoke\\s*\\]`,
23
+ "gi"
24
+ );
25
+ var ROLE_TURN_LINE = /^\s*\[(?:User|Assistant|System)\]\s*:/i;
26
+ function sanitizeAssistantText(text) {
27
+ if (!text || text.indexOf("[") === -1 && text.indexOf("]") === -1) {
28
+ return text;
29
+ }
30
+ const stripped = text.replace(FUNCTION_CALL_BLOCK, "").replace(INVOKE_BLOCK, "");
31
+ let changed = stripped !== text;
32
+ let out = stripped;
33
+ const lines = out.split("\n");
34
+ let end = lines.length;
35
+ for (let i = lines.length - 1; i >= 0; i--) {
36
+ const line = lines[i] ?? "";
37
+ if (line.trim() === "") {
38
+ continue;
39
+ }
40
+ if (ROLE_TURN_LINE.test(line)) {
41
+ end = i;
42
+ continue;
43
+ }
44
+ break;
45
+ }
46
+ if (end < lines.length) {
47
+ out = lines.slice(0, end).join("\n");
48
+ changed = true;
49
+ }
50
+ return changed ? out.replace(/\s+$/, "") : out;
51
+ }
52
+ var TAG_PREFIXES = [
53
+ "function_call",
54
+ "function_cal",
55
+ "function_ca",
56
+ "function_c",
57
+ "function_",
58
+ "function",
59
+ "functio",
60
+ "functi",
61
+ "funct",
62
+ "func",
63
+ "fun",
64
+ "fu",
65
+ "f",
66
+ "invoke",
67
+ "invok",
68
+ "invo",
69
+ "inv",
70
+ "in",
71
+ "i",
72
+ "user",
73
+ "use",
74
+ "us",
75
+ "u",
76
+ "assistant",
77
+ "assistan",
78
+ "assista",
79
+ "assist",
80
+ "assis",
81
+ "assi",
82
+ "ass",
83
+ "as",
84
+ "a",
85
+ "system",
86
+ "syste",
87
+ "syst",
88
+ "sys",
89
+ "sy",
90
+ "s"
91
+ ].join("|");
92
+ var PARTIAL_MARKER_TAIL = new RegExp(`\\[\\s*/?\\s*${NS}(?:${TAG_PREFIXES})?[^\\]]*$`, "i");
93
+ var UNCLOSED_OPENER = new RegExp(`\\[\\s*${NS}function_calls\\s*\\]|\\[\\s*${NS}invoke\\b`, "i");
94
+ function streamingSafeSanitize(text) {
95
+ let cleaned = sanitizeAssistantText(text);
96
+ const opener = UNCLOSED_OPENER.exec(cleaned);
97
+ if (opener && opener.index >= 0) {
98
+ cleaned = cleaned.slice(0, opener.index);
99
+ }
100
+ const tail = PARTIAL_MARKER_TAIL.exec(cleaned);
101
+ if (tail && tail.index >= 0) {
102
+ cleaned = cleaned.slice(0, tail.index);
103
+ }
104
+ return cleaned.replace(/\s+$/, "");
105
+ }
15
106
  var STUB_TEXT = "[image removed: unprocessable image data]";
16
107
  var STUB_TEXT_OVERSIZED = "[image removed: image too large]";
17
108
  var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
@@ -235,6 +326,12 @@ var ClaudeSdkDriver = class extends AgentDriver {
235
326
  sdk = null;
236
327
  toolIdToName = /* @__PURE__ */ new Map();
237
328
  prevText = "";
329
+ /**
330
+ * Count of sanitized characters already streamed for the current message.
331
+ * Lets {@link handleStreamEvent} emit only the newly-stable sanitized suffix
332
+ * as `_textDelta`, so a leaked marker that spans deltas is never half-sent.
333
+ */
334
+ emittedSanitizedLen = 0;
238
335
  /** Set once the streaming text of the current message classifies as a self-healable auth render. */
239
336
  suppressingAuthStream = false;
240
337
  /** Active query — may stay alive between turns if streamInput works. */
@@ -338,6 +435,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
338
435
  if (isFirstAttempt) this._lastTokens = null;
339
436
  this.running = true;
340
437
  this.prevText = "";
438
+ this.emittedSanitizedLen = 0;
341
439
  this.suppressingAuthStream = false;
342
440
  this.turnCompleted = false;
343
441
  const turnPromise = new Promise((resolve, reject) => {
@@ -928,6 +1026,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
928
1026
  if (this.isSuppressibleAuthRender(agentMsg)) {
929
1027
  this.log.info("suppressing SDK auth-error assistant text; self-heal will retry");
930
1028
  this.prevText = "";
1029
+ this.emittedSanitizedLen = 0;
931
1030
  this.suppressingAuthStream = false;
932
1031
  return;
933
1032
  }
@@ -943,6 +1042,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
943
1042
  }
944
1043
  }
945
1044
  this.prevText = "";
1045
+ this.emittedSanitizedLen = 0;
946
1046
  this.suppressingAuthStream = false;
947
1047
  this.emit("agent-event", { type: "message_end", message: agentMsg });
948
1048
  }
@@ -973,14 +1073,18 @@ var ClaudeSdkDriver = class extends AgentDriver {
973
1073
  this.log.info("suppressing SDK auth-error stream; self-heal will retry");
974
1074
  }
975
1075
  if (this.suppressingAuthStream) return;
1076
+ const safe = streamingSafeSanitize(this.prevText);
1077
+ const sanitizedDelta = safe.slice(this.emittedSanitizedLen);
1078
+ this.emittedSanitizedLen = safe.length;
1079
+ if (sanitizedDelta.length === 0) return;
976
1080
  const agentMsg = {
977
1081
  role: "assistant",
978
- content: [{ type: "text", text: this.prevText }]
1082
+ content: [{ type: "text", text: safe }]
979
1083
  };
980
1084
  this.emit("agent-event", {
981
1085
  type: "message_update",
982
1086
  message: agentMsg,
983
- _textDelta: delta
1087
+ _textDelta: sanitizedDelta
984
1088
  });
985
1089
  }
986
1090
  }
@@ -1029,17 +1133,18 @@ var ClaudeSdkDriver = class extends AgentDriver {
1029
1133
  }
1030
1134
  /** Emit the message_end (if any) + success result event for a clean turn. */
1031
1135
  handleSuccessResult(msg) {
1032
- if (msg.result) {
1136
+ const result = msg.result != null ? sanitizeAssistantText(msg.result) : msg.result;
1137
+ if (result) {
1033
1138
  const agentMsg = {
1034
1139
  role: "assistant",
1035
- content: msg.result
1140
+ content: result
1036
1141
  };
1037
1142
  this.emit("agent-event", { type: "message_end", message: agentMsg });
1038
1143
  }
1039
1144
  this.emit("agent-event", {
1040
1145
  type: "result",
1041
1146
  subtype: msg.subtype,
1042
- summary: msg.result ?? "Task completed",
1147
+ summary: result ?? "Task completed",
1043
1148
  costUsd: msg.total_cost_usd ?? 0,
1044
1149
  ...this._lastTokens ? { tokens: this._lastTokens } : {}
1045
1150
  });
@@ -1121,7 +1226,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
1121
1226
  if (Array.isArray(content)) {
1122
1227
  for (const block of content) {
1123
1228
  if (block.type === "text") {
1124
- contentBlocks.push({ type: "text", text: block.text });
1229
+ contentBlocks.push({ type: "text", text: sanitizeAssistantText(block.text) });
1125
1230
  } else if (block.type === "tool_use") {
1126
1231
  contentBlocks.push({
1127
1232
  type: "tool_use",