maka-agent 0.2.0-dev.23.20260906 → 0.2.0-dev.24.20260907

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 (148) hide show
  1. package/dist/acp/maka-acp-agent.js +2 -1
  2. package/dist/acp/session-configuration.js +143 -0
  3. package/dist/acp/session-registry.js +90 -4
  4. package/dist/cli-core.js +2 -0
  5. package/dist/pi-transcript.js +5 -12
  6. package/dist/pi-tui-runner.js +74 -4
  7. package/dist/runtime-host-cli-context.js +167 -78
  8. package/dist/runtime-host-cli-installation.js +8 -2
  9. package/dist/runtime-host-cli.js +31 -1
  10. package/dist/runtime-host-handoff-surface.js +81 -0
  11. package/dist/runtime-host-installed-update-bootstrap.js +13 -0
  12. package/dist/runtime-host-installed-update-coordinator.js +33 -0
  13. package/dist/runtime-host-lifecycle-transaction.js +9 -1
  14. package/dist/runtime-host-local-handoff.js +37 -4
  15. package/dist/runtime-host-local-managed-activation.js +84 -0
  16. package/dist/runtime-host-local-source-retirement.js +18 -2
  17. package/dist/runtime-host-managed-lifecycle-manager.js +1 -0
  18. package/dist/runtime-host-operator-retirement.js +50 -0
  19. package/dist/runtime-host-service-manager.js +3 -0
  20. package/dist/runtime-host-session-driver.js +4 -25
  21. package/dist/runtime-host-session-update.js +62 -0
  22. package/dist/runtime-host-tui-command.js +38 -73
  23. package/dist/runtime-host-tui-context.js +1 -0
  24. package/dist/runtime-host-tui-owner.js +226 -0
  25. package/dist/tui-copy-catalog.js +140 -3
  26. package/dist/tui-host-owner-copy.js +24 -0
  27. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  28. package/node_modules/@maka/core/dist/canonical-runtime-event.js +3 -1
  29. package/node_modules/@maka/core/dist/model-failure.js +40 -0
  30. package/node_modules/@maka/core/dist/model-metadata.generated.js +4 -4
  31. package/node_modules/@maka/core/dist/model-metadata.js +3 -3
  32. package/node_modules/@maka/core/dist/model-web-search.js +5 -4
  33. package/node_modules/@maka/core/dist/provider-registry.js +45 -4
  34. package/node_modules/@maka/core/dist/record-schema.js +9 -2
  35. package/node_modules/@maka/core/dist/runtime-boundary.js +31 -11
  36. package/node_modules/@maka/core/dist/runtime-event.js +37 -6
  37. package/node_modules/@maka/core/dist/runtime-handoff.js +98 -0
  38. package/node_modules/@maka/core/dist/runtime-invocation.js +1 -1
  39. package/node_modules/@maka/core/dist/runtime-logical-execution.js +112 -0
  40. package/node_modules/@maka/core/dist/session.js +54 -52
  41. package/node_modules/@maka/core/dist/slash-command-catalog.js +2 -0
  42. package/node_modules/@maka/core/dist/tool-result-archive-evidence.js +20 -0
  43. package/node_modules/@maka/core/dist/usage-record-schema.js +26 -35
  44. package/node_modules/@maka/core/package.json +4 -0
  45. package/node_modules/@maka/mcp/dist/index.js +131 -1
  46. package/node_modules/@maka/runtime/dist/agent-run.js +272 -105
  47. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +13 -5
  48. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +109 -34
  49. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +127 -133
  50. package/node_modules/@maka/runtime/dist/context-budget.js +14 -9
  51. package/node_modules/@maka/runtime/dist/conversation-copy.js +5 -4
  52. package/node_modules/@maka/runtime/dist/goal-continuation.js +36 -4
  53. package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +18 -9
  54. package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +30 -22
  55. package/node_modules/@maka/runtime/dist/history-compaction.js +29 -4
  56. package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +106 -0
  57. package/node_modules/@maka/runtime/dist/message-authority.js +9 -0
  58. package/node_modules/@maka/runtime/dist/model-adapter.js +19 -98
  59. package/node_modules/@maka/runtime/dist/model-factory.js +19 -81
  60. package/node_modules/@maka/runtime/dist/model-fetcher.js +7 -0
  61. package/node_modules/@maka/runtime/dist/model-runtime.js +85 -111
  62. package/node_modules/@maka/runtime/dist/native-web-search-tool.js +2 -1
  63. package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +2 -2
  64. package/node_modules/@maka/runtime/dist/opencode-session-header.js +4 -2
  65. package/node_modules/@maka/runtime/dist/provider-error-classification.js +84 -123
  66. package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +68 -108
  67. package/node_modules/@maka/runtime/dist/run-handoff-gate.js +97 -0
  68. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +82 -54
  69. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +117 -159
  70. package/node_modules/@maka/runtime/dist/runtime-kernel.js +150 -112
  71. package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +160 -79
  72. package/node_modules/@maka/runtime/dist/runtime-read-model.js +30 -89
  73. package/node_modules/@maka/runtime/dist/runtime-resume.js +80 -4
  74. package/node_modules/@maka/runtime/dist/session-event-runtime-mapper.js +5 -0
  75. package/node_modules/@maka/runtime/dist/session-manager.js +171 -288
  76. package/node_modules/@maka/runtime/dist/session-projection-helpers.js +0 -27
  77. package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +3 -4
  78. package/node_modules/@maka/runtime/dist/test-connection.js +16 -16
  79. package/node_modules/@maka/runtime/dist/tool-result-archive-encoding.js +38 -0
  80. package/node_modules/@maka/runtime/dist/tool-runtime.js +3 -61
  81. package/node_modules/@maka/runtime/package.json +1 -0
  82. package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +35 -0
  83. package/node_modules/@maka/runtime-host/dist/client/connect-or-spawn.js +9 -1
  84. package/node_modules/@maka/runtime-host/dist/client/connection.js +3 -0
  85. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +156 -0
  86. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +273 -0
  87. package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +26 -5
  88. package/node_modules/@maka/runtime-host/dist/client/index.js +2 -0
  89. package/node_modules/@maka/runtime-host/dist/client/launcher.js +3 -0
  90. package/node_modules/@maka/runtime-host/dist/client/remote-compatibility-error.js +2 -0
  91. package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +27 -5
  92. package/node_modules/@maka/runtime-host/dist/operator/index.js +2 -1
  93. package/node_modules/@maka/runtime-host/dist/operator/retirement-cancellation.js +20 -0
  94. package/node_modules/@maka/runtime-host/dist/protocol/host-status.js +21 -12
  95. package/node_modules/@maka/runtime-host/dist/protocol/index.js +25 -1
  96. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +1 -0
  97. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +40 -20
  98. package/node_modules/@maka/runtime-host/dist/protocol/session-transcript.js +0 -5
  99. package/node_modules/@maka/runtime-host/dist/protocol/session-turns.js +29 -58
  100. package/node_modules/@maka/runtime-host/dist/protocol/turn.js +11 -1
  101. package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +1 -0
  102. package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +19 -4
  103. package/node_modules/@maka/runtime-host/dist/server/connection-session.js +7 -6
  104. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +100 -24
  105. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +5 -5
  106. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +3 -2
  107. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +40 -1
  108. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +96 -17
  109. package/node_modules/@maka/runtime-host/dist/server/host-residency-registry.js +13 -7
  110. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-admission-registry.js +3 -1
  111. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +124 -62
  112. package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +76 -6
  113. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +325 -73
  114. package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +37 -2
  115. package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +45 -3
  116. package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +50 -7
  117. package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +87 -25
  118. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +8 -55
  119. package/node_modules/@maka/runtime-host/dist/server/session-sidecar-purge.js +1 -16
  120. package/node_modules/@maka/runtime-host/dist/server/session-transcript-pager.js +0 -1
  121. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +460 -70
  122. package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +1 -1
  123. package/node_modules/@maka/runtime-host/dist/server/storage-maintenance.js +109 -0
  124. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +0 -1
  125. package/node_modules/@maka/storage/dist/artifact-store.js +21 -10
  126. package/node_modules/@maka/storage/dist/artifact-stores.js +1 -1
  127. package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -4
  128. package/node_modules/@maka/storage/dist/codex-session-adapter.js +0 -2
  129. package/node_modules/@maka/storage/dist/context-offload-snapshot.js +325 -0
  130. package/node_modules/@maka/storage/dist/execution-stores.js +9 -7
  131. package/node_modules/@maka/storage/dist/file-session-repository.js +1012 -0
  132. package/node_modules/@maka/storage/dist/opencode-session-adapter.js +0 -4
  133. package/node_modules/@maka/storage/dist/operational-state-backup.js +9 -5
  134. package/node_modules/@maka/storage/dist/runtime-event-persistence.js +1 -0
  135. package/node_modules/@maka/storage/dist/runtime-transcript-query.js +308 -0
  136. package/node_modules/@maka/storage/dist/session-bundle-policy.js +24 -4
  137. package/node_modules/@maka/storage/dist/session-message-projection.js +15 -0
  138. package/node_modules/@maka/storage/dist/session-repository.js +767 -0
  139. package/node_modules/@maka/storage/dist/session-store.js +25 -99
  140. package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +10 -3
  141. package/node_modules/@maka/storage/dist/sqlite-context-offload-store.js +24 -8
  142. package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +7 -1
  143. package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +44 -1
  144. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +129 -25
  145. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +109 -892
  146. package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +111 -0
  147. package/node_modules/@maka/storage/package.json +2 -0
  148. package/package.json +1 -1
