@theia/ai-terminal 1.72.0-next.2 → 1.72.0-next.21
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/lib/browser/ai-terminal-command-block-variable.d.ts +15 -0
- package/lib/browser/ai-terminal-command-block-variable.d.ts.map +1 -0
- package/lib/browser/ai-terminal-command-block-variable.js +132 -0
- package/lib/browser/ai-terminal-command-block-variable.js.map +1 -0
- package/lib/browser/ai-terminal-contribution.spec.d.ts +2 -0
- package/lib/browser/ai-terminal-contribution.spec.d.ts.map +1 -0
- package/lib/browser/ai-terminal-contribution.spec.js +117 -0
- package/lib/browser/ai-terminal-contribution.spec.js.map +1 -0
- package/lib/browser/ai-terminal-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-terminal-frontend-module.js +3 -0
- package/lib/browser/ai-terminal-frontend-module.js.map +1 -1
- package/package.json +9 -9
- package/src/browser/ai-terminal-command-block-variable.ts +143 -0
- package/src/browser/ai-terminal-contribution.spec.ts +139 -0
- package/src/browser/ai-terminal-frontend-module.ts +5 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AIVariableContext, AIVariableContribution, AIVariableResolutionRequest, AIVariableResolver, AIVariableService, ResolvedAIVariable } from '@theia/ai-core';
|
|
2
|
+
import { ILogger, MaybePromise, QuickInputService } from '@theia/core';
|
|
3
|
+
import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
|
|
4
|
+
export declare class AiTerminalCommandBlockVariableContribution implements AIVariableContribution, AIVariableResolver {
|
|
5
|
+
protected readonly terminalService: TerminalService;
|
|
6
|
+
protected readonly quickInputService: QuickInputService;
|
|
7
|
+
protected readonly logger: ILogger;
|
|
8
|
+
/** Fallback line count when command history is unavailable. 50 is a heuristic. */
|
|
9
|
+
protected static readonly FALLBACK_TERMINAL_LINE_COUNT = 50;
|
|
10
|
+
registerVariables(service: AIVariableService): void;
|
|
11
|
+
canResolve(request: AIVariableResolutionRequest, context: AIVariableContext): MaybePromise<number>;
|
|
12
|
+
resolve(request: AIVariableResolutionRequest, context: AIVariableContext): Promise<ResolvedAIVariable | undefined>;
|
|
13
|
+
protected pickCommandBlock(): Promise<string | undefined>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=ai-terminal-command-block-variable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-terminal-command-block-variable.d.ts","sourceRoot":"","sources":["../../src/browser/ai-terminal-command-block-variable.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAc,iBAAiB,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC/K,OAAO,EAAE,OAAO,EAAE,YAAY,EAAO,iBAAiB,EAA2C,MAAM,aAAa,CAAC;AAErH,OAAO,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAwBpF,qBACa,0CAA2C,YAAW,sBAAsB,EAAE,kBAAkB;IAGzG,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAGpD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAGxD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAEnC,kFAAkF;IAClF,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,4BAA4B,MAAM;IAE5D,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAKnD,UAAU,CAAC,OAAO,EAAE,2BAA2B,EAAE,OAAO,EAAE,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC;IAI5F,OAAO,CAAC,OAAO,EAAE,2BAA2B,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC;cAyCxG,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAkClE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
var AiTerminalCommandBlockVariableContribution_1;
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.AiTerminalCommandBlockVariableContribution = void 0;
|
|
20
|
+
const tslib_1 = require("tslib");
|
|
21
|
+
const core_1 = require("@theia/core");
|
|
22
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
23
|
+
const terminal_service_1 = require("@theia/terminal/lib/browser/base/terminal-service");
|
|
24
|
+
const TERMINAL_COMMAND_BLOCK = {
|
|
25
|
+
id: 'ai-terminal:terminal-command-block',
|
|
26
|
+
description: core_1.nls.localize('theia/ai/terminal/terminalCommandBlockAIVariable/description', 'Stores an executed terminal command and its corresponding output.'),
|
|
27
|
+
name: 'terminalCommand',
|
|
28
|
+
args: [{
|
|
29
|
+
name: 'index',
|
|
30
|
+
description: core_1.nls.localize('theia/ai/terminal/terminalCommandBlockAIVariable/index/description', 'Index of the command block in the terminal history. Defaults to the last command if not specified.')
|
|
31
|
+
}]
|
|
32
|
+
};
|
|
33
|
+
var CommandBlockQuickPickItem;
|
|
34
|
+
(function (CommandBlockQuickPickItem) {
|
|
35
|
+
function is(item) {
|
|
36
|
+
return 'blockIndex' in item;
|
|
37
|
+
}
|
|
38
|
+
CommandBlockQuickPickItem.is = is;
|
|
39
|
+
})(CommandBlockQuickPickItem || (CommandBlockQuickPickItem = {}));
|
|
40
|
+
let AiTerminalCommandBlockVariableContribution = class AiTerminalCommandBlockVariableContribution {
|
|
41
|
+
static { AiTerminalCommandBlockVariableContribution_1 = this; }
|
|
42
|
+
/** Fallback line count when command history is unavailable. 50 is a heuristic. */
|
|
43
|
+
static { this.FALLBACK_TERMINAL_LINE_COUNT = 50; }
|
|
44
|
+
registerVariables(service) {
|
|
45
|
+
service.registerResolver(TERMINAL_COMMAND_BLOCK, this);
|
|
46
|
+
service.registerArgumentPicker(TERMINAL_COMMAND_BLOCK, () => this.pickCommandBlock());
|
|
47
|
+
}
|
|
48
|
+
canResolve(request, context) {
|
|
49
|
+
return request.variable.name === TERMINAL_COMMAND_BLOCK.name ? 50 : 0;
|
|
50
|
+
}
|
|
51
|
+
async resolve(request, context) {
|
|
52
|
+
const terminal = this.terminalService.lastUsedTerminal;
|
|
53
|
+
if (!terminal) {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
if (!terminal.commandHistoryState) {
|
|
57
|
+
const bufferContent = terminal.buffer.getLines(Math.max(terminal.buffer.length
|
|
58
|
+
- AiTerminalCommandBlockVariableContribution_1.FALLBACK_TERMINAL_LINE_COUNT, 0), AiTerminalCommandBlockVariableContribution_1.FALLBACK_TERMINAL_LINE_COUNT).join('\n');
|
|
59
|
+
if (!bufferContent) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
variable: TERMINAL_COMMAND_BLOCK,
|
|
64
|
+
value: bufferContent
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const commandHistory = terminal.commandHistoryState.commandHistory;
|
|
68
|
+
if (commandHistory.length === 0) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const trimmedArg = request.arg?.trim();
|
|
72
|
+
const commandIndex = trimmedArg ? Number(trimmedArg) : commandHistory.length - 1;
|
|
73
|
+
if (!Number.isInteger(commandIndex) || commandIndex < 0 || commandIndex >= commandHistory.length) {
|
|
74
|
+
this.logger.warn(`Invalid terminal command index (must be an integer and between 0 and ${commandHistory.length - 1}): ${request.arg}`);
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const block = commandHistory[commandIndex];
|
|
78
|
+
if (!block) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
variable: TERMINAL_COMMAND_BLOCK,
|
|
83
|
+
value: `### Terminal Command:\n${block.command}\n\n### Terminal Output:\n${block.output}`
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async pickCommandBlock() {
|
|
87
|
+
if (!this.terminalService.lastUsedTerminal?.commandHistoryState) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const commandHistory = this.terminalService.lastUsedTerminal.commandHistoryState.commandHistory;
|
|
91
|
+
const quickPick = this.quickInputService.createQuickPick();
|
|
92
|
+
quickPick.title = core_1.nls.localize('theia/ai/terminal/terminalCommandBlockAIVariable/quickPick/title', 'Select a command and its output from the terminal history');
|
|
93
|
+
quickPick.placeholder = core_1.nls.localize('theia/ai/terminal/terminalCommandBlockAIVariable/quickPick/placeholder', 'Type to filter commands');
|
|
94
|
+
quickPick.items = commandHistory.map((block, i) => ({
|
|
95
|
+
label: block.command,
|
|
96
|
+
// replace all whitespace with a single space for better readability
|
|
97
|
+
description: block.output.replace(/\s+/g, ' ').trim().slice(0, 60),
|
|
98
|
+
blockIndex: i
|
|
99
|
+
})).toReversed();
|
|
100
|
+
quickPick.show();
|
|
101
|
+
return new Promise(resolve => {
|
|
102
|
+
quickPick.onDidAccept(() => {
|
|
103
|
+
const selected = quickPick.selectedItems[0];
|
|
104
|
+
if (CommandBlockQuickPickItem.is(selected)) {
|
|
105
|
+
resolve(String(selected.blockIndex));
|
|
106
|
+
}
|
|
107
|
+
quickPick.dispose();
|
|
108
|
+
});
|
|
109
|
+
quickPick.onDidHide(() => {
|
|
110
|
+
resolve(undefined);
|
|
111
|
+
quickPick.dispose();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
exports.AiTerminalCommandBlockVariableContribution = AiTerminalCommandBlockVariableContribution;
|
|
117
|
+
tslib_1.__decorate([
|
|
118
|
+
(0, inversify_1.inject)(terminal_service_1.TerminalService),
|
|
119
|
+
tslib_1.__metadata("design:type", Object)
|
|
120
|
+
], AiTerminalCommandBlockVariableContribution.prototype, "terminalService", void 0);
|
|
121
|
+
tslib_1.__decorate([
|
|
122
|
+
(0, inversify_1.inject)(core_1.QuickInputService),
|
|
123
|
+
tslib_1.__metadata("design:type", Object)
|
|
124
|
+
], AiTerminalCommandBlockVariableContribution.prototype, "quickInputService", void 0);
|
|
125
|
+
tslib_1.__decorate([
|
|
126
|
+
(0, inversify_1.inject)(core_1.ILogger),
|
|
127
|
+
tslib_1.__metadata("design:type", Object)
|
|
128
|
+
], AiTerminalCommandBlockVariableContribution.prototype, "logger", void 0);
|
|
129
|
+
exports.AiTerminalCommandBlockVariableContribution = AiTerminalCommandBlockVariableContribution = AiTerminalCommandBlockVariableContribution_1 = tslib_1.__decorate([
|
|
130
|
+
(0, inversify_1.injectable)()
|
|
131
|
+
], AiTerminalCommandBlockVariableContribution);
|
|
132
|
+
//# sourceMappingURL=ai-terminal-command-block-variable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-terminal-command-block-variable.js","sourceRoot":"","sources":["../../src/browser/ai-terminal-command-block-variable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-terminal-contribution.spec.d.ts","sourceRoot":"","sources":["../../src/browser/ai-terminal-contribution.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const chai_1 = require("chai");
|
|
19
|
+
const core_1 = require("@theia/core");
|
|
20
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
21
|
+
const terminal_service_1 = require("@theia/terminal/lib/browser/base/terminal-service");
|
|
22
|
+
const ai_terminal_command_block_variable_1 = require("./ai-terminal-command-block-variable");
|
|
23
|
+
function createMockTerminal(overrides) {
|
|
24
|
+
const { bufferLines = [], commandHistory } = overrides;
|
|
25
|
+
return {
|
|
26
|
+
buffer: {
|
|
27
|
+
length: bufferLines.length,
|
|
28
|
+
getLines: (start, length) => bufferLines.slice(start, start + length),
|
|
29
|
+
},
|
|
30
|
+
commandHistoryState: commandHistory !== undefined
|
|
31
|
+
? { commandHistory }
|
|
32
|
+
: undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function createRequest(arg) {
|
|
36
|
+
return {
|
|
37
|
+
variable: { id: 'ai-terminal:terminal-command-block', name: 'terminalCommand', description: '' },
|
|
38
|
+
arg,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const mockContext = {};
|
|
42
|
+
describe('AiTerminalCommandBlockVariableContribution.resolve()', () => {
|
|
43
|
+
let mockTerminalService;
|
|
44
|
+
let contribution;
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
const container = new inversify_1.Container();
|
|
47
|
+
mockTerminalService = {
|
|
48
|
+
lastUsedTerminal: createMockTerminal({
|
|
49
|
+
commandHistory: [
|
|
50
|
+
{ command: 'ls', output: 'file1\nfile2' },
|
|
51
|
+
{ command: 'pwd', output: '/home/user' },
|
|
52
|
+
{ command: 'echo hello world', output: 'hello world' },
|
|
53
|
+
]
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
container.bind(terminal_service_1.TerminalService).toConstantValue(mockTerminalService);
|
|
57
|
+
container.bind(core_1.QuickInputService).toConstantValue({});
|
|
58
|
+
container.bind(core_1.ILogger).toConstantValue({ warn: () => { } });
|
|
59
|
+
container.bind(ai_terminal_command_block_variable_1.AiTerminalCommandBlockVariableContribution).toSelf();
|
|
60
|
+
contribution = container.get(ai_terminal_command_block_variable_1.AiTerminalCommandBlockVariableContribution);
|
|
61
|
+
});
|
|
62
|
+
it('returns undefined when there is no last used terminal', async () => {
|
|
63
|
+
mockTerminalService.lastUsedTerminal = undefined;
|
|
64
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
65
|
+
(0, chai_1.expect)(result).to.be.undefined;
|
|
66
|
+
});
|
|
67
|
+
it('returns the last command when no parameter is passed', async () => {
|
|
68
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
69
|
+
(0, chai_1.expect)(result?.value).to.equal('### Terminal Command:\necho hello world\n\n### Terminal Output:\nhello world');
|
|
70
|
+
});
|
|
71
|
+
it('returns the last command when the input is an empty or white space only string', async () => {
|
|
72
|
+
const emptyStringResult = await contribution.resolve(createRequest(''), mockContext);
|
|
73
|
+
const whiteSpaceResult = await contribution.resolve(createRequest(' '), mockContext);
|
|
74
|
+
(0, chai_1.expect)(emptyStringResult?.value).to.equal('### Terminal Command:\necho hello world\n\n### Terminal Output:\nhello world');
|
|
75
|
+
(0, chai_1.expect)(whiteSpaceResult?.value).to.equal('### Terminal Command:\necho hello world\n\n### Terminal Output:\nhello world');
|
|
76
|
+
});
|
|
77
|
+
it('returns the correct command according to the argument', async () => {
|
|
78
|
+
const result = await contribution.resolve(createRequest('1'), mockContext);
|
|
79
|
+
(0, chai_1.expect)(result?.value).to.equal('### Terminal Command:\npwd\n\n### Terminal Output:\n/home/user');
|
|
80
|
+
});
|
|
81
|
+
it('returns the last 50 lines of the terminal when terminal history is not enabled', async () => {
|
|
82
|
+
mockTerminalService.lastUsedTerminal = createMockTerminal({
|
|
83
|
+
bufferLines: ['ls', 'file1\nfile2', 'pwd', '/home/user']
|
|
84
|
+
});
|
|
85
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
86
|
+
(0, chai_1.expect)(result?.value).to.equal('ls\nfile1\nfile2\npwd\n/home/user');
|
|
87
|
+
});
|
|
88
|
+
it('returns undefined when the terminal history is empty', async () => {
|
|
89
|
+
mockTerminalService.lastUsedTerminal = createMockTerminal({
|
|
90
|
+
commandHistory: []
|
|
91
|
+
});
|
|
92
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
93
|
+
(0, chai_1.expect)(result).to.be.undefined;
|
|
94
|
+
});
|
|
95
|
+
it('returns undefined when the input is not a number', async () => {
|
|
96
|
+
const result = await contribution.resolve(createRequest('one'), mockContext);
|
|
97
|
+
(0, chai_1.expect)(result).to.be.undefined;
|
|
98
|
+
});
|
|
99
|
+
it('returns undefined when the input is not an integer', async () => {
|
|
100
|
+
const result = await contribution.resolve(createRequest('1.5'), mockContext);
|
|
101
|
+
(0, chai_1.expect)(result).to.be.undefined;
|
|
102
|
+
});
|
|
103
|
+
it('returns undefined when terminal history is not enabled and the buffer is empty', async () => {
|
|
104
|
+
mockTerminalService.lastUsedTerminal = createMockTerminal({});
|
|
105
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
106
|
+
(0, chai_1.expect)(result).to.be.undefined;
|
|
107
|
+
});
|
|
108
|
+
it('returns undefined when the input is a negative integer', async () => {
|
|
109
|
+
const result = await contribution.resolve(createRequest('-1'), mockContext);
|
|
110
|
+
(0, chai_1.expect)(result).to.be.undefined;
|
|
111
|
+
});
|
|
112
|
+
it('returns undefined when the input index is out of bounds', async () => {
|
|
113
|
+
const result = await contribution.resolve(createRequest('10'), mockContext);
|
|
114
|
+
(0, chai_1.expect)(result).to.be.undefined;
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
//# sourceMappingURL=ai-terminal-contribution.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-terminal-contribution.spec.js","sourceRoot":"","sources":["../../src/browser/ai-terminal-contribution.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-terminal-frontend-module.d.ts","sourceRoot":"","sources":["../../src/browser/ai-terminal-frontend-module.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"ai-terminal-frontend-module.d.ts","sourceRoot":"","sources":["../../src/browser/ai-terminal-frontend-module.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAW/D,OAAO,yCAAyC,CAAC;AACjD,OAAO,kDAAkD,CAAC;;AAE1D,wBA0BG"}
|
|
@@ -29,6 +29,7 @@ const shell_execution_server_1 = require("../common/shell-execution-server");
|
|
|
29
29
|
const shell_command_permission_service_1 = require("./shell-command-permission-service");
|
|
30
30
|
const shell_command_preferences_1 = require("../common/shell-command-preferences");
|
|
31
31
|
const shell_command_analyzer_1 = require("../common/shell-command-analyzer");
|
|
32
|
+
const ai_terminal_command_block_variable_1 = require("./ai-terminal-command-block-variable");
|
|
32
33
|
require("../../src/browser/style/ai-terminal.css");
|
|
33
34
|
require("../../src/browser/style/shell-execution-tool.css");
|
|
34
35
|
exports.default = new inversify_1.ContainerModule(bind => {
|
|
@@ -47,5 +48,7 @@ exports.default = new inversify_1.ContainerModule(bind => {
|
|
|
47
48
|
bind(shell_command_permission_service_1.ShellCommandPermissionService).toSelf().inSingletonScope();
|
|
48
49
|
bind(core_1.PreferenceContribution).toConstantValue({ schema: shell_command_preferences_1.shellCommandPreferences });
|
|
49
50
|
bind(shell_command_analyzer_1.ShellCommandAnalyzer).to(shell_command_analyzer_1.DefaultShellCommandAnalyzer).inSingletonScope();
|
|
51
|
+
bind(ai_terminal_command_block_variable_1.AiTerminalCommandBlockVariableContribution).toSelf().inSingletonScope();
|
|
52
|
+
bind(common_1.AIVariableContribution).toService(ai_terminal_command_block_variable_1.AiTerminalCommandBlockVariableContribution);
|
|
50
53
|
});
|
|
51
54
|
//# sourceMappingURL=ai-terminal-frontend-module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-terminal-frontend-module.js","sourceRoot":"","sources":["../../src/browser/ai-terminal-frontend-module.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;AAEhF,2GAAqG;AACrG,
|
|
1
|
+
{"version":3,"file":"ai-terminal-frontend-module.js","sourceRoot":"","sources":["../../src/browser/ai-terminal-frontend-module.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;AAEhF,2GAAqG;AACrG,sDAA0E;AAC1E,iGAAsF;AACtF,sCAA4F;AAC5F,qDAA8F;AAC9F,4DAA+D;AAC/D,2DAAsD;AACtD,yEAA2E;AAC3E,iEAA4D;AAC5D,mFAA6E;AAC7E,6EAA4F;AAC5F,yFAAmF;AACnF,mFAA8E;AAC9E,6EAAqG;AACrG,6FAAkG;AAElG,mDAAiD;AACjD,4DAA0D;AAE1D,kBAAe,IAAI,2BAAe,CAAC,IAAI,CAAC,EAAE;IACtC,IAAI,CAAC,wDAA6B,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAChE,KAAK,MAAM,UAAU,IAAI,CAAC,0BAAmB,EAAE,uBAAgB,EAAE,gCAAsB,CAAC,EAAE,CAAC;QACvF,IAAI,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,wDAA6B,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC,mCAAe,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAClD,IAAI,CAAC,cAAK,CAAC,CAAC,SAAS,CAAC,mCAAe,CAAC,CAAC;IAEvC,IAAA,2CAAgB,EAAC,yCAAkB,EAAE,IAAI,CAAC,CAAC;IAE3C,IAAI,CAAC,6CAAoB,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;QAC5C,MAAM,UAAU,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,qCAA2B,CAAC,CAAC;QAClE,OAAO,UAAU,CAAC,WAAW,CAAuB,2CAAkB,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAEtB,IAAI,CAAC,sDAAwB,CAAC,CAAC,EAAE,CAAC,0DAA0B,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAEjF,IAAI,CAAC,gEAA6B,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAEhE,IAAI,CAAC,6BAAsB,CAAC,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,mDAAuB,EAAE,CAAC,CAAC;IAElF,IAAI,CAAC,6CAAoB,CAAC,CAAC,EAAE,CAAC,oDAA2B,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAE9E,IAAI,CAAC,+EAA0C,CAAC,CAAC,MAAM,EAAE,CAAC,gBAAgB,EAAE,CAAC;IAC7E,IAAI,CAAC,+BAAsB,CAAC,CAAC,SAAS,CAAC,+EAA0C,CAAC,CAAC;AACvF,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theia/ai-terminal",
|
|
3
|
-
"version": "1.72.0-next.
|
|
3
|
+
"version": "1.72.0-next.21+adeb3ebbf",
|
|
4
4
|
"description": "Theia - AI Terminal Extension",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@theia/ai-chat": "1.72.0-next.
|
|
7
|
-
"@theia/ai-chat-ui": "1.72.0-next.
|
|
8
|
-
"@theia/ai-core": "1.72.0-next.
|
|
9
|
-
"@theia/core": "1.72.0-next.
|
|
10
|
-
"@theia/terminal": "1.72.0-next.
|
|
11
|
-
"@theia/workspace": "1.72.0-next.
|
|
12
|
-
"zod": "^4.3
|
|
6
|
+
"@theia/ai-chat": "1.72.0-next.21+adeb3ebbf",
|
|
7
|
+
"@theia/ai-chat-ui": "1.72.0-next.21+adeb3ebbf",
|
|
8
|
+
"@theia/ai-core": "1.72.0-next.21+adeb3ebbf",
|
|
9
|
+
"@theia/core": "1.72.0-next.21+adeb3ebbf",
|
|
10
|
+
"@theia/terminal": "1.72.0-next.21+adeb3ebbf",
|
|
11
|
+
"@theia/workspace": "1.72.0-next.21+adeb3ebbf",
|
|
12
|
+
"zod": "^4.4.3"
|
|
13
13
|
},
|
|
14
14
|
"publishConfig": {
|
|
15
15
|
"access": "public"
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"nyc": {
|
|
51
51
|
"extends": "../../configs/nyc.json"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "adeb3ebbf5e4b643b5438ca4f71fcfb4483498c8"
|
|
54
54
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { AIVariable, AIVariableContext, AIVariableContribution, AIVariableResolutionRequest, AIVariableResolver, AIVariableService, ResolvedAIVariable } from '@theia/ai-core';
|
|
18
|
+
import { ILogger, MaybePromise, nls, QuickInputService, QuickPickItem, QuickPickItemOrSeparator } from '@theia/core';
|
|
19
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
20
|
+
import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
|
|
21
|
+
|
|
22
|
+
const TERMINAL_COMMAND_BLOCK: AIVariable = {
|
|
23
|
+
id: 'ai-terminal:terminal-command-block',
|
|
24
|
+
description: nls.localize('theia/ai/terminal/terminalCommandBlockAIVariable/description', 'Stores an executed terminal command and its corresponding output.'),
|
|
25
|
+
name: 'terminalCommand',
|
|
26
|
+
args: [{
|
|
27
|
+
name: 'index',
|
|
28
|
+
description: nls.localize('theia/ai/terminal/terminalCommandBlockAIVariable/index/description',
|
|
29
|
+
'Index of the command block in the terminal history. Defaults to the last command if not specified.'
|
|
30
|
+
)
|
|
31
|
+
}]
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
interface CommandBlockQuickPickItem extends QuickPickItem {
|
|
35
|
+
blockIndex: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
namespace CommandBlockQuickPickItem {
|
|
39
|
+
export function is(item: QuickPickItemOrSeparator): item is CommandBlockQuickPickItem {
|
|
40
|
+
return 'blockIndex' in item;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@injectable()
|
|
45
|
+
export class AiTerminalCommandBlockVariableContribution implements AIVariableContribution, AIVariableResolver {
|
|
46
|
+
|
|
47
|
+
@inject(TerminalService)
|
|
48
|
+
protected readonly terminalService: TerminalService;
|
|
49
|
+
|
|
50
|
+
@inject(QuickInputService)
|
|
51
|
+
protected readonly quickInputService: QuickInputService;
|
|
52
|
+
|
|
53
|
+
@inject(ILogger)
|
|
54
|
+
protected readonly logger: ILogger;
|
|
55
|
+
|
|
56
|
+
/** Fallback line count when command history is unavailable. 50 is a heuristic. */
|
|
57
|
+
protected static readonly FALLBACK_TERMINAL_LINE_COUNT = 50;
|
|
58
|
+
|
|
59
|
+
registerVariables(service: AIVariableService): void {
|
|
60
|
+
service.registerResolver(TERMINAL_COMMAND_BLOCK, this);
|
|
61
|
+
service.registerArgumentPicker(TERMINAL_COMMAND_BLOCK, () => this.pickCommandBlock());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
canResolve(request: AIVariableResolutionRequest, context: AIVariableContext): MaybePromise<number> {
|
|
65
|
+
return request.variable.name === TERMINAL_COMMAND_BLOCK.name ? 50 : 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async resolve(request: AIVariableResolutionRequest, context: AIVariableContext): Promise<ResolvedAIVariable | undefined> {
|
|
69
|
+
const terminal = this.terminalService.lastUsedTerminal;
|
|
70
|
+
if (!terminal) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
if (!terminal.commandHistoryState) {
|
|
74
|
+
const bufferContent = terminal.buffer.getLines(
|
|
75
|
+
Math.max(terminal.buffer.length
|
|
76
|
+
- AiTerminalCommandBlockVariableContribution.FALLBACK_TERMINAL_LINE_COUNT, 0),
|
|
77
|
+
AiTerminalCommandBlockVariableContribution.FALLBACK_TERMINAL_LINE_COUNT
|
|
78
|
+
).join('\n');
|
|
79
|
+
if (!bufferContent) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
variable: TERMINAL_COMMAND_BLOCK,
|
|
84
|
+
value: bufferContent
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const commandHistory = terminal.commandHistoryState.commandHistory;
|
|
88
|
+
if (commandHistory.length === 0) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const trimmedArg = request.arg?.trim();
|
|
93
|
+
const commandIndex = trimmedArg ? Number(trimmedArg) : commandHistory.length - 1;
|
|
94
|
+
|
|
95
|
+
if (!Number.isInteger(commandIndex) || commandIndex < 0 || commandIndex >= commandHistory.length) {
|
|
96
|
+
this.logger.warn(`Invalid terminal command index (must be an integer and between 0 and ${commandHistory.length - 1}): ${request.arg}`);
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const block = commandHistory[commandIndex];
|
|
100
|
+
if (!block) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
variable: TERMINAL_COMMAND_BLOCK,
|
|
105
|
+
value: `### Terminal Command:\n${block.command}\n\n### Terminal Output:\n${block.output}`
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
protected async pickCommandBlock(): Promise<string | undefined> {
|
|
110
|
+
if (!this.terminalService.lastUsedTerminal?.commandHistoryState) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
const commandHistory = this.terminalService.lastUsedTerminal.commandHistoryState.commandHistory;
|
|
114
|
+
const quickPick = this.quickInputService.createQuickPick();
|
|
115
|
+
quickPick.title = nls.localize('theia/ai/terminal/terminalCommandBlockAIVariable/quickPick/title', 'Select a command and its output from the terminal history');
|
|
116
|
+
quickPick.placeholder = nls.localize(
|
|
117
|
+
'theia/ai/terminal/terminalCommandBlockAIVariable/quickPick/placeholder',
|
|
118
|
+
'Type to filter commands'
|
|
119
|
+
);
|
|
120
|
+
quickPick.items = commandHistory.map((block, i) => (
|
|
121
|
+
{
|
|
122
|
+
label: block.command,
|
|
123
|
+
// replace all whitespace with a single space for better readability
|
|
124
|
+
description: block.output.replace(/\s+/g, ' ').trim().slice(0, 60),
|
|
125
|
+
blockIndex: i
|
|
126
|
+
} as CommandBlockQuickPickItem
|
|
127
|
+
)).toReversed();
|
|
128
|
+
quickPick.show();
|
|
129
|
+
return new Promise(resolve => {
|
|
130
|
+
quickPick.onDidAccept(() => {
|
|
131
|
+
const selected = quickPick.selectedItems[0];
|
|
132
|
+
if (CommandBlockQuickPickItem.is(selected)) {
|
|
133
|
+
resolve(String(selected.blockIndex));
|
|
134
|
+
}
|
|
135
|
+
quickPick.dispose();
|
|
136
|
+
});
|
|
137
|
+
quickPick.onDidHide(() => {
|
|
138
|
+
resolve(undefined);
|
|
139
|
+
quickPick.dispose();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH and others.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { expect } from 'chai';
|
|
18
|
+
import { ILogger, QuickInputService } from '@theia/core';
|
|
19
|
+
import { AIVariableContext, AIVariableResolutionRequest } from '@theia/ai-core';
|
|
20
|
+
import { Container } from '@theia/core/shared/inversify';
|
|
21
|
+
import { TerminalService } from '@theia/terminal/lib/browser/base/terminal-service';
|
|
22
|
+
import { TerminalBlock, TerminalWidget } from '@theia/terminal/lib/browser/base/terminal-widget';
|
|
23
|
+
import { AiTerminalCommandBlockVariableContribution } from './ai-terminal-command-block-variable';
|
|
24
|
+
|
|
25
|
+
function createMockTerminal(overrides: Partial<{
|
|
26
|
+
bufferLines: string[];
|
|
27
|
+
commandHistory: TerminalBlock[];
|
|
28
|
+
}>): TerminalWidget {
|
|
29
|
+
const { bufferLines = [], commandHistory } = overrides;
|
|
30
|
+
return {
|
|
31
|
+
buffer: {
|
|
32
|
+
length: bufferLines.length,
|
|
33
|
+
getLines: (start: number, length: number) => bufferLines.slice(start, start + length),
|
|
34
|
+
},
|
|
35
|
+
commandHistoryState: commandHistory !== undefined
|
|
36
|
+
? { commandHistory }
|
|
37
|
+
: undefined,
|
|
38
|
+
} as unknown as TerminalWidget;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function createRequest(arg?: string): AIVariableResolutionRequest {
|
|
42
|
+
return {
|
|
43
|
+
variable: { id: 'ai-terminal:terminal-command-block', name: 'terminalCommand', description: '' },
|
|
44
|
+
arg,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const mockContext: AIVariableContext = {};
|
|
49
|
+
|
|
50
|
+
describe('AiTerminalCommandBlockVariableContribution.resolve()', () => {
|
|
51
|
+
let mockTerminalService: { lastUsedTerminal: TerminalWidget | undefined };
|
|
52
|
+
let contribution: AiTerminalCommandBlockVariableContribution;
|
|
53
|
+
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
const container = new Container();
|
|
56
|
+
|
|
57
|
+
mockTerminalService = {
|
|
58
|
+
lastUsedTerminal: createMockTerminal({
|
|
59
|
+
commandHistory: [
|
|
60
|
+
{ command: 'ls', output: 'file1\nfile2' },
|
|
61
|
+
{ command: 'pwd', output: '/home/user' },
|
|
62
|
+
{ command: 'echo hello world', output: 'hello world' },
|
|
63
|
+
]
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
container.bind(TerminalService).toConstantValue(mockTerminalService as unknown as TerminalService);
|
|
68
|
+
container.bind(QuickInputService).toConstantValue({} as unknown as QuickInputService);
|
|
69
|
+
container.bind(ILogger).toConstantValue({ warn: () => { } } as unknown as ILogger);
|
|
70
|
+
container.bind(AiTerminalCommandBlockVariableContribution).toSelf();
|
|
71
|
+
contribution = container.get(AiTerminalCommandBlockVariableContribution);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('returns undefined when there is no last used terminal', async () => {
|
|
75
|
+
mockTerminalService.lastUsedTerminal = undefined;
|
|
76
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
77
|
+
expect(result).to.be.undefined;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('returns the last command when no parameter is passed', async () => {
|
|
81
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
82
|
+
expect(result?.value).to.equal('### Terminal Command:\necho hello world\n\n### Terminal Output:\nhello world');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('returns the last command when the input is an empty or white space only string', async () => {
|
|
86
|
+
const emptyStringResult = await contribution.resolve(createRequest(''), mockContext);
|
|
87
|
+
const whiteSpaceResult = await contribution.resolve(createRequest(' '), mockContext);
|
|
88
|
+
expect(emptyStringResult?.value).to.equal('### Terminal Command:\necho hello world\n\n### Terminal Output:\nhello world');
|
|
89
|
+
expect(whiteSpaceResult?.value).to.equal('### Terminal Command:\necho hello world\n\n### Terminal Output:\nhello world');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('returns the correct command according to the argument', async () => {
|
|
93
|
+
const result = await contribution.resolve(createRequest('1'), mockContext);
|
|
94
|
+
expect(result?.value).to.equal('### Terminal Command:\npwd\n\n### Terminal Output:\n/home/user');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('returns the last 50 lines of the terminal when terminal history is not enabled', async () => {
|
|
98
|
+
mockTerminalService.lastUsedTerminal = createMockTerminal({
|
|
99
|
+
bufferLines: ['ls', 'file1\nfile2', 'pwd', '/home/user']
|
|
100
|
+
});
|
|
101
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
102
|
+
expect(result?.value).to.equal('ls\nfile1\nfile2\npwd\n/home/user');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('returns undefined when the terminal history is empty', async () => {
|
|
106
|
+
mockTerminalService.lastUsedTerminal = createMockTerminal({
|
|
107
|
+
commandHistory: []
|
|
108
|
+
});
|
|
109
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
110
|
+
expect(result).to.be.undefined;
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('returns undefined when the input is not a number', async () => {
|
|
114
|
+
const result = await contribution.resolve(createRequest('one'), mockContext);
|
|
115
|
+
expect(result).to.be.undefined;
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('returns undefined when the input is not an integer', async () => {
|
|
119
|
+
const result = await contribution.resolve(createRequest('1.5'), mockContext);
|
|
120
|
+
expect(result).to.be.undefined;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('returns undefined when terminal history is not enabled and the buffer is empty', async () => {
|
|
124
|
+
mockTerminalService.lastUsedTerminal = createMockTerminal({});
|
|
125
|
+
const result = await contribution.resolve(createRequest(), mockContext);
|
|
126
|
+
expect(result).to.be.undefined;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('returns undefined when the input is a negative integer', async () => {
|
|
130
|
+
const result = await contribution.resolve(createRequest('-1'), mockContext);
|
|
131
|
+
expect(result).to.be.undefined;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('returns undefined when the input index is out of bounds', async () => {
|
|
135
|
+
const result = await contribution.resolve(createRequest('10'), mockContext);
|
|
136
|
+
expect(result).to.be.undefined;
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
});
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { ChatResponsePartRenderer } from '@theia/ai-chat-ui/lib/browser/chat-response-part-renderer';
|
|
18
|
-
import { Agent } from '@theia/ai-core/lib/common';
|
|
18
|
+
import { Agent, AIVariableContribution } from '@theia/ai-core/lib/common';
|
|
19
19
|
import { bindToolProvider } from '@theia/ai-core/lib/common/tool-invocation-registry';
|
|
20
20
|
import { CommandContribution, MenuContribution, PreferenceContribution } from '@theia/core';
|
|
21
21
|
import { KeybindingContribution, WebSocketConnectionProvider } from '@theia/core/lib/browser';
|
|
@@ -28,6 +28,7 @@ import { ShellExecutionServer, shellExecutionPath } from '../common/shell-execut
|
|
|
28
28
|
import { ShellCommandPermissionService } from './shell-command-permission-service';
|
|
29
29
|
import { shellCommandPreferences } from '../common/shell-command-preferences';
|
|
30
30
|
import { DefaultShellCommandAnalyzer, ShellCommandAnalyzer } from '../common/shell-command-analyzer';
|
|
31
|
+
import { AiTerminalCommandBlockVariableContribution } from './ai-terminal-command-block-variable';
|
|
31
32
|
|
|
32
33
|
import '../../src/browser/style/ai-terminal.css';
|
|
33
34
|
import '../../src/browser/style/shell-execution-tool.css';
|
|
@@ -55,4 +56,7 @@ export default new ContainerModule(bind => {
|
|
|
55
56
|
bind(PreferenceContribution).toConstantValue({ schema: shellCommandPreferences });
|
|
56
57
|
|
|
57
58
|
bind(ShellCommandAnalyzer).to(DefaultShellCommandAnalyzer).inSingletonScope();
|
|
59
|
+
|
|
60
|
+
bind(AiTerminalCommandBlockVariableContribution).toSelf().inSingletonScope();
|
|
61
|
+
bind(AIVariableContribution).toService(AiTerminalCommandBlockVariableContribution);
|
|
58
62
|
});
|