@xopcai/xopc 0.0.205 → 0.0.207

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 (208) hide show
  1. package/README.md +7 -7
  2. package/README.zh-CN.md +7 -7
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/telegram/xopc.extension.json +1 -1
  5. package/dist/gateway/static/root/assets/{activity-store-DJBadfSX.js → activity-store-BmpM0zwM.js} +1 -1
  6. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Br6C32BX.js → agent-avatar-dicebear-DhK5wi6_.js} +1 -1
  7. package/dist/gateway/static/root/assets/agents-Bc3Lc-n2.js +68 -0
  8. package/dist/gateway/static/root/assets/{api-B5O7fKXa.js → api-CzaAcDOn.js} +1 -1
  9. package/dist/gateway/static/root/assets/{app-management-settings-panel-Le1vJ1OO.js → app-management-settings-panel-Dqj5G_cd.js} +1 -1
  10. package/dist/gateway/static/root/assets/{appearance-settings-CZlAU60t.js → appearance-settings-Bm1uLGMi.js} +1 -1
  11. package/dist/gateway/static/root/assets/apps-page-BKtwU47-.js +1 -0
  12. package/dist/gateway/static/root/assets/{archive-plugin-CRzXRXPE.js → archive-plugin-CgnzBplN.js} +1 -1
  13. package/dist/gateway/static/root/assets/{attachment-load-CYAAQ6Qi.js → attachment-load-Cuybcmhn.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-page-ilGeRLDN.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-CVR5cUmS.js → binary-plugins-D6BBx6Ps.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-CFe74rWi.js → block-editor-Dk1c3Spa.js} +46 -46
  17. package/dist/gateway/static/root/assets/browser-settings-page-BCu8AZbs.js +8 -0
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-Bd68yluo.js → browser-workflow-inputs-DvfIzCgV.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-B0uiDLga.js → browser-workflows-page-DZScuPlF.js} +2 -2
  20. package/dist/gateway/static/root/assets/capabilities-settings-panel-BbWQBtTe.js +7 -0
  21. package/dist/gateway/static/root/assets/{capability-presets-api-BerPMp6f.js → capability-presets-api-hoA8R_J1.js} +1 -1
  22. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BTVU46Yn.js +3 -0
  23. package/dist/gateway/static/root/assets/{channel-recipient-api-D2d21_XA.js → channel-recipient-api-BS8I65NT.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-settings-BEQsC9a9.js +1 -0
  25. package/dist/gateway/static/root/assets/channels-status-swr-DRwbgtOT.js +1 -0
  26. package/dist/gateway/static/root/assets/chat-terminal-dock-BIPhWBDI.js +36 -0
  27. package/dist/gateway/static/root/assets/chat-terminal-dock-uQUnjRtf.css +1 -0
  28. package/dist/gateway/static/root/assets/{connectors-api-Bq_vUzxP.js → connectors-api-B_78jmvM.js} +1 -1
  29. package/dist/gateway/static/root/assets/connectors-page-w_3kpqbc.js +2 -0
  30. package/dist/gateway/static/root/assets/{cron-expression-DZBxmKGR.js → cron-expression-BBheaBIr.js} +1 -1
  31. package/dist/gateway/static/root/assets/{date-picker-BNHd7HT7.js → date-picker-CDwj7UrT.js} +1 -1
  32. package/dist/gateway/static/root/assets/{dependency-picker-D1kJBknt.js → dependency-picker-Dnrc2qZe.js} +1 -1
  33. package/dist/gateway/static/root/assets/{desktop-pet-Di75oHkC.js → desktop-pet-Bj_vUjXp.js} +1 -1
  34. package/dist/gateway/static/root/assets/{desktop-pet-settings-D6tD1uym.js → desktop-pet-settings-uiCwJJk4.js} +1 -1
  35. package/dist/gateway/static/root/assets/directory-picker-path-field-D0zUQ-TO.js +1 -0
  36. package/dist/gateway/static/root/assets/{extension-debug-page-D91_S7NQ.js → extension-debug-page-_GZ4y2da.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-page-DHzmmr_N.js → extension-page-scR96Edg.js} +1 -1
  38. package/dist/gateway/static/root/assets/{extension-settings-page-BpJNtePi.js → extension-settings-page-CILsAwxx.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-api-BAzLYTKZ.js → gateway-config-api-984O_4wM.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-config-swr-VVcfd3sG.js → gateway-config-swr-D4hvsdJA.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-settings-C5-aKkTp.js → gateway-settings-aF4eQHo3.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-startup-retry-qAX_T2t2.js → gateway-startup-retry-Deo5-O87.js} +1 -1
  43. package/dist/gateway/static/root/assets/heartbeat-settings-D5DrFWH6.js +1 -0
  44. package/dist/gateway/static/root/assets/home-page-DiMWxngC.js +3 -0
  45. package/dist/gateway/static/root/assets/index-DzKLVgY-.js +85 -0
  46. package/dist/gateway/static/root/assets/index-wR5jX-lw.css +2 -0
  47. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-fpNjXnJK.js → keyboard-shortcuts-settings-DGmOlNcB.js} +1 -1
  48. package/dist/gateway/static/root/assets/local-app-workbench-page-De8vuwu1.js +2 -0
  49. package/dist/gateway/static/root/assets/{local-apps-page-DBpQIfNd.js → local-apps-page-CzS2sCxg.js} +1 -1
  50. package/dist/gateway/static/root/assets/{locale-store-CbPVxonP.js → locale-store-C7xtkP3D.js} +1 -1
  51. package/dist/gateway/static/root/assets/logs-page-BI9stsVO.js +2 -0
  52. package/dist/gateway/static/root/assets/{management-settings-CiK7Xkvi.js → management-settings-Cpxs43JB.js} +1 -1
  53. package/dist/gateway/static/root/assets/{markdown-split-DVgpcOze.js → markdown-split-CQvFHxUa.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-view-Dl-0_9JR.js → markdown-view-BRwrSbwM.js} +1 -1
  55. package/dist/gateway/static/root/assets/{media-plugins-DMj1lW-n.js → media-plugins-Bs9MsiaM.js} +1 -1
  56. package/dist/gateway/static/root/assets/messages-Dxk5Rzj_.js +3 -0
  57. package/dist/gateway/static/root/assets/{notes-page-DvX1sTlf.js → notes-page-Dux_g6aZ.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-CGafcgJ8.js +4 -0
  59. package/dist/gateway/static/root/assets/{preview-open-alternatives-DvsLigha.js → preview-open-alternatives-fvhtN4Y2.js} +1 -1
  60. package/dist/gateway/static/root/assets/{product-open-page-DbCraAI3.js → product-open-page-f_jbg-9N.js} +1 -1
  61. package/dist/gateway/static/root/assets/project-detail-page-C6mNsjYr.js +1 -0
  62. package/dist/gateway/static/root/assets/projects-page-D1G6VIxR.js +1 -0
  63. package/dist/gateway/static/root/assets/remote-access-hub-CIez6X0x.js +1 -0
  64. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DzuUglQo.js → runtime-tools-settings-panel-zapSiJrv.js} +1 -1
  65. package/dist/gateway/static/root/assets/{schema-form-plDnazVj.js → schema-form-CFyz8y5v.js} +1 -1
  66. package/dist/gateway/static/root/assets/sessions-page-6irxQjHb.js +1 -0
  67. package/dist/gateway/static/root/assets/settings-advanced-gate-CRb0QTG2.js +1 -0
  68. package/dist/gateway/static/root/assets/{settings-form-section-BwAxX_7e.js → settings-form-section-DCiK4TIq.js} +1 -1
  69. package/dist/gateway/static/root/assets/{settings-loading-skeleton-B3OiTnF9.js → settings-loading-skeleton-DFUJEv4G.js} +1 -1
  70. package/dist/gateway/static/root/assets/{settings-page-DvIWXBvp.js → settings-page-Cnp9Bdd0.js} +1 -1
  71. package/dist/gateway/static/root/assets/{setup-status-panel-DThKKjLV.js → setup-status-panel-BFMGTGBO.js} +1 -1
  72. package/dist/gateway/static/root/assets/{share-preview-page-CFnoGHJb.js → share-preview-page-DA8nA4cz.js} +1 -1
  73. package/dist/gateway/static/root/assets/shares-settings-CaKfvJzQ.js +1 -0
  74. package/dist/gateway/static/root/assets/skill-reload-api-BOBUcYr5.js +1 -0
  75. package/dist/gateway/static/root/assets/{skills-page-B38fY22S.js → skills-page-BJJACxzz.js} +1 -1
  76. package/dist/gateway/static/root/assets/{skills-page.utils-vLIlk1c3.js → skills-page.utils--1-vOg3V.js} +1 -1
  77. package/dist/gateway/static/root/assets/{system-settings-panel-DRV2wljT.js → system-settings-panel-DY0lIaXY.js} +1 -1
  78. package/dist/gateway/static/root/assets/task-detail-page-Ciuwe7AG.js +1 -0
  79. package/dist/gateway/static/root/assets/{theme-store-Bc_eRUev.js → theme-store-DoyRfkoi.js} +1 -1
  80. package/dist/gateway/static/root/assets/{use-autosave-DTu23D9J.js → use-autosave-DzIR5Lxf.js} +1 -1
  81. package/dist/gateway/static/root/assets/{user-context-page-DCwqzN03.js → user-context-page-yf18T_BZ.js} +1 -1
  82. package/dist/gateway/static/root/assets/{voice-api-key-field-CVDMesWc.js → voice-api-key-field-B7MZS8tS.js} +1 -1
  83. package/dist/gateway/static/root/assets/{work-discovery-overlay-cyt93k0V.js → work-discovery-overlay-zyX6yxxF.js} +1 -1
  84. package/dist/gateway/static/root/assets/work-discovery-page-2e5J0sIp.js +1 -0
  85. package/dist/gateway/static/root/assets/workflow-run-setup-panel-Cj1vPWRM.js +3 -0
  86. package/dist/gateway/static/root/assets/workflows-page-D37zWlWY.js +5 -0
  87. package/dist/gateway/static/root/assets/{working-directory-picker-modal-CYWdZUJ5.js → working-directory-picker-modal-Bm7cox3y.js} +1 -1
  88. package/dist/gateway/static/root/index.html +10 -10
  89. package/dist/package.js +1 -1
  90. package/dist/src/agent/agent-manager.d.ts +11 -0
  91. package/dist/src/agent/agent-manager.js +36 -6
  92. package/dist/src/agent/embedded/transcript-runtime.d.ts +2 -1
  93. package/dist/src/agent/embedded/transcript-runtime.js +38 -4
  94. package/dist/src/agent/inbound/inbound-loop.d.ts +1 -1
  95. package/dist/src/agent/memory/compaction-ledger.d.ts +11 -0
  96. package/dist/src/agent/memory/compaction-ledger.js +108 -0
  97. package/dist/src/agent/memory/compaction-serializer.d.ts +2 -0
  98. package/dist/src/agent/memory/compaction-serializer.js +52 -0
  99. package/dist/src/agent/memory/compaction-source-planner.d.ts +20 -0
  100. package/dist/src/agent/memory/compaction-source-planner.js +67 -0
  101. package/dist/src/agent/memory/compaction.d.ts +11 -5
  102. package/dist/src/agent/memory/compaction.js +245 -153
  103. package/dist/src/agent/prompt/sections/behavior.js +1 -1
  104. package/dist/src/agent/prompt/sections/memory-skills.js +4 -2
  105. package/dist/src/agent/prompt/sections/tooling.js +2 -0
  106. package/dist/src/agent/service.d.ts +4 -1
  107. package/dist/src/agent/service.js +12 -0
  108. package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -1
  109. package/dist/src/agent/tool-manuals/xopc-use.js +1 -1
  110. package/dist/src/agent/tools/factory.js +5 -0
  111. package/dist/src/agent/tools/index.d.ts +1 -0
  112. package/dist/src/agent/tools/index.js +2 -1
  113. package/dist/src/agent/tools/session-recall-tool.d.ts +7 -0
  114. package/dist/src/agent/tools/session-recall-tool.js +82 -0
  115. package/dist/src/agent/tools/xopc-use-tool.js +6 -2
  116. package/dist/src/automations/api/routes.js +8 -0
  117. package/dist/src/automations/domain/index.js +2 -2
  118. package/dist/src/automations/domain/types.d.ts +17 -12
  119. package/dist/src/automations/domain/validation.d.ts +30 -32
  120. package/dist/src/automations/domain/validation.js +8 -10
  121. package/dist/src/automations/draft/automation-draft-prompt.js +9 -5
  122. package/dist/src/automations/draft/automation-draft-validator.d.ts +3 -8
  123. package/dist/src/automations/draft/automation-draft-validator.js +3 -3
  124. package/dist/src/automations/index.js +2 -2
  125. package/dist/src/automations/service/action-executor.js +13 -4
  126. package/dist/src/automations/service/automation-service.d.ts +5 -1
  127. package/dist/src/automations/service/automation-service.js +19 -12
  128. package/dist/src/automations/storage/automation-repository.js +8 -4
  129. package/dist/src/automations/storage/automation-run-repository.d.ts +5 -0
  130. package/dist/src/automations/storage/automation-run-repository.js +24 -8
  131. package/dist/src/automations/storage/index.js +2 -2
  132. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  133. package/dist/src/config/agent-profile.js +1 -1
  134. package/dist/src/config/schema.d.ts +1 -0
  135. package/dist/src/gateway/agents-admin.js +1 -1
  136. package/dist/src/gateway/automation-agent-session.d.ts +4 -0
  137. package/dist/src/gateway/automation-agent-session.js +40 -0
  138. package/dist/src/gateway/dreaming-automation-reconciler.js +3 -2
  139. package/dist/src/gateway/heartbeat/service.js +1 -1
  140. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -0
  141. package/dist/src/gateway/hono/routes/commands-skills.js +36 -2
  142. package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -0
  143. package/dist/src/gateway/service/marketplace-service.d.ts +4 -1
  144. package/dist/src/gateway/service/marketplace-service.js +9 -0
  145. package/dist/src/gateway/service/run-gateway-agent.js +3 -3
  146. package/dist/src/gateway/service.js +19 -2
  147. package/dist/src/heartbeat/index.js +1 -1
  148. package/dist/src/mobile/notification-service.js +7 -4
  149. package/dist/src/session/compaction-types.d.ts +30 -0
  150. package/dist/src/session/compaction-types.js +35 -0
  151. package/dist/src/session/manager.d.ts +3 -0
  152. package/dist/src/session/session-context-for-llm.d.ts +4 -2
  153. package/dist/src/session/session-context-for-llm.js +2 -1
  154. package/dist/src/session/store.d.ts +10 -1
  155. package/dist/src/session/store.js +55 -23
  156. package/dist/src/session/types.d.ts +3 -2
  157. package/dist/src/storage/sqlite/index.d.ts +1 -1
  158. package/dist/src/storage/sqlite/index.js +2 -2
  159. package/dist/src/storage/sqlite/migrations/121_automation_inbox.sql +24 -0
  160. package/dist/src/storage/sqlite/migrations/122_automation_session_projects.sql +18 -0
  161. package/dist/src/storage/sqlite/migrations/123_remove_v2_compaction_boundaries.sql +25 -0
  162. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  163. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  164. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  165. package/dist/src/storage/sqlite/schema.js +1 -1
  166. package/dist/src/storage/sqlite/transcript-repository.d.ts +24 -1
  167. package/dist/src/storage/sqlite/transcript-repository.js +78 -29
  168. package/dist/src/user-context/config.d.ts +4 -0
  169. package/dist/src/user-context/config.js +2 -0
  170. package/package.json +4 -3
  171. package/skills/THIRD_PARTY_NOTICES.md +1 -1
  172. package/skills/engineering/define-task/SKILL.md +48 -0
  173. package/skills/engineering/define-task/references/task-contract-rubric.md +15 -0
  174. package/dist/gateway/static/root/assets/agents-DnFIy8Ye.js +0 -68
  175. package/dist/gateway/static/root/assets/apps-page-CONlVc-f.js +0 -1
  176. package/dist/gateway/static/root/assets/automations-page-DuG69tIj.js +0 -6
  177. package/dist/gateway/static/root/assets/browser-settings-page-Cvt-8fqE.js +0 -8
  178. package/dist/gateway/static/root/assets/capabilities-settings-panel-yk3QkGBP.js +0 -7
  179. package/dist/gateway/static/root/assets/capability-presets-settings-panel-DJjVOCJY.js +0 -3
  180. package/dist/gateway/static/root/assets/channels-settings-CaNnYUQo.js +0 -1
  181. package/dist/gateway/static/root/assets/channels-status-swr-CZ5P9jbB.js +0 -1
  182. package/dist/gateway/static/root/assets/connectors-page-DTpCnOsQ.js +0 -2
  183. package/dist/gateway/static/root/assets/directory-picker-path-field-Ly0TUflq.js +0 -1
  184. package/dist/gateway/static/root/assets/heartbeat-settings-CMZr1_Op.js +0 -1
  185. package/dist/gateway/static/root/assets/home-page-CBG9Bk-1.js +0 -3
  186. package/dist/gateway/static/root/assets/index-BBw9QL0p.js +0 -85
  187. package/dist/gateway/static/root/assets/index-Dm-cvIpl.css +0 -2
  188. package/dist/gateway/static/root/assets/local-app-workbench-page-Bi_0Sknt.js +0 -2
  189. package/dist/gateway/static/root/assets/logs-page-BmXcJCKz.js +0 -2
  190. package/dist/gateway/static/root/assets/messages-9zCa8KkW.js +0 -3
  191. package/dist/gateway/static/root/assets/notes-workbench-CMyosgjY.js +0 -4
  192. package/dist/gateway/static/root/assets/project-detail-page-DkS-kbpj.js +0 -1
  193. package/dist/gateway/static/root/assets/projects-page-B3NxP6S4.js +0 -1
  194. package/dist/gateway/static/root/assets/remote-access-hub-DwhrMhjl.js +0 -1
  195. package/dist/gateway/static/root/assets/sessions-page-BOfXXmBL.js +0 -1
  196. package/dist/gateway/static/root/assets/settings-advanced-gate-sPrZfZVR.js +0 -1
  197. package/dist/gateway/static/root/assets/shares-settings-Dvl13Udt.js +0 -1
  198. package/dist/gateway/static/root/assets/skill-reload-api-D9elkZOz.js +0 -1
  199. package/dist/gateway/static/root/assets/task-detail-page-Xd8PlB24.js +0 -1
  200. package/dist/gateway/static/root/assets/work-discovery-page--DTi90d5.js +0 -1
  201. package/dist/gateway/static/root/assets/workflow-run-setup-panel-DrdcfX_N.js +0 -3
  202. package/dist/gateway/static/root/assets/workflows-page-DXyButkm.js +0 -5
  203. package/dist/src/agent/memory/compaction-planner.d.ts +0 -16
  204. package/dist/src/agent/memory/compaction-planner.js +0 -168
  205. package/dist/src/agent/memory/summary-generator.d.ts +0 -46
  206. package/dist/src/agent/memory/summary-generator.js +0 -229
  207. package/skills/engineering/define-goal/SKILL.md +0 -41
  208. package/skills/engineering/define-goal/references/objective-rubric.md +0 -12
