@agents-at-scale/ark 0.1.35 → 0.1.36-rc1
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/arkServices.d.ts +42 -0
- package/dist/arkServices.js +138 -0
- package/dist/arkServices.spec.d.ts +1 -0
- package/dist/arkServices.spec.js +24 -0
- package/dist/charts/charts.d.ts +5 -0
- package/dist/charts/charts.js +6 -0
- package/dist/charts/dependencies.d.ts +6 -0
- package/dist/charts/dependencies.js +50 -0
- package/dist/charts/types.d.ts +40 -0
- package/dist/charts/types.js +1 -0
- package/dist/commands/agents/index.d.ts +3 -0
- package/dist/commands/agents/index.js +65 -0
- package/dist/commands/agents/index.spec.d.ts +1 -0
- package/dist/commands/agents/index.spec.js +67 -0
- package/dist/commands/agents/selector.d.ts +8 -0
- package/dist/commands/agents/selector.js +53 -0
- package/dist/commands/agents.d.ts +2 -0
- package/dist/commands/agents.js +53 -0
- package/dist/commands/chat/index.d.ts +3 -0
- package/dist/commands/chat/index.js +29 -0
- package/dist/commands/chat.d.ts +2 -0
- package/dist/commands/chat.js +45 -0
- package/dist/commands/cluster/get.d.ts +2 -0
- package/dist/commands/cluster/get.js +39 -0
- package/dist/commands/cluster/get.spec.d.ts +1 -0
- package/dist/commands/cluster/get.spec.js +92 -0
- package/dist/commands/cluster/index.d.ts +2 -1
- package/dist/commands/cluster/index.js +3 -5
- package/dist/commands/cluster/index.spec.d.ts +1 -0
- package/dist/commands/cluster/index.spec.js +24 -0
- package/dist/commands/completion/index.d.ts +3 -0
- package/dist/commands/completion/index.js +230 -0
- package/dist/commands/completion/index.spec.d.ts +1 -0
- package/dist/commands/completion/index.spec.js +34 -0
- package/dist/commands/completion.js +159 -2
- package/dist/commands/config/index.d.ts +3 -0
- package/dist/commands/config/index.js +42 -0
- package/dist/commands/config/index.spec.d.ts +1 -0
- package/dist/commands/config/index.spec.js +78 -0
- package/dist/commands/config.d.ts +0 -3
- package/dist/commands/config.js +38 -321
- package/dist/commands/dashboard/index.d.ts +4 -0
- package/dist/commands/dashboard/index.js +39 -0
- package/dist/commands/dashboard.d.ts +3 -0
- package/dist/commands/dashboard.js +39 -0
- package/dist/commands/dev/index.d.ts +3 -0
- package/dist/commands/dev/index.js +9 -0
- package/dist/commands/dev/tool/check.d.ts +2 -0
- package/dist/commands/dev/tool/check.js +142 -0
- package/dist/commands/dev/tool/clean.d.ts +2 -0
- package/dist/commands/dev/tool/clean.js +153 -0
- package/dist/commands/dev/tool/generate.d.ts +2 -0
- package/dist/commands/dev/tool/generate.js +28 -0
- package/dist/commands/dev/tool/index.d.ts +2 -0
- package/dist/commands/dev/tool/index.js +14 -0
- package/dist/commands/dev/tool/init.d.ts +2 -0
- package/dist/commands/dev/tool/init.js +320 -0
- package/dist/commands/dev/tool/shared.d.ts +5 -0
- package/dist/commands/dev/tool/shared.js +258 -0
- package/dist/commands/dev/tool/status.d.ts +2 -0
- package/dist/commands/dev/tool/status.js +136 -0
- package/dist/commands/dev/tool-generate.spec.d.ts +1 -0
- package/dist/commands/dev/tool-generate.spec.js +163 -0
- package/dist/commands/dev/tool.d.ts +2 -0
- package/dist/commands/dev/tool.js +559 -0
- package/dist/commands/dev/tool.spec.d.ts +1 -0
- package/dist/commands/dev/tool.spec.js +48 -0
- package/dist/commands/docs/index.d.ts +4 -0
- package/dist/commands/docs/index.js +18 -0
- package/dist/commands/generate/config.js +5 -24
- package/dist/commands/generate/generators/mcpserver.d.ts +2 -1
- package/dist/commands/generate/generators/mcpserver.js +26 -5
- package/dist/commands/generate/generators/project.js +22 -41
- package/dist/commands/generate/index.d.ts +2 -1
- package/dist/commands/generate/index.js +1 -1
- package/dist/commands/install/index.d.ts +8 -0
- package/dist/commands/install/index.js +295 -0
- package/dist/commands/install/index.spec.d.ts +1 -0
- package/dist/commands/install/index.spec.js +143 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.js +147 -0
- package/dist/commands/models/create.d.ts +1 -0
- package/dist/commands/models/create.js +213 -0
- package/dist/commands/models/create.spec.d.ts +1 -0
- package/dist/commands/models/create.spec.js +125 -0
- package/dist/commands/models/index.d.ts +3 -0
- package/dist/commands/models/index.js +75 -0
- package/dist/commands/models/index.spec.d.ts +1 -0
- package/dist/commands/models/index.spec.js +96 -0
- package/dist/commands/models/selector.d.ts +8 -0
- package/dist/commands/models/selector.js +53 -0
- package/dist/commands/query/index.d.ts +3 -0
- package/dist/commands/query/index.js +24 -0
- package/dist/commands/query/index.spec.d.ts +1 -0
- package/dist/commands/query/index.spec.js +53 -0
- package/dist/commands/routes/index.d.ts +3 -0
- package/dist/commands/routes/index.js +93 -0
- package/dist/commands/routes.d.ts +2 -0
- package/dist/commands/routes.js +101 -0
- package/dist/commands/status/index.d.ts +3 -0
- package/dist/commands/status/index.js +281 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +33 -0
- package/dist/commands/targets/index.d.ts +3 -0
- package/dist/commands/targets/index.js +72 -0
- package/dist/commands/targets/index.spec.d.ts +1 -0
- package/dist/commands/targets/index.spec.js +154 -0
- package/dist/commands/targets.d.ts +2 -0
- package/dist/commands/targets.js +65 -0
- package/dist/commands/teams/index.d.ts +3 -0
- package/dist/commands/teams/index.js +64 -0
- package/dist/commands/teams/index.spec.d.ts +1 -0
- package/dist/commands/teams/index.spec.js +70 -0
- package/dist/commands/teams/selector.d.ts +8 -0
- package/dist/commands/teams/selector.js +55 -0
- package/dist/commands/tools/index.d.ts +3 -0
- package/dist/commands/tools/index.js +49 -0
- package/dist/commands/tools/index.spec.d.ts +1 -0
- package/dist/commands/tools/index.spec.js +70 -0
- package/dist/commands/tools/selector.d.ts +8 -0
- package/dist/commands/tools/selector.js +53 -0
- package/dist/commands/uninstall/index.d.ts +3 -0
- package/dist/commands/uninstall/index.js +101 -0
- package/dist/commands/uninstall/index.spec.d.ts +1 -0
- package/dist/commands/uninstall/index.spec.js +125 -0
- package/dist/commands/uninstall.d.ts +2 -0
- package/dist/commands/uninstall.js +83 -0
- package/dist/components/ChatUI.d.ts +16 -0
- package/dist/components/ChatUI.js +801 -0
- package/dist/components/StatusView.d.ts +10 -0
- package/dist/components/StatusView.js +39 -0
- package/dist/components/statusChecker.d.ts +14 -24
- package/dist/components/statusChecker.js +295 -129
- package/dist/config.d.ts +3 -22
- package/dist/config.js +10 -161
- package/dist/index.d.ts +1 -1
- package/dist/index.js +42 -42
- package/dist/lib/arkApiClient.d.ts +53 -0
- package/dist/lib/arkApiClient.js +102 -0
- package/dist/lib/arkApiProxy.d.ts +9 -0
- package/dist/lib/arkApiProxy.js +22 -0
- package/dist/lib/arkServiceProxy.d.ts +14 -0
- package/dist/lib/arkServiceProxy.js +95 -0
- package/dist/lib/arkStatus.d.ts +10 -0
- package/dist/lib/arkStatus.js +79 -0
- package/dist/lib/arkStatus.spec.d.ts +1 -0
- package/dist/lib/arkStatus.spec.js +49 -0
- package/dist/lib/chatClient.d.ts +33 -0
- package/dist/lib/chatClient.js +93 -0
- package/dist/lib/cluster.d.ts +2 -1
- package/dist/lib/cluster.js +37 -16
- package/dist/lib/cluster.spec.d.ts +1 -0
- package/dist/lib/cluster.spec.js +338 -0
- package/dist/lib/commandUtils.d.ts +4 -0
- package/dist/lib/commandUtils.js +18 -0
- package/dist/lib/commandUtils.test.d.ts +1 -0
- package/dist/lib/commandUtils.test.js +44 -0
- package/dist/lib/commands.d.ts +16 -0
- package/dist/lib/commands.js +29 -0
- package/dist/lib/commands.spec.d.ts +1 -0
- package/dist/lib/commands.spec.js +146 -0
- package/dist/lib/config.d.ts +26 -80
- package/dist/lib/config.js +70 -205
- package/dist/lib/config.spec.d.ts +1 -0
- package/dist/lib/config.spec.js +99 -0
- package/dist/lib/config.test.d.ts +1 -0
- package/dist/lib/config.test.js +93 -0
- package/dist/lib/consts.d.ts +0 -1
- package/dist/lib/consts.js +0 -2
- package/dist/lib/consts.spec.d.ts +1 -0
- package/dist/lib/consts.spec.js +15 -0
- package/dist/lib/dev/tools/analyzer.d.ts +30 -0
- package/dist/lib/dev/tools/analyzer.js +190 -0
- package/dist/lib/dev/tools/discover_tools.py +392 -0
- package/dist/lib/dev/tools/mcp-types.d.ts +28 -0
- package/dist/lib/dev/tools/mcp-types.js +86 -0
- package/dist/lib/dev/tools/types.d.ts +50 -0
- package/dist/lib/dev/tools/types.js +1 -0
- package/dist/lib/errors.js +1 -1
- package/dist/lib/errors.spec.d.ts +1 -0
- package/dist/lib/errors.spec.js +221 -0
- package/dist/lib/exec.d.ts +0 -4
- package/dist/lib/exec.js +0 -11
- package/dist/lib/executeQuery.d.ts +20 -0
- package/dist/lib/executeQuery.js +135 -0
- package/dist/lib/executeQuery.spec.d.ts +1 -0
- package/dist/lib/executeQuery.spec.js +170 -0
- package/dist/lib/nextSteps.d.ts +4 -0
- package/dist/lib/nextSteps.js +20 -0
- package/dist/lib/nextSteps.spec.d.ts +1 -0
- package/dist/lib/nextSteps.spec.js +59 -0
- package/dist/lib/output.d.ts +36 -0
- package/dist/lib/output.js +89 -0
- package/dist/lib/output.spec.d.ts +1 -0
- package/dist/lib/output.spec.js +123 -0
- package/dist/lib/portUtils.d.ts +8 -0
- package/dist/lib/portUtils.js +39 -0
- package/dist/lib/queryRunner.d.ts +22 -0
- package/dist/lib/queryRunner.js +142 -0
- package/dist/lib/startup.d.ts +9 -0
- package/dist/lib/startup.js +87 -0
- package/dist/lib/startup.spec.d.ts +1 -0
- package/dist/lib/startup.spec.js +152 -0
- package/dist/lib/types.d.ts +87 -3
- package/dist/lib/versions.d.ts +23 -0
- package/dist/lib/versions.js +51 -0
- package/dist/types/types.d.ts +40 -0
- package/dist/types/types.js +1 -0
- package/dist/ui/AgentSelector.d.ts +8 -0
- package/dist/ui/AgentSelector.js +53 -0
- package/dist/ui/MainMenu.d.ts +5 -1
- package/dist/ui/MainMenu.js +226 -91
- package/dist/ui/ModelSelector.d.ts +8 -0
- package/dist/ui/ModelSelector.js +53 -0
- package/dist/ui/TeamSelector.d.ts +8 -0
- package/dist/ui/TeamSelector.js +55 -0
- package/dist/ui/ToolSelector.d.ts +8 -0
- package/dist/ui/ToolSelector.js +53 -0
- package/dist/ui/statusFormatter.d.ts +22 -7
- package/dist/ui/statusFormatter.js +39 -39
- package/dist/ui/statusFormatter.spec.d.ts +1 -0
- package/dist/ui/statusFormatter.spec.js +58 -0
- package/package.json +16 -5
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import output from '../../lib/output.js';
|
|
4
|
+
async function fetchResourceTargets(resourceType) {
|
|
5
|
+
const result = await execa('kubectl', ['get', `${resourceType}s`, '-o', 'json'], {
|
|
6
|
+
stdio: 'pipe',
|
|
7
|
+
});
|
|
8
|
+
const data = JSON.parse(result.stdout);
|
|
9
|
+
const items = data.items || [];
|
|
10
|
+
return items.map((item) => ({
|
|
11
|
+
type: resourceType,
|
|
12
|
+
name: item.metadata.name,
|
|
13
|
+
id: `${resourceType}/${item.metadata.name}`,
|
|
14
|
+
available: item.status?.available || item.status?.phase === 'ready' || true,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
async function listTargets(options) {
|
|
18
|
+
try {
|
|
19
|
+
// Fetch all resource types in parallel
|
|
20
|
+
const resourceTypes = options.type
|
|
21
|
+
? [options.type]
|
|
22
|
+
: ['model', 'agent', 'team', 'tool'];
|
|
23
|
+
const targetPromises = resourceTypes.map((type) => fetchResourceTargets(type));
|
|
24
|
+
const targetArrays = await Promise.all(targetPromises);
|
|
25
|
+
// Flatten all targets into single array
|
|
26
|
+
const allTargets = targetArrays.flat();
|
|
27
|
+
// Sort targets by type and name
|
|
28
|
+
allTargets.sort((a, b) => {
|
|
29
|
+
if (a.type !== b.type) {
|
|
30
|
+
return a.type.localeCompare(b.type);
|
|
31
|
+
}
|
|
32
|
+
return a.name.localeCompare(b.name);
|
|
33
|
+
});
|
|
34
|
+
if (options.output === 'json') {
|
|
35
|
+
console.log(JSON.stringify(allTargets, null, 2));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
if (allTargets.length === 0) {
|
|
39
|
+
output.warning('no targets available');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Simple list output with type/name format
|
|
43
|
+
for (const target of allTargets) {
|
|
44
|
+
console.log(target.id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
output.error('fetching targets:', error instanceof Error ? error.message : error);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function createTargetsCommand(_) {
|
|
54
|
+
const targets = new Command('targets');
|
|
55
|
+
targets
|
|
56
|
+
.description('list available query targets (agents, teams, models, tools)')
|
|
57
|
+
.option('-o, --output <format>', 'output format (json or text)', 'text')
|
|
58
|
+
.option('-t, --type <type>', 'filter by type (agent, team, model, tool)')
|
|
59
|
+
.action(async (options) => {
|
|
60
|
+
await listTargets(options);
|
|
61
|
+
});
|
|
62
|
+
targets
|
|
63
|
+
.command('list')
|
|
64
|
+
.alias('ls')
|
|
65
|
+
.description('list all available query targets')
|
|
66
|
+
.option('-o, --output <format>', 'output format (json or text)', 'text')
|
|
67
|
+
.option('-t, --type <type>', 'filter by type (agent, team, model, tool)')
|
|
68
|
+
.action(async (options) => {
|
|
69
|
+
await listTargets(options);
|
|
70
|
+
});
|
|
71
|
+
return targets;
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
// Mock execa to avoid real kubectl calls
|
|
4
|
+
jest.unstable_mockModule('execa', () => ({
|
|
5
|
+
execa: jest.fn(),
|
|
6
|
+
}));
|
|
7
|
+
const mockOutput = {
|
|
8
|
+
warning: jest.fn(),
|
|
9
|
+
error: jest.fn(),
|
|
10
|
+
};
|
|
11
|
+
jest.unstable_mockModule('../../lib/output.js', () => ({
|
|
12
|
+
default: mockOutput,
|
|
13
|
+
}));
|
|
14
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
|
|
15
|
+
throw new Error('process.exit called');
|
|
16
|
+
}));
|
|
17
|
+
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
18
|
+
const { execa } = await import('execa');
|
|
19
|
+
const mockExeca = execa;
|
|
20
|
+
const { createTargetsCommand } = await import('./index.js');
|
|
21
|
+
describe('targets command', () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
it('creates command with correct structure', () => {
|
|
26
|
+
const command = createTargetsCommand({});
|
|
27
|
+
expect(command).toBeInstanceOf(Command);
|
|
28
|
+
expect(command.name()).toBe('targets');
|
|
29
|
+
});
|
|
30
|
+
it('lists targets in text format', async () => {
|
|
31
|
+
// Mock kubectl responses for each resource type (order: model, agent, team, tool)
|
|
32
|
+
mockExeca
|
|
33
|
+
.mockResolvedValueOnce({
|
|
34
|
+
stdout: JSON.stringify({
|
|
35
|
+
items: [{ metadata: { name: 'gpt-4' }, status: { available: true } }],
|
|
36
|
+
}),
|
|
37
|
+
})
|
|
38
|
+
.mockResolvedValueOnce({
|
|
39
|
+
stdout: JSON.stringify({
|
|
40
|
+
items: [
|
|
41
|
+
{ metadata: { name: 'gpt-assistant' }, status: { phase: 'ready' } },
|
|
42
|
+
],
|
|
43
|
+
}),
|
|
44
|
+
})
|
|
45
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
46
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
|
|
47
|
+
const command = createTargetsCommand({});
|
|
48
|
+
await command.parseAsync(['node', 'test']);
|
|
49
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'models', '-o', 'json'], {
|
|
50
|
+
stdio: 'pipe',
|
|
51
|
+
});
|
|
52
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'agents', '-o', 'json'], {
|
|
53
|
+
stdio: 'pipe',
|
|
54
|
+
});
|
|
55
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('agent/gpt-assistant');
|
|
56
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('model/gpt-4');
|
|
57
|
+
});
|
|
58
|
+
it('lists targets in json format', async () => {
|
|
59
|
+
// Order: model, agent, team, tool
|
|
60
|
+
mockExeca
|
|
61
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
62
|
+
.mockResolvedValueOnce({
|
|
63
|
+
stdout: JSON.stringify({
|
|
64
|
+
items: [{ metadata: { name: 'gpt' }, status: { phase: 'ready' } }],
|
|
65
|
+
}),
|
|
66
|
+
})
|
|
67
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
68
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
|
|
69
|
+
const command = createTargetsCommand({});
|
|
70
|
+
await command.parseAsync(['node', 'test', '-o', 'json']);
|
|
71
|
+
const expectedTargets = [
|
|
72
|
+
{ type: 'agent', name: 'gpt', id: 'agent/gpt', available: true },
|
|
73
|
+
];
|
|
74
|
+
expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(expectedTargets, null, 2));
|
|
75
|
+
});
|
|
76
|
+
it('filters targets by type', async () => {
|
|
77
|
+
mockExeca.mockResolvedValueOnce({
|
|
78
|
+
stdout: JSON.stringify({
|
|
79
|
+
items: [
|
|
80
|
+
{ metadata: { name: 'gpt' }, status: { phase: 'ready' } },
|
|
81
|
+
{ metadata: { name: 'helper' }, status: { phase: 'ready' } },
|
|
82
|
+
],
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
85
|
+
const command = createTargetsCommand({});
|
|
86
|
+
await command.parseAsync(['node', 'test', '-t', 'agent']);
|
|
87
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'agents', '-o', 'json'], {
|
|
88
|
+
stdio: 'pipe',
|
|
89
|
+
});
|
|
90
|
+
expect(mockExeca).toHaveBeenCalledTimes(1); // Only agents, not other types
|
|
91
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('agent/gpt');
|
|
92
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('agent/helper');
|
|
93
|
+
});
|
|
94
|
+
it('sorts targets by type then name', async () => {
|
|
95
|
+
// Order: model, agent, team, tool
|
|
96
|
+
mockExeca
|
|
97
|
+
.mockResolvedValueOnce({
|
|
98
|
+
stdout: JSON.stringify({
|
|
99
|
+
items: [
|
|
100
|
+
{ metadata: { name: 'b' }, status: { available: true } },
|
|
101
|
+
{ metadata: { name: 'a' }, status: { available: true } },
|
|
102
|
+
],
|
|
103
|
+
}),
|
|
104
|
+
})
|
|
105
|
+
.mockResolvedValueOnce({
|
|
106
|
+
stdout: JSON.stringify({
|
|
107
|
+
items: [
|
|
108
|
+
{ metadata: { name: 'z' }, status: { phase: 'ready' } },
|
|
109
|
+
{ metadata: { name: 'a' }, status: { phase: 'ready' } },
|
|
110
|
+
],
|
|
111
|
+
}),
|
|
112
|
+
})
|
|
113
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
114
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
|
|
115
|
+
const command = createTargetsCommand({});
|
|
116
|
+
await command.parseAsync(['node', 'test']);
|
|
117
|
+
// Check order of calls - sorted by type then name
|
|
118
|
+
const calls = mockConsoleLog.mock.calls
|
|
119
|
+
.filter((call) => call[0] && call[0].includes('/'))
|
|
120
|
+
.map((call) => call[0]);
|
|
121
|
+
expect(calls).toEqual(['agent/a', 'agent/z', 'model/a', 'model/b']);
|
|
122
|
+
});
|
|
123
|
+
it('shows warning when no targets', async () => {
|
|
124
|
+
// All resource types return empty (order: model, agent, team, tool)
|
|
125
|
+
mockExeca
|
|
126
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
127
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
128
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
129
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
|
|
130
|
+
const command = createTargetsCommand({});
|
|
131
|
+
await command.parseAsync(['node', 'test']);
|
|
132
|
+
expect(mockOutput.warning).toHaveBeenCalledWith('no targets available');
|
|
133
|
+
});
|
|
134
|
+
it('handles errors', async () => {
|
|
135
|
+
mockExeca.mockRejectedValue(new Error('kubectl not found'));
|
|
136
|
+
const command = createTargetsCommand({});
|
|
137
|
+
await expect(command.parseAsync(['node', 'test'])).rejects.toThrow('process.exit called');
|
|
138
|
+
expect(mockOutput.error).toHaveBeenCalledWith('fetching targets:', 'kubectl not found');
|
|
139
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
140
|
+
});
|
|
141
|
+
it('list subcommand works', async () => {
|
|
142
|
+
// Order: model, agent, team, tool
|
|
143
|
+
mockExeca
|
|
144
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
145
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
146
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) })
|
|
147
|
+
.mockResolvedValueOnce({ stdout: JSON.stringify({ items: [] }) });
|
|
148
|
+
const command = createTargetsCommand({});
|
|
149
|
+
await command.parseAsync(['node', 'test', 'list']);
|
|
150
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'models', '-o', 'json'], {
|
|
151
|
+
stdio: 'pipe',
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import output from '../lib/output.js';
|
|
3
|
+
import { ArkApiProxy } from '../lib/arkApiProxy.js';
|
|
4
|
+
async function listTargets(options) {
|
|
5
|
+
let proxy;
|
|
6
|
+
try {
|
|
7
|
+
proxy = new ArkApiProxy();
|
|
8
|
+
const arkApiClient = await proxy.start();
|
|
9
|
+
const allTargets = await arkApiClient.getQueryTargets();
|
|
10
|
+
// Filter by type if specified
|
|
11
|
+
let filteredTargets = allTargets;
|
|
12
|
+
if (options.type) {
|
|
13
|
+
filteredTargets = allTargets.filter((t) => t.type === options.type);
|
|
14
|
+
}
|
|
15
|
+
// Sort targets by type and name
|
|
16
|
+
filteredTargets.sort((a, b) => {
|
|
17
|
+
if (a.type !== b.type) {
|
|
18
|
+
return a.type.localeCompare(b.type);
|
|
19
|
+
}
|
|
20
|
+
return a.name.localeCompare(b.name);
|
|
21
|
+
});
|
|
22
|
+
if (options.output === 'json') {
|
|
23
|
+
console.log(JSON.stringify(filteredTargets, null, 2));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
if (filteredTargets.length === 0) {
|
|
27
|
+
output.warning('no targets available');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Simple list output with type/name format
|
|
31
|
+
for (const target of filteredTargets) {
|
|
32
|
+
console.log(target.id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
output.error('fetching targets:', error instanceof Error ? error.message : error);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
if (proxy) {
|
|
42
|
+
proxy.stop();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function createTargetsCommand() {
|
|
47
|
+
const targets = new Command('targets');
|
|
48
|
+
targets
|
|
49
|
+
.description('list available query targets (agents, teams, models, tools)')
|
|
50
|
+
.option('-o, --output <format>', 'output format (json or text)', 'text')
|
|
51
|
+
.option('-t, --type <type>', 'filter by type (agent, team, model, tool)')
|
|
52
|
+
.action(async (options) => {
|
|
53
|
+
await listTargets(options);
|
|
54
|
+
});
|
|
55
|
+
targets
|
|
56
|
+
.command('list')
|
|
57
|
+
.alias('ls')
|
|
58
|
+
.description('list all available query targets')
|
|
59
|
+
.option('-o, --output <format>', 'output format (json or text)', 'text')
|
|
60
|
+
.option('-t, --type <type>', 'filter by type (agent, team, model, tool)')
|
|
61
|
+
.action(async (options) => {
|
|
62
|
+
await listTargets(options);
|
|
63
|
+
});
|
|
64
|
+
return targets;
|
|
65
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import output from '../../lib/output.js';
|
|
4
|
+
import { executeQuery } from '../../lib/executeQuery.js';
|
|
5
|
+
async function listTeams(options) {
|
|
6
|
+
try {
|
|
7
|
+
// Use kubectl to get teams
|
|
8
|
+
const result = await execa('kubectl', ['get', 'teams', '-o', 'json'], {
|
|
9
|
+
stdio: 'pipe',
|
|
10
|
+
});
|
|
11
|
+
const data = JSON.parse(result.stdout);
|
|
12
|
+
const teams = data.items || [];
|
|
13
|
+
if (options.output === 'json') {
|
|
14
|
+
// Output the raw items for JSON format
|
|
15
|
+
console.log(JSON.stringify(teams, null, 2));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
if (teams.length === 0) {
|
|
19
|
+
output.info('No teams found');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
teams.forEach((team) => {
|
|
23
|
+
console.log(team.metadata.name);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
output.error('fetching teams:', error instanceof Error ? error.message : error);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function createTeamsCommand(_) {
|
|
33
|
+
const teamsCommand = new Command('teams');
|
|
34
|
+
teamsCommand
|
|
35
|
+
.description('List available teams')
|
|
36
|
+
.option('-o, --output <format>', 'Output format (json)', 'text')
|
|
37
|
+
.action(async (options) => {
|
|
38
|
+
await listTeams(options);
|
|
39
|
+
});
|
|
40
|
+
const listCommand = new Command('list');
|
|
41
|
+
listCommand
|
|
42
|
+
.alias('ls')
|
|
43
|
+
.description('List available teams')
|
|
44
|
+
.option('-o, --output <format>', 'Output format (json)', 'text')
|
|
45
|
+
.action(async (options) => {
|
|
46
|
+
await listTeams(options);
|
|
47
|
+
});
|
|
48
|
+
teamsCommand.addCommand(listCommand);
|
|
49
|
+
// Add query command
|
|
50
|
+
const queryCommand = new Command('query');
|
|
51
|
+
queryCommand
|
|
52
|
+
.description('Query a team')
|
|
53
|
+
.argument('<name>', 'Team name')
|
|
54
|
+
.argument('<message>', 'Message to send')
|
|
55
|
+
.action(async (name, message) => {
|
|
56
|
+
await executeQuery({
|
|
57
|
+
targetType: 'team',
|
|
58
|
+
targetName: name,
|
|
59
|
+
message,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
teamsCommand.addCommand(queryCommand);
|
|
63
|
+
return teamsCommand;
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
const mockExeca = jest.fn();
|
|
4
|
+
jest.unstable_mockModule('execa', () => ({
|
|
5
|
+
execa: mockExeca,
|
|
6
|
+
}));
|
|
7
|
+
const mockOutput = {
|
|
8
|
+
info: jest.fn(),
|
|
9
|
+
error: jest.fn(),
|
|
10
|
+
};
|
|
11
|
+
jest.unstable_mockModule('../../lib/output.js', () => ({
|
|
12
|
+
default: mockOutput,
|
|
13
|
+
}));
|
|
14
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
|
|
15
|
+
throw new Error('process.exit called');
|
|
16
|
+
}));
|
|
17
|
+
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
18
|
+
const { createTeamsCommand } = await import('./index.js');
|
|
19
|
+
describe('teams command', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
it('creates command with correct structure', () => {
|
|
24
|
+
const command = createTeamsCommand({});
|
|
25
|
+
expect(command).toBeInstanceOf(Command);
|
|
26
|
+
expect(command.name()).toBe('teams');
|
|
27
|
+
});
|
|
28
|
+
it('lists teams in text format', async () => {
|
|
29
|
+
const mockTeams = {
|
|
30
|
+
items: [
|
|
31
|
+
{ metadata: { name: 'engineering' } },
|
|
32
|
+
{ metadata: { name: 'data-science' } },
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify(mockTeams) });
|
|
36
|
+
const command = createTeamsCommand({});
|
|
37
|
+
await command.parseAsync(['node', 'test']);
|
|
38
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'teams', '-o', 'json'], { stdio: 'pipe' });
|
|
39
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('engineering');
|
|
40
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('data-science');
|
|
41
|
+
});
|
|
42
|
+
it('lists teams in json format', async () => {
|
|
43
|
+
const mockTeams = {
|
|
44
|
+
items: [{ metadata: { name: 'engineering' } }],
|
|
45
|
+
};
|
|
46
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify(mockTeams) });
|
|
47
|
+
const command = createTeamsCommand({});
|
|
48
|
+
await command.parseAsync(['node', 'test', '-o', 'json']);
|
|
49
|
+
expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(mockTeams.items, null, 2));
|
|
50
|
+
});
|
|
51
|
+
it('shows info when no teams', async () => {
|
|
52
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify({ items: [] }) });
|
|
53
|
+
const command = createTeamsCommand({});
|
|
54
|
+
await command.parseAsync(['node', 'test']);
|
|
55
|
+
expect(mockOutput.info).toHaveBeenCalledWith('No teams found');
|
|
56
|
+
});
|
|
57
|
+
it('handles errors', async () => {
|
|
58
|
+
mockExeca.mockRejectedValue(new Error('kubectl failed'));
|
|
59
|
+
const command = createTeamsCommand({});
|
|
60
|
+
await expect(command.parseAsync(['node', 'test'])).rejects.toThrow('process.exit called');
|
|
61
|
+
expect(mockOutput.error).toHaveBeenCalledWith('fetching teams:', 'kubectl failed');
|
|
62
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
63
|
+
});
|
|
64
|
+
it('list subcommand works', async () => {
|
|
65
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify({ items: [] }) });
|
|
66
|
+
const command = createTeamsCommand({});
|
|
67
|
+
await command.parseAsync(['node', 'test', 'list']);
|
|
68
|
+
expect(mockExeca).toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Team, ArkApiClient } from '../../lib/arkApiClient.js';
|
|
2
|
+
interface TeamSelectorProps {
|
|
3
|
+
arkApiClient: ArkApiClient;
|
|
4
|
+
onSelect: (team: Team) => void;
|
|
5
|
+
onExit: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function TeamSelector({ arkApiClient, onSelect, onExit, }: TeamSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
export function TeamSelector({ arkApiClient, onSelect, onExit, }) {
|
|
5
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
+
const [teams, setTeams] = useState([]);
|
|
7
|
+
const [loading, setLoading] = useState(true);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
arkApiClient
|
|
11
|
+
.getTeams()
|
|
12
|
+
.then((fetchedTeams) => {
|
|
13
|
+
setTeams(fetchedTeams);
|
|
14
|
+
setLoading(false);
|
|
15
|
+
})
|
|
16
|
+
.catch((err) => {
|
|
17
|
+
setError(err.message || 'Failed to fetch teams');
|
|
18
|
+
setLoading(false);
|
|
19
|
+
});
|
|
20
|
+
}, [arkApiClient]);
|
|
21
|
+
useInput((input, key) => {
|
|
22
|
+
if (key.escape) {
|
|
23
|
+
onExit();
|
|
24
|
+
}
|
|
25
|
+
else if (key.upArrow || input === 'k') {
|
|
26
|
+
setSelectedIndex((prev) => (prev === 0 ? teams.length - 1 : prev - 1));
|
|
27
|
+
}
|
|
28
|
+
else if (key.downArrow || input === 'j') {
|
|
29
|
+
setSelectedIndex((prev) => (prev === teams.length - 1 ? 0 : prev + 1));
|
|
30
|
+
}
|
|
31
|
+
else if (key.return) {
|
|
32
|
+
onSelect(teams[selectedIndex]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Handle number keys for quick selection
|
|
36
|
+
const num = parseInt(input, 10);
|
|
37
|
+
if (!isNaN(num) && num >= 1 && num <= teams.length) {
|
|
38
|
+
onSelect(teams[num - 1]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
if (loading) {
|
|
43
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "Loading teams..." }) }));
|
|
44
|
+
}
|
|
45
|
+
if (error) {
|
|
46
|
+
return (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }));
|
|
47
|
+
}
|
|
48
|
+
if (teams.length === 0) {
|
|
49
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "No teams available" }) }));
|
|
50
|
+
}
|
|
51
|
+
const selectedTeam = teams[selectedIndex];
|
|
52
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 2, paddingY: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, children: "Select Team" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Choose a team to start a conversation with" }) }), _jsx(Box, { flexDirection: "column", children: teams.map((team, index) => (_jsx(Box, { marginBottom: 0, children: _jsxs(Text, { color: index === selectedIndex ? 'green' : undefined, children: [index === selectedIndex ? '❯ ' : ' ', index + 1, ". ", team.name, team.strategy ? ` (${team.strategy})` : ''] }) }, team.name))) }), selectedTeam &&
|
|
53
|
+
(selectedTeam.description || selectedTeam.members_count) && (_jsx(Box, { marginTop: 1, paddingLeft: 2, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: selectedTeam.description ||
|
|
54
|
+
`Members: ${selectedTeam.members_count}` }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter to confirm \u00B7 Number to select \u00B7 Esc to exit" }) })] }));
|
|
55
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import output from '../../lib/output.js';
|
|
4
|
+
async function listTools(options) {
|
|
5
|
+
try {
|
|
6
|
+
// Use kubectl to get tools (MCPServers)
|
|
7
|
+
const result = await execa('kubectl', ['get', 'mcpservers', '-o', 'json'], {
|
|
8
|
+
stdio: 'pipe',
|
|
9
|
+
});
|
|
10
|
+
const data = JSON.parse(result.stdout);
|
|
11
|
+
const tools = data.items || [];
|
|
12
|
+
if (options.output === 'json') {
|
|
13
|
+
// Output the raw items for JSON format
|
|
14
|
+
console.log(JSON.stringify(tools, null, 2));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
if (tools.length === 0) {
|
|
18
|
+
output.info('No tools found');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
tools.forEach((tool) => {
|
|
22
|
+
console.log(tool.metadata.name);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
output.error('fetching tools:', error instanceof Error ? error.message : error);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function createToolsCommand(_) {
|
|
32
|
+
const toolsCommand = new Command('tools');
|
|
33
|
+
toolsCommand
|
|
34
|
+
.description('List available tools')
|
|
35
|
+
.option('-o, --output <format>', 'Output format (json)', 'text')
|
|
36
|
+
.action(async (options) => {
|
|
37
|
+
await listTools(options);
|
|
38
|
+
});
|
|
39
|
+
const listCommand = new Command('list');
|
|
40
|
+
listCommand
|
|
41
|
+
.alias('ls')
|
|
42
|
+
.description('List available tools')
|
|
43
|
+
.option('-o, --output <format>', 'Output format (json)', 'text')
|
|
44
|
+
.action(async (options) => {
|
|
45
|
+
await listTools(options);
|
|
46
|
+
});
|
|
47
|
+
toolsCommand.addCommand(listCommand);
|
|
48
|
+
return toolsCommand;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
const mockExeca = jest.fn();
|
|
4
|
+
jest.unstable_mockModule('execa', () => ({
|
|
5
|
+
execa: mockExeca,
|
|
6
|
+
}));
|
|
7
|
+
const mockOutput = {
|
|
8
|
+
info: jest.fn(),
|
|
9
|
+
error: jest.fn(),
|
|
10
|
+
};
|
|
11
|
+
jest.unstable_mockModule('../../lib/output.js', () => ({
|
|
12
|
+
default: mockOutput,
|
|
13
|
+
}));
|
|
14
|
+
const mockExit = jest.spyOn(process, 'exit').mockImplementation((() => {
|
|
15
|
+
throw new Error('process.exit called');
|
|
16
|
+
}));
|
|
17
|
+
const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
|
|
18
|
+
const { createToolsCommand } = await import('./index.js');
|
|
19
|
+
describe('tools command', () => {
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
jest.clearAllMocks();
|
|
22
|
+
});
|
|
23
|
+
it('creates command with correct structure', () => {
|
|
24
|
+
const command = createToolsCommand({});
|
|
25
|
+
expect(command).toBeInstanceOf(Command);
|
|
26
|
+
expect(command.name()).toBe('tools');
|
|
27
|
+
});
|
|
28
|
+
it('lists tools in text format', async () => {
|
|
29
|
+
const mockTools = {
|
|
30
|
+
items: [
|
|
31
|
+
{ metadata: { name: 'github-mcp' } },
|
|
32
|
+
{ metadata: { name: 'slack-mcp' } },
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify(mockTools) });
|
|
36
|
+
const command = createToolsCommand({});
|
|
37
|
+
await command.parseAsync(['node', 'test']);
|
|
38
|
+
expect(mockExeca).toHaveBeenCalledWith('kubectl', ['get', 'mcpservers', '-o', 'json'], { stdio: 'pipe' });
|
|
39
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('github-mcp');
|
|
40
|
+
expect(mockConsoleLog).toHaveBeenCalledWith('slack-mcp');
|
|
41
|
+
});
|
|
42
|
+
it('lists tools in json format', async () => {
|
|
43
|
+
const mockTools = {
|
|
44
|
+
items: [{ metadata: { name: 'github-mcp' } }],
|
|
45
|
+
};
|
|
46
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify(mockTools) });
|
|
47
|
+
const command = createToolsCommand({});
|
|
48
|
+
await command.parseAsync(['node', 'test', '-o', 'json']);
|
|
49
|
+
expect(mockConsoleLog).toHaveBeenCalledWith(JSON.stringify(mockTools.items, null, 2));
|
|
50
|
+
});
|
|
51
|
+
it('shows info when no tools', async () => {
|
|
52
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify({ items: [] }) });
|
|
53
|
+
const command = createToolsCommand({});
|
|
54
|
+
await command.parseAsync(['node', 'test']);
|
|
55
|
+
expect(mockOutput.info).toHaveBeenCalledWith('No tools found');
|
|
56
|
+
});
|
|
57
|
+
it('handles errors', async () => {
|
|
58
|
+
mockExeca.mockRejectedValue(new Error('kubectl failed'));
|
|
59
|
+
const command = createToolsCommand({});
|
|
60
|
+
await expect(command.parseAsync(['node', 'test'])).rejects.toThrow('process.exit called');
|
|
61
|
+
expect(mockOutput.error).toHaveBeenCalledWith('fetching tools:', 'kubectl failed');
|
|
62
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
63
|
+
});
|
|
64
|
+
it('list subcommand works', async () => {
|
|
65
|
+
mockExeca.mockResolvedValue({ stdout: JSON.stringify({ items: [] }) });
|
|
66
|
+
const command = createToolsCommand({});
|
|
67
|
+
await command.parseAsync(['node', 'test', 'list']);
|
|
68
|
+
expect(mockExeca).toHaveBeenCalled();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Tool, ArkApiClient } from '../../lib/arkApiClient.js';
|
|
2
|
+
interface ToolSelectorProps {
|
|
3
|
+
arkApiClient: ArkApiClient;
|
|
4
|
+
onSelect: (tool: Tool) => void;
|
|
5
|
+
onExit: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function ToolSelector({ arkApiClient, onSelect, onExit, }: ToolSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|