@xopcai/xopc 0.0.277 → 0.0.282

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 (315) hide show
  1. package/dist/browser-ext/_locales/en/messages.json +34 -4
  2. package/dist/browser-ext/_locales/zh_CN/messages.json +34 -4
  3. package/dist/browser-ext/dist/assets/{auth-ClQTK565.js → auth-DB30ywek.js} +18 -53
  4. package/dist/browser-ext/dist/assets/pcm-capture-worklet-CGN9Mlhg.js +39 -0
  5. package/dist/browser-ext/dist/assets/{sidepanel-CeGqObOa.css → sidepanel-BbSQr-6P.css} +40 -6
  6. package/dist/browser-ext/dist/background.js +1 -1
  7. package/dist/browser-ext/dist/sidepanel.html +2 -2
  8. package/dist/browser-ext/dist/sidepanel.js +1219 -191
  9. package/dist/browser-ext/manifest.json +2 -1
  10. package/dist/extensions/telegram/xopc.extension.json +1 -1
  11. package/dist/gateway/static/root/assets/{activity-store-SJZ5fS17.js → activity-store-iPtG94qr.js} +1 -1
  12. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Cavbls0E.js → agent-avatar-dicebear-Cny5rATT.js} +1 -1
  13. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-OyQ8OVZv.js +1 -0
  14. package/dist/gateway/static/root/assets/{agents-DlDTItrB.js → agents-DJeh_Ewo.js} +1 -1
  15. package/dist/gateway/static/root/assets/{api-CnJAVHBu.js → api-KMJzMqvZ.js} +1 -1
  16. package/dist/gateway/static/root/assets/{app-management-settings-panel-5gS0_LWl.js → app-management-settings-panel-ZqQKaZEI.js} +1 -1
  17. package/dist/gateway/static/root/assets/{appearance-settings-DHzZCJon.js → appearance-settings-CfXsQkKO.js} +1 -1
  18. package/dist/gateway/static/root/assets/apps-page-k-QnVhKW.js +1 -0
  19. package/dist/gateway/static/root/assets/{archive-plugin-Ia98yZe3.js → archive-plugin-BrW53Hap.js} +1 -1
  20. package/dist/gateway/static/root/assets/{attachment-load-DiWW88c8.js → attachment-load-DkfFWHiS.js} +1 -1
  21. package/dist/gateway/static/root/assets/{automations-page-BuhTeGRJ.js → automations-page-e-5we6kD.js} +1 -1
  22. package/dist/gateway/static/root/assets/automations-workspace-DPnlkws1.js +6 -0
  23. package/dist/gateway/static/root/assets/{binary-plugins-DDD48cJv.js → binary-plugins-CWIswfXA.js} +1 -1
  24. package/dist/gateway/static/root/assets/{block-editor-0AWVCD3F.js → block-editor-CfeF1OmA.js} +3 -3
  25. package/dist/gateway/static/root/assets/{browser-automation-inputs-DcVLoIzc.js → browser-automation-inputs-BTIufVbM.js} +1 -1
  26. package/dist/gateway/static/root/assets/{browser-automations-page-BKOYX5xV.js → browser-automations-page-DnsuWKRu.js} +2 -2
  27. package/dist/gateway/static/root/assets/browser-settings-page-C8xyhnxx.js +8 -0
  28. package/dist/gateway/static/root/assets/capabilities-settings-panel-CBllOLTT.js +8 -0
  29. package/dist/gateway/static/root/assets/channels-settings-C-A-VUE2.js +1 -0
  30. package/dist/gateway/static/root/assets/{channels-status-swr-BTT2sIGg.js → channels-status-swr-DMYQNs-J.js} +1 -1
  31. package/dist/gateway/static/root/assets/{chat-terminal-dock-CW9Byi8V.js → chat-terminal-dock-C_Fw1R3A.js} +2 -2
  32. package/dist/gateway/static/root/assets/connectors-page-CtsMo3H4.js +2 -0
  33. package/dist/gateway/static/root/assets/{date-picker-gdYmKC8W.js → date-picker-CPFxjTrN.js} +1 -1
  34. package/dist/gateway/static/root/assets/{dependency-picker-40BYmiMc.js → dependency-picker-C_5KqzjI.js} +1 -1
  35. package/dist/gateway/static/root/assets/{desktop-pet-By1z6tKE.js → desktop-pet-DLJsC5D6.js} +1 -1
  36. package/dist/gateway/static/root/assets/{desktop-pet-settings-ByjJqx9H.js → desktop-pet-settings-BdI1iSgz.js} +1 -1
  37. package/dist/gateway/static/root/assets/device-pairing-wizard-BnvPLhc9.js +1 -0
  38. package/dist/gateway/static/root/assets/{extension-debug-page-DQO65KbM.js → extension-debug-page-BNS_TkZQ.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-page-Db32jip6.js → extension-page-DMSDZ7Mb.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-settings-page-CL8Wx8lf.js → extension-settings-page-CeGCWMt0.js} +1 -1
  41. package/dist/gateway/static/root/assets/gateway-config-swr-Cpmyrr6j.js +1 -0
  42. package/dist/gateway/static/root/assets/gateway-settings-DKOTYUma.js +1 -0
  43. package/dist/gateway/static/root/assets/{gateway-startup-retry-CVTa5HSS.js → gateway-startup-retry-DoiPeb65.js} +1 -1
  44. package/dist/gateway/static/root/assets/{heartbeat-settings-CRXWu2q6.js → heartbeat-settings-gsdL_Yij.js} +1 -1
  45. package/dist/gateway/static/root/assets/home-page-CbeAdS1T.js +1 -0
  46. package/dist/gateway/static/root/assets/{image-generation-api-DtMRG1oF.js → image-generation-api-CqjHWl2T.js} +1 -1
  47. package/dist/gateway/static/root/assets/index-B_Sg5BKz.css +2 -0
  48. package/dist/gateway/static/root/assets/index-enFXJJCU.js +74 -0
  49. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CjehhHPz.js → keyboard-shortcuts-settings-CCLtJ8s8.js} +1 -1
  50. package/dist/gateway/static/root/assets/local-app-workbench-page-DzC6SrXj.js +2 -0
  51. package/dist/gateway/static/root/assets/{local-apps-page-CrIdaTrK.js → local-apps-page-3LdgP3NO.js} +1 -1
  52. package/dist/gateway/static/root/assets/{locale-store-BkJ7g35d.js → locale-store-1urrBBCQ.js} +1 -1
  53. package/dist/gateway/static/root/assets/{logs-page-FfSwV_VH.js → logs-page-DHClKtm6.js} +2 -2
  54. package/dist/gateway/static/root/assets/{management-settings-BakV5aOw.js → management-settings-BaCo9Nuo.js} +1 -1
  55. package/dist/gateway/static/root/assets/{markdown-view-DF3aJP_5.js → markdown-view-BZmcFIWa.js} +1 -1
  56. package/dist/gateway/static/root/assets/{media-plugins-Blv9U6Jp.js → media-plugins-BMjJppvG.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-DYFcjtmG.js +3 -0
  58. package/dist/gateway/static/root/assets/note-detail-panel-hYO2jNhL.js +5 -0
  59. package/dist/gateway/static/root/assets/notes-page-BT66x22W.js +8 -0
  60. package/dist/gateway/static/root/assets/{page-tabs-BQfVtLLC.js → page-tabs-BCszXX_F.js} +1 -1
  61. package/dist/gateway/static/root/assets/{preview-open-alternatives-kjHFiO81.js → preview-open-alternatives-CyM0sanh.js} +1 -1
  62. package/dist/gateway/static/root/assets/proactive-page-CVDGA5sB.js +1 -0
  63. package/dist/gateway/static/root/assets/{product-open-page-BazdmFYo.js → product-open-page-lXAbj85Z.js} +1 -1
  64. package/dist/gateway/static/root/assets/project-detail-page-Bp6TAMPM.js +1 -0
  65. package/dist/gateway/static/root/assets/projects-page-UhOIiDcg.js +1 -0
  66. package/dist/gateway/static/root/assets/{registry-api-CTq8EECj.js → registry-api-CxQstD00.js} +1 -1
  67. package/dist/gateway/static/root/assets/remote-access-hub-DJIkMFT4.js +1 -0
  68. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BhJlopSW.js → runtime-tools-settings-panel-BUFCgRdZ.js} +2 -2
  69. package/dist/gateway/static/root/assets/{schema-form-cxoO_5I1.js → schema-form-B01ksA8M.js} +1 -1
  70. package/dist/gateway/static/root/assets/sessions-page-CQOAwPDt.js +1 -0
  71. package/dist/gateway/static/root/assets/settings-advanced-gate-CFuqbGI-.js +1 -0
  72. package/dist/gateway/static/root/assets/{settings-form-section-BiRTWiBi.js → settings-form-section-DvnjZBa3.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-page-D-Cb71pq.js → settings-page-DZRkpbCh.js} +1 -1
  74. package/dist/gateway/static/root/assets/setup-status-panel-DVaEiAVY.js +1 -0
  75. package/dist/gateway/static/root/assets/{share-preview-page-DciHfTay.js → share-preview-page-vz0UK56q.js} +1 -1
  76. package/dist/gateway/static/root/assets/shares-settings-XiCqMDAe.js +1 -0
  77. package/dist/gateway/static/root/assets/skill-reload-api-C3D8WanU.js +1 -0
  78. package/dist/gateway/static/root/assets/skills-page-CxMWwR6A.js +2 -0
  79. package/dist/gateway/static/root/assets/{skills-page.utils-CU7PALQB.js → skills-page.utils-BryVNYll.js} +1 -1
  80. package/dist/gateway/static/root/assets/{system-settings-panel-GpjNbqvM.js → system-settings-panel-mKFDe6aZ.js} +1 -1
  81. package/dist/gateway/static/root/assets/task-detail-page-Cb0RZNcJ.js +1 -0
  82. package/dist/gateway/static/root/assets/{theme-store-mV6Cm2vj.js → theme-store-Dc5s20V3.js} +1 -1
  83. package/dist/gateway/static/root/assets/tunnel-api-FcI3wKy3.js +1 -0
  84. package/dist/gateway/static/root/assets/{use-autosave-LvCiBidm.js → use-autosave-CDgdtjTC.js} +1 -1
  85. package/dist/gateway/static/root/assets/user-model-page-Cnshc-Un.js +2 -0
  86. package/dist/gateway/static/root/assets/{voice-api-key-field-BlGysZxj.js → voice-api-key-field-Ce8cb5mN.js} +1 -1
  87. package/dist/gateway/static/root/assets/{voice-config-api-D3DdcH4H.js → voice-config-api-Mk78BrpP.js} +1 -1
  88. package/dist/gateway/static/root/assets/{work-discovery-overlay-DvIQOR5x.js → work-discovery-overlay-CacFTtXe.js} +1 -1
  89. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-JIp60bXT.js → workflow-run-setup-panel-V-5HuEUq.js} +2 -2
  90. package/dist/gateway/static/root/assets/workflows-page-1OJimIfo.js +6 -0
  91. package/dist/gateway/static/root/index.html +10 -11
  92. package/dist/package.js +1 -1
  93. package/dist/packages/gateway-contract/src/discussions.js +17 -0
  94. package/dist/packages/gateway-contract/src/proactive.js +4 -2
  95. package/dist/src/agent/agent-manager.js +4 -4
  96. package/dist/src/agent/background-review/run-background-review.js +1 -1
  97. package/dist/src/agent/commands/command-isolation.d.ts +1 -0
  98. package/dist/src/agent/commands/command-isolation.js +17 -1
  99. package/dist/src/agent/commands/commandMounts.d.ts +2 -0
  100. package/dist/src/agent/commands/commandMounts.js +32 -0
  101. package/dist/src/agent/context/project-context.d.ts +1 -0
  102. package/dist/src/agent/context/project-context.js +12 -4
  103. package/dist/src/agent/embedded/model-runtime.js +1 -1
  104. package/dist/src/agent/embedded/run-for-session.js +1 -1
  105. package/dist/src/agent/image/tool-model-config.js +1 -1
  106. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  107. package/dist/src/agent/sandbox/command-validator.js +0 -20
  108. package/dist/src/agent/sandbox/exec-policy.d.ts +1 -0
  109. package/dist/src/agent/sandbox/exec-policy.js +4 -4
  110. package/dist/src/agent/sandbox/fileAccess.d.ts +7 -0
  111. package/dist/src/agent/sandbox/fileAccess.js +100 -0
  112. package/dist/src/agent/sandbox/path-policy.d.ts +2 -0
  113. package/dist/src/agent/sandbox/path-policy.js +54 -17
  114. package/dist/src/agent/sandbox/sanitize-env-vars.js +10 -9
  115. package/dist/src/agent/service.js +2 -2
  116. package/dist/src/agent/session/session-inspector.js +1 -1
  117. package/dist/src/agent/skills/hub-lock.js +1 -1
  118. package/dist/src/agent/source-context/task-context.d.ts +3 -0
  119. package/dist/src/agent/source-context/task-context.js +24 -0
  120. package/dist/src/agent/source-context/types.d.ts +2 -2
  121. package/dist/src/agent/source-context/types.js +1 -1
  122. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  123. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
  124. package/dist/src/agent/tool-manuals/xopc-use.js +1 -0
  125. package/dist/src/agent/tools/apply-patch.js +25 -38
  126. package/dist/src/agent/tools/create-share-tool.js +11 -3
  127. package/dist/src/agent/tools/exec-command.js +2 -1
  128. package/dist/src/agent/tools/find.js +5 -3
  129. package/dist/src/agent/tools/grep.js +21 -4
  130. package/dist/src/agent/tools/image-generate-tool.js +3 -4
  131. package/dist/src/agent/tools/list-dir.js +2 -1
  132. package/dist/src/agent/tools/managed-job-tool.js +1 -0
  133. package/dist/src/agent/tools/publish-artifacts.js +4 -3
  134. package/dist/src/agent/tools/read.js +8 -5
  135. package/dist/src/agent/tools/repository-search.d.ts +2 -0
  136. package/dist/src/agent/tools/repository-search.js +51 -7
  137. package/dist/src/agent/tools/review-workspace.js +76 -10
  138. package/dist/src/agent/tools/send-media.js +4 -3
  139. package/dist/src/agent/tools/tool-paths.js +3 -1
  140. package/dist/src/agent/tools/write.js +4 -17
  141. package/dist/src/agent/tools/xopc-use-tool.js +2 -2
  142. package/dist/src/agent-config/schema.d.ts +24 -0
  143. package/dist/src/agent-config/schema.js +2 -1
  144. package/dist/src/ai-assist/text-assist.js +1 -1
  145. package/dist/src/auth/credentials.js +2 -2
  146. package/dist/src/auth/oauth/xopc-cloud.js +1 -1
  147. package/dist/src/auth/profiles/store.js +1 -1
  148. package/dist/src/auth/sync-provider-auth.js +2 -2
  149. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  150. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  151. package/dist/src/cli/commands/doctor/checks/provider-auth.js +21 -20
  152. package/dist/src/cli/commands/models.js +1 -1
  153. package/dist/src/config/index.js +4 -4
  154. package/dist/src/config/loader.js +2 -2
  155. package/dist/src/config/models-json.js +1 -1
  156. package/dist/src/config/schema.d.ts +16 -0
  157. package/dist/src/discussions/action-tasks.d.ts +21 -0
  158. package/dist/src/discussions/action-tasks.js +93 -0
  159. package/dist/src/discussions/analyzer.d.ts +21 -1
  160. package/dist/src/discussions/analyzer.js +229 -62
  161. package/dist/src/discussions/audio-repair.d.ts +8 -0
  162. package/dist/src/discussions/audio-repair.js +41 -0
  163. package/dist/src/discussions/edits.d.ts +22 -0
  164. package/dist/src/discussions/edits.js +81 -0
  165. package/dist/src/discussions/errors.d.ts +4 -0
  166. package/dist/src/discussions/errors.js +10 -0
  167. package/dist/src/discussions/export.d.ts +2 -0
  168. package/dist/src/discussions/export.js +23 -0
  169. package/dist/src/discussions/index.js +3 -2
  170. package/dist/src/discussions/live-worker.js +1 -1
  171. package/dist/src/discussions/organizer-worker.js +14 -5
  172. package/dist/src/discussions/organizer.d.ts +1 -1
  173. package/dist/src/discussions/organizer.js +60 -24
  174. package/dist/src/discussions/reconcile.d.ts +22 -0
  175. package/dist/src/discussions/reconcile.js +55 -0
  176. package/dist/src/discussions/recording.d.ts +9 -0
  177. package/dist/src/discussions/recording.js +219 -0
  178. package/dist/src/discussions/recordingJobs.d.ts +14 -0
  179. package/dist/src/discussions/recordingJobs.js +69 -0
  180. package/dist/src/discussions/repository.d.ts +4 -2
  181. package/dist/src/discussions/repository.js +15 -10
  182. package/dist/src/discussions/revisions.d.ts +12 -0
  183. package/dist/src/discussions/revisions.js +36 -0
  184. package/dist/src/discussions/sealer.d.ts +1 -0
  185. package/dist/src/discussions/sealer.js +61 -11
  186. package/dist/src/discussions/service.d.ts +16 -15
  187. package/dist/src/discussions/service.js +177 -91
  188. package/dist/src/discussions/types.d.ts +4 -139
  189. package/dist/src/discussions/types.js +1 -11
  190. package/dist/src/extensions/lockfile.js +1 -1
  191. package/dist/src/files/file-service.d.ts +1 -0
  192. package/dist/src/files/file-service.js +77 -0
  193. package/dist/src/gateway/agents-admin.js +1 -1
  194. package/dist/src/gateway/chat-stream/mapper.js +2 -2
  195. package/dist/src/gateway/file-path-classifier.js +1 -1
  196. package/dist/src/gateway/hono/app.js +3 -2
  197. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -0
  198. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  199. package/dist/src/gateway/hono/lib/static-ui.js +1 -0
  200. package/dist/src/gateway/hono/routes/context-sources.js +1 -2
  201. package/dist/src/gateway/hono/routes/discussions.js +126 -19
  202. package/dist/src/gateway/hono/routes/files.js +1 -22
  203. package/dist/src/gateway/hono/routes/index.js +0 -2
  204. package/dist/src/gateway/hono/routes/lazy-bundles.js +16 -0
  205. package/dist/src/gateway/hono/routes/models.js +1 -1
  206. package/dist/src/gateway/hono/routes/proactive-control.js +2 -36
  207. package/dist/src/gateway/hono/routes/project-understanding.d.ts +3 -0
  208. package/dist/src/gateway/hono/routes/project-understanding.js +65 -0
  209. package/dist/src/gateway/hono/routes/projects.js +20 -4
  210. package/dist/src/gateway/hono/routes/session-input-handler.d.ts +2 -2
  211. package/dist/src/gateway/hono/routes/session-input-handler.js +2 -2
  212. package/dist/src/gateway/hono/routes/shares.js +22 -1
  213. package/dist/src/gateway/hono/routes/tasks.js +2 -1
  214. package/dist/src/gateway/hono/routes/work-discovery.d.ts +0 -2
  215. package/dist/src/gateway/hono/routes/work-discovery.js +2 -16
  216. package/dist/src/gateway/hono/routes/workflows.js +2 -2
  217. package/dist/src/gateway/security/gateway-scopes.js +1 -2
  218. package/dist/src/gateway/service/agent-runner.js +2 -2
  219. package/dist/src/gateway/service/config-coordinator.js +1 -1
  220. package/dist/src/gateway/service.d.ts +3 -0
  221. package/dist/src/gateway/service.js +28 -13
  222. package/dist/src/knowledge-memory/repository.d.ts +2 -0
  223. package/dist/src/knowledge-memory/repository.js +3 -1
  224. package/dist/src/media-understanding/audio-transcription-runner.d.ts +1 -0
  225. package/dist/src/media-understanding/audio-transcription-runner.js +1 -0
  226. package/dist/src/media-understanding/runner.js +1 -0
  227. package/dist/src/media-understanding/types.d.ts +8 -0
  228. package/dist/src/notes/service.d.ts +3 -1
  229. package/dist/src/notes/store.d.ts +3 -1
  230. package/dist/src/notes/store.js +5 -3
  231. package/dist/src/proactive/experience.d.ts +38 -21
  232. package/dist/src/proactive/experience.js +113 -12
  233. package/dist/src/proactive/inbox/cards.js +7 -1
  234. package/dist/src/proactive/maintenance.js +0 -1
  235. package/dist/src/proactive/scenarios/control.d.ts +0 -35
  236. package/dist/src/proactive/scenarios/control.js +7 -53
  237. package/dist/src/projects/project-store.js +6 -4
  238. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  239. package/dist/src/providers/index.js +2 -2
  240. package/dist/src/providers/model-registry.js +1 -1
  241. package/dist/src/providers/register-runtime-providers.js +1 -1
  242. package/dist/src/session/client-history.d.ts +1 -1
  243. package/dist/src/session/client-history.js +1 -1
  244. package/dist/src/share/share-store.js +5 -1
  245. package/dist/src/storage/sqlite/migrations/166_remove_proactive_previews.sql +1 -0
  246. package/dist/src/storage/sqlite/migrations/167_discussion_recording_chunks.sql +7 -0
  247. package/dist/src/storage/sqlite/migrations/168_discussion_evidence.sql +16 -0
  248. package/dist/src/storage/sqlite/migrations/169_discussion_action_tasks.sql +8 -0
  249. package/dist/src/storage/sqlite/migrations/170_discussion_edits.sql +8 -0
  250. package/dist/src/storage/sqlite/migrations/171_discussion_recording_jobs.sql +14 -0
  251. package/dist/src/storage/sqlite/migrations/172_project_understanding.sql +3 -0
  252. package/dist/src/storage/sqlite/migrations/173_mobile_discussion_source.sql +5 -0
  253. package/dist/src/storage/sqlite/migrations/__tests__/mobile-discussion-source.test.ts +20 -0
  254. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  255. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  256. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  257. package/dist/src/storage/sqlite/schema.js +1 -1
  258. package/dist/src/tasks/home-query-service.js +2 -2
  259. package/dist/src/tasks/task-application-service.js +77 -3
  260. package/dist/src/tasks/task-context-assembler.js +1 -0
  261. package/dist/src/tasks/task-repository.d.ts +1 -0
  262. package/dist/src/tasks/task-repository.js +4 -0
  263. package/dist/src/tui/tui-startup-resources.js +1 -1
  264. package/dist/src/tui/tui.js +1 -1
  265. package/dist/src/voice/audio/normalize.js +28 -5
  266. package/dist/src/voice/stt/transcribe-core.js +1 -0
  267. package/dist/src/voice/stt/types.d.ts +1 -0
  268. package/dist/src/work-discovery/analyzer.d.ts +1 -0
  269. package/dist/src/work-discovery/analyzer.js +28 -22
  270. package/dist/src/work-discovery/index.js +3 -3
  271. package/dist/src/work-discovery/investigator.js +1 -1
  272. package/dist/src/work-discovery/project-understanding.d.ts +7 -0
  273. package/dist/src/work-discovery/project-understanding.js +38 -0
  274. package/dist/src/work-discovery/repository.d.ts +3 -1
  275. package/dist/src/work-discovery/repository.js +18 -5
  276. package/dist/src/work-discovery/service.d.ts +8 -0
  277. package/dist/src/work-discovery/service.js +163 -15
  278. package/dist/src/work-discovery/types.d.ts +2 -0
  279. package/dist/src/workflows/service/workflow-run-service.js +2 -2
  280. package/package.json +3 -3
  281. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DyCyuJpi.js +0 -1
  282. package/dist/gateway/static/root/assets/apps-page-__yzruGu.js +0 -1
  283. package/dist/gateway/static/root/assets/automations-workspace-DaisbmEh.js +0 -6
  284. package/dist/gateway/static/root/assets/browser-settings-page-C7zjxscU.js +0 -8
  285. package/dist/gateway/static/root/assets/capabilities-settings-panel-7kZMT1r6.js +0 -8
  286. package/dist/gateway/static/root/assets/channels-settings-BKUh6hzO.js +0 -1
  287. package/dist/gateway/static/root/assets/config-reload-event-Bjh2zoKp.js +0 -1
  288. package/dist/gateway/static/root/assets/connectors-page-m8J-F3u8.js +0 -2
  289. package/dist/gateway/static/root/assets/device-pairing-wizard-CfWQfz7a.js +0 -1
  290. package/dist/gateway/static/root/assets/gateway-config-swr-cd8owslz.js +0 -1
  291. package/dist/gateway/static/root/assets/gateway-settings-wLly-Kc1.js +0 -1
  292. package/dist/gateway/static/root/assets/home-page-FqgSwpmy.js +0 -1
  293. package/dist/gateway/static/root/assets/index-5UchbidQ.js +0 -74
  294. package/dist/gateway/static/root/assets/index-CXF9-BpI.css +0 -2
  295. package/dist/gateway/static/root/assets/local-app-workbench-page-DtYZa4GK.js +0 -2
  296. package/dist/gateway/static/root/assets/messages-BGc-OJWg.js +0 -3
  297. package/dist/gateway/static/root/assets/note-detail-panel-JbvyGdEX.js +0 -5
  298. package/dist/gateway/static/root/assets/notes-page-Dm7mE2FK.js +0 -8
  299. package/dist/gateway/static/root/assets/proactive-card-Ap_wfos3.js +0 -1
  300. package/dist/gateway/static/root/assets/proactive-page-D1lEuanT.js +0 -1
  301. package/dist/gateway/static/root/assets/project-detail-page-h00lfcVI.js +0 -1
  302. package/dist/gateway/static/root/assets/projects-page-C2Bo1FAL.js +0 -1
  303. package/dist/gateway/static/root/assets/remote-access-hub-_bZYAl49.js +0 -1
  304. package/dist/gateway/static/root/assets/sessions-page-F7CHsvPa.js +0 -1
  305. package/dist/gateway/static/root/assets/settings-advanced-gate-DtZSUX4H.js +0 -1
  306. package/dist/gateway/static/root/assets/setup-status-panel-VPfBsNVv.js +0 -1
  307. package/dist/gateway/static/root/assets/shares-settings-BS2pnWO0.js +0 -1
  308. package/dist/gateway/static/root/assets/skill-reload-api-DX344nVV.js +0 -1
  309. package/dist/gateway/static/root/assets/skills-page-BhfKUsv7.js +0 -2
  310. package/dist/gateway/static/root/assets/task-detail-page-CElcQ9Sh.js +0 -1
  311. package/dist/gateway/static/root/assets/tunnel-api-Bhi_x_h4.js +0 -1
  312. package/dist/gateway/static/root/assets/user-model-page-BydARq2C.js +0 -2
  313. package/dist/gateway/static/root/assets/workflows-page-B972t6zx.js +0 -6
  314. package/dist/src/proactive/scenarios/preview.d.ts +0 -13
  315. package/dist/src/proactive/scenarios/preview.js +0 -81
