maka-agent 0.2.0-dev.52.20260926 → 0.2.0-dev.53.20260927

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 (71) hide show
  1. package/dist/activation-command.js +11 -3
  2. package/dist/pi-tui-mcp-status.js +73 -5
  3. package/dist/pi-tui-runner.js +1 -1
  4. package/dist/runtime-host-run-command.js +39 -6
  5. package/dist/runtime-host-run-mcp.js +161 -0
  6. package/dist/runtime-host-session-driver.js +22 -2
  7. package/dist/tui-copy-catalog.js +6 -0
  8. package/dist/tui-mcp-control.js +11 -2
  9. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  10. package/node_modules/@maka/core/dist/attachments.js +7 -0
  11. package/node_modules/@maka/core/dist/events.js +11 -0
  12. package/node_modules/@maka/core/dist/provider-registry.js +11 -2
  13. package/node_modules/@maka/core/dist/turn-origin.js +6 -0
  14. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +1 -5
  15. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +80 -24
  16. package/node_modules/@maka/runtime/dist/bots/proxied-fetch.js +5 -4
  17. package/node_modules/@maka/runtime/dist/computer-use-tools.js +136 -100
  18. package/node_modules/@maka/runtime/dist/context-budget-helpers.js +4 -0
  19. package/node_modules/@maka/runtime/dist/conversation-copy.js +51 -205
  20. package/node_modules/@maka/runtime/dist/edit-replace.js +7 -7
  21. package/node_modules/@maka/runtime/dist/filesystem-executor.js +4 -20
  22. package/node_modules/@maka/runtime/dist/filesystem-worker/operations.js +17 -28
  23. package/node_modules/@maka/runtime/dist/format-json.js +39 -0
  24. package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +1 -6
  25. package/node_modules/@maka/runtime/dist/image-file.js +22 -14
  26. package/node_modules/@maka/runtime/dist/model-adapter.js +18 -2
  27. package/node_modules/@maka/runtime/dist/model-history.js +201 -3
  28. package/node_modules/@maka/runtime/dist/network/abortable-connector.js +55 -0
  29. package/node_modules/@maka/runtime/dist/network/proxy-dispatcher.js +72 -37
  30. package/node_modules/@maka/runtime/dist/network/proxy-test.js +1 -1
  31. package/node_modules/@maka/runtime/dist/network/scoped-fetch-transport.js +7 -2
  32. package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +1 -3
  33. package/node_modules/@maka/runtime/dist/provider-error-classification.js +36 -8
  34. package/node_modules/@maka/runtime/dist/recovery-resolver.js +1 -91
  35. package/node_modules/@maka/runtime/dist/runtime-kernel.js +44 -0
  36. package/node_modules/@maka/runtime/dist/session-manager.js +54 -58
  37. package/node_modules/@maka/runtime/dist/subscription-model-fetch.js +84 -2
  38. package/node_modules/@maka/runtime/dist/workers/filesystem-worker.js +63 -51
  39. package/node_modules/@maka/runtime/dist/workspace-executor.js +5 -6
  40. package/node_modules/@maka/runtime-host/dist/adapter/session-projector.js +27 -6
  41. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +4 -1
  42. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +9 -9
  43. package/node_modules/@maka/runtime-host/dist/client/session-catalog-summary.js +9 -1
  44. package/node_modules/@maka/runtime-host/dist/protocol/index.js +12 -1
  45. package/node_modules/@maka/runtime-host/dist/protocol/session-catalog.js +28 -6
  46. package/node_modules/@maka/runtime-host/dist/protocol/turn.js +12 -2
  47. package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +10 -7
  48. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +10 -2
  49. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +2 -0
  50. package/node_modules/@maka/runtime-host/dist/server/interactive-turn-coordinator.js +4 -1
  51. package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +4 -2
  52. package/node_modules/@maka/runtime-host/dist/server/operation-dispatcher.js +4 -0
  53. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +6 -5
  54. package/node_modules/@maka/runtime-host/dist/server/safe-boundary-resume-policy.js +27 -0
  55. package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +5 -3
  56. package/node_modules/@maka/runtime-host/dist/server/session-continuity-coordinator.js +7 -2
  57. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +11 -141
  58. package/node_modules/@maka/runtime-host/dist/server/session-revision-graph-references.js +46 -75
  59. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +18 -2
  60. package/node_modules/@maka/runtime-host/dist/server/workhub-result-coordinator.js +33 -3
  61. package/node_modules/@maka/runtime-host/dist/transport/framed-byte-stream-transport.js +39 -5
  62. package/node_modules/@maka/storage/dist/agent-run-store-contract.js +7 -1
  63. package/node_modules/@maka/storage/dist/artifact-store.js +1 -5
  64. package/node_modules/@maka/storage/dist/artifact-stores.js +0 -3
  65. package/node_modules/@maka/storage/dist/atomic-file-write.js +1 -0
  66. package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +107 -57
  67. package/node_modules/@maka/storage/dist/codex-session-adapter.js +227 -19
  68. package/node_modules/@maka/storage/dist/external-session-importer.js +1 -1
  69. package/node_modules/@maka/storage/dist/mcp-config-store.js +22 -3
  70. package/node_modules/@maka/storage/dist/settings-store.js +281 -13
  71. package/package.json +1 -1
