@prismer/runtime 2.0.7 → 2.0.8

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 (207) hide show
  1. package/CHANGELOG.md +201 -0
  2. package/built-in-skills/agent-coordination/SKILL.md +235 -0
  3. package/built-in-skills/agent-meta/SKILL.md +52 -0
  4. package/built-in-skills/assets/SKILL.md +131 -0
  5. package/built-in-skills/canvas-design/LICENSE.txt +202 -0
  6. package/built-in-skills/canvas-design/SKILL.md +156 -0
  7. package/built-in-skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  8. package/built-in-skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  9. package/built-in-skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  10. package/built-in-skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
  11. package/built-in-skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  12. package/built-in-skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
  13. package/built-in-skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  14. package/built-in-skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  15. package/built-in-skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  16. package/built-in-skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  17. package/built-in-skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  18. package/built-in-skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  19. package/built-in-skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  20. package/built-in-skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  21. package/built-in-skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
  22. package/built-in-skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  23. package/built-in-skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
  24. package/built-in-skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  25. package/built-in-skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  26. package/built-in-skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
  27. package/built-in-skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  28. package/built-in-skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
  29. package/built-in-skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  30. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  31. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  32. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  33. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  34. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  35. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  36. package/built-in-skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  37. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  38. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  39. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  40. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  41. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  42. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  43. package/built-in-skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  44. package/built-in-skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
  45. package/built-in-skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  46. package/built-in-skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  47. package/built-in-skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  48. package/built-in-skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  49. package/built-in-skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  50. package/built-in-skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  51. package/built-in-skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
  52. package/built-in-skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  53. package/built-in-skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  54. package/built-in-skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  55. package/built-in-skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  56. package/built-in-skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  57. package/built-in-skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  58. package/built-in-skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  59. package/built-in-skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  60. package/built-in-skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
  61. package/built-in-skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  62. package/built-in-skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  63. package/built-in-skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  64. package/built-in-skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  65. package/built-in-skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  66. package/built-in-skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  67. package/built-in-skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  68. package/built-in-skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
  69. package/built-in-skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
  70. package/built-in-skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  71. package/built-in-skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  72. package/built-in-skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
  73. package/built-in-skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  74. package/built-in-skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
  75. package/built-in-skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  76. package/built-in-skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  77. package/built-in-skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
  78. package/built-in-skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  79. package/built-in-skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  80. package/built-in-skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  81. package/built-in-skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  82. package/built-in-skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  83. package/built-in-skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  84. package/built-in-skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
  85. package/built-in-skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  86. package/built-in-skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  87. package/built-in-skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  88. package/built-in-skills/claim-agent-ownership/SKILL.md +254 -0
  89. package/built-in-skills/claude-api/LICENSE.txt +202 -0
  90. package/built-in-skills/claude-api/SKILL.md +324 -0
  91. package/built-in-skills/claude-api/csharp/claude-api.md +402 -0
  92. package/built-in-skills/claude-api/curl/examples.md +216 -0
  93. package/built-in-skills/claude-api/curl/managed-agents.md +336 -0
  94. package/built-in-skills/claude-api/go/claude-api.md +421 -0
  95. package/built-in-skills/claude-api/go/managed-agents/README.md +561 -0
  96. package/built-in-skills/claude-api/java/claude-api.md +432 -0
  97. package/built-in-skills/claude-api/java/managed-agents/README.md +442 -0
  98. package/built-in-skills/claude-api/php/claude-api.md +375 -0
  99. package/built-in-skills/claude-api/php/managed-agents/README.md +435 -0
  100. package/built-in-skills/claude-api/python/claude-api/README.md +420 -0
  101. package/built-in-skills/claude-api/python/claude-api/batches.md +185 -0
  102. package/built-in-skills/claude-api/python/claude-api/files-api.md +165 -0
  103. package/built-in-skills/claude-api/python/claude-api/streaming.md +162 -0
  104. package/built-in-skills/claude-api/python/claude-api/tool-use.md +590 -0
  105. package/built-in-skills/claude-api/python/managed-agents/README.md +332 -0
  106. package/built-in-skills/claude-api/ruby/claude-api.md +113 -0
  107. package/built-in-skills/claude-api/ruby/managed-agents/README.md +389 -0
  108. package/built-in-skills/claude-api/shared/agent-design.md +101 -0
  109. package/built-in-skills/claude-api/shared/error-codes.md +213 -0
  110. package/built-in-skills/claude-api/shared/live-sources.md +135 -0
  111. package/built-in-skills/claude-api/shared/managed-agents-api-reference.md +378 -0
  112. package/built-in-skills/claude-api/shared/managed-agents-client-patterns.md +209 -0
  113. package/built-in-skills/claude-api/shared/managed-agents-core.md +238 -0
  114. package/built-in-skills/claude-api/shared/managed-agents-environments.md +215 -0
  115. package/built-in-skills/claude-api/shared/managed-agents-events.md +195 -0
  116. package/built-in-skills/claude-api/shared/managed-agents-memory.md +197 -0
  117. package/built-in-skills/claude-api/shared/managed-agents-multiagent.md +99 -0
  118. package/built-in-skills/claude-api/shared/managed-agents-onboarding.md +114 -0
  119. package/built-in-skills/claude-api/shared/managed-agents-outcomes.md +106 -0
  120. package/built-in-skills/claude-api/shared/managed-agents-overview.md +68 -0
  121. package/built-in-skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +173 -0
  122. package/built-in-skills/claude-api/shared/managed-agents-tools.md +321 -0
  123. package/built-in-skills/claude-api/shared/managed-agents-webhooks.md +110 -0
  124. package/built-in-skills/claude-api/shared/model-migration.md +779 -0
  125. package/built-in-skills/claude-api/shared/models.md +121 -0
  126. package/built-in-skills/claude-api/shared/prompt-caching.md +171 -0
  127. package/built-in-skills/claude-api/shared/tool-use-concepts.md +327 -0
  128. package/built-in-skills/claude-api/typescript/claude-api/README.md +333 -0
  129. package/built-in-skills/claude-api/typescript/claude-api/batches.md +106 -0
  130. package/built-in-skills/claude-api/typescript/claude-api/files-api.md +98 -0
  131. package/built-in-skills/claude-api/typescript/claude-api/streaming.md +178 -0
  132. package/built-in-skills/claude-api/typescript/claude-api/tool-use.md +527 -0
  133. package/built-in-skills/claude-api/typescript/managed-agents/README.md +359 -0
  134. package/built-in-skills/doc-coauthoring/SKILL.md +375 -0
  135. package/built-in-skills/frontend-design/LICENSE.txt +177 -0
  136. package/built-in-skills/frontend-design/SKILL.md +42 -0
  137. package/built-in-skills/human-approval/SKILL.md +114 -0
  138. package/built-in-skills/image-generate/SKILL.md +327 -0
  139. package/built-in-skills/ingest/SKILL.md +105 -0
  140. package/built-in-skills/internal-comms/LICENSE.txt +202 -0
  141. package/built-in-skills/internal-comms/SKILL.md +32 -0
  142. package/built-in-skills/internal-comms/examples/3p-updates.md +47 -0
  143. package/built-in-skills/internal-comms/examples/company-newsletter.md +65 -0
  144. package/built-in-skills/internal-comms/examples/faq-answers.md +30 -0
  145. package/built-in-skills/internal-comms/examples/general-comms.md +16 -0
  146. package/built-in-skills/liteparse/SKILL.md +156 -0
  147. package/built-in-skills/mcp-builder/LICENSE.txt +202 -0
  148. package/built-in-skills/mcp-builder/SKILL.md +236 -0
  149. package/built-in-skills/mcp-builder/reference/evaluation.md +602 -0
  150. package/built-in-skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  151. package/built-in-skills/mcp-builder/reference/node_mcp_server.md +970 -0
  152. package/built-in-skills/mcp-builder/reference/python_mcp_server.md +719 -0
  153. package/built-in-skills/mcp-builder/scripts/connections.py +151 -0
  154. package/built-in-skills/mcp-builder/scripts/evaluation.py +373 -0
  155. package/built-in-skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  156. package/built-in-skills/mcp-builder/scripts/requirements.txt +2 -0
  157. package/built-in-skills/memory/SKILL.md +106 -0
  158. package/built-in-skills/memory-curation/SKILL.md +135 -0
  159. package/built-in-skills/office-artifacts/SKILL.md +198 -0
  160. package/built-in-skills/prismer-im-collab/SKILL.md +148 -0
  161. package/built-in-skills/skill-authoring/SKILL.md +124 -0
  162. package/built-in-skills/skill-authoring/skill.json +74 -0
  163. package/built-in-skills/skill-creator/LICENSE.txt +202 -0
  164. package/built-in-skills/skill-creator/SKILL.md +485 -0
  165. package/built-in-skills/skill-creator/agents/analyzer.md +274 -0
  166. package/built-in-skills/skill-creator/agents/comparator.md +202 -0
  167. package/built-in-skills/skill-creator/agents/grader.md +223 -0
  168. package/built-in-skills/skill-creator/assets/eval_review.html +146 -0
  169. package/built-in-skills/skill-creator/eval-viewer/generate_review.py +471 -0
  170. package/built-in-skills/skill-creator/eval-viewer/viewer.html +1325 -0
  171. package/built-in-skills/skill-creator/references/schemas.md +430 -0
  172. package/built-in-skills/skill-creator/scripts/__init__.py +0 -0
  173. package/built-in-skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  174. package/built-in-skills/skill-creator/scripts/generate_report.py +326 -0
  175. package/built-in-skills/skill-creator/scripts/improve_description.py +247 -0
  176. package/built-in-skills/skill-creator/scripts/package_skill.py +136 -0
  177. package/built-in-skills/skill-creator/scripts/quick_validate.py +103 -0
  178. package/built-in-skills/skill-creator/scripts/run_eval.py +310 -0
  179. package/built-in-skills/skill-creator/scripts/run_loop.py +328 -0
  180. package/built-in-skills/skill-creator/scripts/utils.py +47 -0
  181. package/built-in-skills/slack-gif-creator/LICENSE.txt +202 -0
  182. package/built-in-skills/slack-gif-creator/SKILL.md +271 -0
  183. package/built-in-skills/slack-gif-creator/core/easing.py +234 -0
  184. package/built-in-skills/slack-gif-creator/core/frame_composer.py +176 -0
  185. package/built-in-skills/slack-gif-creator/core/gif_builder.py +269 -0
  186. package/built-in-skills/slack-gif-creator/core/validators.py +136 -0
  187. package/built-in-skills/slack-gif-creator/requirements.txt +4 -0
  188. package/built-in-skills/tasks/SKILL.md +398 -0
  189. package/built-in-skills/team/SKILL.md +76 -0
  190. package/built-in-skills/web-artifacts-builder/LICENSE.txt +202 -0
  191. package/built-in-skills/web-artifacts-builder/SKILL.md +104 -0
  192. package/built-in-skills/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
  193. package/built-in-skills/web-artifacts-builder/scripts/init-artifact.sh +334 -0
  194. package/built-in-skills/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
  195. package/built-in-skills/webapp-testing/LICENSE.txt +202 -0
  196. package/built-in-skills/webapp-testing/SKILL.md +96 -0
  197. package/built-in-skills/webapp-testing/examples/console_logging.py +35 -0
  198. package/built-in-skills/webapp-testing/examples/element_discovery.py +40 -0
  199. package/built-in-skills/webapp-testing/examples/static_html_automation.py +33 -0
  200. package/built-in-skills/webapp-testing/scripts/with_server.py +106 -0
  201. package/dist/cli.cjs +6195 -1631
  202. package/dist/cli.js +6148 -1585
  203. package/dist/index.cjs +6032 -1468
  204. package/dist/index.d.cts +813 -43
  205. package/dist/index.d.ts +813 -43
  206. package/dist/index.js +6017 -1454
  207. package/package.json +4 -2
