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

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 (154) hide show
  1. package/README.md +38 -19
  2. package/README.zh-CN.md +34 -19
  3. package/dist/mcp-capability-provider.js +4 -1
  4. package/dist/pi-transcript-tools.js +6 -0
  5. package/dist/pi-tui-layout.js +56 -10
  6. package/dist/pi-tui-mcp-status.js +2 -2
  7. package/dist/pi-tui-pickers.js +121 -30
  8. package/dist/pi-tui-runner.js +156 -42
  9. package/dist/pi-tui-todo.js +221 -0
  10. package/dist/pi-tui-transcript-viewer.js +134 -7
  11. package/dist/runtime-host-cli-context.js +70 -13
  12. package/dist/runtime-host-handoff-surface.js +51 -26
  13. package/dist/runtime-host-local-handoff.js +11 -1
  14. package/dist/runtime-host-service-manager.js +0 -3
  15. package/dist/runtime-host-session-channel.js +13 -0
  16. package/dist/runtime-host-session-driver.js +42 -1
  17. package/dist/tui-autocomplete-layout.js +3 -1
  18. package/dist/tui-copy-catalog.js +85 -6
  19. package/dist/tui-editor-render.js +36 -0
  20. package/dist/tui-mcp-control.js +41 -6
  21. package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
  22. package/node_modules/@maka/core/dist/agent-run.js +1 -0
  23. package/node_modules/@maka/core/dist/attachments.js +3 -0
  24. package/node_modules/@maka/core/dist/canonical-json.js +27 -0
  25. package/node_modules/@maka/core/dist/capabilities.js +35 -0
  26. package/node_modules/@maka/core/dist/computer-use.js +0 -1
  27. package/node_modules/@maka/core/dist/display-redaction.js +18 -0
  28. package/node_modules/@maka/core/dist/llm-connections.js +13 -0
  29. package/node_modules/@maka/core/dist/model-call-attempt.js +2 -0
  30. package/node_modules/@maka/core/dist/model-metadata.js +4 -0
  31. package/node_modules/@maka/core/dist/redaction.js +35 -0
  32. package/node_modules/@maka/core/dist/run-composition.js +77 -2
  33. package/node_modules/@maka/core/dist/runtime-event.js +3 -0
  34. package/node_modules/@maka/core/dist/session.js +57 -6
  35. package/node_modules/@maka/core/dist/slash-command-catalog.js +1 -0
  36. package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
  37. package/node_modules/@maka/core/dist/workhub-action-result.js +68 -0
  38. package/node_modules/@maka/core/package.json +3 -3
  39. package/node_modules/@maka/eval/dist/experiment-directory.js +4 -13
  40. package/node_modules/@maka/eval/dist/toolchain-verification.js +1 -1
  41. package/node_modules/@maka/mcp/dist/form-elicitation.js +213 -0
  42. package/node_modules/@maka/mcp/dist/index.js +337 -71
  43. package/node_modules/@maka/runtime/dist/agent-run-inspect.js +0 -13
  44. package/node_modules/@maka/runtime/dist/agent-run.js +90 -2
  45. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +16 -8
  46. package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +57 -50
  47. package/node_modules/@maka/runtime/dist/archive-read-tool.js +2 -2
  48. package/node_modules/@maka/runtime/dist/context-budget-helpers.js +0 -16
  49. package/node_modules/@maka/runtime/dist/conversation-copy.js +153 -11
  50. package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +3 -3
  51. package/node_modules/@maka/runtime/dist/goal-continuation.js +5 -1
  52. package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +69 -1
  53. package/node_modules/@maka/runtime/dist/mcp-tools.js +7 -2
  54. package/node_modules/@maka/runtime/dist/model-fetcher.js +42 -2
  55. package/node_modules/@maka/runtime/dist/model-history.js +0 -112
  56. package/node_modules/@maka/runtime/dist/plugin-runtime.js +20 -10
  57. package/node_modules/@maka/runtime/dist/plugin-tool-service.js +205 -0
  58. package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +8 -1
  59. package/node_modules/@maka/runtime/dist/request-shape.js +23 -0
  60. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +1 -1
  61. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +24 -1
  62. package/node_modules/@maka/runtime/dist/runtime-kernel.js +127 -13
  63. package/node_modules/@maka/runtime/dist/session-manager.js +20 -36
  64. package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +21 -0
  65. package/node_modules/@maka/runtime/dist/stream-graph-supervisor-tools.js +0 -5
  66. package/node_modules/@maka/runtime/dist/test-connection.js +0 -1
  67. package/node_modules/@maka/runtime/dist/tool-activation-identity.js +41 -0
  68. package/node_modules/@maka/runtime/dist/tool-availability.js +11 -1
  69. package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +63 -1
  70. package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +42 -12
  71. package/node_modules/@maka/runtime/dist/tool-result-archive.js +27 -4
  72. package/node_modules/@maka/runtime/package.json +1 -0
  73. package/node_modules/@maka/runtime-host/dist/client/connection.js +30 -5
  74. package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +52 -13
  75. package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +2 -0
  76. package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +4 -2
  77. package/node_modules/@maka/runtime-host/dist/client/peer-client.js +18 -1
  78. package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +19 -0
  79. package/node_modules/@maka/runtime-host/dist/control/endpoint.js +1 -3
  80. package/node_modules/@maka/runtime-host/dist/node-error.js +22 -0
  81. package/node_modules/@maka/runtime-host/dist/operator/managed-deployment.js +1 -3
  82. package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +0 -1
  83. package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +1 -1
  84. package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +1 -3
  85. package/node_modules/@maka/runtime-host/dist/protocol/index.js +9 -1
  86. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +3 -2
  87. package/node_modules/@maka/runtime-host/dist/protocol/plan.js +1 -0
  88. package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +27 -5
  89. package/node_modules/@maka/runtime-host/dist/protocol/project-catalog.js +2 -2
  90. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -0
  91. package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +86 -157
  92. package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +4 -0
  93. package/node_modules/@maka/runtime-host/dist/server/agent-graph-coordinator.js +0 -3
  94. package/node_modules/@maka/runtime-host/dist/server/canonical-session-projection.js +2 -1
  95. package/node_modules/@maka/runtime-host/dist/server/connection-session.js +28 -8
  96. package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +112 -56
  97. package/node_modules/@maka/runtime-host/dist/server/execution-artifacts.js +32 -32
  98. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +85 -25
  99. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +42 -14
  100. package/node_modules/@maka/runtime-host/dist/server/failure-diagnostic.js +24 -0
  101. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +7 -3
  102. package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -3
  103. package/node_modules/@maka/runtime-host/dist/server/host-session-availability.js +5 -2
  104. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +3 -2
  105. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +34 -4
  106. package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +51 -23
  107. package/node_modules/@maka/runtime-host/dist/server/operation-dispatcher.js +2 -7
  108. package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
  109. package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +6 -0
  110. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +110 -14
  111. package/node_modules/@maka/runtime-host/dist/server/runtime-resource-coordinator.js +11 -8
  112. package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +31 -21
  113. package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +1 -1
  114. package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +20 -8
  115. package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +5 -2
  116. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +4 -0
  117. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +15 -104
  118. package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +3 -0
  119. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +59 -82
  120. package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +132 -139
  121. package/node_modules/@maka/runtime-host/dist/server/workhub-message-attachments.js +46 -0
  122. package/node_modules/@maka/storage/dist/agent-run-store.js +14 -1
  123. package/node_modules/@maka/storage/dist/artifact-store.js +40 -3
  124. package/node_modules/@maka/storage/dist/atomic-file-write.js +74 -0
  125. package/node_modules/@maka/storage/dist/claude-code-session-adapter.js +0 -1
  126. package/node_modules/@maka/storage/dist/codex-session-adapter.js +284 -196
  127. package/node_modules/@maka/storage/dist/credential-store.js +12 -63
  128. package/node_modules/@maka/storage/dist/execution-stores.js +4 -1
  129. package/node_modules/@maka/storage/dist/git-exec.js +61 -0
  130. package/node_modules/@maka/storage/dist/git-worktree-child-executor.js +8 -35
  131. package/node_modules/@maka/storage/dist/goal-authority.js +2 -2
  132. package/node_modules/@maka/storage/dist/interaction-store.js +2 -2
  133. package/node_modules/@maka/storage/dist/mcp-config-store.js +10 -25
  134. package/node_modules/@maka/storage/dist/project-catalog.js +2 -23
  135. package/node_modules/@maka/storage/dist/runtime-event-invariants.js +2 -2
  136. package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +8 -3
  137. package/node_modules/@maka/storage/dist/scheduled-task-store.js +249 -283
  138. package/node_modules/@maka/storage/dist/session-bundle-manifest.js +5 -17
  139. package/node_modules/@maka/storage/dist/session-bundle-policy.js +2 -1
  140. package/node_modules/@maka/storage/dist/session-copy-cleanup.js +2 -1
  141. package/node_modules/@maka/storage/dist/session-store.js +14 -2
  142. package/node_modules/@maka/storage/dist/settings-store.js +8 -4
  143. package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +11 -0
  144. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +1 -2
  145. package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +12 -1
  146. package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +67 -3
  147. package/node_modules/@maka/storage/dist/stable-storage.js +14 -1
  148. package/node_modules/@maka/storage/dist/storage-id.js +28 -0
  149. package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +31 -4
  150. package/node_modules/@maka/storage/dist/workspace-identity.js +2 -15
  151. package/node_modules/@maka/storage/dist/workspace-version-authority-internal.js +1 -8
  152. package/package.json +1 -1
  153. package/node_modules/@maka/core/dist/workhub-creation-intent.js +0 -990
  154. package/node_modules/@maka/core/dist/workhub-session-resolver.js +0 -50
