@tt-a1i/hive 2.0.1 → 2.1.0

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 (147) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.en.md +15 -6
  3. package/README.md +26 -4
  4. package/dist/src/cli/hive.d.ts +4 -0
  5. package/dist/src/cli/hive.js +25 -3
  6. package/dist/src/cli/team.d.ts +8 -1
  7. package/dist/src/cli/team.js +111 -11
  8. package/dist/src/server/action-center-summary.d.ts +193 -0
  9. package/dist/src/server/action-center-summary.js +188 -0
  10. package/dist/src/server/agent-command-resolver.d.ts +6 -0
  11. package/dist/src/server/agent-command-resolver.js +16 -0
  12. package/dist/src/server/agent-manager.js +11 -1
  13. package/dist/src/server/agent-run-starter.js +47 -6
  14. package/dist/src/server/agent-runtime-types.d.ts +4 -0
  15. package/dist/src/server/agent-startup-instructions.d.ts +4 -0
  16. package/dist/src/server/agent-startup-instructions.js +35 -9
  17. package/dist/src/server/agent-stdin-dispatcher.js +17 -9
  18. package/dist/src/server/diagnostics-support-bundle.d.ts +288 -0
  19. package/dist/src/server/diagnostics-support-bundle.js +179 -0
  20. package/dist/src/server/dispatch-ledger-store.d.ts +4 -1
  21. package/dist/src/server/dispatch-ledger-store.js +46 -6
  22. package/dist/src/server/hive-envelope-escape.d.ts +2 -0
  23. package/dist/src/server/hive-envelope-escape.js +2 -0
  24. package/dist/src/server/hive-team-guidance.d.ts +1 -1
  25. package/dist/src/server/hive-team-guidance.js +67 -25
  26. package/dist/src/server/message-log-store.d.ts +1 -1
  27. package/dist/src/server/post-start-input-writer.js +8 -2
  28. package/dist/src/server/preset-launch-support.d.ts +2 -0
  29. package/dist/src/server/preset-launch-support.js +65 -2
  30. package/dist/src/server/protocol-event-stats.d.ts +39 -0
  31. package/dist/src/server/protocol-event-stats.js +84 -0
  32. package/dist/src/server/recovery-summary.js +19 -14
  33. package/dist/src/server/role-template-store.d.ts +1 -1
  34. package/dist/src/server/role-templates.d.ts +1 -0
  35. package/dist/src/server/role-templates.js +43 -29
  36. package/dist/src/server/routes-action-center.d.ts +2 -0
  37. package/dist/src/server/routes-action-center.js +37 -0
  38. package/dist/src/server/routes-diagnostics.d.ts +2 -0
  39. package/dist/src/server/routes-diagnostics.js +17 -0
  40. package/dist/src/server/routes-scenarios.d.ts +25 -0
  41. package/dist/src/server/routes-scenarios.js +89 -0
  42. package/dist/src/server/routes-settings.js +2 -11
  43. package/dist/src/server/routes-team-memory.js +52 -0
  44. package/dist/src/server/routes-team.js +40 -20
  45. package/dist/src/server/routes-workspace-memory-dreams.js +8 -0
  46. package/dist/src/server/routes-workspace-uploads.d.ts +2 -0
  47. package/dist/src/server/routes-workspace-uploads.js +154 -0
  48. package/dist/src/server/routes-workspaces.js +29 -3
  49. package/dist/src/server/routes.js +8 -0
  50. package/dist/src/server/runtime-message-builders.d.ts +0 -1
  51. package/dist/src/server/runtime-message-builders.js +0 -8
  52. package/dist/src/server/runtime-store-contract.d.ts +15 -0
  53. package/dist/src/server/runtime-store-dream.d.ts +14 -1
  54. package/dist/src/server/runtime-store-dream.js +49 -1
  55. package/dist/src/server/runtime-store-helpers.d.ts +7 -0
  56. package/dist/src/server/runtime-store-helpers.js +85 -22
  57. package/dist/src/server/runtime-store-worker-mutations.d.ts +11 -0
  58. package/dist/src/server/runtime-store-worker-mutations.js +46 -0
  59. package/dist/src/server/runtime-store-workflows.js +10 -6
  60. package/dist/src/server/runtime-store.js +34 -42
  61. package/dist/src/server/scenario-presets.d.ts +25 -0
  62. package/dist/src/server/scenario-presets.js +35 -0
  63. package/dist/src/server/sentinel-heartbeat.d.ts +30 -0
  64. package/dist/src/server/sentinel-heartbeat.js +145 -0
  65. package/dist/src/server/spawn-cli-resolver.d.ts +37 -0
  66. package/dist/src/server/spawn-cli-resolver.js +70 -0
  67. package/dist/src/server/spawn-worker-defaults.d.ts +13 -0
  68. package/dist/src/server/spawn-worker-defaults.js +45 -0
  69. package/dist/src/server/sqlite-schema-v32.d.ts +2 -0
  70. package/dist/src/server/sqlite-schema-v32.js +17 -0
  71. package/dist/src/server/sqlite-schema-v33.d.ts +3 -0
  72. package/dist/src/server/sqlite-schema-v33.js +18 -0
  73. package/dist/src/server/sqlite-schema-v34.d.ts +11 -0
  74. package/dist/src/server/sqlite-schema-v34.js +19 -0
  75. package/dist/src/server/sqlite-schema-v35.d.ts +3 -0
  76. package/dist/src/server/sqlite-schema-v35.js +23 -0
  77. package/dist/src/server/sqlite-schema.d.ts +1 -1
  78. package/dist/src/server/sqlite-schema.js +35 -1
  79. package/dist/src/server/system-message.d.ts +5 -2
  80. package/dist/src/server/system-message.js +5 -2
  81. package/dist/src/server/tasks-file-watcher.d.ts +8 -0
  82. package/dist/src/server/tasks-file-watcher.js +31 -2
  83. package/dist/src/server/team-authz.d.ts +9 -1
  84. package/dist/src/server/team-authz.js +24 -0
  85. package/dist/src/server/team-list-serializer.d.ts +2 -2
  86. package/dist/src/server/team-list-serializer.js +2 -1
  87. package/dist/src/server/team-memory-digest.js +4 -4
  88. package/dist/src/server/team-memory-dream-applier.js +24 -3
  89. package/dist/src/server/team-memory-dream-prompt.d.ts +13 -0
  90. package/dist/src/server/team-memory-dream-prompt.js +91 -0
  91. package/dist/src/server/team-memory-dream-run-store.d.ts +2 -0
  92. package/dist/src/server/team-memory-dream-run-store.js +14 -4
  93. package/dist/src/server/team-memory-dream-runner.d.ts +2 -21
  94. package/dist/src/server/team-memory-dream-runner.js +3 -148
  95. package/dist/src/server/team-memory-dream-store.d.ts +1 -1
  96. package/dist/src/server/team-memory-dream-store.js +1 -1
  97. package/dist/src/server/team-operations.d.ts +18 -2
  98. package/dist/src/server/team-operations.js +222 -33
  99. package/dist/src/server/team-recap.d.ts +10 -0
  100. package/dist/src/server/team-recap.js +73 -0
  101. package/dist/src/server/terminal-input-profile.js +95 -6
  102. package/dist/src/server/upload-limits.d.ts +2 -0
  103. package/dist/src/server/upload-limits.js +2 -0
  104. package/dist/src/server/workflow-cli-policy.d.ts +7 -2
  105. package/dist/src/server/workflow-cli-policy.js +15 -3
  106. package/dist/src/server/workflow-run-store.d.ts +1 -0
  107. package/dist/src/server/workflow-run-store.js +11 -1
  108. package/dist/src/server/workflow-runner.d.ts +4 -1
  109. package/dist/src/server/workflow-runner.js +418 -118
  110. package/dist/src/server/workflow-script-loader.d.ts +3 -2
  111. package/dist/src/server/workflow-script-loader.js +161 -0
  112. package/dist/src/server/workspace-store-contract.d.ts +2 -0
  113. package/dist/src/server/workspace-store.d.ts +1 -1
  114. package/dist/src/server/workspace-store.js +40 -30
  115. package/dist/src/server/workspace-upload-store.d.ts +40 -0
  116. package/dist/src/server/workspace-upload-store.js +295 -0
  117. package/dist/src/shared/scenario-presets.d.ts +32 -0
  118. package/dist/src/shared/scenario-presets.js +69 -0
  119. package/dist/src/shared/types.d.ts +12 -1
  120. package/package.json +1 -1
  121. package/web/dist/assets/AddWorkerDialog-DBLhwb91.js +2 -0
  122. package/web/dist/assets/AddWorkspaceFlow-cxvhVAsT.js +1 -0
  123. package/web/dist/assets/FirstRunWizard-DlEPnWWw.js +1 -0
  124. package/web/dist/assets/{MarketplaceDrawer-BFfGT8hH.js → MarketplaceDrawer-CfSiRi8e.js} +11 -11
  125. package/web/dist/assets/TaskGraphDrawer-C2JufcPs.js +1 -0
  126. package/web/dist/assets/WhatsNewDialog-vP7buLos.js +1 -0
  127. package/web/dist/assets/WorkerModal-CSorwcdP.js +1 -0
  128. package/web/dist/assets/{WorkflowsDrawer-CiIdHS6_.js → WorkflowsDrawer-BXS3w9Uq.js} +1 -1
  129. package/web/dist/assets/WorkspaceMemoryDrawer-D71ivohr.js +1 -0
  130. package/web/dist/assets/{WorkspaceTaskDrawer-CyhhEB1Z.js → WorkspaceTaskDrawer-CGCTSHKa.js} +1 -1
  131. package/web/dist/assets/index-BcwN8cCw.js +79 -0
  132. package/web/dist/assets/index-StXTPHls.css +1 -0
  133. package/web/dist/assets/{search-BtRkkEmS.js → search-BZw4T67h.js} +1 -1
  134. package/web/dist/assets/{square-terminal-lEeQUWb3.js → square-terminal-B7E57In1.js} +1 -1
  135. package/web/dist/index.html +2 -2
  136. package/web/dist/sw.js +1 -1
  137. package/dist/src/server/env-sync-message.d.ts +0 -9
  138. package/dist/src/server/env-sync-message.js +0 -29
  139. package/web/dist/assets/AddWorkerDialog-C86CwNgQ.js +0 -2
  140. package/web/dist/assets/AddWorkspaceFlow-Bm2Jz34D.js +0 -1
  141. package/web/dist/assets/FirstRunWizard-XzBoEpA5.js +0 -1
  142. package/web/dist/assets/TaskGraphDrawer-_uVH_0C1.js +0 -1
  143. package/web/dist/assets/WhatsNewDialog-DkJHmkMs.js +0 -1
  144. package/web/dist/assets/WorkerModal-BtMJEOG9.js +0 -1
  145. package/web/dist/assets/WorkspaceMemoryDrawer-C6sNocl_.js +0 -1
  146. package/web/dist/assets/index-BAiLYajK.css +0 -1
  147. package/web/dist/assets/index-K-GG8UwR.js +0 -73
