@tt-a1i/hive 2.1.6 → 2.1.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 (41) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/src/server/agent-runtime-contract.d.ts +1 -9
  3. package/dist/src/server/agent-runtime.js +1 -7
  4. package/dist/src/server/agent-stdin-dispatcher.d.ts +2 -11
  5. package/dist/src/server/agent-stdin-dispatcher.js +14 -12
  6. package/dist/src/server/hive-team-guidance.js +12 -11
  7. package/dist/src/server/post-start-input-writer.js +1 -1
  8. package/dist/src/server/report-outbox-store.d.ts +10 -8
  9. package/dist/src/server/report-outbox-store.js +10 -1
  10. package/dist/src/server/role-templates.js +8 -4
  11. package/dist/src/server/routes-remote.js +46 -14
  12. package/dist/src/server/routes-team.js +1 -1
  13. package/dist/src/server/routes-workspaces.js +3 -6
  14. package/dist/src/server/runtime-store-contract.d.ts +2 -2
  15. package/dist/src/server/runtime-store-helpers.d.ts +4 -0
  16. package/dist/src/server/runtime-store-helpers.js +34 -11
  17. package/dist/src/server/runtime-store-worker-mutations.js +12 -6
  18. package/dist/src/server/runtime-store-workflows.js +7 -1
  19. package/dist/src/server/team-operations.d.ts +12 -5
  20. package/dist/src/server/team-operations.js +218 -159
  21. package/dist/src/shared/remote-bridge-routing.js +3 -1
  22. package/package.json +1 -1
  23. package/web/dist/assets/{AddWorkerDialog-DFNkbR_Q.js → AddWorkerDialog-Cd53ifv2.js} +2 -2
  24. package/web/dist/assets/{AddWorkspaceFlow-BjpjCuRe.js → AddWorkspaceFlow-3sR25gDy.js} +1 -1
  25. package/web/dist/assets/{FirstRunWizard-BuLgUAny.js → FirstRunWizard-DU8PipxA.js} +1 -1
  26. package/web/dist/assets/{MarketplaceDrawer-BALuhrnd.js → MarketplaceDrawer-BkNcknv0.js} +1 -1
  27. package/web/dist/assets/{TaskGraphDrawer-DQTS6JPI.js → TaskGraphDrawer-9mXNimSE.js} +1 -1
  28. package/web/dist/assets/{WhatsNewDialog-DpgjEIaA.js → WhatsNewDialog-C7awVYub.js} +1 -1
  29. package/web/dist/assets/WorkerModal-BzgrOKzF.js +1 -0
  30. package/web/dist/assets/{WorkflowsDrawer-DPWlZs4S.js → WorkflowsDrawer-C4yjTdY7.js} +1 -1
  31. package/web/dist/assets/{WorkspaceMemoryDrawer-C0vny4zK.js → WorkspaceMemoryDrawer-BlDznlGm.js} +1 -1
  32. package/web/dist/assets/{WorkspaceTaskDrawer-CJcFZh8C.js → WorkspaceTaskDrawer-CpGGZkp3.js} +1 -1
  33. package/web/dist/assets/index-BEyvsWk6.js +84 -0
  34. package/web/dist/assets/index-VHK8pAJq.css +1 -0
  35. package/web/dist/assets/{search-Bl5O-SfR.js → search-Cv0KnMjw.js} +1 -1
  36. package/web/dist/assets/{square-terminal-DCDaflg3.js → square-terminal-BZ7EavxU.js} +1 -1
  37. package/web/dist/index.html +2 -2
  38. package/web/dist/sw.js +1 -1
  39. package/web/dist/assets/WorkerModal-1y-Xdwv-.js +0 -1
  40. package/web/dist/assets/index-CEP_bvOg.css +0 -1
  41. package/web/dist/assets/index-CR1SPGBZ.js +0 -84
@@ -76,6 +76,7 @@ const createWorkspaceUploadStorage = (dataDir) => {
76
76
  };
