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
@@ -16,10 +16,11 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { randomUUID } from 'node:crypto';
20
- import { chmod, mkdir, open, readFile, rename, rm } from 'node:fs/promises';
19
+ import { readFile } from 'node:fs/promises';
21
20
  import { dirname, join } from 'node:path';
21
+ import { writeAtomicFile } from './atomic-file-write.js';
22
22
  import { withFileUpdateLock } from './file-update-lock.js';
23
+ import { hardenDirectory } from './stable-storage.js';
23
24
  /** Current on-disk schema version. Unknown versions fail closed on read. */
24
25
  export const CREDENTIAL_SCHEMA_VERSION = 1;
25
26
  export function createFileCredentialStore(workspaceRoot) {
@@ -129,68 +130,14 @@ class FileCredentialStore {
129
130
  }
130
131
  }
131
132
  /**
132
- * Create (or harden) the directory that holds a secret file: 0700, and
133
- * re-chmod a pre-existing looser dir so neither the secret nor the lock can sit
134
- * world-readable. mkdir's mode only applies on creation, so the chmod is what
135
- * fixes an existing dir. On POSIX a chmod failure fails closed (we must not
136
- * write plaintext credentials into a dir we couldn't lock down); no-op on
137
- * Windows. Shared by the writer and the lock so their dir hardening can't drift.
138
- */
139
- async function ensureSecretDir(dir) {
140
- await mkdir(dir, { recursive: true, mode: 0o700 });
141
- await chmodStrict(dir, 0o700);
142
- }
143
- /**
144
- * Owner-only atomic write for a credentials file: a 0700 dir, an exclusive
145
- * 0600 temp ('wx'/O_EXCL so we never follow a pre-planted symlink at a
146
- * predictable path), a durability fence before and after the atomic rename,
147
- * and temp cleanup on failure.
133
+ * Owner-only atomic write for a credentials file. Directory hardening is an
134
+ * explicit credential-store policy; file publication uses the shared legacy
135
+ * JSON writer so its mode, synchronization, and cleanup behavior remains
136
+ * aligned with settings and MCP config.
148
137
  */
149
138
  async function writeSecretFileAtomic(path, contents) {
150
- await ensureSecretDir(dirname(path));
151
- const tempPath = `${path}.${randomUUID()}.tmp`;
152
- try {
153
- const handle = await open(tempPath, 'wx', 0o600);
154
- try {
155
- await handle.writeFile(contents, 'utf8');
156
- await handle.sync();
157
- }
158
- finally {
159
- await handle.close();
160
- }
161
- await chmodStrict(tempPath, 0o600);
162
- await rename(tempPath, path);
163
- await syncDirectory(dirname(path));
164
- }
165
- catch (error) {
166
- await rm(tempPath, { force: true });
167
- throw error;
168
- }
169
- }
170
- async function syncDirectory(path) {
171
- if (process.platform === 'win32')
172
- return;
173
- const handle = await open(path, 'r');
174
- try {
175
- await handle.sync();
176
- }
177
- finally {
178
- await handle.close();
179
- }
180
- }
181
- /**
182
- * chmod that fails loud on POSIX and is best-effort on Windows. A secret file
183
- * or its directory left looser than intended breaks the 0600/0700 boundary, so
184
- * on POSIX we surface the failure rather than write plaintext into it; Windows
185
- * has no POSIX mode, so a failure there is a no-op. One policy for both the
186
- * secret file (0600) and its directory (0700) so they can't drift apart.
187
- */
188
- async function chmodStrict(path, mode) {
189
- if (process.platform === 'win32') {
190
- await chmod(path, mode).catch(() => { });
191
- return;
192
- }
193
- await chmod(path, mode);
139
+ await hardenDirectory(dirname(path));
140
+ await writeAtomicFile(path, contents, { fileMode: 0o600 });
194
141
  }
195
142
  const LOCK_TIMEOUT_MS = 10_000;