@@ -0,0 +1,288 @@
1
+ import type { RuntimeStore } from './runtime-store.js';
2
+ import type { VersionInfoPayload } from './version-service.js';
3
+ export declare const buildDiagnosticsSupportBundle: (input: {
4
+ now?: number;
5
+ store: RuntimeStore;
6
+ version: VersionInfoPayload;
7
+ }) => {
8
+ app: {
9
+ current_version: string;
10
+ install_hint: string;
11
+ latest_version: string;
12
+ package_name: string;
13
+ update_available: boolean;
14
+ };
15
+ generated_at: number;
16
+ retention: import("./protocol-event-stats.js").RetentionSignals;
17
+ privacy: {
18
+ omitted: string[];
19
+ included_as_metadata_only: string[];
20
+ };
21
+ remote: {
22
+ status: {
23
+ connected: boolean;
24
+ connection: import("./remote-tunnel.js").TunnelStatus;
25
+ enabled: boolean;
26
+ gateway_url: string | null;
27
+ gateway_url_custom: boolean;
28
+ logged_in: boolean;
29
+ };
30
+ devices: {
31
+ active_count: number;
32
+ last_active_at: number | null;
33
+ revoked_count: number;
34
+ total_count: number;
35
+ };
36
+ recent_audit: {
37
+ action: string;
38
+ byte_count: number | null;
39
+ device_id: string | null;
40
+ endpoint: string | null;
41
+ has_preview: boolean;
42
+ id: number;
43
+ reject_reason: string | null;
44
+ result: string;
45
+ ts: number;
46
+ workspace_id: string | null;
47
+ }[];
48
+ };
49
+ runtime: {
50
+ arch: NodeJS.Architecture;
51
+ node_version: string;
52
+ os_release: string;
53
+ platform: NodeJS.Platform;
54
+ };
55
+ schema_version: number;
56
+ workspaces: {
57
+ active_workspace_id: string | null;
58
+ included_count: number;
59
+ items: {
60
+ action_center: {
61
+ attention: Record<string, unknown>[];
62
+ generated_at: number;
63
+ recent_activity: ({
64
+ kind: string;
65
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
66
+ submitted_at: number | null;
67
+ timestamp: number;
68
+ to_agent_id: string;
69
+ to_worker_name: string | null;
70
+ workflow_run_id: string | null;
71
+ label: string | null;
72
+ phase: string | null;
73
+ report_preview: string | null;
74
+ task_preview: string | null;
75
+ has_label?: never;
76
+ has_phase?: never;
77
+ created_at: number;
78
+ id: string;
79
+ } | {
80
+ kind: string;
81
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
82
+ submitted_at: number | null;
83
+ timestamp: number;
84
+ to_agent_id: string;
85
+ to_worker_name: string | null;
86
+ workflow_run_id: string | null;
87
+ has_label: boolean;
88
+ has_phase: boolean;
89
+ label?: never;
90
+ phase?: never;
91
+ report_preview?: never;
92
+ task_preview?: never;
93
+ created_at: number;
94
+ id: string;
95
+ })[];
96
+ summary: {
97
+ idle_workers: number;
98
+ open_dispatches: number;
99
+ recent_reports: number;
100
+ stopped_with_queue: number;
101
+ stopped_workers: number;
102
+ total_workers: number;
103
+ waiting_reports: number;
104
+ working_workers: number;
105
+ };
106
+ workers: ({
107
+ terminal_hint: string | null;
108
+ current_dispatch: {
109
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
110
+ submitted_at: number | null;
111
+ timestamp: number;
112
+ to_agent_id: string;
113
+ to_worker_name: string | null;
114
+ workflow_run_id: string | null;
115
+ label: string | null;
116
+ phase: string | null;
117
+ report_preview: string | null;
118
+ task_preview: string | null;
119
+ has_label?: never;
120
+ has_phase?: never;
121
+ created_at: number;
122
+ id: string;
123
+ } | {
124
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
125
+ submitted_at: number | null;
126
+ timestamp: number;
127
+ to_agent_id: string;
128
+ to_worker_name: string | null;
129
+ workflow_run_id: string | null;
130
+ has_label: boolean;
131
+ has_phase: boolean;
132
+ label?: never;
133
+ phase?: never;
134
+ report_preview?: never;
135
+ task_preview?: never;
136
+ created_at: number;
137
+ id: string;
138
+ } | null;
139
+ id: string;
140
+ latest_report: {
141
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
142
+ submitted_at: number | null;
143
+ timestamp: number;
144
+ to_agent_id: string;
145
+ to_worker_name: string | null;
146
+ workflow_run_id: string | null;
147
+ label: string | null;
148
+ phase: string | null;
149
+ report_preview: string | null;
150
+ task_preview: string | null;
151
+ has_label?: never;
152
+ has_phase?: never;
153
+ created_at: number;
154
+ id: string;
155
+ } | {
156
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
157
+ submitted_at: number | null;
158
+ timestamp: number;
159
+ to_agent_id: string;
160
+ to_worker_name: string | null;
161
+ workflow_run_id: string | null;
162
+ has_label: boolean;
163
+ has_phase: boolean;
164
+ label?: never;
165
+ phase?: never;
166
+ report_preview?: never;
167
+ task_preview?: never;
168
+ created_at: number;
169
+ id: string;
170
+ } | null;
171
+ name: string;
172
+ pending_task_count: number;
173
+ role: import("../shared/types.js").WorkerRole;
174
+ status: "idle" | "working" | "stopped";
175
+ } | {
176
+ terminal_hint?: never;
177
+ current_dispatch: {
178
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
179
+ submitted_at: number | null;
180
+ timestamp: number;
181
+ to_agent_id: string;
182
+ to_worker_name: string | null;
183
+ workflow_run_id: string | null;
184
+ label: string | null;
185
+ phase: string | null;
186
+ report_preview: string | null;
187
+ task_preview: string | null;
188
+ has_label?: never;
189
+ has_phase?: never;
190
+ created_at: number;
191
+ id: string;
192
+ } | {
193
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
194
+ submitted_at: number | null;
195
+ timestamp: number;
196
+ to_agent_id: string;
197
+ to_worker_name: string | null;
198
+ workflow_run_id: string | null;
199
+ has_label: boolean;
200
+ has_phase: boolean;
201
+ label?: never;
202
+ phase?: never;
203
+ report_preview?: never;
204
+ task_preview?: never;
205
+ created_at: number;
206
+ id: string;
207
+ } | null;
208
+ id: string;
209
+ latest_report: {
210
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
211
+ submitted_at: number | null;
212
+ timestamp: number;
213
+ to_agent_id: string;
214
+ to_worker_name: string | null;
215
+ workflow_run_id: string | null;
216
+ label: string | null;
217
+ phase: string | null;
218
+ report_preview: string | null;
219
+ task_preview: string | null;
220
+ has_label?: never;
221
+ has_phase?: never;
222
+ created_at: number;
223
+ id: string;
224
+ } | {
225
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
226
+ submitted_at: number | null;
227
+ timestamp: number;
228
+ to_agent_id: string;
229
+ to_worker_name: string | null;
230
+ workflow_run_id: string | null;
231
+ has_label: boolean;
232
+ has_phase: boolean;
233
+ label?: never;
234
+ phase?: never;
235
+ report_preview?: never;
236
+ task_preview?: never;
237
+ created_at: number;
238
+ id: string;
239
+ } | null;
240
+ name: string;
241
+ pending_task_count: number;
242
+ role: import("../shared/types.js").WorkerRole;
243
+ status: "idle" | "working" | "stopped";
244
+ })[];
245
+ workspace_id: string;
246
+ };
247
+ id: string;
248
+ name: string;
249
+ path: {
250
+ basename: string | null;
251
+ has_parent: boolean;
252
+ path_kind: "windows" | "unknown" | "posix";
253
+ };
254
+ recent_dispatches: {
255
+ artifact_count: number;
256
+ created_at: number;
257
+ from_agent_id: string | null;
258
+ has_label: boolean;
259
+ has_phase: boolean;
260
+ has_report: boolean;
261
+ id: string;
262
+ report_text_length: number;
263
+ reported_at: number | null;
264
+ status: import("./dispatch-ledger-store.js").DispatchStatus;
265
+ submitted_at: number | null;
266
+ task_text_length: number;
267
+ to_agent_id: string;
268
+ to_worker_name: string | null;
269
+ workflow_run_id: string | null;
270
+ }[];
271
+ runs: import("./terminal-input-profile.js").TerminalRunSummary[];
272
+ workers: {
273
+ command_preset_id: string | null;
274
+ ephemeral: boolean;
275
+ has_last_pty_line: boolean;
276
+ id: string;
277
+ name: string;
278
+ pending_task_count: number;
279
+ role: import("../shared/types.js").WorkerRole;
280
+ spawned_by: "workflow" | "orchestrator" | null;
281
+ status: "idle" | "working" | "stopped";
282
+ }[];
283
+ workers_truncated: boolean;
284
+ }[];
285
+ total_count: number;
286
+ truncated: boolean;
287
+ };
288
+ };
@@ -0,0 +1,179 @@
1
+ import { arch, platform, release } from 'node:os';
2
+ import { basename, win32 } from 'node:path';
3
+ import { buildActionCenterSummary } from './action-center-summary.js';
4
+ import { DEFAULT_GATEWAY_URL, REMOTE_DAEMON_TOKEN_KEY, REMOTE_ENABLED_KEY, REMOTE_GATEWAY_URL_KEY, } from './remote-config-keys.js';
5
+ const ACTIVE_WORKSPACE_KEY = 'active_workspace_id';
6
+ const MAX_INCLUDED_WORKSPACES = 5;
7
+ const MAX_WORKERS_PER_WORKSPACE = 20;
8
+ const MAX_RUNS_PER_WORKSPACE = 20;
9
+ const MAX_RECENT_DISPATCHES = 20;
10
+ const MAX_REMOTE_AUDIT = 50;
11
+ const detectPathKind = (workspacePath) => {
12
+ if (/^[a-z]:[\\/]/iu.test(workspacePath) || workspacePath.includes('\\'))
13
+ return 'windows';
14
+ if (workspacePath.startsWith('/'))
15
+ return 'posix';
16
+ return 'unknown';
17
+ };
18
+ const redactWorkspacePath = (workspacePath) => {
19
+ const pathKind = detectPathKind(workspacePath);
20
+ const base = pathKind === 'windows'
21
+ ? win32.basename(workspacePath)
22
+ : basename(workspacePath) || workspacePath;
23
+ const trimmed = workspacePath.replace(/[\\/]+$/u, '');
24
+ const hasParent = pathKind === 'windows' ? trimmed.includes('\\') : trimmed.includes('/');
25
+ return {
26
+ basename: base || null,
27
+ has_parent: hasParent,
28
+ path_kind: pathKind,
29
+ };
30
+ };
31
+ const isLoggedIn = (store) => (store.settings.getAppState(REMOTE_GATEWAY_URL_KEY)?.value ?? null) !== null &&
32
+ (store.settings.getAppState(REMOTE_DAEMON_TOKEN_KEY)?.value ?? null) !== null;
33
+ const buildRemoteSummary = (store) => {
34
+ const devices = store.getRemoteDeviceStore().list(true);
35
+ const activeDevices = devices.filter((device) => device.revokedAt === null);
36
+ const lastActiveValues = devices
37
+ .map((device) => device.lastActive)
38
+ .filter((value) => typeof value === 'number');
39
+ // A self-hosted gateway URL is private infrastructure; the shareable bundle
40
+ // only names the default gateway and otherwise records that a custom one is
41
+ // in use.
42
+ const gatewayUrl = store.settings.getAppState(REMOTE_GATEWAY_URL_KEY)?.value ?? null;
43
+ const gatewayUrlIsCustom = gatewayUrl !== null && gatewayUrl !== DEFAULT_GATEWAY_URL;
44
+ return {
45
+ status: {
46
+ connected: store.getRemoteTunnelStatus() === 'online',
47
+ connection: store.getRemoteTunnelStatus(),
48
+ enabled: store.settings.getAppState(REMOTE_ENABLED_KEY)?.value === 'true',
49
+ gateway_url: gatewayUrlIsCustom ? null : gatewayUrl,
50
+ gateway_url_custom: gatewayUrlIsCustom,
51
+ logged_in: isLoggedIn(store),
52
+ },
53
+ devices: {
54
+ active_count: activeDevices.length,
55
+ last_active_at: lastActiveValues.length > 0 ? Math.max(...lastActiveValues) : null,
56
+ revoked_count: devices.length - activeDevices.length,
57
+ total_count: devices.length,
58
+ },
59
+ recent_audit: store
60
+ .getRemoteAuditStore()
61
+ .list(MAX_REMOTE_AUDIT)
62
+ .map((entry) => ({
63
+ action: entry.action,
64
+ byte_count: entry.byteCount,
65
+ device_id: entry.deviceId,
66
+ endpoint: entry.endpoint,
67
+ has_preview: Boolean(entry.preview),
68
+ id: entry.id,
69
+ reject_reason: entry.rejectReason,
70
+ result: entry.result,
71
+ ts: entry.ts,
72
+ workspace_id: entry.workspaceId,
73
+ })),
74
+ };
75
+ };
76
+ const buildWorkspaceDiagnostics = (store, workspace) => {
77
+ const allWorkers = store.listWorkers(workspace.id);
78
+ const workers = allWorkers.slice(0, MAX_WORKERS_PER_WORKSPACE);
79
+ const workerNameById = new Map(workers.map((worker) => [worker.id, worker.name]));
80
+ const dispatches = store.listRecentDispatches(workspace.id, MAX_RECENT_DISPATCHES);
81
+ return {
82
+ action_center: buildActionCenterSummary({
83
+ includeTextEvidence: false,
84
+ store,
85
+ workspaceId: workspace.id,
86
+ }),
87
+ id: workspace.id,
88
+ name: workspace.name,
89
+ path: redactWorkspacePath(workspace.path),
90
+ recent_dispatches: dispatches.map((dispatch) => ({
91
+ artifact_count: dispatch.artifacts.length,
92
+ created_at: dispatch.createdAt,
93
+ from_agent_id: dispatch.fromAgentId,
94
+ has_label: dispatch.label !== null,
95
+ has_phase: dispatch.phase !== null,
96
+ has_report: Boolean(dispatch.reportText),
97
+ id: dispatch.id,
98
+ report_text_length: dispatch.reportText?.length ?? 0,
99
+ reported_at: dispatch.reportedAt,
100
+ status: dispatch.status,
101
+ submitted_at: dispatch.submittedAt,
102
+ task_text_length: dispatch.text.length,
103
+ to_agent_id: dispatch.toAgentId,
104
+ to_worker_name: workerNameById.get(dispatch.toAgentId) ?? null,
105
+ workflow_run_id: dispatch.workflowRunId,
106
+ })),
107
+ runs: store.listTerminalRuns(workspace.id).slice(0, MAX_RUNS_PER_WORKSPACE),
108
+ workers: workers.map((worker) => ({
109
+ command_preset_id: worker.commandPresetId ??
110
+ store.peekAgentLaunchConfig(workspace.id, worker.id)?.commandPresetId ??
111
+ null,
112
+ ephemeral: worker.ephemeral === true,
113
+ has_last_pty_line: Boolean(store.getLastPtyLineForAgent(workspace.id, worker.id)),
114
+ id: worker.id,
115
+ name: worker.name,
116
+ pending_task_count: worker.pendingTaskCount,
117
+ role: worker.role,
118
+ spawned_by: worker.spawnedBy ?? null,
119
+ status: worker.status,
120
+ })),
121
+ workers_truncated: allWorkers.length > MAX_WORKERS_PER_WORKSPACE,
122
+ };
123
+ };
124
+ export const buildDiagnosticsSupportBundle = (input) => {
125
+ const now = input.now ?? Date.now();
126
+ const workspaces = input.store.listWorkspaces();
127
+ const includedWorkspaces = workspaces.slice(0, MAX_INCLUDED_WORKSPACES);
128
+ return {
129
+ app: {
130
+ current_version: input.version.current_version,
131
+ install_hint: input.version.install_hint,
132
+ latest_version: input.version.latest_version,
133
+ package_name: input.version.package_name,
134
+ update_available: input.version.update_available,
135
+ },
136
+ generated_at: now,
137
+ /* Local-only per-day protocol activity counters (issue #23) — counts only,
138
+ no task text, no names; safe for a shareable bundle. */
139
+ retention: input.store.getRetentionSignals(),
140
+ privacy: {
141
+ omitted: [
142
+ 'tokens',
143
+ 'cookies',
144
+ 'remote_device_keys',
145
+ 'environment_variables',
146
+ 'full_terminal_transcripts',
147
+ 'remote_ws_input_previews',
148
+ 'dispatch_text_previews',
149
+ 'report_text_previews',
150
+ 'last_pty_line_previews',
151
+ 'project_source_files',
152
+ 'full_workspace_paths',
153
+ 'custom_gateway_urls',
154
+ ],
155
+ included_as_metadata_only: [
156
+ 'dispatch_text',
157
+ 'report_text',
158
+ 'last_pty_line',
159
+ 'dispatch_labels',
160
+ 'dispatch_phases',
161
+ ],
162
+ },
163
+ remote: buildRemoteSummary(input.store),
164
+ runtime: {
165
+ arch: arch(),
166
+ node_version: process.version,
167
+ os_release: release(),
168
+ platform: platform(),
169
+ },
170
+ schema_version: 1,
171
+ workspaces: {
172
+ active_workspace_id: input.store.settings.getAppState(ACTIVE_WORKSPACE_KEY)?.value ?? null,
173
+ included_count: includedWorkspaces.length,
174
+ items: includedWorkspaces.map((workspace) => buildWorkspaceDiagnostics(input.store, workspace)),
175
+ total_count: workspaces.length,
176
+ truncated: workspaces.length > includedWorkspaces.length,
177
+ },
178
+ };
179
+ };
@@ -53,16 +53,20 @@ export declare const createDispatchLedgerStore: (db: Database) => {
53
53
  deleteWorkspaceDispatches: (workspaceId: string) => void;
54
54
  findOpenDispatch: (workspaceId: string, toAgentId: string, dispatchId?: string) => DispatchRecord | undefined;
55
55
  findOpenDispatchById: (workspaceId: string, dispatchId: string) => DispatchRecord | undefined;
56
+ claimQueuedDispatch: (dispatchId: string) => boolean;
57
+ reparkClaimedDispatch: (dispatchId: string) => boolean;
56
58
  listOpenDispatchKinds: () => Array<{
57
59
  type: "send";
58
60
  worker_id: string;
59
61
  workspace_id: string;
60
62
  }>;
61
63
  listOpenDispatchIdsForRun: (runId: string) => string[];
64
+ listOpenWorkspaceDispatches: (workspaceId: string) => DispatchRecord[];
62
65
  listOpenWorkflowDispatchesForWorker: (workspaceId: string, workerId: string) => Array<{
63
66
  dispatchId: string;
64
67
  runId: string;
65
68
  }>;
69
+ listRecentWorkspaceDispatches: (workspaceId: string, limit?: number) => DispatchRecord[];
66
70
  listWorkflowRunDispatches: (runId: string) => DispatchRecord[];
67
71
  listWorkspaceDispatches: (workspaceId: string, options?: ListDispatchesOptions) => DispatchRecord[];
68
72
  markCancelled: (input: CancelDispatchInput) => {
@@ -103,6 +107,5 @@ export declare const createDispatchLedgerStore: (db: Database) => {
103
107
  workflowRunId: string | null;
104
108
  workspaceId: string;
105
109
  } | undefined;
106
- markSubmitted: (dispatchId: string) => void;
107
110
  };
108
111
  export {};
@@ -75,11 +75,28 @@ export const createDispatchLedgerStore = (db) => {
75
75
  const deleteDispatch = (dispatchId) => {
76
76
  db.prepare('DELETE FROM dispatches WHERE id = ?').run(dispatchId);
77
77
  };
78
- const markSubmitted = (dispatchId) => {
79
- const submittedAt = Date.now();
80
- db.prepare(`UPDATE dispatches
81
- SET status = ?, submitted_at = ?
82
- WHERE id = ?`).run('submitted', submittedAt, dispatchId);
78
+ /** Atomic claim for delivery: flips queued → submitted only if still
79
+ * queued. Exactly one of N racing deliverers (send path, start replay)
80
+ * wins; the rest skip the PTY write. */
81
+ const claimQueuedDispatch = (dispatchId) => {
82
+ const result = db
83
+ .prepare(`UPDATE dispatches
84
+ SET status = 'submitted', submitted_at = ?
85
+ WHERE id = ? AND status = 'queued'`)
86
+ .run(Date.now(), dispatchId);
87
+ return result.changes === 1;
88
+ };
89
+ /** Inverse of claimQueuedDispatch for replay failures: the write never
90
+ * reached a live PTY (PtyInactive), so the dispatch goes back to parked
91
+ * instead of being cancelled — the next worker start retries it. Only a
92
+ * still-'submitted' row can be reparked (a report/cancel wins). */
93
+ const reparkClaimedDispatch = (dispatchId) => {
94
+ const result = db
95
+ .prepare(`UPDATE dispatches
96
+ SET status = 'queued', submitted_at = NULL
97
+ WHERE id = ? AND status = 'submitted'`)
98
+ .run(dispatchId);
99
+ return result.changes === 1;
83
100
  };
84
101
  const findOpenDispatch = (workspaceId, toAgentId, dispatchId) => {
85
102
  if (dispatchId) {
@@ -175,6 +192,26 @@ export const createDispatchLedgerStore = (db) => {
175
192
  LIMIT ? OFFSET ?`)
176
193
  .all(workspaceId, limit, offset).map(toRecord);
177
194
  };
195
+ const listRecentWorkspaceDispatches = (workspaceId, limit = 100) => {
196
+ const rows = db
197
+ .prepare(`SELECT *
198
+ FROM dispatches
199
+ WHERE workspace_id = ?
200
+ ORDER BY sequence DESC, created_at DESC
201
+ LIMIT ?`)
202
+ .all(workspaceId, limit);
203
+ return rows.map(toRecord);
204
+ };
205
+ const listOpenWorkspaceDispatches = (workspaceId) => {
206
+ const rows = db
207
+ .prepare(`SELECT *
208
+ FROM dispatches
209
+ WHERE workspace_id = ?
210
+ AND status IN ('queued', 'submitted')
211
+ ORDER BY sequence ASC, created_at ASC`)
212
+ .all(workspaceId);
213
+ return rows.map(toRecord);
214
+ };
178
215
  const listOpenDispatchKinds = () => {
179
216
  return db
180
217
  .prepare(`SELECT workspace_id, to_agent_id AS worker_id, 'send' AS type
@@ -229,13 +266,16 @@ export const createDispatchLedgerStore = (db) => {
229
266
  deleteWorkspaceDispatches,
230
267
  findOpenDispatch,
231
268
  findOpenDispatchById,
269
+ claimQueuedDispatch,
270
+ reparkClaimedDispatch,
232
271
  listOpenDispatchKinds,
233
272
  listOpenDispatchIdsForRun,
273
+ listOpenWorkspaceDispatches,
234
274
  listOpenWorkflowDispatchesForWorker,
275
+ listRecentWorkspaceDispatches,
235
276
  listWorkflowRunDispatches,
236
277
  listWorkspaceDispatches,
237
278
  markCancelled,
238
279
  markReportedByWorker,
239
- markSubmitted,
240
280
  };
241
281
  };
@@ -0,0 +1,2 @@
1
+ export declare const escapeHiveEnvelopeText: (value: string) => string;
2
+ export declare const escapeHiveEnvelopeAttribute: (value: string) => string;
@@ -0,0 +1,2 @@
1
+ export const escapeHiveEnvelopeText = (value) => value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
2
+ export const escapeHiveEnvelopeAttribute = (value) => escapeHiveEnvelopeText(value).replaceAll('"', '&quot;').replaceAll("'", '&#39;');
@@ -5,7 +5,7 @@ import { type WorkflowCliPolicy } from './workflow-cli-policy.js';
5
5
  * Tail reminder appended to every message that flows INTO the orchestrator
6
6
  * (worker reports, worker status updates, user chat input). Re-anchors the
7
7
  * role + dispatch syntax after the agent's CLI internally compacts the
8
- * conversation transcript (`/compact` in CC, auto-summarize in Codex, etc.)
8
+ * conversation transcript (manual compaction, auto-summarization, etc.)
9
9
  * and forgets the original startup instructions.
10
10
  *
11
11
  * Format choice (XML envelope, position at message tail, action-menu wording)