maka-agent 0.2.0-dev.10.20260831 → 0.2.0-dev.11.20260831

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 (108) hide show
  1. package/LICENSE +47 -0
  2. package/dist/pi-tui-mcp-status.js +84 -5
  3. package/dist/runtime-host-cli-context.js +4 -0
  4. package/dist/runtime-host-tui-context.js +16 -1
  5. package/dist/tui-copy-catalog.js +10 -0
  6. package/dist/tui-mcp-control.js +46 -4
  7. package/dist/tui-mcp-remote-publication.js +395 -0
  8. package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
  9. package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
  10. package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
  11. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  12. package/node_modules/@maka/core/dist/agent-run.js +5 -0
  13. package/node_modules/@maka/core/dist/chat-model-choice.js +3 -1
  14. package/node_modules/@maka/core/dist/execution-inspect.js +3 -1
  15. package/node_modules/@maka/core/dist/model-call-attempt.js +66 -0
  16. package/node_modules/@maka/core/dist/model-catalog.js +27 -8
  17. package/node_modules/@maka/core/dist/model-facts.js +286 -0
  18. package/node_modules/@maka/core/dist/model-projection-transition.js +145 -0
  19. package/node_modules/@maka/core/dist/runtime-boundary.js +2 -2
  20. package/node_modules/@maka/core/dist/runtime-event.js +1 -1
  21. package/node_modules/@maka/core/dist/runtime-policy/connection-catalog-codec.js +62 -1
  22. package/node_modules/@maka/core/dist/session-todo.js +101 -0
  23. package/node_modules/@maka/core/dist/tool-activity-args.js +4 -0
  24. package/node_modules/@maka/core/dist/tool-quiet-preview.js +5 -5
  25. package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
  26. package/node_modules/@maka/core/package.json +3 -0
  27. package/node_modules/@maka/runtime/dist/active-tool-result-prune.js +45 -131
  28. package/node_modules/@maka/runtime/dist/agent-run.js +51 -44
  29. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +143 -199
  30. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +235 -69
  31. package/node_modules/@maka/runtime/dist/context-budget-helpers.js +4 -41
  32. package/node_modules/@maka/runtime/dist/context-budget-policy.js +8 -1
  33. package/node_modules/@maka/runtime/dist/context-budget.js +9 -81
  34. package/node_modules/@maka/runtime/dist/context-diagnostics.js +63 -27
  35. package/node_modules/@maka/runtime/dist/continuation-replay.js +19 -11
  36. package/node_modules/@maka/runtime/dist/conversation-copy.js +179 -16
  37. package/node_modules/@maka/runtime/dist/deep-research-tools.js +2 -3
  38. package/node_modules/@maka/runtime/dist/durable-tool-result-projection.js +21 -0
  39. package/node_modules/@maka/runtime/dist/execution-inspect.js +13 -3
  40. package/node_modules/@maka/runtime/dist/history-compact-checkpoint.js +58 -7
  41. package/node_modules/@maka/runtime/dist/history-compact-ledger.js +9 -1
  42. package/node_modules/@maka/runtime/dist/history-compact-summarizer.js +2 -2
  43. package/node_modules/@maka/runtime/dist/history-compact-summary-validation.js +2 -1
  44. package/node_modules/@maka/runtime/dist/history-compaction.js +2 -1
  45. package/node_modules/@maka/runtime/dist/latest-context-snapshot.js +114 -20
  46. package/node_modules/@maka/runtime/dist/model-adapter.js +47 -15
  47. package/node_modules/@maka/runtime/dist/model-factory.js +7 -1
  48. package/node_modules/@maka/runtime/dist/model-history.js +107 -2
  49. package/node_modules/@maka/runtime/dist/model-projection-transition-ledger.js +207 -0
  50. package/node_modules/@maka/runtime/dist/model-runtime.js +5 -2
  51. package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +12 -14
  52. package/node_modules/@maka/runtime/dist/prompt-composition.js +33 -21
  53. package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +35 -74
  54. package/node_modules/@maka/runtime/dist/request-shape.js +256 -343
  55. package/node_modules/@maka/runtime/dist/run-trace.js +2 -24
  56. package/node_modules/@maka/runtime/dist/runtime-continuation-admission.js +1 -1
  57. package/node_modules/@maka/runtime/dist/runtime-kernel.js +77 -23
  58. package/node_modules/@maka/runtime/dist/runtime-resume.js +20 -11
  59. package/node_modules/@maka/runtime/dist/session-manager.js +45 -9
  60. package/node_modules/@maka/runtime/dist/session-recap.js +2 -1
  61. package/node_modules/@maka/runtime/dist/session-todo-tools.js +67 -0
  62. package/node_modules/@maka/runtime/dist/subagent-tools.js +2 -77
  63. package/node_modules/@maka/runtime/dist/system-prompt/main-session-prompt.js +1 -1
  64. package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +227 -0
  65. package/node_modules/@maka/runtime/dist/tool-result-archive.js +40 -168
  66. package/node_modules/@maka/runtime/package.json +1 -1
  67. package/node_modules/@maka/runtime-host/dist/client/host-profile.js +221 -19
  68. package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
  69. package/node_modules/@maka/runtime-host/dist/protocol/index.js +11 -2
  70. package/node_modules/@maka/runtime-host/dist/protocol/operations.js +5 -3
  71. package/node_modules/@maka/runtime-host/dist/protocol/runtime-policy.js +49 -1
  72. package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -1
  73. package/node_modules/@maka/runtime-host/dist/protocol/session-retirement.js +30 -3
  74. package/node_modules/@maka/runtime-host/dist/protocol/session-todo.js +53 -0
  75. package/node_modules/@maka/runtime-host/dist/server/child-agent-composition.js +1 -1
  76. package/node_modules/@maka/runtime-host/dist/server/connection-effect-coordinator.js +1 -0
  77. package/node_modules/@maka/runtime-host/dist/server/deep-research-coordinator.js +1 -1
  78. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +46 -62
  79. package/node_modules/@maka/runtime-host/dist/server/execution-model-authority.js +26 -8
  80. package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +38 -43
  81. package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +0 -23
  82. package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +7 -9
  83. package/node_modules/@maka/runtime-host/dist/server/runtime-policy-coordinator.js +5 -1
  84. package/node_modules/@maka/runtime-host/dist/server/session-retirement-coordinator.js +58 -9
  85. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +30 -13
  86. package/node_modules/@maka/runtime-host/dist/server/session-sidecar-purge.js +1 -1
  87. package/node_modules/@maka/runtime-host/dist/server/session-todo-coordinator.js +77 -0
  88. package/node_modules/@maka/storage/dist/agent-run-store.js +76 -15
  89. package/node_modules/@maka/storage/dist/artifact-attachments.js +29 -6
  90. package/node_modules/@maka/storage/dist/artifact-stores.js +13 -2
  91. package/node_modules/@maka/storage/dist/credential-store.js +3 -0
  92. package/node_modules/@maka/storage/dist/execution-stores.js +1 -0
  93. package/node_modules/@maka/storage/dist/file-lifetime-owner.js +30 -2
  94. package/node_modules/@maka/storage/dist/model-facts-store.js +79 -0
  95. package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +7 -4
  96. package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +98 -20
  97. package/node_modules/@maka/storage/dist/runtime-policy/document-io.js +22 -16
  98. package/node_modules/@maka/storage/dist/session-todo-authority.js +106 -0
  99. package/node_modules/@maka/storage/dist/session-todo-store.js +231 -0
  100. package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +42 -1
  101. package/node_modules/@maka/storage/dist/sqlite-workflow-schema.js +6 -1
  102. package/node_modules/@maka/storage/dist/storage-writer-composition.js +3 -3
  103. package/node_modules/@maka/storage/package.json +1 -1
  104. package/package.json +1 -1
  105. package/node_modules/@maka/runtime/dist/task-ledger-tools.js +0 -244
  106. package/node_modules/@maka/runtime/dist/test-helpers.js +0 -61
  107. package/node_modules/@maka/runtime-host/dist/protocol/task-ledger.js +0 -321
  108. package/node_modules/@maka/runtime-host/dist/server/task-ledger-coordinator.js +0 -154
