maka-agent 0.2.0-dev.25.20260908 → 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.
- package/dist/mcp-capability-provider.js +4 -1
- package/dist/pi-tui-mcp-status.js +2 -2
- package/dist/pi-tui-pickers.js +19 -29
- package/dist/tui-autocomplete-layout.js +3 -1
- package/dist/tui-copy-catalog.js +6 -3
- package/dist/tui-editor-render.js +36 -0
- package/dist/tui-mcp-control.js +41 -6
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/runtime-event.js +3 -0
- package/node_modules/@maka/core/dist/session.js +29 -4
- package/node_modules/@maka/core/dist/workhub-action-result.js +68 -0
- package/node_modules/@maka/core/package.json +2 -3
- package/node_modules/@maka/eval/dist/toolchain-verification.js +1 -1
- package/node_modules/@maka/mcp/dist/form-elicitation.js +213 -0
- package/node_modules/@maka/mcp/dist/index.js +337 -71
- package/node_modules/@maka/runtime/dist/agent-run.js +10 -1
- package/node_modules/@maka/runtime/dist/goal-continuation.js +5 -1
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +20 -1
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +120 -13
- package/node_modules/@maka/runtime/dist/session-manager.js +20 -36
- package/node_modules/@maka/runtime-host/dist/client/connection.js +30 -5
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +17 -1
- package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +4 -2
- package/node_modules/@maka/runtime-host/dist/client/peer-client.js +18 -1
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +5 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +3 -2
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/workhub-coordination.js +68 -168
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/canonical-session-projection.js +2 -1
- package/node_modules/@maka/runtime-host/dist/server/connection-session.js +28 -8
- package/node_modules/@maka/runtime-host/dist/server/daily-review-coordinator.js +112 -56
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +45 -20
- package/node_modules/@maka/runtime-host/dist/server/failure-diagnostic.js +24 -0
- package/node_modules/@maka/runtime-host/dist/server/goal-coordinator.js +7 -3
- package/node_modules/@maka/runtime-host/dist/server/host-kernel.js +3 -3
- package/node_modules/@maka/runtime-host/dist/server/host-session-availability.js +5 -2
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +3 -2
- package/node_modules/@maka/runtime-host/dist/server/hosted-execution-tool-profile.js +34 -4
- package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +4 -1
- package/node_modules/@maka/runtime-host/dist/server/operation-dispatcher.js +2 -7
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +110 -14
- package/node_modules/@maka/runtime-host/dist/server/runtime-resource-coordinator.js +11 -8
- package/node_modules/@maka/runtime-host/dist/server/scheduled-task-coordinator.js +31 -21
- package/node_modules/@maka/runtime-host/dist/server/serial-outbound-writer.js +1 -1
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +20 -8
- package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +15 -104
- package/node_modules/@maka/runtime-host/dist/server/shared-session-transcript.js +3 -0
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-action-gate.js +44 -85
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +120 -137
- package/node_modules/@maka/storage/dist/agent-run-store.js +14 -1
- package/node_modules/@maka/storage/dist/artifact-store.js +40 -3
- package/node_modules/@maka/storage/dist/atomic-file-write.js +74 -0
- package/node_modules/@maka/storage/dist/credential-store.js +12 -63
- package/node_modules/@maka/storage/dist/execution-stores.js +4 -1
- package/node_modules/@maka/storage/dist/mcp-config-store.js +10 -25
- package/node_modules/@maka/storage/dist/session-store.js +14 -2
- package/node_modules/@maka/storage/dist/settings-store.js +8 -4
- package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +11 -0
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-schema.js +12 -1
- package/node_modules/@maka/storage/dist/sqlite-session-metadata-store.js +67 -3
- package/node_modules/@maka/storage/dist/stable-storage.js +14 -1
- package/package.json +1 -1
- package/node_modules/@maka/core/dist/workhub-creation-intent.js +0 -990
- package/node_modules/@maka/core/dist/workhub-session-resolver.js +0 -50
|
@@ -73,7 +73,10 @@ export function createMcpCapabilityProvider(manager) {
|
|
|
73
73
|
if (!binding)
|
|
74
74
|
throw new Error('MCP capability is not part of the published snapshot');
|
|
75
75
|
await options.accept({ kind: 'none' });
|
|
76
|
-
return projectMcpResult(await manager.callTool(binding, frame.arguments, {
|
|
76
|
+
return projectMcpResult(await manager.callTool(binding, frame.arguments, {
|
|
77
|
+
signal: options.signal,
|
|
78
|
+
requestInteraction: options.requestInteraction,
|
|
79
|
+
}));
|
|
77
80
|
},
|
|
78
81
|
};
|
|
79
82
|
}
|
|
@@ -210,7 +210,7 @@ export class McpManagementOverlay {
|
|
|
210
210
|
return;
|
|
211
211
|
const protocol = matchesKey(data, '1')
|
|
212
212
|
? 'legacy'
|
|
213
|
-
: matchesKey(data, '2')
|
|
213
|
+
: matchesKey(data, '2') || matchesKey(data, 'enter')
|
|
214
214
|
? 'auto'
|
|
215
215
|
: matchesKey(data, '3')
|
|
216
216
|
? '2026-07-28'
|
|
@@ -371,7 +371,7 @@ export class McpManagementOverlay {
|
|
|
371
371
|
return [ansi.bold(editor.transportTitle), '', '1 stdio', '2 Streamable HTTP'];
|
|
372
372
|
}
|
|
373
373
|
if (this.phase.kind === 'protocol') {
|
|
374
|
-
return [ansi.bold(editor.protocolTitle), '', '1 legacy', '2 auto', '3 2026-07-28'];
|
|
374
|
+
return [ansi.bold(editor.protocolTitle), '', '1 legacy', '2 auto (Enter)', '3 2026-07-28'];
|
|
375
375
|
}
|
|
376
376
|
if (this.phase.kind === 'confirm_add') {
|
|
377
377
|
return confirmAddDocument(this.phase.draft, this.input.locale);
|
package/dist/pi-tui-pickers.js
CHANGED
|
@@ -21,6 +21,7 @@ import { defineUiMessageCatalog, formatUiMessage, resolveUiMessageCatalog, } fro
|
|
|
21
21
|
import { providerDefaultsOf, validateSlug, } from '@maka/core/llm-connections';
|
|
22
22
|
import { CONNECTION_NAME_MAX_LENGTH } from '@maka/core/runtime-policy';
|
|
23
23
|
import { ansi, editorTheme, selectListTheme, stripAnsi } from './tui-ansi.js';
|
|
24
|
+
import { stripUnfocusedCursorStyle } from './tui-editor-render.js';
|
|
24
25
|
import { TUI_COPY_RESOURCES } from './tui-copy-catalog.js';
|
|
25
26
|
const TUI_PICKER_COPY = resolveUiMessageCatalog(defineUiMessageCatalog()(TUI_COPY_RESOURCES.pickers));
|
|
26
27
|
export function onboardingFailureMessage(failure, locale) {
|
|
@@ -433,22 +434,13 @@ export class UserQuestionOverlay {
|
|
|
433
434
|
return assemble(cappedTitle, optionRows.map((rows) => clampRowsWithEllipsis(rows, perOption, safeWidth)));
|
|
434
435
|
}
|
|
435
436
|
renderInputRow(width) {
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
// Focused only while the input row is highlighted: that both shows the block
|
|
439
|
-
// cursor and emits the hardware-cursor marker (#1064) so IME candidate windows
|
|
440
|
-
// anchor to the edited text instead of the terminal bottom.
|
|
437
|
+
const marker = this.onInputRow ? '→' : ' ';
|
|
438
|
+
// Focus controls the IME marker and our cursor-visibility adapter (#1064).
|
|
441
439
|
this.editor.focused = this.onInputRow;
|
|
442
440
|
if (!this.onInputRow && this.editor.getText().length === 0) {
|
|
443
|
-
return [padLine(`${
|
|
441
|
+
return [padLine(`${marker} ${ansi.dim(this.input.placeholder)}`, width)];
|
|
444
442
|
}
|
|
445
|
-
|
|
446
|
-
// so the answer reads as one row of the list.
|
|
447
|
-
const editorLines = this.editor.render(contentWidth).slice(1, -1);
|
|
448
|
-
if (editorLines.length === 0) {
|
|
449
|
-
return [padLine(`${prefix}${ansi.dim(this.input.placeholder)}`, width)];
|
|
450
|
-
}
|
|
451
|
-
return editorLines.map((line, index) => padLine(`${index === 0 ? prefix : ' '}${line}`, width));
|
|
443
|
+
return renderFieldRow(this.editor, marker, width);
|
|
452
444
|
}
|
|
453
445
|
}
|
|
454
446
|
export function modelPickerItems(currentModel, models, locale) {
|
|
@@ -750,14 +742,7 @@ export class ModelSearchOverlay {
|
|
|
750
742
|
];
|
|
751
743
|
}
|
|
752
744
|
renderFieldRow(editor, label, width) {
|
|
753
|
-
|
|
754
|
-
const prefixWidth = visibleWidth(prefix);
|
|
755
|
-
const contentWidth = Math.max(1, width - prefixWidth);
|
|
756
|
-
const editorLines = editor.render(contentWidth).slice(1, -1);
|
|
757
|
-
if (editorLines.length === 0) {
|
|
758
|
-
return [padLine(prefix, width)];
|
|
759
|
-
}
|
|
760
|
-
return editorLines.map((line, index) => padLine(`${index === 0 ? prefix : ' '.repeat(prefixWidth)}${line}`, width));
|
|
745
|
+
return renderFieldRow(editor, label, width);
|
|
761
746
|
}
|
|
762
747
|
}
|
|
763
748
|
/**
|
|
@@ -873,6 +858,18 @@ function padLine(text, width) {
|
|
|
873
858
|
const trimmed = visibleWidth(text) > safeWidth ? truncateToWidth(text, safeWidth, '') : text;
|
|
874
859
|
return `${trimmed}${' '.repeat(Math.max(0, safeWidth - visibleWidth(trimmed)))}`;
|
|
875
860
|
}
|
|
861
|
+
function renderFieldRow(editor, label, width) {
|
|
862
|
+
const prefix = `${label} `;
|
|
863
|
+
const prefixWidth = visibleWidth(prefix);
|
|
864
|
+
const contentWidth = Math.max(1, width - prefixWidth);
|
|
865
|
+
// These field editors have no autocomplete rows. Keep Editor's wrapping and
|
|
866
|
+
// scrolling, but omit its top/bottom borders.
|
|
867
|
+
const lines = editor.render(contentWidth).slice(1, -1);
|
|
868
|
+
const editorLines = stripUnfocusedCursorStyle(lines, editor.focused);
|
|
869
|
+
if (editorLines.length === 0)
|
|
870
|
+
return [padLine(prefix, width)];
|
|
871
|
+
return editorLines.map((line, index) => padLine(`${index === 0 ? prefix : ' '.repeat(prefixWidth)}${line}`, width));
|
|
872
|
+
}
|
|
876
873
|
function keyEntryHint(copy, hasConnection, returnsTo) {
|
|
877
874
|
const action = hasConnection ? 'reuse' : 'enter';
|
|
878
875
|
return copy.keyHints[action][returnsTo];
|
|
@@ -1546,13 +1543,6 @@ export class OnboardingWizard {
|
|
|
1546
1543
|
];
|
|
1547
1544
|
}
|
|
1548
1545
|
renderFieldRow(editor, label, width) {
|
|
1549
|
-
|
|
1550
|
-
const prefixWidth = visibleWidth(prefix);
|
|
1551
|
-
const contentWidth = Math.max(1, width - prefixWidth);
|
|
1552
|
-
const editorLines = editor.render(contentWidth).slice(1, -1);
|
|
1553
|
-
if (editorLines.length === 0) {
|
|
1554
|
-
return [padLine(prefix, width)];
|
|
1555
|
-
}
|
|
1556
|
-
return editorLines.map((line, index) => padLine(`${index === 0 ? prefix : ' '.repeat(prefixWidth)}${line}`, width));
|
|
1546
|
+
return renderFieldRow(editor, label, width);
|
|
1557
1547
|
}
|
|
1558
1548
|
}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
import { selectListTheme, stripAnsi } from './tui-ansi.js';
|
|
20
|
+
import { stripUnfocusedCursorStyle } from './tui-editor-render.js';
|
|
20
21
|
export function arrangeAutocompleteAboveEditor(input) {
|
|
21
22
|
if (!input.autocompleteShowing) {
|
|
22
23
|
return { lines: input.lines, autocompleteSlotRows: 0, editorRows: input.lines.length };
|
|
@@ -72,7 +73,8 @@ export class MakaAutocompleteAboveEditorComponent {
|
|
|
72
73
|
this.editor.handleInput(data);
|
|
73
74
|
}
|
|
74
75
|
render(width) {
|
|
75
|
-
const
|
|
76
|
+
const renderedLines = this.editor.render(width);
|
|
77
|
+
const lines = stripUnfocusedCursorStyle(renderedLines, this.editor.focused);
|
|
76
78
|
const result = arrangeAutocompleteAboveEditor({
|
|
77
79
|
lines,
|
|
78
80
|
autocompleteShowing: this.editor.isShowingAutocomplete(),
|
package/dist/tui-copy-catalog.js
CHANGED
|
@@ -326,6 +326,7 @@ export const TUI_COPY_RESOURCES = {
|
|
|
326
326
|
'credential-cleanup-failed': 'Stored credentials could not be removed; the configuration was not changed.',
|
|
327
327
|
'publication-credential-failed': 'The provider credential could not be stored or applied.',
|
|
328
328
|
'persist-failed': 'The configuration could not be saved.',
|
|
329
|
+
'commit-unknown': 'Configuration published; crash durability is uncertain. Check synchronization before retrying.',
|
|
329
330
|
'manager-failed': 'The MCP connection action failed.',
|
|
330
331
|
turn_active: 'MCP cannot be changed while a turn or another control action is running.',
|
|
331
332
|
invalid: 'Check the value and try again.',
|
|
@@ -424,6 +425,7 @@ export const TUI_COPY_RESOURCES = {
|
|
|
424
425
|
'credential-cleanup-failed': '无法删除旧凭据,配置未修改。',
|
|
425
426
|
'publication-credential-failed': '无法保存或应用 Provider 凭据。',
|
|
426
427
|
'persist-failed': '无法保存配置。',
|
|
428
|
+
'commit-unknown': '配置已发布,但无法确认崩溃后的持久性。请先检查同步状态再重试。',
|
|
427
429
|
'manager-failed': 'MCP 连接操作失败。',
|
|
428
430
|
turn_active: 'Turn 或其他控制操作运行期间不能修改 MCP。',
|
|
429
431
|
invalid: '请检查输入后重试。',
|
|
@@ -522,6 +524,7 @@ export const TUI_COPY_RESOURCES = {
|
|
|
522
524
|
'credential-cleanup-failed': '無法移除已儲存的認證資料;設定未變更。',
|
|
523
525
|
'publication-credential-failed': '無法儲存或套用 Provider 認證資料。',
|
|
524
526
|
'persist-failed': '無法儲存設定。',
|
|
527
|
+
'commit-unknown': '設定已發布,但無法確認當機後的持久性。請先檢查同步狀態再重試。',
|
|
525
528
|
'manager-failed': 'MCP 連線操作失敗。',
|
|
526
529
|
turn_active: 'Turn 或其他控制操作執行期間無法修改 MCP。',
|
|
527
530
|
invalid: '請檢查輸入後重試。',
|
|
@@ -620,7 +623,7 @@ export const TUI_COPY_RESOURCES = {
|
|
|
620
623
|
pickers: {
|
|
621
624
|
en: {
|
|
622
625
|
modelPickerTitle: 'Select Model',
|
|
623
|
-
modelSwitchCacheWarning: '
|
|
626
|
+
modelSwitchCacheWarning: '\u26a0 Switching models may rebuild the prompt cache; the next request may be slower or cost more.',
|
|
624
627
|
modelSearchHint: 'Search models / providers / connections · ↑↓ select · Enter confirm · Esc cancel',
|
|
625
628
|
searchLabel: 'Search',
|
|
626
629
|
noMatchingModels: 'No matching models',
|
|
@@ -715,7 +718,7 @@ export const TUI_COPY_RESOURCES = {
|
|
|
715
718
|
},
|
|
716
719
|
'zh-CN': {
|
|
717
720
|
modelPickerTitle: '选择模型',
|
|
718
|
-
modelSwitchCacheWarning: '
|
|
721
|
+
modelSwitchCacheWarning: '\u26a0 切换模型可能需要重建提示缓存;下一次请求可能更慢或成本更高。',
|
|
719
722
|
modelSearchHint: '搜索模型 / 服务商 / 连接 · ↑↓ 选择 · Enter 确认 · Esc 取消',
|
|
720
723
|
searchLabel: '搜索',
|
|
721
724
|
noMatchingModels: '没有匹配的模型',
|
|
@@ -809,7 +812,7 @@ export const TUI_COPY_RESOURCES = {
|
|
|
809
812
|
},
|
|
810
813
|
'zh-TW': {
|
|
811
814
|
modelPickerTitle: '選擇模型',
|
|
812
|
-
modelSwitchCacheWarning: '
|
|
815
|
+
modelSwitchCacheWarning: '\u26a0 切換模型可能需要重建提示快取;下一次請求可能較慢或成本較高。',
|
|
813
816
|
modelSearchHint: '搜尋模型 / 服務商 / 連線 · ↑↓ 選擇 · Enter 確認 · Esc 取消',
|
|
814
817
|
searchLabel: '搜尋',
|
|
815
818
|
noMatchingModels: '沒有符合的模型',
|
|
@@ -0,0 +1,36 @@
|
|
|
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
|
+
export function stripUnfocusedCursorStyle(lines, focused) {
|
|
20
|
+
if (focused)
|
|
21
|
+
return lines;
|
|
22
|
+
// pi-tui 0.84.4 paints its cursor even when the editor is unfocused.
|
|
23
|
+
// Remove the reverse-video wrapper, keeping the captured text ($1):
|
|
24
|
+
//
|
|
25
|
+
// Input: \x1b[7mhello\x1b[0m
|
|
26
|
+
// └─────┘└───┘└─────┘
|
|
27
|
+
// reverse text reset
|
|
28
|
+
// remove keep remove
|
|
29
|
+
// $1
|
|
30
|
+
// Output: hello
|
|
31
|
+
//
|
|
32
|
+
// ([^\x1b]*) captures text without ESC, so the match cannot cross another
|
|
33
|
+
// ANSI sequence. Other text using this same wrapper would also lose its
|
|
34
|
+
// reverse styling. Recheck when changing themes or upgrading pi-tui.
|
|
35
|
+
return lines.map((line) => line.replace(/\x1b\[7m([^\x1b]*)\x1b\[0m/gu, '$1'));
|
|
36
|
+
}
|
package/dist/tui-mcp-control.js
CHANGED
|
@@ -20,7 +20,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
20
20
|
import { MCP_CONFIG_VERSION, mcpConfigChangeRetiresCredentials, resolveMcpProtocolPreference, } from '@maka/core/mcp';
|
|
21
21
|
import { createCredentialMcpOAuthStorage, McpClientManager } from '@maka/mcp';
|
|
22
22
|
import { createFileCredentialStore } from '@maka/storage/credential-store';
|
|
23
|
-
import { createMcpConfigStore, assertMcpEndpointPolicyOnChanges, McpConfigSourceError, normalizeMcpConfig, normalizeMcpImport, } from '@maka/storage/mcp-config-store';
|
|
23
|
+
import { AtomicFileWriteCommitUnknownError, createMcpConfigStore, assertMcpEndpointPolicyOnChanges, McpConfigSourceError, normalizeMcpConfig, normalizeMcpImport, } from '@maka/storage/mcp-config-store';
|
|
24
24
|
import { createMcpCapabilityProvider } from './mcp-capability-provider.js';
|
|
25
25
|
const RUNTIME_HOST_CREDENTIAL_ENV = 'MAKA_RUNTIME_HOST_ACCESS_CREDENTIAL';
|
|
26
26
|
export function createTuiMcpController(input, overrides = {}) {
|
|
@@ -289,10 +289,45 @@ class TuiMcpControllerImpl {
|
|
|
289
289
|
catch (error) {
|
|
290
290
|
if (error instanceof TuiMcpMutationError)
|
|
291
291
|
return error.result;
|
|
292
|
+
if (error instanceof AtomicFileWriteCommitUnknownError) {
|
|
293
|
+
// The transform has already published, including any credential
|
|
294
|
+
// retirement. Reload its authority; never replay those effects.
|
|
295
|
+
this.#preparedImport = undefined;
|
|
296
|
+
let reconciliationError;
|
|
297
|
+
if (!this.#closed) {
|
|
298
|
+
try {
|
|
299
|
+
({ reconciliationError } = await this.#synchronizeCommittedConfig(await this.#deps.configStore.get()));
|
|
300
|
+
}
|
|
301
|
+
catch (failure) {
|
|
302
|
+
reconciliationError = failure;
|
|
303
|
+
this.#publicationSuppressed = false;
|
|
304
|
+
this.#snapshot = freezeSnapshot({
|
|
305
|
+
...this.#snapshot,
|
|
306
|
+
configuration: 'out_of_sync',
|
|
307
|
+
servers: this.#snapshot.servers.map((server) => ({
|
|
308
|
+
...server,
|
|
309
|
+
synchronized: false,
|
|
310
|
+
})),
|
|
311
|
+
});
|
|
312
|
+
this.#notify();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Reconciliation does not establish the missing durability fence,
|
|
316
|
+
// and its own failure must not replace the original write error.
|
|
317
|
+
return {
|
|
318
|
+
status: 'failed',
|
|
319
|
+
reason: 'commit-unknown',
|
|
320
|
+
cause: error,
|
|
321
|
+
...(reconciliationError === undefined ? {} : { reconciliationError }),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
292
324
|
return { status: 'failed', reason: 'persist-failed' };
|
|
293
325
|
}
|
|
326
|
+
return (await this.#synchronizeCommittedConfig(committed)).result;
|
|
327
|
+
}
|
|
328
|
+
async #synchronizeCommittedConfig(committed) {
|
|
294
329
|
if (this.#closed)
|
|
295
|
-
return { status: 'failed', reason: 'closed' };
|
|
330
|
+
return { result: { status: 'failed', reason: 'closed' } };
|
|
296
331
|
this.#preparedImport = undefined;
|
|
297
332
|
this.#config = cloneConfig(committed);
|
|
298
333
|
this.#updateSnapshot({ configuration: 'synchronizing' });
|
|
@@ -301,19 +336,19 @@ class TuiMcpControllerImpl {
|
|
|
301
336
|
try {
|
|
302
337
|
await this.#deps.manager.sync(committed);
|
|
303
338
|
}
|
|
304
|
-
catch {
|
|
339
|
+
catch (error) {
|
|
305
340
|
this.#publicationSuppressed = false;
|
|
306
341
|
this.#updateSnapshot({ configuration: 'out_of_sync' });
|
|
307
342
|
this.#refreshManagerSnapshot();
|
|
308
343
|
await this.#settlePublication();
|
|
309
|
-
return { status: 'applied', effect: 'sync_failed' };
|
|
344
|
+
return { result: { status: 'applied', effect: 'sync_failed' }, reconciliationError: error };
|
|
310
345
|
}
|
|
311
346
|
this.#publicationSuppressed = false;
|
|
312
347
|
if (this.#closed)
|
|
313
|
-
return { status: 'failed', reason: 'closed' };
|
|
348
|
+
return { result: { status: 'failed', reason: 'closed' } };
|
|
314
349
|
this.#updateSnapshot({ configuration: 'ready' });
|
|
315
350
|
this.#refreshManagerSnapshot();
|
|
316
|
-
return { status: 'applied', effect: await this.#settlePublication() };
|
|
351
|
+
return { result: { status: 'applied', effect: await this.#settlePublication() } };
|
|
317
352
|
}
|
|
318
353
|
#prepareMutation(current, action) {
|
|
319
354
|
const servers = { ...current.mcpServers };
|
|
Binary file
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
* Phase 1 scope: types + small pure helpers only. No storage, runner,
|
|
32
32
|
* projection, or ledger logic lives here. Those arrive in later nodes.
|
|
33
33
|
*/
|
|
34
|
+
import { isWorkHubActionReceipt } from './workhub-action-result.js';
|
|
34
35
|
import { isModelRetryDecision } from './model-failure.js';
|
|
35
36
|
import { isRuntimeHandoffPause, runtimeHandoffPause, } from './runtime-handoff.js';
|
|
36
37
|
import { isMessageContent, normalizeMessageContent, } from './events.js';
|
|
@@ -229,6 +230,7 @@ const INVOCATION_ROOT_SHAPES = {
|
|
|
229
230
|
};
|
|
230
231
|
const RUNTIME_ACTIONS_SHAPE = defineObjectShape()([], [
|
|
231
232
|
'handoffPause',
|
|
233
|
+
'coordination',
|
|
232
234
|
'stateDelta',
|
|
233
235
|
'artifactDelta',
|
|
234
236
|
'permissionRequest',
|
|
@@ -583,6 +585,7 @@ function isRuntimeEventActions(value) {
|
|
|
583
585
|
return false;
|
|
584
586
|
}
|
|
585
587
|
return ((value.handoffPause === undefined || isRuntimeHandoffPause(value.handoffPause)) &&
|
|
588
|
+
(value.coordination === undefined || isWorkHubActionReceipt(value.coordination)) &&
|
|
586
589
|
(value.stateDelta === undefined || isRecord(value.stateDelta)) &&
|
|
587
590
|
(value.artifactDelta === undefined ||
|
|
588
591
|
(isRecord(value.artifactDelta) &&
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* specific language governing permissions and limitations
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
|
+
import { isWorkHubActionReceipt } from './workhub-action-result.js';
|
|
19
20
|
import { MODEL_FAILURE_MESSAGE_MAX_BYTES, isModelRetryDecision, } from './model-failure.js';
|
|
20
21
|
import { decodeMessageContent, TOOL_ACTIVITY_KINDS, } from './events.js';
|
|
21
22
|
import { isPermissionMode, isToolCategory, } from './permission.js';
|
|
@@ -64,7 +65,11 @@ export function isTurnStatus(value) {
|
|
|
64
65
|
// ============================================================================
|
|
65
66
|
// Header (JSONL line 1)
|
|
66
67
|
// ============================================================================
|
|
67
|
-
export const SESSION_TOOL_PROFILES = [
|
|
68
|
+
export const SESSION_TOOL_PROFILES = [
|
|
69
|
+
'headless-coding-v1',
|
|
70
|
+
'workhub-coordination-v1',
|
|
71
|
+
'workhub-coordination-v2',
|
|
72
|
+
];
|
|
68
73
|
export function isSessionToolProfile(value) {
|
|
69
74
|
return typeof value === 'string' && SESSION_TOOL_PROFILES.includes(value);
|
|
70
75
|
}
|
|
@@ -341,6 +346,7 @@ const USER_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'turnId', 'ts', 't
|
|
|
341
346
|
'quotes',
|
|
342
347
|
'inlineReferences',
|
|
343
348
|
'steeringEventId',
|
|
349
|
+
'coordinationActionId',
|
|
344
350
|
'origin',
|
|
345
351
|
]);
|
|
346
352
|
const ASSISTANT_MESSAGE_SHAPE = defineObjectShape()(['type', 'id', 'turnId', 'ts', 'text', 'modelId'], ['thinking', 'contentOrder', 'providerOptions']);
|
|
@@ -418,7 +424,15 @@ const WORKHUB_DELEGATION_ASSIGNED_MESSAGE_SHAPE = defineObjectShape()([
|
|
|
418
424
|
'targetTurnId',
|
|
419
425
|
'targetMessageId',
|
|
420
426
|
'targetSessionName',
|
|
421
|
-
], [
|
|
427
|
+
], [
|
|
428
|
+
'attachments',
|
|
429
|
+
'targetAttachments',
|
|
430
|
+
'create',
|
|
431
|
+
'steered',
|
|
432
|
+
'replacesActionId',
|
|
433
|
+
'replacesDelegationId',
|
|
434
|
+
'delegationText',
|
|
435
|
+
]);
|
|
422
436
|
const WORKHUB_DELEGATION_REPLACEMENT_REQUESTED_MESSAGE_SHAPE = defineObjectShape()([
|
|
423
437
|
'type',
|
|
424
438
|
'id',
|
|
@@ -437,7 +451,7 @@ const WORKHUB_DELEGATION_REPLACEMENT_REQUESTED_MESSAGE_SHAPE = defineObjectShape
|
|
|
437
451
|
'replacedTargetSessionId',
|
|
438
452
|
'replacedTargetMessageId',
|
|
439
453
|
'targetSessionName',
|
|
440
|
-
], ['attachments', 'create']);
|
|
454
|
+
], ['attachments', 'create', 'delegationText']);
|
|
441
455
|
const WORKHUB_DELEGATION_SUPERSEDED_MESSAGE_SHAPE = defineObjectShape()([
|
|
442
456
|
'type',
|
|
443
457
|
'id',
|
|
@@ -523,7 +537,10 @@ function decodeMessage(value, decodeToolResultContent) {
|
|
|
523
537
|
case 'user':
|
|
524
538
|
if (hasExactShape(message, USER_MESSAGE_SHAPE) &&
|
|
525
539
|
hasMessageEnvelope(message, true) &&
|
|
526
|
-
(message.origin === undefined || decodeTurnOrigin(message.origin) !== undefined)
|
|
540
|
+
(message.origin === undefined || decodeTurnOrigin(message.origin) !== undefined) &&
|
|
541
|
+
(message.coordinationActionId === undefined ||
|
|
542
|
+
(typeof message.coordinationActionId === 'string' &&
|
|
543
|
+
message.coordinationActionId.length > 0))) {
|
|
527
544
|
const { displayText, attachments, directoryReferences, quotes, inlineReferences, origin, ...envelope } = message;
|
|
528
545
|
const decodedOrigin = origin === undefined ? undefined : decodeTurnOrigin(origin);
|
|
529
546
|
try {
|
|
@@ -632,6 +649,11 @@ function decodeMessage(value, decodeToolResultContent) {
|
|
|
632
649
|
throw new Error('Invalid stored message schema');
|
|
633
650
|
}
|
|
634
651
|
function isWorkHubCoordinationMessage(message) {
|
|
652
|
+
if (message.kind === 'action_receipt')
|
|
653
|
+
return (hasMessageEnvelope(message, true) &&
|
|
654
|
+
message.schemaVersion === 1 &&
|
|
655
|
+
Object.keys(message).every((k) => ['type', 'kind', 'schemaVersion', 'id', 'turnId', 'ts', 'receipt'].includes(k)) &&
|
|
656
|
+
isWorkHubActionReceipt(message.receipt));
|
|
635
657
|
if (message.kind === 'delegation_stop_requested') {
|
|
636
658
|
return (hasMessageEnvelope(message, true) &&
|
|
637
659
|
hasExactShape(message, WORKHUB_DELEGATION_STOP_REQUESTED_MESSAGE_SHAPE) &&
|
|
@@ -708,6 +730,8 @@ function isWorkHubCoordinationMessage(message) {
|
|
|
708
730
|
typeof message.userText === 'string' &&
|
|
709
731
|
message.userText.trim().length > 0 &&
|
|
710
732
|
isWorkHubMessageAttachments(message.attachments) &&
|
|
733
|
+
(message.delegationText === undefined ||
|
|
734
|
+
(typeof message.delegationText === 'string' && message.delegationText.trim().length > 0)) &&
|
|
711
735
|
((message.disposition === 'delegate_existing' && message.create === undefined) ||
|
|
712
736
|
(message.disposition === 'create_new' && isWorkHubDelegationCreateSpec(message.create))) &&
|
|
713
737
|
(message.disposition === 'delegate_existing' || message.disposition === 'create_new');
|
|
@@ -729,6 +753,7 @@ function isWorkHubCoordinationMessage(message) {
|
|
|
729
753
|
}
|
|
730
754
|
return (message.kind === 'delegation_assigned' &&
|
|
731
755
|
hasExactShape(message, WORKHUB_DELEGATION_ASSIGNED_MESSAGE_SHAPE) &&
|
|
756
|
+
isWorkHubMessageAttachments(message.targetAttachments) &&
|
|
732
757
|
typeof message.delegationId === 'string' &&
|
|
733
758
|
typeof message.targetTurnId === 'string' &&
|
|
734
759
|
typeof message.targetMessageId === 'string' &&
|
|
@@ -0,0 +1,68 @@
|
|
|
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 { isRecord } from './record-schema.js';
|
|
20
|
+
export function isWorkHubActionReceipt(value) {
|
|
21
|
+
if (!isRecord(value) ||
|
|
22
|
+
Object.keys(value).some((k) => !['actionId', 'userText', 'result', 'clarification'].includes(k)) ||
|
|
23
|
+
typeof value.actionId !== 'string' ||
|
|
24
|
+
!value.actionId ||
|
|
25
|
+
typeof value.userText !== 'string' ||
|
|
26
|
+
!value.userText.trim() ||
|
|
27
|
+
(value.clarification !== undefined && typeof value.clarification !== 'string'))
|
|
28
|
+
return false;
|
|
29
|
+
return isWorkHubActionResult(value.result);
|
|
30
|
+
}
|
|
31
|
+
/** Shared closed result contract for Runtime receipts and Host protocol replies. */
|
|
32
|
+
export function isWorkHubActionResult(r) {
|
|
33
|
+
if (!isRecord(r))
|
|
34
|
+
return false;
|
|
35
|
+
const text = (k) => typeof r[k] === 'string' && /^[A-Za-z0-9_-]{1,128}$/u.test(r[k]);
|
|
36
|
+
const keys = (allowed) => Object.keys(r).every((k) => allowed.includes(k));
|
|
37
|
+
if (r.disposition === 'answer_here' || r.disposition === 'clarify')
|
|
38
|
+
return keys(['disposition', 'coordinationTurnId']) && text('coordinationTurnId');
|
|
39
|
+
if (r.disposition === 'delegate_existing' ||
|
|
40
|
+
r.disposition === 'create_new' ||
|
|
41
|
+
r.disposition === 'replace')
|
|
42
|
+
return (keys([
|
|
43
|
+
'disposition',
|
|
44
|
+
'targetSessionId',
|
|
45
|
+
'targetTurnId',
|
|
46
|
+
'steered',
|
|
47
|
+
...(r.disposition === 'replace' ? ['replacementDisposition'] : []),
|
|
48
|
+
]) &&
|
|
49
|
+
text('targetSessionId') &&
|
|
50
|
+
text('targetTurnId') &&
|
|
51
|
+
(r.steered === undefined || r.steered === true) &&
|
|
52
|
+
(r.disposition !== 'replace' ||
|
|
53
|
+
r.replacementDisposition === 'delegate_existing' ||
|
|
54
|
+
r.replacementDisposition === 'create_new'));
|
|
55
|
+
if (r.disposition === 'stop_work' || r.disposition === 'resume_work')
|
|
56
|
+
return ((r.disposition === 'stop_work'
|
|
57
|
+
? ((r.outcome !== 'stop_delivered' && r.outcome !== 'not_owned') ||
|
|
58
|
+
r.targetTurnId !== undefined) &&
|
|
59
|
+
(r.outcome !== 'cancelled_pending' || r.targetTurnId === undefined)
|
|
60
|
+
: (r.outcome === 'resume_started') === (r.targetTurnId !== undefined)) &&
|
|
61
|
+
keys(['disposition', 'outcome', 'targetSessionId', 'targetTurnId']) &&
|
|
62
|
+
text('targetSessionId') &&
|
|
63
|
+
(r.targetTurnId === undefined || text('targetTurnId')) &&
|
|
64
|
+
(r.disposition === 'stop_work'
|
|
65
|
+
? ['cancelled_pending', 'stop_delivered', 'already_terminal', 'not_owned']
|
|
66
|
+
: ['resume_started', 'already_running']).includes(String(r.outcome)));
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
@@ -83,8 +83,6 @@
|
|
|
83
83
|
"./deep-research-client-progress": "./dist/deep-research-client-progress.js",
|
|
84
84
|
"./daily-review": "./dist/daily-review.js",
|
|
85
85
|
"./work-board": "./dist/work-board.js",
|
|
86
|
-
"./workhub-creation-intent": "./dist/workhub-creation-intent.js",
|
|
87
|
-
"./workhub-session-resolver": "./dist/workhub-session-resolver.js",
|
|
88
86
|
"./deep-research": "./dist/deep-research.js",
|
|
89
87
|
"./session-start-mode": "./dist/session-start-mode.js",
|
|
90
88
|
"./long-term-memory": "./dist/long-term-memory.js",
|
|
@@ -156,7 +154,8 @@
|
|
|
156
154
|
"./ui-locale": "./dist/ui-locale.js",
|
|
157
155
|
"./unified-diff": "./dist/unified-diff.js",
|
|
158
156
|
"./dev-single-instance": "./dist/dev-single-instance.js",
|
|
159
|
-
"./maka-wordmark": "./dist/maka-wordmark.js"
|
|
157
|
+
"./maka-wordmark": "./dist/maka-wordmark.js",
|
|
158
|
+
"./workhub-action-result": "./dist/workhub-action-result.js"
|
|
160
159
|
},
|
|
161
160
|
"dependencies": {
|
|
162
161
|
"intl-messageformat": "11.2.14"
|
|
@@ -60,7 +60,7 @@ export const TOOLCHAIN_IDENTITIES = {
|
|
|
60
60
|
'deepseek-harness': {
|
|
61
61
|
root: '/opt/maka-deepseek-harness-toolchain',
|
|
62
62
|
version: '0.1.0-rc.6',
|
|
63
|
-
fingerprint: 'sha256:
|
|
63
|
+
fingerprint: 'sha256:5314e15659d4c35381ce15ca4802933d61bc3af718d7eeb8260f4fa32ccf5860',
|
|
64
64
|
},
|
|
65
65
|
};
|
|
66
66
|
// The identity table is the profile registry: a profile without a pinned
|