@@ -28,7 +28,7 @@ import { isOrchestrationMode } from '@maka/core/orchestration';
28
28
  import { decodePersistedPermissionMode, isPermissionMode } from '@maka/core/permission';
29
29
  import { isSubagentWorkspaceBinding } from '@maka/core/subagent-workspace';
30
30
  import { isSessionToolProfile, } from '@maka/core/session';
31
- import { isVisibleSessionMessage, lastMessagePreviewForMessages, latestVisibleMessageAt, projectSessionCatalogMessages, } from './session-message-projection.js';
31
+ import { projectSessionCatalogMessages } from './session-message-projection.js';
32
32
  export { projectSessionCatalogMessages };
33
33
  const SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
34
34
  export function isSafeSessionId(sessionId) {
@@ -50,17 +50,6 @@ export class SessionNotFoundError extends Error {
50
50
  export function isSessionNotFoundError(error) {
51
51
  return error instanceof SessionNotFoundError;
52
52
  }
53
- export class SessionReadMarkerMessageNotFoundError extends Error {
54
- sessionId;
55
- messageId;
56
- name = 'SessionReadMarkerMessageNotFoundError';
57
- code = 'session_read_marker_message_not_found';
58
- constructor(sessionId, messageId) {
59
- super(`Session read marker message does not exist: ${messageId}`);
60
- this.sessionId = sessionId;
61
- this.messageId = messageId;
62
- }
63
- }
64
53
  export const EXTERNAL_SESSION_IMPORT_LOOKUP_MAX_SOURCE_IDS = 256;
65
54
  export const EXTERNAL_SESSION_IMPORT_LOOKUP_MAX_RECENT_SESSION_IDS = 16;
66
55
  export function createSessionStore(workspaceRoot) {
@@ -303,6 +292,10 @@ class SqliteSessionStore {
303
292
  await this.ensureReady();
304
293
  return this.metadata.listSandboxBoundaryRestartClosures(sessionId);
305
294
  }
295
+ async hasExplicitSandboxBoundaryDenial(identities) {
296
+ await this.ensureReady();
297
+ return this.metadata.hasExplicitSandboxBoundaryDenial(identities);
298
+ }
306
299
  async settleSandboxBoundaryRequest(input) {
307
300
  await this.ensureReady();
308
301
  return this.metadata.settleSandboxBoundaryRequest(input);
@@ -313,29 +306,9 @@ class SqliteSessionStore {
313
306
  }
314
307
  async list(filter) {
315
308
  await this.ensureReady();
316
- const records = (await this.metadata.list(filter, 'ordinary')).filter((record) => record.header.conversationCopy?.state !== 'preparing');
317
- const withPreviews = [];
318
- for (const record of records) {
319
- const previewMessages = await this.metadata.readPreviewMessages(record.header.id);
320
- withPreviews.push({ record, previewMessages });
321
- }
322
- withPreviews.sort((a, b) => {
323
- const aLastMessageAt = maxTimestamp(a.record.header.lastMessageAt, latestVisibleMessageAt(a.previewMessages));
324
- const bLastMessageAt = maxTimestamp(b.record.header.lastMessageAt, latestVisibleMessageAt(b.previewMessages));
325
- const tsDelta = (bLastMessageAt ?? 0) - (aLastMessageAt ?? 0);
326
- return tsDelta !== 0 ? tsDelta : a.record.header.id.localeCompare(b.record.header.id);
327
- });
328
- const summaries = [];
329
- for (let index = 0; index < withPreviews.length; index += 1) {
330
- const { record, previewMessages } = withPreviews[index];
331
- const { header } = record;
332
- let messages = previewMessages.slice(-10);
333
- if (index < 3) {
334
- messages = (await this.metadata.readMessages(header.id)).slice(-10);
335
- }
336
- summaries.push(toSummary(header, messages));
337
- }
338
- return summaries;
309
+ return (await this.metadata.list(filter, 'ordinary'))
310
+ .filter((record) => record.header.conversationCopy?.state !== 'preparing')
311
+ .map((record) => toCatalogSummary(record.header, record.lastMessagePreview));
339
312
  }
340
313
  async listCatalogPage(filter, cursor, limit, expectedRevision) {
341
314
  await this.ensureCatalogProjectionReadable();
@@ -360,11 +333,7 @@ class SqliteSessionStore {
360
333
  };
361
334
  }
362
335
  async listForRecovery() {
363
- const headers = await this.listHeaders();
364
- for (const header of headers) {
365
- await this.metadata.readMessagesForRecovery(header.id);
366
- }
367
- return headers;
336
+ return this.listHeaders();
368
337
  }
369
338
  async listHeaders() {
370
339
  await this.ensureReady();
@@ -395,34 +364,14 @@ class SqliteSessionStore {
395
364
  await this.ensureReady();
396
365
  return this.metadata.readMessages(sessionId);
397
366
  }
398
- async readTranscriptPageSnapshot(sessionId, request) {
399
- await this.ensureReady();
400
- return this.metadata.readTranscriptPage(sessionId, request);
401
- }
402
367
  async readTranscriptMessagesSnapshot(sessionId, request) {
403
368
  await this.ensureReady();
404
369
  return this.metadata.readTranscriptMessages(sessionId, request);
405
370
  }
406
- async readTranscriptRecordsSnapshot(sessionId, request) {
407
- await this.ensureReady();
408
- return this.metadata.readTranscriptRecords(sessionId, request);
409
- }
410
371
  async readTranscriptHighWaterSnapshot(sessionId) {
411
372
  await this.ensureReady();
412
373
  return this.metadata.readTranscriptHighWater(sessionId);
413
374
  }
414
- async readTurnContributionsSnapshot(sessionId, throughSequence, position, maxContributions) {
415
- await this.ensureReady();
416
- return this.metadata.readTurnContributions(sessionId, throughSequence, position, maxContributions);
417
- }
418
- async readTurnLandmarksSnapshot(sessionId, maxLandmarks) {
419
- await this.ensureReady();
420
- return this.metadata.readTurnLandmarks(sessionId, maxLandmarks);
421
- }
422
- async readMessagesForRecovery(sessionId) {
423
- await this.ensureReady();
424
- return this.metadata.readMessagesForRecovery(sessionId);
425
- }
426
375
  async listTurnsSnapshot(sessionId) {
427
376
  return deriveTurnRecords(await this.readMessagesSnapshot(sessionId));
428
377
  }
@@ -432,6 +381,10 @@ class SqliteSessionStore {
432
381
  async readMessages(sessionId) {
433
382
  return this.readMessagesSnapshot(sessionId);
434
383
  }
384
+ async readMessagesAfter(sessionId, request) {
385
+ await this.ensureReady();
386
+ return this.metadata.readMessagesAfter(sessionId, request);
387
+ }
435
388
  async listTurns(sessionId) {
436
389
  return deriveTurnRecords(await this.readMessages(sessionId));
437
390
  }
@@ -446,6 +399,11 @@ class SqliteSessionStore {
446
399
  for (const listener of this.transcriptChangeListeners)
447
400
  listener(sessionId);
448
401
  }
402
+ /** @see SqliteSessionMetadataStore.commitMessageCatalogProjection */
403
+ async commitMessageCatalogProjection(sessionId, message) {
404
+ await this.ensureReady();
405
+ await this.metadata.commitMessageCatalogProjection(sessionId, message);
406
+ }
449
407
  async commitMessageAdmission(admission) {
450
408
  await this.ensureReady();
451
409
  return this.metadata.commitMessageAdmission(admission);
@@ -503,33 +461,6 @@ class SqliteSessionStore {
503
461
  await this.ensureReady();
504
462
  return projectHeaderSnapshot(await this.metadata.updateSessionConfiguration(sessionId, input));
505
463
  }
506
- async markSessionReadThroughMessage(sessionId, messageId) {
507
- for (let attempt = 0; attempt < 3; attempt += 1) {
508
- const record = await this.readHeaderRecordSnapshot(sessionId);
509
- const messages = await this.readMessagesSnapshot(sessionId);
510
- const visibleMessages = messages.filter(isVisibleSessionMessage);
511
- const targetIndex = visibleMessages.findIndex((message) => message.id === messageId);
512
- if (targetIndex < 0) {
513
- throw new SessionReadMarkerMessageNotFoundError(sessionId, messageId);
514
- }
515
- const currentIndex = record.header.lastReadMessageId === undefined
516
- ? -1
517
- : visibleMessages.findIndex((message) => message.id === record.header.lastReadMessageId);
518
- const hasUnread = targetIndex < visibleMessages.length - 1;
519
- if (targetIndex < currentIndex ||
520
- (targetIndex === currentIndex && record.header.hasUnread === hasUnread)) {
521
- return record;
522
- }
523
- try {
524
- return await this.updateHeaderVersioned(sessionId, { lastReadMessageId: messageId, hasUnread }, record.revision);
525
- }
526
- catch (error) {
527
- if (!(error instanceof SessionMetadataVersionConflictError) || attempt === 2)
528
- throw error;
529
- }
530
- }
531
- throw new Error('Session read marker retry loop did not terminate');
532
- }
533
464
  async probeSessionRemoval(sessionId) {
534
465
  await this.ensureReady();
535
466
  return projectRemovalProbe(await this.metadata.probeRemoval(sessionId));
@@ -678,6 +609,11 @@ function buildSessionHeader(workspaceRoot, input, sessionId = randomUUID(), conv
678
609
  collaborationMode: input.collaborationMode ?? 'agent',
679
610
  orchestrationMode: input.orchestrationMode ?? 'default',
680
611
  ...(input.thinkingLevel !== undefined ? { thinkingLevel: input.thinkingLevel } : {}),
612
+ // Born on the ledger: a Session created here records its execution facts as
613
+ // RuntimeEvents from its first turn, so there is no transcript to convert.
614
+ // Only an imported transcript (staged at 0) and a Session written before
615
+ // this field existed have anything for the converter to do.
616
+ transcriptLedgerVersion: 1,
681
617
  schemaVersion: 1,
682
618
  };
683
619
  assertValidSessionLineage(header);
@@ -886,10 +822,8 @@ function projectStableSessionCreateProbe(probe) {
886
822
  ? { kind: 'existing', record: projectHeaderSnapshot(probe.record) }
887
823
  : probe;
888
824
  }
889
- function toSummary(header, messages = []) {
890
- const preview = lastMessagePreviewForMessages(messages);
891
- const derivedLastMessageAt = latestVisibleMessageAt(messages);
892
- const lastMessageAt = maxTimestamp(header.lastMessageAt, derivedLastMessageAt);
825
+ function toSummary(header) {
826
+ const lastMessageAt = header.lastMessageAt;
893
827
  return {
894
828
  id: header.id,
895
829
  cwd: header.cwd,
@@ -900,7 +834,6 @@ function toSummary(header, messages = []) {
900
834
  labels: header.labels,
901
835
  hasUnread: header.hasUnread,
902
836
  lastMessageAt,
903
- ...(preview ? { lastMessagePreview: preview } : {}),
904
837
  status: header.status,
905
838
  ...(header.blockedReason ? { blockedReason: header.blockedReason } : {}),
906
839
  ...(header.statusUpdatedAt !== undefined ? { statusUpdatedAt: header.statusUpdatedAt } : {}),
@@ -939,13 +872,6 @@ function toCatalogSummary(header, lastMessagePreview) {
939
872
  ...(lastMessagePreview === undefined ? {} : { lastMessagePreview }),
940
873
  };
941
874
  }
942
- function maxTimestamp(left, right) {
943
- if (left === undefined)
944
- return right;
945
- if (right === undefined)
946
- return left;
947
- return Math.max(left, right);
948
- }
949
875
  function normalizeSessionName(name) {
950
876
  return name === 'New Session' ? DEFAULT_SESSION_NAME : name;
951
877
  }
@@ -68,13 +68,20 @@ class SqliteArtifactMetadataRepository {
68
68
  }
69
69
  });
70
70
  }
71
- readUpgradeOrphanPaths() {
71
+ readUpgradeOrphanPaths(after, limit) {
72
72
  this.assertOpen();
73
73
  const rows = this.#lease.database
74
- .prepare('SELECT relative_path FROM artifact_upgrade_orphan_paths ORDER BY relative_path')
75
- .all();
74
+ .prepare(`SELECT relative_path FROM artifact_upgrade_orphan_paths
75
+ WHERE relative_path > ? ORDER BY relative_path LIMIT ?`)
76
+ .all(after, limit);
76
77
  return rows.map((row) => row.relative_path);
77
78
  }
79
+ hasRelativePath(relativePath) {
80
+ this.assertOpen();
81
+ return Boolean(this.#lease.database
82
+ .prepare('SELECT 1 FROM artifact_records WHERE relative_path = ?')
83
+ .get(relativePath));
84
+ }
78
85
  forgetUpgradeOrphanPaths(relativePaths) {
79
86
  this.assertOpen();
80
87
  this.#lease.transaction('write', () => {
@@ -253,7 +253,7 @@ export class SqliteContextOffloadStore {
253
253
  return this.#runManagedValueMutation(async () => {
254
254
  this.#assertOpen();
255
255
  if (this.#hasPendingFileDeletions()) {
256
- await this.#drainPendingFileDeletions(input.maxBlobs);
256
+ await this.#drainPendingFileDeletions(input.maxBlobs, input.maxBytes);
257
257
  return {
258
258
  deletedBlobs: 0,
259
259
  deletedBytes: 0,
@@ -262,7 +262,7 @@ export class SqliteContextOffloadStore {
262
262
  }
263
263
  const collected = this.#writeTransaction(() => {
264
264
  const rows = this.#database
265
- .prepare(`SELECT c.blob_id, b.size_bytes, b.storage_kind, b.payload
265
+ .prepare(`SELECT c.blob_id, b.size_bytes, b.storage_kind
266
266
  FROM context_gc_candidates c INDEXED BY context_gc_candidates_eligible
267
267
  JOIN context_blobs b ON b.blob_id = c.blob_id
268
268
  WHERE c.unreferenced_at < ?
@@ -272,6 +272,8 @@ export class SqliteContextOffloadStore {
272
272
  const selected = [];
273
273
  let deletedBytes = 0;
274
274
  let inlineDeletedBytes = 0;
275
+ // Admit by metadata before SQLite materializes legacy inline BLOBs.
276
+ const readValue = this.#database.prepare('SELECT storage_kind, size_bytes, payload FROM context_blobs WHERE blob_id = ?');
275
277
  for (const row of rows) {
276
278
  if (selected.length === input.maxBlobs)
277
279
  break;
@@ -279,15 +281,21 @@ export class SqliteContextOffloadStore {
279
281
  if (!blobId || !isNonNegativeSafeInteger(row.size_bytes)) {
280
282
  throw new Error('Invalid context garbage candidate');
281
283
  }
282
- const value = decodeBlobValue(row, Buffer.from(blobId).toString('hex'));
283
- if (!value)
284
- throw new Error('Invalid context garbage candidate value');
285
284
  if (exceedsLimit(deletedBytes, row.size_bytes, input.maxBytes)) {
286
285
  if (selected.length === 0) {
287
286
  throw new Error(`Context garbage byte limit ${input.maxBytes} cannot fit eligible blob of ${row.size_bytes} bytes`);
288
287
  }
289
288
  break;
290
289
  }
290
+ const stored = readValue.get(blobId);
291
+ if (!stored ||
292
+ stored.size_bytes !== row.size_bytes ||
293
+ stored.storage_kind !== row.storage_kind) {
294
+ throw new Error('Invalid context garbage candidate metadata');
295
+ }
296
+ const value = decodeBlobValue(stored, Buffer.from(blobId).toString('hex'));
297
+ if (!value)
298
+ throw new Error('Invalid context garbage candidate value');
291
299
  deletedBytes = addSafeInteger(deletedBytes, row.size_bytes, 'Collected context bytes');
292
300
  selected.push({
293
301
  blobId,
@@ -329,7 +337,7 @@ export class SqliteContextOffloadStore {
329
337
  hasMore: rows.length > selected.length,
330
338
  };
331
339
  });
332
- await this.#drainPendingFileDeletions(input.maxBlobs);
340
+ await this.#drainPendingFileDeletions(input.maxBlobs, input.maxBytes);
333
341
  return {
334
342
  ...collected,
335
343
  hasMore: collected.hasMore || this.#hasPendingFileDeletions(),
@@ -714,11 +722,19 @@ export class SqliteContextOffloadStore {
714
722
  }
715
723
  });
716
724
  }
717
- async #drainPendingFileDeletions(limit) {
725
+ async #drainPendingFileDeletions(limit, maxBytes) {
718
726
  const rows = this.#database
719
- .prepare('SELECT locator FROM context_file_deletions ORDER BY enqueued_at, locator LIMIT ?')
727
+ .prepare('SELECT locator, size_bytes FROM context_file_deletions ORDER BY enqueued_at, locator LIMIT ?')
720
728
  .all(limit);
729
+ let bytes = 0;
721
730
  for (const row of rows) {
731
+ const size = readNonNegativeInteger(row.size_bytes, 'Pending context file deletion bytes');
732
+ if (exceedsLimit(bytes, size, maxBytes)) {
733
+ if (bytes === 0)
734
+ throw new Error('Context garbage byte limit cannot fit pending file');
735
+ break;
736
+ }
737
+ bytes += size;
722
738
  const locator = decodeManagedFileLocator(row.locator);
723
739
  if (!locator)
724
740
  throw new Error('Invalid pending context file deletion locator');
@@ -16,7 +16,8 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- export const SQLITE_CORE_EXECUTION_SCHEMA_VERSION = 8;
19
+ export const SQLITE_CORE_EXECUTION_SCHEMA_VERSION = 9;
20
+ export const MODEL_PROJECTION_TARGET_SQL = "CASE WHEN json_valid(record_json) THEN CASE WHEN json_type(record_json, '$.data.transition.target.runtimeEventId') = 'text' THEN nullif(json_extract(record_json, '$.data.transition.target.runtimeEventId'), '') WHEN json_type(record_json, '$.data.runtimeEventId') = 'text' THEN nullif(json_extract(record_json, '$.data.runtimeEventId'), '') END END";
20
21
  export function migrateSqliteCoreExecutionDatabase(db) {
21
22
  db.exec(`
22
23
  CREATE TABLE IF NOT EXISTS core_agent_runs (
@@ -50,6 +51,11 @@ export function migrateSqliteCoreExecutionDatabase(db) {
50
51
  CREATE INDEX IF NOT EXISTS core_agent_run_events_type_sequence
51
52
  ON core_agent_run_events(event_type, session_id, run_id, sequence);
52
53
 
54
+ CREATE INDEX IF NOT EXISTS core_model_projection_target
55
+ ON core_agent_run_events(session_id,
56
+ ${MODEL_PROJECTION_TARGET_SQL}
57
+ ) WHERE event_type = 'model_projection_transition_recorded';
58
+
53
59
  CREATE TABLE IF NOT EXISTS core_agent_run_projections (
54
60
  session_id TEXT NOT NULL,
55
61
  event_type TEXT NOT NULL,
@@ -18,8 +18,9 @@
18
18
  */
19
19
  import { decodePersistedLegacyRunHeader, invocationOpeningFromLegacyRunHeader, } from './legacy-run-header.js';
20
20
  import { encodeCanonicalRuntimeEvent } from '@maka/core/canonical-runtime-event';
21
+ import { TERMINAL_RUNTIME_EVENT_SQL } from './runtime-transcript-query.js';
21
22
  import { buildInvocationOpenedEvent, buildSyntheticTerminalRuntimeEvent, } from '@maka/core/runtime-invocation';
22
- export const SQLITE_RUNTIME_SCHEMA_VERSION = 16;
23
+ export const SQLITE_RUNTIME_SCHEMA_VERSION = 18;
23
24
  export const RUNTIME_RECOVERY_AUTHORITY_CAPABILITY = 'runtime_recovery_authority';
24
25
  export const RUNTIME_RECOVERY_AUTHORITY_CAPABILITY_VERSION = 1;
25
26
  export const RUNTIME_CONTINUATION_AUTHORITY_CAPABILITY = 'runtime_continuation_authority';
@@ -567,6 +568,48 @@ const MIGRATIONS = new Map([
567
568
  ALTER TABLE runtime_continuation_claims_v16 RENAME TO runtime_continuation_claims;
568
569
  `,
569
570
  ],
571
+ [
572
+ 17,
573
+ `
574
+ -- Handoff replaces a physical attempt, not the admitted logical Turn.
575
+ -- Keep physical identities and each source boundary exclusive.
576
+ CREATE TABLE runtime_continuation_claims_v17 (
577
+ claim_id TEXT PRIMARY KEY,
578
+ source_session_id TEXT NOT NULL,
579
+ source_invocation_id TEXT NOT NULL,
580
+ source_run_id TEXT NOT NULL,
581
+ source_turn_id TEXT NOT NULL,
582
+ source_event_high_water INTEGER NOT NULL CHECK (source_event_high_water > 0),
583
+ source_prefix_digest TEXT NOT NULL,
584
+ boundary_digest TEXT NOT NULL UNIQUE,
585
+ boundary_json TEXT NOT NULL,
586
+ provider_projection_version INTEGER NOT NULL CHECK (provider_projection_version IN (1, 2)),
587
+ provider_replay_digest TEXT NOT NULL,
588
+ target_session_id TEXT NOT NULL,
589
+ target_invocation_id TEXT NOT NULL UNIQUE,
590
+ target_run_id TEXT NOT NULL UNIQUE,
591
+ target_turn_id TEXT NOT NULL,
592
+ target_opening_json TEXT NOT NULL,
593
+ claimed_at INTEGER NOT NULL,
594
+ start_event_id TEXT UNIQUE REFERENCES runtime_events(event_id) ON DELETE CASCADE,
595
+ start_kind TEXT CHECK (start_kind IS NULL OR start_kind IN ('runtime_admission', 'claim_repair')),
596
+ protocol_version INTEGER NOT NULL CHECK (protocol_version = 1),
597
+ UNIQUE (source_session_id, source_run_id, source_event_high_water, source_prefix_digest)
598
+ );
599
+ INSERT INTO runtime_continuation_claims_v17 SELECT * FROM runtime_continuation_claims;
600
+ DROP TABLE runtime_continuation_claims;
601
+ ALTER TABLE runtime_continuation_claims_v17 RENAME TO runtime_continuation_claims;
602
+ CREATE UNIQUE INDEX runtime_continuation_fresh_turn
603
+ ON runtime_continuation_claims(target_session_id, target_turn_id)
604
+ WHERE json_extract(target_opening_json, '$.source.kind') <> 'handoff';
605
+ `,
606
+ ],
607
+ [
608
+ 18,
609
+ `
610
+ CREATE INDEX IF NOT EXISTS runtime_events_terminal ON runtime_events(invocation_id, event_seq) WHERE ${TERMINAL_RUNTIME_EVENT_SQL};
611
+ `,
612
+ ],
570
613
  ]);
571
614
  /**
572
615
  * Data migrations that a SQL statement cannot express, applied inside the same