package/LICENSE CHANGED
@@ -261,6 +261,53 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
261
261
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
262
262
  SOFTWARE.
263
263
 
264
+ Sigstore dependency patch
265
+
266
+ Source: https://www.npmjs.com/package/@sigstore/core/v/4.0.1
267
+ Repository: https://github.com/sigstore/sigstore-js/tree/main/packages/core
268
+ Version: 4.0.1
269
+ Dependency patch: patches/@sigstore+core+4.0.1.patch
270
+ Copyright 2023 The Sigstore Authors
271
+ License: Apache-2.0
272
+
273
+ Maka redistributes a source patch that selects the signature digest in
274
+ @sigstore/core. The patch modifies Apache-2.0 source and is covered by the
275
+ Apache License, Version 2.0 reproduced above.
276
+
277
+ TUF metadata models dependency patch
278
+
279
+ Source: https://www.npmjs.com/package/@tufjs/models/v/5.0.0
280
+ Repository: https://github.com/theupdateframework/tuf-js/tree/main/packages/models
281
+ Version: 5.0.0
282
+ Dependency patch: patches/@tufjs+models+5.0.0.patch
283
+ Copyright (c) 2022 GitHub and the TUF Contributors
284
+ License: MIT
285
+
286
+ Maka redistributes a source patch that selects the signature digest in
287
+ @tufjs/models. The following MIT License applies to that material:
288
+
289
+ MIT License
290
+
291
+ Copyright (c) 2022 GitHub and the TUF Contributors
292
+
293
+ Permission is hereby granted, free of charge, to any person obtaining a copy
294
+ of this software and associated documentation files (the "Software"), to deal
295
+ in the Software without restriction, including without limitation the rights
296
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
297
+ copies of the Software, and to permit persons to whom the Software is
298
+ furnished to do so, subject to the following conditions:
299
+
300
+ The above copyright notice and this permission notice shall be included in
301
+ all copies or substantial portions of the Software.
302
+
303
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
304
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
305
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
306
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
307
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
308
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
309
+ THE SOFTWARE.
310
+
264
311
  node-pty dependency patch
