@prismer/runtime 2.0.6 → 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 +10239 -3309
  202. package/dist/cli.js +10111 -3183
  203. package/dist/index.cjs +11275 -4344
  204. package/dist/index.d.cts +932 -43
  205. package/dist/index.d.ts +932 -43
  206. package/dist/index.js +13087 -6158
  207. package/package.json +4 -2
package/dist/index.d.cts 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
@@ -130,6 +296,45 @@ interface TaskDispatchRequestPayload {
130
296
  }>;
131
297
  /** Wave-8 W1: assets cloud wants daemon to fold into agent context. */
132
298
  assetRefs?: AssetRef[];
299
+ /**
300
+ * release201/09 Phase 2 — task project scope. NULL = workspace-level
301
+ * (`_unscoped` sentinel on disk). Daemon uses this together with
302
+ * `agentImUserId` / `profile.workspaceId` to compose the per-task
303
+ * scratch path: `workspaces/<wid>/projects/<pid|_unscoped>/tasks/<tid>/`.
304
+ * Also forwarded into the spawned agent process as `PRISMER_ACTIVE_PROJECT_ID`
305
+ * (when non-null) so built-in skill --project flag defaults work.
306
+ */
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;
133
338
  }
134
339
  interface TaskDispatchProgressPayload {
135
340
  taskId: string;
@@ -155,6 +360,21 @@ interface AssetDispatchObservation {
155
360
  /** L5: end-to-end fetch duration in ms (DNS + connect + body read). */
156
361
  durationMs?: number;
157
362
  }
363
+ /**
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
366
+ * the file extension (e.g. agent wrote `report.pdf` with markdown content).
367
+ * Cloud persists these on `IMTask.metadata.outboxRejections` (wire field name
368
+ * kept for the cross-process contract) and prepends a
369
+ * warning section to the next dispatch prompt so the agent can self-correct.
370
+ */
371
+ interface OutboxRejectionRecord {
372
+ filename: string;
373
+ reason: string;
374
+ inferredMime: string;
375
+ detectedMime: string;
376
+ rejectedAt: string;
377
+ }
158
378
  interface TaskDispatchReplyPayload {
159
379
  taskId: string;
160
380
  ok: boolean;
@@ -170,6 +390,13 @@ interface TaskDispatchReplyPayload {
170
390
  };
171
391
  /** Wave-8 W1: per-asset handling report. */
172
392
  assetObservability?: AssetDispatchObservation[];
393
+ /**
394
+ * P1-2 (2026-05-25): files quarantined locally by artifacts-watcher's
395
+ * magic-bytes check during this turn. Cloud writes them onto
396
+ * `IMTask.metadata.outboxRejections` so the next dispatch prompt can warn
397
+ * the agent.
398
+ */
399
+ outboxRejections?: OutboxRejectionRecord[];
173
400
  }
174
401
  interface TaskCancelPayload {
175
402
  taskId: string;
@@ -338,7 +565,7 @@ declare class MemoryStore {
338
565
  private rowToPage;
339
566
  }
340
567
 
341
- type MemoryScope = 'workspace-shared' | 'agent-private';
568
+ type MemoryScope = 'workspace-shared' | 'agent-private' | 'session-scratch' | 'role-shared' | 'project-shared' | 'global';
342
569
  interface ScopedMemoryStoreOptions {
343
570
  /** Filesystem root, e.g. `~/.prismer/memory` (will create per-workspace dir under). */
344
571
  rootDir: string;
@@ -353,12 +580,37 @@ interface ScopedWriteInput extends Omit<MemoryWriteInput, 'workspaceId'> {
353
580
  scope: MemoryScope;
354
581
  /** Required when scope='agent-private'; rejected when scope='workspace-shared'. */
355
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;
356
599
  }
357
600
  interface ScopedSearchInput {
358
601
  query: string;
359
602
  scope: MemoryScope;
360
603
  /** Required when scope='agent-private' — search only this agent's bucket. */
361
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;
362
614
  options?: MemorySearchOptions;
363
615
  }
364
616
  /**
@@ -369,19 +621,67 @@ declare class ScopedMemoryStore {
369
621
  private readonly opts;
370
622
  private sharedStore;
371
623
  private agentStores;
624
+ private scratchStores;
625
+ private roleStores;
626
+ private projectStores;
627
+ private globalStore;
372
628
  private readonly workspaceDir;
373
629
  constructor(opts: ScopedMemoryStoreOptions);
374
630
  /** Resolve the shared store (lazy open). */
375
631
  shared(): MemoryStore;
376
632
  /** Resolve the per-agent store (lazy open). */
377
633
  forAgent(agentImUserId: string): MemoryStore;
378
- /** Resolve the right store for (scope, agentImUserId). */
379
- 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;
380
677
  /** Write a memory page into the correct bucket. */
381
678
  write(input: ScopedWriteInput): {
382
679
  pageId: string;
383
680
  scope: MemoryScope;
384
681
  agentImUserId?: string;
682
+ sessionKey?: string;
683
+ roleSlug?: string;
684
+ projectId?: string;
385
685
  };
386
686
  /**
387
687
  * Search only the requested bucket. This is the daemon-first FTS5 path
@@ -396,6 +696,18 @@ declare class ScopedMemoryStore {
396
696
  searchForAgent(query: string, agentImUserId: string, options?: MemorySearchOptions): MemorySearchResult[];
397
697
  /** List which agent ids currently have a private DB on disk (for diagnostics). */
398
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;
399
711
  /** Total disk footprint (best-effort; sums each bucket's main DB file). */
400
712
  diskBytes(): {
401
713
  shared: number;
@@ -485,7 +797,23 @@ interface StepRecorderHandle {
485
797
  }
486
798
  interface TaskInput {
487
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;
488
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
+ */
489
817
  metadata?: Record<string, unknown>;
490
818
  timeoutMs?: number;
491
819
  onProgress?: (p: {
@@ -547,6 +875,110 @@ interface TaskInput {
547
875
  * → passes here). Adapters never instantiate the store themselves.
548
876
  */
549
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;
550
982
  }
551
983
  interface TaskResult {
552
984
  ok: boolean;
@@ -565,7 +997,16 @@ interface TaskResult {
565
997
  tokensUsed?: number;
566
998
  durationMs?: number;
567
999
  };
568
- /** 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
+ */
569
1010
  metadata?: Record<string, unknown>;
570
1011
  }
571
1012
  /**
@@ -660,7 +1101,29 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
660
1101
  model: z.ZodDefault<z.ZodString>;
661
1102
  /** Named custom provider written into Hermes config.yaml. */
662
1103
  prismerProviderName: z.ZodDefault<z.ZodString>;
663
- /** 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
+ */
664
1127
  prismerProviderBaseUrl: z.ZodOptional<z.ZodString>;
665
1128
  /** Env key Hermes reads from profile .env for the Prismer API key. */
666
1129
  prismerApiKeyEnv: z.ZodDefault<z.ZodString>;
@@ -677,12 +1140,6 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
677
1140
  * native state key directly and records the exact bridge result on the task.
678
1141
  */
679
1142
  mirrorNativeGoals: z.ZodDefault<z.ZodBoolean>;
680
- /**
681
- * Optional checkout path for Hermes Agent source. Used only as a fallback
682
- * when the installed `hermes` binary is older than the native Kanban CLI
683
- * surface but the local source tree contains hermes_cli/kanban_db.py.
684
- */
685
- hermesSourceDir: z.ZodOptional<z.ZodString>;
686
1143
  nativeMirrorTimeoutMs: z.ZodDefault<z.ZodNumber>;
687
1144
  /** Task authority level: executor (default) or orchestrator. */
688
1145
  taskAuthority: z.ZodDefault<z.ZodOptional<z.ZodEnum<["executor", "orchestrator"]>>>;
@@ -703,6 +1160,74 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
703
1160
  }, z.ZodTypeAny, "passthrough">>, "many">]>>;
704
1161
  /** Override the skills root read for dispatch-time SKILL.md injection. */
705
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>;
706
1231
  /**
707
1232
  * Role-template snapshot carried in AgentProfile.config by cloud ACP.
708
1233
  * Expected fields used here:
@@ -773,22 +1298,26 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
773
1298
  installPrismerMcpServer: boolean;
774
1299
  model: string;
775
1300
  prismerProviderName: string;
1301
+ proxyProvider: string;
776
1302
  prismerApiKeyEnv: string;
777
1303
  mirrorNativeKanban: boolean;
778
1304
  mirrorNativeGoals: boolean;
779
1305
  nativeMirrorTimeoutMs: number;
780
1306
  taskAuthority: "executor" | "orchestrator";
781
1307
  approvalPolicy: "strict" | "auto-low-risk" | "autonomous";
1308
+ installMemoryHooks: boolean;
1309
+ enableBuiltinMemory: boolean;
782
1310
  hermesProfileName?: string | undefined;
783
1311
  prismerMcpServerPath?: string | undefined;
784
1312
  prismerProviderBaseUrl?: string | undefined;
785
- hermesSourceDir?: string | undefined;
786
1313
  mcpAllowlist?: string[] | null | undefined;
787
1314
  operatingPrinciples?: string | Record<string, string> | z.objectOutputType<{
788
1315
  source: z.ZodString;
789
1316
  text: z.ZodString;
790
1317
  }, z.ZodTypeAny, "passthrough">[] | undefined;
791
1318
  skillsDir?: string | undefined;
1319
+ skillsExternalDirs?: string[] | undefined;
1320
+ supportsVision?: boolean | undefined;
792
1321
  roleTemplate?: z.objectOutputType<{
793
1322
  mcpServers: z.ZodOptional<z.ZodArray<z.ZodObject<{
794
1323
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -819,11 +1348,11 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
819
1348
  prismerMcpServerPath?: string | undefined;
820
1349
  model?: string | undefined;
821
1350
  prismerProviderName?: string | undefined;
1351
+ proxyProvider?: string | undefined;
822
1352
  prismerProviderBaseUrl?: string | undefined;
823
1353
  prismerApiKeyEnv?: string | undefined;
824
1354
  mirrorNativeKanban?: boolean | undefined;
825
1355
  mirrorNativeGoals?: boolean | undefined;
826
- hermesSourceDir?: string | undefined;
827
1356
  nativeMirrorTimeoutMs?: number | undefined;
828
1357
  taskAuthority?: "executor" | "orchestrator" | undefined;
829
1358
  approvalPolicy?: "strict" | "auto-low-risk" | "autonomous" | undefined;
@@ -833,6 +1362,10 @@ declare const HermesProfileConfigSchema: z.ZodObject<{
833
1362
  text: z.ZodString;
834
1363
  }, z.ZodTypeAny, "passthrough">[] | undefined;
835
1364
  skillsDir?: string | undefined;
1365
+ skillsExternalDirs?: string[] | undefined;
1366
+ installMemoryHooks?: boolean | undefined;
1367
+ enableBuiltinMemory?: boolean | undefined;
1368
+ supportsVision?: boolean | undefined;
836
1369
  roleTemplate?: z.objectInputType<{
837
1370
  mcpServers: z.ZodOptional<z.ZodArray<z.ZodObject<{
838
1371
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
@@ -898,11 +1431,27 @@ declare const OpenClawProfileConfigSchema: z.ZodObject<{
898
1431
  }, z.ZodTypeAny, "passthrough">>, "many">>;
899
1432
  }, z.ZodTypeAny, "passthrough">>>;
900
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>;
901
1448
  }, "strip", z.ZodTypeAny, {
902
1449
  port: number;
903
1450
  apiKey: string;
904
1451
  model: string;
1452
+ prismerApiKeyEnv: string;
905
1453
  approvalPolicy: "strict" | "auto-low-risk" | "autonomous";
1454
+ proxyProvider?: "newapi" | "deepseek" | undefined;
906
1455
  mcpAllowlist?: string[] | null | undefined;
907
1456
  skillsDir?: string | undefined;
908
1457
  roleTemplate?: z.objectOutputType<{
@@ -914,10 +1463,14 @@ declare const OpenClawProfileConfigSchema: z.ZodObject<{
914
1463
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
915
1464
  }, z.ZodTypeAny, "passthrough">>, "many">>;
916
1465
  }, z.ZodTypeAny, "passthrough"> | undefined;
1466
+ prismerModel?: string | undefined;
1467
+ openclawConfigPath?: string | undefined;
917
1468
  }, {
918
1469
  apiKey: string;
919
1470
  port?: number | undefined;
920
1471
  model?: string | undefined;
1472
+ proxyProvider?: "newapi" | "deepseek" | undefined;
1473
+ prismerApiKeyEnv?: string | undefined;
921
1474
  approvalPolicy?: "strict" | "auto-low-risk" | "autonomous" | undefined;
922
1475
  mcpAllowlist?: string[] | null | undefined;
923
1476
  skillsDir?: string | undefined;
@@ -930,6 +1483,8 @@ declare const OpenClawProfileConfigSchema: z.ZodObject<{
930
1483
  toolsAllowlist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
931
1484
  }, z.ZodTypeAny, "passthrough">>, "many">>;
932
1485
  }, z.ZodTypeAny, "passthrough"> | undefined;
1486
+ prismerModel?: string | undefined;
1487
+ openclawConfigPath?: string | undefined;
933
1488
  }>;
934
1489
  type OpenClawProfileConfig = z.infer<typeof OpenClawProfileConfigSchema>;
935
1490
  declare const openclawAdapter: AdapterDef;
@@ -994,7 +1549,7 @@ type LocalDb = Database.Database;
994
1549
  declare function openLocalDb(path: string): LocalDb;
995
1550
  declare function runMigrations(db: LocalDb): void;
996
1551
  declare function currentSchemaVersion(db: LocalDb): number;
997
- declare const TARGET_SCHEMA_VERSION = 4;
1552
+ declare const TARGET_SCHEMA_VERSION = 8;
998
1553
 
999
1554
  type SyncResourceType = 'workspace' | 'agent' | 'agent_profile';
1000
1555
  type SyncOperation = 'create' | 'update' | 'delete';
@@ -1191,11 +1746,28 @@ interface ConfigPaths {
1191
1746
  cacheDir: string;
1192
1747
  logsDir: string;
1193
1748
  /**
1194
- * Per-task run scratch dirs. Each chat-mention dispatch creates
1195
- * `${runsDir}/${taskId}/_outbox/` for adapter-produced files; the
1196
- * OutboxWatcher uploads from there into IMAssets.
1749
+ * Legacy per-task run scratch dirs (pre-release201/09).
1750
+ *
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}`
1754
+ * via `resolveTaskWorkdir()`. `runsDir` is kept as a fallback for tests + a
1755
+ * once-off startup migration helper (`runs/<tid>/` → new path; symlink 兜底
1756
+ * 90 天兼容期, §9.3.1).
1197
1757
  */
1198
1758
  runsDir: string;
1759
+ /**
1760
+ * release201/09 Phase 2 root for workspace × project × task scoped scratch:
1761
+ * `${root}/workspaces/`. resolveTaskWorkdir() composes the per-task path
1762
+ * underneath. Cache GC + project archive scan this root.
1763
+ */
1764
+ workspacesDir: string;
1765
+ /**
1766
+ * release201/09 Phase 2 root for device × agent role layer:
1767
+ * `${root}/devices/`. v2.0.7 Phase 2 不主动创建,Phase 3 (agent transfer)
1768
+ * 才落盘 `profile.json` / `skills/<slug>/` 等内容,本 helper 只解析路径。
1769
+ */
1770
+ devicesDir: string;
1199
1771
  }
1200
1772
  /**
1201
1773
  * Resolve paths for the prismer home directory. Honors `PRISMER_HOME` env var;
@@ -1628,13 +2200,14 @@ interface UrlResolution {
1628
2200
  */
1629
2201
  declare function extractHttpUrls(text: string): string[];
1630
2202
 
1631
- interface OutboxWatcherOptions {
2203
+ interface ArtifactsWatcherOptions {
1632
2204
  /**
1633
2205
  * Default directory to watch when no setActiveTask has narrowed it.
1634
- * Container mode: `/workspace/_outbox`. Host mode: omit (no default
1635
- * 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).
1636
2209
  */
1637
- outboxDir?: string;
2210
+ artifactsDir?: string;
1638
2211
  /** Cloud client (already configured with apiKey + baseUrl). */
1639
2212
  cloud: CloudClient;
1640
2213
  /**
@@ -1658,19 +2231,39 @@ interface OutboxWatcherOptions {
1658
2231
  info: (msg: string) => void;
1659
2232
  warn: (msg: string) => void;
1660
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;
1661
2250
  }
1662
2251
  interface ActiveTask {
1663
2252
  taskId: string;
1664
2253
  /** Adapter name; surfaces in upload metadata for observability. */
1665
2254
  adapter?: string;
1666
2255
  /**
1667
- * Per-task outbox directory. When set, scans this directory in
1668
- * 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
1669
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.
1670
2263
  */
1671
- outboxDir?: string;
2264
+ artifactsDir?: string;
1672
2265
  }
1673
- declare class OutboxWatcher {
2266
+ declare class ArtifactsWatcher {
1674
2267
  private opts;
1675
2268
  private timer?;
1676
2269
  private uploaded;
@@ -1690,7 +2283,7 @@ declare class OutboxWatcher {
1690
2283
  /**
1691
2284
  * Legacy container/sandbox task. Used only when an `ActiveTask` is set
1692
2285
  * **without** an `outboxDir` (i.e. the legacy `setActiveTask` shape
1693
- * where the watcher's default `opts.outboxDir` is the scan target).
2286
+ * where the watcher's default `opts.artifactsDir` is the scan target).
1694
2287
  * Single slot because the legacy container deployment only ever runs
1695
2288
  * one task at a time per container.
1696
2289
  */
@@ -1703,13 +2296,13 @@ declare class OutboxWatcher {
1703
2296
  * can stamp it onto task.dispatch.reply.assetIds.
1704
2297
  */
1705
2298
  private pendingByTask;
1706
- constructor(opts: OutboxWatcherOptions);
2299
+ constructor(opts: ArtifactsWatcherOptions);
1707
2300
  /**
1708
2301
  * Register a host-mode task envelope. Each call adds (or replaces) an
1709
2302
  * entry keyed by `task.taskId` so concurrent dispatches do not clobber
1710
2303
  * each other.
1711
2304
  *
1712
- * 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
1713
2306
  * isolation boundary. For the legacy container/sandbox single-slot
1714
2307
  * shape (no per-task dir), use `setActiveTask` instead.
1715
2308
  */
@@ -1727,7 +2320,7 @@ declare class OutboxWatcher {
1727
2320
  * mode). The caller is still responsible for `removeActiveTask`
1728
2321
  * (or another `setActiveTask(null)`) at teardown.
1729
2322
  * - Non-null **without** `outboxDir` → store in the legacy container
1730
- * slot. Uploads from `opts.outboxDir` are tagged with this task.
2323
+ * slot. Uploads from `opts.artifactsDir` are tagged with this task.
1731
2324
  * - `null` → clear the legacy container slot only. Does NOT touch
1732
2325
  * the host-mode `activeTasks` map; concurrent host-mode dispatches
1733
2326
  * keep their own slots until they call `removeActiveTask`
@@ -1745,6 +2338,46 @@ declare class OutboxWatcher {
1745
2338
  * second time. dispatch.ts calls this once at reply-build time.
1746
2339
  */
1747
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
+ }>;
1748
2381
  start(): void;
1749
2382
  stop(): void;
1750
2383
  /**
@@ -1762,8 +2395,13 @@ declare class OutboxWatcher {
1762
2395
  * and accumulated per-task without sharing global mutable state.
1763
2396
  *
1764
2397
  * Dedup so a directory configured in both spots only scans once
1765
- * (legacy single-task case where opts.outboxDir == legacyTask.outboxDir
2398
+ * (legacy single-task case where opts.artifactsDir == legacyTask.artifactsDir
1766
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.
1767
2405
  */
1768
2406
  private currentScanDirs;
1769
2407
  private tick;
@@ -1875,14 +2513,20 @@ interface DispatchDeps {
1875
2513
  /** Hook for tests / observability. */
1876
2514
  onProgress?: (taskId: string, p: TaskDispatchProgressPayload) => void;
1877
2515
  /**
1878
- * Outbox uploader. When provided, dispatch creates a per-task outbox
1879
- * directory under `paths.runsDir`, points the watcher at it via
1880
- * setActiveTask, and drains its assetIds into reply.assetIds at flush
1881
- * 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.
1882
2519
  */
1883
- outboxWatcher?: OutboxWatcher;
1884
- /** Daemon paths — used to derive the per-task outbox dir. */
2520
+ artifactsWatcher?: ArtifactsWatcher;
2521
+ /** Daemon paths — used to derive the per-task artifacts dir. */
1885
2522
  paths?: ConfigPaths;
2523
+ /**
2524
+ * release201/09 §9.9 — Stable device identifier from `config.toml`. Surfaced
2525
+ * to the spawned agent process as `PRISMER_DAEMON_ID` env for metric-outbox
2526
+ * emission + transfer manifest authoring. Optional so existing tests can
2527
+ * omit it; production runner always provides.
2528
+ */
2529
+ daemonId?: string;
1886
2530
  /**
1887
2531
  * Multi-workspace asset metadata indexes for #filename resolution.
1888
2532
  * Keyed by workspaceId. If absent, #ref resolution is skipped entirely.
@@ -2012,6 +2656,17 @@ declare class ServicePool {
2012
2656
  * on first use or after a crash. Re-checks `healthy()` before returning a cached entry.
2013
2657
  */
2014
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;
2015
2670
  /** Drop a service handle (e.g. on profile delete or daemon shutdown). */
2016
2671
  drop(profileId: string): Promise<void>;
2017
2672
  /** Drop all handles, e.g. on graceful shutdown. */
@@ -2085,11 +2740,72 @@ interface LocalServerOptions {
2085
2740
  * When set, /healthz reports `assetReady: true`.
2086
2741
  */
2087
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>;
2766
+ /**
2767
+ * Optional first-pass handler for `/v1/hooks/*` routes (v2.1 §9.5
2768
+ * daemon-as-hook-intake). Returns true if the request was handled
2769
+ * (response written); false to let the normal route table fall through.
2770
+ * Wired by the daemon runner from `attachHookServer()` in
2771
+ * `daemon/memory/hook-server.ts` whenever both memory + run-session
2772
+ * registry are available. When set, /healthz reports `hooksReady: true`.
2773
+ */
2774
+ attachHooks?: (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
2775
+ /**
2776
+ * Optional first-pass handler for `/v1/checkpoints/*` routes
2777
+ * (release201/09 §9.4a.7 task product self-check). Independent of
2778
+ * `attachHooks` — checkpoints fire on SDK status-transition only, while
2779
+ * hooks fire per LLM call. Wired by the runner from
2780
+ * `attachCheckpointServer()` in `daemon/checkpoint-server.ts`. When set,
2781
+ * /healthz reports `checkpointsReady: true`.
2782
+ */
2783
+ attachCheckpoints?: (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
2784
+ /**
2785
+ * Optional snapshot getter for the eval-session capability
2786
+ * (release201/08 §7.2). When provided, /healthz reports `evalSessions`
2787
+ * with the current active count + per-run summaries. The runner wires
2788
+ * this from `EvalSessionRunner.getState()`.
2789
+ */
2790
+ getEvalSessions?: () => {
2791
+ active: number;
2792
+ queued: number;
2793
+ maxConcurrent: number;
2794
+ runs: Array<{
2795
+ runId: string;
2796
+ skillId: string;
2797
+ startedAt: string;
2798
+ }>;
2799
+ };
2088
2800
  }
2089
2801
  interface AssetWriteHandlerResult {
2090
2802
  status: 200 | 400 | 502;
2091
2803
  body: unknown;
2092
2804
  }
2805
+ interface DeliverHandlerResult {
2806
+ status: 200 | 400 | 404 | 422 | 502;
2807
+ body: unknown;
2808
+ }
2093
2809
  /**
2094
2810
  * Dispatch envelope received from the sandbox controller proxy. The schema
2095
2811
  * mirrors `DaemonDispatchSchema` in `infra/sandbox-controller/src/api/v1/
@@ -2177,6 +2893,16 @@ interface LocalServerState {
2177
2893
  name: string;
2178
2894
  ready: boolean;
2179
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;
2180
2906
  }>;
2181
2907
  /**
2182
2908
  * Resource snapshot (Release 200 §5.4 + 08 §175). v200 baseline returns
@@ -2223,7 +2949,7 @@ declare class LocalServer {
2223
2949
  *
2224
2950
  * Walks `snapshotRoot` (default `/workspace`), computes per-file
2225
2951
  * sha256 + sizeBytes + mtime, returns `{ files: [...], rootPath }`.
2226
- * Skips dotfiles + the `_outbox/_uploaded` reserved subdir. Phase 1
2952
+ * Skips dotfiles + the `<artifacts|_outbox|result>/_uploaded` reserved subdir. Phase 1
2227
2953
  * caller (cloud or controller) is responsible for POSTing the result
2228
2954
  * to `/api/sandboxes/:id/snapshot/manifest`.
2229
2955
  */
@@ -2245,6 +2971,19 @@ declare class LocalServer {
2245
2971
  * 502 on cloud upstream failure; 501 if no sink wired.
2246
2972
  */
2247
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;
2248
2987
  /**
2249
2988
  * POST /dispatch — external channel message → hosted agent dispatch.
2250
2989
  *
@@ -2297,8 +3036,12 @@ declare class Runner extends EventEmitter {
2297
3036
  private servicePool;
2298
3037
  private shellConfig;
2299
3038
  private localServer?;
2300
- private outboxWatcher?;
3039
+ private evalRunner?;
3040
+ private artifactsWatcher?;
2301
3041
  private memoryWiring?;
3042
+ private runSessionRegistry?;
3043
+ private runCheckpointStore?;
3044
+ private hermesSessionMapper?;
2302
3045
  private assetMetadataIndexes;
2303
3046
  private workspaceMirrors;
2304
3047
  private assetOriginOutbox?;
@@ -2321,10 +3064,21 @@ declare class Runner extends EventEmitter {
2321
3064
  private taskReaperTimer?;
2322
3065
  private skillResyncTimer?;
2323
3066
  private skillSyncInFlight;
3067
+ private resumeInFlightTimer?;
3068
+ private resumeInFlightDone;
2324
3069
  private pendingReplyCache;
2325
3070
  private pendingReplyRecoveryDone;
2326
3071
  constructor(opts?: RunnerOptions);
2327
3072
  start(): Promise<void>;
3073
+ /**
3074
+ * v2.1 §9.5 — build a ProfileResolver backed by the daemon's local
3075
+ * `agent_profiles` mirror. Used by the hook server to translate
3076
+ * `?profile=<name>` query into agentImUserId + workspaceId + role slug
3077
+ * when the run-session registry doesn't yet have the run mapping
3078
+ * (e.g. for the very first pre_llm_call of a session, before the
3079
+ * adapter has had a chance to call register()).
3080
+ */
3081
+ private buildProfileResolver;
2328
3082
  /**
2329
3083
  * F16 (2026-05-20) — enumerate every non-deleted local agent_profile and
2330
3084
  * fan-out `syncInstalledSkillsForDispatch` via `syncAllAgentSkills`.
@@ -2334,6 +3088,62 @@ declare class Runner extends EventEmitter {
2334
3088
  private syncAllSkillsBackground;
2335
3089
  /** F16 — read all live agent_profiles from local DB → AgentProfile[]. */
2336
3090
  private loadAllProfiles;
3091
+ /**
3092
+ * P0-2 (2026-05-25) — daemon cold-start sweep.
3093
+ *
3094
+ * Pulls `IMTaskRun.status='running'` rows where the bound daemon (via
3095
+ * `IMAgentBinding.boundDaemonId`) is this daemon, then re-enqueues each
3096
+ * via the same `onTaskDispatch` handler the ws path uses. Replaces the
3097
+ * slow (~5min) cloud-side `sweepTimedOut()` fallback for pod restarts.
3098
+ *
3099
+ * Idempotent on the daemon side: `onTaskDispatch` dedupes by taskId
3100
+ * against `runningTasks`, so any task that happened to be redispatched
3101
+ * from cloud immediately after our reconnect (via redispatchPending on
3102
+ * the agent.host.declare path) won't double-trigger here.
3103
+ *
3104
+ * Caveat: if the agent was mid-LLM-call when the daemon crashed, the
3105
+ * resumed dispatch starts the call from scratch — token cost duplicated.
3106
+ * We accept that vs the alternative (5min of silence + cloud marks the
3107
+ * run `failed` without any retry).
3108
+ */
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;
3139
+ /**
3140
+ * Rebuild a `task.dispatch.request` payload from an in-flight IMTaskRun
3141
+ * row + its parent IMTask. Mirrors what cloud-side
3142
+ * v19x-helpers.buildTaskDispatchRequest does, with one extra field:
3143
+ * `metadata.resumed = true` so downstream prompt injection can note
3144
+ * this is a recovery dispatch.
3145
+ */
3146
+ private reconstructDispatchPayload;
2337
3147
  stop(): Promise<void>;
2338
3148
  isRunning(): boolean;
2339
3149
  /**
@@ -2424,10 +3234,30 @@ declare class Runner extends EventEmitter {
2424
3234
  * validation logic doesn't trip on an unknown field.
2425
3235
  */
2426
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;
2427
3243
  private onHostAcked;
2428
3244
  private applyHostAckOwnershipLock;
2429
3245
  private onTaskDispatch;
2430
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;
2431
3261
  private findMessageDispatchAgent;
2432
3262
  private postMessageDispatchReply;
2433
3263
  /**
@@ -2447,6 +3277,26 @@ declare class Runner extends EventEmitter {
2447
3277
  private syncProfileFromCloud;
2448
3278
  private resolveOwnedAgent;
2449
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;
2450
3300
  private onAssetChanged;
2451
3301
  private onWorkspaceFileChanged;
2452
3302
  private snapshotAdapterObservability;
@@ -2554,13 +3404,13 @@ declare const CCConfigSchema: z.ZodObject<{
2554
3404
  }, "strip", z.ZodTypeAny, {
2555
3405
  name: string;
2556
3406
  command: string;
2557
- env?: Record<string, string> | undefined;
2558
3407
  args?: string[] | undefined;
3408
+ env?: Record<string, string> | undefined;
2559
3409
  }, {
2560
3410
  name: string;
2561
3411
  command: string;
2562
- env?: Record<string, string> | undefined;
2563
3412
  args?: string[] | undefined;
3413
+ env?: Record<string, string> | undefined;
2564
3414
  }>, "many">>;
2565
3415
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
2566
3416
  maxTurns: z.ZodDefault<z.ZodNumber>;
@@ -2575,8 +3425,8 @@ declare const CCConfigSchema: z.ZodObject<{
2575
3425
  mcpServers?: {
2576
3426
  name: string;
2577
3427
  command: string;
2578
- env?: Record<string, string> | undefined;
2579
3428
  args?: string[] | undefined;
3429
+ env?: Record<string, string> | undefined;
2580
3430
  }[] | undefined;
2581
3431
  systemPrompt?: string | undefined;
2582
3432
  allowedTools?: string[] | undefined;
@@ -2589,8 +3439,8 @@ declare const CCConfigSchema: z.ZodObject<{
2589
3439
  mcpServers?: {
2590
3440
  name: string;
2591
3441
  command: string;
2592
- env?: Record<string, string> | undefined;
2593
3442
  args?: string[] | undefined;
3443
+ env?: Record<string, string> | undefined;
2594
3444
  }[] | undefined;
2595
3445
  systemPrompt?: string | undefined;
2596
3446
  allowedTools?: string[] | undefined;
@@ -2628,20 +3478,59 @@ declare const CodexConfigSchema: z.ZodObject<{
2628
3478
  * scoped key under a different name.
2629
3479
  */
2630
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>;
2631
3514
  }, "strip", z.ZodTypeAny, {
2632
3515
  sandbox: "read-only" | "workspace-write" | "danger-full-access";
2633
3516
  model: string;
3517
+ prismerApiKeyEnv: string;
2634
3518
  cwd: string;
2635
3519
  apiKeyEnv: string;
3520
+ sessionContinuity: boolean;
3521
+ proxyProvider?: string | undefined;
2636
3522
  systemPrompt?: string | undefined;
2637
3523
  envVars?: Record<string, string> | undefined;
2638
3524
  }, {
2639
3525
  cwd: string;
2640
3526
  sandbox?: "read-only" | "workspace-write" | "danger-full-access" | undefined;
2641
3527
  model?: string | undefined;
3528
+ proxyProvider?: string | undefined;
3529
+ prismerApiKeyEnv?: string | undefined;
2642
3530
  systemPrompt?: string | undefined;
2643
- envVars?: Record<string, string> | undefined;
2644
3531
  apiKeyEnv?: string | undefined;
3532
+ envVars?: Record<string, string> | undefined;
3533
+ sessionContinuity?: boolean | undefined;
2645
3534
  }>;
2646
3535
  type CodexConfig = z.infer<typeof CodexConfigSchema>;
2647
3536
  /**