@robota-sdk/agent-transport 3.0.0-beta.72 → 3.0.0-beta.74
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/node/headless/index.cjs +1 -1
- package/dist/node/headless/index.d.ts +1 -1
- package/dist/node/headless/index.js +1 -1
- package/dist/node/{headless-DCtHvyVf.cjs → headless-BeHAOlIM.cjs} +4 -3
- package/dist/node/{headless-C6tj35h3.js → headless-D02zUEGh.js} +4 -3
- package/dist/node/headless-D02zUEGh.js.map +1 -0
- package/dist/node/http/index.cjs +1 -1
- package/dist/node/http/index.d.ts +1 -1
- package/dist/node/http/index.js +1 -1
- package/dist/node/{http-Br10Ps8m.js → http-2Jiuflc1.js} +1 -1
- package/dist/node/http-2Jiuflc1.js.map +1 -0
- package/dist/node/http-CBAvefLw.cjs +1 -0
- package/dist/node/{index-BVNhOeeU.d.ts → index-BQLN_Lc9.d.ts} +5 -3
- package/dist/node/index-BQLN_Lc9.d.ts.map +1 -0
- package/dist/node/{index-C9LWCL4l.d.ts → index-BnAGE-u9.d.ts} +2 -3
- package/dist/node/index-BnAGE-u9.d.ts.map +1 -0
- package/dist/node/{index-COWvtBa2.d.ts → index-BrQ4gGw0.d.ts} +3 -3
- package/dist/node/index-BrQ4gGw0.d.ts.map +1 -0
- package/dist/node/{index-X2Zg8FEY.d.ts → index-CoeBF21y.d.ts} +3 -3
- package/dist/node/index-CoeBF21y.d.ts.map +1 -0
- package/dist/node/{index-27HV5PJB.d.ts → index-DE3-dHqw.d.ts} +8 -3
- package/dist/node/index-DE3-dHqw.d.ts.map +1 -0
- package/dist/node/{index-BRgV_MPB.d.ts → index-DHt-2VQ-.d.ts} +2 -3
- package/dist/node/index-DHt-2VQ-.d.ts.map +1 -0
- package/dist/node/{index-nBlMTFkZ.d.ts → index-DMwKN5Le.d.ts} +2 -3
- package/dist/node/index-DMwKN5Le.d.ts.map +1 -0
- package/dist/node/{index-TMAlNHuM.d.ts → index-IvYaYY6v.d.ts} +5 -3
- package/dist/node/index-IvYaYY6v.d.ts.map +1 -0
- package/dist/node/{index-BRchlFBE.d.ts → index-WKTgvhlg.d.ts} +8 -3
- package/dist/node/index-WKTgvhlg.d.ts.map +1 -0
- package/dist/node/{index-C5KNEBO9.d.ts → index-c0M42fsA.d.ts} +2 -3
- package/dist/node/index-c0M42fsA.d.ts.map +1 -0
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.ts +6 -7
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/dist/node/mcp/index.cjs +1 -1
- package/dist/node/mcp/index.d.ts +1 -1
- package/dist/node/mcp/index.js +1 -1
- package/dist/node/mcp-BOglBJNy.cjs +1 -0
- package/dist/node/{mcp-BAujHOMr.js → mcp-D3BBVK7C.js} +1 -1
- package/dist/node/mcp-D3BBVK7C.js.map +1 -0
- package/dist/node/{chunk-Bmb41Sf3.cjs → rolldown-runtime-CMqjfN_6.cjs} +1 -1
- package/dist/node/testing/index.cjs +1 -0
- package/dist/node/testing/index.d.ts +21 -0
- package/dist/node/testing/index.d.ts.map +1 -0
- package/dist/node/testing/index.js +2 -0
- package/dist/node/testing/index.js.map +1 -0
- package/dist/node/tui/index.cjs +1 -1
- package/dist/node/tui/index.d.ts +1 -1
- package/dist/node/tui/index.js +1 -1
- package/dist/node/{tui-4hA-SMtS.js → tui-Btb1q88j.js} +5 -5
- package/dist/node/tui-Btb1q88j.js.map +1 -0
- package/dist/node/tui-SbUT7Zlt.cjs +24 -0
- package/dist/node/ws/index.cjs +1 -1
- package/dist/node/ws/index.d.ts +1 -1
- package/dist/node/ws/index.js +1 -1
- package/dist/node/{ws-BWel8nzl.js → ws-Dc2RUwVs.js} +1 -1
- package/dist/node/ws-Dc2RUwVs.js.map +1 -0
- package/dist/node/ws-QNMQn5kg.cjs +1 -0
- package/package.json +35 -22
- package/src/headless/HeadlessInteractionChannel.ts +9 -1
- package/src/headless/__tests__/headless-channel-options.test.ts +106 -0
- package/src/headless/__tests__/headless-provider-failure.integration.test.ts +143 -0
- package/src/headless/__tests__/headless-runner-initialization.test.ts +1 -1
- package/src/headless/__tests__/headless-runner.test.ts +24 -3
- package/src/headless/__tests__/headless-transport.test.ts +1 -2
- package/src/headless/headless-runner.ts +3 -2
- package/src/headless/headless-stream-json.ts +5 -5
- package/src/headless/headless-transport.ts +1 -2
- package/src/http/__tests__/http-transport.test.ts +1 -1
- package/src/http/__tests__/routes.test.ts +1 -1
- package/src/http/http-transport.ts +1 -2
- package/src/http/routes.ts +1 -1
- package/src/mcp/__tests__/mcp-server.test.ts +1 -1
- package/src/mcp/__tests__/mcp-transport.test.ts +1 -1
- package/src/mcp/mcp-server.ts +1 -1
- package/src/mcp/mcp-transport.ts +1 -2
- package/src/testing/__tests__/scripted-provider.test.ts +73 -0
- package/src/testing/index.ts +7 -0
- package/src/testing/scripted-provider.ts +73 -0
- package/src/transport-registry.ts +1 -1
- package/src/tui/App.tsx +38 -29
- package/src/tui/BackgroundTaskPanel.tsx +1 -1
- package/src/tui/CjkTextInput.tsx +4 -8
- package/src/tui/ExecutionWorkspaceDetailPane.tsx +1 -1
- package/src/tui/ExecutionWorkspaceSwitcher.tsx +1 -1
- package/src/tui/InputArea.tsx +15 -7
- package/src/tui/InteractivePrompt.tsx +2 -2
- package/src/tui/PluginTUI.tsx +1 -1
- package/src/tui/SessionPicker.tsx +1 -1
- package/src/tui/SessionStatusBar.tsx +1 -1
- package/src/tui/SlashAutocomplete.tsx +1 -1
- package/src/tui/StatusBar.tsx +1 -7
- package/src/tui/StreamingIndicator.tsx +1 -1
- package/src/tui/TransportTUI.tsx +1 -1
- package/src/tui/TuiInteractionChannel.ts +60 -38
- package/src/tui/UsageSummaryEntry.tsx +1 -1
- package/src/tui/__tests__/PluginTUI.test.tsx +1 -1
- package/src/tui/__tests__/SlashAutocomplete.test.tsx +1 -1
- package/src/tui/__tests__/TuiInteractionChannel.display-contract.test.ts +1 -1
- package/src/tui/__tests__/TuiInteractionChannel.lifecycle.test.ts +5 -2
- package/src/tui/__tests__/TuiInteractionChannel.requestAction.test.ts +1 -1
- package/src/tui/__tests__/background-task-panel.test.tsx +1 -1
- package/src/tui/__tests__/background-task-row-format.test.ts +1 -1
- package/src/tui/__tests__/channel-factory-integration.test.ts +138 -0
- package/src/tui/__tests__/execution-workspace-switcher.test.tsx +1 -1
- package/src/tui/__tests__/execution-workspace-view-model.test.ts +1 -1
- package/src/tui/__tests__/fixtures/provider-setup-prompt-driver.tsx +1 -1
- package/src/tui/__tests__/input-area-flow.test.ts +1 -1
- package/src/tui/__tests__/pty/pty-driver.ts +135 -0
- package/src/tui/__tests__/pty/tui-pty.ptytest.ts +61 -0
- package/src/tui/__tests__/render-channel-options.test.ts +32 -0
- package/src/tui/__tests__/session-init-poller.test.ts +102 -0
- package/src/tui/__tests__/session-switch-channel.test.tsx +307 -0
- package/src/tui/__tests__/slash-routing-effects.test.ts +4 -1
- package/src/tui/__tests__/status-activity.test.ts +3 -3
- package/src/tui/__tests__/status-bar.test.tsx +7 -6
- package/src/tui/__tests__/tui-channel-init-failure.test.ts +57 -0
- package/src/tui/__tests__/tui-state-manager.test.ts +1 -1
- package/src/tui/background-task-row-format.ts +1 -1
- package/src/tui/execution-workspace-view-model.ts +1 -1
- package/src/tui/flows/input-area-flow.ts +1 -1
- package/src/tui/flows/permission-prompt-flow.ts +1 -1
- package/src/tui/flows/session-init-poller.ts +77 -0
- package/src/tui/hooks/command-effect-handler.ts +4 -1
- package/src/tui/hooks/command-effect-queue.ts +1 -1
- package/src/tui/hooks/side-effects-types.ts +2 -2
- package/src/tui/hooks/useAutocomplete.ts +3 -2
- package/src/tui/hooks/usePluginCallbacks.ts +1 -1
- package/src/tui/hooks/usePluginScreenData.ts +1 -1
- package/src/tui/hooks/useSideEffects.ts +1 -1
- package/src/tui/hooks/useSlashRouting.ts +3 -3
- package/src/tui/hooks/useStatusLineSettings.ts +1 -1
- package/src/tui/hooks/useTuiChannel.ts +3 -3
- package/src/tui/plugin-tui-handlers.ts +1 -1
- package/src/tui/render.tsx +38 -25
- package/src/tui/status-activity.ts +2 -2
- package/src/tui/tui-cli-adapter.ts +3 -3
- package/src/tui/tui-state-manager.ts +2 -2
- package/src/tui/tui-transport.ts +4 -2
- package/src/ws/__tests__/ws-handler.test.ts +6 -4
- package/src/ws/__tests__/ws-transport.test.ts +1 -1
- package/src/ws/ws-background-messages.ts +1 -1
- package/src/ws/ws-handler.ts +4 -4
- package/src/ws/ws-protocol.ts +6 -4
- package/src/ws/ws-transport-configurable.ts +4 -2
- package/src/ws/ws-transport.ts +1 -2
- package/dist/node/headless-C6tj35h3.js.map +0 -1
- package/dist/node/http-Br10Ps8m.js.map +0 -1
- package/dist/node/http-Da6Kw4oy.cjs +0 -1
- package/dist/node/index-27HV5PJB.d.ts.map +0 -1
- package/dist/node/index-BRchlFBE.d.ts.map +0 -1
- package/dist/node/index-BRgV_MPB.d.ts.map +0 -1
- package/dist/node/index-BVNhOeeU.d.ts.map +0 -1
- package/dist/node/index-C5KNEBO9.d.ts.map +0 -1
- package/dist/node/index-C9LWCL4l.d.ts.map +0 -1
- package/dist/node/index-COWvtBa2.d.ts.map +0 -1
- package/dist/node/index-TMAlNHuM.d.ts.map +0 -1
- package/dist/node/index-X2Zg8FEY.d.ts.map +0 -1
- package/dist/node/index-nBlMTFkZ.d.ts.map +0 -1
- package/dist/node/mcp-BAujHOMr.js.map +0 -1
- package/dist/node/mcp-Bl8jUfev.cjs +0 -1
- package/dist/node/tui-4hA-SMtS.js.map +0 -1
- package/dist/node/tui-CcLmEJ1r.cjs +0 -24
- package/dist/node/ws-BWel8nzl.js.map +0 -1
- package/dist/node/ws-tCjj2gPu.cjs +0 -1
- package/src/tui/InkTerminal.ts +0 -42
- package/src/tui/hooks/use-interactive-session-init.ts +0 -91
- package/src/tui/hooks/usePermissionQueue.ts +0 -52
|
@@ -109,18 +109,19 @@ describe('StatusBar', () => {
|
|
|
109
109
|
);
|
|
110
110
|
const frame = lastFrame()!;
|
|
111
111
|
expect(frame).not.toContain('Activity:');
|
|
112
|
-
expect(frame).toContain('Tools
|
|
112
|
+
expect(frame).toContain('Tools (2)');
|
|
113
|
+
expect(frame).not.toContain('Tools x2');
|
|
113
114
|
expect(frame).toContain('queued');
|
|
114
115
|
expect(frame).not.toContain('thinking...');
|
|
115
|
-
expect(frame.indexOf('Tools
|
|
116
|
+
expect(frame.indexOf('Tools (2)')).toBeLessThan(frame.indexOf('test-model'));
|
|
116
117
|
expect(frame).not.toContain('Thinking...');
|
|
117
118
|
});
|
|
118
119
|
|
|
119
120
|
it('shows background activity when no foreground execution is active', () => {
|
|
120
121
|
const { lastFrame } = render(<StatusBar {...baseProps} activeBackgroundTaskCount={3} />);
|
|
121
122
|
const frame = lastFrame()!;
|
|
122
|
-
expect(frame).toContain('Background
|
|
123
|
-
expect(frame.indexOf('Background
|
|
123
|
+
expect(frame).toContain('Background (3)');
|
|
124
|
+
expect(frame.indexOf('Background (3)')).toBeLessThan(frame.indexOf('test-model'));
|
|
124
125
|
});
|
|
125
126
|
|
|
126
127
|
it('keeps the activity segment compact for narrow terminals', () => {
|
|
@@ -134,10 +135,10 @@ describe('StatusBar', () => {
|
|
|
134
135
|
/>,
|
|
135
136
|
);
|
|
136
137
|
const frame = lastFrame()!;
|
|
137
|
-
const firstLine = frame.split('\n')[
|
|
138
|
+
const firstLine = frame.split('\n')[0] ?? '';
|
|
138
139
|
const activityEnd = firstLine.indexOf('test-model');
|
|
139
140
|
const activitySegment = firstLine.slice(0, activityEnd);
|
|
140
|
-
expect(activitySegment).toContain('Tools
|
|
141
|
+
expect(activitySegment).toContain('Tools (12)');
|
|
141
142
|
expect(activitySegment.length).toBeLessThanOrEqual(40);
|
|
142
143
|
});
|
|
143
144
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import type { IAIProvider } from '@robota-sdk/agent-core';
|
|
3
|
+
|
|
4
|
+
vi.mock('@robota-sdk/agent-framework', async (importOriginal) => {
|
|
5
|
+
const mod = await importOriginal<typeof import('@robota-sdk/agent-framework')>();
|
|
6
|
+
|
|
7
|
+
class FakeInteractiveSession {
|
|
8
|
+
on(): void {}
|
|
9
|
+
off(): void {}
|
|
10
|
+
getFullHistory(): unknown[] {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
getContextState(): never {
|
|
14
|
+
throw new Error('ENOENT: session store unreadable');
|
|
15
|
+
}
|
|
16
|
+
getName(): string | undefined {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
getSession(): { getSessionId: () => string } {
|
|
20
|
+
return { getSessionId: () => 'test-session' };
|
|
21
|
+
}
|
|
22
|
+
async shutdown(): Promise<void> {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { ...mod, InteractiveSession: FakeInteractiveSession };
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
import { TuiInteractionChannel } from '../TuiInteractionChannel.js';
|
|
29
|
+
|
|
30
|
+
describe('TuiInteractionChannel init failure surfacing', () => {
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
vi.useFakeTimers();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
vi.useRealTimers();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('TC-05: a real init error records a session-init-error entry and sets error state', async () => {
|
|
40
|
+
const channel = new TuiInteractionChannel({
|
|
41
|
+
cwd: '/tmp/project',
|
|
42
|
+
provider: {} as IAIProvider,
|
|
43
|
+
});
|
|
44
|
+
await channel.start();
|
|
45
|
+
|
|
46
|
+
vi.advanceTimersByTime(400);
|
|
47
|
+
|
|
48
|
+
const entries = channel.stateManager.history;
|
|
49
|
+
const initError = entries.find((e) => e.type === 'session-init-error');
|
|
50
|
+
expect(initError).toBeDefined();
|
|
51
|
+
const message = (initError?.data as { message?: string } | undefined)?.message ?? '';
|
|
52
|
+
expect(message).toContain('Session initialization failed');
|
|
53
|
+
expect(message).toContain('ENOENT');
|
|
54
|
+
|
|
55
|
+
await channel.stop();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { describe, it, expect, vi } from 'vitest';
|
|
7
7
|
import { TuiStateManager } from '../tui-state-manager.js';
|
|
8
|
-
import type {
|
|
8
|
+
import type { IExecutionResult, IToolState } from '@robota-sdk/agent-interface-transport';
|
|
9
9
|
|
|
10
10
|
function makeResult(overrides?: Partial<IExecutionResult>): IExecutionResult {
|
|
11
11
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formatExecutionWorkspaceEntryRow } from './execution-workspace-view-model.js';
|
|
2
2
|
|
|
3
|
-
import type { IExecutionWorkspaceEntry } from '@robota-sdk/agent-
|
|
3
|
+
import type { IExecutionWorkspaceEntry } from '@robota-sdk/agent-interface-transport';
|
|
4
4
|
|
|
5
5
|
export interface IBackgroundTaskRow {
|
|
6
6
|
connector: '├' | '└';
|
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
IExecutionWorkspaceEntry,
|
|
4
4
|
IExecutionWorkspaceSnapshot,
|
|
5
5
|
TExecutionWorkspaceStatus,
|
|
6
|
-
} from '@robota-sdk/agent-
|
|
6
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
7
7
|
|
|
8
8
|
const ACTIVE_STATUSES: readonly TExecutionWorkspaceStatus[] = [
|
|
9
9
|
'active',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isSlashCommand, tokeniseSlashCommand } from '@robota-sdk/agent-framework';
|
|
2
2
|
|
|
3
3
|
import type { IHistoryEntry, TUniversalValue } from '@robota-sdk/agent-core';
|
|
4
|
-
import type { ICommand } from '@robota-sdk/agent-
|
|
4
|
+
import type { ICommand } from '@robota-sdk/agent-interface-transport';
|
|
5
5
|
|
|
6
6
|
export interface IAutocompleteInputKey {
|
|
7
7
|
upArrow?: boolean;
|
|
@@ -67,7 +67,7 @@ export function applyPermissionPromptInput(
|
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
function getPermissionDecision(index: number): TPermissionPromptDecision {
|
|
71
71
|
if (index === 0) return true;
|
|
72
72
|
if (index === 1) return 'allow-session';
|
|
73
73
|
if (index === 2) return 'allow-project';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded polling helper for asynchronous session initialization.
|
|
3
|
+
*
|
|
4
|
+
* Distinguishes benign "not yet initialized" errors (retried until a timeout)
|
|
5
|
+
* from real failures (surfaced immediately), so the TUI can show an error
|
|
6
|
+
* instead of spinning forever.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type TSessionInitFailure =
|
|
10
|
+
| { kind: 'timeout'; lastError: Error | undefined }
|
|
11
|
+
| { kind: 'error'; error: Error };
|
|
12
|
+
|
|
13
|
+
export interface ISessionInitPollerOptions {
|
|
14
|
+
/** Throws while the session is not ready; returns normally when ready. */
|
|
15
|
+
check: () => void;
|
|
16
|
+
intervalMs: number;
|
|
17
|
+
timeoutMs: number;
|
|
18
|
+
/** Returns true when an error means "keep polling". Defaults to /not initialized/i. */
|
|
19
|
+
isBenignError?: (error: Error) => boolean;
|
|
20
|
+
onReady: () => void;
|
|
21
|
+
onFailure: (failure: TSessionInitFailure) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ISessionInitPoller {
|
|
25
|
+
start(): void;
|
|
26
|
+
stop(): void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function defaultIsBenignError(error: Error): boolean {
|
|
30
|
+
return /not initialized/i.test(error.message);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function createSessionInitPoller(options: ISessionInitPollerOptions): ISessionInitPoller {
|
|
34
|
+
const isBenign = options.isBenignError ?? defaultIsBenignError;
|
|
35
|
+
let timer: ReturnType<typeof setInterval> | null = null;
|
|
36
|
+
let elapsedMs = 0;
|
|
37
|
+
let lastBenignError: Error | undefined;
|
|
38
|
+
|
|
39
|
+
function stop(): void {
|
|
40
|
+
if (timer !== null) {
|
|
41
|
+
clearInterval(timer);
|
|
42
|
+
timer = null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function tick(): void {
|
|
47
|
+
elapsedMs += options.intervalMs;
|
|
48
|
+
try {
|
|
49
|
+
options.check();
|
|
50
|
+
} catch (raw) {
|
|
51
|
+
// allow-fallback: poller's purpose is to classify and route this error, never to swallow it
|
|
52
|
+
const error = raw instanceof Error ? raw : new Error(String(raw));
|
|
53
|
+
if (!isBenign(error)) {
|
|
54
|
+
stop();
|
|
55
|
+
options.onFailure({ kind: 'error', error });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
lastBenignError = error;
|
|
59
|
+
if (elapsedMs >= options.timeoutMs) {
|
|
60
|
+
stop();
|
|
61
|
+
options.onFailure({ kind: 'timeout', lastError: lastBenignError });
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
stop();
|
|
66
|
+
options.onReady();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
start(): void {
|
|
71
|
+
if (timer !== null) return;
|
|
72
|
+
elapsedMs = 0;
|
|
73
|
+
timer = setInterval(tick, options.intervalMs);
|
|
74
|
+
},
|
|
75
|
+
stop,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -3,7 +3,10 @@ import { isStatusLineCommandSettingsPatch } from '@robota-sdk/agent-framework';
|
|
|
3
3
|
|
|
4
4
|
import type { ITuiCliAdapter } from '../tui-cli-adapter.js';
|
|
5
5
|
import type { IHistoryEntry, TSessionEndReason } from '@robota-sdk/agent-core';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
TCommandEffect,
|
|
8
|
+
TStatusLineCommandSettingsPatch,
|
|
9
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
7
10
|
|
|
8
11
|
export interface ICommandEffectHandlerDeps {
|
|
9
12
|
addEntry: (entry: IHistoryEntry) => void;
|
|
@@ -2,9 +2,9 @@ import type { ICommandEffectQueue } from './command-effect-queue.js';
|
|
|
2
2
|
import type { IHistoryEntry } from '@robota-sdk/agent-core';
|
|
3
3
|
import type { InteractiveSession } from '@robota-sdk/agent-framework';
|
|
4
4
|
import type {
|
|
5
|
-
TCommandInteractionPrompt as TInteractivePrompt,
|
|
6
5
|
IStatusLineCommandSettings as TStatusLineSettings,
|
|
7
|
-
|
|
6
|
+
TCommandInteractionPrompt as TInteractivePrompt,
|
|
7
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
8
8
|
|
|
9
9
|
export type { TInteractivePrompt, TStatusLineSettings };
|
|
10
10
|
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
import React, { useState, useMemo } from 'react';
|
|
7
7
|
|
|
8
|
-
import type { CommandRegistry
|
|
8
|
+
import type { CommandRegistry } from '@robota-sdk/agent-framework';
|
|
9
|
+
import type { ICommand } from '@robota-sdk/agent-interface-transport';
|
|
9
10
|
|
|
10
11
|
/** Parse input to determine autocomplete state */
|
|
11
|
-
|
|
12
|
+
function parseSlashInput(value: string): {
|
|
12
13
|
isSlash: boolean;
|
|
13
14
|
parentCommand: string;
|
|
14
15
|
filter: string;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { useMemo } from 'react';
|
|
10
10
|
|
|
11
|
-
import type { ICommandPluginAdapter } from '@robota-sdk/agent-
|
|
11
|
+
import type { ICommandPluginAdapter } from '@robota-sdk/agent-interface-transport';
|
|
12
12
|
|
|
13
13
|
function createNoOpPluginAdapter(): ICommandPluginAdapter {
|
|
14
14
|
return {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { useState, useEffect } from 'react';
|
|
7
7
|
|
|
8
8
|
import type { IMenuSelectItem } from '../MenuSelect.js';
|
|
9
|
-
import type { ICommandPluginAdapter } from '@robota-sdk/agent-
|
|
9
|
+
import type { ICommandPluginAdapter } from '@robota-sdk/agent-interface-transport';
|
|
10
10
|
|
|
11
11
|
export function usePluginScreenData(
|
|
12
12
|
screen: string,
|
|
@@ -8,7 +8,7 @@ import { useTuiCliAdapter } from '../tui-cli-adapter-context.js';
|
|
|
8
8
|
import type { IUseSideEffectsOptions, IUseSideEffectsResult } from './side-effects-types.js';
|
|
9
9
|
import type { TInteractivePrompt } from './side-effects-types.js';
|
|
10
10
|
import type { TSessionEndReason } from '@robota-sdk/agent-core';
|
|
11
|
-
import type { ICommandInteraction, ICommandResult } from '@robota-sdk/agent-
|
|
11
|
+
import type { ICommandInteraction, ICommandResult } from '@robota-sdk/agent-interface-transport';
|
|
12
12
|
|
|
13
13
|
const EXIT_DELAY_MS = 500;
|
|
14
14
|
|
|
@@ -8,12 +8,12 @@ import { useCallback } from 'react';
|
|
|
8
8
|
|
|
9
9
|
import type { TuiStateManager } from '../tui-state-manager.js';
|
|
10
10
|
import type { ICommandEffectQueue } from './command-effect-queue.js';
|
|
11
|
+
import type { CommandRegistry } from '@robota-sdk/agent-framework';
|
|
11
12
|
import type {
|
|
12
|
-
IInteractiveSession,
|
|
13
|
-
CommandRegistry,
|
|
14
13
|
ICommandResult,
|
|
14
|
+
IInteractiveSession,
|
|
15
15
|
TCommandEffect,
|
|
16
|
-
} from '@robota-sdk/agent-
|
|
16
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
17
17
|
|
|
18
18
|
export function useSlashRouting(
|
|
19
19
|
interactiveSession: IInteractiveSession,
|
|
@@ -4,7 +4,7 @@ import { useState } from 'react';
|
|
|
4
4
|
import { useTuiCliAdapter } from '../tui-cli-adapter-context.js';
|
|
5
5
|
|
|
6
6
|
import type { TUniversalValue } from '@robota-sdk/agent-core';
|
|
7
|
-
import type { IStatusLineCommandSettings } from '@robota-sdk/agent-
|
|
7
|
+
import type { IStatusLineCommandSettings } from '@robota-sdk/agent-interface-transport';
|
|
8
8
|
|
|
9
9
|
function readStatusLineSettings(
|
|
10
10
|
settings: Record<string, TUniversalValue>,
|
|
@@ -13,10 +13,10 @@ import type { IPermissionRequest } from '../types.js';
|
|
|
13
13
|
import type { IHistoryEntry, TSessionEndReason } from '@robota-sdk/agent-core';
|
|
14
14
|
import type { InteractiveSession, CommandRegistry } from '@robota-sdk/agent-framework';
|
|
15
15
|
import type {
|
|
16
|
-
IToolState,
|
|
17
|
-
IExecutionWorkspaceSnapshot,
|
|
18
16
|
IExecutionDetailPage,
|
|
19
|
-
|
|
17
|
+
IExecutionWorkspaceSnapshot,
|
|
18
|
+
IToolState,
|
|
19
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
20
20
|
|
|
21
21
|
export interface IInteractiveSessionState {
|
|
22
22
|
interactiveSession: InteractiveSession;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { IMenuSelectItem } from './MenuSelect.js';
|
|
7
|
-
import type { ICommandPluginAdapter } from '@robota-sdk/agent-
|
|
7
|
+
import type { ICommandPluginAdapter } from '@robota-sdk/agent-interface-transport';
|
|
8
8
|
|
|
9
9
|
interface IConfirmState {
|
|
10
10
|
message: string;
|
package/src/tui/render.tsx
CHANGED
|
@@ -15,13 +15,15 @@ import type {
|
|
|
15
15
|
IBackgroundTaskRunner,
|
|
16
16
|
ICommandHostAdapters,
|
|
17
17
|
ICommandModule,
|
|
18
|
-
IInteractiveSession,
|
|
19
|
-
IInteractiveSessionStore,
|
|
20
18
|
TSubagentRunnerFactory,
|
|
21
19
|
TShellExecFn,
|
|
22
20
|
CommandRegistry,
|
|
23
21
|
} from '@robota-sdk/agent-framework';
|
|
24
|
-
import type {
|
|
22
|
+
import type {
|
|
23
|
+
IInteractiveSession,
|
|
24
|
+
IInteractiveSessionStore,
|
|
25
|
+
ITransportRegistryView,
|
|
26
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
25
27
|
|
|
26
28
|
export interface IRenderOptions {
|
|
27
29
|
cwd: string;
|
|
@@ -32,6 +34,8 @@ export interface IRenderOptions {
|
|
|
32
34
|
language?: string;
|
|
33
35
|
permissionMode?: TPermissionMode;
|
|
34
36
|
maxTurns?: number;
|
|
37
|
+
allowedTools?: string[];
|
|
38
|
+
deniedTools?: string[];
|
|
35
39
|
version?: string;
|
|
36
40
|
sessionStore?: IInteractiveSessionStore;
|
|
37
41
|
resumeSessionId?: string;
|
|
@@ -50,6 +54,34 @@ export interface IRenderOptions {
|
|
|
50
54
|
agentName?: string;
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
/** Map render options to TuiInteractionChannel constructor options. */
|
|
58
|
+
export function toChannelOptions(
|
|
59
|
+
options: IRenderOptions,
|
|
60
|
+
resumeSessionId?: string,
|
|
61
|
+
): ConstructorParameters<typeof TuiInteractionChannel>[0] {
|
|
62
|
+
return {
|
|
63
|
+
cwd: options.cwd,
|
|
64
|
+
provider: options.provider,
|
|
65
|
+
permissionMode: options.permissionMode,
|
|
66
|
+
maxTurns: options.maxTurns,
|
|
67
|
+
allowedTools: options.allowedTools,
|
|
68
|
+
deniedTools: options.deniedTools,
|
|
69
|
+
sessionStore: options.sessionStore,
|
|
70
|
+
resumeSessionId,
|
|
71
|
+
forkSession: options.forkSession,
|
|
72
|
+
sessionName: options.sessionName,
|
|
73
|
+
backgroundTaskRunners: options.backgroundTaskRunners,
|
|
74
|
+
subagentRunnerFactory: options.subagentRunnerFactory,
|
|
75
|
+
commandModules: options.commandModules,
|
|
76
|
+
commandHostAdapters: options.commandHostAdapters,
|
|
77
|
+
shellExec: options.shellExec,
|
|
78
|
+
transportRegistry: options.transportRegistry,
|
|
79
|
+
language: options.language,
|
|
80
|
+
reloadPluginCommandSource: options.reloadPluginCommandSource,
|
|
81
|
+
agentName: options.agentName,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
53
85
|
export async function renderApp(options: IRenderOptions): Promise<void> {
|
|
54
86
|
process.on('unhandledRejection', (reason) => {
|
|
55
87
|
process.stderr.write(`\n[UNHANDLED REJECTION] ${reason}\n`);
|
|
@@ -58,33 +90,14 @@ export async function renderApp(options: IRenderOptions): Promise<void> {
|
|
|
58
90
|
}
|
|
59
91
|
});
|
|
60
92
|
|
|
93
|
+
// Single-owner lifecycle (CLI-B12): render.tsx supplies only the factory;
|
|
94
|
+
// App creates, replaces, and stops channels exclusively through React state.
|
|
61
95
|
const createChannel = (resumeSessionId?: string): TuiInteractionChannel =>
|
|
62
|
-
new TuiInteractionChannel(
|
|
63
|
-
cwd: options.cwd,
|
|
64
|
-
provider: options.provider,
|
|
65
|
-
permissionMode: options.permissionMode,
|
|
66
|
-
maxTurns: options.maxTurns,
|
|
67
|
-
sessionStore: options.sessionStore,
|
|
68
|
-
resumeSessionId,
|
|
69
|
-
forkSession: options.forkSession,
|
|
70
|
-
sessionName: options.sessionName,
|
|
71
|
-
backgroundTaskRunners: options.backgroundTaskRunners,
|
|
72
|
-
subagentRunnerFactory: options.subagentRunnerFactory,
|
|
73
|
-
commandModules: options.commandModules,
|
|
74
|
-
commandHostAdapters: options.commandHostAdapters,
|
|
75
|
-
shellExec: options.shellExec,
|
|
76
|
-
transportRegistry: options.transportRegistry,
|
|
77
|
-
language: options.language,
|
|
78
|
-
reloadPluginCommandSource: options.reloadPluginCommandSource,
|
|
79
|
-
agentName: options.agentName,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
const channel = createChannel(options.resumeSessionId);
|
|
96
|
+
new TuiInteractionChannel(toChannelOptions(options, resumeSessionId));
|
|
83
97
|
|
|
84
98
|
const instance = render(
|
|
85
99
|
<App
|
|
86
100
|
cwd={options.cwd}
|
|
87
|
-
channel={channel}
|
|
88
101
|
createChannel={createChannel}
|
|
89
102
|
providerOverride={options.providerOverride}
|
|
90
103
|
providerType={options.providerType}
|
|
@@ -30,7 +30,7 @@ function getPrimaryActivity(
|
|
|
30
30
|
if (input.activeToolCount > NO_ACTIVE_ITEMS) {
|
|
31
31
|
return {
|
|
32
32
|
kind: 'tools',
|
|
33
|
-
label: `Tools
|
|
33
|
+
label: `Tools (${input.activeToolCount})`,
|
|
34
34
|
color: 'cyan',
|
|
35
35
|
};
|
|
36
36
|
}
|
|
@@ -44,7 +44,7 @@ function getPrimaryActivity(
|
|
|
44
44
|
if (input.activeBackgroundTaskCount > NO_ACTIVE_ITEMS) {
|
|
45
45
|
return {
|
|
46
46
|
kind: 'background',
|
|
47
|
-
label: `Background
|
|
47
|
+
label: `Background (${input.activeBackgroundTaskCount})`,
|
|
48
48
|
color: 'cyan',
|
|
49
49
|
};
|
|
50
50
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { TUniversalValue } from '@robota-sdk/agent-core';
|
|
2
|
+
import type { CommandRegistry } from '@robota-sdk/agent-framework';
|
|
2
3
|
import type {
|
|
3
|
-
TStatusLineCommandSettingsPatch,
|
|
4
4
|
IStatusLineCommandSettings,
|
|
5
|
-
|
|
6
|
-
} from '@robota-sdk/agent-
|
|
5
|
+
TStatusLineCommandSettingsPatch,
|
|
6
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
7
7
|
|
|
8
8
|
export interface ITuiCliAdapter {
|
|
9
9
|
getUserSettingsPath(): string;
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
import type { IContextWindowState, IHistoryEntry } from '@robota-sdk/agent-core';
|
|
12
12
|
import type {
|
|
13
|
-
IToolState,
|
|
14
13
|
IExecutionResult,
|
|
15
14
|
IExecutionWorkspaceSnapshot,
|
|
16
|
-
|
|
15
|
+
IToolState,
|
|
16
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
17
17
|
|
|
18
18
|
/** Max messages kept in rendering state */
|
|
19
19
|
const MAX_RENDERED_MESSAGES = 100;
|
package/src/tui/tui-transport.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { renderApp, type IRenderOptions } from './render.js';
|
|
2
2
|
|
|
3
3
|
import type { TUniversalValue } from '@robota-sdk/agent-core';
|
|
4
|
-
import type {
|
|
5
|
-
|
|
4
|
+
import type {
|
|
5
|
+
IConfigurableTransport,
|
|
6
|
+
IInteractiveSession,
|
|
7
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
6
8
|
|
|
7
9
|
export class TuiTransport implements IConfigurableTransport<IInteractiveSession> {
|
|
8
10
|
readonly name = 'tui';
|
|
@@ -6,15 +6,17 @@ import { describe, it, expect, vi } from 'vitest';
|
|
|
6
6
|
import { createWsHandler } from '../ws-handler.js';
|
|
7
7
|
import type { TServerMessage } from '../ws-protocol.js';
|
|
8
8
|
import type {
|
|
9
|
-
|
|
10
|
-
IBackgroundTaskState,
|
|
9
|
+
IBackgroundJobGroupState,
|
|
11
10
|
IExecutionWorkspaceEvent,
|
|
12
11
|
IExecutionWorkspaceSnapshot,
|
|
13
12
|
IInteractiveSession,
|
|
14
|
-
IBackgroundJobGroupState,
|
|
15
13
|
TBackgroundJobGroupEvent,
|
|
16
|
-
TBackgroundTaskEvent,
|
|
17
14
|
TExecutionWorkspaceUpdateCause,
|
|
15
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
16
|
+
import type {
|
|
17
|
+
IBackgroundTaskLogPage,
|
|
18
|
+
IBackgroundTaskState,
|
|
19
|
+
TBackgroundTaskEvent,
|
|
18
20
|
} from '@robota-sdk/agent-framework';
|
|
19
21
|
|
|
20
22
|
const backgroundTask: IBackgroundTaskState = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { createWsTransport } from '../ws-transport.js';
|
|
3
|
-
import type { IInteractiveSession } from '@robota-sdk/agent-
|
|
3
|
+
import type { IInteractiveSession } from '@robota-sdk/agent-interface-transport';
|
|
4
4
|
|
|
5
5
|
function createMockSession(): IInteractiveSession {
|
|
6
6
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TBackgroundControlAction, TClientMessage, TServerMessage } from './ws-protocol.js';
|
|
2
|
-
import type { IInteractiveSession } from '@robota-sdk/agent-
|
|
2
|
+
import type { IInteractiveSession } from '@robota-sdk/agent-interface-transport';
|
|
3
3
|
|
|
4
4
|
export function handleBackgroundQueryMessage(
|
|
5
5
|
session: IInteractiveSession,
|
package/src/ws/ws-handler.ts
CHANGED
|
@@ -14,14 +14,14 @@ import {
|
|
|
14
14
|
} from './ws-background-messages.js';
|
|
15
15
|
|
|
16
16
|
import type { TClientMessage, TServerMessage } from './ws-protocol.js';
|
|
17
|
+
import type { TBackgroundTaskEvent } from '@robota-sdk/agent-framework';
|
|
17
18
|
import type {
|
|
18
|
-
IInteractiveSession,
|
|
19
19
|
IExecutionResult,
|
|
20
20
|
IExecutionWorkspaceEvent,
|
|
21
|
-
|
|
22
|
-
TBackgroundTaskEvent,
|
|
21
|
+
IInteractiveSession,
|
|
23
22
|
IToolState,
|
|
24
|
-
|
|
23
|
+
TBackgroundJobGroupEvent,
|
|
24
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
25
25
|
|
|
26
26
|
export interface IWsHandlerOptions {
|
|
27
27
|
/** IInteractiveSession to expose. */
|
package/src/ws/ws-protocol.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
InteractiveSession,
|
|
3
|
-
ICommandResult,
|
|
4
|
-
IBackgroundJobGroupState,
|
|
5
3
|
IBackgroundTaskInput,
|
|
6
4
|
IBackgroundTaskListFilter,
|
|
7
5
|
IBackgroundTaskLogCursor,
|
|
8
6
|
IBackgroundTaskLogPage,
|
|
9
7
|
IBackgroundTaskState,
|
|
8
|
+
TBackgroundTaskEvent,
|
|
9
|
+
} from '@robota-sdk/agent-framework';
|
|
10
|
+
import type {
|
|
11
|
+
IBackgroundJobGroupState,
|
|
12
|
+
ICommandResult,
|
|
10
13
|
IExecutionResult,
|
|
11
14
|
IExecutionWorkspaceSnapshot,
|
|
12
15
|
IToolState,
|
|
13
16
|
TBackgroundJobGroupEvent,
|
|
14
|
-
|
|
15
|
-
} from '@robota-sdk/agent-framework';
|
|
17
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
16
18
|
|
|
17
19
|
export type TBackgroundControlAction = 'cancel' | 'close' | 'send';
|
|
18
20
|
|
|
@@ -11,8 +11,10 @@ import { createWsHandler } from './ws-handler.js';
|
|
|
11
11
|
|
|
12
12
|
import type { TServerMessage } from './ws-protocol.js';
|
|
13
13
|
import type { TUniversalValue } from '@robota-sdk/agent-core';
|
|
14
|
-
import type {
|
|
15
|
-
|
|
14
|
+
import type {
|
|
15
|
+
IConfigurableTransport,
|
|
16
|
+
IInteractiveSession,
|
|
17
|
+
} from '@robota-sdk/agent-interface-transport';
|
|
16
18
|
|
|
17
19
|
const DEFAULT_PORT = 7070;
|
|
18
20
|
const DEFAULT_MAX_RETRIES = 20;
|
package/src/ws/ws-transport.ts
CHANGED
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
import { createWsHandler } from './ws-handler.js';
|
|
9
9
|
|
|
10
10
|
import type { TServerMessage } from './ws-protocol.js';
|
|
11
|
-
import type { IInteractiveSession } from '@robota-sdk/agent-
|
|
12
|
-
import type { ITransportAdapter } from '@robota-sdk/agent-interface-transport';
|
|
11
|
+
import type { IInteractiveSession, ITransportAdapter } from '@robota-sdk/agent-interface-transport';
|
|
13
12
|
|
|
14
13
|
export interface IWsTransportOptions {
|
|
15
14
|
/** Send a JSON message to the connected WebSocket client. */
|