@@ -33,7 +33,7 @@ import { buildToolOperationId } from './runtime-commit-sink.js';
33
33
  import { isContinuationStartRuntimeEvent } from './runtime-event-read-model.js';
34
34
  import { runtimeHandoffPause } from '@maka/core/runtime-handoff';
35
35
  import { buildToolResultArchiveResourceRef, parseToolResultArchiveResourceRef, parseToolResultEventAddress, } from './tool-result-archive-resource.js';
36
- import { deserializeToolResultArchive, isArchivedToolResultPlaceholder, buildLedgerArchivedToolResultPlaceholder, } from './tool-result-archive.js';
36
+ import { isArchivedToolResultPlaceholder, buildLedgerArchivedToolResultPlaceholder, } from './tool-result-archive.js';
37
37
  import { rewriteDurableToolResultProjectionArtifactRefs } from './durable-tool-result-projection.js';
38
38
  import { buildModelProjectionTransition, durableToolResultProjectionDigest, decodeModelProjectionTransition, MODEL_PROJECTION_TRANSITION_EVENT_TYPE, } from '@maka/core/model-projection-transition';
39
39
  import { baseToolResultProjection, decodeLedgerTransition, reduceEffectiveModelProjections, } from './model-projection-transition-ledger.js';
@@ -76,9 +76,6 @@ function collectConversationCopyStorageRefs(input) {
76
76
  addSerialized(event.content.result);
77
77
  }
78
78
  }
79
- for (const serializedResult of input.archivedResults) {
80
- addSerialized(deserializeToolResultArchive(serializedResult));
81
- }
82
79
  return refs;
83
80
  }
84
81
  /** Finds durable Session context references that the exact copy will rewrite. */
@@ -126,7 +123,7 @@ export function createConversationCopySlice(messages, sourceTurnId, boundary) {
126
123
  };
127
124
  }