@@ -49,6 +49,10 @@ export declare class AutomationService {
49
49
  }): Promise<AutomationProductEventRun[]>;
50
50
  getRun(runId: string): Promise<AutomationRun | null>;
51
51
  listRunEvents(runId: string): Promise<AutomationRunEvent[]>;
52
+ markRunRead(runId: string): Promise<boolean>;
53
+ markAllRunsRead(options?: {
54
+ projectId?: string;
55
+ }): Promise<number>;
52
56
  cancelRun(runId: string): Promise<boolean>;
53
57
  getMetrics(): Promise<AutomationMetrics>;
54
58
  private recomputeNextRuns;
@@ -60,5 +64,5 @@ export declare class AutomationService {
60
64
  private waitForRetry;
61
65
  private appendRunEvent;
62
66
  private finishAutomationRun;
63
- private postAfterRunWebhook;
67
+ private postCompletionWebhook;
64
68
  }
@@ -5,7 +5,7 @@ import { computeNextAutomationRunAtMs, timerDelayUntil } from "../domain/schedul
5
5
  import { AutomationSchema, CreateAutomationSchema, UpdateAutomationSchema } from "../domain/validation.js";
6
6
  import { AutomationActionExecutor } from "./action-executor.js";
7
7
  import { deleteAutomation, getAutomation, listAutomations, saveAutomation, saveAutomations } from "../storage/automation-repository.js";