265
312
 
266
313
  Source: https://www.npmjs.com/package/node-pty/v/1.2.0-beta.15
@@ -16,7 +16,7 @@
16
16
  * specific language governing permissions and limitations
17
17
  * under the License.
18
18
  */
19
- import { Editor, Key, matchesKey, truncateToWidth, visibleWidth, } from '@earendil-works/pi-tui';
19
+ import { Editor, Input, Key, matchesKey, truncateToWidth, visibleWidth, } from '@earendil-works/pi-tui';
20
20
  import { defineUiMessageCatalog, formatUiMessage, resolveUiMessageCatalog, } from '@maka/core/ui-locale';
21
21
  import { normalizeMcpConfig } from '@maka/storage/mcp-config-store';
22
22
  import { ansi, editorTheme } from './tui-ansi.js';
@@ -24,7 +24,7 @@ import { TUI_COPY_RESOURCES } from './tui-copy-catalog.js';
24
24
  const CHROME_ROWS = 2;
25
25
  const MCP_STATUS_COPY = resolveUiMessageCatalog(defineUiMessageCatalog()(TUI_COPY_RESOURCES['mcp-status']));
26
26
  /** One in-frame state machine for status, editing, confirmation, and errors.
27
- * Raw config values live only in the editor and are cleared on every exit;
27
+ * Raw config values live only in the input component and are cleared on every exit;
28
28
  * no management result is written into the conversation transcript. */
