@robota-sdk/agent-transport 3.0.0-beta.69 → 3.0.0-beta.71
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 +2 -2
- package/dist/node/headless/index.js +1 -1
- package/dist/node/headless-C6tj35h3.js +15 -0
- package/dist/node/headless-C6tj35h3.js.map +1 -0
- package/dist/node/headless-DCtHvyVf.cjs +14 -0
- package/dist/node/http/index.d.ts +1 -1
- package/dist/node/index-27HV5PJB.d.ts +68 -0
- package/dist/node/index-27HV5PJB.d.ts.map +1 -0
- package/dist/node/index-BRchlFBE.d.ts +68 -0
- package/dist/node/index-BRchlFBE.d.ts.map +1 -0
- package/dist/node/{index-C7DvsmEg.d.ts → index-BRgV_MPB.d.ts} +2 -2
- package/dist/node/{index-C7DvsmEg.d.ts.map → index-BRgV_MPB.d.ts.map} +1 -1
- package/dist/node/{index-D-aT_t_N.d.ts → index-BVNhOeeU.d.ts} +3 -2
- package/dist/node/{index-D-aT_t_N.d.ts.map → index-BVNhOeeU.d.ts.map} +1 -1
- package/dist/node/{index-yvGShbDx.d.ts → index-COWvtBa2.d.ts} +2 -2
- package/dist/node/{index-yvGShbDx.d.ts.map → index-COWvtBa2.d.ts.map} +1 -1
- package/dist/node/{index-ioN9mYAD.d.ts → index-TMAlNHuM.d.ts} +5 -4
- package/dist/node/{index-ioN9mYAD.d.ts.map → index-TMAlNHuM.d.ts.map} +1 -1
- package/dist/node/{index-DOA2KIYt.d.ts → index-nBlMTFkZ.d.ts} +2 -2
- package/dist/node/{index-DOA2KIYt.d.ts.map → index-nBlMTFkZ.d.ts.map} +1 -1
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.ts +7 -7
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/dist/node/mcp/index.d.ts +1 -1
- package/dist/node/tui/index.cjs +1 -1
- package/dist/node/tui/index.d.ts +2 -2
- package/dist/node/tui/index.js +1 -1
- package/dist/node/tui-Bl-bm9iA.js +25 -0
- package/dist/node/tui-Bl-bm9iA.js.map +1 -0
- package/dist/node/tui-DULGN7sr.cjs +24 -0
- package/dist/node/ws/index.d.ts +1 -1
- package/package.json +6 -6
- package/src/headless/HeadlessInteractionChannel.ts +84 -0
- package/src/headless/index.ts +2 -0
- package/src/tui/App.tsx +38 -60
- package/src/tui/InputArea.tsx +3 -59
- package/src/tui/StatusBar.tsx +1 -1
- package/src/tui/TuiInteractionChannel.ts +461 -0
- package/src/tui/__tests__/TuiInteractionChannel.display-contract.test.ts +239 -0
- package/src/tui/__tests__/TuiInteractionChannel.lifecycle.test.ts +294 -0
- package/src/tui/__tests__/TuiInteractionChannel.requestAction.test.ts +124 -0
- package/src/tui/__tests__/compact-event-bridge.test.ts +1 -1
- package/src/tui/__tests__/input-area-flow.test.ts +5 -12
- package/src/tui/flows/input-area-flow.ts +10 -15
- package/src/tui/hooks/use-interactive-session-init.ts +37 -2
- package/src/tui/hooks/useSlashRouting.ts +1 -1
- package/src/tui/hooks/useTuiChannel.ts +95 -0
- package/src/tui/index.ts +2 -1
- package/src/tui/interactions/__tests__/CommandConfirm.test.tsx +124 -0
- package/src/tui/interactions/__tests__/CommandPicker.test.tsx +138 -0
- package/src/tui/render.tsx +43 -1
- package/src/tui/tui-state-manager.ts +2 -1
- package/src/tui/tui-transport.ts +1 -1
- package/dist/node/headless-C-Ezlo9U.js +0 -15
- package/dist/node/headless-C-Ezlo9U.js.map +0 -1
- package/dist/node/headless-Cv-igy49.cjs +0 -14
- package/dist/node/index-CP7kaYMg.d.ts +0 -41
- package/dist/node/index-CP7kaYMg.d.ts.map +0 -1
- package/dist/node/index-Gby9H4q2.d.ts +0 -41
- package/dist/node/index-Gby9H4q2.d.ts.map +0 -1
- package/dist/node/tui-87G6pg3z.js +0 -25
- package/dist/node/tui-87G6pg3z.js.map +0 -1
- package/dist/node/tui-BAtwGilM.cjs +0 -24
- package/src/tui/command-interaction-registry.ts +0 -66
- package/src/tui/hooks/useInteractiveSession.ts +0 -299
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from 'ink-testing-library';
|
|
3
|
+
import { describe, it, expect } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import CommandConfirm from '../CommandConfirm.js';
|
|
6
|
+
|
|
7
|
+
import type { ITuiConfirmInteraction } from '../../command-interaction.js';
|
|
8
|
+
|
|
9
|
+
const delay = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));
|
|
10
|
+
|
|
11
|
+
function makeInteraction(message: string): ITuiConfirmInteraction {
|
|
12
|
+
return { onMissingArgs: 'confirm', message };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('CommandConfirm', () => {
|
|
16
|
+
it('renders the message text', () => {
|
|
17
|
+
const { lastFrame } = render(
|
|
18
|
+
<CommandConfirm
|
|
19
|
+
commandName="exit"
|
|
20
|
+
interaction={makeInteraction('Exit the session?')}
|
|
21
|
+
onConfirm={() => {}}
|
|
22
|
+
onCancel={() => {}}
|
|
23
|
+
/>,
|
|
24
|
+
);
|
|
25
|
+
expect(lastFrame()).toContain('Exit the session?');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('calls onConfirm when y is pressed', () => {
|
|
29
|
+
let confirmed = false;
|
|
30
|
+
const { stdin } = render(
|
|
31
|
+
<CommandConfirm
|
|
32
|
+
commandName="exit"
|
|
33
|
+
interaction={makeInteraction('Exit?')}
|
|
34
|
+
onConfirm={() => {
|
|
35
|
+
confirmed = true;
|
|
36
|
+
}}
|
|
37
|
+
onCancel={() => {}}
|
|
38
|
+
/>,
|
|
39
|
+
);
|
|
40
|
+
stdin.write('y');
|
|
41
|
+
expect(confirmed).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('calls onConfirm when Y is pressed', () => {
|
|
45
|
+
let confirmed = false;
|
|
46
|
+
const { stdin } = render(
|
|
47
|
+
<CommandConfirm
|
|
48
|
+
commandName="exit"
|
|
49
|
+
interaction={makeInteraction('Exit?')}
|
|
50
|
+
onConfirm={() => {
|
|
51
|
+
confirmed = true;
|
|
52
|
+
}}
|
|
53
|
+
onCancel={() => {}}
|
|
54
|
+
/>,
|
|
55
|
+
);
|
|
56
|
+
stdin.write('Y');
|
|
57
|
+
expect(confirmed).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('calls onConfirm on Enter', () => {
|
|
61
|
+
let confirmed = false;
|
|
62
|
+
const { stdin } = render(
|
|
63
|
+
<CommandConfirm
|
|
64
|
+
commandName="exit"
|
|
65
|
+
interaction={makeInteraction('Exit?')}
|
|
66
|
+
onConfirm={() => {
|
|
67
|
+
confirmed = true;
|
|
68
|
+
}}
|
|
69
|
+
onCancel={() => {}}
|
|
70
|
+
/>,
|
|
71
|
+
);
|
|
72
|
+
stdin.write('\r');
|
|
73
|
+
expect(confirmed).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('calls onCancel when n is pressed', () => {
|
|
77
|
+
let cancelled = false;
|
|
78
|
+
const { stdin } = render(
|
|
79
|
+
<CommandConfirm
|
|
80
|
+
commandName="exit"
|
|
81
|
+
interaction={makeInteraction('Exit?')}
|
|
82
|
+
onConfirm={() => {}}
|
|
83
|
+
onCancel={() => {
|
|
84
|
+
cancelled = true;
|
|
85
|
+
}}
|
|
86
|
+
/>,
|
|
87
|
+
);
|
|
88
|
+
stdin.write('n');
|
|
89
|
+
expect(cancelled).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('calls onCancel when N is pressed', () => {
|
|
93
|
+
let cancelled = false;
|
|
94
|
+
const { stdin } = render(
|
|
95
|
+
<CommandConfirm
|
|
96
|
+
commandName="exit"
|
|
97
|
+
interaction={makeInteraction('Exit?')}
|
|
98
|
+
onConfirm={() => {}}
|
|
99
|
+
onCancel={() => {
|
|
100
|
+
cancelled = true;
|
|
101
|
+
}}
|
|
102
|
+
/>,
|
|
103
|
+
);
|
|
104
|
+
stdin.write('N');
|
|
105
|
+
expect(cancelled).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('calls onCancel on Escape', async () => {
|
|
109
|
+
let cancelled = false;
|
|
110
|
+
const { stdin } = render(
|
|
111
|
+
<CommandConfirm
|
|
112
|
+
commandName="exit"
|
|
113
|
+
interaction={makeInteraction('Exit?')}
|
|
114
|
+
onConfirm={() => {}}
|
|
115
|
+
onCancel={() => {
|
|
116
|
+
cancelled = true;
|
|
117
|
+
}}
|
|
118
|
+
/>,
|
|
119
|
+
);
|
|
120
|
+
stdin.write('\x1b');
|
|
121
|
+
await delay(50);
|
|
122
|
+
expect(cancelled).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render } from 'ink-testing-library';
|
|
3
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import CommandPicker from '../CommandPicker.js';
|
|
6
|
+
|
|
7
|
+
import type { ITuiPickerInteraction, ITuiPickerItem } from '../../command-interaction.js';
|
|
8
|
+
|
|
9
|
+
const delay = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));
|
|
10
|
+
|
|
11
|
+
function makeInteraction(items: ITuiPickerItem[]): ITuiPickerInteraction {
|
|
12
|
+
return {
|
|
13
|
+
onMissingArgs: 'picker',
|
|
14
|
+
getItems: () => items,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const ITEMS: ITuiPickerItem[] = [
|
|
19
|
+
{ label: 'plan', value: 'plan', description: 'Plan mode' },
|
|
20
|
+
{ label: 'default', value: 'default', description: 'Default mode' },
|
|
21
|
+
{ label: 'auto', value: 'auto' },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
describe('CommandPicker', () => {
|
|
25
|
+
it('renders all item labels', () => {
|
|
26
|
+
const { lastFrame } = render(
|
|
27
|
+
<CommandPicker
|
|
28
|
+
commandName="mode"
|
|
29
|
+
interaction={makeInteraction(ITEMS)}
|
|
30
|
+
onSelect={() => {}}
|
|
31
|
+
onCancel={() => {}}
|
|
32
|
+
/>,
|
|
33
|
+
);
|
|
34
|
+
const frame = lastFrame()!;
|
|
35
|
+
expect(frame).toContain('plan');
|
|
36
|
+
expect(frame).toContain('default');
|
|
37
|
+
expect(frame).toContain('auto');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('highlights first item by default', () => {
|
|
41
|
+
const { lastFrame } = render(
|
|
42
|
+
<CommandPicker
|
|
43
|
+
commandName="mode"
|
|
44
|
+
interaction={makeInteraction(ITEMS)}
|
|
45
|
+
onSelect={() => {}}
|
|
46
|
+
onCancel={() => {}}
|
|
47
|
+
/>,
|
|
48
|
+
);
|
|
49
|
+
const frame = lastFrame()!;
|
|
50
|
+
expect(frame).toContain('▸ plan');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('calls onSelect with first item on Enter', () => {
|
|
54
|
+
const onSelect = vi.fn();
|
|
55
|
+
const { stdin } = render(
|
|
56
|
+
<CommandPicker
|
|
57
|
+
commandName="mode"
|
|
58
|
+
interaction={makeInteraction(ITEMS)}
|
|
59
|
+
onSelect={onSelect}
|
|
60
|
+
onCancel={() => {}}
|
|
61
|
+
/>,
|
|
62
|
+
);
|
|
63
|
+
stdin.write('\r');
|
|
64
|
+
expect(onSelect).toHaveBeenCalledWith(ITEMS[0]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('moves highlight down on arrow-down then selects on Enter', async () => {
|
|
68
|
+
let selected: ITuiPickerItem | undefined;
|
|
69
|
+
const { stdin } = render(
|
|
70
|
+
<CommandPicker
|
|
71
|
+
commandName="mode"
|
|
72
|
+
interaction={makeInteraction(ITEMS)}
|
|
73
|
+
onSelect={(item) => {
|
|
74
|
+
selected = item;
|
|
75
|
+
}}
|
|
76
|
+
onCancel={() => {}}
|
|
77
|
+
/>,
|
|
78
|
+
);
|
|
79
|
+
stdin.write('\x1B[B'); // ↓
|
|
80
|
+
await delay(50);
|
|
81
|
+
stdin.write('\r');
|
|
82
|
+
expect(selected).toEqual(ITEMS[1]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('calls onCancel on Escape', async () => {
|
|
86
|
+
let cancelled = false;
|
|
87
|
+
const { stdin } = render(
|
|
88
|
+
<CommandPicker
|
|
89
|
+
commandName="mode"
|
|
90
|
+
interaction={makeInteraction(ITEMS)}
|
|
91
|
+
onSelect={() => {}}
|
|
92
|
+
onCancel={() => {
|
|
93
|
+
cancelled = true;
|
|
94
|
+
}}
|
|
95
|
+
/>,
|
|
96
|
+
);
|
|
97
|
+
stdin.write('\x1b');
|
|
98
|
+
await delay(50);
|
|
99
|
+
expect(cancelled).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('calls onCancel on q', () => {
|
|
103
|
+
const onCancel = vi.fn();
|
|
104
|
+
const { stdin } = render(
|
|
105
|
+
<CommandPicker
|
|
106
|
+
commandName="mode"
|
|
107
|
+
interaction={makeInteraction(ITEMS)}
|
|
108
|
+
onSelect={() => {}}
|
|
109
|
+
onCancel={onCancel}
|
|
110
|
+
/>,
|
|
111
|
+
);
|
|
112
|
+
stdin.write('q');
|
|
113
|
+
expect(onCancel).toHaveBeenCalled();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('wraps highlight from last to first on arrow-down at bottom', async () => {
|
|
117
|
+
let selected: ITuiPickerItem | undefined;
|
|
118
|
+
const { stdin } = render(
|
|
119
|
+
<CommandPicker
|
|
120
|
+
commandName="mode"
|
|
121
|
+
interaction={makeInteraction(ITEMS)}
|
|
122
|
+
onSelect={(item) => {
|
|
123
|
+
selected = item;
|
|
124
|
+
}}
|
|
125
|
+
onCancel={() => {}}
|
|
126
|
+
/>,
|
|
127
|
+
);
|
|
128
|
+
// Navigate to last item (index 2)
|
|
129
|
+
stdin.write('\x1B[B'); // ↓ to index 1
|
|
130
|
+
await delay(50);
|
|
131
|
+
stdin.write('\x1B[B'); // ↓ to index 2
|
|
132
|
+
await delay(50);
|
|
133
|
+
stdin.write('\x1B[B'); // ↓ wraps to index 0
|
|
134
|
+
await delay(50);
|
|
135
|
+
stdin.write('\r');
|
|
136
|
+
expect(selected).toEqual(ITEMS[0]);
|
|
137
|
+
});
|
|
138
|
+
});
|
package/src/tui/render.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { render } from 'ink';
|
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
8
|
import App from './App.js';
|
|
9
|
+
import { TuiInteractionChannel } from './TuiInteractionChannel.js';
|
|
9
10
|
|
|
10
11
|
import type { ITuiCliAdapter } from './tui-cli-adapter.js';
|
|
11
12
|
import type { IAIProvider } from '@robota-sdk/agent-core';
|
|
@@ -57,6 +58,47 @@ export async function renderApp(options: IRenderOptions): Promise<void> {
|
|
|
57
58
|
}
|
|
58
59
|
});
|
|
59
60
|
|
|
60
|
-
const
|
|
61
|
+
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);
|
|
83
|
+
|
|
84
|
+
const instance = render(
|
|
85
|
+
<App
|
|
86
|
+
cwd={options.cwd}
|
|
87
|
+
channel={channel}
|
|
88
|
+
createChannel={createChannel}
|
|
89
|
+
providerOverride={options.providerOverride}
|
|
90
|
+
providerType={options.providerType}
|
|
91
|
+
modelId={options.modelId}
|
|
92
|
+
permissionMode={options.permissionMode}
|
|
93
|
+
version={options.version}
|
|
94
|
+
sessionStore={options.sessionStore}
|
|
95
|
+
resumeSessionId={options.resumeSessionId}
|
|
96
|
+
showSessionPickerOnStart={options.showSessionPickerOnStart}
|
|
97
|
+
startupUpdateNotice={options.startupUpdateNotice}
|
|
98
|
+
transportRegistry={options.transportRegistry}
|
|
99
|
+
cliAdapter={options.cliAdapter}
|
|
100
|
+
/>,
|
|
101
|
+
{ exitOnCtrlC: false },
|
|
102
|
+
);
|
|
61
103
|
await instance.waitUntilExit();
|
|
62
104
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Converts InteractiveSession events into rendering state.
|
|
5
5
|
* No React dependency. Fully unit-testable.
|
|
6
6
|
*
|
|
7
|
-
* React hook (
|
|
7
|
+
* React hook (useTuiChannel) subscribes to onChange
|
|
8
8
|
* and reads state for rendering.
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -107,6 +107,7 @@ export class TuiStateManager {
|
|
|
107
107
|
this.activeTools = [];
|
|
108
108
|
} else {
|
|
109
109
|
this.isAborting = false;
|
|
110
|
+
this.activeTools = [];
|
|
110
111
|
}
|
|
111
112
|
this.notify();
|
|
112
113
|
};
|
package/src/tui/tui-transport.ts
CHANGED
|
@@ -16,7 +16,7 @@ export class TuiTransport implements IConfigurableTransport<IInteractiveSession>
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
attach(_session: IInteractiveSession): void {
|
|
19
|
-
// TuiTransport creates its own InteractiveSession internally via
|
|
19
|
+
// TuiTransport creates its own InteractiveSession internally via TuiInteractionChannel.
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async start(): Promise<void> {
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import*as e from"node:readline";import{randomUUID as t}from"node:crypto";var n=class{write(e){process.stdout.write(e)}writeLine(e){process.stdout.write(e+`
|
|
2
|
-
`)}writeMarkdown(e){process.stdout.write(e)}writeError(e){process.stderr.write(e+`
|
|
3
|
-
`)}prompt(t){return new Promise(n=>{let r=e.createInterface({input:process.stdin,output:process.stdout,terminal:!1,historySize:0});r.question(t,e=>{r.close(),n(e)})})}async select(e,t=0){for(let n=0;n<e.length;n++){let r=n===t?`>`:` `;process.stdout.write(` ${r} ${n+1}) ${e[n]}\n`)}let n=(await this.prompt(` Choose [1-${e.length}] (default: ${e[t]}): `)).trim().toLowerCase();if(n===``)return t;let r=parseInt(n,10);return!isNaN(r)&&r>=1&&r<=e.length?r-1:t}spinner(e){return{stop(){},update(){}}}};const r=(e,t=!1)=>new Promise((n,r)=>{process.stdout.write(e);let i=``,a=process.stdin,o=a.isRaw;if(!a.isTTY){r(Error(`Cannot prompt for input: stdin is not a TTY.
|
|
4
|
-
Set your API key via environment variable instead:
|
|
5
|
-
ANTHROPIC_API_KEY=<key> robota
|
|
6
|
-
OPENAI_API_KEY=<key> robota`));return}a.setRawMode(!0),a.resume(),a.setEncoding(`utf8`);let s=e=>{for(let r of e)if(r===`\r`||r===`
|
|
7
|
-
`){a.removeListener(`data`,s),a.setRawMode(o??!1),a.pause(),process.stdout.write(`
|
|
8
|
-
`),n(i.trim());return}else r===``||r===`\b`?i.length>0&&(i=i.slice(0,-1),process.stdout.write(`\b \b`)):r===``?(a.removeListener(`data`,s),a.setRawMode(o??!1),a.pause(),process.stdout.write(`
|
|
9
|
-
`),process.exit(0)):r.charCodeAt(0)>=32&&(i+=r,process.stdout.write(t?`*`:r))};a.on(`data`,s)});function i(e){let t=e.trimStart();if(!t.startsWith(`/`))return null;let[n=``,...r]=t.slice(1).split(/\s+/);return n.length===0?null:{name:n,args:r.join(` `)}}async function a(e,t){let n=i(t);if(!n)return{kind:`not-slash`};let r=await e.executeCommand(n.name,n.args);return r?r.effects?.some(e=>e.type===`session-execution-started`)?{kind:`session-execution`}:{kind:`command-result`,result:r}:{kind:`command-result`,result:{message:`Unknown command "/${n.name}".`,success:!1}}}function o(e,n,r){let i=JSON.stringify({type:`stream_event`,event:r,session_id:n(e),uuid:t()});process.stdout.write(i+`
|
|
10
|
-
`)}function s(e,t,n,r){let i=n=>o(e,t,n),a=e=>i({type:`content_block_delta`,delta:{type:`text_delta`,text:e}}),s=e=>i({type:`background_task_event`,background_task_event:e}),l=e=>i({type:`background_job_group_event`,background_job_group_event:e}),u=()=>c(e,{onTextDelta:a,onBackgroundTaskEvent:s,onBackgroundJobGroupEvent:l,onComplete:d,onInterrupted:f,onError:p}),d=i=>{u(),n(t(e),i.response,`success`),r(0)},f=i=>{u(),n(t(e),i.response,`success`),r(0)},p=i=>{u(),n(t(e),``,`error`,i),r(1)};return e.on(`text_delta`,a),e.on(`background_task_event`,s),e.on(`background_job_group_event`,l),e.on(`complete`,d),e.on(`interrupted`,f),e.on(`error`,p),u}function c(e,t){e.off(`text_delta`,t.onTextDelta),e.off(`background_task_event`,t.onBackgroundTaskEvent),e.off(`background_job_group_event`,t.onBackgroundJobGroupEvent),e.off(`complete`,t.onComplete),e.off(`interrupted`,t.onInterrupted),e.off(`error`,t.onError)}function l(e){let{session:t,outputFormat:n}=e;return{run:e=>n===`text`?p(t,e):n===`json`?m(t,e):h(t,e)}}function u(e){let t=e.message.toLowerCase();return t.includes(`api key`)||t.includes(`no provider`)||t.includes(`provider`)?`config_error`:t.includes(`tool`)||t.includes(`execution`)?`tool_error`:`api_error`}function d(e,t,n,r){let i={type:`result`,result:t,session_id:e,subtype:n};n===`error`&&r!==void 0&&(i.error_code=u(r));let a=JSON.stringify(i);process.stdout.write(a+`
|
|
11
|
-
`)}function f(e){try{return e.getSession().getSessionId()}catch{return``}}function p(e,t){return new Promise(n=>{let r=()=>{e.off(`complete`,i),e.off(`interrupted`,o),e.off(`error`,s)},i=e=>{r(),process.stdout.write(e.response+`
|
|
12
|
-
`),n(0)},o=e=>{r(),e.response&&process.stdout.write(e.response+`
|
|
13
|
-
`),n(0)},s=e=>{r(),n(1)};e.on(`complete`,i),e.on(`interrupted`,o),e.on(`error`,s),a(e,t).then(i=>{if(i.kind===`command-result`){r(),process.stdout.write(i.result.message+`
|
|
14
|
-
`),n(+!i.result.success);return}i.kind!==`session-execution`&&e.submit(t)})})}function m(e,t){return new Promise(n=>{let r=()=>{e.off(`complete`,i),e.off(`interrupted`,o),e.off(`error`,s)},i=t=>{r(),d(f(e),t.response,`success`),n(0)},o=t=>{r(),d(f(e),t.response,`success`),n(0)},s=t=>{r(),d(f(e),``,`error`,t),n(1)};e.on(`complete`,i),e.on(`interrupted`,o),e.on(`error`,s),a(e,t).then(i=>{if(i.kind===`command-result`){r(),d(f(e),i.result.message,i.result.success?`success`:`error`),n(+!i.result.success);return}i.kind!==`session-execution`&&e.submit(t)})})}function h(e,t){return new Promise(n=>{let r=s(e,f,d,n);a(e,t).then(i=>{if(i.kind===`command-result`){r(),d(f(e),i.result.message,i.result.success?`success`:`error`),n(+!i.result.success);return}i.kind!==`session-execution`&&e.submit(t)})})}function g(e){let t=null,n=0;return{name:`headless`,attach(e){t=e},async start(){if(!t)throw Error(`No session attached. Call attach() first.`);n=await l({session:t,outputFormat:e.outputFormat}).run(e.prompt)},async stop(){},getExitCode(){return n}}}export{n as i,l as n,r,g as t};
|
|
15
|
-
//# sourceMappingURL=headless-C-Ezlo9U.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"headless-C-Ezlo9U.js","names":[],"sources":["../../src/headless/print-terminal.ts","../../src/headless/cli-input.ts","../../src/headless/headless-stream-json.ts","../../src/headless/headless-runner.ts","../../src/headless/headless-transport.ts"],"sourcesContent":["/**\n * ITerminalOutput implementation for print mode (-p).\n *\n * Writes to stdout/stderr directly. The readline-based prompt and select are\n * only invoked if the agent triggers a permission-gated tool, which is rare in\n * one-shot print mode but must still work correctly.\n */\n\nimport * as readline from 'node:readline';\nimport type { ITerminalOutput, ISpinner } from '@robota-sdk/agent-core';\n\nexport class PrintTerminal implements ITerminalOutput {\n write(text: string): void {\n process.stdout.write(text);\n }\n writeLine(text: string): void {\n process.stdout.write(text + '\\n');\n }\n writeMarkdown(md: string): void {\n process.stdout.write(md);\n }\n writeError(text: string): void {\n process.stderr.write(text + '\\n');\n }\n prompt(question: string): Promise<string> {\n return new Promise<string>((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: false,\n historySize: 0,\n });\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n }\n async select(options: string[], initialIndex = 0): Promise<number> {\n for (let i = 0; i < options.length; i++) {\n const marker = i === initialIndex ? '>' : ' ';\n process.stdout.write(` ${marker} ${i + 1}) ${options[i]}\\n`);\n }\n const answer = await this.prompt(\n ` Choose [1-${options.length}] (default: ${options[initialIndex]}): `,\n );\n const trimmed = answer.trim().toLowerCase();\n if (trimmed === '') return initialIndex;\n const num = parseInt(trimmed, 10);\n if (!isNaN(num) && num >= 1 && num <= options.length) return num - 1;\n return initialIndex;\n }\n spinner(_message: string): ISpinner {\n return { stop(): void {}, update(): void {} };\n }\n}\n","const PRINTABLE_ASCII_START = 32;\n\nexport const promptInput = (label: string, masked = false): Promise<string> =>\n new Promise<string>((resolve, reject) => {\n process.stdout.write(label);\n let input = '';\n const stdin = process.stdin;\n const wasRaw = stdin.isRaw;\n if (!stdin.isTTY) {\n reject(\n new Error(\n 'Cannot prompt for input: stdin is not a TTY.\\n' +\n 'Set your API key via environment variable instead:\\n' +\n ' ANTHROPIC_API_KEY=<key> robota\\n' +\n ' OPENAI_API_KEY=<key> robota',\n ),\n );\n return;\n }\n stdin.setRawMode(true);\n stdin.resume();\n stdin.setEncoding('utf8');\n const onData = (data: string): void => {\n for (const ch of data) {\n if (ch === '\\r' || ch === '\\n') {\n stdin.removeListener('data', onData);\n stdin.setRawMode(wasRaw ?? false);\n stdin.pause();\n process.stdout.write('\\n');\n resolve(input.trim());\n return;\n } else if (ch === '\\x7f' || ch === '\\b') {\n if (input.length > 0) {\n input = input.slice(0, -1);\n process.stdout.write('\\b \\b');\n }\n } else if (ch === '\\x03') {\n stdin.removeListener('data', onData);\n stdin.setRawMode(wasRaw ?? false);\n stdin.pause();\n process.stdout.write('\\n');\n process.exit(0);\n } else if (ch.charCodeAt(0) >= PRINTABLE_ASCII_START) {\n input += ch;\n process.stdout.write(masked ? '*' : ch);\n }\n }\n };\n stdin.on('data', onData);\n });\n","import { randomUUID } from 'node:crypto';\n\nimport type {\n IInteractiveSession,\n IExecutionResult,\n ICommandResult,\n TBackgroundJobGroupEvent,\n TBackgroundTaskEvent,\n} from '@robota-sdk/agent-framework';\n\ntype TSlashCommandExecution =\n | { readonly kind: 'not-slash' }\n | { readonly kind: 'command-result'; readonly result: ICommandResult }\n | { readonly kind: 'session-execution' };\n\nfunction parseSlashCommand(prompt: string): { name: string; args: string } | null {\n const trimmed = prompt.trimStart();\n if (!trimmed.startsWith('/')) return null;\n const withoutSlash = trimmed.slice(1);\n const [name = '', ...args] = withoutSlash.split(/\\s+/);\n if (name.length === 0) return null;\n return { name, args: args.join(' ') };\n}\n\nexport async function executeSlashCommandIfPresent(\n session: IInteractiveSession,\n prompt: string,\n): Promise<TSlashCommandExecution> {\n const command = parseSlashCommand(prompt);\n if (!command) return { kind: 'not-slash' };\n\n const result = await session.executeCommand(command.name, command.args);\n if (result) {\n if (result.effects?.some((effect) => effect.type === 'session-execution-started')) {\n return { kind: 'session-execution' };\n }\n return { kind: 'command-result', result };\n }\n return {\n kind: 'command-result',\n result: { message: `Unknown command \"/${command.name}\".`, success: false },\n };\n}\n\ntype TStreamJsonEvent =\n | {\n type: 'content_block_delta';\n delta: { type: 'text_delta'; text: string };\n }\n | {\n type: 'background_task_event';\n background_task_event: TBackgroundTaskEvent;\n }\n | {\n type: 'background_job_group_event';\n background_job_group_event: TBackgroundJobGroupEvent;\n };\n\ninterface IStreamJsonHandlers {\n onTextDelta: (text: string) => void;\n onBackgroundTaskEvent: (event: TBackgroundTaskEvent) => void;\n onBackgroundJobGroupEvent: (event: TBackgroundJobGroupEvent) => void;\n onComplete: (result: IExecutionResult) => void;\n onInterrupted: (result: IExecutionResult) => void;\n onError: (error: Error) => void;\n}\n\nexport function writeStreamJsonEvent(\n session: IInteractiveSession,\n getSessionId: (s: IInteractiveSession) => string,\n event: TStreamJsonEvent,\n): void {\n const output = JSON.stringify({\n type: 'stream_event',\n event,\n session_id: getSessionId(session),\n uuid: randomUUID(),\n });\n process.stdout.write(output + '\\n');\n}\n\nexport function subscribeStreamJsonEvents(\n session: IInteractiveSession,\n getSessionId: (s: IInteractiveSession) => string,\n writeJsonResult: (\n sessionId: string,\n result: string,\n subtype: 'success' | 'error',\n error?: Error,\n ) => void,\n resolve: (exitCode: number) => void,\n): () => void {\n const emit = (event: TStreamJsonEvent): void =>\n writeStreamJsonEvent(session, getSessionId, event);\n\n const onTextDelta = (text: string): void =>\n emit({ type: 'content_block_delta', delta: { type: 'text_delta', text } });\n const onBackgroundTaskEvent = (event: TBackgroundTaskEvent): void =>\n emit({ type: 'background_task_event', background_task_event: event });\n const onBackgroundJobGroupEvent = (event: TBackgroundJobGroupEvent): void =>\n emit({ type: 'background_job_group_event', background_job_group_event: event });\n\n const cleanup = (): void =>\n unsubscribeStreamJsonEvents(session, {\n onTextDelta,\n onBackgroundTaskEvent,\n onBackgroundJobGroupEvent,\n onComplete,\n onInterrupted,\n onError,\n });\n\n const onComplete = (result: IExecutionResult): void => {\n cleanup();\n writeJsonResult(getSessionId(session), result.response, 'success');\n resolve(0);\n };\n const onInterrupted = (result: IExecutionResult): void => {\n cleanup();\n writeJsonResult(getSessionId(session), result.response, 'success');\n resolve(0);\n };\n const onError = (error: Error): void => {\n cleanup();\n writeJsonResult(getSessionId(session), '', 'error', error);\n resolve(1);\n };\n\n session.on('text_delta', onTextDelta);\n session.on('background_task_event', onBackgroundTaskEvent);\n session.on('background_job_group_event', onBackgroundJobGroupEvent);\n session.on('complete', onComplete);\n session.on('interrupted', onInterrupted);\n session.on('error', onError);\n return cleanup;\n}\n\nfunction unsubscribeStreamJsonEvents(\n session: IInteractiveSession,\n handlers: IStreamJsonHandlers,\n): void {\n session.off('text_delta', handlers.onTextDelta);\n session.off('background_task_event', handlers.onBackgroundTaskEvent);\n session.off('background_job_group_event', handlers.onBackgroundJobGroupEvent);\n session.off('complete', handlers.onComplete);\n session.off('interrupted', handlers.onInterrupted);\n session.off('error', handlers.onError);\n}\n","import { executeSlashCommandIfPresent, subscribeStreamJsonEvents } from './headless-stream-json.js';\n\nimport type { IInteractiveSession, IExecutionResult } from '@robota-sdk/agent-framework';\n\nexport type TOutputFormat = 'text' | 'json' | 'stream-json';\n\nexport interface IHeadlessRunnerOptions {\n session: IInteractiveSession;\n outputFormat: TOutputFormat;\n}\n\nexport function createHeadlessRunner(options: IHeadlessRunnerOptions): {\n run: (prompt: string) => Promise<number>;\n} {\n const { session, outputFormat } = options;\n return {\n run: (prompt: string): Promise<number> => {\n if (outputFormat === 'text') return runTextFormat(session, prompt);\n if (outputFormat === 'json') return runJsonFormat(session, prompt);\n return runStreamJsonFormat(session, prompt);\n },\n };\n}\n\nexport function resolveErrorCode(error: Error): string {\n const msg = error.message.toLowerCase();\n if (msg.includes('api key') || msg.includes('no provider') || msg.includes('provider')) {\n return 'config_error';\n }\n if (msg.includes('tool') || msg.includes('execution')) {\n return 'tool_error';\n }\n return 'api_error';\n}\n\nexport function writeJsonResult(\n sessionId: string,\n result: string,\n subtype: 'success' | 'error',\n error?: Error,\n): void {\n const payload: Record<string, unknown> = {\n type: 'result',\n result,\n session_id: sessionId,\n subtype,\n };\n if (subtype === 'error' && error !== undefined) {\n payload['error_code'] = resolveErrorCode(error);\n }\n const output = JSON.stringify(payload);\n process.stdout.write(output + '\\n');\n}\n\nexport function getSessionId(session: IInteractiveSession): string {\n try {\n return session.getSession().getSessionId();\n } catch {\n // allow-fallback: session may not be initialized yet\n return '';\n }\n}\n\nfunction runTextFormat(session: IInteractiveSession, prompt: string): Promise<number> {\n return new Promise<number>((resolve) => {\n const cleanup = (): void => {\n session.off('complete', onComplete);\n session.off('interrupted', onInterrupted);\n session.off('error', onError);\n };\n const onComplete = (result: IExecutionResult): void => {\n cleanup();\n process.stdout.write(result.response + '\\n');\n resolve(0);\n };\n const onInterrupted = (result: IExecutionResult): void => {\n cleanup();\n if (result.response) process.stdout.write(result.response + '\\n');\n resolve(0);\n };\n const onError = (_error: Error): void => {\n cleanup();\n resolve(1);\n };\n\n session.on('complete', onComplete);\n session.on('interrupted', onInterrupted);\n session.on('error', onError);\n\n void executeSlashCommandIfPresent(session, prompt).then((cmd) => {\n if (cmd.kind === 'command-result') {\n cleanup();\n process.stdout.write(cmd.result.message + '\\n');\n resolve(cmd.result.success ? 0 : 1);\n return;\n }\n if (cmd.kind !== 'session-execution') void session.submit(prompt);\n });\n });\n}\n\nfunction runJsonFormat(session: IInteractiveSession, prompt: string): Promise<number> {\n return new Promise<number>((resolve) => {\n const cleanup = (): void => {\n session.off('complete', onComplete);\n session.off('interrupted', onInterrupted);\n session.off('error', onError);\n };\n const onComplete = (result: IExecutionResult): void => {\n cleanup();\n writeJsonResult(getSessionId(session), result.response, 'success');\n resolve(0);\n };\n const onInterrupted = (result: IExecutionResult): void => {\n cleanup();\n writeJsonResult(getSessionId(session), result.response, 'success');\n resolve(0);\n };\n const onError = (error: Error): void => {\n cleanup();\n writeJsonResult(getSessionId(session), '', 'error', error);\n resolve(1);\n };\n\n session.on('complete', onComplete);\n session.on('interrupted', onInterrupted);\n session.on('error', onError);\n\n void executeSlashCommandIfPresent(session, prompt).then((cmd) => {\n if (cmd.kind === 'command-result') {\n cleanup();\n writeJsonResult(\n getSessionId(session),\n cmd.result.message,\n cmd.result.success ? 'success' : 'error',\n );\n resolve(cmd.result.success ? 0 : 1);\n return;\n }\n if (cmd.kind !== 'session-execution') void session.submit(prompt);\n });\n });\n}\n\nfunction runStreamJsonFormat(session: IInteractiveSession, prompt: string): Promise<number> {\n return new Promise<number>((resolve) => {\n const cleanup = subscribeStreamJsonEvents(session, getSessionId, writeJsonResult, resolve);\n\n void executeSlashCommandIfPresent(session, prompt).then((cmd) => {\n if (cmd.kind === 'command-result') {\n cleanup();\n writeJsonResult(\n getSessionId(session),\n cmd.result.message,\n cmd.result.success ? 'success' : 'error',\n );\n resolve(cmd.result.success ? 0 : 1);\n return;\n }\n if (cmd.kind !== 'session-execution') void session.submit(prompt);\n });\n });\n}\n","/**\n * ITransportAdapter implementation for headless transport.\n *\n * Wraps createHeadlessRunner into the unified ITransportAdapter interface.\n * After start() completes, getExitCode() returns the runner's exit code.\n */\n\nimport { createHeadlessRunner } from './headless-runner.js';\n\nimport type { TOutputFormat } from './headless-runner.js';\nimport type { IInteractiveSession } from '@robota-sdk/agent-framework';\nimport type { ITransportAdapter } from '@robota-sdk/agent-interface-transport';\n\nexport interface IHeadlessTransportOptions {\n /** Output format: 'text', 'json', or 'stream-json'. */\n outputFormat: TOutputFormat;\n /** The prompt to execute. */\n prompt: string;\n}\n\nexport function createHeadlessTransport(\n options: IHeadlessTransportOptions,\n): ITransportAdapter<IInteractiveSession> & { getExitCode(): number } {\n let session: IInteractiveSession | null = null;\n let exitCode = 0;\n\n return {\n name: 'headless',\n attach(s: IInteractiveSession) {\n session = s;\n },\n async start() {\n if (!session) throw new Error('No session attached. Call attach() first.');\n const runner = createHeadlessRunner({ session, outputFormat: options.outputFormat });\n exitCode = await runner.run(options.prompt);\n },\n async stop() {\n /* no-op: headless runner completes in start() */\n },\n getExitCode() {\n return exitCode;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const e=require(`./chunk-Bmb41Sf3.cjs`);let t=require(`node:readline`);t=e.t(t,1);let n=require(`node:crypto`);var r=class{write(e){process.stdout.write(e)}writeLine(e){process.stdout.write(e+`
|
|
2
|
-
`)}writeMarkdown(e){process.stdout.write(e)}writeError(e){process.stderr.write(e+`
|
|
3
|
-
`)}prompt(e){return new Promise(n=>{let r=t.createInterface({input:process.stdin,output:process.stdout,terminal:!1,historySize:0});r.question(e,e=>{r.close(),n(e)})})}async select(e,t=0){for(let n=0;n<e.length;n++){let r=n===t?`>`:` `;process.stdout.write(` ${r} ${n+1}) ${e[n]}\n`)}let n=(await this.prompt(` Choose [1-${e.length}] (default: ${e[t]}): `)).trim().toLowerCase();if(n===``)return t;let r=parseInt(n,10);return!isNaN(r)&&r>=1&&r<=e.length?r-1:t}spinner(e){return{stop(){},update(){}}}};const i=(e,t=!1)=>new Promise((n,r)=>{process.stdout.write(e);let i=``,a=process.stdin,o=a.isRaw;if(!a.isTTY){r(Error(`Cannot prompt for input: stdin is not a TTY.
|
|
4
|
-
Set your API key via environment variable instead:
|
|
5
|
-
ANTHROPIC_API_KEY=<key> robota
|
|
6
|
-
OPENAI_API_KEY=<key> robota`));return}a.setRawMode(!0),a.resume(),a.setEncoding(`utf8`);let s=e=>{for(let r of e)if(r===`\r`||r===`
|
|
7
|
-
`){a.removeListener(`data`,s),a.setRawMode(o??!1),a.pause(),process.stdout.write(`
|
|
8
|
-
`),n(i.trim());return}else r===``||r===`\b`?i.length>0&&(i=i.slice(0,-1),process.stdout.write(`\b \b`)):r===``?(a.removeListener(`data`,s),a.setRawMode(o??!1),a.pause(),process.stdout.write(`
|
|
9
|
-
`),process.exit(0)):r.charCodeAt(0)>=32&&(i+=r,process.stdout.write(t?`*`:r))};a.on(`data`,s)});function a(e){let t=e.trimStart();if(!t.startsWith(`/`))return null;let[n=``,...r]=t.slice(1).split(/\s+/);return n.length===0?null:{name:n,args:r.join(` `)}}async function o(e,t){let n=a(t);if(!n)return{kind:`not-slash`};let r=await e.executeCommand(n.name,n.args);return r?r.effects?.some(e=>e.type===`session-execution-started`)?{kind:`session-execution`}:{kind:`command-result`,result:r}:{kind:`command-result`,result:{message:`Unknown command "/${n.name}".`,success:!1}}}function s(e,t,r){let i=JSON.stringify({type:`stream_event`,event:r,session_id:t(e),uuid:(0,n.randomUUID)()});process.stdout.write(i+`
|
|
10
|
-
`)}function c(e,t,n,r){let i=n=>s(e,t,n),a=e=>i({type:`content_block_delta`,delta:{type:`text_delta`,text:e}}),o=e=>i({type:`background_task_event`,background_task_event:e}),c=e=>i({type:`background_job_group_event`,background_job_group_event:e}),u=()=>l(e,{onTextDelta:a,onBackgroundTaskEvent:o,onBackgroundJobGroupEvent:c,onComplete:d,onInterrupted:f,onError:p}),d=i=>{u(),n(t(e),i.response,`success`),r(0)},f=i=>{u(),n(t(e),i.response,`success`),r(0)},p=i=>{u(),n(t(e),``,`error`,i),r(1)};return e.on(`text_delta`,a),e.on(`background_task_event`,o),e.on(`background_job_group_event`,c),e.on(`complete`,d),e.on(`interrupted`,f),e.on(`error`,p),u}function l(e,t){e.off(`text_delta`,t.onTextDelta),e.off(`background_task_event`,t.onBackgroundTaskEvent),e.off(`background_job_group_event`,t.onBackgroundJobGroupEvent),e.off(`complete`,t.onComplete),e.off(`interrupted`,t.onInterrupted),e.off(`error`,t.onError)}function u(e){let{session:t,outputFormat:n}=e;return{run:e=>n===`text`?m(t,e):n===`json`?h(t,e):g(t,e)}}function d(e){let t=e.message.toLowerCase();return t.includes(`api key`)||t.includes(`no provider`)||t.includes(`provider`)?`config_error`:t.includes(`tool`)||t.includes(`execution`)?`tool_error`:`api_error`}function f(e,t,n,r){let i={type:`result`,result:t,session_id:e,subtype:n};n===`error`&&r!==void 0&&(i.error_code=d(r));let a=JSON.stringify(i);process.stdout.write(a+`
|
|
11
|
-
`)}function p(e){try{return e.getSession().getSessionId()}catch{return``}}function m(e,t){return new Promise(n=>{let r=()=>{e.off(`complete`,i),e.off(`interrupted`,a),e.off(`error`,s)},i=e=>{r(),process.stdout.write(e.response+`
|
|
12
|
-
`),n(0)},a=e=>{r(),e.response&&process.stdout.write(e.response+`
|
|
13
|
-
`),n(0)},s=e=>{r(),n(1)};e.on(`complete`,i),e.on(`interrupted`,a),e.on(`error`,s),o(e,t).then(i=>{if(i.kind===`command-result`){r(),process.stdout.write(i.result.message+`
|
|
14
|
-
`),n(+!i.result.success);return}i.kind!==`session-execution`&&e.submit(t)})})}function h(e,t){return new Promise(n=>{let r=()=>{e.off(`complete`,i),e.off(`interrupted`,a),e.off(`error`,s)},i=t=>{r(),f(p(e),t.response,`success`),n(0)},a=t=>{r(),f(p(e),t.response,`success`),n(0)},s=t=>{r(),f(p(e),``,`error`,t),n(1)};e.on(`complete`,i),e.on(`interrupted`,a),e.on(`error`,s),o(e,t).then(i=>{if(i.kind===`command-result`){r(),f(p(e),i.result.message,i.result.success?`success`:`error`),n(+!i.result.success);return}i.kind!==`session-execution`&&e.submit(t)})})}function g(e,t){return new Promise(n=>{let r=c(e,p,f,n);o(e,t).then(i=>{if(i.kind===`command-result`){r(),f(p(e),i.result.message,i.result.success?`success`:`error`),n(+!i.result.success);return}i.kind!==`session-execution`&&e.submit(t)})})}function _(e){let t=null,n=0;return{name:`headless`,attach(e){t=e},async start(){if(!t)throw Error(`No session attached. Call attach() first.`);n=await u({session:t,outputFormat:e.outputFormat}).run(e.prompt)},async stop(){},getExitCode(){return n}}}Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return _}});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ISpinner, ITerminalOutput } from "@robota-sdk/agent-core";
|
|
2
|
-
import { IInteractiveSession } from "@robota-sdk/agent-framework";
|
|
3
|
-
import { ITransportAdapter } from "@robota-sdk/agent-interface-transport";
|
|
4
|
-
|
|
5
|
-
//#region src/headless/print-terminal.d.ts
|
|
6
|
-
declare class PrintTerminal implements ITerminalOutput {
|
|
7
|
-
write(text: string): void;
|
|
8
|
-
writeLine(text: string): void;
|
|
9
|
-
writeMarkdown(md: string): void;
|
|
10
|
-
writeError(text: string): void;
|
|
11
|
-
prompt(question: string): Promise<string>;
|
|
12
|
-
select(options: string[], initialIndex?: number): Promise<number>;
|
|
13
|
-
spinner(_message: string): ISpinner;
|
|
14
|
-
}
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/headless/cli-input.d.ts
|
|
17
|
-
declare const promptInput: (label: string, masked?: boolean) => Promise<string>;
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region src/headless/headless-runner.d.ts
|
|
20
|
-
type TOutputFormat = 'text' | 'json' | 'stream-json';
|
|
21
|
-
interface IHeadlessRunnerOptions {
|
|
22
|
-
session: IInteractiveSession;
|
|
23
|
-
outputFormat: TOutputFormat;
|
|
24
|
-
}
|
|
25
|
-
declare function createHeadlessRunner(options: IHeadlessRunnerOptions): {
|
|
26
|
-
run: (prompt: string) => Promise<number>;
|
|
27
|
-
};
|
|
28
|
-
//#endregion
|
|
29
|
-
//#region src/headless/headless-transport.d.ts
|
|
30
|
-
interface IHeadlessTransportOptions {
|
|
31
|
-
/** Output format: 'text', 'json', or 'stream-json'. */
|
|
32
|
-
outputFormat: TOutputFormat;
|
|
33
|
-
/** The prompt to execute. */
|
|
34
|
-
prompt: string;
|
|
35
|
-
}
|
|
36
|
-
declare function createHeadlessTransport(options: IHeadlessTransportOptions): ITransportAdapter<IInteractiveSession> & {
|
|
37
|
-
getExitCode(): number;
|
|
38
|
-
};
|
|
39
|
-
//#endregion
|
|
40
|
-
export { createHeadlessRunner as a, TOutputFormat as i, createHeadlessTransport as n, promptInput as o, IHeadlessRunnerOptions as r, PrintTerminal as s, IHeadlessTransportOptions as t };
|
|
41
|
-
//# sourceMappingURL=index-CP7kaYMg.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-CP7kaYMg.d.ts","names":[],"sources":["../../src/headless/print-terminal.ts","../../src/headless/cli-input.ts","../../src/headless/headless-runner.ts","../../src/headless/headless-transport.ts"],"mappings":";;;;;cAWa,aAAA,YAAyB,eAAA;EACpC,KAAA,CAAM,IAAA;EAGN,SAAA,CAAU,IAAA;EAGV,aAAA,CAAc,EAAA;EAGd,UAAA,CAAW,IAAA;EAGX,MAAA,CAAO,QAAA,WAAmB,OAAA;EAcpB,MAAA,CAAO,OAAA,YAAmB,YAAA,YAAmB,OAAA;EAcnD,OAAA,CAAQ,QAAA,WAAmB,QAAA;AAAA;;;cClDhB,WAAA,GAAe,KAAA,UAAe,MAAA,eAAiB,OAAO;;;KCEvD,aAAA;AAAA,UAEK,sBAAA;EACf,OAAA,EAAS,mBAAA;EACT,YAAA,EAAc,aAAa;AAAA;AAAA,iBAGb,oBAAA,CAAqB,OAAA,EAAS,sBAAA;EAC5C,GAAA,GAAM,MAAA,aAAmB,OAAO;AAAA;;;UCCjB,yBAAA;EHuCY;EGrC3B,YAAA,EAAc,aAAa;EHJwB;EGMnD,MAAA;AAAA;AAAA,iBAGc,uBAAA,CACd,OAAA,EAAS,yBAAA,GACR,iBAAA,CAAkB,mBAAA;EAAyB,WAAA;AAAA"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ISpinner, ITerminalOutput } from "@robota-sdk/agent-core";
|
|
2
|
-
import { IInteractiveSession } from "@robota-sdk/agent-framework";
|
|
3
|
-
import { ITransportAdapter } from "@robota-sdk/agent-interface-transport";
|
|
4
|
-
|
|
5
|
-
//#region src/headless/print-terminal.d.ts
|
|
6
|
-
declare class PrintTerminal implements ITerminalOutput {
|
|
7
|
-
write(text: string): void;
|
|
8
|
-
writeLine(text: string): void;
|
|
9
|
-
writeMarkdown(md: string): void;
|
|
10
|
-
writeError(text: string): void;
|
|
11
|
-
prompt(question: string): Promise<string>;
|
|
12
|
-
select(options: string[], initialIndex?: number): Promise<number>;
|
|
13
|
-
spinner(_message: string): ISpinner;
|
|
14
|
-
}
|
|
15
|
-
//#endregion
|
|
16
|
-
//#region src/headless/cli-input.d.ts
|
|
17
|
-
declare const promptInput: (label: string, masked?: boolean) => Promise<string>;
|
|
18
|
-
//#endregion
|
|
19
|
-
//#region src/headless/headless-runner.d.ts
|
|
20
|
-
type TOutputFormat = 'text' | 'json' | 'stream-json';
|
|
21
|
-
interface IHeadlessRunnerOptions {
|
|
22
|
-
session: IInteractiveSession;
|
|
23
|
-
outputFormat: TOutputFormat;
|
|
24
|
-
}
|
|
25
|
-
declare function createHeadlessRunner(options: IHeadlessRunnerOptions): {
|
|
26
|
-
run: (prompt: string) => Promise<number>;
|
|
27
|
-
};
|
|
28
|
-
//#endregion
|
|
29
|
-
//#region src/headless/headless-transport.d.ts
|
|
30
|
-
interface IHeadlessTransportOptions {
|
|
31
|
-
/** Output format: 'text', 'json', or 'stream-json'. */
|
|
32
|
-
outputFormat: TOutputFormat;
|
|
33
|
-
/** The prompt to execute. */
|
|
34
|
-
prompt: string;
|
|
35
|
-
}
|
|
36
|
-
declare function createHeadlessTransport(options: IHeadlessTransportOptions): ITransportAdapter<IInteractiveSession> & {
|
|
37
|
-
getExitCode(): number;
|
|
38
|
-
};
|
|
39
|
-
//#endregion
|
|
40
|
-
export { createHeadlessRunner as a, TOutputFormat as i, createHeadlessTransport as n, promptInput as o, IHeadlessRunnerOptions as r, PrintTerminal as s, IHeadlessTransportOptions as t };
|
|
41
|
-
//# sourceMappingURL=index-Gby9H4q2.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-Gby9H4q2.d.ts","names":[],"sources":["../../src/headless/print-terminal.ts","../../src/headless/cli-input.ts","../../src/headless/headless-runner.ts","../../src/headless/headless-transport.ts"],"mappings":";;;;;cAWa,aAAA,YAAyB,eAAA;EACpC,KAAA,CAAM,IAAA;EAGN,SAAA,CAAU,IAAA;EAGV,aAAA,CAAc,EAAA;EAGd,UAAA,CAAW,IAAA;EAGX,MAAA,CAAO,QAAA,WAAmB,OAAA;EAcpB,MAAA,CAAO,OAAA,YAAmB,YAAA,YAAmB,OAAA;EAcnD,OAAA,CAAQ,QAAA,WAAmB,QAAA;AAAA;;;cClDhB,WAAA,GAAe,KAAA,UAAe,MAAA,eAAiB,OAAO;;;KCEvD,aAAA;AAAA,UAEK,sBAAA;EACf,OAAA,EAAS,mBAAA;EACT,YAAA,EAAc,aAAa;AAAA;AAAA,iBAGb,oBAAA,CAAqB,OAAA,EAAS,sBAAA;EAC5C,GAAA,GAAM,MAAA,aAAmB,OAAO;AAAA;;;UCCjB,yBAAA;EHuCY;EGrC3B,YAAA,EAAc,aAAa;EHJwB;EGMnD,MAAA;AAAA;AAAA,iBAGc,uBAAA,CACd,OAAA,EAAS,yBAAA,GACR,iBAAA,CAAkB,mBAAA;EAAyB,WAAA;AAAA"}
|