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.
- package/README.md +38 -19
- package/README.zh-CN.md +34 -19
- package/dist/mcp-capability-provider.js +4 -1
- package/dist/pi-transcript-tools.js +6 -0
- package/dist/pi-tui-layout.js +56 -10
- package/dist/pi-tui-mcp-status.js +2 -2
- package/dist/pi-tui-pickers.js +121 -30
- package/dist/pi-tui-runner.js +156 -42
- package/dist/pi-tui-todo.js +221 -0
- package/dist/pi-tui-transcript-viewer.js +134 -7
- package/dist/runtime-host-cli-context.js +70 -13
- package/dist/runtime-host-handoff-surface.js +51 -26
- package/dist/runtime-host-local-handoff.js +11 -1
- package/dist/runtime-host-service-manager.js +0 -3
- package/dist/runtime-host-session-channel.js +13 -0
- package/dist/runtime-host-session-driver.js +42 -1
- package/dist/tui-autocomplete-layout.js +3 -1
- package/dist/tui-copy-catalog.js +85 -6
- 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/agent-run.js +1 -0
- package/node_modules/@maka/core/dist/attachments.js +3 -0
- package/node_modules/@maka/core/dist/canonical-json.js +27 -0
- package/node_modules/@maka/core/dist/capabilities.js +35 -0
- package/node_modules/@maka/core/dist/computer-use.js +0 -1
- package/node_modules/@maka/core/dist/display-redaction.js +18 -0
- package/node_modules/@maka/core/dist/llm-connections.js +13 -0
- package/node_modules/@maka/core/dist/model-call-attempt.js +2 -0
- package/node_modules/@maka/core/dist/model-metadata.js +4 -0
- package/node_modules/@maka/core/dist/redaction.js +35 -0
- package/node_modules/@maka/core/dist/run-composition.js +77 -2
- package/node_modules/@maka/core/dist/runtime-event.js +3 -0
- package/node_modules/@maka/core/dist/session.js +57 -6
- package/node_modules/@maka/core/dist/slash-command-catalog.js +1 -0
- package/node_modules/@maka/core/dist/tool-result-record-schema.js +2 -1
- package/node_modules/@maka/core/dist/workhub-action-result.js +68 -0
- package/node_modules/@maka/core/package.json +3 -3
- package/node_modules/@maka/eval/dist/experiment-directory.js +4 -13
- 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-inspect.js +0 -13
- package/node_modules/@maka/runtime/dist/agent-run.js +90 -2
- package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +16 -8
- package/node_modules/@maka/runtime/dist/ai-sdk-turn.js +57 -50
- package/node_modules/@maka/runtime/dist/archive-read-tool.js +2 -2
- package/node_modules/@maka/runtime/dist/context-budget-helpers.js +0 -16
- package/node_modules/@maka/runtime/dist/conversation-copy.js +153 -11
- package/node_modules/@maka/runtime/dist/github-copilot-oauth-enrollment.js +3 -3
- package/node_modules/@maka/runtime/dist/goal-continuation.js +5 -1
- package/node_modules/@maka/runtime/dist/ledger-tool-result-archive-reader.js +69 -1
- package/node_modules/@maka/runtime/dist/mcp-tools.js +7 -2
- package/node_modules/@maka/runtime/dist/model-fetcher.js +42 -2
- package/node_modules/@maka/runtime/dist/model-history.js +0 -112
- package/node_modules/@maka/runtime/dist/plugin-runtime.js +20 -10
- package/node_modules/@maka/runtime/dist/plugin-tool-service.js +205 -0
- package/node_modules/@maka/runtime/dist/provider-request-telemetry.js +8 -1
- package/node_modules/@maka/runtime/dist/request-shape.js +23 -0
- package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +1 -1
- package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +24 -1
- package/node_modules/@maka/runtime/dist/runtime-kernel.js +127 -13
- package/node_modules/@maka/runtime/dist/session-manager.js +20 -36
- package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +21 -0
- package/node_modules/@maka/runtime/dist/stream-graph-supervisor-tools.js +0 -5
- package/node_modules/@maka/runtime/dist/test-connection.js +0 -1
- package/node_modules/@maka/runtime/dist/tool-activation-identity.js +41 -0
- package/node_modules/@maka/runtime/dist/tool-availability.js +11 -1
- package/node_modules/@maka/runtime/dist/tool-result-archive-resource.js +63 -1
- package/node_modules/@maka/runtime/dist/tool-result-archive-transition.js +42 -12
- package/node_modules/@maka/runtime/dist/tool-result-archive.js +27 -4
- package/node_modules/@maka/runtime/package.json +1 -0
- package/node_modules/@maka/runtime-host/dist/client/connection.js +30 -5
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +52 -13
- package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +2 -0
- 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/client/session-subscription.js +19 -0
- package/node_modules/@maka/runtime-host/dist/control/endpoint.js +1 -3
- package/node_modules/@maka/runtime-host/dist/node-error.js +22 -0
- package/node_modules/@maka/runtime-host/dist/operator/managed-deployment.js +1 -3
- package/node_modules/@maka/runtime-host/dist/peer-mesh/limits.js +0 -1
- package/node_modules/@maka/runtime-host/dist/peer-mesh/model.js +1 -1
- package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +1 -3
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +9 -1
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +3 -2
- package/node_modules/@maka/runtime-host/dist/protocol/plan.js +1 -0
- package/node_modules/@maka/runtime-host/dist/protocol/plugin-platform.js +27 -5
- package/node_modules/@maka/runtime-host/dist/protocol/project-catalog.js +2 -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 +86 -157
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +4 -0
- package/node_modules/@maka/runtime-host/dist/server/agent-graph-coordinator.js +0 -3
- 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-artifacts.js +32 -32
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +85 -25
- package/node_modules/@maka/runtime-host/dist/server/execution-model-composition.js +42 -14
- 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 +51 -23
- package/node_modules/@maka/runtime-host/dist/server/operation-dispatcher.js +2 -7
- package/node_modules/@maka/runtime-host/dist/server/plugin-platform-coordinator.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/plugin-platform.js +6 -0
- 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-retirement-coordinator.js +5 -2
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +4 -0
- 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 +59 -82
- package/node_modules/@maka/runtime-host/dist/server/workhub-coordination-coordinator.js +132 -139
- package/node_modules/@maka/runtime-host/dist/server/workhub-message-attachments.js +46 -0
- 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/claude-code-session-adapter.js +0 -1
- package/node_modules/@maka/storage/dist/codex-session-adapter.js +284 -196
- 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/git-exec.js +61 -0
- package/node_modules/@maka/storage/dist/git-worktree-child-executor.js +8 -35
- package/node_modules/@maka/storage/dist/goal-authority.js +2 -2
- package/node_modules/@maka/storage/dist/interaction-store.js +2 -2
- package/node_modules/@maka/storage/dist/mcp-config-store.js +10 -25
- package/node_modules/@maka/storage/dist/project-catalog.js +2 -23
- package/node_modules/@maka/storage/dist/runtime-event-invariants.js +2 -2
- package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +8 -3
- package/node_modules/@maka/storage/dist/scheduled-task-store.js +249 -283
- package/node_modules/@maka/storage/dist/session-bundle-manifest.js +5 -17
- package/node_modules/@maka/storage/dist/session-bundle-policy.js +2 -1
- package/node_modules/@maka/storage/dist/session-copy-cleanup.js +2 -1
- 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-runtime-store.js +1 -2
- 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/node_modules/@maka/storage/dist/storage-id.js +28 -0
- package/node_modules/@maka/storage/dist/tool-result-archive-evidence.js +31 -4
- package/node_modules/@maka/storage/dist/workspace-identity.js +2 -15
- package/node_modules/@maka/storage/dist/workspace-version-authority-internal.js +1 -8
- 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
package/dist/pi-tui-runner.js
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
import { randomUUID } from 'node:crypto';
|
|
20
|
-
import { basename } from 'node:path';
|
|
21
20
|
import { Key, ProcessTerminal, SelectList, TuiMainScreen, isKeyRelease, isKeyRepeat, matchesKey, } from '@earendil-works/pi-tui';
|
|
21
|
+
import { CurrentTodoStore, TodoOverlay, renderTodoIndicator } from './pi-tui-todo.js';
|
|
22
22
|
import { isThinkingLevel } from '@maka/core/model-thinking';
|
|
23
23
|
import { deriveConnectionSlug, } from '@maka/core/llm-connections';
|
|
24
24
|
import { projectRevisionLinkedSessionTree } from '@maka/core/session-revisions';
|
|
@@ -49,7 +49,7 @@ import { CTX_REFRESH_DEBOUNCE_MS, createCtxRefresher, scheduleCtxRefreshTimeout,
|
|
|
49
49
|
import { sessionStatusBadge } from './tui-session-status.js';
|
|
50
50
|
import { AttentionController, DISABLE_FOCUS_REPORTING, ENABLE_FOCUS_REPORTING, FOCUS_IN_SEQUENCE, FOCUS_OUT_SEQUENCE, } from './tui-attention.js';
|
|
51
51
|
import { MakaActivityStripComponent, MakaPendingQueueComponent, MakaPiLayoutComponent, MakaStatusLineComponent, MakaTranscriptComponent, } from './pi-tui-layout.js';
|
|
52
|
-
import { MakaAutocompleteProvider, DirectoryPickerOverlay, ModelSearchOverlay, OnboardingWizard, PickerOverlay, UserQuestionOverlay, modelChoiceConnectionLabels, getTuiPickerCopy, modelPickerItems, onboardingFailureMessage, permissionModePickerItems, skillPickerItems, thinkingLevelPickerItems, } from './pi-tui-pickers.js';
|
|
52
|
+
import { MakaAutocompleteProvider, DirectoryPickerOverlay, ModelSearchOverlay, SessionSearchOverlay, OnboardingWizard, PickerOverlay, UserQuestionOverlay, modelChoiceConnectionLabels, getTuiPickerCopy, modelPickerItems, onboardingFailureMessage, permissionModePickerItems, skillPickerItems, thinkingLevelPickerItems, } from './pi-tui-pickers.js';
|
|
53
53
|
import { formatMakaResumeCommand } from './cli-invocation.js';
|
|
54
54
|
import { goalAttachedNoticeText, goalPausedNoticeText, goalStatusLabel, goalSummaryLines, isLiveGoalStatus, } from './pi-goal.js';
|
|
55
55
|
import { getTuiPrimaryGuidance } from './tui-primary-guidance.js';
|
|
@@ -212,6 +212,20 @@ export async function runMakaPiTui(input) {
|
|
|
212
212
|
// True while the /session picker is open mid-turn: Escape must close the
|
|
213
213
|
// overlay, not arm the double-Escape interrupt for the running Turn (#3380).
|
|
214
214
|
let sessionPickerOverlayOpen = false;
|
|
215
|
+
let transcriptOverlay;
|
|
216
|
+
let todoOverlay;
|
|
217
|
+
const closeTodoOverlay = () => {
|
|
218
|
+
todoOverlay?.hide();
|
|
219
|
+
todoOverlay = undefined;
|
|
220
|
+
};
|
|
221
|
+
let transcriptViewer;
|
|
222
|
+
let transcriptViewerSessionId;
|
|
223
|
+
const resetTranscriptViewer = () => {
|
|
224
|
+
transcriptOverlay?.hide();
|
|
225
|
+
transcriptOverlay = undefined;
|
|
226
|
+
transcriptViewer = undefined;
|
|
227
|
+
transcriptViewerSessionId = undefined;
|
|
228
|
+
};
|
|
215
229
|
let lastTurnEscapeAt = 0;
|
|
216
230
|
let lastIdleEscapeAt = 0;
|
|
217
231
|
let lastIdleCtrlCAt = 0;
|
|
@@ -318,6 +332,34 @@ export async function runMakaPiTui(input) {
|
|
|
318
332
|
const activityStrip = new MakaActivityStripComponent(metadata);
|
|
319
333
|
const pendingQueue = new MakaPendingQueueComponent(state, locale);
|
|
320
334
|
const statusLine = new MakaStatusLineComponent(metadata);
|
|
335
|
+
const currentTodo = new CurrentTodoStore({
|
|
336
|
+
read: async (sessionId) => {
|
|
337
|
+
if (!input.driver.queryTodo)
|
|
338
|
+
throw new Error('Todo query unavailable');
|
|
339
|
+
return input.driver.queryTodo(sessionId);
|
|
340
|
+
},
|
|
341
|
+
}, () => {
|
|
342
|
+
if (!closed)
|
|
343
|
+
tui.requestRender();
|
|
344
|
+
});
|
|
345
|
+
const syncTodoSession = () => {
|
|
346
|
+
currentTodo.setSession(input.driver.getSessionId() ?? undefined);
|
|
347
|
+
};
|
|
348
|
+
const unsubscribeTodoChanges = input.driver.subscribeTodoChanges?.((sessionId) => {
|
|
349
|
+
if (sessionId !== input.driver.getSessionId())
|
|
350
|
+
return;
|
|
351
|
+
syncTodoSession();
|
|
352
|
+
void currentTodo.refresh();
|
|
353
|
+
});
|
|
354
|
+
const todoIndicator = {
|
|
355
|
+
invalidate() { },
|
|
356
|
+
render(width) {
|
|
357
|
+
if (!input.driver.queryTodo)
|
|
358
|
+
return [];
|
|
359
|
+
const line = renderTodoIndicator(currentTodo.getState(), { locale, width });
|
|
360
|
+
return line === undefined ? [] : [line];
|
|
361
|
+
},
|
|
362
|
+
};
|
|
321
363
|
// Use the vendor editor's full 20-item autocomplete capacity. Larger command
|
|
322
364
|
// catalogs remain scrollable and keep an exact position/total counter.
|
|
323
365
|
const editor = new MakaSkillHighlightEditor(tui, editorTheme(), {
|
|
@@ -326,7 +368,7 @@ export async function runMakaPiTui(input) {
|
|
|
326
368
|
});
|
|
327
369
|
let refreshEditorCwd;
|
|
328
370
|
const editorSurface = new MakaAutocompleteAboveEditorComponent(editor);
|
|
329
|
-
const layout = new MakaPiLayoutComponent(state, transcript, activityStrip, pendingQueue, editorSurface, statusLine, terminal);
|
|
371
|
+
const layout = new MakaPiLayoutComponent(state, transcript, activityStrip, pendingQueue, editorSurface, statusLine, terminal, todoIndicator);
|
|
330
372
|
const attention = new AttentionController(terminal, {
|
|
331
373
|
baseTitle: input.title,
|
|
332
374
|
...(input.attentionLongTurnThresholdMs !== undefined
|
|
@@ -608,6 +650,9 @@ export async function runMakaPiTui(input) {
|
|
|
608
650
|
unsubscribeModelCatalogChanges?.();
|
|
609
651
|
unsubscribeSessionTitleChanges();
|
|
610
652
|
unsubscribeGoalChanges?.();
|
|
653
|
+
unsubscribeTodoChanges?.();
|
|
654
|
+
currentTodo.dispose();
|
|
655
|
+
closeTodoOverlay();
|
|
611
656
|
void sideConversation?.stopParentObserver?.();
|
|
612
657
|
unsubscribeStartedTurns();
|
|
613
658
|
unsubscribeResolvedInteractions();
|
|
@@ -1209,6 +1254,7 @@ export async function runMakaPiTui(input) {
|
|
|
1209
1254
|
});
|
|
1210
1255
|
}
|
|
1211
1256
|
const adoptSessionMetadata = (summary, announceIdentity = true) => {
|
|
1257
|
+
syncTodoSession();
|
|
1212
1258
|
cwd = summary.cwd ?? cwd;
|
|
1213
1259
|
setSessionTitle(summary.name);
|
|
1214
1260
|
model = summary.model;
|
|
@@ -1297,6 +1343,8 @@ export async function runMakaPiTui(input) {
|
|
|
1297
1343
|
// `messages`. Shared by switchSession and rewindToTurn so both land the same
|
|
1298
1344
|
// runner state (model/connection/thinking/transcript/scroll).
|
|
1299
1345
|
const applySwitchResult = async ({ summary, messages, activeTurn, }) => {
|
|
1346
|
+
resetTranscriptViewer();
|
|
1347
|
+
closeTodoOverlay();
|
|
1300
1348
|
adoptSessionMetadata(summary, false);
|
|
1301
1349
|
replaceTranscript(messages);
|
|
1302
1350
|
syncInteractionOverlays();
|
|
@@ -1856,6 +1904,11 @@ export async function runMakaPiTui(input) {
|
|
|
1856
1904
|
formOverlay = showBottomPicker(formOverlayComponent);
|
|
1857
1905
|
};
|
|
1858
1906
|
const syncInteractionOverlays = () => {
|
|
1907
|
+
if (state.pendingInteraction) {
|
|
1908
|
+
closeTodoOverlay();
|
|
1909
|
+
transcriptOverlay?.hide();
|
|
1910
|
+
transcriptOverlay = undefined;
|
|
1911
|
+
}
|
|
1859
1912
|
syncUserQuestionOverlay();
|
|
1860
1913
|
syncFormOverlay();
|
|
1861
1914
|
};
|
|
@@ -2305,45 +2358,58 @@ export async function runMakaPiTui(input) {
|
|
|
2305
2358
|
foreignByValue.set(`foreign:${summary.source}:${summary.id}`, summary);
|
|
2306
2359
|
}
|
|
2307
2360
|
}
|
|
2361
|
+
let overlay;
|
|
2362
|
+
let sessionSearch;
|
|
2308
2363
|
const renderScope = () => {
|
|
2309
2364
|
const visibleSessions = sessionListScope === 'current'
|
|
2310
2365
|
? projectedSessions.filter(({ session }) => session.cwd === cwd)
|
|
2311
2366
|
: projectedSessions;
|
|
2312
|
-
const
|
|
2367
|
+
const choices = visibleSessions.map(({ session, depth }) => {
|
|
2313
2368
|
const state = availability.get(session.id);
|
|
2314
2369
|
const statusBadge = sessionStatusBadge(session, locale);
|
|
2315
2370
|
const statusDetail = statusBadge ? ` · ${statusBadge}` : '';
|
|
2316
|
-
const location = sessionListScope === 'all' && session.cwd ? ` ${
|
|
2371
|
+
const location = sessionListScope === 'all' && session.cwd ? ` ${session.cwd}` : '';
|
|
2317
2372
|
const childDetail = session.subagentRuntime
|
|
2318
2373
|
? ` subagent:${session.subagentRuntime.profile}`
|
|
2319
2374
|
: '';
|
|
2320
|
-
|
|
2375
|
+
const item = {
|
|
2321
2376
|
value: session.id,
|
|
2322
2377
|
label: `${depth > 0 ? `${' '.repeat(depth - 1)}↳ ` : ''}${session.name || session.id}`,
|
|
2323
2378
|
description: state?.available === false
|
|
2324
2379
|
? `${shortSessionId(session.id)}${statusDetail} ${state.reason}`
|
|
2325
2380
|
: `${shortSessionId(session.id)}${statusDetail}${location}${childDetail} ${session.llmConnectionSlug} ${session.model}`,
|
|
2326
2381
|
};
|
|
2382
|
+
return {
|
|
2383
|
+
item,
|
|
2384
|
+
searchText: [
|
|
2385
|
+
session.name,
|
|
2386
|
+
session.id,
|
|
2387
|
+
session.cwd,
|
|
2388
|
+
session.model,
|
|
2389
|
+
session.llmConnectionSlug,
|
|
2390
|
+
]
|
|
2391
|
+
.filter(Boolean)
|
|
2392
|
+
.join(' ')
|
|
2393
|
+
.toLocaleLowerCase(),
|
|
2394
|
+
};
|
|
2327
2395
|
});
|
|
2328
2396
|
// Foreign sessions are cwd-scoped; show them in both scope views (they
|
|
2329
2397
|
// belong to this project) so a Tab toggle never makes them vanish.
|
|
2330
2398
|
for (const [value, summary] of foreignByValue) {
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2399
|
+
choices.push({
|
|
2400
|
+
item: {
|
|
2401
|
+
value,
|
|
2402
|
+
label: summary.title,
|
|
2403
|
+
description: `↩ resume from ${foreignSourceLabel(summary.source)}`,
|
|
2404
|
+
},
|
|
2405
|
+
searchText: `${summary.title} ${summary.id} ${summary.cwd} ${summary.source}`.toLocaleLowerCase(),
|
|
2335
2406
|
});
|
|
2336
2407
|
}
|
|
2337
|
-
const list = new SelectList(items, 10, selectListTheme(), {
|
|
2338
|
-
minPrimaryColumnWidth: 20,
|
|
2339
|
-
maxPrimaryColumnWidth: Math.max(20, terminal.columns - 30),
|
|
2340
|
-
});
|
|
2341
|
-
let overlay;
|
|
2342
2408
|
const closeOverlay = () => {
|
|
2343
2409
|
sessionPickerOverlayOpen = false;
|
|
2344
2410
|
overlay?.hide();
|
|
2345
2411
|
};
|
|
2346
|
-
|
|
2412
|
+
const onSelect = (item) => {
|
|
2347
2413
|
const foreign = foreignByValue.get(item.value);
|
|
2348
2414
|
if (foreign) {
|
|
2349
2415
|
closeOverlay();
|
|
@@ -2355,21 +2421,27 @@ export async function runMakaPiTui(input) {
|
|
|
2355
2421
|
closeOverlay();
|
|
2356
2422
|
void goToSession(item.value);
|
|
2357
2423
|
};
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2424
|
+
const scopeLabel = sessionListScope === 'current'
|
|
2425
|
+
? pickerCopy.sessionScopeCurrent
|
|
2426
|
+
: pickerCopy.sessionScopeAll;
|
|
2427
|
+
if (sessionSearch) {
|
|
2428
|
+
sessionSearch.updateChoices(choices, scopeLabel);
|
|
2429
|
+
sessionSearch.invalidate();
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
sessionSearch = new SessionSearchOverlay(tui, {
|
|
2433
|
+
locale,
|
|
2434
|
+
choices,
|
|
2435
|
+
scopeLabel,
|
|
2436
|
+
onSelect,
|
|
2437
|
+
onCancel: closeOverlay,
|
|
2438
|
+
onToggleScope: () => {
|
|
2367
2439
|
sessionListScope = sessionListScope === 'current' ? 'all' : 'current';
|
|
2368
|
-
overlay?.hide();
|
|
2369
2440
|
renderScope();
|
|
2370
|
-
return true;
|
|
2371
2441
|
},
|
|
2372
|
-
})
|
|
2442
|
+
});
|
|
2443
|
+
sessionPickerOverlayOpen = true;
|
|
2444
|
+
overlay = showBottomPicker(sessionSearch);
|
|
2373
2445
|
};
|
|
2374
2446
|
renderScope();
|
|
2375
2447
|
};
|
|
@@ -2427,6 +2499,9 @@ export async function runMakaPiTui(input) {
|
|
|
2427
2499
|
requestRender();
|
|
2428
2500
|
return false;
|
|
2429
2501
|
}
|
|
2502
|
+
resetTranscriptViewer();
|
|
2503
|
+
closeTodoOverlay();
|
|
2504
|
+
syncTodoSession();
|
|
2430
2505
|
// A fresh session is not bound by the previous one's boundary. Falling back
|
|
2431
2506
|
// to the *current* label would keep the previous Session's mode, including
|
|
2432
2507
|
// Auto while a changed Host default creates with full access; the launch
|
|
@@ -2508,20 +2583,42 @@ export async function runMakaPiTui(input) {
|
|
|
2508
2583
|
requestRender();
|
|
2509
2584
|
};
|
|
2510
2585
|
const showTranscriptViewer = () => {
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
const
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2586
|
+
if (state.pendingInteraction)
|
|
2587
|
+
return;
|
|
2588
|
+
const sessionId = input.driver.getSessionId() ?? undefined;
|
|
2589
|
+
if (!transcriptViewer || transcriptViewerSessionId !== sessionId) {
|
|
2590
|
+
transcriptViewerSessionId = sessionId;
|
|
2591
|
+
transcriptViewer = new TranscriptViewerOverlay({
|
|
2592
|
+
renderTranscript: transcript.createDocumentRenderer(),
|
|
2593
|
+
locale,
|
|
2594
|
+
viewportRows: () => terminal.rows,
|
|
2595
|
+
onClose: () => {
|
|
2596
|
+
transcriptOverlay?.hide();
|
|
2597
|
+
transcriptOverlay = undefined;
|
|
2598
|
+
},
|
|
2599
|
+
onChange: () => tui.requestRender(),
|
|
2600
|
+
});
|
|
2601
|
+
}
|
|
2602
|
+
transcriptOverlay = tui.showOverlay(transcriptViewer, {
|
|
2520
2603
|
anchor: 'top-left',
|
|
2521
2604
|
width: '100%',
|
|
2522
2605
|
maxHeight: '100%',
|
|
2523
2606
|
});
|
|
2524
2607
|
};
|
|
2608
|
+
const showTodo = () => {
|
|
2609
|
+
if (state.pendingInteraction)
|
|
2610
|
+
return;
|
|
2611
|
+
syncTodoSession();
|
|
2612
|
+
void currentTodo.refresh();
|
|
2613
|
+
closeTodoOverlay();
|
|
2614
|
+
todoOverlay = tui.showOverlay(new TodoOverlay({
|
|
2615
|
+
locale,
|
|
2616
|
+
getState: () => input.driver.queryTodo ? currentTodo.getState() : { status: 'error', items: [] },
|
|
2617
|
+
viewportRows: () => terminal.rows,
|
|
2618
|
+
onClose: closeTodoOverlay,
|
|
2619
|
+
onChange: () => tui.requestRender(),
|
|
2620
|
+
}), { anchor: 'top-left', width: '100%', maxHeight: '100%' });
|
|
2621
|
+
};
|
|
2525
2622
|
const showMcpStatus = () => {
|
|
2526
2623
|
let overlay;
|
|
2527
2624
|
const viewer = new McpManagementOverlay({
|
|
@@ -3311,6 +3408,22 @@ export async function runMakaPiTui(input) {
|
|
|
3311
3408
|
showTranscriptViewer();
|
|
3312
3409
|
},
|
|
3313
3410
|
},
|
|
3411
|
+
todo: {
|
|
3412
|
+
description: primaryGuidance.commands.todo,
|
|
3413
|
+
midTurn: 'local',
|
|
3414
|
+
run: (parts) => {
|
|
3415
|
+
if (parts.length !== 1) {
|
|
3416
|
+
state.entries.push({
|
|
3417
|
+
kind: 'notice',
|
|
3418
|
+
level: 'error',
|
|
3419
|
+
text: TUI_COPY_RESOURCES.todo[locale].usage,
|
|
3420
|
+
});
|
|
3421
|
+
requestRender();
|
|
3422
|
+
return;
|
|
3423
|
+
}
|
|
3424
|
+
showTodo();
|
|
3425
|
+
},
|
|
3426
|
+
},
|
|
3314
3427
|
permissions: {
|
|
3315
3428
|
description: primaryGuidance.commands.permissions,
|
|
3316
3429
|
midTurn: 'refuse',
|
|
@@ -3605,9 +3718,8 @@ export async function runMakaPiTui(input) {
|
|
|
3605
3718
|
if (!matchesKey(data, Key.escape))
|
|
3606
3719
|
lastIdleEscapeAt = 0;
|
|
3607
3720
|
if (matchesKey(data, Key.ctrl('o')) && !isKeyRepeat(data)) {
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
}
|
|
3721
|
+
showTranscriptViewer();
|
|
3722
|
+
return { consume: true };
|
|
3611
3723
|
}
|
|
3612
3724
|
if (matchesKey(data, Key.ctrl('t')) && !isKeyRepeat(data)) {
|
|
3613
3725
|
if (handleExpansionToggleKey('thinking')) {
|
|
@@ -3718,11 +3830,11 @@ export async function runMakaPiTui(input) {
|
|
|
3718
3830
|
// re-wrapping) a full clear would wipe the scrollback the user scrolls through.
|
|
3719
3831
|
// Differential rendering clears the vacated rows without the wipe.
|
|
3720
3832
|
//
|
|
3721
|
-
// The
|
|
3833
|
+
// The live Ctrl+T thinking toggle is viewport-anchored for the same reason: an
|
|
3722
3834
|
// entry above the live viewport lives in terminal scrollback, which cannot
|
|
3723
3835
|
// be rewritten, so resizing it would push pi-tui's differential renderer
|
|
3724
3836
|
// into a scrollback-clearing full redraw (its `firstChanged < viewportTop`
|
|
3725
|
-
// path).
|
|
3837
|
+
// path). It therefore retargets only entries inside the viewport;
|
|
3726
3838
|
// see entryInLiveViewport in pi-transcript.ts (#1097). A block whose own
|
|
3727
3839
|
// expansion pushed its head above the viewport can consequently not be
|
|
3728
3840
|
// collapsed by the next press (#1134): the toggle still flips the default
|
|
@@ -3731,6 +3843,7 @@ export async function runMakaPiTui(input) {
|
|
|
3731
3843
|
// again within EXPANSION_COLLAPSE_CONFIRM_WINDOW_MS applies the collapsed
|
|
3732
3844
|
// default to those blocks too and pays one scrollback-clearing full redraw
|
|
3733
3845
|
// (requestRender(true)), re-anchoring the viewport at the tail.
|
|
3846
|
+
// Ctrl+O instead opens a detached reader whose details never resize live rows.
|
|
3734
3847
|
tui.setClearOnShrink(false);
|
|
3735
3848
|
tui.addChild(layout);
|
|
3736
3849
|
tui.setFocus(editorSurface);
|
|
@@ -3772,6 +3885,7 @@ export async function runMakaPiTui(input) {
|
|
|
3772
3885
|
}
|
|
3773
3886
|
});
|
|
3774
3887
|
}
|
|
3888
|
+
syncTodoSession();
|
|
3775
3889
|
return closedPromise;
|
|
3776
3890
|
}
|
|
3777
3891
|
const BOTTOM_PICKER_MARGIN_ROWS = 4;
|
|
@@ -0,0 +1,221 @@
|
|
|
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 { Key, isKeyRelease, isKeyRepeat, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi, } from '@earendil-works/pi-tui';
|
|
20
|
+
import { projectSessionTodoItemsForDisplay, } from '@maka/core/session-todo';
|
|
21
|
+
import { ansi } from './tui-ansi.js';
|
|
22
|
+
import { TUI_COPY_RESOURCES } from './tui-copy-catalog.js';
|
|
23
|
+
/** Owns only the current session; late queries cannot cross session changes or disposal. */
|
|
24
|
+
export class CurrentTodoStore {
|
|
25
|
+
reader;
|
|
26
|
+
onChange;
|
|
27
|
+
snapshot = { status: 'idle', items: [] };
|
|
28
|
+
generation = 0;
|
|
29
|
+
disposed = false;
|
|
30
|
+
pending;
|
|
31
|
+
refreshAgain = false;
|
|
32
|
+
constructor(reader, onChange = () => undefined) {
|
|
33
|
+
this.reader = reader;
|
|
34
|
+
this.onChange = onChange;
|
|
35
|
+
}
|
|
36
|
+
getState() {
|
|
37
|
+
return this.snapshot;
|
|
38
|
+
}
|
|
39
|
+
setSession(sessionId) {
|
|
40
|
+
if (this.disposed || this.snapshot.sessionId === sessionId)
|
|
41
|
+
return;
|
|
42
|
+
this.generation++;
|
|
43
|
+
this.pending = undefined;
|
|
44
|
+
this.refreshAgain = false;
|
|
45
|
+
this.publish({ status: 'idle', ...(sessionId ? { sessionId } : {}), items: [] });
|
|
46
|
+
if (sessionId)
|
|
47
|
+
void this.refresh();
|
|
48
|
+
}
|
|
49
|
+
refresh() {
|
|
50
|
+
const { sessionId } = this.snapshot;
|
|
51
|
+
if (this.disposed || !sessionId)
|
|
52
|
+
return Promise.resolve(false);
|
|
53
|
+
if (this.pending) {
|
|
54
|
+
this.refreshAgain = true;
|
|
55
|
+
return this.pending;
|
|
56
|
+
}
|
|
57
|
+
const pending = this.load(sessionId, this.generation).finally(() => {
|
|
58
|
+
if (this.pending !== pending)
|
|
59
|
+
return;
|
|
60
|
+
this.pending = undefined;
|
|
61
|
+
if (this.refreshAgain) {
|
|
62
|
+
this.refreshAgain = false;
|
|
63
|
+
void this.refresh();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
this.pending = pending;
|
|
67
|
+
return pending;
|
|
68
|
+
}
|
|
69
|
+
dispose() {
|
|
70
|
+
this.disposed = true;
|
|
71
|
+
this.generation++;
|
|
72
|
+
this.pending = undefined;
|
|
73
|
+
this.refreshAgain = false;
|
|
74
|
+
this.snapshot = { status: 'idle', items: [] };
|
|
75
|
+
}
|
|
76
|
+
async load(sessionId, generation) {
|
|
77
|
+
// Keep current data visible during background refreshes, without a second cache.
|
|
78
|
+
if (this.snapshot.status !== 'ready' && this.snapshot.status !== 'empty') {
|
|
79
|
+
this.publish({ status: 'loading', sessionId, items: [] });
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const result = await this.reader.read(sessionId);
|
|
83
|
+
if (generation !== this.generation)
|
|
84
|
+
return false;
|
|
85
|
+
const items = projectSessionTodoItemsForDisplay(result.items);
|
|
86
|
+
this.publish({ status: items.length ? 'ready' : 'empty', sessionId, items });
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
if (generation !== this.generation)
|
|
90
|
+
return false;
|
|
91
|
+
this.publish({ status: 'error', sessionId, items: [] });
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
publish(snapshot) {
|
|
96
|
+
this.snapshot = snapshot;
|
|
97
|
+
this.onChange();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** Render the one-line current Todo indicator. Empty and initial states stay hidden. */
|
|
101
|
+
export function renderTodoIndicator(snapshot, input) {
|
|
102
|
+
const copy = TUI_COPY_RESOURCES.todo[input.locale];
|
|
103
|
+
if (snapshot.status === 'idle' || snapshot.status === 'loading' || snapshot.status === 'empty') {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
if (snapshot.status === 'error')
|
|
107
|
+
return fitLine(`${copy.unavailable} · ${copy.open}`, input.width);
|
|
108
|
+
const current = snapshot.items.find((item) => item.status === 'in_progress');
|
|
109
|
+
const completed = snapshot.items.filter((item) => item.status === 'completed').length;
|
|
110
|
+
const suffix = `${copy.progress} ${completed}/${snapshot.items.length} · ${copy.open}`;
|
|
111
|
+
const prefix = current ? `${ansi.accent('◐')} ` : '';
|
|
112
|
+
const available = input.width - visibleWidth(prefix) - visibleWidth(suffix) - (current ? 3 : 1);
|
|
113
|
+
if (!current)
|
|
114
|
+
return fitLine(suffix, input.width);
|
|
115
|
+
if (available < 1)
|
|
116
|
+
return fitLine(suffix, input.width);
|
|
117
|
+
const content = truncateToWidth(current.content, Math.max(1, available), '…');
|
|
118
|
+
return fitLine(`${prefix}${content} · ${suffix}`, input.width);
|
|
119
|
+
}
|
|
120
|
+
/** Read-only, scrollable view of the current Todo projection. */
|
|
121
|
+
export class TodoOverlay {
|
|
122
|
+
input;
|
|
123
|
+
top = 0;
|
|
124
|
+
bodyRows = 1;
|
|
125
|
+
width = 80;
|
|
126
|
+
constructor(input) {
|
|
127
|
+
this.input = input;
|
|
128
|
+
}
|
|
129
|
+
invalidate() { }
|
|
130
|
+
handleInput(data) {
|
|
131
|
+
if (isKeyRelease(data))
|
|
132
|
+
return;
|
|
133
|
+
if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl('c'))) {
|
|
134
|
+
if (!isKeyRepeat(data))
|
|
135
|
+
this.input.onClose();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (matchesKey(data, Key.up))
|
|
139
|
+
this.scrollBy(-1);
|
|
140
|
+
else if (matchesKey(data, Key.down))
|
|
141
|
+
this.scrollBy(1);
|
|
142
|
+
else if (matchesKey(data, Key.pageUp))
|
|
143
|
+
this.scrollBy(-this.bodyRows);
|
|
144
|
+
else if (matchesKey(data, Key.pageDown))
|
|
145
|
+
this.scrollBy(this.bodyRows);
|
|
146
|
+
else if (matchesKey(data, Key.home)) {
|
|
147
|
+
this.scrollTo(0);
|
|
148
|
+
this.input.onChange?.();
|
|
149
|
+
}
|
|
150
|
+
else if (matchesKey(data, Key.end)) {
|
|
151
|
+
this.scrollTo(Number.MAX_SAFE_INTEGER);
|
|
152
|
+
this.input.onChange?.();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
render(width) {
|
|
156
|
+
const safeWidth = Math.max(1, width);
|
|
157
|
+
this.width = safeWidth;
|
|
158
|
+
const copy = TUI_COPY_RESOURCES.todo[this.input.locale];
|
|
159
|
+
const viewport = Math.max(1, Math.floor(this.input.viewportRows()));
|
|
160
|
+
const showFooter = viewport > 2;
|
|
161
|
+
this.bodyRows = Math.max(0, viewport - (showFooter ? 2 : 1));
|
|
162
|
+
const snapshot = this.input.getState();
|
|
163
|
+
const rows = this.rows(snapshot, safeWidth);
|
|
164
|
+
const maxTop = Math.max(0, rows.length - this.bodyRows);
|
|
165
|
+
this.top = Math.min(this.top, maxTop);
|
|
166
|
+
const visible = rows.slice(this.top, this.top + this.bodyRows);
|
|
167
|
+
const completed = snapshot.items.filter((item) => item.status === 'completed').length;
|
|
168
|
+
const summary = snapshot.status === 'ready'
|
|
169
|
+
? ` · ${completed}/${snapshot.items.length} ${copy.markedComplete}`
|
|
170
|
+
: '';
|
|
171
|
+
const position = rows.length > this.bodyRows && this.bodyRows > 0
|
|
172
|
+
? ` · ${this.top + 1}-${this.top + visible.length}/${rows.length}`
|
|
173
|
+
: '';
|
|
174
|
+
const header = padLine(`${ansi.bold(copy.title)}${summary}${ansi.dim(position)}`, safeWidth);
|
|
175
|
+
const body = [
|
|
176
|
+
...visible,
|
|
177
|
+
...Array.from({ length: this.bodyRows - visible.length }, () => ' '.repeat(safeWidth)),
|
|
178
|
+
];
|
|
179
|
+
if (!showFooter)
|
|
180
|
+
return [header, ...body];
|
|
181
|
+
const footer = padLine(ansi.dim(copy.hint), safeWidth);
|
|
182
|
+
return [header, ...body, footer];
|
|
183
|
+
}
|
|
184
|
+
rows(snapshot, width) {
|
|
185
|
+
const copy = TUI_COPY_RESOURCES.todo[this.input.locale];
|
|
186
|
+
if (snapshot.status === 'loading')
|
|
187
|
+
return [padLine(copy.loading, width)];
|
|
188
|
+
if (snapshot.status === 'error')
|
|
189
|
+
return [padLine(copy.unavailable, width)];
|
|
190
|
+
if (snapshot.status === 'idle' || snapshot.status === 'empty')
|
|
191
|
+
return [padLine(copy.empty, width)];
|
|
192
|
+
return snapshot.items.flatMap((item) => {
|
|
193
|
+
const symbol = item.status === 'completed'
|
|
194
|
+
? ansi.green('✓')
|
|
195
|
+
: item.status === 'in_progress'
|
|
196
|
+
? ansi.accent('●')
|
|
197
|
+
: ansi.muted('○');
|
|
198
|
+
return wrapTodoItem(`${symbol} `, item.content, width);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
scrollBy(delta) {
|
|
202
|
+
this.scrollTo(this.top + delta);
|
|
203
|
+
this.input.onChange?.();
|
|
204
|
+
}
|
|
205
|
+
scrollTo(top) {
|
|
206
|
+
const rows = this.rows(this.input.getState(), this.width);
|
|
207
|
+
this.top = Math.max(0, Math.min(top, Math.max(0, rows.length - this.bodyRows)));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function wrapTodoItem(prefix, content, width) {
|
|
211
|
+
const lines = wrapTextWithAnsi(content, Math.max(1, width - 2));
|
|
212
|
+
return (lines.length ? lines : ['']).map((line, index) => padLine(`${index === 0 ? prefix : ' '}${line}`, width));
|
|
213
|
+
}
|
|
214
|
+
function fitLine(text, width) {
|
|
215
|
+
return truncateToWidth(text, Math.max(1, width), '…');
|
|
216
|
+
}
|
|
217
|
+
function padLine(text, width) {
|
|
218
|
+
const safeWidth = Math.max(1, width);
|
|
219
|
+
const trimmed = fitLine(text, safeWidth);
|
|
220
|
+
return `${trimmed}${' '.repeat(Math.max(0, safeWidth - visibleWidth(trimmed)))}`;
|
|
221
|
+
}
|