128
125
  export function rewriteConversationCopyMessage(message, references) {
129
- if (message.type === 'assistant' && references.mode === 'exact') {
126
+ if (message.type === 'assistant') {
130
127
  return {
131
128
  ...message,
132
129
  text: rewriteAttachmentResourceRefs(message.text, references.artifactIds),
@@ -583,9 +580,7 @@ function rewriteReadInput(input, references, clonedEvents) {
583
580
  return input;
584
581
  const path = eventId
585
582
  ? `${prefix}${encodeURIComponent(references.runtimeEventIds.get(eventId) ?? eventId)}`
586
- : rewriteLedgerArchiveText(references.mode === 'exact'
587
- ? rewriteAttachmentResourceRefs(original, references.artifactIds)
588
- : original, references);
583
+ : rewriteLedgerArchiveText(rewriteAttachmentResourceRefs(original, references.artifactIds), references);
589
584
  if (!input.path.startsWith('maka://read/'))
590
585
  return { ...input, path };
591
586
  const url = new URL(input.path);
@@ -673,52 +668,6 @@ async function loadConversationCopyRunEvents(sourceRuns, sourceEvents, copyTurnI
673
668
  ];
674
669
  }));
675
670
  }
676
- export function archivedToolResultContainsConversationOwnedReferences(serializedResult, sourceSessionId, externalChildReferences) {
677
- const value = deserializeToolResultArchive(serializedResult);
678
- if (isArchivedToolResultPlaceholder(value))
679
- return true;
680
- let content;
681
- try {
682
- content = decodePersistedToolResultContent(markPersisted(value));
683
- }
684
- catch {
685
- return false;
686
- }
687
- if (content.kind === 'archived_tool_result')
688
- return true;
689
- if (content.kind === 'image') {
690
- return ((content.ref.kind === 'session_file' || content.ref.kind === 'session_context') &&
691
- content.ref.sessionId === sourceSessionId);
692
- }
693
- if (content.kind === 'subagent') {
694
- const [linked] = conversationCopyLinkedChildReferences(content);
695
- if (linked) {
696
- return !linkedChildReferencesAreExternal(linked, externalChildReferences);
697
- }
698
- return content.runId !== undefined || content.artifactIds.length > 0;
699
- }
700
- if (content.kind === 'agent_swarm') {
701
- if (content.items.some((item) => !item.childSessionId &&
702
- (item.runId !== undefined ||
703
- item.resumedFromRunId !== undefined ||
704
- item.artifactIds.length > 0))) {
705
- return true;
706
- }
707
- return conversationCopyLinkedChildReferences(content).some((linked) => !linkedChildReferencesAreExternal(linked, externalChildReferences));
708
- }
709
- return false;
710
- }
711
- export function archivedToolResultContainsLinkedChildReferences(serializedResult) {
712
- const value = deserializeToolResultArchive(serializedResult);
713
- if (isArchivedToolResultPlaceholder(value))
714
- return false;
715
- try {
716
- return (conversationCopyLinkedChildReferences(decodePersistedToolResultContent(markPersisted(value))).length > 0);
717
- }
718
- catch {
719
- return false;
720
- }
721
- }
722
671
  export function conversationCopyLinkedChildReferences(content) {
723
672
  if (content.kind === 'subagent') {
724
673
  if (!content.childSessionId)
@@ -771,9 +720,6 @@ export function collectConversationCopyLinkedChildReferences(input) {
771
720
  if (event.content?.kind === 'function_response')
772
721
  add(event.content.result);
773
722
  }
774
- for (const serializedResult of input.archivedResults) {
775
- add(deserializeToolResultArchive(serializedResult));
776
- }
777
723
  return references;
778
724
  }
779
725
  /**
@@ -925,31 +871,33 @@ function cloneModelProjectionTransition(event, references, clonedRuntimeEvents,
925
871
  if (!sourceProjection) {
926
872
  throw new Error(`Cannot copy model projection transition ${event.id} onto its target`);
927
873
  }
928
- let rewritten;
874
+ // The copied event already holds the target's rewritten result, so every
875
+ // archive, including a legacy Artifact-backed one, is rebuilt as a ledger
876
+ // archive of that event instead of pointing at the source's archived body.
877
+ const serialized = serializeToolResultProjectionV1(sourceProjection);
878
+ const rewritten = buildLedgerArchivedToolResultPlaceholder({
879
+ storage: 'ledger',
880
+ runtimeEventId: clonedTarget.id,
881
+ toolCallId: placeholder.toolCallId,
882
+ toolName: placeholder.toolName,
883
+ sourceProjectionDigest: durableToolResultProjectionDigest(sourceProjection),
884
+ bodySha256: createHash('sha256').update(serialized).digest('hex'),
885
+ originalBytes: Buffer.byteLength(serialized),
886
+ originalEstimatedTokens: placeholder.originalEstimatedTokens,
887
+ reason: placeholder.reason,
888
+ ...(source.previousTransitionId
889
+ ? {
890
+ previousTransitionId: requiredMappedId(transitionIds, source.previousTransitionId, 'model projection transition'),
891
+ }
892
+ : {}),
893
+ });
894
+ if (placeholder.page) {
895
+ rewritten.page = readToolResultPage(serialized, { path: rewritten.resourceRef }, READ_PAGE_MAX_BYTES - Buffer.byteLength(JSON.stringify(rewritten)) - 32);
896
+ }
897
+ // Earlier Reads of a legacy archive keep naming its copied Artifact.
929
898
  if (placeholder.rewriteVersion === 2) {
930
- const { previousTransitionId: _previous, ...rest } = placeholder;
931
- const serialized = serializeToolResultProjectionV1(sourceProjection);
932
- rewritten = buildLedgerArchivedToolResultPlaceholder({
933
- ...rest,
934
- runtimeEventId: clonedTarget.id,
935
- sourceProjectionDigest: durableToolResultProjectionDigest(sourceProjection),
936
- bodySha256: createHash('sha256').update(serialized).digest('hex'),
937
- originalBytes: Buffer.byteLength(serialized),
938
- ...(source.previousTransitionId
939
- ? {
940
- previousTransitionId: requiredMappedId(transitionIds, source.previousTransitionId, 'model projection transition'),
941
- }
942
- : {}),
943
- });
944
- if (rewritten.page) {
945
- delete rewritten.page;
946
- rewritten.page = readToolResultPage(serialized, { path: rewritten.resourceRef }, READ_PAGE_MAX_BYTES - Buffer.byteLength(JSON.stringify(rewritten)) - 32);
947
- }
948
899
  references.ledgerArchives?.set(placeholder.resourceRef ?? buildToolResultArchiveResourceRef(placeholder), rewritten);
949
900
  }
950
- else {
951
- rewritten = rewriteArchivedToolResult(placeholder, references);
952
- }
953
901
  const transition = buildModelProjectionTransition({
954
902
  sessionId: references.targetSessionId,
955
903
  target: {
@@ -1016,8 +964,6 @@ function requiredMappedId(ids, sourceId, kind) {
1016
964
  return targetId;
1017
965
  }
1018
966
  function rewriteOwnedArtifactId(sourceArtifactId, references) {
1019
- if (references.mode === 'preserve_external')
1020
- return sourceArtifactId;
1021
967
  return rewriteOwnedId(sourceArtifactId, references.artifactIds, 'Artifact');
1022
968
  }
1023
969
  /**
@@ -1032,8 +978,6 @@ function rewriteOwnedArtifactId(sourceArtifactId, references) {
1032
978
  * make a whole Session uncopyable over a byte nothing reads.
1033
979
  */
1034
980
  function reclaimableArtifactReference(sourceArtifactId, references) {
1035
- if (references.mode === 'preserve_external')
1036
- return sourceArtifactId;
1037
981
  return references.artifactIds.get(sourceArtifactId);
1038
982
  }
1039
983
  /** The `captureArtifactId` join, or nothing when its Artifact is gone. */
@@ -1188,9 +1132,7 @@ function rewriteRuntimeEventReferences(event, references) {
1188
1132
  const content = event.content?.kind === 'text'
1189
1133
  ? {
1190
1134
  ...event.content,
1191
- ...(references.mode === 'exact'
1192
- ? { text: rewriteAttachmentResourceRefs(event.content.text, references.artifactIds) }
1193
- : {}),
1135
+ text: rewriteAttachmentResourceRefs(event.content.text, references.artifactIds),
1194
1136
  ...(event.content.attachments
1195
1137
  ? {
1196
1138
  attachments: event.content.attachments.map((attachment) => ({
@@ -1233,11 +1175,7 @@ function rewriteRuntimeEventReferences(event, references) {
1233
1175
  }
1234
1176
  : {}),
1235
1177
  ...(event.refs.artifactId
1236
- ? archivedSnapshotResult(event.refs.artifactId, references) !== undefined
1237
- ? {}
1238
- : {
1239
- artifactId: rewriteOwnedArtifactId(event.refs.artifactId, references),
1240
- }
1178
+ ? { artifactId: rewriteOwnedArtifactId(event.refs.artifactId, references) }
1241
1179
  : {}),
1242
1180
  ...(event.refs.sourceInvocationId
1243
1181
  ? {
@@ -1322,9 +1260,6 @@ function rewriteToolResultContent(content, references) {
1322
1260
  originalBytes: rewritten.originalBytes,
1323
1261
  };
1324
1262
  }
1325
- const snapshot = rewriteArchivedSnapshot(content, references);
1326
- if (snapshot)
1327
- return snapshot;
1328
1263
  return {
1329
1264
  ...content,
1330
1265
  runtimeEventId: rewriteOwnedId(content.runtimeEventId, references.runtimeEventIds, 'RuntimeEvent'),
@@ -1334,56 +1269,45 @@ function rewriteToolResultContent(content, references) {
1334
1269
  };
1335
1270
  }
1336
1271
  if (content.kind === 'json' && isArchivedToolResultPlaceholder(content.value)) {
1337
- const snapshot = rewriteArchivedSnapshot(content.value, references);
1338
- if (snapshot)
1339
- return snapshot;
1340
1272
  return {
1341
1273
  ...content,
1342
1274
  value: rewriteArchivedToolResult(content.value, references),
1343
1275
  };
1344
1276
  }
1345
1277
  if (content.kind === 'subagent') {
1346
- if (linkedChildrenAreSnapshots(references) && content.childSessionId) {
1278
+ const shared = sharedChild(content.childSessionId, references);
1279
+ if (content.childSessionId && !shared) {
1347
1280
  const { childSessionId: _childSessionId, runId: _runId, ...snapshot } = content;
1348
- return {
1349
- ...snapshot,
1350
- artifactIds: rewriteSnapshotArtifactIds(content.artifactIds, references),
1351
- };
1281
+ return { ...snapshot, artifactIds: rewriteArtifactIds(content.artifactIds, references) };
1352
1282
  }
1353
1283
  return {
1354
1284
  ...content,
1355
1285
  ...(content.runId
1356
- ? {
1357
- runId: rewriteLinkedRunId(content.runId, content.childSessionId, references, 'AgentRun'),
1358
- }
1286
+ ? { runId: rewriteLinkedRunId(content.runId, shared, references, 'AgentRun') }
1359
1287
  : {}),
1360
- artifactIds: rewriteLinkedArtifactIds(content.artifactIds, content.childSessionId, references),
1288
+ artifactIds: rewriteLinkedArtifactIds(content.artifactIds, shared, references),
1361
1289
  };
1362
1290
  }
1363
1291
  if (content.kind === 'agent_swarm') {
1364
1292
  return {
1365
1293
  ...content,
1366
1294
  items: content.items.map((item) => {
1367
- if (linkedChildrenAreSnapshots(references) && item.childSessionId) {
1295
+ const shared = sharedChild(item.childSessionId, references);
1296
+ if (item.childSessionId && !shared) {
1368
1297
  const { childSessionId: _childSessionId, runId: _runId, resumedFromRunId: _resumedFromRunId, ...snapshot } = item;
1369
- return {
1370
- ...snapshot,
1371
- artifactIds: rewriteSnapshotArtifactIds(item.artifactIds, references),
1372
- };
1298
+ return { ...snapshot, artifactIds: rewriteArtifactIds(item.artifactIds, references) };
1373
1299
  }
1374
1300
  return {
1375
1301
  ...item,
1376
1302
  ...(item.runId
1377
- ? {
1378
- runId: rewriteLinkedRunId(item.runId, item.childSessionId, references, 'AgentRun'),
1379
- }
1303
+ ? { runId: rewriteLinkedRunId(item.runId, shared, references, 'AgentRun') }
1380
1304
  : {}),
1381
1305
  ...(item.resumedFromRunId
1382
1306
  ? {
1383
- resumedFromRunId: rewriteLinkedRunId(item.resumedFromRunId, item.childSessionId, references, 'resumed AgentRun'),
1307
+ resumedFromRunId: rewriteLinkedRunId(item.resumedFromRunId, shared, references, 'resumed AgentRun'),
1384
1308
  }
1385
1309
  : {}),
1386
- artifactIds: rewriteLinkedArtifactIds(item.artifactIds, item.childSessionId, references),
1310
+ artifactIds: rewriteLinkedArtifactIds(item.artifactIds, shared, references),
1387
1311
  };
1388
1312
  }),
1389
1313
  };
@@ -1391,12 +1315,8 @@ function rewriteToolResultContent(content, references) {
1391
1315
  return content;
1392
1316
  }
1393
1317
  function rewriteRuntimeToolResult(value, references) {
1394
- if (isArchivedToolResultPlaceholder(value)) {
1395
- const snapshot = rewriteArchivedSnapshot(value, references);
1396
- if (snapshot)
1397
- return snapshot;
1318
+ if (isArchivedToolResultPlaceholder(value))
1398
1319
  return rewriteArchivedToolResult(value, references);
1399
- }
1400
1320
  let content;
1401
1321
  try {
1402
1322
  content = decodePersistedToolResultContent(markPersisted(value));
@@ -1412,82 +1332,18 @@ function rewriteArtifactIds(artifactIds, references) {
1412
1332
  return targetArtifactId === undefined ? [] : [targetArtifactId];
1413
1333
  });
1414
1334
  }
1415
- function validatedExternalChildReferences(childSessionId, references) {
1416
- if (references.mode === 'preserve_external')
1417
- return undefined;
1418
- if (references.linkedChildren.mode === 'snapshot')
1419
- return undefined;
1420
- if (references.linkedChildren.mode === 'reject') {
1421
- throw new Error(`Conversation copy cannot retain linked child Session ${childSessionId}`);
1422
- }
1423
- const external = references.linkedChildren.references.get(childSessionId);
1424
- if (!external) {
1425
- throw new Error(`Conversation copy is missing linked child Session ${childSessionId}`);
1426
- }
1427
- return external;
1428
- }
1429
- function linkedChildrenAreSnapshots(references) {
1430
- return references.mode === 'exact' && references.linkedChildren.mode === 'snapshot';
1431
- }
1432
- function rewriteSnapshotArtifactIds(artifactIds, references) {
1433
- if (references.mode !== 'exact' || references.linkedChildren.mode !== 'snapshot') {
1434
- return artifactIds;
1435
- }
1436
- return artifactIds.flatMap((artifactId) => {
1437
- const targetArtifactId = references.artifactIds.get(artifactId);
1438
- return targetArtifactId === undefined ? [] : [targetArtifactId];
1439
- });
1440
- }
1441
- function rewriteArchivedSnapshot(value, references) {
1442
- const serializedResult = archivedSnapshotResult(value.artifactId, references);
1443
- if (serializedResult === undefined)
1444
- return undefined;
1445
- const archived = deserializeToolResultArchive(serializedResult);
1446
- if (isArchivedToolResultPlaceholder(archived)) {
1447
- return unavailableArchivedToolResult(value, references);
1448
- }
1449
- try {
1450
- const decoded = decodePersistedToolResultContent(markPersisted(archived));
1451
- return decoded.kind === 'archived_tool_result'
1452
- ? unavailableArchivedToolResult(value, references)
1453
- : rewriteToolResultContent(decoded, references);
1454
- }
1455
- catch {
1456
- return unavailableArchivedToolResult(value, references);
1457
- }
1335
+ function sharedChild(childSessionId, references) {
1336
+ return childSessionId === undefined ? undefined : references.sharedChildren?.get(childSessionId);
1458
1337
  }
1459
- function archivedSnapshotResult(artifactId, references) {
1460
- if (artifactId === undefined ||
1461
- references.mode !== 'exact' ||
1462
- references.linkedChildren.mode !== 'snapshot') {
1463
- return undefined;
1464
- }
1465
- return references.linkedChildren.archivedResults.get(artifactId);
1338
+ function rewriteLinkedRunId(sourceId, shared, references, kind) {
1339
+ return shared
1340
+ ? preserveExternalId(sourceId, shared.runIds, kind)
1341
+ : rewriteOwnedId(sourceId, references.runIds, kind);
1466
1342
  }
1467
- function unavailableArchivedToolResult(value, references) {
1468
- return {
1469
- kind: 'archived_tool_result',
1470
- status: 'missing',
1471
- runtimeEventId: rewriteOwnedId(value.runtimeEventId, references.runtimeEventIds, 'RuntimeEvent'),
1472
- toolCallId: value.toolCallId,
1473
- toolName: value.toolName,
1474
- originalEstimatedTokens: value.originalEstimatedTokens,
1475
- originalBytes: value.originalBytes,
1476
- rewriteVersion: value.rewriteVersion,
1477
- reason: value.reason,
1478
- };
1479
- }
1480
- function rewriteLinkedRunId(sourceId, childSessionId, references, kind) {
1481
- if (!childSessionId)
1482
- return rewriteOwnedId(sourceId, references.runIds, kind);
1483
- const external = validatedExternalChildReferences(childSessionId, references);
1484
- return external ? preserveExternalId(sourceId, external.runIds, kind) : sourceId;
1485
- }
1486
- function rewriteLinkedArtifactIds(sourceIds, childSessionId, references) {
1487
- if (!childSessionId)
1488
- return rewriteArtifactIds(sourceIds, references);
1489
- const external = validatedExternalChildReferences(childSessionId, references);
1490
- return external ? preserveExternalIds(sourceIds, external.artifactIds, 'Artifact') : sourceIds;
1343
+ function rewriteLinkedArtifactIds(sourceIds, shared, references) {
1344
+ return shared
1345
+ ? preserveExternalIds(sourceIds, shared.artifactIds, 'Artifact')
1346
+ : rewriteArtifactIds(sourceIds, references);
1491
1347
  }
1492
1348
  function preserveExternalIds(sourceIds, externalIds, kind) {
1493
1349
  return sourceIds.map((sourceId) => preserveExternalId(sourceId, externalIds, kind));
@@ -1498,21 +1354,11 @@ function preserveExternalId(sourceId, externalIds, kind) {
1498
1354
  }
1499
1355
  return sourceId;
1500
1356
  }
1501
- function linkedChildReferencesAreExternal(linked, externalChildReferences) {
1502
- const external = externalChildReferences?.get(linked.childSessionId);
1503
- return (external !== undefined &&
1504
- [linked.runId, linked.resumedFromRunId]
1505
- .filter((id) => !!id)
1506
- .every((runId) => external.runIds.has(runId)) &&
1507
- linked.artifactIds.every((artifactId) => external.artifactIds.has(artifactId)));
1508
- }
1509
1357
  function rewriteStorageRef(ref, references) {
1510
1358
  if ((ref.kind !== 'session_file' && ref.kind !== 'session_context') ||
1511
1359
  ref.sessionId !== references.sourceSessionId) {
1512
1360
  return ref;
1513
1361
  }
1514
- if (references.mode === 'preserve_external')
1515
- return ref;
1516
1362
  if (ref.kind === 'session_context') {
1517
1363
  const refId = references.contextRefs?.get(ref.refId);
1518
1364
  if (!refId)
@@ -90,15 +90,15 @@ export function computeEditedSource(source, oldString, newString, where) {
90
90
  if (oldString === '') {
91
91
  throw new Error(`old_string must not be empty in ${where}`);
92
92
  }
93
- // Exact match first — counted via indexOf so a large file is not split into an
94
- // array of substrings just to count. Short-circuits before any fuzzy work.
95
- const exactCount = countOccurrences(source, oldString);
96
- if (exactCount === 1) {
93
+ // A second starting position already proves ambiguity, including an overlap.
94
+ // Stop there instead of repeatedly scanning long, repetitive snippets.
95
+ const exactIndex = source.indexOf(oldString);
96
+ if (exactIndex !== -1) {
97
+ if (source.indexOf(oldString, exactIndex + 1) !== -1) {
98
+ throw new Error(`old_string is not unique in ${where} (at least 2 matches)`);
99
+ }
97
100
  return finish(source, oldString, newString, 'exact');
98
101
  }
99
- if (exactCount > 1) {
100
- throw new Error(`old_string is not unique in ${where} (${exactCount} matches)`);
101
- }
102
102
  // Exact failed — entering fuzzy territory. Apply fuzzy-only guards up front so
103
103
  // a too-short, binary, or oversized input is rejected before any scanning.
104
104
  if (oldString.trim().length < MIN_FUZZY_OLD_STRING_LENGTH) {
@@ -28,6 +28,7 @@
28
28
  // "full access" stricter than ask mode, which grants :slash_tmp outright (#2083).
29
29
  import { Buffer } from 'node:buffer';
30
30
  import { readPage } from './read-page.js';
31
+ import { formatJsonText } from './format-json.js';
31
32
  import { lstat, realpath, stat } from 'node:fs/promises';
32
33
  import { isAbsolute } from 'node:path';
33
34
  import { ToolOutcomeUnknownError } from '@maka/core/events';
@@ -436,10 +437,7 @@ function createWorkspaceFilesystemExecutor(workspace) {
436
437
  transform: (ctx) => {
437
438
  original = ctx.content ?? '';
438
439
  try {
439
- const value = operation.sortKeys
440
- ? sortKeysDeep(JSON.parse(original))
441
- : JSON.parse(original);
442
- return JSON.stringify(value, null, 2);
440
+ return formatJsonText(original, operation.sortKeys ?? false);
443
441
  }
444
442
  catch (error) {
445
443
  parseError = error instanceof Error ? error.message : 'parse failed';
@@ -480,9 +478,9 @@ function createWorkspaceFilesystemExecutor(workspace) {
480
478
  throw new Error('FormatJson does not support image files.');
481
479
  const original = read.content;
482
480
  const bytesBefore = Buffer.byteLength(original, 'utf8');
483
- let parsed;
481
+ let formatted;
484
482
  try {
485
- parsed = JSON.parse(original);
483
+ formatted = formatJsonText(original, operation.sortKeys ?? false);
486
484
  }
487
485
  catch (error) {
488
486
  return {
@@ -496,8 +494,6 @@ function createWorkspaceFilesystemExecutor(workspace) {
496
494
  changed: false,
497
495
  };
498
496
  }
499
- const value = operation.sortKeys ? sortKeysDeep(parsed) : parsed;
500
- const formatted = JSON.stringify(value, null, 2);
501
497
  const { bytes: bytesAfter } = await workspace.writeFile({
502
498
  cwd,
503
499
  path,
@@ -571,15 +567,3 @@ function assertGlobPatternInScope(pattern, scope) {
571
567
  async function canonicalExistingPath(path) {
572
568
  return await realpath(path).catch(() => path);
573
569
  }
574
- // Object.fromEntries creates own data properties, so special keys like
575
- // "__proto__" are preserved instead of triggering the inherited setter.
576
- function sortKeysDeep(value) {
577
- if (Array.isArray(value))
578
- return value.map(sortKeysDeep);
579
- if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
580
- return Object.fromEntries(Object.keys(value)
581
- .sort()
582
- .map((key) => [key, sortKeysDeep(value[key])]));
583
- }
584
- return value;
585
- }
@@ -27,9 +27,10 @@ import { sandboxBoundaryExpansionAllowsPath } from '@maka/core/sandbox-boundary'
27
27
  import { ApplyPatchRejectedError, applyUpdateToContent, createPatchedFile, } from '../apply-patch-file.js';
28
28
  import { computeEditedSource } from '../edit-replace.js';
29
29
  import { readPage } from '../read-page.js';
30
+ import { formatJsonText } from '../format-json.js';
30
31
  import { createEditUnifiedDiff, createUnifiedDiff } from '../unified-diff.js';
31
32
  import { compareAndDeleteEntry, hostVisibilityAfterWrite, openStableTarget, readModifyWriteThroughHandle, StableWriteFailure, writeThroughHandle, } from '../file-stable-write.js';
32
- import { isSupportedImagePath, readWorkspaceImage } from '../image-file.js';
33
+ import { readWorkspaceFile } from '../image-file.js';
33
34
  import { FILESYSTEM_WORKER_PROTOCOL_VERSION, operationAccess, operationUsesDirectoryEntry, } from './protocol.js';
34
35
  import { isLikelySandboxDenial } from '../sandbox/detect.js';
35
36
  // Canonicalisation must match the sandbox the worker runs in: realpath-based
@@ -60,22 +61,21 @@ export async function executeFilesystemOperation(operation, operationBoundary, d
60
61
  switch (operation.kind) {
61
62
  case 'read': {
62
63
  const path = await resolveExistingAllowed(operation.cwd, operation.path, 'Read', 'read', operationBoundary);
63
- if (isSupportedImagePath(path)) {
64
- try {
65
- const image = await readWorkspaceImage(path);
66
- return {
67
- kind: 'read_image',
68
- base64: Buffer.from(image.bytes).toString('base64'),
69
- mimeType: image.mimeType,
70
- };
71
- }
72
- catch (error) {
73
- throw operationError('filesystem_error', error instanceof Error ? error.message : 'Image could not be read.');
74
- }
64
+ const file = await readWorkspaceFile(path).catch((error) => {
65
+ throw operationError('filesystem_error', error instanceof Error ? error.message : 'File could not be read.');
66
+ });
67
+ if ('bytes' in file) {
68
+ return {
69
+ kind: 'read_image',
70
+ base64: Buffer.from(file.bytes).toString('base64'),
71
+ mimeType: file.mimeType,
72
+ };
75
73
  }
76
- const content = await fs.readFile(path, 'utf8');
77
74
  try {
78
- return { kind: 'read', ...readPage(content, operation, undefined, operation.continuation) };
75
+ return {
76
+ kind: 'read',
77
+ ...readPage(file.content, operation, undefined, operation.continuation),
78
+ };
79
79
  }
80
80
  catch (error) {
81
81
  throw operationError('invalid_request', error instanceof Error
@@ -215,9 +215,9 @@ export async function executeFilesystemOperation(operation, operationBoundary, d
215
215
  try {
216
216
  const original = await handle.readFile('utf8');
217
217
  const bytesBefore = Buffer.byteLength(original, 'utf8');
218
- let parsed;
218
+ let formatted;
219
219
  try {
220
- parsed = JSON.parse(original);
220
+ formatted = formatJsonText(original, operation.sortKeys ?? false);
221
221
  }
222
222
  catch (error) {
223
223
  // Invalid JSON: return the structured failure without writing.
@@ -232,7 +232,6 @@ export async function executeFilesystemOperation(operation, operationBoundary, d
232
232
  changed: false,
233
233
  };
234
234
  }
235
- const formatted = JSON.stringify(operation.sortKeys ? sortKeysDeep(parsed) : parsed, null, 2);
236
235
  if (formatted !== original) {
237
236
  await writeThroughHandle(handle, formatted);
238
237
  }
@@ -316,16 +315,6 @@ class FilesystemOperationError extends Error {
316
315
  function operationError(code, message) {
317
316
  return new FilesystemOperationError(code, message);
318
317
  }
319
- function sortKeysDeep(value) {
320
- if (Array.isArray(value))
321
- return value.map(sortKeysDeep);
322
- if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
323
- return Object.fromEntries(Object.keys(value)
324
- .sort()
325
- .map((key) => [key, sortKeysDeep(value[key])]));
326
- }
327
- return value;
328
- }
329
318
  function normalizeOperationError(error) {
330
319
  if (error instanceof FilesystemOperationError)
331
320
  return error;
@@ -0,0 +1,39 @@
1
+ /*
2
+ * Licensed to the Apache Software Foundation (ASF) under one
3
+ * or more contributor license agreements. See the NOTICE file
4
+ * distributed with this work for additional information
5
+ * regarding copyright ownership. The ASF licenses this file
6
+ * to you under the Apache License, Version 2.0 (the
7
+ * "License"); you may not use this file except in compliance
8
+ * with the License. You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing,
13
+ * software distributed under the License is distributed on an
14
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ * KIND, either express or implied. See the License for the
16
+ * specific language governing permissions and limitations
17
+ * under the License.
18
+ */
19
+ // Supported Node versions provide rawJSON; the ES2022 type library does not.
20
+ const sourceJson = JSON;
21
+ /** Format JSON without converting its numeric literals through binary64. */
22
+ export function formatJsonText(source, sortKeys) {
23
+ const value = JSON.parse(source, (_key, value, context) => {
24
+ if (typeof value === 'number') {
25
+ if (context?.source === undefined)
26
+ throw new Error('JSON number source is unavailable');
27
+ return sourceJson.rawJSON(context.source);
28
+ }
29
+ // Revivers visit children first, so sorting here handles nested objects
30
+ // without traversing (and accidentally expanding) raw numeric values.
31
+ if (sortKeys && value !== null && typeof value === 'object' && !Array.isArray(value)) {
32
+ return Object.fromEntries(Object.keys(value)
33
+ .sort()
34
+ .map((key) => [key, value[key]]));
35
+ }
36
+ return value;
37
+ });
38
+ return JSON.stringify(value, null, 2);
39
+ }
@@ -18,6 +18,7 @@
18
18
  */
19
19
  import { createHash } from 'node:crypto';
20
20
  import { Buffer } from 'node:buffer';
21
+ import { nonEmpty, sha256 } from './context-budget-helpers.js';
21
22
  import { stableStringify } from './request-shape.js';
22
23
  import { findCheckpointSummaryDefect, SECTIONED_SUMMARY_FORMAT, } from './history-compact-summary-validation.js';
23
24
  // v3: coverage identity and the source digest stay pinned on the RAW ledger
@@ -515,12 +516,6 @@ function effectiveDigestEvent(event) {
515
516
  }
516
517
  return { ...event, content: { ...identity, result } };
517
518
  }
518
- function sha256(value) {
519
- return createHash('sha256').update(value).digest('hex');
520
- }
521
- function nonEmpty(value) {
522
- return typeof value === 'string' && value.length > 0;
523
- }
524
519
  function validHistoryCompactProviderState(value) {
525
520
  if (!value || typeof value !== 'object')
526
521
  return false;