package/dist/index.d.ts CHANGED
@@ -4,6 +4,136 @@ import { EventEmitter } from 'node:events';
4
4
  import { IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Command } from 'commander';
6
6
 
7
+ /**
8
+ * Sender / participant role within a conversation. Mirrors
9
+ * `TaskDispatchContextEntry['senderRole']` on the cloud side.
10
+ */
11
+ type EnvelopeRole = 'human' | 'agent' | 'admin' | 'system';
12
+ /** Active participant of the conversation. */
13
+ interface ParticipantRef {
14
+ imUserId: string;
15
+ username: string;
16
+ displayName: string;
17
+ role: string;
18
+ agentType?: string | null;
19
+ }
20
+ /**
21
+ * One raw L1 message in the `recent` tail. Visibility-filtered per
22
+ * docs/release201/26 §5.1 (lifecycle / system events are stripped cloud-side).
23
+ */
24
+ interface EnvelopeRecentEntry {
25
+ messageId: string;
26
+ role: EnvelopeRole;
27
+ sender: string;
28
+ content: string;
29
+ createdAt: string;
30
+ /** Asset IDs attached to this message; bytes are never inlined here. */
31
+ assetRefs?: AssetRef[];
32
+ }
33
+ /** Structured salient facts extracted by the L2 producer (all optional). */
34
+ interface EnvelopeSalientFacts {
35
+ topicHeadlines?: string[];
36
+ decisions?: string[];
37
+ openQuestions?: string[];
38
+ entitiesMentioned?: string[];
39
+ userPreferences?: string[];
40
+ agentCommitments?: string[];
41
+ discardedDirections?: string[];
42
+ /** metric-only: count of `task.*` lifecycle events covered by this segment. */
43
+ taskEventCount?: number;
44
+ /** metric-only: count of `awaiting_human_approval` events covered. */
45
+ approvalCount?: number;
46
+ }
47
+ /** A compressed L2 Range segment (Phase 1's only `segmentKind`). */
48
+ interface EnvelopeSegment {
49
+ segmentSeq: number;
50
+ coversFromAt: string;
51
+ coversToAt: string;
52
+ summary: string;
53
+ salientFacts: EnvelopeSalientFacts;
54
+ sourceCount: number;
55
+ tokenCountCl100k: number;
56
+ }
57
+ /**
58
+ * Quote snapshot. Decision C: the ref always points at the raw `messageId`;
59
+ * the snapshot survives source deletion via `sourceDeletedAt`.
60
+ */
61
+ interface EnvelopeQuote {
62
+ quotedMessageId: string;
63
+ snippet: string;
64
+ quotedSender: string;
65
+ quotedAt: string;
66
+ /** Set when the quoted raw message has since been deleted. */
67
+ sourceDeletedAt?: string;
68
+ /**
69
+ * release201/26 §13.4a P2 — image assets on the quoted (older) message,
70
+ * re-attached by the cloud (with `cdnUrl`) so the adapter can re-inject them
71
+ * as image parts in the current turn. Cross-turn vision is blind on stateful
72
+ * upstreams (Hermes stores prior images as `[screenshot]` placeholders), so
73
+ * a text snippet / url-in-text is not enough — the agent must receive the
74
+ * image input again. Reuses the wire `AssetRef` shape.
75
+ */
76
+ imageAssetRefs?: AssetRef[];
77
+ }
78
+ /** Resolved identifier (entity name → canonical id). Phase 3 only. */
79
+ interface EnvelopeIdentifier {
80
+ kind: string;
81
+ canonicalId: string;
82
+ displayLabel: string;
83
+ lastSeenAt: string;
84
+ }
85
+ /** Recent task execution trace. Phase 3 only. */
86
+ interface EnvelopeRecentTaskTrace {
87
+ taskId: string;
88
+ toolsUsed: string[];
89
+ outputs: string[];
90
+ decisions: string[];
91
+ }
92
+ /** Per-category token floors (cl100k). */
93
+ interface EnvelopeBudgetFloors {
94
+ recent: number;
95
+ compressedSegments: number;
96
+ quotes: number;
97
+ identifierIndex: number;
98
+ recentTaskTrace: number;
99
+ }
100
+ interface EnvelopeBudget {
101
+ /** Total budget in cl100k tokens (Phase 1 default 8000, §6). */
102
+ totalTokens: number;
103
+ floors: EnvelopeBudgetFloors;
104
+ }
105
+ /**
106
+ * Asset partition (decision D). `inputs` participate in the agent's context
107
+ * (image-as-input / file-as-input); `archives` are described only and do not
108
+ * consume vision tokens.
109
+ */
110
+ interface EnvelopeAssets {
111
+ inputs: AssetRef[];
112
+ archives: AssetRef[];
113
+ }
114
+ /**
115
+ * Conversation context envelope — the L3 input contract (cloud → daemon).
116
+ * See docs/release201/26 §5.
117
+ */
118
+ interface ConversationContextEnvelope {
119
+ envelopeVersion: 1;
120
+ conversationId: string;
121
+ conversationType: 'direct' | 'group';
122
+ participants: ParticipantRef[];
123
+ /** L1 raw tail, oldest first. Visibility-filtered per §5.1. */
124
+ recent: EnvelopeRecentEntry[];
125
+ /** L2 Range segments (Phase 1's only kind). */
126
+ compressedSegments: EnvelopeSegment[];
127
+ /** Quote snapshots; ref always points at the raw messageId (decision C). */
128
+ quotes: EnvelopeQuote[];
129
+ /** Phase 3 only — undefined in Phase 1. */
130
+ identifierIndex?: EnvelopeIdentifier[];
131
+ /** Phase 3 only — undefined in Phase 1. */
132
+ recentTaskTrace?: EnvelopeRecentTaskTrace;
133
+ assets: EnvelopeAssets;
134
+ budget: EnvelopeBudget;
135
+ }
136
+
7
137
  type IMAgentStatus = 'online' | 'busy' | 'idle' | 'offline';