77
77
  export const createRuntimeStoreServices = (options = {}) => {
78
78
  const db = openRuntimeDatabase(options.dataDir);
79
+ let closing = false;
79
80
  const uploadStorage = createWorkspaceUploadStorage(options.dataDir);
80
81
  const messageLogStore = createMessageLogStore(db);
81
82
  const dispatchLedgerStore = createDispatchLedgerStore(db);
@@ -239,18 +240,24 @@ export const createRuntimeStoreServices = (options = {}) => {
239
240
  // agentRuntime is assigned.
240
241
  function removeWorkerCompletely(workspaceId, workerId) {
241
242
  const activeRun = agentRuntime.getActiveRunByAgentId(workspaceId, workerId);
242
- // Open dispatch rows are about to be hard-deleted — tell their issuers
243
- // first, or parked/in-flight work vanishes silently (review finding).
244
- try {
245
- teamOps.notifyIssuersOfDroppedDispatches(workspaceId, workerId, 'the worker was dismissed');
246
- }
247
- catch (error) {
248
- console.error('[hive] swallowed:removeWorker.notifyDropped', error);
249
- }
243
+ const droppedNoticeTargets = new Set();
250
244
  db.transaction(() => {
245
+ for (const dispatch of dispatchLedgerStore.listWorkspaceDispatches(workspaceId)) {
246
+ if (dispatch.toAgentId === workerId && dispatch.workflowRunId === null) {
247
+ reportOutbox.deletePendingForDispatch(dispatch.id);
248
+ }
249
+ }
250
+ // Open dispatch rows are about to be hard-deleted — queue issuer notices
251
+ // in the same transaction or the delete must not commit.
252
+ for (const targetAgentId of teamOps.notifyIssuersOfDroppedDispatches(workspaceId, workerId, 'the worker was dismissed')) {
253
+ droppedNoticeTargets.add(targetAgentId);
254
+ }
251
255
  dispatchLedgerStore.deleteWorkerDispatches(workspaceId, workerId);
252
256
  workspaceStore.deleteWorker(workspaceId, workerId);
253
257
  })();
258
+ for (const targetAgentId of droppedNoticeTargets) {
259
+ teamOps.drainReportOutbox(workspaceId, targetAgentId);
260
+ }
254
261
  agentRuntime.deleteAgentLaunchConfig(workspaceId, workerId);
255
262
  if (activeRun)
256
263
  agentRuntime.stopAgentRun(activeRun.runId);
@@ -283,6 +290,8 @@ export const createRuntimeStoreServices = (options = {}) => {
283
290
  reparkClaimedDispatch: dispatchLedgerStore.reparkClaimedDispatch,
284
291
  reportOutbox,
285
292
  notifyWebhook: webhookNotifier.notify,
293
+ runDataMutation: (mutation) => db.transaction(mutation)(),
294
+ isRuntimeClosing: () => closing,
286
295
  workflowDispatchAwaiter,
287
296
  workspaceStore,
288
297
  dismissEphemeralWorker: (workspaceId, workerId) => removeWorkerCompletely(workspaceId, workerId),
@@ -296,6 +305,10 @@ export const createRuntimeStoreServices = (options = {}) => {
296
305
  agentRuntime,
297
306
  db,
298
307
  dispatchLedgerStore,
308
+ isRuntimeClosing: () => closing,
309
+ markRuntimeClosing: () => {
310
+ closing = true;
311
+ },
299
312
  messageLogStore,
300
313
  remoteAuditStore,
301
314
  remoteDeviceSessions,
@@ -310,6 +323,7 @@ export const createRuntimeStoreServices = (options = {}) => {
310
323
  teamMemoryDreamScheduler,
311
324
  sentinelHeartbeat,
312
325
  protocolEventStats,
326
+ reportOutbox,
313
327
  teamMemoryDreamStore,
314
328
  teamMemoryDiagnostics,
315
329
  teamMemoryExport,
@@ -345,7 +359,15 @@ export const createRuntimeStoreLifecycle = ({ agentManager, services, }) => {
345
359
  // for orchestrator/workflow pseudo-agents, which never hold queued
346
360
  // worker dispatches addressed to themselves). Wait for post-start
347
361
  // guidance first so startup instructions never race the first task.
348
- const replayQueuedDispatches = () => {
362
+ const deliverPostStartBacklog = () => {
363
+ if (services.isRuntimeClosing())
364
+ return;
365
+ try {
366
+ services.teamOps.drainReportOutbox(workspaceId, agentId);
367
+ }
368
+ catch (error) {
369
+ console.error('[hive] swallowed:startAgent.drainOutbox', error);
370
+ }
349
371
  try {
350
372
  services.teamOps.replayQueuedDispatches(workspaceId, agentId, {
351
373
  createdBeforeMs: run.startedAt,
@@ -356,12 +378,12 @@ export const createRuntimeStoreLifecycle = ({ agentManager, services, }) => {
356
378
  }
357
379
  };
358
380
  if (run.postStartInputReady) {
359
- void run.postStartInputReady.then(replayQueuedDispatches).catch((error) => {
381
+ void run.postStartInputReady.then(deliverPostStartBacklog).catch((error) => {
360
382
  console.error('[hive] swallowed:startAgent.replayAfterPostStart', error);
361
383
  });
362
384
  }
363
385
  else {
364
- replayQueuedDispatches();
386
+ deliverPostStartBacklog();
365
387
  }
366
388
  }
367
389
  return run;
@@ -406,6 +428,7 @@ export const createRuntimeStoreLifecycle = ({ agentManager, services, }) => {
406
428
  };
407
429
  return {
408
430
  close: async () => {
431
+ services.markRuntimeClosing();
409
432
  try {
410
433
  // Fail in-flight workflow awaiters BEFORE their workers vanish, so the
411
434
  // runner's `await agent(...)` rejects with a clear shutdown error
@@ -29,16 +29,22 @@ export const createRuntimeStoreWorkerMutations = ({ addWorker, configureAgentLau
29
29
  },
30
30
  deleteWorker: (workspaceId, workerId) => {
31
31
  const activeRun = services.agentRuntime.getActiveRunByAgentId(workspaceId, workerId);
32
- try {
33
- services.teamOps.notifyIssuersOfDroppedDispatches(workspaceId, workerId, 'the worker was removed');
34
- }
35
- catch (error) {
36
- console.error('[hive] swallowed:deleteWorker.notifyDropped', error);
37
- }
32
+ const droppedNoticeTargets = new Set();
38
33
  runDataMutation(() => {
34
+ for (const dispatch of services.dispatchLedgerStore.listWorkspaceDispatches(workspaceId)) {
35
+ if (dispatch.toAgentId === workerId && dispatch.workflowRunId === null) {
36
+ services.reportOutbox.deletePendingForDispatch(dispatch.id);
37
+ }
38
+ }
39
+ for (const targetAgentId of services.teamOps.notifyIssuersOfDroppedDispatches(workspaceId, workerId, 'the worker was removed')) {
40
+ droppedNoticeTargets.add(targetAgentId);
41
+ }
39
42
  services.dispatchLedgerStore.deleteWorkerDispatches(workspaceId, workerId);
40
43
  services.workspaceStore.deleteWorker(workspaceId, workerId);
41
44
  });
45
+ for (const targetAgentId of droppedNoticeTargets) {
46
+ services.teamOps.drainReportOutbox(workspaceId, targetAgentId);
47
+ }
42
48
  services.agentRuntime.deleteAgentLaunchConfig(workspaceId, workerId);
43
49
  if (activeRun)
44
50
  services.agentRuntime.stopAgentRun(activeRun.runId);
@@ -23,7 +23,13 @@ export const createRuntimeStoreWorkflowRuntime = (services, store) => {
23
23
  return false;
24
24
  services.workspaceStore.markTaskCancelled(workspaceId, openDispatch.toAgentId);
25
25
  try {
26
- services.agentRuntime.writeCancelPrompt(workspaceId, cancelled.toAgentId, cancelled.id, reason);
26
+ void services.agentRuntime
27
+ .writeCancelPrompt(workspaceId, cancelled.toAgentId, cancelled.id, reason, {
28
+ requireActiveRun: true,
29
+ })
30
+ .catch((error) => {
31
+ console.error('[hive] swallowed:workflow.cancelDispatch.forward', error);
32
+ });
27
33
  }
28
34
  catch (error) {
29
35
  console.error('[hive] swallowed:workflow.cancelDispatch.forward', error);
@@ -46,6 +46,10 @@ export interface TeamOperationsInput {
46
46
  reportOutbox: ReportOutboxStore;
47
47
  /** Fire an outbound completion webhook (best-effort) when a worker reports. */
48
48
  notifyWebhook?: (event: WebhookEvent) => void;
49
+ /** Runs durable protocol writes atomically when backed by SQLite. */
50
+ runDataMutation?: (mutation: () => void) => void;
51
+ /** True once runtime shutdown has begun; late async PTY callbacks must not touch SQLite. */
52
+ isRuntimeClosing?: () => boolean;
49
53
  workflowDispatchAwaiter: WorkflowDispatchAwaiter;
50
54
  workspaceStore: WorkspaceStore;
51
55
  /** Auto-dismiss an ephemeral orchestrator-spawned worker after its
@@ -90,20 +94,23 @@ export interface ReportTaskResult {
90
94
  forwarded: boolean;
91
95
  pendingWarning?: string;
92
96
  }
93
- export declare const createTeamOperations: ({ agentRuntime, createDispatch, deleteDispatch, deleteMessage, findOpenDispatch, findOpenDispatchById, listOpenWorkspaceDispatches, insertMessage, markDispatchCancelled, markDispatchReportedByWorker, claimQueuedDispatch, reparkClaimedDispatch, reportOutbox, notifyWebhook, workflowDispatchAwaiter, workspaceStore, dismissEphemeralWorker, recordProtocolEvent, getFlags, }: TeamOperationsInput) => {
94
- cancelTask(workspaceId: string, dispatchId: string, input: CancelTaskInput): {
97
+ export declare const createTeamOperations: ({ agentRuntime, createDispatch, deleteDispatch, deleteMessage, findOpenDispatch, findOpenDispatchById, listOpenWorkspaceDispatches, insertMessage, markDispatchCancelled, markDispatchReportedByWorker, claimQueuedDispatch, reparkClaimedDispatch, reportOutbox, notifyWebhook, runDataMutation, isRuntimeClosing, workflowDispatchAwaiter, workspaceStore, dismissEphemeralWorker, recordProtocolEvent, getFlags, }: TeamOperationsInput) => {
98
+ cancelTask(workspaceId: string, dispatchId: string, input: CancelTaskInput): Promise<{
95
99
  dispatch: DispatchRecord;
96
100
  forwardError: string | null;
97
101
  forwarded: boolean;
98
- };
102
+ }>;
99
103
  dispatchTask: (workspaceId: string, workerId: string, text: string, input?: DispatchTaskInput) => Promise<DispatchRecord>;
100
- drainReportOutbox: (workspaceId: string) => void;
104
+ drainReportOutbox: (workspaceId: string, targetAgentId?: string) => {
105
+ attempted: number;
106
+ firstSyncError: string | null;
107
+ };
101
108
  replayQueuedDispatches: (workspaceId: string, workerId: string, options?: {
102
109
  beforeSequence?: number;
103
110
  createdBeforeMs?: number;
104
111
  excludeDispatchId?: string;
105
112
  }) => void;
106
- notifyIssuersOfDroppedDispatches: (workspaceId: string, workerId: string, reason: string) => void;
113
+ notifyIssuersOfDroppedDispatches: (workspaceId: string, workerId: string, reason: string) => string[];
107
114
  dispatchTaskByWorkerName(workspaceId: string, workerName: string, text: string, input?: DispatchTaskInput): Promise<DispatchRecord & {
108
115
  restartedWorker: boolean;
109
116
  }>;