@@ -17,6 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { isNonEmptyUnicodeString, isSha256Digest, SESSION_BUNDLE_ARCHIVE_FORMAT, SESSION_BUNDLE_CANONICALIZATION_VERSION, SESSION_BUNDLE_CODEC_NAME, SESSION_BUNDLE_CODEC_VERSION, SESSION_BUNDLE_COMPRESSION_FORMAT, SESSION_BUNDLE_COMPRESSION_LEVEL, SESSION_BUNDLE_SCHEMA_VERSION, SESSION_BUNDLE_STATE_IDENTITY_PATH, SESSION_BUNDLE_STATE_PATH, SESSION_BUNDLE_WORKSPACE_PATH, SessionBundleFileError, } from './session-bundle-contract.js';
20
+ import { stableJsonStringify } from '@maka/core/canonical-json';
20
21
  const MANIFEST_KEYS = ['codec', 'envelope', 'payload', 'schemaVersion', 'stateIdentity'];
21
22
  const CODEC_KEYS = [
22
23
  'archive',
@@ -167,25 +168,12 @@ function decodePayload(value) {
167
168
  };
168
169
  }
169
170
  function canonicalJson(value) {
170
- if (value === null)
171
- return 'null';
172
- if (typeof value === 'string')
173
- return JSON.stringify(value);
174
- if (typeof value === 'number') {
175
- if (!Number.isFinite(value))
176
- throw invalidManifest();
177
- return JSON.stringify(value);
171
+ try {
172
+ return stableJsonStringify(value);
178
173
  }
179
- if (typeof value === 'boolean')
180
- return value ? 'true' : 'false';
181
- if (Array.isArray(value))
182
- return `[${value.map((item) => canonicalJson(item)).join(',')}]`;
183
- if (!isRecord(value))
174
+ catch {
184
175
  throw invalidManifest();
185
- return `{${Object.keys(value)
186
- .sort()
187
- .map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
188
- .join(',')}}`;
176
+ }
189
177
  }
190
178
  function hasExactKeys(value, expected) {
191
179
  const actual = Object.keys(value);
@@ -25,6 +25,7 @@ import { withArtifactWriterLock } from './artifact-writer-lock.js';
25
25
  import { withOfflineContextSnapshot, copyContextSnapshot, validateContextSnapshot, planContextSnapshotFiles, } from './context-offload-snapshot.js';
26
26
  import { CONTEXT_OFFLOAD_DATABASE_NAME, CONTEXT_OFFLOAD_VALUES_DIRECTORY_NAME, } from './sqlite-context-offload-store.js';
27
27
  import { acquireOperationalStateDatabase, OPERATIONAL_STATE_DATABASE_NAME, } from './operational-state-store.js';
28
+ import { isSafeStorageId } from './storage-id.js';
28
29
  export const SESSION_BUNDLE_STATE_ENTRIES = [
29
30
  'artifacts',
30
31
  OPERATIONAL_STATE_DATABASE_NAME,
@@ -325,7 +326,7 @@ function assertRootsSeparate(left, right, allowSame) {
325
326
  }
326
327
  }
327
328
  function assertSafeSessionId(sessionId) {
328
- if (!/^[A-Za-z0-9_-]{1,128}$/.test(sessionId)) {
329
+ if (!isSafeStorageId(sessionId)) {
329
330
  throw new SessionBundleExportError('invalid_root', `Invalid session id: ${sessionId}`);
330
331
  }
331
332
  }
@@ -19,6 +19,7 @@
19
19
  import { randomUUID } from 'node:crypto';
20
20
  import { acquireOperationalStateDatabase, } from './operational-state-store.js';
21
21
  import { isProcessLifetimeOwnerReference, } from './process-lifetime-owner.js';
22
+ import { isSafeStorageId } from './storage-id.js';
22
23
  export function createSessionCopyCleanupAuthority(input) {
23
24
  return new SessionCopyCleanupAuthorityImpl(new SqliteSessionCopyCleanupStore(input.workspaceRoot, input.databaseOptions), input.removeSession, input.resumeSessionCopy, input.processId ?? randomUUID(), input.isOwnerProcessActive, input.processLifetimeOwner);
24
25
  }
@@ -392,7 +393,7 @@ function normalizeSessionId(value) {
392
393
  if (typeof value !== 'string')
393
394
  throw new Error('Invalid Session copy id');
394
395
  const normalized = value.trim();
395
- if (!/^[A-Za-z0-9_-]{1,128}$/.test(normalized)) {
396
+ if (!isSafeStorageId(normalized)) {
396
397
  throw new Error('Invalid Session copy id');
397
398
  }
398
399
  return normalized;
@@ -351,9 +351,9 @@ class SqliteSessionStore {
351
351
  // pre-cutover session sees its imported rows.
352
352
  return projectHeaderSnapshot(await this.metadata.read(sessionId));
353
353
  }
354
- async readCatalogRecord(sessionId) {
354
+ async readCatalogRecord(sessionId, roleScope = 'ordinary') {
355
355
  await this.ensureCatalogProjectionReadable();
356
- const record = await this.metadata.readCatalogRecord(sessionId);
356
+ const record = await this.metadata.readCatalogRecord(sessionId, roleScope);
357
357
  return {
358
358
  ...projectHeaderSnapshot(record),
359
359
  activityAt: record.activityAt,
@@ -372,6 +372,18 @@ class SqliteSessionStore {
372
372
  await this.ensureReady();
373
373
  return this.metadata.readTranscriptHighWater(sessionId);
374
374
  }
375
+ async readCoordinationTranscriptIndexState() {
376
+ await this.ensureReady();
377
+ return this.metadata.readCoordinationTranscriptIndexState();
378
+ }
379
+ async appendCoordinationTranscriptIndex(records) {
380
+ await this.ensureReady();
381
+ return this.metadata.appendCoordinationTranscriptIndex(records);
382
+ }
383
+ async readCoordinationTranscriptIndex(request) {
384
+ await this.ensureReady();
385
+ return this.metadata.readCoordinationTranscriptIndex(request);
386
+ }
375
387
  async listTurnsSnapshot(sessionId) {
376
388
  return deriveTurnRecords(await this.readMessagesSnapshot(sessionId));
377
389
  }
@@ -16,10 +16,11 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
19
+ import { mkdir, readFile } from 'node:fs/promises';
20
20
  import { dirname, join } from 'node:path';
21
21
  import { createDefaultSettings, mergeSettings, normalizeSettings } from '@maka/core/settings';
22
22
  import { sanitizeOnboardingMilestones } from '@maka/core/onboarding';
23
+ import { writeAtomicFile } from './atomic-file-write.js';
23
24
  export function createSettingsStore(workspaceRoot) {
24
25
  return new FileSettingsStore(workspaceRoot);
25
26
  }
@@ -133,10 +134,13 @@ class FileSettingsStore {
133
134
  return result;
134
135
  }
135
136
  async write(settings) {
137
+ // SettingsStore does not own the workspace directory's permission policy:
138
+ // sibling stores such as MCP config may independently harden the same root.
139
+ // Keep both directory creation and the historical umask-derived file mode.
136
140
  await mkdir(dirname(this.settingsPath), { recursive: true });
137
- const tempPath = `${this.settingsPath}.${process.pid}.${Date.now()}.tmp`;
138
- await writeFile(tempPath, JSON.stringify(settings, null, 2) + '\n', 'utf8');
139
- await rename(tempPath, this.settingsPath);
141
+ await writeAtomicFile(this.settingsPath, JSON.stringify(settings, null, 2) + '\n', {
142
+ fileMode: 0o666 & ~process.umask(),
143
+ });
140
144
  }
141
145
  withQueue(operation) {
142
146
  const next = this.queue.then(operation, operation);
@@ -82,6 +82,17 @@ class SqliteArtifactMetadataRepository {
82
82
  .prepare('SELECT 1 FROM artifact_records WHERE relative_path = ?')
83
83
  .get(relativePath));
84
84
  }
85
+ readRelativePathsByCaseFoldedArtifactIds(artifactIds) {
86
+ this.assertOpen();
87
+ if (artifactIds.length === 0)
88
+ return [];
89
+ const placeholders = artifactIds.map(() => '?').join(', ');
90
+ const rows = this.#lease.database
91
+ .prepare(`SELECT relative_path FROM artifact_records
92
+ WHERE artifact_id COLLATE NOCASE IN (${placeholders})`)
93
+ .all(...artifactIds);
94
+ return rows.map((row) => row.relative_path);
95
+ }
85
96
  forgetUpgradeOrphanPaths(relativePaths) {
86
97
  this.assertOpen();
87
98
  this.#lease.transaction('write', () => {
@@ -1360,8 +1360,7 @@ export class SqliteRuntimeStore {
1360
1360
  });
1361
1361
  }
1362
1362
  registerWorkspaceBaselineAuthorityWriter() {
1363
- const readWorkspaceHead = this.readWorkspaceHead.bind(this);
1364
- registerWorkspaceBaselineAuthorityWriterInternal(this, (input, rootId) => this.#commitWorkspaceBaseline(input, rootId), (input, rootId) => this.#commitWorkspaceSuccessor(input, rootId), (input, rootId) => this.#commitManagedMutationTerminal(input, rootId), (rootId) => this.#bindWorkspaceStorageRoot(rootId), readWorkspaceHead, (workspaceInstanceId) => this.#readActiveManagedMutation(workspaceInstanceId));
1363
+ registerWorkspaceBaselineAuthorityWriterInternal(this, (input, rootId) => this.#commitWorkspaceBaseline(input, rootId), (input, rootId) => this.#commitWorkspaceSuccessor(input, rootId), (input, rootId) => this.#commitManagedMutationTerminal(input, rootId), (rootId) => this.#bindWorkspaceStorageRoot(rootId), (workspaceInstanceId) => this.#readActiveManagedMutation(workspaceInstanceId));
1365
1364
  }
1366
1365
  async #readActiveManagedMutation(workspaceInstanceId) {
1367
1366
  return this.readTransaction(() => {
@@ -16,7 +16,7 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- export const SQLITE_SESSION_METADATA_SCHEMA_VERSION = 38;
19
+ export const SQLITE_SESSION_METADATA_SCHEMA_VERSION = 39;
20
20
  export const SQLITE_SESSION_MESSAGE_CHUNK_BYTES = 64 * 1024;
21
21
  export const SQLITE_SESSION_MESSAGE_CHUNK_MARKER = '{"$maka":"session-message-chunks-v1"}';
22
22
  export const SQLITE_AGENT_GRAPH_CONTROL_TABLES = [
@@ -32,6 +32,17 @@ export const SQLITE_AGENT_GRAPH_CONTROL_TABLES = [
32
32
  'agent_graph_supervisor_wake_attempts',
33
33
  ];
34
34
  const MIGRATIONS = new Map([
35
+ [
36
+ 39,
37
+ `
38
+ CREATE TABLE IF NOT EXISTS coordination_transcript_index (
39
+ sequence INTEGER PRIMARY KEY,
40
+ source TEXT NOT NULL CHECK (source IN ('legacy', 'runtime')),
41
+ source_sequence INTEGER NOT NULL CHECK (source_sequence >= 0),
42
+ UNIQUE (source, source_sequence)
43
+ );
44
+ `,
45
+ ],
35
46
  [
36
47
  1,
37
48
  `
@@ -730,10 +730,12 @@ export class SqliteSessionMetadataStore {
730
730
  throw new SessionNotFoundError(sessionId);
731
731
  return record;
732
732
  }
733
- async readCatalogRecord(sessionId) {
733
+ async readCatalogRecord(sessionId, roleScope = 'ordinary') {
734
734
  this.assertOpen();
735
735
  assertSafeSessionId(sessionId);
736
- const role = sqliteOrdinarySessionRolePredicate();
736
+ const role = roleScope === 'recoverable'
737
+ ? sqliteRecoverableSessionRolePredicate()
738
+ : sqliteOrdinarySessionRolePredicate();
737
739
  const row = this.db
738
740
  .prepare(`
739
741
  SELECT
@@ -1206,7 +1208,11 @@ export class SqliteSessionMetadataStore {
1206
1208
  assignment.id !== `wha_${suffix}` ||
1207
1209
  assignment.targetMessageId !== `whm_${suffix}` ||
1208
1210
  assignment.delegationId !== `whd_${suffix}` ||
1209
- !messageContentsEqual(admission.content, normalizeMessageContent({ text: assignment.userText })) ||
1211
+ !workHubAssignmentAttachmentsMatchTarget(assignment) ||
1212
+ !messageContentsEqual(admission.content, normalizeMessageContent({
1213
+ text: assignment.delegationText ?? assignment.userText,
1214
+ ...(assignment.targetAttachments ? { attachments: assignment.targetAttachments } : {}),
1215
+ })) ||
1210
1216
  admission.submittedContentDigest !== messageContentDigest(admission.content) ||
1211
1217
  admission.submittedPlacement !== 'current_turn' ||
1212
1218
  admission.placement !== 'current_turn' ||
@@ -1825,6 +1831,45 @@ export class SqliteSessionMetadataStore {
1825
1831
  unique.forEach((messageId, index) => update.run(index, sessionId, messageId));
1826
1832
  });
1827
1833
  }
1834
+ async readCoordinationTranscriptIndexState() {
1835
+ this.assertOpen();
1836
+ return this.db
1837
+ .prepare(`SELECT (SELECT MAX(sequence) FROM coordination_transcript_index) AS highWater,
1838
+ (SELECT MAX(source_sequence) FROM coordination_transcript_index WHERE source = 'legacy') AS legacy,
1839
+ (SELECT MAX(source_sequence) FROM coordination_transcript_index WHERE source = 'runtime') AS runtime`)
1840
+ .get();
1841
+ }
1842
+ async appendCoordinationTranscriptIndex(records) {
1843
+ this.assertOpen();
1844
+ if (records.length > 64)
1845
+ throw new Error('Coordination transcript index batch exceeds limit');
1846
+ this.transaction(() => {
1847
+ let sequence = this.db
1848
+ .prepare('SELECT MAX(sequence) AS value FROM coordination_transcript_index')
1849
+ .get().value ?? -1;
1850
+ const insert = this.db.prepare(`INSERT INTO coordination_transcript_index
1851
+ (sequence, source, source_sequence) VALUES (?, ?, ?)
1852
+ ON CONFLICT(source, source_sequence) DO NOTHING`);
1853
+ for (const record of records) {
1854
+ if (!Number.isSafeInteger(record.sourceSequence) || record.sourceSequence < 0)
1855
+ throw new Error('Invalid Coordination source sequence');
1856
+ const result = insert.run(sequence + 1, record.source, record.sourceSequence);
1857
+ if (result.changes)
1858
+ sequence++;
1859
+ }
1860
+ });
1861
+ }
1862
+ async readCoordinationTranscriptIndex(request) {
1863
+ this.assertOpen();
1864
+ if (!Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > 64)
1865
+ throw new Error('Invalid Coordination transcript index limit');
1866
+ const older = request.direction === 'older';
1867
+ return this.db
1868
+ .prepare(`SELECT sequence, source, source_sequence AS sourceSequence
1869
+ FROM coordination_transcript_index WHERE sequence <= ? AND sequence ${older ? '<=' : '>='} ?
1870
+ ORDER BY sequence ${older ? 'DESC' : 'ASC'} LIMIT ?`)
1871
+ .all(request.throughSequence, request.position, request.limit);
1872
+ }
1828
1873
  async readMessages(sessionId) {
1829
1874
  return this.readMessagesWith(sessionId, decodeStoredMessage);
1830
1875
  }
@@ -4566,6 +4611,21 @@ function isWorkHubActionOperation(value) {
4566
4611
  value === 'replace' ||
4567
4612
  value === 'stop');
4568
4613
  }
4614
+ function workHubAssignmentAttachmentsMatchTarget(assignment) {
4615
+ const source = assignment.attachments ?? [];
4616
+ const target = assignment.targetAttachments ?? [];
4617
+ return (source.length === target.length &&
4618
+ source.every((attachment, index) => {
4619
+ const copied = target[index];
4620
+ const { ref: sourceRef, ...sourceMetadata } = attachment;
4621
+ const { ref: targetRef, ...targetMetadata } = copied;
4622
+ return (sourceRef.kind === 'session_file' &&
4623
+ sourceRef.sessionId === WORKHUB_COORDINATION_SESSION_ID &&
4624
+ targetRef.kind === 'session_file' &&
4625
+ targetRef.sessionId === assignment.targetSessionId &&
4626
+ isDeepStrictEqual(sourceMetadata, targetMetadata));
4627
+ }));
4628
+ }
4569
4629
  function sameWorkHubAssignmentRequest(existing, requested) {
4570
4630
  return isDeepStrictEqual({
4571
4631
  actionId: existing.actionId,
@@ -4574,6 +4634,8 @@ function sameWorkHubAssignmentRequest(existing, requested) {
4574
4634
  targetSessionId: existing.targetSessionId,
4575
4635
  disposition: existing.disposition,
4576
4636
  userText: existing.userText,
4637
+ delegationText: existing.delegationText,
4638
+ attachments: existing.attachments,
4577
4639
  create: existing.create,
4578
4640
  replacesActionId: existing.replacesActionId,
4579
4641
  replacesDelegationId: existing.replacesDelegationId,
@@ -4584,6 +4646,8 @@ function sameWorkHubAssignmentRequest(existing, requested) {
4584
4646
  targetSessionId: requested.targetSessionId,
4585
4647
  disposition: requested.disposition,
4586
4648
  userText: requested.userText,
4649
+ delegationText: requested.delegationText,
4650
+ attachments: requested.attachments,
4587
4651
  create: requested.create,
4588
4652
  replacesActionId: requested.replacesActionId,
4589
4653
  replacesDelegationId: requested.replacesDelegationId,
@@ -17,7 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { constants } from 'node:fs';
20
- import { lstat, open } from 'node:fs/promises';
20
+ import { chmod, lstat, mkdir, open } from 'node:fs/promises';
21
21
  import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
22
22
  const openStableFile = open;
23
23
  const lstatStableFile = lstat;
@@ -74,6 +74,19 @@ export async function syncFile(path) {
74
74
  await handle.close();
75
75
  }
76
76
  }
77
+ /**
78
+ * Create (or harden) an owner-only directory: recursive mkdir plus a
79
+ * fail-closed chmod, since mkdir's mode only applies on creation. Callers that
80
+ * store secrets use this before creating their file or update lock.
81
+ */
82
+ export async function hardenDirectory(dir, mode = 0o700) {
83
+ await mkdir(dir, { recursive: true, mode });
84
+ if (process.platform === 'win32') {
85
+ await chmod(dir, mode).catch(() => { });
86
+ return;
87
+ }
88
+ await chmod(dir, mode);
89
+ }
77
90
  export async function syncDirectoryChain(path, root, beforeSync) {
78
91
  const boundary = resolve(root);
79
92
  let current = resolve(path);
@@ -0,0 +1,28 @@
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
+ const SAFE_STORAGE_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
20
+ /** Returns whether a value can safely be used as a persisted storage identity. */
21
+ export function isSafeStorageId(value) {
22
+ return typeof value === 'string' && SAFE_STORAGE_ID_PATTERN.test(value);
23
+ }
24
+ /** Throws a TypeError unless the value is a safe persisted storage identity. */
25
+ export function assertSafeStorageId(value, message = 'Storage identity is invalid') {
26
+ if (!isSafeStorageId(value))
27
+ throw new TypeError(message);
28
+ }
@@ -23,6 +23,12 @@ import { decodeAgentRunEvent } from '@maka/core/agent-run';
23
23
  import { MODEL_PROJECTION_TARGET_SQL as TARGET } from './sqlite-core-execution-schema.js';
24
24
  const TRANSITIONS = 'core_agent_run_events INDEXED BY core_model_projection_target';
25
25
  const KIND = "event_type = 'model_projection_transition_recorded'";
26
+ // SQLite may parse the containing JSON, but only these reconstruction fields
27
+ // cross into JS or count toward the evidence budget. Raw tool bytes never do.
28
+ const EVENT_EVIDENCE = `CASE WHEN json_valid(payload_json) THEN json_extract(payload_json,
29
+ '$.id', '$.sessionId', '$.runId', '$.invocationId', '$.turnId', '$.ts', '$.partial',
30
+ '$.author', '$.role', '$.content.kind', '$.content.id', '$.content.name',
31
+ '$.content.modelProjection', '$.content.providerExecuted') END`;
26
32
  /** Reader-first foundation; no archive writer or fallback is activated by opening it. */
27
33
  export async function openToolResultArchiveEvidenceReader(lease) {
28
34
  await assertStorageRootLease(lease, 'interactive', lease.access);
@@ -51,10 +57,12 @@ export async function openToolResultArchiveEvidenceReader(lease) {
51
57
  const db = database.database;
52
58
  const { sessionId, runtimeEventId } = accepted;
53
59
  const eventSize = db
54
- .prepare('SELECT length(CAST(payload_json AS BLOB)) AS bytes FROM runtime_events WHERE event_id = ? AND session_id = ?')
60
+ .prepare(`SELECT length(CAST(${EVENT_EVIDENCE} AS BLOB)) AS bytes FROM runtime_events WHERE event_id = ? AND session_id = ?`)
55
61
  .get(runtimeEventId, sessionId);
56
62
  if (!eventSize)
57
63
  return { ok: false, reason: 'not_found' };
64
+ if (eventSize.bytes === null)
65
+ return { ok: false, reason: 'corrupt' };
58
66
  // An unscoped unreadable transition prevents proving completeness.
59
67
  if (db
60
68
  .prepare(`SELECT 1 FROM ${TRANSITIONS} WHERE ${KIND} AND session_id = ? AND ${TARGET} IS NULL LIMIT 1`)
@@ -72,11 +80,30 @@ export async function openToolResultArchiveEvidenceReader(lease) {
72
80
  if (!Number.isSafeInteger(bytes) || bytes < 0 || bytes > MAX_BYTES)
73
81
  return { ok: false, reason: 'too_large' };
74
82
  const raw = db
75
- .prepare('SELECT payload_json FROM runtime_events WHERE event_id = ? AND session_id = ?')
83
+ .prepare(`SELECT ${EVENT_EVIDENCE} AS evidence_json FROM runtime_events WHERE event_id = ? AND session_id = ?`)
76
84
  .get(runtimeEventId, sessionId);
77
85
  let event;
78
86
  try {
79
- event = decodeRuntimeEvent(JSON.parse(String(raw?.payload_json)));
87
+ const [id, sessionId, runId, invocationId, turnId, ts, partial, author, role, kind, callId, name, modelProjection, providerExecuted,] = JSON.parse(String(raw?.evidence_json));
88
+ event = decodeRuntimeEvent({
89
+ id,
90
+ sessionId,
91
+ runId,
92
+ invocationId,
93
+ turnId,
94
+ ts,
95
+ partial,
96
+ author,
97
+ role,
98
+ content: {
99
+ kind,
100
+ id: callId,
101
+ name,
102
+ result: null,
103
+ ...(modelProjection === null ? {} : { modelProjection }),
104
+ ...(providerExecuted === null ? {} : { providerExecuted }),
105
+ },
106
+ });
80
107
  }
81
108
  catch {
82
109
  return { ok: false, reason: 'corrupt' };
@@ -98,7 +125,7 @@ export async function openToolResultArchiveEvidenceReader(lease) {
98
125
  return { ok: false, reason: 'corrupt' };
99
126
  transitions.push(transition);
100
127
  }
101
- return { ok: true, event, transitions };
128
+ return { ok: true, event, transitions, storedBytes: bytes };
102
129
  });
103
130
  });
104
131
  }
@@ -16,12 +16,11 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { execFile } from 'node:child_process';
20
19
  import { randomUUID } from 'node:crypto';
21
20
  import { constants as fsConstants } from 'node:fs';
22
21
  import { lstat, open, realpath, stat } from 'node:fs/promises';
23
22
  import { isAbsolute, join, normalize, parse, resolve } from 'node:path';
24
- import { promisify } from 'node:util';
23
+ import { execGitText } from './git-exec.js';
25
24
  import { hasEnclosingGitEntry } from './git-entry.js';
26
25
  import { publishMarkerFile, readBoundedMarkerFile } from './marker-file.js';
27
26
  export const WORKSPACE_MARKER_FILE = '.maka-workspace.json';
@@ -29,7 +28,6 @@ export const WORKSPACE_MARKER_SCHEMA_VERSION = 1;
29
28
  export const WORKSPACE_IDENTITY_PREFIX = 'workspace:v1:';
30
29
  const MAX_WORKSPACE_MARKER_BYTES = 4_096;
31
30
  const MAX_GIT_EXCLUDE_BYTES = 1024 * 1024;
32
- const execFileAsync = promisify(execFile);
33
31
  export class WorkspaceIdentityError extends Error {
34
32
  code;
35
33
  constructor(code, message, options) {
@@ -101,18 +99,7 @@ async function createWorkspaceMarker(snapshot, workspaceId) {
101
99
  async function ensureWorkspaceMarkerIgnored(workspacePath) {
102
100
  if (!(await hasEnclosingGitEntry(workspacePath)))
103
101
  return;
104
- const env = { ...process.env, GIT_OPTIONAL_LOCKS: '0' };
105
- delete env.GIT_DIR;
106
- delete env.GIT_WORK_TREE;
107
- delete env.GIT_INDEX_FILE;
108
- delete env.GIT_COMMON_DIR;
109
- const { stdout } = await execFileAsync('git', ['-C', workspacePath, 'rev-parse', '--path-format=absolute', '--git-path', 'info/exclude'], {
110
- env,
111
- encoding: 'utf8',
112
- maxBuffer: 64 * 1024,
113
- timeout: 3_000,
114
- windowsHide: true,
115
- });
102
+ const stdout = await execGitText(workspacePath, ['rev-parse', '--path-format=absolute', '--git-path', 'info/exclude'], { maxBuffer: 64 * 1024, timeoutMs: 3_000 });
116
103
  const excludePath = stdout.trim();
117
104
  if (!isAbsolute(excludePath)) {
118
105
  throw new Error(`Git returned a non-absolute exclude path: ${excludePath}`);
@@ -17,7 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  const workspaceBaselineAuthorityWriters = new WeakMap();
20
- export function registerWorkspaceBaselineAuthorityWriterInternal(store, writer, successorWriter, terminalWriter, bindStorageRoot, readHead, readActiveManagedMutation) {
20
+ export function registerWorkspaceBaselineAuthorityWriterInternal(store, writer, successorWriter, terminalWriter, bindStorageRoot, readActiveManagedMutation) {
21
21
  if (workspaceBaselineAuthorityWriters.has(store)) {
22
22
  throw new Error('Workspace baseline authority writer is already registered');
23
23
  }
@@ -25,7 +25,6 @@ export function registerWorkspaceBaselineAuthorityWriterInternal(store, writer,
25
25
  writer,
26
26
  successorWriter,
27
27
  terminalWriter,
28
- readHead,
29
28
  readActiveManagedMutation,
30
29
  bindStorageRoot,
31
30
  });
@@ -36,12 +35,6 @@ export function readActiveManagedMutationInternal(store, workspaceInstanceId) {
36
35
  throw new Error('Managed mutation reservation reader is unavailable');
37
36
  return registration.readActiveManagedMutation(workspaceInstanceId);
38
37
  }
39
- export function readWorkspaceHeadInternal(store, workspaceId, workspaceEpochId) {
40
- const registration = workspaceBaselineAuthorityWriters.get(store);
41
- if (!registration)
42
- throw new Error('Workspace baseline authority reader is unavailable');
43
- return registration.readHead(workspaceId, workspaceEpochId);
44
- }
45
38
  /**
46
39
  * Storage-internal authority seam. This module is deliberately absent from the
47
40
  * @maka/storage package exports. The schema-9 reader, migration, and projection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maka-agent",
3
- "version": "0.2.0-dev.24.20260907",
3
+ "version": "0.2.0-dev.26.20260909",
4
4
  "description": "Apache Maka (Incubating) developer snapshot; not an Apache release.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",