29
29
  export class McpManagementOverlay {
30
30
  input;
@@ -100,6 +100,10 @@ export class McpManagementOverlay {
100
100
  else if (this.phase.kind === 'confirm_remove' && matchesKey(data, 'y')) {
101
101
  void this.runAction({ kind: 'remove', serverId: this.phase.serverId });
102
102
  }
103
+ else if (this.phase.kind === 'confirm_remove_publication_credential' &&
104
+ matchesKey(data, 'y')) {
105
+ void this.runAction({ kind: 'remove_publication_credential' });
106
+ }
103
107
  }
104
108
  render(width) {
105
109
  const safeWidth = Math.max(1, width);
@@ -127,7 +131,8 @@ export class McpManagementOverlay {
127
131
  return this.input.surface;
128
132
  }
129
133
  handleListInput(data) {
130
- const servers = this.input.surface?.snapshot().servers ?? [];
134
+ const snapshot = this.input.surface?.snapshot();
135
+ const servers = snapshot?.servers ?? [];
131
136
  if (matchesKey(data, Key.up)) {
132
137
  this.selected = clamp(this.selected - 1, 0, servers.length - 1);
133
138
  }
@@ -146,6 +151,16 @@ export class McpManagementOverlay {
146
151
  this.selected = Math.max(0, servers.length - 1);
147
152
  else if (matchesKey(data, 'a') && this.management())
148
153
  this.phase = { kind: 'add_choice' };
154
+ else if (matchesKey(data, 'p') &&
155
+ this.management() &&
156
+ snapshot?.canManagePublicationCredential) {
157
+ this.startInput('publication_credential');
158
+ }
159
+ else if (matchesKey(data, 'x') &&
160
+ this.management() &&
161
+ snapshot?.canManagePublicationCredential) {
162
+ this.phase = { kind: 'confirm_remove_publication_credential' };
163
+ }
149
164
  else {
150
165
  const server = servers[this.selected];
151
166
  if (!server || !this.management())
@@ -218,7 +233,10 @@ export class McpManagementOverlay {
218
233
  this.clearEditor();
219
234
  this.notice = undefined;
220
235
  this.phase = { kind: 'input', input, draft, serverId, revision };
221
- this.editor = new Editor(this.input.tui, editorTheme(), { paddingX: 0 });
236
+ this.editor =
237
+ input === 'publication_credential'
238
+ ? new MaskedTextInput()
239
+ : new Editor(this.input.tui, editorTheme(), { paddingX: 0 });
222
240
  this.editor.onSubmit = (submitted) => this.submitInput(submitted);
223
241
  this.editor.setText(value);
224
242
  this.editor.focused = true;
@@ -290,6 +308,12 @@ export class McpManagementOverlay {
290
308
  config,
291
309
  });
292
310
  }
311
+ else if (phase.input === 'publication_credential') {
312
+ if (!trimmed)
313
+ throw new Error();
314
+ this.clearEditor();
315
+ void this.runAction({ kind: 'set_publication_credential', credential: trimmed });
316
+ }
293
317
  else {
294
318
  const preview = this.management()?.previewImport(value);
295
319
  if (!preview || preview.status !== 'ready')
@@ -376,6 +400,17 @@ export class McpManagementOverlay {
376
400
  confirmCopy(this.input.locale),
377
401
  ];
378
402
  }
403
+ if (this.phase.kind === 'confirm_remove_publication_credential') {
404
+ return [
405
+ heading(this.input.locale, 'Remove the remote provider credential?', '删除远程 Provider 凭据?'),
406
+ '',
407
+ this.input.locale === 'zh'
408
+ ? '这会停止向所选 Runtime Host 发布 MCP 工具。'
409
+ : 'This stops publishing MCP tools to the selected Runtime Host.',
410
+ '',
411
+ confirmCopy(this.input.locale),
412
+ ];
413
+ }
379
414
  if (this.phase.kind === 'busy')
380
415
  return [ansi.yellow(this.phase.label)];
381
416
  const lines = [publicationLine(snapshot, this.input.locale)];
@@ -421,7 +456,9 @@ export class McpManagementOverlay {
421
456
  return copy.back;
422
457
  if (!this.management())
423
458
  return copy.readOnly;
424
- return copy.manage;
459
+ return this.input.surface?.snapshot().canManagePublicationCredential
460
+ ? copy.managePublication
461
+ : copy.manage;
425
462
  }
426
463
  backToList(clearNotice = true) {
427
464
  if (this.phase.kind === 'confirm_import') {
@@ -481,6 +518,40 @@ export class McpManagementOverlay {
481
518
  return Math.max(0, this.documentRows - this.bodyRows);
482
519
  }
483
520
  }
521
+ class MaskedTextInput {
522
+ #input = new Input();
523
+ onSubmit;
524
+ onChange;
525
+ constructor() {
526
+ this.#input.onSubmit = (value) => this.onSubmit?.(value);
527
+ }
528
+ get focused() {
529
+ return this.#input.focused;
530
+ }
531
+ set focused(value) {
532
+ this.#input.focused = value;
533
+ }
534
+ setText(value) {
535
+ this.#input.setValue(value);
536
+ }
537
+ handleInput(data) {
538
+ this.#input.handleInput(data);
539
+ this.onChange?.(this.#input.getValue());
540
+ }
541
+ invalidate() {
542
+ this.#input.invalidate();
543
+ }
544
+ render(width) {
545
+ const value = this.#input.getValue();
546
+ this.#input.setValue('•'.repeat(value.length));
547
+ try {
548
+ return this.#input.render(width);
549
+ }
550
+ finally {
551
+ this.#input.setValue(value);
552
+ }
553
+ }
554
+ }
484
555
  function normalizeOneServer(serverId, source) {
485
556
  const value = JSON.parse(source);
486
557
  return normalizeMcpConfig({ version: 3, mcpServers: { [serverId]: value } }).mcpServers[serverId];
@@ -573,6 +644,7 @@ function copy(locale, key) {
573
644
  closed: 'The MCP controller is closed.',
574
645
  'invalid-config': 'The server configuration is invalid.',
575
646
  'credential-cleanup-failed': 'Stored credentials could not be removed; the configuration was not changed.',
647
+ 'publication-credential-failed': 'The provider credential could not be stored or applied.',
576
648
  'persist-failed': 'The configuration could not be saved.',
577
649
  'manager-failed': 'The MCP connection action failed.',
578
650
  turn_active: 'MCP cannot be changed while a turn or another control action is running.',
@@ -595,6 +667,7 @@ function copy(locale, key) {
595
667
  closed: 'MCP 控制器已关闭。',
596
668
  'invalid-config': '服务器配置无效。',
597
669
  'credential-cleanup-failed': '无法删除旧凭据,配置未修改。',
670
+ 'publication-credential-failed': '无法保存或应用 Provider 凭据。',
598
671
  'persist-failed': '无法保存配置。',
599
672
  'manager-failed': 'MCP 连接操作失败。',
600
673
  turn_active: 'Turn 或其他控制操作运行期间不能修改 MCP。',
@@ -649,6 +722,7 @@ function inputLabel(kind, locale) {
649
722
  headers: ['Request headers', '请求头'],
650
723
  edit: ['Edit server JSON', '编辑服务器 JSON'],
651
724
  import: ['Paste MCP JSON', '粘贴 MCP JSON'],
725
+ publication_credential: ['Provider credential', 'Provider 凭据'],
652
726
  };
653
727
  return labels[kind][locale === 'zh' ? 1 : 0];
654
728
  }
@@ -660,6 +734,11 @@ function inputHint(kind, locale) {
660
734
  return `JSON string map, ${optional}`;
661
735
  if (kind === 'cwd')
662
736
  return optional;
737
+ if (kind === 'publication_credential') {
738
+ return locale === 'zh'
739
+ ? '仅保存到本机凭据存储;不会写入 profile、参数或对话 · Enter 提交 · Esc 返回'
740
+ : 'Stored only in the local credential store; never written to profiles, arguments, or chat · Enter submit · Esc back';
741
+ }
663
742
  return locale === 'zh' ? 'Enter 提交 · Esc 返回' : 'Enter submit · Esc back';
664
743
  }
665
744
  function configurationLine(state, locale) {
@@ -124,6 +124,10 @@ export async function connectRuntimeHostCli(input, overrides = {}) {
124
124
  connection: liveConnection,
125
125
  catalog: await deps.readConnectionCatalog(liveConnection),
126
126
  profile,
127
+ clientInstanceId,
128
+ ...(resolvedProfile.profileIncarnationId
129
+ ? { profileIncarnationId: resolvedProfile.profileIncarnationId }
130
+ : {}),
127
131
  close: async () => {
128
132
  try {
129
133
  await liveConnection.close();
@@ -28,6 +28,7 @@ import { connectRuntimeHostCli, readHostChatDefaultPermissionMode, resolveRuntim
28
28
  import { createRuntimeHostMakaSessionDriver, } from './runtime-host-session-driver.js';
29
29
  import { createRuntimeHostOnboardingSurface, projectRuntimeHostConnectionIdentities, projectRuntimeHostModelChoices, } from './runtime-host-onboarding.js';
30
30
  import { createTuiMcpController, } from './tui-mcp-control.js';
31
+ import { createRemoteTuiMcpPublicationTarget } from './tui-mcp-remote-publication.js';
31
32
  export async function createRuntimeHostTuiContext(input) {
32
33
  const connected = await connectRuntimeHostCli({
33
34
  clientDataRoot: input.clientDataRoot,
@@ -70,7 +71,7 @@ export async function createRuntimeHostTuiContext(input) {
70
71
  };
71
72
  const driver = createRuntimeHostMakaSessionDriver(driverInput);
72
73
  await driver.recoverSideConversations();
73
- if (!runtimeHostProfileUsesHostWorkspace(connected.profile.kind)) {
74
+ if (connected.profile.kind === 'local') {
74
75
  if (!isRuntimeHostReconnectingConnection(connection)) {
75
76
  throw new Error('Local Runtime Host TUI connection is not reconnectable');
76
77
  }
@@ -79,6 +80,20 @@ export async function createRuntimeHostTuiContext(input) {
79
80
  connection,
80
81
  });
81
82
  }
83
+ else if (connected.profile.kind === 'remote') {
84
+ if (!connected.profileIncarnationId) {
85
+ throw new Error('Remote Runtime Host profile incarnation is unavailable');
86
+ }
87
+ mcp = createTuiMcpController({
88
+ workspaceRoot: input.rootPath,
89
+ connection: createRemoteTuiMcpPublicationTarget({
90
+ clientDataRoot: input.clientDataRoot,
91
+ profile: connected.profile,
92
+ profileIncarnationId: connected.profileIncarnationId,
93
+ ownerClientInstanceId: connected.clientInstanceId,
94
+ }),
95
+ });
96
+ }
82
97
  const modelContextWindow = selectedTarget.connection?.models.find((model) => model.id === selectedTarget.model)?.contextWindow;
83
98
  return {
84
99
  connection,
@@ -24,6 +24,7 @@ export const TUI_COPY_RESOURCES = {
24
24
  back: 'Esc back',
25
25
  readOnly: '↑/↓ scroll · q/Esc close',
26
26
  manage: 'a Add · Enter Edit · Space Enable/disable · t Test · r Reconnect · d Remove · Esc Close',
27
+ managePublication: 'a Add · Enter Edit · Space Enable/disable · t Test · r Reconnect · d Remove · p Set provider credential · x Remove credential · Esc Close',
27
28
  },
28
29
  unavailableTitle: 'This TUI is not connected to a local MCP control plane.',
29
30
  unavailableDetail: 'Client MCP tool association for remote Runtime Hosts is planned for a later release.',
@@ -33,6 +34,10 @@ export const TUI_COPY_RESOURCES = {
33
34
  publication: {
34
35
  waiting: 'waiting to publish',
35
36
  host_unavailable: 'Runtime Host reconnecting',
37
+ credential_required: 'provider credential required',
38
+ credential_rejected: 'provider credential rejected',
39
+ provider_conflict: 'provider active in another TUI',
40
+ target_mismatch: 'provider target mismatch',
36
41
  publishing: 'publishing',
37
42
  published: 'published',
38
43
  not_published: 'not published',
@@ -56,6 +61,7 @@ export const TUI_COPY_RESOURCES = {
56
61
  back: 'Esc 返回',
57
62
  readOnly: '↑/↓ 滚动 · q/Esc 关闭',
58
63
  manage: 'a 添加 · Enter 编辑 · Space 启用/停用 · t 测试 · r 重连 · d 删除 · Esc 关闭',
64
+ managePublication: 'a 添加 · Enter 编辑 · Space 启用/停用 · t 测试 · r 重连 · d 删除 · p 设置 Provider 凭据 · x 删除凭据 · Esc 关闭',
59
65
  },
60
66
  unavailableTitle: '当前 TUI 未连接本地 MCP 控制面。',
61
67
  unavailableDetail: '远程 Runtime Host 的客户端 MCP 工具关联将在后续版本提供。',
@@ -65,6 +71,10 @@ export const TUI_COPY_RESOURCES = {
65
71
  publication: {
66
72
  waiting: '等待发布',
67
73
  host_unavailable: 'Runtime Host 重连中',
74
+ credential_required: '需要 Provider 凭据',
75
+ credential_rejected: 'Provider 凭据已被拒绝',
76
+ provider_conflict: 'Provider 已在另一个 TUI 中运行',
77
+ target_mismatch: 'Provider 目标不匹配',
68
78
  publishing: '正在发布',
69
79
  published: '已发布',
70
80
  not_published: '未发布',
@@ -56,12 +56,17 @@ class TuiMcpControllerImpl {
56
56
  initialization: 'loading',
57
57
  configuration: 'synchronizing',
58
58
  publication: 'waiting',
59
+ canManagePublicationCredential: false,
59
60
  toolCount: 0,
60
61
  servers: [],
61
62
  });
62
63
  constructor(connection, deps) {
63
64
  this.#connection = connection;
64
65
  this.#deps = deps;
66
+ this.#snapshot = freezeSnapshot({
67
+ ...this.#snapshot,
68
+ canManagePublicationCredential: Boolean(connection.setCredential && connection.removeCredential),
69
+ });
65
70
  this.#disposeManagerChange = deps.manager.onChange(() => {
66
71
  try {
67
72
  this.#refreshManagerSnapshot();
@@ -77,7 +82,12 @@ class TuiMcpControllerImpl {
77
82
  this.#availability = availability;
78
83
  if (availability.kind === 'unavailable') {
79
84
  this.#published = undefined;
80
- this.#updateSnapshot({ publication: 'host_unavailable' });
85
+ this.#updateSnapshot({
86
+ publication: availability.reason ?? 'host_unavailable',
87
+ ...(availability.reason === 'provider_conflict'
88
+ ? { canManagePublicationCredential: false }
89
+ : {}),
90
+ });
81
91
  }
82
92
  else {
83
93
  this.#updateSnapshot({ publication: 'waiting' });
@@ -160,6 +170,7 @@ class TuiMcpControllerImpl {
160
170
  await this.#connection.unregisterClientCapabilities().catch(() => undefined);
161
171
  }
162
172
  this.#published = undefined;
173
+ await this.#connection.closePublication?.().catch(() => undefined);
163
174
  await managerClosing;
164
175
  await this.#initialization.catch(() => undefined);
165
176
  }
@@ -189,6 +200,30 @@ class TuiMcpControllerImpl {
189
200
  async #executeAction(action) {
190
201
  if (this.#closed)
191
202
  return { status: 'failed', reason: 'closed' };
203
+ if (action.kind === 'set_publication_credential') {
204
+ if (!this.#connection.setCredential) {
205
+ return { status: 'failed', reason: 'publication-credential-failed' };
206
+ }
207
+ try {
208
+ await this.#connection.setCredential(action.credential);
209
+ return { status: 'applied', effect: await this.#settlePublication() };
210
+ }
211
+ catch {
212
+ return { status: 'failed', reason: 'publication-credential-failed' };
213
+ }
214
+ }
215
+ if (action.kind === 'remove_publication_credential') {
216
+ if (!this.#connection.removeCredential) {
217
+ return { status: 'failed', reason: 'publication-credential-failed' };
218
+ }
219
+ try {
220
+ await this.#connection.removeCredential();
221
+ return { status: 'applied', effect: 'pending_host' };
222
+ }
223
+ catch {
224
+ return { status: 'failed', reason: 'publication-credential-failed' };
225
+ }
226
+ }
192
227
  if (action.kind === 'test') {
193
228
  try {
194
229
  const test = await this.#deps.manager.test(action.serverId);
@@ -334,10 +369,16 @@ class TuiMcpControllerImpl {
334
369
  while (!this.#closed && (this.#publicationTask || this.#publicationRequested)) {
335
370
  await this.#publicationTask?.catch(() => undefined);
336
371
  }
337
- if (this.#snapshot.publication === 'error')
372
+ if (this.#snapshot.publication === 'error' ||
373
+ this.#snapshot.publication === 'credential_rejected' ||
374
+ this.#snapshot.publication === 'provider_conflict' ||
375
+ this.#snapshot.publication === 'target_mismatch') {
338
376
  return 'publication_failed';
339
- if (this.#snapshot.publication === 'host_unavailable')
377
+ }
378
+ if (this.#snapshot.publication === 'host_unavailable' ||
379
+ this.#snapshot.publication === 'credential_required') {
340
380
  return 'pending_host';
381
+ }
341
382
  return 'published';
342
383
  }
343
384
  #refreshManagerSnapshot(initialization = this.#snapshot.initialization, configuration = this.#snapshot.configuration) {
@@ -351,6 +392,7 @@ class TuiMcpControllerImpl {
351
392
  initialization,
352
393
  configuration,
353
394
  publication: this.#snapshot.publication,
395
+ canManagePublicationCredential: this.#snapshot.canManagePublicationCredential,
354
396
  toolCount: this.#deps.manager.toolSnapshot().tools.length,
355
397
  servers: [...serverIds]
356
398
  .sort((left, right) => left.localeCompare(right))
@@ -383,7 +425,7 @@ class TuiMcpControllerImpl {
383
425
  async #publishCurrentSnapshot() {
384
426
  const availability = this.#availability;
385
427
  if (availability.kind !== 'connected') {
386
- this.#updateSnapshot({ publication: 'host_unavailable' });
428
+ this.#updateSnapshot({ publication: availability.reason ?? 'host_unavailable' });
387
429
  return;
388
430
  }
389
431
  const identity = connectionIdentity(availability);