8
- import { appendAutomationRunEvent, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, saveAutomationRun, touchAutomationRunLease } from "../storage/automation-run-repository.js";
8
+ import { appendAutomationRunEvent, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, markAllAutomationRunsRead, markAutomationRunRead, saveAutomationRun, touchAutomationRunLease } from "../storage/automation-run-repository.js";
9
9
  import "../storage/index.js";
10
10
  import { randomUUID } from "node:crypto";
11
11
  //#region src/automations/service/automation-service.ts
@@ -71,7 +71,8 @@ var AutomationService = class {
71
71
  id: parsed.id?.trim() || randomUUID().slice(0, 12),
72
72
  enabled: parsed.enabled ?? true,
73
73
  safety: parsed.safety ?? { mode: "auto_apply" },
74
- afterRun: parsed.afterRun ?? { kind: "none" },
74
+ conversationMode: parsed.conversationMode ?? "new_session",
75
+ notificationPolicy: parsed.notificationPolicy ?? "attention",
75
76
  state: parsed.state ?? {},
76
77
  createdAtMs: now,
77
78
  updatedAtMs: now
@@ -165,6 +166,12 @@ var AutomationService = class {
165
166
  async listRunEvents(runId) {
166
167
  return listAutomationRunEvents(runId);
167
168
  }
169
+ async markRunRead(runId) {
170
+ return markAutomationRunRead(runId);
171
+ }
172
+ async markAllRunsRead(options) {
173
+ return markAllAutomationRunsRead(options);
174
+ }
168
175
  async cancelRun(runId) {
169
176
  const controller = this.activeRuns.get(runId);
170
177
  if (!controller) return false;
@@ -389,30 +396,30 @@ var AutomationService = class {
389
396
  };
390
397
  this.appendRunEvent(run, task.termination.cancellationConfirmed ? "run.cancel_confirmed" : "run.cancellation_unconfirmed", task.termination.cancellationConfirmed ? "Automation cancellation confirmed" : "Automation cancellation was not confirmed within the cleanup grace period", { termination: task.termination });
391
398
  }
392
- if (status === "timeout" || status === "cancelled") {} else if ((automation.safety?.mode ?? "auto_apply") !== "auto_apply" && automation.afterRun?.kind === "webhook") this.appendRunEvent(run, "after_run.completed", "After-run webhook skipped by safety mode", { safety: automation.safety ?? { mode: "auto_apply" } });
393
- else if (automation.afterRun?.kind === "webhook") {
394
- activePhase = "after_run";
399
+ if (status === "timeout" || status === "cancelled") {} else if ((automation.safety?.mode ?? "auto_apply") !== "auto_apply" && automation.completionWebhookUrl) this.appendRunEvent(run, "completion_hook.completed", "Completion webhook skipped by safety mode", { safety: automation.safety ?? { mode: "auto_apply" } });
400
+ else if (automation.completionWebhookUrl) {
401
+ activePhase = "completion_hook";
395
402
  run = {
396
403
  ...run,
397
- currentPhase: "after_run"
404
+ currentPhase: "completion_hook"
398
405
  };
399
406
  saveAutomationRun(run);
400
- this.appendRunEvent(run, "after_run.started", "Calling after-run webhook", { url: automation.afterRun.url });
401
- await this.postAfterRunWebhook(automation.afterRun.url, run, controller.signal);
402
- this.appendRunEvent(run, "after_run.completed", "After-run webhook completed");
407
+ this.appendRunEvent(run, "completion_hook.started", "Calling completion webhook", { url: automation.completionWebhookUrl });
408
+ await this.postCompletionWebhook(automation.completionWebhookUrl, run, controller.signal);
409
+ this.appendRunEvent(run, "completion_hook.completed", "Completion webhook completed");
403
410
  }
404
411
  } catch (err) {
405
412
  error = err instanceof Error ? err.message : String(err);
406
413
  const deadlineExceeded = run.deadlineAtMs !== void 0 && Date.now() >= run.deadlineAtMs;
407
414
  status = controller.signal.aborted ? "cancelled" : deadlineExceeded ? "timeout" : "failed";
408
- this.appendRunEvent(run, activePhase === "after_run" ? "after_run.failed" : "action.failed", `Automation run ${status}`, { error });
415
+ this.appendRunEvent(run, activePhase === "completion_hook" ? "completion_hook.failed" : "action.failed", `Automation run ${status}`, { error });
409
416
  run = {
410
417
  ...run,
411
418
  status,
412
419
  error,
413
420
  termination: {
414
421
  reason: status === "cancelled" ? "user_cancelled" : status === "timeout" ? "deadline_exceeded" : "failed",
415
- component: activePhase === "after_run" ? "automation" : run.termination?.component,
422
+ component: activePhase === "completion_hook" ? "automation" : run.termination?.component,
416
423
  cancellationConfirmed: status !== "cancelled" || controller.signal.aborted
417
424
  }
418
425
  };
@@ -580,7 +587,7 @@ var AutomationService = class {
580
587
  saveAutomation(next);
581
588
  this.armTimer();
582
589
  }
583
- async postAfterRunWebhook(url, run, signal) {
590
+ async postCompletionWebhook(url, run, signal) {
584
591
  const remainingMs = run.deadlineAtMs === void 0 ? 3e4 : Math.max(1, run.deadlineAtMs - Date.now());
585
592
  const requestSignal = AbortSignal.any([signal, AbortSignal.timeout(remainingMs)]);
586
593
  const response = await fetch(url, {
@@ -18,7 +18,9 @@ function rowToAutomation(row) {
18
18
  trigger: parseJson(row.trigger_json),
19
19
  action: parseJson(row.action_json),
20
20
  safety: parseJson(row.safety_json) ?? { mode: "auto_apply" },
21
- afterRun: parseJson(row.after_run_json),
21
+ conversationMode: row.conversation_mode,
22
+ notificationPolicy: row.notification_policy,
23
+ completionWebhookUrl: row.completion_webhook_url ?? void 0,
22
24
  reliability: parseJson(row.reliability_json),
23
25
  state: parseJson(row.state_json) ?? {},
24
26
  createdAtMs: row.created_at_ms,
@@ -28,12 +30,14 @@ function rowToAutomation(row) {
28
30
  function upsertAutomation(db, automation) {
29
31
  db.prepare(`INSERT OR REPLACE INTO automations (
30
32
  automation_id, name, description, project_id, enabled, trigger_json, action_json,
31
- safety_json, after_run_json, reliability_json, state_json, created_at_ms, updated_at_ms
32
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(automation.id, automation.name, automation.description ?? null, automation.projectId ?? null, automation.enabled ? 1 : 0, JSON.stringify(automation.trigger), JSON.stringify(automation.action), bindJson(automation.safety ?? { mode: "auto_apply" }), bindJson(automation.afterRun), bindJson(automation.reliability), JSON.stringify(automation.state ?? {}), automation.createdAtMs, automation.updatedAtMs);
33
+ safety_json, conversation_mode, notification_policy, completion_webhook_url,
34
+ reliability_json, state_json, created_at_ms, updated_at_ms
35
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(automation.id, automation.name, automation.description ?? null, automation.projectId ?? null, automation.enabled ? 1 : 0, JSON.stringify(automation.trigger), JSON.stringify(automation.action), bindJson(automation.safety ?? { mode: "auto_apply" }), automation.conversationMode, automation.notificationPolicy, automation.completionWebhookUrl ?? null, bindJson(automation.reliability), JSON.stringify(automation.state ?? {}), automation.createdAtMs, automation.updatedAtMs);
33
36
  }
34
37
  const AUTOMATION_SELECT = `
35
38
  SELECT automation_id, name, description, project_id, enabled, trigger_json, action_json,
36
- safety_json, after_run_json, reliability_json, state_json, created_at_ms, updated_at_ms
39
+ safety_json, conversation_mode, notification_policy, completion_webhook_url,
40
+ reliability_json, state_json, created_at_ms, updated_at_ms
37
41
  FROM automations
38
42
  `;
39
43
  function listAutomations(options) {
@@ -17,3 +17,8 @@ export declare function listAutomationRunsForProductEvent(options: {
17
17
  limit?: number;
18
18
  }): AutomationProductEventRun[];
19
19
  export declare function deleteAutomationRunsForAutomation(automationId: string): void;
20
+ export declare function markAutomationRunRead(runId: string, readAtMs?: number): boolean;
21
+ export declare function markAllAutomationRunsRead(options?: {
22
+ projectId?: string;
23
+ readAtMs?: number;
24
+ }): number;
@@ -29,7 +29,8 @@ function rowToRun(row) {
29
29
  leaseOwner: row.lease_owner ?? void 0,
30
30
  leaseExpiresAtMs: row.lease_expires_at_ms ?? void 0,
31
31
  attemptNumber: row.attempt_number,
32
- rootRunId: row.root_run_id ?? void 0
32
+ rootRunId: row.root_run_id ?? void 0,
33
+ readAtMs: row.read_at_ms ?? void 0
33
34
  };
34
35
  }
35
36
  function rowToEvent(row) {
@@ -68,8 +69,8 @@ function saveAutomationRun(run) {
68
69
  duration_ms, summary, error, session_key, workflow_run_id, model,
69
70
  deadline_at_ms, current_phase, cancel_requested_at_ms, cancel_confirmed_at_ms,
70
71
  termination_json, heartbeat_at_ms, lease_owner, lease_expires_at_ms,
71
- attempt_number, root_run_id
72
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(run.id, run.automationId, run.automationName, run.status, JSON.stringify(run.triggerSnapshot), JSON.stringify(run.actionSnapshot), run.manual ? 1 : 0, run.createdAtMs, run.startedAtMs ?? null, run.endedAtMs ?? null, run.durationMs ?? null, run.summary ?? null, run.error ?? null, run.sessionKey ?? null, run.workflowRunId ?? null, run.model ?? null, run.deadlineAtMs ?? null, run.currentPhase ?? null, run.cancelRequestedAtMs ?? null, run.cancelConfirmedAtMs ?? null, run.termination ? JSON.stringify(run.termination) : null, run.heartbeatAtMs ?? null, run.leaseOwner ?? null, run.leaseExpiresAtMs ?? null, run.attemptNumber ?? 1, run.rootRunId ?? run.id);
72
+ attempt_number, root_run_id, read_at_ms
73
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(run.id, run.automationId, run.automationName, run.status, JSON.stringify(run.triggerSnapshot), JSON.stringify(run.actionSnapshot), run.manual ? 1 : 0, run.createdAtMs, run.startedAtMs ?? null, run.endedAtMs ?? null, run.durationMs ?? null, run.summary ?? null, run.error ?? null, run.sessionKey ?? null, run.workflowRunId ?? null, run.model ?? null, run.deadlineAtMs ?? null, run.currentPhase ?? null, run.cancelRequestedAtMs ?? null, run.cancelConfirmedAtMs ?? null, run.termination ? JSON.stringify(run.termination) : null, run.heartbeatAtMs ?? null, run.leaseOwner ?? null, run.leaseExpiresAtMs ?? null, run.attemptNumber ?? 1, run.rootRunId ?? run.id, run.readAtMs ?? null);
73
74
  trimRuns(db, run.automationId);
74
75
  });
75
76
  }
@@ -90,7 +91,7 @@ function getAutomationRun(runId) {
90
91
  duration_ms, summary, error, session_key, workflow_run_id, model,
91
92
  deadline_at_ms, current_phase, cancel_requested_at_ms, cancel_confirmed_at_ms,
92
93
  termination_json, heartbeat_at_ms, lease_owner, lease_expires_at_ms,
93
- attempt_number, root_run_id
94
+ attempt_number, root_run_id, read_at_ms
94
95
  FROM automation_runs
95
96
  WHERE run_id = ?`).get(runId);
96
97
  return row ? rowToRun(row) : null;
@@ -103,7 +104,7 @@ function listAutomationRuns(options) {
103
104
  duration_ms, summary, error, session_key, workflow_run_id, model,
104
105
  deadline_at_ms, current_phase, cancel_requested_at_ms, cancel_confirmed_at_ms,
105
106
  termination_json, heartbeat_at_ms, lease_owner, lease_expires_at_ms,
106
- attempt_number, root_run_id
107
+ attempt_number, root_run_id, read_at_ms
107
108
  FROM automation_runs`;
108
109
  let rows;
109
110
  if (options?.automationId) rows = db.prepare(`${base} WHERE automation_id = ? ORDER BY created_at_ms DESC LIMIT ?`).all(options.automationId, limit);
@@ -112,7 +113,7 @@ function listAutomationRuns(options) {
112
113
  r.duration_ms, r.summary, r.error, r.session_key, r.workflow_run_id, r.model,
113
114
  r.deadline_at_ms, r.current_phase, r.cancel_requested_at_ms, r.cancel_confirmed_at_ms,
114
115
  r.termination_json, r.heartbeat_at_ms, r.lease_owner, r.lease_expires_at_ms,
115
- r.attempt_number, r.root_run_id
116
+ r.attempt_number, r.root_run_id, r.read_at_ms
116
117
  FROM automation_runs r
117
118
  JOIN automations a ON a.automation_id = r.automation_id
118
119
  WHERE a.project_id = ?
@@ -138,7 +139,7 @@ function listAutomationRunsForProductEvent(options) {
138
139
  r.duration_ms, r.summary, r.error, r.session_key, r.workflow_run_id, r.model,
139
140
  r.deadline_at_ms, r.current_phase, r.cancel_requested_at_ms, r.cancel_confirmed_at_ms,
140
141
  r.termination_json, r.heartbeat_at_ms, r.lease_owner, r.lease_expires_at_ms,
141
- r.attempt_number, r.root_run_id,
142
+ r.attempt_number, r.root_run_id, r.read_at_ms,
142
143
  e.event_id, e.run_id AS event_run_id, e.automation_id AS event_automation_id,
143
144
  e.type AS event_type, e.message AS event_message, e.data_json AS event_data_json,
144
145
  e.created_at_ms AS event_created_at_ms
@@ -165,5 +166,20 @@ function deleteAutomationRunsForAutomation(automationId) {
165
166
  db.prepare(`DELETE FROM automation_runs WHERE automation_id = ?`).run(automationId);
166
167
  });
167
168
  }
169
+ function markAutomationRunRead(runId, readAtMs = Date.now()) {
170
+ return getSqliteDatabase().prepare(`UPDATE automation_runs SET read_at_ms = ? WHERE run_id = ? AND ended_at_ms IS NOT NULL`).run(readAtMs, runId).changes > 0;
171
+ }
172
+ function markAllAutomationRunsRead(options) {
173
+ const projectId = options?.projectId?.trim();
174
+ const result = getSqliteDatabase().prepare(projectId ? `UPDATE automation_runs
175
+ SET read_at_ms = ?
176
+ WHERE read_at_ms IS NULL
177
+ AND ended_at_ms IS NOT NULL
178
+ AND EXISTS (
179
+ SELECT 1 FROM automations a
180
+ WHERE a.automation_id = automation_runs.automation_id AND a.project_id = ?
181
+ )` : `UPDATE automation_runs SET read_at_ms = ? WHERE read_at_ms IS NULL AND ended_at_ms IS NOT NULL`).run(options?.readAtMs ?? Date.now(), ...projectId ? [projectId] : []);
182
+ return Number(result.changes);
183
+ }
168
184
  //#endregion
169
- export { appendAutomationRunEvent, deleteAutomationRunsForAutomation, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, saveAutomationRun, touchAutomationRunLease };
185
+ export { appendAutomationRunEvent, deleteAutomationRunsForAutomation, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, markAllAutomationRunsRead, markAutomationRunRead, saveAutomationRun, touchAutomationRunLease };
@@ -1,3 +1,3 @@
1
1
  import { deleteAutomation, getAutomation, listAutomations, saveAutomation, saveAutomations } from "./automation-repository.js";
2
- import { appendAutomationRunEvent, deleteAutomationRunsForAutomation, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, saveAutomationRun, touchAutomationRunLease } from "./automation-run-repository.js";
3
- export { appendAutomationRunEvent, deleteAutomation, deleteAutomationRunsForAutomation, getAutomation, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, listAutomations, saveAutomation, saveAutomationRun, saveAutomations, touchAutomationRunLease };
2
+ import { appendAutomationRunEvent, deleteAutomationRunsForAutomation, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, markAllAutomationRunsRead, markAutomationRunRead, saveAutomationRun, touchAutomationRunLease } from "./automation-run-repository.js";
3
+ export { appendAutomationRunEvent, deleteAutomation, deleteAutomationRunsForAutomation, getAutomation, getAutomationRun, listAutomationRunEvents, listAutomationRuns, listAutomationRunsForProductEvent, listAutomations, markAllAutomationRunsRead, markAutomationRunRead, saveAutomation, saveAutomationRun, saveAutomations, touchAutomationRunLease };
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
52
52
  id: "database-schema",
53
53
  label: "Database schema",
54
54
  status: "pass",
55
- message: `SQLite schema v${status.dbVersion} (current release v120).`,
55
+ message: `SQLite schema v${status.dbVersion} (current release v123).`,
56
56
  hints: []
57
57
  };
58
58
  }
@@ -1,6 +1,6 @@
1
- import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
2
1
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
3
2
  import "../agent-manifest/index.js";
3
+ import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
4
4
  import { init_session_key, parseSessionKey } from "../routing/session-key.js";
5
5
  import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
6
6
  //#region src/config/agent-profile.ts
@@ -1537,6 +1537,7 @@ export declare const ConfigSchema: z.ZodDefault<z.ZodObject<{
1537
1537
  summaryTimeoutMs: z.ZodDefault<z.ZodNumber>;
1538
1538
  summaryRetries: z.ZodDefault<z.ZodNumber>;
1539
1539
  qualityGuard: z.ZodDefault<z.ZodBoolean>;
1540
+ gapAudit: z.ZodDefault<z.ZodBoolean>;
1540
1541
  model: z.ZodOptional<z.ZodString>;
1541
1542
  minToolResultKeepChars: z.ZodDefault<z.ZodNumber>;
1542
1543
  maxActiveTranscriptBytes: z.ZodDefault<z.ZodNumber>;
@@ -1,5 +1,5 @@
1
- import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
2
1
  import { resolveCapabilityPresetLayer, resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
2
+ import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
3
3
  import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
4
4
  import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
5
5
  import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
@@ -0,0 +1,4 @@
1
+ import type { PrepareAutomationAgentSessionInput } from '../automations/index.js';
2
+ import type { ProjectService } from '../projects/index.js';
3
+ import type { SessionStore } from '../session/index.js';
4
+ export declare function prepareAutomationAgentSession(store: SessionStore, projects: ProjectService, input: PrepareAutomationAgentSessionInput): Promise<void>;
@@ -0,0 +1,40 @@
1
+ //#region src/gateway/automation-agent-session.ts
2
+ async function prepareAutomationAgentSession(store, projects, input) {
3
+ await store.resolveTranscriptPath(input.sessionKey, { metadata: {
4
+ projectId: input.projectId,
5
+ sourceChannel: "automation",
6
+ sourceChatId: `default:dm:${input.peerId}`,
7
+ sessionType: "chat",
8
+ routing: {
9
+ agentId: input.agentId,
10
+ source: "automation",
11
+ accountId: "default",
12
+ peerKind: "dm",
13
+ peerId: input.peerId
14
+ }
15
+ } });
16
+ const current = await store.getMetadata(input.sessionKey);
17
+ await store.updateMetadata(input.sessionKey, {
18
+ sourceChannel: "automation",
19
+ sourceChatId: `default:dm:${input.peerId}`,
20
+ sessionType: "chat",
21
+ routing: {
22
+ agentId: input.agentId,
23
+ source: "automation",
24
+ accountId: "default",
25
+ peerKind: "dm",
26
+ peerId: input.peerId
27
+ },
28
+ tags: [...new Set([...current?.tags ?? [], "automation"])],
29
+ customData: {
30
+ ...current?.customData ?? {},
31
+ origin: "automation",
32
+ automationId: input.automationId,
33
+ latestAutomationRunId: input.runId
34
+ }
35
+ });
36
+ if (input.projectId) projects.attachSession(input.sessionKey, input.projectId);
37
+ else if (current?.projectId) projects.detachSession(input.sessionKey);
38
+ }
39
+ //#endregion
40
+ export { prepareAutomationAgentSession };
@@ -41,7 +41,8 @@ async function reconcileDreamingAutomations(params) {
41
41
  trigger,
42
42
  action,
43
43
  safety: { mode: "auto_apply" },
44
- afterRun: { kind: "none" },
44
+ conversationMode: "continuous",
45
+ notificationPolicy: "none",
45
46
  reliability: { disableAfterConsecutiveFailures: 3 }
46
47
  };
47
48
  if (!current) {
@@ -52,7 +53,7 @@ async function reconcileDreamingAutomations(params) {
52
53
  result.created = true;
53
54
  return result;
54
55
  }
55
- if (current.name !== next.name || current.description !== next.description || !current.enabled || JSON.stringify(current.trigger) !== JSON.stringify(trigger) || JSON.stringify(current.action) !== JSON.stringify(action) || current.safety?.mode !== "auto_apply" || current.afterRun?.kind !== "none" || current.reliability?.disableAfterConsecutiveFailures !== 3) {
56
+ if (current.name !== next.name || current.description !== next.description || !current.enabled || JSON.stringify(current.trigger) !== JSON.stringify(trigger) || JSON.stringify(current.action) !== JSON.stringify(action) || current.safety?.mode !== "auto_apply" || current.conversationMode !== "continuous" || current.notificationPolicy !== "none" || current.reliability?.disableAfterConsecutiveFailures !== 3) {
56
57
  await params.automationService.update(USER_CONTEXT_CONSOLIDATION_AUTOMATION_ID, next);
57
58
  result.updated = true;
58
59
  }
@@ -1,9 +1,9 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { shouldSilence, stripHeartbeatToken } from "../../heartbeat/tokens.js";
4
+ import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
4
5
  import { isWithinActiveHours } from "../../heartbeat/active-hours.js";
5
6
  import { isHeartbeatContentEmpty } from "../../heartbeat/content-check.js";
6
- import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
7
7
  import { createHeartbeatWake } from "../../heartbeat/wake.js";
8
8
  import { resolveHeartbeatMdPath } from "../workspace-heartbeat-path.js";
9
9
  import { readFile } from "fs/promises";
@@ -320,6 +320,7 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
320
320
  summaryTimeoutMs: number;
321
321
  summaryRetries: number;
322
322
  qualityGuard: boolean;
323
+ gapAudit: boolean;
323
324
  minToolResultKeepChars: number;
324
325
  maxActiveTranscriptBytes: number;
325
326
  postCompactionSections: string[];
@@ -74,9 +74,43 @@ function registerCommandsSkillsRoutes(authenticated, deps) {
74
74
  }, 400);
75
75
  }
76
76
  });
77
- authenticated.get("/api/chat/skills", (c) => {
77
+ authenticated.get("/api/chat/skills", async (c) => {
78
+ const sessionKey = c.req.query("sessionKey")?.trim();
78
79
  const agentId = c.req.query("agentId")?.trim() || service.getConfig().agents?.default || "main";
79
- const payload = service.marketplace.getAgentSkillsApi(agentId);
80
+ const payload = sessionKey ? await service.marketplace.getSessionSkillsApi(sessionKey) : service.marketplace.getAgentSkillsApi(agentId);
81
+ return c.json({
82
+ ok: true,
83
+ payload
84
+ });
85
+ });
86
+ authenticated.get("/api/chat/workspace-trust", async (c) => {
87
+ const sessionKey = c.req.query("sessionKey")?.trim();
88
+ if (!sessionKey) return c.json({
89
+ ok: false,
90
+ error: "Missing sessionKey"
91
+ }, 400);
92
+ const payload = await service.marketplace.getSessionWorkspaceTrustApi(sessionKey);
93
+ return c.json({
94
+ ok: true,
95
+ payload
96
+ });
97
+ });
98
+ authenticated.patch("/api/chat/workspace-trust", async (c) => {
99
+ let body;
100
+ try {
101
+ body = await c.req.json();
102
+ } catch {
103
+ return c.json({
104
+ ok: false,
105
+ error: "Invalid JSON"
106
+ }, 400);
107
+ }
108
+ const sessionKey = typeof body.sessionKey === "string" ? body.sessionKey.trim() : "";
109
+ if (!sessionKey || typeof body.trusted !== "boolean") return c.json({
110
+ ok: false,
111
+ error: "Expected { sessionKey: string, trusted: boolean }"
112
+ }, 400);
113
+ const payload = await service.marketplace.setSessionWorkspaceTrustApi(sessionKey, body.trusted);
80
114
  return c.json({
81
115
  ok: true,
82
116
  payload
@@ -161,6 +161,7 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
161
161
  "/api/review",
162
162
  "/api/skills",
163
163
  "/api/chat/skills",
164
+ "/api/chat/workspace-trust",
164
165
  "/api/chat/capabilities"
165
166
  ]),
166
167
  load: async () => {
@@ -2,7 +2,7 @@ import type { Config } from '../../config/schema.js';
2
2
  import type { AgentService } from '../../agent/service.js';
3
3
  import type { ChannelManager } from '../../channels/manager.js';
4
4
  import type { ExtensionLoader } from '../../extensions/loader.js';
5
- import type { AgentSkillAvailabilityEntry, AgentSkillAvailabilityPayload, SkillCatalogEntry, SkillCatalogRuntimeMeta } from '../../agent/agent-manager.js';
5
+ import type { AgentSkillAvailabilityEntry, AgentSkillAvailabilityPayload, SkillCatalogEntry, SkillCatalogRuntimeMeta, WorkspaceTrustState } from '../../agent/agent-manager.js';
6
6
  import type { ManagedSkillListItem } from '../../agent/skills/managed-store.js';
7
7
  import type { SkillMarkdownPreviewPayload } from '../../agent/skills/types.js';
8
8
  import type { MarketplaceCategoryOption, SkillsStoreListParams, UnifiedMarketplaceListResponse, UnifiedMarketplacePackageDetail } from '../../agent/skills/skills-marketplace.js';
@@ -73,6 +73,9 @@ export declare class GatewayMarketplaceService {
73
73
  } & SkillCatalogRuntimeMeta;
74
74
  getSkillsStatusApi(): SkillCatalogRuntimeMeta;
75
75
  getAgentSkillsApi(agentId: string): AgentSkillAvailabilityPayload;
76
+ getSessionSkillsApi(sessionKey: string): Promise<AgentSkillAvailabilityPayload>;
77
+ getSessionWorkspaceTrustApi(sessionKey: string): Promise<WorkspaceTrustState>;
78
+ setSessionWorkspaceTrustApi(sessionKey: string, trusted: boolean): Promise<WorkspaceTrustState>;
76
79
  getSkillMarkdownSource(skillName: string): SkillMarkdownPreviewPayload | null;
77
80
  deleteSkill(skillId: string, target?: SkillInstallTarget): void;
78
81
  installSkillZip(buffer: Buffer, opts: {
@@ -68,6 +68,15 @@ var GatewayMarketplaceService = class {
68
68
  getAgentSkillsApi(agentId) {
69
69
  return this.opts.getAgentService().getAgentSkillAvailability(agentId);
70
70
  }
71
+ getSessionSkillsApi(sessionKey) {
72
+ return this.opts.getAgentService().getSessionSkillAvailability(sessionKey);
73
+ }
74
+ getSessionWorkspaceTrustApi(sessionKey) {
75
+ return this.opts.getAgentService().getSessionWorkspaceTrust(sessionKey);
76
+ }
77
+ setSessionWorkspaceTrustApi(sessionKey, trusted) {
78
+ return this.opts.getAgentService().setSessionWorkspaceTrust(sessionKey, trusted);
79
+ }
71
80
  getSkillMarkdownSource(skillName) {
72
81
  return this.opts.getAgentService().getSkillMarkdownSource(skillName);
73
82
  }
@@ -187,11 +187,11 @@ async function* runGatewayAgent(deps, message, channel, chatId, origin, attachme
187
187
  skipTaskReview: reviewHint?.skipTaskReview ?? false,
188
188
  outboundMetadata: {}
189
189
  });
190
- } catch (goalErr) {
190
+ } catch (completionErr) {
191
191
  log.warn({
192
- err: goalErr,
192
+ err: completionErr,
193
193
  sessionKey
194
- }, `Session turn complete failed: ${goalErr instanceof Error ? goalErr.message : String(goalErr)}`);
194
+ }, `Session turn complete failed: ${completionErr instanceof Error ? completionErr.message : String(completionErr)}`);
195
195
  }
196
196
  agentService.endInboundTurn(sessionKey);
197
197
  }
@@ -69,6 +69,7 @@ import "../discussions/index.js";
69
69
  import { EndpointToolRuntime } from "../endpoint-tools/runtime.js";
70
70
  import "../endpoint-tools/index.js";
71
71
  import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
72
+ import { prepareAutomationAgentSession } from "./automation-agent-session.js";
72
73
  import { reconcileDreamingAutomations } from "./dreaming-automation-reconciler.js";
73
74
  import { NotesStore } from "../notes/store.js";
74
75
  import { buildNoteAgentContext } from "../notes/agent-context.js";
@@ -495,7 +496,7 @@ var GatewayService = class {
495
496
  this.automationService.setDeps({
496
497
  agentService: this._agentService,
497
498
  getDefaultAgentId: () => getDefaultAgentId(this.config),
498
- getProjectWorkspaceRoot: (projectId) => this.projects.get(projectId)?.workspaceRoot,
499
+ prepareAgentSession: (input) => prepareAutomationAgentSession(this.sessionIndex.getStore(), this.projects, input),
499
500
  workflowRunService: this.createWorkflowRunService(),
500
501
  browserRecipeService: this.browserRecipes,
501
502
  executeTaskCommand: ({ taskId, idempotencyKey, command }) => {
@@ -865,6 +866,7 @@ var GatewayService = class {
865
866
  this.automationService.setDeps({
866
867
  agentService: this.agentService,
867
868
  getDefaultAgentId: () => getDefaultAgentId(this.config),
869
+ prepareAgentSession: (input) => prepareAutomationAgentSession(this.sessionIndex.getStore(), this.projects, input),
868
870
  workflowRunService: this.createWorkflowRunService(),
869
871
  browserRecipeService: this.browserRecipes,
870
872
  executeTaskCommand: ({ taskId, idempotencyKey, command }) => {
@@ -1502,7 +1504,22 @@ var GatewayService = class {
1502
1504
  this.createMobileNotificationService().handleGatewayEvent(type, payload);
1503
1505
  }
1504
1506
  handleAutomationRunCompleted(run) {
1505
- this.emit("automation.run.completed", { run });
1507
+ this.automationService.get(run.automationId).then((automation) => {
1508
+ if (!automation) return;
1509
+ const requiresAttention = run.status !== "succeeded" || (automation.safety?.mode ?? "auto_apply") !== "auto_apply";
1510
+ this.emit("automation.run.completed", {
1511
+ run,
1512
+ notificationPolicy: automation.notificationPolicy,
1513
+ requiresAttention,
1514
+ projectId: automation.projectId
1515
+ });
1516
+ }).catch((err) => {
1517
+ log.warn({
1518
+ err,
1519
+ automationId: run.automationId,
1520
+ runId: run.id
1521
+ }, "Automation completion event failed");
1522
+ });
1506
1523
  }
1507
1524
  startAutomationProductEventBridge() {
1508
1525
  this.stopAutomationProductEventBridge?.();
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, shouldSilence, stripHeartbeatToken } from "./tokens.js";
2
+ import { appendCronEventLines } from "./event-prompt.js";
2
3
  import { isWithinActiveHours } from "./active-hours.js";
3
4
  import { isHeartbeatContentEmpty } from "./content-check.js";
4
- import { appendCronEventLines } from "./event-prompt.js";
5
5
  import { createHeartbeatWake } from "./wake.js";
6
6
  export { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, appendCronEventLines, createHeartbeatWake, isHeartbeatContentEmpty, isWithinActiveHours, shouldSilence, stripHeartbeatToken };
@@ -40,10 +40,13 @@ function taskEvent(payload) {
40
40
  }
41
41
  function automationEvent(payload) {
42
42
  if (!payload || typeof payload !== "object") return null;
43
- if (payload.silent === true) return null;
44
- const run = payload.run;
43
+ const event = payload;
44
+ if (event.notificationPolicy === "none") return null;
45
+ if (event.notificationPolicy === "attention" && event.requiresAttention !== true) return null;
46
+ const run = event.run;
45
47
  if (!run || run.status !== "failed" && run.status !== "timeout" && run.status !== "succeeded") return null;
46
48
  const type = run.status === "succeeded" ? "automation.completed" : "automation.failed";
49
+ const route = `/automations?automation=${encodeURIComponent(run.automationId)}&run=${encodeURIComponent(run.id)}`;
47
50
  return {
48
51
  type,
49
52
  entity: {
@@ -53,9 +56,9 @@ function automationEvent(payload) {
53
56
  priority: type === "automation.failed" ? "high" : "normal",
54
57
  title: type === "automation.failed" ? "Automation failed" : "Automation completed",
55
58
  body: run.automationName.slice(0, 120),
56
- deepLink: "/automation",
59
+ deepLink: route,
57
60
  payload: {
58
- route: "/automation",
61
+ route,
59
62
  automationId: run.automationId,
60
63
  runId: run.id,
61
64
  eventType: type
@@ -0,0 +1,30 @@
1
+ export declare const HANDOVER_ITEM_KINDS: readonly ["objective", "decision", "pending_user_ask", "todo", "constraint", "file_change", "tool_outcome", "failure", "current_state", "next_action"];
2
+ export type HandoverItemKind = typeof HANDOVER_ITEM_KINDS[number];
3
+ export type HandoverItemStatus = 'active' | 'completed' | 'superseded';
4
+ export interface CompactionSourceRef {
5
+ entryId: string;
6
+ seq: number;
7
+ }
8
+ export interface CompactionHandoverItem {
9
+ id: string;
10
+ kind: HandoverItemKind;
11
+ text: string;
12
+ status: HandoverItemStatus;
13
+ sources: CompactionSourceRef[];
14
+ identifiers: string[];
15
+ }
16
+ export interface CompactionHandover {
17
+ version: 1;
18
+ sourceThroughSeq: number;
19
+ previousBoundaryId?: string;
20
+ items: CompactionHandoverItem[];
21
+ }
22
+ export interface CompactionAudit {
23
+ status: 'passed' | 'degraded' | 'disabled';
24
+ mode: 'structural' | 'risk' | 'full';
25
+ missingItemsFound: number;
26
+ repaired: boolean;
27
+ auditModelRef?: string;
28
+ }
29
+ export declare function isCompactionHandover(value: unknown): value is CompactionHandover;
30
+ export declare function isCompactionAudit(value: unknown): value is CompactionAudit;
@@ -0,0 +1,35 @@
1
+ //#region src/session/compaction-types.ts
2
+ const HANDOVER_ITEM_KINDS = [
3
+ "objective",
4
+ "decision",
5
+ "pending_user_ask",
6
+ "todo",
7
+ "constraint",
8
+ "file_change",
9
+ "tool_outcome",
10
+ "failure",
11
+ "current_state",
12
+ "next_action"
13
+ ];
14
+ function isCompactionHandover(value) {
15
+ if (!value || typeof value !== "object") return false;
16
+ const handover = value;
17
+ const sourceThroughSeq = Number(handover.sourceThroughSeq);
18
+ if (handover.version !== 1 || !Number.isInteger(handover.sourceThroughSeq) || sourceThroughSeq < 0 || handover.previousBoundaryId !== void 0 && typeof handover.previousBoundaryId !== "string" || !Array.isArray(handover.items)) return false;
19
+ return handover.items.every((item) => {
20
+ if (!item || typeof item !== "object") return false;
21
+ const record = item;
22
+ return typeof record.id === "string" && record.id.length > 0 && HANDOVER_ITEM_KINDS.includes(record.kind) && typeof record.text === "string" && record.text.length > 0 && (record.status === "active" || record.status === "completed" || record.status === "superseded") && Array.isArray(record.sources) && record.sources.length > 0 && record.sources.every((source) => {
23
+ if (!source || typeof source !== "object") return false;
24
+ const ref = source;
25
+ return typeof ref.entryId === "string" && ref.entryId.length > 0 && Number.isInteger(ref.seq) && Number(ref.seq) > 0 && Number(ref.seq) <= sourceThroughSeq;
26
+ }) && Array.isArray(record.identifiers) && record.identifiers.every((identifier) => typeof identifier === "string");
27
+ });
28
+ }
29
+ function isCompactionAudit(value) {
30
+ if (!value || typeof value !== "object") return false;
31
+ const audit = value;
32
+ return (audit.status === "passed" || audit.status === "degraded" || audit.status === "disabled") && (audit.mode === "structural" || audit.mode === "risk" || audit.mode === "full") && Number.isInteger(audit.missingItemsFound) && typeof audit.repaired === "boolean" && (audit.auditModelRef === void 0 || typeof audit.auditModelRef === "string");
33
+ }
34
+ //#endregion
35
+ export { HANDOVER_ITEM_KINDS, isCompactionAudit, isCompactionHandover };
@@ -185,6 +185,9 @@ export declare class SessionIndex extends EventEmitter {
185
185
  compactionCount: number;
186
186
  totalTokensBefore: number;
187
187
  totalTokensAfter: number;
188
+ auditPassedCount: number;
189
+ auditDegradedCount: number;
190
+ auditMissingItemsFound: number;
188
191
  lastCompactionAt: string;
189
192
  }>;
190
193
  listCompactionBoundaries(key: string): Promise<import("./types.js").CompactionBoundarySummary[]>;