8
138
  interface HostedAgentDeclaration {
9
139
  imUserId: string;
@@ -53,6 +183,21 @@ interface TaskDispatchContextEntry {
53
183
  createdAt: string;
54
184
  /** Wave-8 W1: assets the human attached to THIS chat message. */
55
185
  attachedAssetIds?: string[];
186
+ /**
187
+ * 2026-05-31 release201/30 §XML-context P0 — enriched metadata for the
188
+ * assets attached to this message. Daemon renders each entry as
189
+ * `<asset id mime filename size_bytes/>` inside a `<attached_assets>`
190
+ * child of `<prior_message>` / `<current_message>` so the agent sees
191
+ * prior-turn file attachments (PDF / image / etc.) instead of a blank
192
+ * text body. Optional + forward-compat with older cloud builds (falls
193
+ * back to id-only rendering from `attachedAssetIds`).
194
+ */
195
+ attachedAssets?: Array<{
196
+ id: string;
197
+ mime?: string;
198
+ filename?: string;
199
+ sizeBytes?: number;
200
+ }>;
56
201
  }
57
202
  /** Wave-8 W1: hydrated asset reference attached to a dispatch. */
58
203
  interface AssetRef {
@@ -92,6 +237,18 @@ interface ResolvedAssetRef extends AssetRef {
92
237
  }
93
238
  interface TaskDispatchRequestPayload {
94
239
  taskId: string;
240
+ /**
241
+ * release202/09 §3.2 — structural run-vs-task signal.
242
+ * - `'run'` → chat-dispatch run (`taskId` mirrors the run id). Daemon
243
+ * injects `PRISMER_RUN_ID` (not `PRISMER_TASK_ID`); the turn closes from
244
+ * the agent's reply — no `cloud task` op needed.
245
+ * - `'task'` → kanban task. Daemon injects `PRISMER_TASK_ID`.
246
+ * Optional + forward-compatible: missing → daemon falls back to id-shape
247
+ * (`run_` prefix) and then legacy probe-both.
248
+ */
249
+ kind?: 'run' | 'task';
250
+ /** The run id when `kind === 'run'`. */
251
+ runId?: string;
95
252
  /** Agent target for runtimeRoute='agent'. Shell dispatches do not use this. */
96
253
  agentImUserId?: string;
97
254
  /** Runtime/device target for runtimeRoute='shell'. */
@@ -105,6 +262,15 @@ interface TaskDispatchRequestPayload {
105
262
  timeoutMs?: number;
106
263
  context?: TaskDispatchContextEntry[];
107
264
  conversationId?: string;
265
+ /**
266
+ * release201/30 §7 — end-to-end trace id, originated by the frontend
267
+ * (`X-Prismer-Trace-Id`) or generated by the cloud middleware when absent.
268
+ * Daemon prefixes its stderr lines with `[trace=${traceId}]` so an
269
+ * operator can grep one id across frontend → cloud → daemon. Optional and
270
+ * forward-compatible: missing means the wire frame predates the field;
271
+ * dispatch.ts falls back to `daemon-fallback-<rand>`.
272
+ */
273
+ traceId?: string;
108
274
  /**
109
275
  * Channel mode for the originating conversation. Optional and
110
276
  * forward-compatible: when missing, daemon renders 'unknown' in the
@@ -139,6 +305,36 @@ interface TaskDispatchRequestPayload {
139
305
  * (when non-null) so built-in skill --project flag defaults work.
140
306
  */
141
307
  projectId?: string | null;
308
+ /**
309
+ * release201/30 — username of the chat sender that triggered this dispatch.
310
+ * Daemon uses this to label the <current_message author="..."> tag inside
311
+ * the XML-wrapped conversation context the sessions-style adapters send.
312
+ *
313
+ * Optional: when missing, daemon falls back to the trigger row's own
314
+ * username (typically the human owner), which is still correct for
315
+ * single-author dispatch flows.
316
+ */
317
+ triggerSenderUsername?: string;
318
+ /**
319
+ * release201/30 — role of the trigger message sender. Mirrors
320
+ * `TaskDispatchContextEntry.senderRole` vocabulary.
321
+ */
322
+ triggerSenderRole?: 'human' | 'agent' | 'admin' | 'system';
323
+ /**
324
+ * release201/25 §7 / release201/26 envelope refactor — typed L3 input
325
+ * contract built cloud-side by `ConversationMemoryService.buildEnvelope`.
326
+ *
327
+ * Envelope-aware adapters call `renderContextEnvelope` (per-adapter
328
+ * module under `sdk/.../adapters/<name>/context-render.ts`) to turn this
329
+ * into their native wire shape. Legacy fields above (`context`,
330
+ * `participants`, `triggerSenderUsername`, `triggerSenderRole`) are still
331
+ * populated for one release window so older adapters keep working.
332
+ *
333
+ * Optional + forward-compatible: missing means the cloud build predates
334
+ * the wiring (or the flag is off); adapter falls back to the legacy XML
335
+ * composer / N-message path.
336
+ */
337
+ contextEnvelope?: ConversationContextEnvelope;
142
338
  }
143
339
  interface TaskDispatchProgressPayload {
144
340
  taskId: string;
@@ -165,10 +361,11 @@ interface AssetDispatchObservation {
165
361
  durationMs?: number;
166
362
  }
167
363
  /**
168
- * P1-2 (2026-05-25): per-file outbox rejection record. Surfaced when daemon's
169
- * `outbox-watcher` rejects an artifact because its magic bytes don't match
364
+ * P1-2 (2026-05-25): per-file artifact rejection record. Surfaced when daemon's
365
+ * `artifacts-watcher` rejects an artifact because its magic bytes don't match
170
366
  * the file extension (e.g. agent wrote `report.pdf` with markdown content).
171
- * Cloud persists these on `IMTask.metadata.outboxRejections` and prepends a
367
+ * Cloud persists these on `IMTask.metadata.outboxRejections` (wire field name
368
+ * kept for the cross-process contract) and prepends a
172
369
  * warning section to the next dispatch prompt so the agent can self-correct.
173
370
  */
174
371
  interface OutboxRejectionRecord {
@@ -194,7 +391,7 @@ interface TaskDispatchReplyPayload {
194
391
  /** Wave-8 W1: per-asset handling report. */
195
392
  assetObservability?: AssetDispatchObservation[];
196
393
  /**
197
- * P1-2 (2026-05-25): files quarantined locally by outbox-watcher's
394
+ * P1-2 (2026-05-25): files quarantined locally by artifacts-watcher's
198
395
  * magic-bytes check during this turn. Cloud writes them onto
199
396
  * `IMTask.metadata.outboxRejections` so the next dispatch prompt can warn
200
397
  * the agent.
@@ -368,7 +565,7 @@ declare class MemoryStore {
368
565
  private rowToPage;
369
566
  }
370
567
 
371
- type MemoryScope = 'workspace-shared' | 'agent-private';
568
+ type MemoryScope = 'workspace-shared' | 'agent-private' | 'session-scratch' | 'role-shared' | 'project-shared' | 'global';
372
569
  interface ScopedMemoryStoreOptions {
373
570
  /** Filesystem root, e.g. `~/.prismer/memory` (will create per-workspace dir under). */
374
571
  rootDir: string;
@@ -383,12 +580,37 @@ interface ScopedWriteInput extends Omit<MemoryWriteInput, 'workspaceId'> {
383
580
  scope: MemoryScope;
384
581
  /** Required when scope='agent-private'; rejected when scope='workspace-shared'. */
385
582
  agentImUserId?: string;
583
+ /**
584
+ * Required when scope='session-scratch' (release201/26 §14.9 #A5) — opaque
585
+ * throwaway key, e.g. `eval-<runId>`. Rejected for the other scopes.
586
+ */
587
+ sessionKey?: string;
588
+ /**
589
+ * Required when scope='role-shared' (release201/26 §14.6 #A5b) — role
590
+ * template slug; the bucket is shared across all agents of that role.
591
+ * Rejected for the other scopes.
592
+ */
593
+ roleSlug?: string;
594
+ /**
595
+ * Required when scope='project-shared' (release201/26 §14.6 #A5b) — project
596
+ * identifier; the bucket is scoped to a project. Rejected for other scopes.
597
+ */
598
+ projectId?: string;
386
599
  }
387
600
  interface ScopedSearchInput {
388
601
  query: string;
389
602
  scope: MemoryScope;
390
603
  /** Required when scope='agent-private' — search only this agent's bucket. */
391
604
  agentImUserId?: string;
605
+ /**
606
+ * Required when scope='session-scratch' — search only this throwaway bucket;
607
+ * never falls through to shared/agent buckets (full isolation, §14.9 #A5).
608
+ */
609
+ sessionKey?: string;
610
+ /** Required when scope='role-shared' (release201/26 §14.6 #A5b). */
611
+ roleSlug?: string;
612
+ /** Required when scope='project-shared' (release201/26 §14.6 #A5b). */
613
+ projectId?: string;
392
614
  options?: MemorySearchOptions;
393
615
  }
394
616
  /**
@@ -399,19 +621,67 @@ declare class ScopedMemoryStore {
399
621
  private readonly opts;
400
622
  private sharedStore;
401
623
  private agentStores;
624
+ private scratchStores;
625
+ private roleStores;
626
+ private projectStores;
627
+ private globalStore;
402
628
  private readonly workspaceDir;
403
629
  constructor(opts: ScopedMemoryStoreOptions);
404
630
  /** Resolve the shared store (lazy open). */
405
631
  shared(): MemoryStore;
406
632
  /** Resolve the per-agent store (lazy open). */
407
633
  forAgent(agentImUserId: string): MemoryStore;
408
- /** Resolve the right store for (scope, agentImUserId). */
409
- resolve(scope: MemoryScope, agentImUserId?: string): MemoryStore;
634
+ /**
635
+ * Resolve the per-session scratch store (lazy open). release201/26 §14.9 #A5.
636
+ *
637
+ * The bucket lives under `<workspaceDir>/scratch/<sanitizedSessionKey>.db`.
638
+ * It is fully isolated: nothing in here is ever merged into shared/agent
639
+ * searches, and it is meant to be torn down via `dropScratch` after the run.
640
+ */
641
+ forScratch(sessionKey: string): MemoryStore;
642
+ /**
643
+ * Resolve the per-role shared store (lazy open). release201/26 §14.6 #A5b.
644
+ * Bucket: `<workspaceDir>/roles/<sanitizedRoleSlug>.db` — shared across all
645
+ * agents instantiated from the same role template.
646
+ */
647
+ forRole(roleSlug: string): MemoryStore;
648
+ /**
649
+ * Resolve the per-project shared store (lazy open). release201/26 §14.6 #A5b.
650
+ * Bucket: `<workspaceDir>/projects/<sanitizedProjectId>.db`.
651
+ */
652
+ forProject(projectId: string): MemoryStore;
653
+ /**
654
+ * Resolve the CROSS-workspace global store (lazy open). release201/26 §14.6
655
+ * #A5b. The bucket lives at `<rootDir>/global.db` (one level ABOVE the
656
+ * per-workspace dir) so every ScopedMemoryStore sharing the same rootDir reads
657
+ * and writes the same global.db, regardless of workspaceId. The store is
658
+ * opened with the constant GLOBAL_WORKSPACE_ID so MemoryStore's single-
659
+ * workspace filter does not re-partition global rows per workspace.
660
+ */
661
+ global(): MemoryStore;
662
+ /** Resolve the right store for (scope, agentImUserId, sessionKey, roleSlug, projectId). */
663
+ resolve(scope: MemoryScope, agentImUserId?: string, sessionKey?: string, roleSlug?: string, projectId?: string): MemoryStore;
664
+ /**
665
+ * Sanitize an opaque key (sessionKey / roleSlug / projectId) for filesystem
666
+ * safety. Rejects empty/blank keys; maps any char outside [A-Za-z0-9_-] to
667
+ * '_' so a key like `eval-../../etc` cannot escape its bucket dir.
668
+ * release201/26 §14.9 #A5 + §14.6 #A5b.
669
+ */
670
+ private static sanitizeKey;
671
+ /**
672
+ * Sanitize an opaque sessionKey for filesystem safety. Rejects empty/blank
673
+ * keys; maps any char outside [A-Za-z0-9_-] to '_' so a key like
674
+ * `eval-../../etc` cannot escape the scratch dir. release201/26 §14.9 #A5.
675
+ */
676
+ private static sanitizeSessionKey;
410
677
  /** Write a memory page into the correct bucket. */
411
678
  write(input: ScopedWriteInput): {
412
679
  pageId: string;
413
680
  scope: MemoryScope;
414
681
  agentImUserId?: string;
682
+ sessionKey?: string;
683
+ roleSlug?: string;
684
+ projectId?: string;
415
685
  };
416
686
  /**
417
687
  * Search only the requested bucket. This is the daemon-first FTS5 path
@@ -426,6 +696,18 @@ declare class ScopedMemoryStore {
426
696
  searchForAgent(query: string, agentImUserId: string, options?: MemorySearchOptions): MemorySearchResult[];
427
697
  /** List which agent ids currently have a private DB on disk (for diagnostics). */
428
698
  listAgentBuckets(): string[];
699
+ /**
700
+ * List which scratch sessionKeys currently have a DB on disk. For
701
+ * housekeeping — e.g. dropping orphaned scratch buckets from crashed eval
702
+ * runs. release201/26 §14.9 #A5.
703
+ */
704
+ listScratchKeys(): string[];
705
+ /**
706
+ * Close + delete a scratch bucket's db file(s) (incl. -wal / -shm sidecars).
707
+ * Called after an eval/throwaway run to clean up. Idempotent: a missing
708
+ * bucket is a no-op. release201/26 §14.9 #A5.
709
+ */
710
+ dropScratch(sessionKey: string): void;
429
711
  /** Total disk footprint (best-effort; sums each bucket's main DB file). */
430
712
  diskBytes(): {
431
713
  shared: number;
@@ -515,7 +797,23 @@ interface StepRecorderHandle {
515
797
  }
516
798
  interface TaskInput {
517
799
  taskId: string;
800
+ /**
801
+ * release202/09 §3.2 — whether this dispatch is a chat-dispatch RUN or a
802
+ * kanban TASK. Threaded from `TaskDispatchRequestPayload.kind`. When 'run',
803
+ * `runId` carries the run id and `taskId` mirrors it (back-compat); adapters
804
+ * surface `<run_id>` (not `<task_id>`) in execution_context. Optional —
805
+ * adapters that don't read it fall back to the id shape (`run_` prefix).
806
+ */
807
+ kind?: 'run' | 'task';
808
+ /** The run id when `kind === 'run'` (release202/09 §3.2). */
809
+ runId?: string;
518
810
  prompt: string;
811
+ /**
812
+ * Adapter-private input metadata. release202/05 C2 — `metadata.conversationId`
813
+ * + `metadata.agentImUserId` are already populated on dispatch and are the
814
+ * keys ProviderSessionMapper.get()/put() use to scope a provider session to
815
+ * one (conversation × agent × adapter) triple.
816
+ */
519
817
  metadata?: Record<string, unknown>;
520
818
  timeoutMs?: number;
521
819
  onProgress?: (p: {
@@ -577,6 +875,110 @@ interface TaskInput {
577
875
  * → passes here). Adapters never instantiate the store themselves.
578
876
  */
579
877
  memoryStore?: ScopedMemoryStore;
878
+ /**
879
+ * Raw structured conversation history. Adapters that natively understand
880
+ * role-tagged messages (Hermes /v1/runs, OpenAI Responses) should consume
881
+ * this instead of parsing `prompt`. Adapters that don't (claude-code,
882
+ * codex CLI) can ignore it — dispatch.ts still concats into `prompt` as
883
+ * a fallback. 2026-05-29 — added to fix Hermes context-dropout where
884
+ * dispatch concatenated history into a single user-input string and
885
+ * Hermes treated it as one new turn (api_server.py:3537-3590).
886
+ */
887
+ contextEntries?: Array<{
888
+ role: 'user' | 'assistant' | 'system';
889
+ content: string;
890
+ sender?: string;
891
+ senderRole?: string;
892
+ /**
893
+ * release201/30 — original IM message createdAt (ISO 8601). Consumed by
894
+ * sessions-dispatcher to stamp the `at="..."` attribute on each
895
+ * <prior_message> tag inside the conversation context XML so the model
896
+ * can reason about chronology. Optional for back-compat; missing
897
+ * timestamps degrade to "now" at compose time.
898
+ */
899
+ createdAt?: string;
900
+ /**
901
+ * release201/30 §XML-context P0 (2026-05-31) — asset attachments
902
+ * carried alongside this prior chat message. Forwarded verbatim from
903
+ * cloud's `TaskDispatchContextEntry.attachedAssetIds /
904
+ * attachedAssets` so sessions-dispatcher can stamp
905
+ * `<attached_assets>` children inside `<prior_message>` and the agent
906
+ * sees prior PDF/image references even though the chat surface only
907
+ * carried the user's text body. Optional; absence is treated as "no
908
+ * attachments on this turn".
909
+ */
910
+ attachedAssetIds?: string[];
911
+ attachedAssets?: Array<{
912
+ id: string;
913
+ mime?: string;
914
+ filename?: string;
915
+ sizeBytes?: number;
916
+ }>;
917
+ }>;
918
+ /**
919
+ * Unconcatenated original user prompt for adapters that take history
920
+ * separately via `contextEntries`. When set, Hermes /v1/runs sends this
921
+ * as `input` and the history as `conversation_history`. When unset,
922
+ * adapters fall back to `prompt` (already concatenated by dispatch.ts).
923
+ */
924
+ currentPrompt?: string;
925
+ /**
926
+ * 2026-05-29 — asset reminder/inline blocks produced by
927
+ * `dispatch.ts:resolveAssetRefs` for non-image / text-like assets
928
+ * aggregated from the chat context window (W1).
929
+ *
930
+ * These blocks are also baked into `prompt` (so legacy text-only
931
+ * adapters keep working), but adapters that send only `currentPrompt`
932
+ * to a stateful upstream (Hermes sessions API, OpenAI Responses with
933
+ * server-side history) would otherwise drop them and the agent would
934
+ * be told "no file was attached" even though the cloud W1 collector
935
+ * picked the asset up. Sessions-dispatcher must prepend these to the
936
+ * current-turn message text.
937
+ *
938
+ * Empty / undefined → no assets resolved into prompt blocks; the
939
+ * adapter sends the bare currentPrompt.
940
+ */
941
+ assetPromptBlocks?: string[];
942
+ /**
943
+ * release201/30 — fields required by sessions-style adapters (Hermes
944
+ * /api/sessions/{id}/chat/stream) to build a <conversation_context> XML
945
+ * block that disambiguates first-person voice across participants in
946
+ * group chats. Legacy /v1/runs path and non-Hermes adapters ignore these.
947
+ *
948
+ * See `daemon/conversation-context.ts` for the composer that consumes
949
+ * these fields.
950
+ */
951
+ conversationType?: 'direct' | 'group' | 'unknown';
952
+ conversationId?: string;
953
+ /** profile.agentUsername — agent's human handle (ceo / engineer / etc). */
954
+ profileAgentUsername?: string;
955
+ /** profile.agentImUserId — agent's IM user id. */
956
+ profileAgentImUserId?: string;
957
+ /** Authoritative recipient list of the originating conversation. */
958
+ participants?: Array<{
959
+ imUserId: string;
960
+ username: string;
961
+ displayName: string;
962
+ role: string;
963
+ agentType?: string | null;
964
+ }>;
965
+ /** Username of the human/agent who sent the dispatch trigger message. */
966
+ currentMessageSender?: string;
967
+ /** Role of the dispatch trigger sender (human / agent / admin / system). */
968
+ currentMessageSenderRole?: 'human' | 'agent' | 'admin' | 'system';
969
+ /**
970
+ * release201/25 §7 / release201/26 — typed L3 input contract (cloud built
971
+ * via `ConversationMemoryService.buildEnvelope`). Envelope-aware adapter
972
+ * paths import their adapter's `context-render.ts` module
973
+ * (`adapters/<name>/context-render.ts`) and call `renderContextEnvelope`
974
+ * to translate this into their native history shape (Hermes XML body,
975
+ * OpenClaw `/v1/responses` input array, CLI markdown, ...).
976
+ *
977
+ * Optional + forward-compat: when undefined, adapters fall back to the
978
+ * legacy fields above (`contextEntries` + `participants` +
979
+ * `currentMessageSender*`) and compose the body themselves.
980
+ */
981
+ contextEnvelope?: ConversationContextEnvelope;
580
982
  }
581
983
  interface TaskResult {
582
984
  ok: boolean;
@@ -595,7 +997,16 @@ interface TaskResult {
595
997
  tokensUsed?: number;
596
998
  durationMs?: number;
597
999
  };
598
- /** Adapter-private metadata used by daemon-side bridges/observability. */
1000
+ /**
1001
+ * Adapter-private metadata used by daemon-side bridges/observability.
1002
+ *
1003
+ * release202/05 C2 — interactive adapters (codex / claude-code) MAY set
1004
+ * `metadata.providerSessionId?: string` here: the provider/CLI session
1005
+ * (thread) id to persist via ProviderSessionMapper so the next turn on the
1006
+ * same (conversation, agent, adapter) can `resume` it. No type change needed
1007
+ * (metadata is `Record<string, unknown>`); the daemon dispatch bridge reads
1008
+ * the key and persists when present.
1009
+ */
599
1010
  metadata?: Record<string, unknown>;
600
1011
  }
601
1012
  /**
@@ -690,7 +1101,29 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
690
1101
  model: z.ZodDefault<z.ZodString>;
691
1102
  /** Named custom provider written into Hermes config.yaml. */
692
1103
  prismerProviderName: z.ZodDefault<z.ZodString>;
693
- /** Override cloud provider base. Defaults to PRISMER_BASE_URL + /api/v1. */
1104
+ /**
1105
+ * 2026-05-30 — per-agent LLM proxy selector.
1106
+ *
1107
+ * Picks which Prismer Cloud upstream pool this hermes profile points its
1108
+ * `chat/completions` calls at. Default `newapi` is the platform aggregator
1109
+ * (gemini / kimi / etc.). `deepseek` swaps the cloud-side `base_url` to the
1110
+ * `/api/v1/proxy/deepseek/chat/completions` alias so the cloud forwards the
1111
+ * request directly to DeepSeek regardless of the global
1112
+ * `DEEPSEEK_BYPASS_ENABLED` env. Lets two agents share a workspace + daemon
1113
+ * but route to different LLM backends for an apples-to-apples comparison.
1114
+ *
1115
+ * Resolution priority for `custom_providers[0].base_url`:
1116
+ * 1. `prismerProviderBaseUrl` (explicit operator override) — wins always.
1117
+ * 2. `proxyProvider === 'deepseek'` → PRISMER_BASE_URL + `/api/v1/proxy/deepseek`
1118
+ * 3. `proxyProvider === 'newapi'` (default) → PRISMER_BASE_URL + `/api/v1`
1119
+ */
1120
+ proxyProvider: z.ZodDefault<z.ZodOptional<z.ZodString>>;
1121
+ /**
1122
+ * Override cloud provider base. Defaults to PRISMER_BASE_URL + /api/v1
1123
+ * (or `/api/v1/proxy/<proxyProvider>` when `proxyProvider !== 'newapi'`).
1124
+ * An explicit value here WINS over `proxyProvider` — operators who pin
1125
+ * the base_url get exactly what they pinned.
1126
+ */
694
1127
  prismerProviderBaseUrl: z.ZodOptional<z.ZodString>;
695
1128
  /** Env key Hermes reads from profile .env for the Prismer API key. */
696
1129
  prismerApiKeyEnv: z.ZodDefault<z.ZodString>;
@@ -727,6 +1160,74 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
727
1160
  }, z.ZodTypeAny, "passthrough">>, "many">]>>;
728
1161
  /** Override the skills root read for dispatch-time SKILL.md injection. */
729
1162
  skillsDir: z.ZodOptional<z.ZodString>;
1163
+ /**
1164
+ * release201/24 §Phase2 — extra skill dirs registered into the gateway's
1165
+ * config.yaml `skills.external_dirs` so the skill-under-test enters Hermes'
1166
+ * NATIVE skill discovery (skills_list / skill tools). The daemon's
1167
+ * system-prompt injection alone is not seen by the agent's skill tools, and
1168
+ * HERMES_HOME does NOT scope skill loading (the ~90 bundled skills ship with
1169
+ * the hermes package). The eval session spawner sets this to its isolated
1170
+ * temp-home skills dir.
1171
+ */
1172
+ skillsExternalDirs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
1173
+ /**
1174
+ * release201/24 §Phase2 — install the prismer daemon memory hooks
1175
+ * (pre_llm_call recall / post_llm_call extract / on_session_end). Default
1176
+ * true. The eval session spawner sets this FALSE so a throwaway eval run
1177
+ * neither READS contaminated workspace memory (a prior failed run's
1178
+ * "skill X is stale" note biases the agent) nor WRITES memories that poison
1179
+ * later runs — the eval judges the skill on its own merits.
1180
+ */
1181
+ installMemoryHooks: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1182
+ /**
1183
+ * release201/26 §14 Phase A (#A1) — enable hermes' BUILTIN knowledge memory
1184
+ * (`MEMORY.md` / `USER.md` injected into the system prompt). Default false.
1185
+ *
1186
+ * release201/09 §9.4b (2026-05-30 hotfix, Option B2) — important correction
1187
+ * to the previous comment claim "hermes' code default = False, we don't
1188
+ * write a memory: block so it stays off". That was WRONG: hermes
1189
+ * deep-merges user config OVER `DEFAULT_CONFIG` (hermes_cli/config.py:4701
1190
+ * `_deep_merge`), and `DEFAULT_CONFIG.memory.memory_enabled = True`
1191
+ * (config.py:1373). `agent_init.py:1076` reads from the MERGED config, so
1192
+ * not writing a `memory:` block leaves hermes builtin memory ON. Real
1193
+ * contamination symptom (2026-05-30 user report): after workspace clear +
1194
+ * new workspace spawn, CEO recited 5 prior-workspace agent IDs + 7 named
1195
+ * humans verbatim from `~/.hermes/profiles/ceo/memories/MEMORY.md`. Fix
1196
+ * here = ALWAYS write the `memory:` block with explicit values; default
1197
+ * (false) writes `memory_enabled: false` + `user_profile_enabled: false`
1198
+ * so hermes' builtin MEMORY.md/USER.md injection is genuinely off. When
1199
+ * true (release201/26 §14 Phase A cutover), writes `memory_enabled: true`
1200
+ * + `user_profile_enabled: true`. Operator-set sibling keys in an existing
1201
+ * memory: block (e.g. `memory_char_limit`, `provider`) are preserved.
1202
+ */
1203
+ enableBuiltinMemory: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1204
+ /**
1205
+ * release201/26 §13.4a (P2 spike, 2026-05-30) — pin hermes vision config so
1206
+ * an agent on a `custom:` provider can actually RECEIVE images.
1207
+ *
1208
+ * Production坑: hermes v0.15.0 does NOT route images through the main chat's
1209
+ * inline image part; it spins up a separate `vision_analyze_tool` aux LLM.
1210
+ * That aux path's provider auto-detect does NOT recognize `custom:` providers
1211
+ * → 502. Every daemon agent runs a custom provider (`custom:prismer` →
1212
+ * Prismer Cloud `/api/v1`), so DEFAULT behaviour is: agent receives an image
1213
+ * → guaranteed 502. The spike-verified fix is pure config (no hermes patch):
1214
+ * model.supports_vision: true + agent.image_input_mode: native
1215
+ * which takes the native fast-path and feeds the image straight to the main
1216
+ * model. The default model `us-kimi-k2.6` is vision-capable and correctly
1217
+ * described images under this config in the spike.
1218
+ *
1219
+ * Default取舍 (2026-05-30, evidence-based): when the caller does NOT set this
1220
+ * explicitly, the effective value is `VISION_CAPABLE_MODELS.has(config.model)`
1221
+ * — a per-model allowlist measured by real cloud-proxy vision probes (see the
1222
+ * `VISION_CAPABLE_MODELS` docblock). This REPLACES the prior
1223
+ * `proxyProvider === 'deepseek' ? false : true` heuristic. Verified vision
1224
+ * models (gemini-3.1-pro-preview, gemini-3.1-flash-lite-preview, us-kimi-k2.6
1225
+ * — the daemon default) default ON; verified text-only models
1226
+ * (deepseek-v4-flash / deepseek-v4-pro, which 400 on image parts) default OFF.
1227
+ * An explicit value here always wins; set `true` to force vision on an
1228
+ * unmeasured model, `false` for any text-only / reasoning model.
1229
+ */
1230
+ supportsVision: z.ZodOptional<z.ZodBoolean>;
730
1231
  /**
731
1232
  * Role-template snapshot carried in AgentProfile.config by cloud ACP.
732
1233
  * Expected fields used here:
@@ -797,12 +1298,15 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
797
1298
  installPrismerMcpServer: boolean;
798
1299
  model: string;
799
1300
  prismerProviderName: string;
1301
+ proxyProvider: string;
800
1302
  prismerApiKeyEnv: string;
801
1303
  mirrorNativeKanban: boolean;
802
1304
  mirrorNativeGoals: boolean;
803
1305
  nativeMirrorTimeoutMs: number;
804
1306
  taskAuthority: "executor" | "orchestrator";
805
1307
  approvalPolicy: "strict" | "auto-low-risk" | "autonomous";
1308
+ installMemoryHooks: boolean;
1309
+ enableBuiltinMemory: boolean;
806
1310
  hermesProfileName?: string | undefined;
807
1311
  prismerMcpServerPath?: string | undefined;
808
1312
  prismerProviderBaseUrl?: string | undefined;
@@ -812,6 +1316,8 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
812
1316
  text: z.ZodString;
813
1317
  }, z.ZodTypeAny, "passthrough">[] | undefined;
814
1318
  skillsDir?: string | undefined;
1319
+ skillsExternalDirs?: string[] | undefined;
1320
+ supportsVision?: boolean | undefined;
815
1321
  roleTemplate?: z.objectOutputType<{
816
1322
  mcpServers: z.ZodOptional<z.ZodArray<z.ZodObject<{
817
1323
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -842,6 +1348,7 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
842
1348
  prismerMcpServerPath?: string | undefined;
843
1349
  model?: string | undefined;
844
1350
  prismerProviderName?: string | undefined;
1351
+ proxyProvider?: string | undefined;
845
1352
  prismerProviderBaseUrl?: string | undefined;
846
1353
  prismerApiKeyEnv?: string | undefined;
847
1354
  mirrorNativeKanban?: boolean | undefined;
@@ -855,6 +1362,10 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
855
1362
  text: z.ZodString;
856
1363
  }, z.ZodTypeAny, "passthrough">[] | undefined;
857
1364
  skillsDir?: string | undefined;
1365
+ skillsExternalDirs?: string[] | undefined;
1366
+ installMemoryHooks?: boolean | undefined;
1367
+ enableBuiltinMemory?: boolean | undefined;
1368
+ supportsVision?: boolean | undefined;
858
1369
  roleTemplate?: z.objectInputType<{
859
1370
  mcpServers: z.ZodOptional<z.ZodArray<z.ZodObject<{
860
1371
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -920,11 +1431,27 @@ declare const OpenClawProfileConfigSchema: z.ZodObject<{
920
1431
  }, z.ZodTypeAny, "passthrough">>, "many">>;
921
1432
  }, z.ZodTypeAny, "passthrough">>>;
922
1433
  skillsDir: z.ZodOptional<z.ZodString>;
1434
+ /**
1435
+ * release202/03 §3.2 — when set, ensure the OpenClaw gateway's openclaw.json
1436
+ * carries a `prismer` model provider pointing at our cloud gateway, and that
1437
+ * `agents.defaults.model.primary` is the curated model below. Lets each
1438
+ * OpenClaw agent run a different curated chat model through one sk-prismer key
1439
+ * (tiered model). Undefined = leave openclaw.json untouched (legacy).
1440
+ */
1441
+ proxyProvider: z.ZodOptional<z.ZodEnum<["newapi", "deepseek"]>>;
1442
+ /** Curated LLM model id the gateway should use (e.g. 'us-kimi-k2.6'). */
1443
+ prismerModel: z.ZodOptional<z.ZodString>;
1444
+ /** Env var (in the gateway process) holding the sk-prismer-* key. */
1445
+ prismerApiKeyEnv: z.ZodDefault<z.ZodString>;
1446
+ /** openclaw.json path (default ~/.openclaw/openclaw.json or $OPENCLAW_HOME). */
1447
+ openclawConfigPath: z.ZodOptional<z.ZodString>;
923
1448
  }, "strip", z.ZodTypeAny, {
924
1449
  port: number;
925
1450
  apiKey: string;
926
1451
  model: string;
1452
+ prismerApiKeyEnv: string;
927
1453
  approvalPolicy: "strict" | "auto-low-risk" | "autonomous";
1454
+ proxyProvider?: "newapi" | "deepseek" | undefined;
928
1455
  mcpAllowlist?: string[] | null | undefined;
929
1456
  skillsDir?: string | undefined;
930
1457
  roleTemplate?: z.objectOutputType<{
@@ -936,10 +1463,14 @@ declare const OpenClawProfileConfigSchema: z.ZodObject<{
936
1463
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
937
1464
  }, z.ZodTypeAny, "passthrough">>, "many">>;
938
1465
  }, z.ZodTypeAny, "passthrough"> | undefined;
1466
+ prismerModel?: string | undefined;
1467
+ openclawConfigPath?: string | undefined;
939
1468
  }, {
940
1469
  apiKey: string;
941
1470
  port?: number | undefined;
942
1471
  model?: string | undefined;
1472
+ proxyProvider?: "newapi" | "deepseek" | undefined;
1473
+ prismerApiKeyEnv?: string | undefined;
943
1474
  approvalPolicy?: "strict" | "auto-low-risk" | "autonomous" | undefined;
944
1475
  mcpAllowlist?: string[] | null | undefined;
945
1476
  skillsDir?: string | undefined;
@@ -952,6 +1483,8 @@ declare const OpenClawProfileConfigSchema: z.ZodObject<{
952
1483
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
953
1484
  }, z.ZodTypeAny, "passthrough">>, "many">>;
954
1485
  }, z.ZodTypeAny, "passthrough"> | undefined;
1486
+ prismerModel?: string | undefined;
1487
+ openclawConfigPath?: string | undefined;
955
1488
  }>;
956
1489
  type OpenClawProfileConfig = z.infer<typeof OpenClawProfileConfigSchema>;
957
1490
  declare const openclawAdapter: AdapterDef;
@@ -1016,7 +1549,7 @@ type LocalDb = Database.Database;
1016
1549
  declare function openLocalDb(path: string): LocalDb;
1017
1550
  declare function runMigrations(db: LocalDb): void;
1018
1551
  declare function currentSchemaVersion(db: LocalDb): number;
1019
- declare const TARGET_SCHEMA_VERSION = 5;
1552
+ declare const TARGET_SCHEMA_VERSION = 8;
1020
1553
 
1021
1554
  type SyncResourceType = 'workspace' | 'agent' | 'agent_profile';
1022
1555
  type SyncOperation = 'create' | 'update' | 'delete';
@@ -1215,9 +1748,9 @@ interface ConfigPaths {
1215
1748
  /**
1216
1749
  * Legacy per-task run scratch dirs (pre-release201/09).
1217
1750
  *
1218
- * Pre-09: `${runsDir}/${taskId}/_outbox|workdir/`.
1219
- * 09 Phase 2: dispatch.ts now writes to
1220
- * `${root}/workspaces/<wid>/projects/<pid|_unscoped>/tasks/<tid>/{result,workdir}`
1751
+ * Pre-09: `${runsDir}/${taskId}/_outbox|scratch/`.
1752
+ * 09 Phase 2 / release202/04: dispatch.ts now writes to
1753
+ * `${root}/workspaces/<wid>/projects/<pid|_unscoped>/tasks/<tid>/{artifacts,scratch}`
1221
1754
  * via `resolveTaskWorkdir()`. `runsDir` is kept as a fallback for tests + a
1222
1755
  * once-off startup migration helper (`runs/<tid>/` → new path; symlink 兜底
1223
1756
  * 90 天兼容期, §9.3.1).
@@ -1667,13 +2200,14 @@ interface UrlResolution {
1667
2200
  */
1668
2201
  declare function extractHttpUrls(text: string): string[];
1669
2202
 
1670
- interface OutboxWatcherOptions {
2203
+ interface ArtifactsWatcherOptions {
1671
2204
  /**
1672
2205
  * Default directory to watch when no setActiveTask has narrowed it.
1673
- * Container mode: `/workspace/_outbox`. Host mode: omit (no default
1674
- * scan only watch when an active task points at a specific dir).
2206
+ * Container mode: `/workspace/_outbox` (legacy path name kept for the
2207
+ * container controller contract). Host mode: omit (no default scan only
2208
+ * watch when an active task points at a specific dir).
1675
2209
  */
1676
- outboxDir?: string;
2210
+ artifactsDir?: string;
1677
2211
  /** Cloud client (already configured with apiKey + baseUrl). */
1678
2212
  cloud: CloudClient;
1679
2213
  /**
@@ -1697,19 +2231,39 @@ interface OutboxWatcherOptions {
1697
2231
  info: (msg: string) => void;
1698
2232
  warn: (msg: string) => void;
1699
2233
  };
2234
+ /**
2235
+ * release202/09 P2 — directory auto-scan gate. **Default FALSE.**
2236
+ *
2237
+ * When false, the polling scan loop does NOT run: the watcher never reads
2238
+ * `artifactsDir` and never auto-uploads files. File delivery is instead
2239
+ * driven EXPLICITLY by the agent via `cloud deliver` → daemon local-server
2240
+ * `POST /local/deliver` → `recordDeliveredAsset(taskId, assetId)`. The
2241
+ * `pendingByTask` / `flushPending` / `recordDeliveredAsset` plumbing and the
2242
+ * `upload()` path all still work — only the implicit directory-magic is off.
2243
+ *
2244
+ * The original directory-scan code (currentScanDirs / tick / scanDir /
2245
+ * quarantine) is retained intact behind this flag so it can be re-enabled
2246
+ * (autoScan:true) as a fallback if the explicit path needs to fall back to
2247
+ * the legacy auto-archive behaviour.
2248
+ */
2249
+ autoScan?: boolean;
1700
2250
  }
1701
2251
  interface ActiveTask {
1702
2252
  taskId: string;
1703
2253
  /** Adapter name; surfaces in upload metadata for observability. */
1704
2254
  adapter?: string;
1705
2255
  /**
1706
- * Per-task outbox directory. When set, scans this directory in
1707
- * addition to `opts.outboxDir`. Files uploaded from here are tagged
2256
+ * Per-task artifacts directory. When set, scans this directory in
2257
+ * addition to `opts.artifactsDir`. Files uploaded from here are tagged
1708
2258
  * with `kind=agent-output` (host-mode contract).
2259
+ *
2260
+ * Backward-compat (release202/04 P0): the watcher also scans the sibling
2261
+ * legacy `result/` and `_outbox/` dirs (resolved from this dir's parent)
2262
+ * for in-flight tasks created before the artifacts rename.
1709
2263
  */
1710
- outboxDir?: string;
2264
+ artifactsDir?: string;
1711
2265
  }
1712
- declare class OutboxWatcher {
2266
+ declare class ArtifactsWatcher {
1713
2267
  private opts;
1714
2268
  private timer?;
1715
2269
  private uploaded;
@@ -1729,7 +2283,7 @@ declare class OutboxWatcher {
1729
2283
  /**
1730
2284
  * Legacy container/sandbox task. Used only when an `ActiveTask` is set
1731
2285
  * **without** an `outboxDir` (i.e. the legacy `setActiveTask` shape
1732
- * where the watcher's default `opts.outboxDir` is the scan target).
2286
+ * where the watcher's default `opts.artifactsDir` is the scan target).
1733
2287
  * Single slot because the legacy container deployment only ever runs
1734
2288
  * one task at a time per container.
1735
2289
  */
@@ -1742,13 +2296,13 @@ declare class OutboxWatcher {
1742
2296
  * can stamp it onto task.dispatch.reply.assetIds.
1743
2297
  */
1744
2298
  private pendingByTask;
1745
- constructor(opts: OutboxWatcherOptions);
2299
+ constructor(opts: ArtifactsWatcherOptions);
1746
2300
  /**
1747
2301
  * Register a host-mode task envelope. Each call adds (or replaces) an
1748
2302
  * entry keyed by `task.taskId` so concurrent dispatches do not clobber
1749
2303
  * each other.
1750
2304
  *
1751
- * Requires `task.outboxDir` to be set — the per-task workdir is the
2305
+ * Requires `task.artifactsDir` to be set — the per-task workdir is the
1752
2306
  * isolation boundary. For the legacy container/sandbox single-slot
1753
2307
  * shape (no per-task dir), use `setActiveTask` instead.
1754
2308
  */
@@ -1766,7 +2320,7 @@ declare class OutboxWatcher {
1766
2320
  * mode). The caller is still responsible for `removeActiveTask`
1767
2321
  * (or another `setActiveTask(null)`) at teardown.
1768
2322
  * - Non-null **without** `outboxDir` → store in the legacy container
1769
- * slot. Uploads from `opts.outboxDir` are tagged with this task.
2323
+ * slot. Uploads from `opts.artifactsDir` are tagged with this task.
1770
2324
  * - `null` → clear the legacy container slot only. Does NOT touch
1771
2325
  * the host-mode `activeTasks` map; concurrent host-mode dispatches
1772
2326
  * keep their own slots until they call `removeActiveTask`
@@ -1784,6 +2338,46 @@ declare class OutboxWatcher {
1784
2338
  * second time. dispatch.ts calls this once at reply-build time.
1785
2339
  */
1786
2340
  flushPending(taskId: string): string[];
2341
+ /**
2342
+ * release202/09 P2 — explicit-delivery hook (动作 A).
2343
+ *
2344
+ * Append an already-uploaded assetId to `pendingByTask[taskId]` so the
2345
+ * dispatch-end `flushPending(taskId)` surfaces it on
2346
+ * `task.dispatch.reply.assetIds` — exactly the same channel the (now
2347
+ * gated-off) auto-scan used at lines ~578-580. This is the bridge that
2348
+ * lets the daemon local-server's `POST /local/deliver` handler reuse the
2349
+ * existing reply-attachment plumbing instead of inventing a parallel one.
2350
+ *
2351
+ * Idempotency: callers should pass each assetId once. We de-dup defensively
2352
+ * so a double-delivered file does not appear twice in reply.assetIds.
2353
+ */
2354
+ recordDeliveredAsset(taskId: string, assetId: string): void;
2355
+ /**
2356
+ * release202/09 P2 — explicit upload entrypoint shared by the daemon
2357
+ * local-server `POST /local/deliver` handler. Reads the file off the
2358
+ * container FS, runs the SAME agent-output-policy + magic-bytes guards the
2359
+ * auto-scan `upload()` path uses, and POSTs via `DaemonAssetUploadClient`
2360
+ * with the daemon's credential. Returns the freshly-minted assetId.
2361
+ *
2362
+ * Unlike the private `upload()` (which is keyed on an ActiveTask + Stats
2363
+ * from the scan loop), this is a one-shot for a caller-supplied absolute
2364
+ * path; it does NOT touch `pendingByTask` — the caller decides whether the
2365
+ * file rides the reply (`recordDeliveredAsset`, 动作 A) or goes out as a
2366
+ * standalone message (动作 B).
2367
+ *
2368
+ * Throws a clear Error on policy / magic-bytes rejection so the agent can
2369
+ * read why its file was refused.
2370
+ */
2371
+ deliverFile(input: {
2372
+ taskId: string;
2373
+ filePath: string;
2374
+ adapter?: string;
2375
+ }): Promise<{
2376
+ assetId: string;
2377
+ mime: string;
2378
+ filename: string;
2379
+ sizeBytes: number;
2380
+ }>;
1787
2381
  start(): void;
1788
2382
  stop(): void;
1789
2383
  /**
@@ -1801,8 +2395,13 @@ declare class OutboxWatcher {
1801
2395
  * and accumulated per-task without sharing global mutable state.
1802
2396
  *
1803
2397
  * Dedup so a directory configured in both spots only scans once
1804
- * (legacy single-task case where opts.outboxDir == legacyTask.outboxDir
2398
+ * (legacy single-task case where opts.artifactsDir == legacyTask.artifactsDir
1805
2399
  * is unlikely but cheap to handle).
2400
+ *
2401
+ * Backward-compat (release202/04 P0): for each host-mode task pointing at
2402
+ * the new `artifacts/` dir, also enqueue its sibling legacy `result/` and
2403
+ * `_outbox/` dirs (same parent). readdir on a missing legacy dir is a cheap
2404
+ * ENOENT no-op in scanDir, so this is safe even when no legacy files exist.
1806
2405
  */
1807
2406
  private currentScanDirs;
1808
2407
  private tick;
@@ -1914,13 +2513,12 @@ interface DispatchDeps {
1914
2513
  /** Hook for tests / observability. */
1915
2514
  onProgress?: (taskId: string, p: TaskDispatchProgressPayload) => void;
1916
2515
  /**
1917
- * Outbox uploader. When provided, dispatch creates a per-task outbox
1918
- * directory under `paths.runsDir`, points the watcher at it via
1919
- * setActiveTask, and drains its assetIds into reply.assetIds at flush
1920
- * time. Optional so tests can omit it.
2516
+ * Artifacts uploader. When provided, dispatch creates a per-task artifacts
2517
+ * directory, points the watcher at it via setActiveTask, and drains its
2518
+ * assetIds into reply.assetIds at flush time. Optional so tests can omit it.
1921
2519
  */
1922
- outboxWatcher?: OutboxWatcher;
1923
- /** Daemon paths — used to derive the per-task outbox dir. */
2520
+ artifactsWatcher?: ArtifactsWatcher;
2521
+ /** Daemon paths — used to derive the per-task artifacts dir. */
1924
2522
  paths?: ConfigPaths;
1925
2523
  /**
1926
2524
  * release201/09 §9.9 — Stable device identifier from `config.toml`. Surfaced
@@ -2058,6 +2656,17 @@ declare class ServicePool {
2058
2656
  * on first use or after a crash. Re-checks `healthy()` before returning a cached entry.
2059
2657
  */
2060
2658
  ensureService(profile: AgentProfile, adapter: AdapterDef): Promise<AdapterService>;
2659
+ /**
2660
+ * Best-effort read of a cached service by profileId. Does NOT trigger
2661
+ * ensureService / health probe (use ensureService for that). Returns
2662
+ * `undefined` when the pool has never seen the profile or it crashed.
2663
+ *
2664
+ * Added for release201/25 §16.4 A6 — runner needs to reach a live
2665
+ * HermesService instance to call native `resolveApproval` without
2666
+ * paying ensureService's spawn cost (the service is already alive for
2667
+ * the in-flight task).
2668
+ */
2669
+ peek(profileId: string): AdapterService | undefined;
2061
2670
  /** Drop a service handle (e.g. on profile delete or daemon shutdown). */
2062
2671
  drop(profileId: string): Promise<void>;
2063
2672
  /** Drop all handles, e.g. on graceful shutdown. */
@@ -2131,6 +2740,29 @@ interface LocalServerOptions {
2131
2740
  * When set, /healthz reports `assetReady: true`.
2132
2741
  */
2133
2742
  attachAsset?: (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
2743
+ /**
2744
+ * release202/09 P2 — explicit file-delivery handler for
2745
+ * `POST /local/deliver`. The in-container agent's `cloud deliver` /
2746
+ * `cloud file send` proxy to this endpoint so the daemon (which holds the
2747
+ * usable IM credential the agent lacks) performs the upload + delivery.
2748
+ *
2749
+ * Body: `{ taskId, path, mode: 'attach' | 'send' | 'task-attach' | 'message-attach', conversationId?, messageId? }`.
2750
+ * - `mode:'attach'` (动作 A): upload + record the assetId onto the active
2751
+ * task's pending list so dispatch-end `flushPending` rides it on the
2752
+ * agent's reply (`reply.assetIds`).
2753
+ * - `mode:'send'` (动作 B): upload + post a standalone message carrying the
2754
+ * attachment to `conversationId`.
2755
+ * - `mode:'task-attach'` (动作 ③, P5#2): upload as a TASK-bound asset
2756
+ * (`sourceTaskId`) for a real kanban task; cloud auto-rolls it onto the
2757
+ * task card + re-emits the terminal digest. No chat reply, no message.
2758
+ * - `mode:'message-attach'` (动作 A2, P5#3): upload + append the asset to an
2759
+ * ALREADY-SENT message (`conversationId` + `messageId`) via the cloud
2760
+ * attach route, which re-emits `message.updated` so the UI picks it up.
2761
+ *
2762
+ * Returns a structured `{ status, body }`. The runner wires this from
2763
+ * `attachDeliver()` in `daemon/asset/deliver.ts`.
2764
+ */
2765
+ onDeliver?: (body: unknown) => Promise<DeliverHandlerResult>;
2134
2766
  /**
2135
2767
  * Optional first-pass handler for `/v1/hooks/*` routes (v2.1 §9.5
2136
2768
  * daemon-as-hook-intake). Returns true if the request was handled
@@ -2170,6 +2802,10 @@ interface AssetWriteHandlerResult {
2170
2802
  status: 200 | 400 | 502;
2171
2803
  body: unknown;
2172
2804
  }
2805
+ interface DeliverHandlerResult {
2806
+ status: 200 | 400 | 404 | 422 | 502;
2807
+ body: unknown;
2808
+ }
2173
2809
  /**
2174
2810
  * Dispatch envelope received from the sandbox controller proxy. The schema
2175
2811
  * mirrors `DaemonDispatchSchema` in `infra/sandbox-controller/src/api/v1/
@@ -2257,6 +2893,16 @@ interface LocalServerState {
2257
2893
  name: string;
2258
2894
  ready: boolean;
2259
2895
  version?: string;
2896
+ /**
2897
+ * Release 201 v2.0.7 P1 — pinned binary version range from
2898
+ * `adapters/known-versions.ts`. `minVersion` is the lowest upstream
2899
+ * the wrapper has actively run against; `knownGood` is the rev
2900
+ * exercised by the current cookbook + CI smoke. Both are surfaced
2901
+ * verbatim so cloud-side debug-pipeline can flag drift between the
2902
+ * detected `version` and what we've tested.
2903
+ */
2904
+ minVersion?: string;
2905
+ knownGood?: string;
2260
2906
  }>;
2261
2907
  /**
2262
2908
  * Resource snapshot (Release 200 §5.4 + 08 §175). v200 baseline returns
@@ -2303,7 +2949,7 @@ declare class LocalServer {
2303
2949
  *
2304
2950
  * Walks `snapshotRoot` (default `/workspace`), computes per-file
2305
2951
  * sha256 + sizeBytes + mtime, returns `{ files: [...], rootPath }`.
2306
- * Skips dotfiles + the `_outbox/_uploaded` reserved subdir. Phase 1
2952
+ * Skips dotfiles + the `<artifacts|_outbox|result>/_uploaded` reserved subdir. Phase 1
2307
2953
  * caller (cloud or controller) is responsible for POSTing the result
2308
2954
  * to `/api/sandboxes/:id/snapshot/manifest`.
2309
2955
  */
@@ -2325,6 +2971,19 @@ declare class LocalServer {
2325
2971
  * 502 on cloud upstream failure; 501 if no sink wired.
2326
2972
  */
2327
2973
  private handleAssetWrite;
2974
+ /**
2975
+ * POST /local/deliver — release202/09 P2 explicit file delivery.
2976
+ *
2977
+ * Body: { taskId, path, mode: 'attach' | 'send' | 'task-attach' | 'message-attach', conversationId?, messageId? }
2978
+ * 200: { ok: true, assetId }
2979
+ * 400 invalid body; 404 file not found; 422 policy/magic-bytes rejection;
2980
+ * 502 cloud upstream failure; 501 if no sink wired.
2981
+ *
2982
+ * The daemon-side `onDeliver` sink (daemon/asset/deliver.ts) owns the
2983
+ * upload (via ArtifactsWatcher.deliverFile, daemon credential) and the
2984
+ * attach-vs-send branch.
2985
+ */
2986
+ private handleDeliver;
2328
2987
  /**
2329
2988
  * POST /dispatch — external channel message → hosted agent dispatch.
2330
2989
  *
@@ -2377,9 +3036,12 @@ declare class Runner extends EventEmitter {
2377
3036
  private servicePool;
2378
3037
  private shellConfig;
2379
3038
  private localServer?;
2380
- private outboxWatcher?;
3039
+ private evalRunner?;
3040
+ private artifactsWatcher?;
2381
3041
  private memoryWiring?;
2382
3042
  private runSessionRegistry?;
3043
+ private runCheckpointStore?;
3044
+ private hermesSessionMapper?;
2383
3045
  private assetMetadataIndexes;
2384
3046
  private workspaceMirrors;
2385
3047
  private assetOriginOutbox?;
@@ -2445,6 +3107,35 @@ declare class Runner extends EventEmitter {
2445
3107
  * run `failed` without any retry).
2446
3108
  */
2447
3109
  private resumeInFlightTasks;
3110
+ /**
3111
+ * release201/26 Phase 4 — daemon-local checkpoint resume scan.
3112
+ *
3113
+ * Looks at `local_run_checkpoints` (phase-level). A run that still has
3114
+ * checkpoints at boot means the daemon died before dispatch.ts reached its
3115
+ * terminal `finally` (which deletes them). For each:
3116
+ *
3117
+ * - adapter registered + healthy → RESUMABLE. The cloud-side sweep
3118
+ * (resumeInFlightTasks, which ran just before this) already re-dispatches
3119
+ * in-flight runs from cloud truth — that fresh dispatch writes new
3120
+ * checkpoints — so here we only confirm resumability, count it, and clear
3121
+ * the stale checkpoint. onResume is a confirm/log step, not a second
3122
+ * dispatch (onTaskDispatch would dedupe anyway).
3123
+ * - adapter missing / unhealthy → emit `task.dispatch.resume_failed` so
3124
+ * cloud marks IMTaskRun.status='resume_failed' and the chat strip renders
3125
+ * "task interrupted, retry".
3126
+ *
3127
+ * Best-effort + one-shot in spirit (the scan clears each run's checkpoints, so
3128
+ * a re-invocation is a no-op). Requires ws so resume_failed can be sent.
3129
+ */
3130
+ private resumeFromCheckpoints;
3131
+ /**
3132
+ * release201/26 §9 — emit daemon_run_resume_total{result} (and, on failure,
3133
+ * task_dispatch_resume_failed_total). Fire-and-forget; the cloud /batch
3134
+ * endpoint requires workspaceId, so we attach this daemon's bound workspace
3135
+ * (best-effort — when unknown the event is dropped by cloud, which is fine:
3136
+ * an unscoped daemon has no run to attribute).
3137
+ */
3138
+ private emitResumeMetric;
2448
3139
  /**
2449
3140
  * Rebuild a `task.dispatch.request` payload from an in-flight IMTaskRun
2450
3141
  * row + its parent IMTask. Mirrors what cloud-side
@@ -2543,10 +3234,30 @@ declare class Runner extends EventEmitter {
2543
3234
  * validation logic doesn't trip on an unknown field.
2544
3235
  */
2545
3236
  private onWebhookDispatch;
3237
+ /**
3238
+ * release201/24 §3 — handle a cloud-pushed eval run. Ack immediately over
3239
+ * the reverse channel (so cloud's WsRpcService settles), then run the eval
3240
+ * asynchronously. Per-case results are POSTed by EvalSessionRunner.onFinish.
3241
+ */
3242
+ private onEvalRequest;
2546
3243
  private onHostAcked;
2547
3244
  private applyHostAckOwnershipLock;
2548
3245
  private onTaskDispatch;
2549
3246
  private onTaskCancel;
3247
+ /**
3248
+ * release201/25 §16.4 A6 — additionally call hermes-native
3249
+ * `POST /v1/runs/{runId}/approval` so hermes-internal HITL state
3250
+ * (session-level "always" cache, pending approval timer) aligns with
3251
+ * the cloud-side decision. The cloud-side redispatch (approval.decided)
3252
+ * is still the authoritative continuation; this is the SECOND write
3253
+ * to keep hermes in sync.
3254
+ *
3255
+ * Best-effort and tolerant: any failure (no runId / no hermes service /
3256
+ * capability missing / hermes 4xx) is logged but never propagated. The
3257
+ * agent will still receive its `approval.decided` task dispatch.
3258
+ */
3259
+ private onTaskApprovalResolve;
3260
+ private onTaskClarifyResolve;
2550
3261
  private findMessageDispatchAgent;
2551
3262
  private postMessageDispatchReply;
2552
3263
  /**
@@ -2566,6 +3277,26 @@ declare class Runner extends EventEmitter {
2566
3277
  private syncProfileFromCloud;
2567
3278
  private resolveOwnedAgent;
2568
3279
  private onWorkspaceChanged;
3280
+ /**
3281
+ * release201/09 §9.4b — wipe local hermes profile memories + per-agent
3282
+ * memory dir for every agent the cloud says belonged to the cleared
3283
+ * workspace. Cloud has already deleted the cloud-side rows (cascade
3284
+ * ordering: cloud-first, daemon-second), so this fan-out is purely
3285
+ * local-FS cleanup. Best-effort: every failure stderr-logs and continues.
3286
+ *
3287
+ * Resolution: iterate local agent_profiles rows whose agent_im_user_id
3288
+ * appears in payload.agentImUserIds; for each, derive the hermes profile
3289
+ * name via getHermesProfileName (same call site spawn / configure uses)
3290
+ * and call wipeHermesProfileMemory. Then for every agent_im_user_id,
3291
+ * wipe ~/.prismer/devices/<did>/agents/<aid>/memory/* (skills/ stays).
3292
+ *
3293
+ * We do NOT delete agent_profiles rows from local SQLite here — that
3294
+ * happens via the existing agent_profile.changed (delete) flow which the
3295
+ * cloud also emits as part of workspace clear (im_agent_profiles rows
3296
+ * are deleted by clearWorkspaceCascade). This handler is purely the
3297
+ * filesystem-layer counterpart of those Prisma deletes.
3298
+ */
3299
+ private onWorkspaceClearDaemonCleanup;
2569
3300
  private onAssetChanged;
2570
3301
  private onWorkspaceFileChanged;
2571
3302
  private snapshotAdapterObservability;
@@ -2671,15 +3402,15 @@ declare const CCConfigSchema: z.ZodObject<{
2671
3402
  args: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
2672
3403
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
2673
3404
  }, "strip", z.ZodTypeAny, {
2674
- command: string;
2675
3405
  name: string;
2676
- env?: Record<string, string> | undefined;
3406
+ command: string;
2677
3407
  args?: string[] | undefined;
3408
+ env?: Record<string, string> | undefined;
2678
3409
  }, {
2679
- command: string;
2680
3410
  name: string;
2681
- env?: Record<string, string> | undefined;
3411
+ command: string;
2682
3412
  args?: string[] | undefined;
3413
+ env?: Record<string, string> | undefined;
2683
3414
  }>, "many">>;
2684
3415
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
2685
3416
  maxTurns: z.ZodDefault<z.ZodNumber>;
@@ -2692,10 +3423,10 @@ declare const CCConfigSchema: z.ZodObject<{
2692
3423
  maxTurns: number;
2693
3424
  route: "default" | "prismer" | "omniroute";
2694
3425
  mcpServers?: {
2695
- command: string;
2696
3426
  name: string;
2697
- env?: Record<string, string> | undefined;
3427
+ command: string;
2698
3428
  args?: string[] | undefined;
3429
+ env?: Record<string, string> | undefined;
2699
3430
  }[] | undefined;
2700
3431
  systemPrompt?: string | undefined;
2701
3432
  allowedTools?: string[] | undefined;
@@ -2706,10 +3437,10 @@ declare const CCConfigSchema: z.ZodObject<{
2706
3437
  cwd: string;
2707
3438
  model?: string | undefined;
2708
3439
  mcpServers?: {
2709
- command: string;
2710
3440
  name: string;
2711
- env?: Record<string, string> | undefined;
3441
+ command: string;
2712
3442
  args?: string[] | undefined;
3443
+ env?: Record<string, string> | undefined;
2713
3444
  }[] | undefined;
2714
3445
  systemPrompt?: string | undefined;
2715
3446
  allowedTools?: string[] | undefined;
@@ -2747,20 +3478,59 @@ declare const CodexConfigSchema: z.ZodObject<{
2747
3478
  * scoped key under a different name.
2748
3479
  */
2749
3480
  apiKeyEnv: z.ZodDefault<z.ZodString>;
3481
+ /**
3482
+ * release202/03 §3.2 + 07 — route Codex through our cloud gateway instead of
3483
+ * the official OpenAI endpoint. When set, the adapter writes a per-dispatch
3484
+ * `CODEX_HOME/config.toml` pointing `model_provider=prismer` with
3485
+ * `wire_api="responses"` and a `sk-prismer-*` bearer at:
3486
+ * - `newapi` (or default) → `<PRISMER_BASE_URL>/api/v1` (→ /api/v1/responses)
3487
+ * - any other chain id → `<PRISMER_BASE_URL>/api/v1/proxy/<chain>` (→ /api/v1/proxy/<chain>/responses)
3488
+ * The cloud bridge translates Responses↔Chat and walks the selected provider
3489
+ * chain (07). release202/07 widened this from the old `'newapi'|'deepseek'`
3490
+ * enum to ANY configured chain id. Undefined = official OpenAI endpoint.
3491
+ */
3492
+ proxyProvider: z.ZodOptional<z.ZodString>;
3493
+ /** Env var holding the sk-prismer-* key (default PRISMER_API_KEY). */
3494
+ prismerApiKeyEnv: z.ZodDefault<z.ZodString>;
3495
+ /**
3496
+ * release202/05 C2 — per-(conversation × agent) session continuity. When true
3497
+ * (default), the adapter persists codex session files (drops `--ephemeral`)
3498
+ * and, on subsequent turns of the same conversation, resumes the prior
3499
+ * codex thread via `codex exec resume <thread_id>` so context carries across
3500
+ * turns instead of re-bootstrapping every dispatch.
3501
+ *
3502
+ * Empirically verified (codex-cli 0.133.0, 2026-06-02): a fresh `codex exec`
3503
+ * emits `{"type":"thread.started","thread_id":"<uuid>"}`; `codex exec resume
3504
+ * --json --skip-git-repo-check <thread_id> "<prompt>"` reloads that thread and
3505
+ * recalls prior context. NOTE: `--sandbox`/`--cd` are NOT accepted on the
3506
+ * `resume` subcommand (the help lists them but the parser rejects them when a
3507
+ * positional SESSION_ID is present); sandbox is inherited from the persisted
3508
+ * session, so resume turns reuse turn-1's sandbox/cwd.
3509
+ *
3510
+ * Set false to keep the legacy `--ephemeral` one-shot behavior (no session
3511
+ * files, no resume).
3512
+ */
3513
+ sessionContinuity: z.ZodDefault<z.ZodBoolean>;
2750
3514
  }, "strip", z.ZodTypeAny, {
2751
3515
  sandbox: "read-only" | "workspace-write" | "danger-full-access";
2752
3516
  model: string;
3517
+ prismerApiKeyEnv: string;
2753
3518
  cwd: string;
2754
3519
  apiKeyEnv: string;
3520
+ sessionContinuity: boolean;
3521
+ proxyProvider?: string | undefined;
2755
3522
  systemPrompt?: string | undefined;
2756
3523
  envVars?: Record<string, string> | undefined;
2757
3524
  }, {
2758
3525
  cwd: string;
2759
3526
  sandbox?: "read-only" | "workspace-write" | "danger-full-access" | undefined;
2760
3527
  model?: string | undefined;
3528
+ proxyProvider?: string | undefined;
3529
+ prismerApiKeyEnv?: string | undefined;
2761
3530
  systemPrompt?: string | undefined;
2762
- envVars?: Record<string, string> | undefined;
2763
3531
  apiKeyEnv?: string | undefined;
3532
+ envVars?: Record<string, string> | undefined;
3533
+ sessionContinuity?: boolean | undefined;
2764
3534
  }>;
2765
3535
  type CodexConfig = z.infer<typeof CodexConfigSchema>;
2766
3536
  /**