@@ -1 +1 @@
1
- export declare const xopcUseManual = "# XOPC Use Tool Manual\n\n## Purpose\n\n`xopc_use` operates first-class XOPC product objects without editing SQLite or product files directly.\nLoad this manual before a non-trivial mutation.\n\n```json\n{\n \"mode\": \"project | proactive | automation | note | task | task_run | local_app | settings\",\n \"command\": \"...\",\n \"args\": {},\n \"dryRun\": false\n}\n```\n\nSend one object command per call. Inspect the returned JSON `ok` field; a tool call can\ncomplete successfully while the product command returns `ok: false`.\n\n## Proactive delegation\n\nUse mode proactive only for explicit user delegation. Inspect list before start; edit existing subscriptions instead of duplicating them.\nFor one email thread, call mail_sources, then follow_up with sourceItemId, instructions and dueAt (ISO timestamp).\nUse update_follow_up with the current expectedRevision to pause, resume, adjust the deadline or end the delegation.\nOn a communication card, continue_card with its id reads current work and binds this conversation to the delegation.\nUse the returned exact connectionId when retrieving or replying to the thread. Review current recipients and the full draft with the user and retain connector confirmation for sending. Never mark sent from an approval alone; require a successful provider receipt. The delegation continues watching synchronized replies until explicitly ended.\n\n## Object routing\n\n| Object | Tool |\n| --- | --- |\n| Project, milestone, project update | `xopc_use` mode `project` |\n| Automation | `xopc_use` mode `automation` |\n| Task intent and lifecycle | `xopc_use` mode `task` |\n| Task execution attempt, receipt, events and waits | `xopc_use` mode `task_run` |\n| Note | `xopc_use` mode `note` |\n| Local app | `xopc_use` mode `local_app` |\n| Settings jump target | `xopc_use` mode `settings` |\n| Workflow run | dedicated `workflow` tool; pass `taskId` to link it to a Task |\n| Session, memory, skill, connected app or workspace file | its dedicated tool |\n\nDo not emulate Workflow APIs through `xopc_use`. A Task is durable intent;\na TaskRun is one execution attempt; a WorkflowRun is a procedure execution and may belong\nto a TaskRun. Never treat these three objects as interchangeable.\n\n## Reliable protocol\n\n1. Use `list` then `get` when an id is unknown.\n2. Read the current `version` before a Task mutation.\n3. Use `dryRun: true` for broad Project changes or uncertain mutations.\n4. Mutate once with the exact id and current concurrency token.\n5. Verify the returned object and preserve any \u201COpen in xopc\u201D delivery link.\n6. On a conflict, read again and reconsider the operation; do not blindly retry.\n\nTimestamps are Unix epoch milliseconds. Array fields are arrays of strings. Omission\npreserves a patchable field; an empty array intentionally clears it. Prefer explicit\n`projectId`, `taskId`, `runId`, `noteId`, and `localAppId` fields over `id`.\n\n## Proactive delegated work\n\nUse mode `proactive` for work the user asks the assistant to keep following.\nUse `list` before starting; update existing delegations instead of duplicating them.\n- `start`: {scenarioKey: \"project_delivery_risk\" | \"meeting_preparation\" | \"discussion_follow_up\", projectId?: string, instructions: string}.\n- `update`: {id, expectedRevision, userInstructions?, enabled?, completedAt?}. Read the revision from list. completedAt is an ISO timestamp; ending work also sets enabled false.\n- `check`: {id}, for project checks.\n- `get_card`: {id}, reads the current authorized artifact and action state before discussing it.\nInstructions adjust what to watch; they never grant new action permissions. Distinguish a task being created from its work being completed. Do not claim a draft was sent.\n\n## Projects\n\nCommands: `list`, `get`, `create`, `update`, `resolve_workspace`,\n`list_milestones`, `create_milestone`, `update_milestone`, `list_updates`,\nand `create_update`.\n\nProject statuses: `planned`, `active`, `paused`, `completed`, `cancelled`,\n`archived`. Health values: `unknown`, `on_track`, `at_risk`, `off_track`.\n\nA Project defines bounded shared context for related work. Its durable planning fields are `outcome`,\n`successCriteria`, `scope`, `nonGoals`, `ownerId`, `targetAt`, and `health`.\nUse `brief` for a concise description and `instructions` for durable operating guidance.\n\n### Create\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"create\",\n \"args\": {\n \"name\": \"AI Product Research\",\n \"outcome\": \"Choose a validated product direction\",\n \"successCriteria\": [\"Ten customer interviews\", \"Decision recorded\"],\n \"scope\": { \"market\": \"developer tools\" },\n \"nonGoals\": [\"Build the production product\"],\n \"health\": \"on_track\",\n \"targetAt\": 1760000000000,\n \"workspaceRoot\": \"/path/to/repo\"\n }\n}\n```\n\n### Update\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"update\",\n \"args\": {\n \"projectId\": \"project_id\",\n \"status\": \"active\",\n \"health\": \"at_risk\",\n \"successCriteria\": [\"Ten interviews\", \"Evidence-backed decision\"]\n }\n}\n```\n\n### Resolve a workspace\n\nUse `autoCreate: false` for lookup. Set it to true only when creating a Project is authorized.\n\n```json\n{ \"mode\": \"project\", \"command\": \"resolve_workspace\", \"args\": { \"workspacePath\": \"/path/to/repo\", \"autoCreate\": false } }\n```\n\n### Milestones\n\nMilestone statuses: `planned`, `active`, `completed`, `cancelled`.\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"create_milestone\",\n \"args\": {\n \"projectId\": \"project_id\",\n \"title\": \"Finish discovery\",\n \"status\": \"active\",\n \"targetAt\": 1760000000000,\n \"sortOrder\": 10\n }\n}\n```\n\nUse `list_milestones` with `projectId`. Use `update_milestone` with both\n`projectId` and `milestoneId`. Milestone deletion is intentionally not exposed.\n\n### Immutable project updates\n\nProject updates are append-only progress snapshots. They also update Project health.\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"create_update\",\n \"args\": {\n \"projectId\": \"project_id\",\n \"health\": \"on_track\",\n \"summary\": \"Discovery is complete\",\n \"progress\": [\"Interviewed ten users\"],\n \"risks\": [\"Pricing remains unvalidated\"],\n \"nextSteps\": [\"Run pricing tests\"]\n }\n}\n```\n\nUse `list_updates` with `projectId` and optional `limit`. Updates cannot be edited.\n\n## Automations\n\nCommands: `list`, `get`, `create`, `update`, `delete`, `run`, `pause`,\n`resume`, and `history`.\n\nAutomation `create` automatically uses the current session Project when `projectId` is\nomitted. An explicit `projectId` takes precedence and is validated before mutation. Use an\nexplicit id when creating for a Project other than the current session Project.\n\n### Create in the current Project\n\n`trigger` and `action` use the same shapes as the Automation product API.\n\n```json\n{\n \"mode\": \"automation\",\n \"command\": \"create\",\n \"args\": {\n \"name\": \"Daily project review\",\n \"trigger\": { \"kind\": \"schedule\", \"schedule\": { \"kind\": \"cron\", \"expr\": \"0 9 * * 1-5\", \"tz\": \"Asia/Shanghai\" } },\n \"action\": { \"kind\": \"agent\", \"instruction\": \"Review the current project and summarize risks.\" }\n }\n}\n```\n\nTo override the inherited Project, add `\"projectId\": \"project_id\"` to `args`.\nThe create payload may also be nested under `args.automation`; top-level `args.projectId`\nhas precedence.\n\n### List and history\n\n`list` and unqualified `history` inherit the current session Project. Pass an explicit\n`projectId` to query another Project. Pass `automationId` to `history` for one Automation.\n\n### Update and operate\n\nUse `automationId` for `get`, `update`, `delete`, `run`, `pause`, and `resume`.\nFor `update`, patch fields may be direct args or nested under `args.patch`. Supplying a new\n`projectId` reassigns the Automation after validating the target Project.\n\n## Tasks\n\nCommands: `list`, `get`, `create`, `update_dependencies`, `add_context`,\n`remove_context`, `command`, and `delete`.\n\nTask phases are `backlog`, `ready`, `active`, `review`, and `closed`.\nOperational state is projected separately as `idle`, `queued`, `running`, `waiting`,\n`verifying`, `succeeded`, `failed`, or `cancelled`. Never send either value as a\nfree-form status update.\n\n`task.get` returns the Task, its projected `model`, dependencies, dependents, context,\nauthority grants, TaskRuns, receipts, and waits.\nThe projected model is the correct source for current operational state and attention items.\n\n`delete` permanently removes the Task and its contracts, waits, context links, TaskRuns,\nreceipts, and Task-owned execution records. It does not delete linked Sessions, workspace files,\nor external artifacts. Cancel an active TaskRun before deletion, and use `dryRun: true` when\nthe user's intent is ambiguous.\n\n```json\n{ \"mode\": \"task\", \"command\": \"delete\", \"args\": { \"taskId\": \"task_id\" }, \"dryRun\": true }\n```\n\n### Capture or start\n\n`createMode` defaults to `capture`, which creates a backlog Task without executing it.\nUse `start` only when immediate execution is intended.\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"create\",\n \"args\": {\n \"objective\": \"Complete the customer research report\",\n \"projectId\": \"project_id\",\n \"createMode\": \"capture\",\n \"priority\": \"high\",\n \"expectedOutputs\": [\"Research report\"],\n \"acceptanceCriteria\": [\"Sources are cited\"],\n \"constraints\": [\"Do not contact customers without approval\"],\n \"dependsOnTaskIds\": []\n }\n}\n```\n\n### Dependencies\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"update_dependencies\",\n \"args\": {\n \"taskId\": \"task_id\",\n \"expectedVersion\": 3,\n \"dependsOnTaskIds\": [\"dependency_task_id\"]\n }\n}\n```\n\n### Context links\n\nUse `add_context` to link a document, file, URL, session, memory, Task, artifact, or source\nas `input`, `reference`, `constraint`, `deliverable`, or `evidence` context.\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"add_context\",\n \"args\": {\n \"taskId\": \"task_id\",\n \"targetKind\": \"file\",\n \"targetId\": \"/path/to/spec.md\",\n \"role\": \"input\",\n \"title\": \"Product specification\",\n \"pinned\": true,\n \"retrievalPolicy\": {},\n \"metadata\": {}\n }\n}\n```\n\nUse `remove_context` with `taskId` and the exact `edgeId` returned by `task.get`.\nDo not add authority grants through this tool; an Agent must not authorize itself.\n\n### Typed lifecycle commands\n\nEvery command requires `taskId`, the Task's current `expectedVersion`, a `type`, and\ntype-specific fields inside `commandArgs`.\n\nSupported command types:\n\n- `mark_ready`\n- `start`: `{ \"executor\": { \"kind\": \"agent\", \"agentId\": \"main\" } }`\n- `request_review`\n- `close`: `{ \"resolution\": \"done | cancelled | duplicate | wont_do\" }`\n- `reopen`: `{ \"phase\": \"ready | active\" }`\n- `add_wait`: `{ \"wait\": { \"kind\": \"dependency | approval | input | schedule | external | paused\", \"reason\": \"...\", \"condition\": {} } }`\n- `resolve_wait`: `{ \"waitId\": \"wait_id\", \"resolution\": {} }`\n- `delegate`: `{ \"agentId\": \"agent_id\" }`\n- `revise_contract`: `{ \"contract\": { ...complete contract... } }`\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"command\",\n \"args\": {\n \"taskId\": \"task_id\",\n \"expectedVersion\": 3,\n \"type\": \"start\",\n \"commandArgs\": {\n \"executor\": { \"kind\": \"agent\", \"agentId\": \"main\" }\n }\n }\n}\n```\n\nContract revision is replacement, not a patch. Read the Task and preserve all contract fields\nthe user did not ask to change. Resolve a wait through `resolve_wait`; do not directly mutate\na TaskRun or manufacture a phase transition.\n\n## TaskRuns\n\nTaskRun inspection is read-only except for explicit cancellation. Other execution state is\ncontrolled by Task commands and the runtime coordinator.\n\n### List attempts for a Task\n\n```json\n{ \"mode\": \"task_run\", \"command\": \"list\", \"args\": { \"taskId\": \"task_id\", \"limit\": 20 } }\n```\n\nThe result contains run attempts, finalized receipts, and active waits.\n\n### Inspect one attempt\n\n```json\n{ \"mode\": \"task_run\", \"command\": \"get\", \"args\": { \"runId\": \"run_id\" } }\n```\n\nThe result contains the TaskRun, its receipt when terminal, ordered events, and active Task waits.\n\n### Cancel an attempt\n\nRead the run first, then pass its current version. Cancellation creates a terminal receipt.\n\n```json\n{\n \"mode\": \"task_run\",\n \"command\": \"cancel\",\n \"args\": { \"runId\": \"run_id\", \"expectedVersion\": 2, \"reason\": \"User cancelled execution\" }\n}\n```\n\nDo not guess commands such as retry, force-complete, heartbeat, or transition; they are not Agent APIs.\n\n## Notes\n\nCommands: `list`, `get`, `create`, `append`, `preview_edit`, `update`, and `delete`.\nUse Notes for durable prose and reference material, not as a Task substitute. Prefer `append`\nwhen preserving user content. Use `preview_edit` before a canonical rewrite.\n\n```json\n{ \"mode\": \"note\", \"command\": \"create\", \"args\": { \"title\": \"Decision\", \"markdown\": \"...\", \"projectId\": \"project_id\" } }\n```\n\n```json\n{ \"mode\": \"note\", \"command\": \"append\", \"args\": { \"noteId\": \"note_id\", \"heading\": \"AI synthesis\", \"content\": \"...\" } }\n```\n\nUse `update` with `status: \"trashed\"` for a recoverable removal. `delete` permanently\nremoves the Note and its stored snapshots and media; use `dryRun: true` first when the\nuser's intent is ambiguous.\n\n```json\n{ \"mode\": \"note\", \"command\": \"delete\", \"args\": { \"noteId\": \"note_id\" }, \"dryRun\": true }\n```\n\n## Local apps and settings\n\nLocal app commands are `list`, `get`, `create`, and `validate`. Installation,\nactivation, rollback, and uninstall remain product runtime operations.\n\nSettings supports only `open` and returns an exact product jump target without changing config.\n\n## Error recovery\n\n| Result | Recovery |\n| --- | --- |\n| service unavailable | Stop retrying and report the unavailable capability. |\n| not found | Re-list in the intended scope; do not invent another id. |\n| conflict | Read the current object and reassess using its latest version. |\n| waiting | Inspect the Task projection and TaskRun waits; resolve only the real blocker. |\n| invalid command or state | Read the object and use only a documented transition. |\n| unsupported operation | Use the dedicated tool or product UI; never write storage directly. |\n\n## Deliberate boundaries\n\n- Project deletion and milestone deletion are not Agent APIs.\n- TaskRun mutation is internal to execution coordination except for optimistic cancellation.\n- Project updates are immutable.\n- Workflow and Automation operations remain in their dedicated tools.\n- Only the documented Task and TaskRun commands are valid; do not infer hidden aliases.\n";
1
+ export declare const xopcUseManual = "# XOPC Use Tool Manual\n\n## Purpose\n\n`xopc_use` operates first-class XOPC product objects without editing SQLite or product files directly.\nLoad this manual before a non-trivial mutation.\n\n```json\n{\n \"mode\": \"project | proactive | automation | note | task | task_run | local_app | settings\",\n \"command\": \"...\",\n \"args\": {},\n \"dryRun\": false\n}\n```\n\nSend one object command per call. Inspect the returned JSON `ok` field; a tool call can\ncomplete successfully while the product command returns `ok: false`.\n\n## Proactive delegation\n\nUse mode proactive only for explicit user delegation. Inspect list before start; edit existing subscriptions instead of duplicating them.\nWhen the user adopts a one-off result and repeating it would materially reduce future effort, offer one short natural-language upgrade such as \u201C\u4EE5\u540E\u8FD9\u7C7B\u4F1A\u8BAE\u90FD\u8FD9\u6837\u51C6\u5907\u5417\uFF1F\u201D. Start or update a proactive scene only after the user explicitly accepts. Confirm the moment, scope, promised help, notification timing and action boundary in ordinary language; do not expose scenario keys, schedules or runs.\nFor one email thread, call mail_sources, then follow_up with sourceItemId, instructions and dueAt (ISO timestamp).\nUse update_follow_up with the current expectedRevision to pause, resume, adjust the deadline or end the delegation.\nOn a communication card, continue_card with its id reads current work and binds this conversation to the delegation.\nUse the returned exact connectionId when retrieving or replying to the thread. Review current recipients and the full draft with the user and retain connector confirmation for sending. Never mark sent from an approval alone; require a successful provider receipt. The delegation continues watching synchronized replies until explicitly ended.\n\n## Object routing\n\n| Object | Tool |\n| --- | --- |\n| Project, milestone, project update | `xopc_use` mode `project` |\n| Automation | `xopc_use` mode `automation` |\n| Task intent and lifecycle | `xopc_use` mode `task` |\n| Task execution attempt, receipt, events and waits | `xopc_use` mode `task_run` |\n| Note | `xopc_use` mode `note` |\n| Local app | `xopc_use` mode `local_app` |\n| Settings jump target | `xopc_use` mode `settings` |\n| Workflow run | dedicated `workflow` tool; pass `taskId` to link it to a Task |\n| Session, memory, skill, connected app or workspace file | its dedicated tool |\n\nDo not emulate Workflow APIs through `xopc_use`. A Task is durable intent;\na TaskRun is one execution attempt; a WorkflowRun is a procedure execution and may belong\nto a TaskRun. Never treat these three objects as interchangeable.\n\n## Reliable protocol\n\n1. Use `list` then `get` when an id is unknown.\n2. Read the current `version` before a Task mutation.\n3. Use `dryRun: true` for broad Project changes or uncertain mutations.\n4. Mutate once with the exact id and current concurrency token.\n5. Verify the returned object and preserve any \u201COpen in xopc\u201D delivery link.\n6. On a conflict, read again and reconsider the operation; do not blindly retry.\n\nTimestamps are Unix epoch milliseconds. Array fields are arrays of strings. Omission\npreserves a patchable field; an empty array intentionally clears it. Prefer explicit\n`projectId`, `taskId`, `runId`, `noteId`, and `localAppId` fields over `id`.\n\n## Proactive delegated work\n\nUse mode `proactive` for work the user asks the assistant to keep following.\nUse `list` before starting; update existing delegations instead of duplicating them.\n- `start`: {scenarioKey: \"project_delivery_risk\" | \"meeting_preparation\" | \"discussion_follow_up\", projectId?: string, instructions: string}.\n- `update`: {id, expectedRevision, userInstructions?, enabled?, completedAt?}. Read the revision from list. completedAt is an ISO timestamp; ending work also sets enabled false.\n- `check`: {id}, for project checks.\n- `get_card`: {id}, reads the current authorized artifact and action state before discussing it.\nInstructions adjust what to watch; they never grant new action permissions. Distinguish a task being created from its work being completed. Do not claim a draft was sent.\n\n## Projects\n\nCommands: `list`, `get`, `create`, `update`, `resolve_workspace`,\n`list_milestones`, `create_milestone`, `update_milestone`, `list_updates`,\nand `create_update`.\n\nProject statuses: `planned`, `active`, `paused`, `completed`, `cancelled`,\n`archived`. Health values: `unknown`, `on_track`, `at_risk`, `off_track`.\n\nA Project defines bounded shared context for related work. Its durable planning fields are `outcome`,\n`successCriteria`, `scope`, `nonGoals`, `ownerId`, `targetAt`, and `health`.\nUse `brief` for a concise description and `instructions` for durable operating guidance.\n\n### Create\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"create\",\n \"args\": {\n \"name\": \"AI Product Research\",\n \"outcome\": \"Choose a validated product direction\",\n \"successCriteria\": [\"Ten customer interviews\", \"Decision recorded\"],\n \"scope\": { \"market\": \"developer tools\" },\n \"nonGoals\": [\"Build the production product\"],\n \"health\": \"on_track\",\n \"targetAt\": 1760000000000,\n \"workspaceRoot\": \"/path/to/repo\"\n }\n}\n```\n\n### Update\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"update\",\n \"args\": {\n \"projectId\": \"project_id\",\n \"status\": \"active\",\n \"health\": \"at_risk\",\n \"successCriteria\": [\"Ten interviews\", \"Evidence-backed decision\"]\n }\n}\n```\n\n### Resolve a workspace\n\nUse `autoCreate: false` for lookup. Set it to true only when creating a Project is authorized.\n\n```json\n{ \"mode\": \"project\", \"command\": \"resolve_workspace\", \"args\": { \"workspacePath\": \"/path/to/repo\", \"autoCreate\": false } }\n```\n\n### Milestones\n\nMilestone statuses: `planned`, `active`, `completed`, `cancelled`.\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"create_milestone\",\n \"args\": {\n \"projectId\": \"project_id\",\n \"title\": \"Finish discovery\",\n \"status\": \"active\",\n \"targetAt\": 1760000000000,\n \"sortOrder\": 10\n }\n}\n```\n\nUse `list_milestones` with `projectId`. Use `update_milestone` with both\n`projectId` and `milestoneId`. Milestone deletion is intentionally not exposed.\n\n### Immutable project updates\n\nProject updates are append-only progress snapshots. They also update Project health.\n\n```json\n{\n \"mode\": \"project\",\n \"command\": \"create_update\",\n \"args\": {\n \"projectId\": \"project_id\",\n \"health\": \"on_track\",\n \"summary\": \"Discovery is complete\",\n \"progress\": [\"Interviewed ten users\"],\n \"risks\": [\"Pricing remains unvalidated\"],\n \"nextSteps\": [\"Run pricing tests\"]\n }\n}\n```\n\nUse `list_updates` with `projectId` and optional `limit`. Updates cannot be edited.\n\n## Automations\n\nCommands: `list`, `get`, `create`, `update`, `delete`, `run`, `pause`,\n`resume`, and `history`.\n\nAutomation `create` automatically uses the current session Project when `projectId` is\nomitted. An explicit `projectId` takes precedence and is validated before mutation. Use an\nexplicit id when creating for a Project other than the current session Project.\n\n### Create in the current Project\n\n`trigger` and `action` use the same shapes as the Automation product API.\n\n```json\n{\n \"mode\": \"automation\",\n \"command\": \"create\",\n \"args\": {\n \"name\": \"Daily project review\",\n \"trigger\": { \"kind\": \"schedule\", \"schedule\": { \"kind\": \"cron\", \"expr\": \"0 9 * * 1-5\", \"tz\": \"Asia/Shanghai\" } },\n \"action\": { \"kind\": \"agent\", \"instruction\": \"Review the current project and summarize risks.\" }\n }\n}\n```\n\nTo override the inherited Project, add `\"projectId\": \"project_id\"` to `args`.\nThe create payload may also be nested under `args.automation`; top-level `args.projectId`\nhas precedence.\n\n### List and history\n\n`list` and unqualified `history` inherit the current session Project. Pass an explicit\n`projectId` to query another Project. Pass `automationId` to `history` for one Automation.\n\n### Update and operate\n\nUse `automationId` for `get`, `update`, `delete`, `run`, `pause`, and `resume`.\nFor `update`, patch fields may be direct args or nested under `args.patch`. Supplying a new\n`projectId` reassigns the Automation after validating the target Project.\n\n## Tasks\n\nCommands: `list`, `get`, `create`, `update_dependencies`, `add_context`,\n`remove_context`, `command`, and `delete`.\n\nTask phases are `backlog`, `ready`, `active`, `review`, and `closed`.\nOperational state is projected separately as `idle`, `queued`, `running`, `waiting`,\n`verifying`, `succeeded`, `failed`, or `cancelled`. Never send either value as a\nfree-form status update.\n\n`task.get` returns the Task, its projected `model`, dependencies, dependents, context,\nauthority grants, TaskRuns, receipts, and waits.\nThe projected model is the correct source for current operational state and attention items.\n\n`delete` permanently removes the Task and its contracts, waits, context links, TaskRuns,\nreceipts, and Task-owned execution records. It does not delete linked Sessions, workspace files,\nor external artifacts. Cancel an active TaskRun before deletion, and use `dryRun: true` when\nthe user's intent is ambiguous.\n\n```json\n{ \"mode\": \"task\", \"command\": \"delete\", \"args\": { \"taskId\": \"task_id\" }, \"dryRun\": true }\n```\n\n### Capture or start\n\n`createMode` defaults to `capture`, which creates a backlog Task without executing it.\nUse `start` only when immediate execution is intended.\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"create\",\n \"args\": {\n \"objective\": \"Complete the customer research report\",\n \"projectId\": \"project_id\",\n \"createMode\": \"capture\",\n \"priority\": \"high\",\n \"expectedOutputs\": [\"Research report\"],\n \"acceptanceCriteria\": [\"Sources are cited\"],\n \"constraints\": [\"Do not contact customers without approval\"],\n \"dependsOnTaskIds\": []\n }\n}\n```\n\n### Dependencies\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"update_dependencies\",\n \"args\": {\n \"taskId\": \"task_id\",\n \"expectedVersion\": 3,\n \"dependsOnTaskIds\": [\"dependency_task_id\"]\n }\n}\n```\n\n### Context links\n\nUse `add_context` to link a document, file, URL, session, memory, Task, artifact, or source\nas `input`, `reference`, `constraint`, `deliverable`, or `evidence` context.\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"add_context\",\n \"args\": {\n \"taskId\": \"task_id\",\n \"targetKind\": \"file\",\n \"targetId\": \"/path/to/spec.md\",\n \"role\": \"input\",\n \"title\": \"Product specification\",\n \"pinned\": true,\n \"retrievalPolicy\": {},\n \"metadata\": {}\n }\n}\n```\n\nUse `remove_context` with `taskId` and the exact `edgeId` returned by `task.get`.\nDo not add authority grants through this tool; an Agent must not authorize itself.\n\n### Typed lifecycle commands\n\nEvery command requires `taskId`, the Task's current `expectedVersion`, a `type`, and\ntype-specific fields inside `commandArgs`.\n\nSupported command types:\n\n- `mark_ready`\n- `start`: `{ \"executor\": { \"kind\": \"agent\", \"agentId\": \"main\" } }`\n- `request_review`\n- `close`: `{ \"resolution\": \"done | cancelled | duplicate | wont_do\" }`\n- `reopen`: `{ \"phase\": \"ready | active\" }`\n- `add_wait`: `{ \"wait\": { \"kind\": \"dependency | approval | input | schedule | external | paused\", \"reason\": \"...\", \"condition\": {} } }`\n- `resolve_wait`: `{ \"waitId\": \"wait_id\", \"resolution\": {} }`\n- `delegate`: `{ \"agentId\": \"agent_id\" }`\n- `revise_contract`: `{ \"contract\": { ...complete contract... } }`\n\n```json\n{\n \"mode\": \"task\",\n \"command\": \"command\",\n \"args\": {\n \"taskId\": \"task_id\",\n \"expectedVersion\": 3,\n \"type\": \"start\",\n \"commandArgs\": {\n \"executor\": { \"kind\": \"agent\", \"agentId\": \"main\" }\n }\n }\n}\n```\n\nContract revision is replacement, not a patch. Read the Task and preserve all contract fields\nthe user did not ask to change. Resolve a wait through `resolve_wait`; do not directly mutate\na TaskRun or manufacture a phase transition.\n\n## TaskRuns\n\nTaskRun inspection is read-only except for explicit cancellation. Other execution state is\ncontrolled by Task commands and the runtime coordinator.\n\n### List attempts for a Task\n\n```json\n{ \"mode\": \"task_run\", \"command\": \"list\", \"args\": { \"taskId\": \"task_id\", \"limit\": 20 } }\n```\n\nThe result contains run attempts, finalized receipts, and active waits.\n\n### Inspect one attempt\n\n```json\n{ \"mode\": \"task_run\", \"command\": \"get\", \"args\": { \"runId\": \"run_id\" } }\n```\n\nThe result contains the TaskRun, its receipt when terminal, ordered events, and active Task waits.\n\n### Cancel an attempt\n\nRead the run first, then pass its current version. Cancellation creates a terminal receipt.\n\n```json\n{\n \"mode\": \"task_run\",\n \"command\": \"cancel\",\n \"args\": { \"runId\": \"run_id\", \"expectedVersion\": 2, \"reason\": \"User cancelled execution\" }\n}\n```\n\nDo not guess commands such as retry, force-complete, heartbeat, or transition; they are not Agent APIs.\n\n## Notes\n\nCommands: `list`, `get`, `create`, `append`, `preview_edit`, `update`, and `delete`.\nUse Notes for durable prose and reference material, not as a Task substitute. Prefer `append`\nwhen preserving user content. Use `preview_edit` before a canonical rewrite.\n\n```json\n{ \"mode\": \"note\", \"command\": \"create\", \"args\": { \"title\": \"Decision\", \"markdown\": \"...\", \"projectId\": \"project_id\" } }\n```\n\n```json\n{ \"mode\": \"note\", \"command\": \"append\", \"args\": { \"noteId\": \"note_id\", \"heading\": \"AI synthesis\", \"content\": \"...\" } }\n```\n\nUse `update` with `status: \"trashed\"` for a recoverable removal. `delete` permanently\nremoves the Note and its stored snapshots and media; use `dryRun: true` first when the\nuser's intent is ambiguous.\n\n```json\n{ \"mode\": \"note\", \"command\": \"delete\", \"args\": { \"noteId\": \"note_id\" }, \"dryRun\": true }\n```\n\n## Local apps and settings\n\nLocal app commands are `list`, `get`, `create`, and `validate`. Installation,\nactivation, rollback, and uninstall remain product runtime operations.\n\nSettings supports only `open` and returns an exact product jump target without changing config.\n\n## Error recovery\n\n| Result | Recovery |\n| --- | --- |\n| service unavailable | Stop retrying and report the unavailable capability. |\n| not found | Re-list in the intended scope; do not invent another id. |\n| conflict | Read the current object and reassess using its latest version. |\n| waiting | Inspect the Task projection and TaskRun waits; resolve only the real blocker. |\n| invalid command or state | Read the object and use only a documented transition. |\n| unsupported operation | Use the dedicated tool or product UI; never write storage directly. |\n\n## Deliberate boundaries\n\n- Project deletion and milestone deletion are not Agent APIs.\n- TaskRun mutation is internal to execution coordination except for optimistic cancellation.\n- Project updates are immutable.\n- Workflow and Automation operations remain in their dedicated tools.\n- Only the documented Task and TaskRun commands are valid; do not infer hidden aliases.\n";
@@ -21,6 +21,7 @@ complete successfully while the product command returns \`ok: false\`.
21
21
  ## Proactive delegation
22
22
 
23
23
  Use mode proactive only for explicit user delegation. Inspect list before start; edit existing subscriptions instead of duplicating them.
24
+ When the user adopts a one-off result and repeating it would materially reduce future effort, offer one short natural-language upgrade such as “以后这类会议都这样准备吗?”. Start or update a proactive scene only after the user explicitly accepts. Confirm the moment, scope, promised help, notification timing and action boundary in ordinary language; do not expose scenario keys, schedules or runs.
24
25
  For one email thread, call mail_sources, then follow_up with sourceItemId, instructions and dueAt (ISO timestamp).
25
26
  Use update_follow_up with the current expectedRevision to pause, resume, adjust the deadline or end the delegation.
26
27
  On a communication card, continue_card with its id reads current work and binds this conversation to the delegation.
@@ -1,9 +1,7 @@
1
- import { checkFileSafety } from "../prompt/safety.js";
2
- import { resolvePathUnderWorkspace } from "./tool-paths.js";
3
- import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
1
+ import { checkedFilePath, deleteWorkspaceFile, readWorkspaceFile, writeWorkspaceFile } from "../sandbox/fileAccess.js";
4
2
  import { detectLineEnding, generateDiffString, normalizeToLF, restoreLineEndings } from "./edit-diff.js";
5
- import { dirname, relative } from "node:path";
6
- import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
3
+ import { relative } from "node:path";
4
+ import { stat } from "node:fs/promises";
7
5
  import { Type } from "@sinclair/typebox";
8
6
  //#region src/agent/tools/apply-patch.ts
9
7
  const ApplyPatchSchema = Type.Object({ patch: Type.String({ description: [
@@ -128,19 +126,11 @@ function applyHunks(original, hunks, path) {
128
126
  }
129
127
  return content;
130
128
  }
131
- async function readExisting(path) {
132
- return readFile(path, "utf-8");
129
+ async function readExisting(workspace, path) {
130
+ return readWorkspaceFile(workspace, path).toString("utf8");
133
131
  }
134
132
  async function assertWritable(workspace, path) {
135
- const quick = checkFileSafety("write", path);
136
- if (!quick.allowed) throw new Error(quick.message ?? `Cannot write ${path}`);
137
- const policy = evaluateFilePolicy({
138
- operation: "write",
139
- path,
140
- workspaceRoot: workspace
141
- });
142
- if (!policy.allowed) throw new Error(`Sandbox: ${policy.reason}`);
143
- return resolvePathUnderWorkspace(path, workspace);
133
+ return checkedFilePath(workspace, path, "write");
144
134
  }
145
135
  async function pathExists(path) {
146
136
  try {
@@ -178,7 +168,7 @@ async function buildPatchPlan(workspace, parsed) {
178
168
  if (op.kind === "delete") {
179
169
  const target = await assertWritable(workspace, op.path);
180
170
  rememberTarget(target);
181
- const oldContent = await readExisting(target);
171
+ const oldContent = await readExisting(workspace, target);
182
172
  const diff = generateDiffString(oldContent, "", op.path);
183
173
  const counts = countDiff(diff);
184
174
  changes.push({
@@ -193,7 +183,7 @@ async function buildPatchPlan(workspace, parsed) {
193
183
  }
194
184
  const target = await assertWritable(workspace, op.path);
195
185
  rememberTarget(target);
196
- const oldContent = await readExisting(target);
186
+ const oldContent = await readExisting(workspace, target);
197
187
  const lineEnding = detectLineEnding(oldContent);
198
188
  const newContent = restoreLineEndings(applyHunks(normalizeToLF(oldContent), op.hunks, op.path), lineEnding);
199
189
  const destination = op.moveTo ? await assertWritable(workspace, op.moveTo) : target;
@@ -217,33 +207,28 @@ async function buildPatchPlan(workspace, parsed) {
217
207
  }
218
208
  return changes;
219
209
  }
220
- async function commitPatchPlan(changes) {
210
+ async function commitPatchPlan(workspace, changes) {
221
211
  const committed = [];
222
212
  try {
223
213
  for (const change of changes) {
224
214
  committed.push(change);
225
- if (change.kind === "add") {
226
- await mkdir(dirname(change.absolutePath), { recursive: true });
227
- await writeFile(change.absolutePath, change.newContent ?? "", "utf-8");
228
- } else if (change.kind === "delete") await rm(change.absolutePath);
215
+ if (change.kind === "add") writeWorkspaceFile(workspace, change.absolutePath, change.newContent ?? "");
216
+ else if (change.kind === "delete") deleteWorkspaceFile(workspace, change.absolutePath);
229
217
  else {
230
218
  const destination = change.absoluteMoveTo ?? change.absolutePath;
231
- await mkdir(dirname(destination), { recursive: true });
232
- await writeFile(destination, change.newContent ?? "", "utf-8");
233
- if (destination !== change.absolutePath) await rm(change.absolutePath);
219
+ writeWorkspaceFile(workspace, destination, change.newContent ?? "");
220
+ if (destination !== change.absolutePath) deleteWorkspaceFile(workspace, change.absolutePath);
234
221
  }
235
222
  }
236
223
  } catch (error) {
237
224
  for (const change of committed.reverse()) try {
238
- if (change.kind === "add") await rm(change.absolutePath, { force: true });
239
- else if (change.kind === "delete") {
240
- await mkdir(dirname(change.absolutePath), { recursive: true });
241
- await writeFile(change.absolutePath, change.oldContent ?? "", "utf-8");
242
- } else if (change.absoluteMoveTo) {
243
- await rm(change.absoluteMoveTo, { force: true });
244
- await mkdir(dirname(change.absolutePath), { recursive: true });
245
- await writeFile(change.absolutePath, change.oldContent ?? "", "utf-8");
246
- } else await writeFile(change.absolutePath, change.oldContent ?? "", "utf-8");
225
+ if (change.kind === "add") {
226
+ if (await pathExists(change.absolutePath)) deleteWorkspaceFile(workspace, change.absolutePath);
227
+ } else if (change.kind === "delete") writeWorkspaceFile(workspace, change.absolutePath, change.oldContent ?? "");
228
+ else if (change.absoluteMoveTo) {
229
+ if (await pathExists(change.absoluteMoveTo)) deleteWorkspaceFile(workspace, change.absoluteMoveTo);
230
+ writeWorkspaceFile(workspace, change.absolutePath, change.oldContent ?? "");
231
+ } else writeWorkspaceFile(workspace, change.absolutePath, change.oldContent ?? "");
247
232
  } catch {}
248
233
  throw error;
249
234
  }
@@ -262,12 +247,14 @@ function createApplyPatchTool(workspace) {
262
247
  finalGuardRelevant: true,
263
248
  async execute(_toolCallId, params) {
264
249
  try {
265
- const changes = await buildPatchPlan(workspace, parsePatch(params.patch ?? ""));
266
- await commitPatchPlan(changes);
250
+ const parsed = parsePatch(params.patch ?? "");
251
+ const canonicalWorkspace = checkedFilePath(workspace, workspace, "write");
252
+ const changes = await buildPatchPlan(canonicalWorkspace, parsed);
253
+ await commitPatchPlan(canonicalWorkspace, changes);
267
254
  const diff = changes.map((change) => change.diff).join("\n");
268
255
  const added = changes.reduce((sum, change) => sum + change.added, 0);
269
256
  const removed = changes.reduce((sum, change) => sum + change.removed, 0);
270
- const files = changes.map((change) => relative(workspace, change.absoluteMoveTo ?? change.absolutePath));
257
+ const files = changes.map((change) => relative(canonicalWorkspace, change.absoluteMoveTo ?? change.absolutePath));
271
258
  const summary = changes.map((change) => {
272
259
  const display = change.moveTo ? `${change.path} -> ${change.moveTo}` : change.path;
273
260
  return `${change.kind}: ${display} (+${change.added}/-${change.removed})`;
@@ -1,4 +1,5 @@
1
1
  import { turnOutcomeKindFromFileName } from "../../../packages/gateway-contract/src/turn-outcome.js";
2
+ import { assertWorkspaceTreeReadable, checkedFilePath } from "../sandbox/fileAccess.js";
2
3
  import { resolvePathUnderWorkspace } from "./tool-paths.js";
3
4
  import { resolveGatewayEffectiveHost } from "../../config/gateway-bind.js";
4
5
  import { resolveShareConfig } from "../../share/share-config.js";
@@ -11,6 +12,7 @@ import { resolveReverseProxyPublicUrl } from "../../gateway/public-url.js";
11
12
  import { audienceDefaults, decideShareKind, makeDescription, makeTitle, probeShareTarget, rememberStagedSite, stageSingleHtmlAsSite } from "../../share/share-auto.js";
12
13
  import { scheduleThumbnail } from "../../share/share-thumbnail.js";
13
14
  import { resolveToolLocale, shareToolErrorLine, shareToolSuccessLines } from "../../i18n/share-tool-bundle.js";
15
+ import { relative } from "node:path";
14
16
  import { createHash } from "node:crypto";
15
17
  import { Type } from "@sinclair/typebox";
16
18
  //#region src/agent/tools/create-share-tool.ts
@@ -87,9 +89,15 @@ function createCreateShareTool(deps) {
87
89
  reverseProxyPublicUrl: resolveReverseProxyPublicUrl(cfg)
88
90
  };
89
91
  const tokenHash = hashCreator(deps.getAgentId?.() ?? "agent-tool");
90
- const absolutePath = resolvePathUnderWorkspace(p.filePath, workspace);
91
- if (!absolutePath.startsWith(workspace)) return errorResult(locale, "File must be inside the agent workspace.");
92
- const relPath = absolutePath === workspace ? "" : absolutePath.slice(workspace.length).replace(/^[\\/]+/, "").replace(/\\/g, "/");
92
+ let relPath;
93
+ try {
94
+ const root = checkedFilePath(workspace, workspace, "read");
95
+ const absolutePath = checkedFilePath(workspace, resolvePathUnderWorkspace(p.filePath, workspace), "read");
96
+ relPath = relative(root, absolutePath).replace(/\\/g, "/");
97
+ if (relPath) assertWorkspaceTreeReadable(workspace, absolutePath);
98
+ } catch (err) {
99
+ return errorResult(locale, `Cannot read target: ${err instanceof Error ? err.message : String(err)}`);
100
+ }
93
101
  if (!relPath) return errorResult(locale, "Cannot share the workspace root itself.");
94
102
  let probe;
95
103
  try {
@@ -1,6 +1,6 @@
1
1
  import { commandRegistry, commandTimeout } from "../commands/command-registry.js";
2
- import { formatSize, truncateTail } from "./truncate.js";
3
2
  import { evaluateExecPolicy } from "../sandbox/exec-policy.js";
3
+ import { formatSize, truncateTail } from "./truncate.js";
4
4
  import { publishArtifactPaths } from "./publish-artifacts.js";
5
5
  import { resolve } from "node:path";
6
6
  import { Type } from "@sinclair/typebox";
@@ -93,6 +93,7 @@ function createExecCommandTool(workspaceCwd, options) {
93
93
  const policy = evaluateExecPolicy({
94
94
  command,
95
95
  cwd: requestedCwd,
96
+ workspaceRoot: workspaceCwd,
96
97
  allowedEnvVars: options?.getSkillPassthroughEnvVarNames?.() ?? []
97
98
  });
98
99
  if (!policy.allowed) {
@@ -1,6 +1,6 @@
1
1
  import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
2
2
  import { resolveToCwd } from "../../utils/helpers.js";
3
- import { repositorySearch } from "./repository-search.js";
3
+ import { isSearchFileAllowed, repositorySearch } from "./repository-search.js";
4
4
  import { Type } from "@sinclair/typebox";
5
5
  //#region src/agent/tools/find.ts
6
6
  const findSchema = Type.Object({
@@ -20,20 +20,22 @@ function createFindTool(cwd) {
20
20
  supportsParallel: true,
21
21
  idempotent: true,
22
22
  async execute(_id, params, signal) {
23
- const path = resolveToCwd(params.path || ".", cwd);
23
+ let path = resolveToCwd(params.path || ".", cwd);
24
24
  const policy = evaluateFilePolicy({
25
25
  operation: "read",
26
26
  path,
27
27
  workspaceRoot: cwd
28
28
  });
29
29
  if (!policy.allowed) throw new Error(policy.reason);
30
+ path = policy.canonicalPath;
30
31
  const result = await repositorySearch(path, [
31
32
  "--files",
33
+ "--null",
32
34
  "--glob",
33
35
  params.pattern
34
36
  ], signal);
35
37
  const limit = Math.min(1e4, Math.max(1, params.limit ?? 1e3));
36
- const lines = result.output.trimEnd().split("\n").filter(Boolean).sort();
38
+ const lines = result.output.split("\0").slice(0, -1).filter((file) => file && isSearchFileAllowed(cwd, resolveToCwd(file, path))).sort();
37
39
  const truncated = result.truncated || lines.length > limit;
38
40
  return {
39
41
  content: [{
@@ -1,6 +1,6 @@
1
1
  import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
2
2
  import { resolveToCwd } from "../../utils/helpers.js";
3
- import { repositorySearch } from "./repository-search.js";
3
+ import { isSearchFileAllowed, repositorySearch } from "./repository-search.js";
4
4
  import { Type } from "@sinclair/typebox";
5
5
  //#region src/agent/tools/grep.ts
6
6
  const grepSchema = Type.Object({
@@ -27,15 +27,17 @@ function createGrepTool(cwd) {
27
27
  supportsParallel: true,
28
28
  idempotent: true,
29
29
  async execute(_id, params, signal) {
30
- const path = resolveToCwd(params.path || ".", cwd);
30
+ let path = resolveToCwd(params.path || ".", cwd);
31
31
  const policy = evaluateFilePolicy({
32
32
  operation: "read",
33
33
  path,
34
34
  workspaceRoot: cwd
35
35
  });
36
36
  if (!policy.allowed) throw new Error(policy.reason);
37
+ path = policy.canonicalPath;
37
38
  const limit = Math.min(1e3, Math.max(1, params.limit ?? 100));
38
39
  const result = await repositorySearch(cwd, [
40
+ "--json",
39
41
  "--line-number",
40
42
  "--with-filename",
41
43
  "--color",
@@ -55,13 +57,28 @@ function createGrepTool(cwd) {
55
57
  "--",
56
58
  path
57
59
  ], signal);
58
- const lines = result.output.trimEnd().split("\n");
60
+ const lines = [];
61
+ for (const row of result.output.split("\n")) {
62
+ if (!row) continue;
63
+ let event;
64
+ try {
65
+ event = JSON.parse(row);
66
+ } catch {
67
+ if (result.truncated) continue;
68
+ throw new Error("Invalid search output");
69
+ }
70
+ if (event.type !== "match" && event.type !== "context") continue;
71
+ const data = event.data;
72
+ if (!data?.path?.text || !data.lines?.text || !isSearchFileAllowed(cwd, data.path.text)) continue;
73
+ const separator = event.type === "match" ? ":" : "-";
74
+ lines.push(`${data.path.text}${separator}${data.line_number}${separator}${data.lines.text.replace(/\r?\n$/, "")}`);
75
+ }
59
76
  const outputLimit = limit * (1 + 2 * (params.context ?? 0));
60
77
  const truncated = result.truncated || lines.length > outputLimit;
61
78
  return {
62
79
  content: [{
63
80
  type: "text",
64
- text: (result.output ? lines.slice(0, outputLimit).join("\n") : "No matches found") + (truncated ? "\n[Results truncated; narrow the path or pattern.]" : "")
81
+ text: (lines.length ? lines.slice(0, outputLimit).join("\n") : "No matches found") + (truncated ? "\n[Results truncated; narrow the path or pattern.]" : "")
65
82
  }],
66
83
  details: { truncated }
67
84
  };
@@ -1,4 +1,5 @@
1
1
  import { getAgentDefaultImageGenerationModelConfig, init_schema } from "../../config/schema.js";
2
+ import { readWorkspaceFile, writeWorkspaceFile } from "../sandbox/fileAccess.js";
2
3
  import { imageAssetFromDataUrl, imageFileExtensionForMimeType, mimeTypeFromFileName, parseImageDataUrl, sniffImageMimeType } from "../image/generation/image-assets.js";
3
4
  import { persistToolMedia } from "./tool-media.js";
4
5
  import { buildCapabilityPlansForConfig } from "../../capabilities/readiness/from-config.js";
@@ -9,7 +10,6 @@ import { getImageGenerationProvider } from "../image/generation/provider-registr
9
10
  import { generateImage, listImageGenerationProvidersSummary } from "../image/generation/runtime.js";
10
11
  import path from "node:path";
11
12
  import { randomBytes } from "node:crypto";
12
- import { mkdir, readFile, writeFile } from "node:fs/promises";
13
13
  import { Type } from "@sinclair/typebox";
14
14
  //#region src/agent/tools/image-generate-tool.ts
15
15
  init_schema();
@@ -114,7 +114,7 @@ async function loadInputImages(params) {
114
114
  if (resolved !== workspaceAbs && !resolved.startsWith(workspaceAbs + path.sep)) throw new ToolInputError("inputImages[].source escapes workspace.");
115
115
  let buffer;
116
116
  try {
117
- buffer = await readFile(resolved);
117
+ buffer = readWorkspaceFile(params.workspace, resolved);
118
118
  } catch (e) {
119
119
  throw new ToolInputError(`inputImages[].source not readable: ${e instanceof Error ? e.message : String(e)}`);
120
120
  }
@@ -173,7 +173,6 @@ function resolveImageGenerationModelConfigForTool(params) {
173
173
  }
174
174
  async function saveGeneratedImages(params) {
175
175
  const dir = path.join(params.workspace, "media", "generated");
176
- await mkdir(dir, { recursive: true });
177
176
  const out = [];
178
177
  const random = randomBytes(4).toString("hex");
179
178
  let i = 0;
@@ -182,7 +181,7 @@ async function saveGeneratedImages(params) {
182
181
  const ext = imageFileExtensionForMimeType(img.mimeType);
183
182
  const name = `${(params.filenameHint?.replace(/[^\w.-]/g, "") || "image") + `-${random}`}-${i}.${ext}`;
184
183
  const full = path.join(dir, name);
185
- await writeFile(full, img.buffer);
184
+ writeWorkspaceFile(params.workspace, full, img.buffer);
186
185
  out.push(full);
187
186
  }
188
187
  return out;
@@ -1,3 +1,4 @@
1
+ import { checkedFilePath } from "../sandbox/fileAccess.js";
1
2
  import { resolvePathUnderWorkspace } from "./tool-paths.js";
2
3
  import { readdir } from "fs/promises";
3
4
  import { Type } from "@sinclair/typebox";
@@ -16,7 +17,7 @@ function createListDirTool(workspace) {
16
17
  return {
17
18
  content: [{
18
19
  type: "text",
19
- text: (await readdir(resolvePathUnderWorkspace(params.path, workspace), { withFileTypes: true })).map((e) => {
20
+ text: (await readdir(checkedFilePath(workspace, resolvePathUnderWorkspace(params.path, workspace), "read"), { withFileTypes: true })).map((e) => {
20
21
  return `${e.isDirectory() ? "d" : e.isFile() ? "f" : "?"} ${e.name}`;
21
22
  }).join("\n") || "(empty)"
22
23
  }],
@@ -71,6 +71,7 @@ function createManagedJobTool(workspace, getSessionKey, getSkillPassthroughEnvVa
71
71
  error: "command is required"
72
72
  });
73
73
  const policy = evaluateExecPolicy({
74
+ workspaceRoot: workspace,
74
75
  command,
75
76
  cwd: resolve(workspace, input.cwd?.trim() || "."),
76
77
  allowedEnvVars: getSkillPassthroughEnvVarNames?.() ?? []
@@ -1,10 +1,11 @@
1
1
  import { turnOutcomeKindFromFileName, turnOutcomeMimeTypeFromFileName } from "../../../packages/gateway-contract/src/turn-outcome.js";
2
+ import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
3
+ import { readWorkspaceFile } from "../sandbox/fileAccess.js";
2
4
  import { resolvePathUnderWorkspace } from "./tool-paths.js";
3
5
  import { fileResourceId, fileSpaceId } from "../../files/file-service.js";
4
- import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
5
6
  import { persistToolMedia } from "./tool-media.js";
6
7
  import { basename, isAbsolute, relative, sep } from "node:path";
7
- import { readFile, realpath } from "node:fs/promises";
8
+ import { realpath } from "node:fs/promises";
8
9
  import { Type } from "@sinclair/typebox";
9
10
  //#region src/agent/tools/publish-artifacts.ts
10
11
  const PublishArtifactsSchema = Type.Object({ paths: Type.Array(Type.String({ minLength: 1 }), {
@@ -35,7 +36,7 @@ async function publishArtifactPaths(params) {
35
36
  if (sourcePath !== ".." && !sourcePath.startsWith(`..${sep}`) && !isAbsolute(sourcePath)) sourceFileId = fileResourceId(fileSpaceId(root), sourcePath.split(sep).join("/"));
36
37
  }
37
38
  const media = await persistToolMedia({
38
- buffer: await readFile(source),
39
+ buffer: readWorkspaceFile(params.workspaceRoot, source),
39
40
  filePath: resolved
40
41
  });
41
42
  const kind = turnOutcomeKindFromFileName(media.name);
@@ -1,7 +1,8 @@
1
+ import { checkedFilePath, readWorkspaceFile } from "../sandbox/fileAccess.js";
1
2
  import { checkFileSafety } from "../prompt/safety.js";
2
3
  import { DEFAULT_MAX_BYTES, formatSize, truncateHead } from "./truncate.js";
3
4
  import { isBareProfileMarkdownFileName, resolvePathUnderWorkspace, resolveProfileMarkdownPathIfBareName } from "./tool-paths.js";
4
- import { readFile, stat } from "fs/promises";
5
+ import { stat } from "fs/promises";
5
6
  import { Type } from "@sinclair/typebox";
6
7
  //#region src/agent/tools/read.ts
7
8
  const MAX_FILE_SIZE = 10 * 1024 * 1024;
@@ -41,7 +42,8 @@ async function executeReadFile(workspace, profileMarkdownRoot, params) {
41
42
  }],
42
43
  details: { status: "failed" }
43
44
  };
44
- let normalized = resolvePathUnderWorkspace(params.path, workspace);
45
+ let activeRoot = workspace;
46
+ let normalized = checkedFilePath(activeRoot, resolvePathUnderWorkspace(params.path, workspace), "read");
45
47
  let stats;
46
48
  try {
47
49
  stats = await stat(normalized);
@@ -49,8 +51,9 @@ async function executeReadFile(workspace, profileMarkdownRoot, params) {
49
51
  if (e?.code === "ENOENT" && profileMarkdownRoot && isBareProfileMarkdownFileName(params.path)) {
50
52
  const alt = resolveProfileMarkdownPathIfBareName(params.path, profileMarkdownRoot);
51
53
  try {
52
- stats = await stat(alt);
53
- normalized = alt;
54
+ normalized = checkedFilePath(profileMarkdownRoot, alt, "read");
55
+ stats = await stat(normalized);
56
+ activeRoot = profileMarkdownRoot;
54
57
  } catch {
55
58
  throw e;
56
59
  }
@@ -63,7 +66,7 @@ async function executeReadFile(workspace, profileMarkdownRoot, params) {
63
66
  }],
64
67
  details: { status: "failed" }
65
68
  };
66
- const content = await readFile(normalized, "utf-8");
69
+ const content = readWorkspaceFile(activeRoot, normalized, MAX_FILE_SIZE).toString("utf8");
67
70
  const offset = Math.max(1, params.offset ?? 1);
68
71
  const lines = content.split("\n");
69
72
  if (offset > lines.length) throw new Error(`Offset ${offset} exceeds ${lines.length} lines`);
@@ -3,3 +3,5 @@ export declare function repositorySearch(cwd: string, args: string[], signal?: A
3
3
  output: string;
4
4
  truncated: boolean;
5
5
  }>;
6
+ /** Search results must satisfy the same policy as direct file reads. */
7
+ export declare function isSearchFileAllowed(workspace: string, path: string): boolean;
@@ -1,4 +1,7 @@
1
+ import { prepareSafeToolEnv } from "../sandbox/sanitize-env-vars.js";
2
+ import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
1
3
  import { resolveRipgrepBinary } from "../../infra/ripgrep.js";
4
+ import { lstatSync } from "node:fs";
2
5
  import { spawn } from "node:child_process";
3
6
  //#region src/agent/tools/repository-search.ts
4
7
  /** Bounded native search; unavailable tools and invalid regexes are explicit failures. */
@@ -6,15 +9,41 @@ async function repositorySearch(cwd, args, signal) {
6
9
  signal?.throwIfAborted();
7
10
  const binary = await resolveRipgrepBinary();
8
11
  return new Promise((resolve, reject) => {
12
+ const separator = args.indexOf("--");
13
+ const options = separator < 0 ? args : args.slice(0, separator);
14
+ const targets = separator < 0 ? [] : args.slice(separator);
15
+ const excluded = [
16
+ ".git",
17
+ "node_modules",
18
+ ".env",
19
+ ".env.*",
20
+ ".ssh",
21
+ ".aws",
22
+ ".gnupg",
23
+ ".docker",
24
+ ".config",
25
+ ".netrc",
26
+ ".npmrc",
27
+ ".cargo/credentials",
28
+ ".kube",
29
+ ".xopc"
30
+ ];
9
31
  const child = spawn(binary, [
10
32
  "--no-config",
11
33
  "--hidden",
12
- "--glob",
13
- "!.git",
14
- "--glob",
15
- "!node_modules",
16
- ...args
17
- ], { cwd });
34
+ ...options,
35
+ ...excluded.flatMap((path) => [
36
+ "--glob",
37
+ `!**/${path}`,
38
+ "--glob",
39
+ `!**/${path}/**`
40
+ ]),
41
+ "--no-follow",
42
+ ...targets
43
+ ], {
44
+ cwd,
45
+ env: prepareSafeToolEnv(process.env)
46
+ });
18
47
  const chunks = [];
19
48
  let bytes = 0, truncated = false, stderr = "";
20
49
  const timer = setTimeout(() => child.kill("SIGKILL"), 1e4);
@@ -52,5 +81,20 @@ async function repositorySearch(cwd, args, signal) {
52
81
  if (signal?.aborted) abort();
53
82
  });
54
83
  }
84
+ /** Search results must satisfy the same policy as direct file reads. */
85
+ function isSearchFileAllowed(workspace, path) {
86
+ const policy = evaluateFilePolicy({
87
+ operation: "read",
88
+ workspaceRoot: workspace,
89
+ path
90
+ });
91
+ if (!policy.allowed || !policy.canonicalPath) return false;
92
+ try {
93
+ const stat = lstatSync(policy.canonicalPath);
94
+ return stat.isFile() && stat.nlink === 1;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
55
99
  //#endregion
56
- export { repositorySearch };
100
+ export { isSearchFileAllowed, repositorySearch };