196
143
  /**
@@ -220,7 +167,9 @@ const LOCK_TIMEOUT_MS = 10_000;
220
167
  * stays the typed store and callers can't drive the lock directly.
221
168
  */
222
169
  export async function withCredentialFileLock(targetPath, fn, timeoutMs = LOCK_TIMEOUT_MS) {
223
- await ensureSecretDir(dirname(targetPath));
170
+ // Same owner-only hardening the writer applies, so the lock directory can
171
+ // never sit looser than the secret it guards.
172
+ await hardenDirectory(dirname(targetPath));
224
173
  return withFileUpdateLock(targetPath, fn, timeoutMs);
225
174
  }
226
175
  const STORED_CREDENTIAL_KINDS = [
@@ -149,10 +149,13 @@ async function createExecutionStoresForWrite(lease, kind, extension) {
149
149
  listForRecovery: () => run(() => sessionStore.listForRecovery()),
150
150
  readHeaderSnapshot: (sessionId) => run(() => sessionStore.readHeaderSnapshot(sessionId)),
151
151
  readHeaderRecordSnapshot: (sessionId) => run(() => sessionStore.readHeaderRecordSnapshot(sessionId)),
152
- readCatalogRecord: (sessionId) => run(() => sessionStore.readCatalogRecord(sessionId)),
152
+ readCatalogRecord: (sessionId, roleScope) => run(() => sessionStore.readCatalogRecord(sessionId, roleScope)),
153
153
  probeSessionRemoval: (sessionId) => run(() => sessionStore.probeSessionRemoval(sessionId)),
154
154
  readMessagesSnapshot: (sessionId) => run(() => sessionStore.readMessagesSnapshot(sessionId)),
155
155
  readTranscriptMessagesSnapshot: (sessionId, request) => run(() => sessionStore.readTranscriptMessagesSnapshot(sessionId, request)),
156
+ readCoordinationTranscriptIndexState: () => run(() => sessionStore.readCoordinationTranscriptIndexState()),
157
+ appendCoordinationTranscriptIndex: (records) => run(() => sessionStore.appendCoordinationTranscriptIndex(records)),
158
+ readCoordinationTranscriptIndex: (request) => run(() => sessionStore.readCoordinationTranscriptIndex(request)),
156
159
  readTranscriptHighWaterSnapshot: (sessionId) => run(() => sessionStore.readTranscriptHighWaterSnapshot(sessionId)),
157
160
  listTurnsSnapshot: (sessionId) => run(() => sessionStore.listTurnsSnapshot(sessionId)),
158
161
  readHeader: (sessionId) => run(() => sessionStore.readHeader(sessionId)),
@@ -0,0 +1,61 @@
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
+ import { execFile } from 'node:child_process';
20
+ import { promisify } from 'node:util';
21
+ const execFileAsync = promisify(execFile);
22
+ const DEFAULT_TIMEOUT_MS = 2 * 60 * 1_000;
23
+ const DEFAULT_TEXT_MAX_BUFFER = 1024 * 1024;
24
+ const DEFAULT_BYTES_MAX_BUFFER = Number.MAX_SAFE_INTEGER;
25
+ /**
26
+ * Runs Git with repository discovery isolated from ambient Git environment
27
+ * variables. Callers may provide a temporary index for patch construction.
28
+ */
29
+ export async function execGitText(cwd, args, options = {}) {
30
+ const { stdout } = await execFileAsync('git', ['-C', cwd, ...args], {
31
+ env: gitEnvironment(options),
32
+ encoding: 'utf8',
33
+ maxBuffer: options.maxBuffer ?? DEFAULT_TEXT_MAX_BUFFER,
34
+ timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
35
+ windowsHide: true,
36
+ });
37
+ return stdout;
38
+ }
39
+ export async function execGitBytes(cwd, args, options = {}) {
40
+ const { stdout } = await execFileAsync('git', ['-C', cwd, ...args], {
41
+ env: gitEnvironment(options),
42
+ encoding: 'buffer',
43
+ maxBuffer: options.maxBuffer ?? DEFAULT_BYTES_MAX_BUFFER,
44
+ timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
45
+ windowsHide: true,
46
+ });
47
+ return new Uint8Array(stdout);
48
+ }
49
+ function gitEnvironment(options) {
50
+ const env = { ...process.env, GIT_OPTIONAL_LOCKS: '0' };
51
+ delete env.GIT_DIR;
52
+ delete env.GIT_WORK_TREE;
53
+ delete env.GIT_COMMON_DIR;
54
+ if (options.gitIndexFile === undefined) {
55
+ delete env.GIT_INDEX_FILE;
56
+ }
57
+ else {
58
+ env.GIT_INDEX_FILE = options.gitIndexFile;
59
+ }
60
+ return env;
61
+ }
@@ -16,17 +16,14 @@
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 { copyFile, mkdir, mkdtemp, readdir, realpath, rm, stat } from 'node:fs/promises';
21
20
  import { tmpdir } from 'node:os';
22
21
  import { isAbsolute, join, normalize, resolve } from 'node:path';
23
- import { promisify } from 'node:util';
24
22
  import { SUBAGENT_WORKSPACE_BINDING_SCHEMA_VERSION, isSubagentWorkspaceBinding, } from '@maka/core/subagent-workspace';
23
+ import { execGitBytes, execGitText } from './git-exec.js';
25
24
  import { resolveProjectLocation } from './project-catalog.js';
26
- const execFileAsync = promisify(execFile);
27
25
  const LEASE_PATTERN = /^subagent_worktree_([a-f0-9]{32})$/;
28
26
  const WORKTREE_DIRECTORY_PATTERN = /^[a-f0-9]{32}$/;
29
- const GIT_TIMEOUT_MS = 2 * 60 * 1_000;
30
27
  /**
31
28
  * Host-owned Git worktree allocator for linked child Sessions.
32
29
  *
@@ -96,8 +93,8 @@ class GitWorktreeChildExecutor {
96
93
  const currentIndex = (await runGit(binding.worktreePath, ['rev-parse', '--git-path', 'index'])).trim();
97
94
  // Preserve staged and committed ignored paths, then overlay all working-tree changes.
98
95
  await copyFile(isAbsolute(currentIndex) ? currentIndex : resolve(binding.worktreePath, currentIndex), indexPath);
99
- const env = { GIT_INDEX_FILE: indexPath };
100
- await runGit(binding.worktreePath, ['add', '--all', '--'], env);
96
+ const gitOptions = { gitIndexFile: indexPath };
97
+ await runGit(binding.worktreePath, ['add', '--all', '--'], gitOptions);
101
98
  return await runGitBytes(binding.worktreePath, [
102
99
  'diff',
103
100
  '--cached',
@@ -108,7 +105,7 @@ class GitWorktreeChildExecutor {
108
105
  '--no-color',
109
106
  binding.baseCommit,
110
107
  '--',
111
- ], env);
108
+ ], gitOptions);
112
109
  }
113
110
  finally {
114
111
  await rm(temporary, { recursive: true, force: true });
@@ -398,35 +395,11 @@ async function gitCurrentBranch(cwd) {
398
395
  throw error;
399
396
  }
400
397
  }
401
- async function runGit(cwd, args, overrides = {}) {
402
- const env = gitEnvironment(overrides);
403
- const { stdout } = await execFileAsync('git', ['-C', cwd, ...args], {
404
- env,
405
- encoding: 'utf8',
406
- maxBuffer: 1024 * 1024,
407
- timeout: GIT_TIMEOUT_MS,
408
- windowsHide: true,
409
- });
410
- return stdout;
398
+ async function runGit(cwd, args, options = {}) {
399
+ return execGitText(cwd, args, options);
411
400
  }
412
- async function runGitBytes(cwd, args, overrides = {}) {
413
- const { stdout } = await execFileAsync('git', ['-C', cwd, ...args], {
414
- env: gitEnvironment(overrides),
415
- encoding: 'buffer',
416
- maxBuffer: Number.MAX_SAFE_INTEGER,
417
- timeout: GIT_TIMEOUT_MS,
418
- windowsHide: true,
419
- });
420
- return new Uint8Array(stdout);
421
- }
422
- function gitEnvironment(overrides) {
423
- const env = { ...process.env, GIT_OPTIONAL_LOCKS: '0', ...overrides };
424
- delete env.GIT_DIR;
425
- delete env.GIT_WORK_TREE;
426
- delete env.GIT_COMMON_DIR;
427
- if (overrides.GIT_INDEX_FILE === undefined)
428
- delete env.GIT_INDEX_FILE;
429
- return env;
401
+ async function runGitBytes(cwd, args, options = {}) {
402
+ return execGitBytes(cwd, args, options);
430
403
  }
431
404
  function gitExitCode(error) {
432
405
  if (!error || typeof error !== 'object' || !('code' in error))
@@ -19,6 +19,7 @@
19
19
  import { decodeGoalAuthorityRecord } from '@maka/core/goal';
20
20
  import { acquireOperationalStateDatabase, } from './operational-state-store.js';
21
21
  import { assertStorageRootLease, runWithStorageRootLease, StorageRootAuthorityError, } from './root-authority.js';
22
+ import { assertSafeStorageId } from './storage-id.js';
22
23
  const writerBrand = Symbol('InteractiveGoalAuthorityWriter');
23
24
  const writers = new WeakSet();
24
25
  const writerByLease = new WeakMap();
@@ -217,6 +218,5 @@ function cloneSnapshot(snapshot) {
217
218
  });
218
219
  }
219
220
  function requireId(value, label) {
220
- if (!/^[A-Za-z0-9_-]{1,128}$/.test(value))
221
- throw new TypeError(`${label} identity is invalid`);
221
+ assertSafeStorageId(value, `${label} identity is invalid`);
222
222
  }
@@ -22,7 +22,7 @@ import { clientCapabilityScopeIdentity, decodeClientCapabilitySessionGrant, deco
22
22
  import { decodeInteractionCanonicalOutcome, decodeInteractionRequest, interactionCanonicalOutcomesEquivalent, isInteractionCanonicalOutcomeValidForRequest, projectInteractionFormRequest, projectInteractionQuestionRequest, } from '@maka/core/interaction';
23
23
  import { assertStorageRootLease, runWithStorageRootLease, StorageRootAuthorityError, } from './root-authority.js';
24
24
  import { acquireOperationalStateDatabase, } from './operational-state-store.js';
25
- const SAFE_ID = /^[A-Za-z0-9_-]{1,128}$/;
25
+ import { isSafeStorageId } from './storage-id.js';
26
26
  const REMEMBER_SCOPE_ID = /^[0-9a-f]{64}$/;
27
27
  export const STORED_INTERACTION_REQUEST_MAX_BYTES = 20 * 1024;
28
28
  export const STORED_INTERACTION_OUTCOME_MAX_BYTES = 12 * 1024;
@@ -512,7 +512,7 @@ function identity(value) {
512
512
  };
513
513
  }
514
514
  function assertId(value, source = 'input', message = 'Invalid Interaction identity') {
515
- if (typeof value !== 'string' || !SAFE_ID.test(value))
515
+ if (!isSafeStorageId(value))
516
516
  decodeFailure(source, message);
517
517
  return value;
518
518
  }
@@ -16,11 +16,15 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { randomUUID } from 'node:crypto';
20
- import { chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
19
+ import { readFile } from 'node:fs/promises';
21
20
  import { dirname, join } from 'node:path';
22
21
  import { MCP_CONFIG_VERSION, createDefaultMcpConfig, isNonLoopbackCleartextHttp, } from '@maka/core/mcp';
22
+ import { writeAtomicFile } from './atomic-file-write.js';
23
23
  import { withProcessLifetimeFileUpdateLock } from './process-lifetime-file-update-lock.js';
24
+ import { hardenDirectory } from './stable-storage.js';
25
+ // Consumers reconcile an already-published write through this store's public
26
+ // boundary; the shared atomic writer itself remains internal to storage.
27
+ export { AtomicFileWriteCommitUnknownError } from './atomic-file-write.js';
24
28
  const MAX_SERVERS = 100;
25
29
  const MAX_ID_LENGTH = 128;
26
30
  const MAX_STRING_LENGTH = 8_192;
@@ -157,34 +161,15 @@ class FileMcpConfigStore {
157
161
  return withProcessLifetimeFileUpdateLock(this.path, operation);
158
162
  }
159
163
  async write(config) {
160
- const dir = dirname(this.path);
161
164
  await this.ensureDirectory();
162
- const tempPath = join(dir, `.mcp-${randomUUID()}.tmp`);
163
- try {
164
- await writeFile(tempPath, `${JSON.stringify(config, null, 2)}\n`, {
165
- encoding: 'utf8',
166
- mode: 0o600,
167
- flag: 'wx',
168
- });
169
- if (process.platform !== 'win32')
170
- await chmod(tempPath, 0o600);
171
- await rename(tempPath, this.path);
172
- if (process.platform !== 'win32')
173
- await chmod(this.path, 0o600);
174
- }
175
- finally {
176
- await rm(tempPath, { force: true }).catch(() => { });
177
- }
165
+ await writeAtomicFile(this.path, `${JSON.stringify(config, null, 2)}\n`, {
166
+ fileMode: 0o600,
167
+ });
178
168
  }
179
169
  ensureDirectory() {
180
170
  if (this.directoryReady)
181
171
  return this.directoryReady;
182
- const dir = dirname(this.path);
183
- const ready = (async () => {
184
- await mkdir(dir, { recursive: true, mode: 0o700 });
185
- if (process.platform !== 'win32')
186
- await chmod(dir, 0o700);
187
- })();
172
+ const ready = hardenDirectory(dirname(this.path), 0o700);
188
173
  this.directoryReady = ready;
189
174
  void ready.catch(() => {
190
175
  if (this.directoryReady === ready)
@@ -16,16 +16,14 @@
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 { realpath, stat } from 'node:fs/promises';
22
21
  import { basename, dirname, isAbsolute, join, normalize, relative, resolve, sep } from 'node:path';
23
- import { promisify } from 'node:util';
24
22
  import { markPersisted } from '@maka/core/persisted-value';
23
+ import { execGitText } from './git-exec.js';
25
24
  import { hasEnclosingGitEntry } from './git-entry.js';
26
25
  import { acquireOperationalStateDatabase, } from './operational-state-store.js';
27
26
  import { decodePersistedSessionHeader, normalizeSessionHeader } from './session-store.js';
28
- const execFileAsync = promisify(execFile);
29
27
  export class ProjectPathMismatchError extends Error {
30
28
  projectId;
31
29
  path;
@@ -690,26 +688,7 @@ function isPathWithin(root, candidate) {
690
688
  return path === '' || (!isAbsolute(path) && path !== '..' && !path.startsWith(`..${sep}`));
691
689
  }
692
690
  async function resolveGitLocation(canonicalPath) {
693
- const env = { ...process.env, GIT_OPTIONAL_LOCKS: '0' };
694
- delete env.GIT_DIR;
695
- delete env.GIT_WORK_TREE;
696
- delete env.GIT_INDEX_FILE;
697
- delete env.GIT_COMMON_DIR;
698
- const { stdout: locationOutput } = await execFileAsync('git', [
699
- '-C',
700
- canonicalPath,
701
- 'rev-parse',
702
- '--path-format=absolute',
703
- '--show-toplevel',
704
- '--git-dir',
705
- '--git-common-dir',
706
- ], {
707
- env,
708
- encoding: 'utf8',
709
- maxBuffer: 64 * 1024,
710
- timeout: 3_000,
711
- windowsHide: true,
712
- });
691
+ const locationOutput = await execGitText(canonicalPath, ['rev-parse', '--path-format=absolute', '--show-toplevel', '--git-dir', '--git-common-dir'], { maxBuffer: 64 * 1024, timeoutMs: 3_000 });
713
692
  const [worktreeRootRaw, gitDirRaw, commonDirRaw] = locationOutput.trim().split(/\r?\n/);
714
693
  if (!worktreeRootRaw || !gitDirRaw || !commonDirRaw) {
715
694
  throw new Error(`Git returned an incomplete project location for: ${canonicalPath}`);
@@ -16,9 +16,9 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- const SAFE_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
19
+ import { isSafeStorageId } from './storage-id.js';
20
20
  export function isRuntimeStorageSafeId(value) {
21
- return SAFE_ID_PATTERN.test(value);
21
+ return isSafeStorageId(value);
22
22
  }
23
23
  export function immutableSteeringMessageId(event) {
24
24
  const messageId = event.refs?.providerEventId;
@@ -20,7 +20,7 @@ import { randomUUID } from 'node:crypto';
20
20
  import { isDeepStrictEqual } from 'node:util';
21
21
  import { CONNECTION_CATALOG_MAX_CONNECTIONS, decodeCanonicalConnectionCatalogEntry, decodeConnectionName, decodeConnectionSlug, decodeConnectionTarget, decodeConnectionTestSummary, decodeProviderType, decodeRuntimePolicyEntityId, normalizeConnectionCatalogEntryUpdateForProvider, normalizeConnectionModelDiscoveryResult, normalizeCreateCatalogConnectionInput, normalizeRemoveCatalogConnectionInput, normalizeSetDefaultConnectionTargetInput, normalizeUpdateCatalogConnectionInput, } from '@maka/core/runtime-policy';
22
22
  import { PROVIDER_REGISTRY, reconcileConnectionAfterModelFetch } from '@maka/core/llm-connections';
23
- import { modelIdAliasesForProvider } from '@maka/core/model-metadata';
23
+ import { modelIdAliasesForProvider, providerReportsCompleteModelCatalog, } from '@maka/core/model-metadata';
24
24
  import { isRetiredProvider } from '@maka/core/provider-registry';
25
25
  import { pruneRelayModelProfiles } from '@maka/core/model-thinking';
26
26
  import { deepFreeze, nextRevision, record, revision, unique } from './codec.js';
@@ -325,14 +325,19 @@ export class ConnectionCatalogDocumentOwner {
325
325
  hasModelInventory: previous.models.length > 0,
326
326
  }, result.models, {
327
327
  aliases: modelIdAliasesForProvider(previous.providerType),
328
+ authoritative: providerReportsCompleteModelCatalog(previous.providerType),
328
329
  });
329
330
  // Discovery MOVES a target: a provider's model rename carries the default
330
331
  // across by alias. A default outside the selection the reconciler just
331
332
  // decided is its own bug — fail closed where it is still attributable.
332
333
  const defaultTarget = currentDefaultTarget
333
- ? { connectionId: previous.connectionId, modelId: reconciled.defaultModel }
334
+ ? reconciled.defaultModel
335
+ ? { connectionId: previous.connectionId, modelId: reconciled.defaultModel }
336
+ : null
334
337
  : current.defaultTarget;
335
- if (currentDefaultTarget && !reconciled.enabledModelIds.includes(reconciled.defaultModel)) {
338
+ if (currentDefaultTarget &&
339
+ reconciled.defaultModel &&
340
+ !reconciled.enabledModelIds.includes(reconciled.defaultModel)) {
336
341
  throw codecError('invalid_document', 'Model discovery reconciled a default outside its own selection');
337
342
  }
338
343
  // A refresh only ever migrates a renamed id now, but that rename still