@agents-at-scale/ark 0.1.45 → 0.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/arkServices.js +13 -1
- package/dist/arkServices.spec.js +6 -0
- package/dist/commands/agents/index.d.ts +1 -1
- package/dist/commands/agents/index.js +4 -2
- package/dist/commands/completion/index.js +2 -4
- package/dist/commands/install/index.js +20 -10
- package/dist/commands/marketplace/index.js +51 -23
- package/dist/commands/marketplace/index.spec.d.ts +1 -0
- package/dist/commands/marketplace/index.spec.js +88 -0
- package/dist/commands/models/index.d.ts +1 -1
- package/dist/commands/models/index.js +4 -2
- package/dist/commands/query/index.d.ts +1 -1
- package/dist/commands/query/index.js +4 -2
- package/dist/commands/status/index.js +7 -2
- package/dist/commands/teams/index.d.ts +1 -1
- package/dist/commands/teams/index.js +4 -2
- package/dist/commands/uninstall/index.js +20 -10
- package/dist/lib/chatClient.d.ts +1 -0
- package/dist/lib/chatClient.js +4 -2
- package/dist/lib/config.d.ts +14 -0
- package/dist/lib/config.js +41 -0
- package/dist/lib/config.spec.js +93 -0
- package/dist/lib/constants.d.ts +3 -0
- package/dist/lib/constants.js +5 -0
- package/dist/lib/executeQuery.js +9 -3
- package/dist/lib/executeQuery.spec.js +4 -1
- package/dist/lib/kubectl.d.ts +1 -0
- package/dist/lib/kubectl.js +62 -0
- package/dist/lib/marketplaceFetcher.d.ts +6 -0
- package/dist/lib/marketplaceFetcher.js +80 -0
- package/dist/lib/marketplaceFetcher.spec.d.ts +1 -0
- package/dist/lib/marketplaceFetcher.spec.js +225 -0
- package/dist/marketplaceServices.d.ts +15 -6
- package/dist/marketplaceServices.js +38 -40
- package/dist/marketplaceServices.spec.d.ts +1 -0
- package/dist/marketplaceServices.spec.js +74 -0
- package/dist/types/marketplace.d.ts +37 -0
- package/dist/types/marketplace.js +1 -0
- package/dist/ui/AgentSelector.d.ts +8 -0
- package/dist/ui/AgentSelector.js +53 -0
- 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/package.json +1 -1
- package/templates/marketplace/marketplace.json.example +59 -0
|
@@ -2,50 +2,48 @@
|
|
|
2
2
|
* Marketplace service definitions for external ARK marketplace resources
|
|
3
3
|
* Repository: https://github.com/mckinsey/agents-at-scale-marketplace
|
|
4
4
|
* Charts are installed from the public OCI registry
|
|
5
|
+
*
|
|
6
|
+
* Supports Anthropic Marketplace JSON format for dynamic enumeration
|
|
5
7
|
*/
|
|
6
|
-
|
|
8
|
+
import { getMarketplaceServicesFromManifest, getMarketplaceAgentsFromManifest, } from './lib/marketplaceFetcher.js';
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
+
* Get all marketplace services, fetching from marketplace.json
|
|
11
|
+
* Returns null if marketplace is unavailable
|
|
10
12
|
*/
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
name: 'phoenix',
|
|
14
|
-
helmReleaseName: 'phoenix',
|
|
15
|
-
description: 'AI/ML observability and evaluation platform with OpenTelemetry integration',
|
|
16
|
-
enabled: true,
|
|
17
|
-
category: 'marketplace',
|
|
18
|
-
namespace: 'phoenix',
|
|
19
|
-
chartPath: `${MARKETPLACE_REGISTRY}/phoenix`,
|
|
20
|
-
installArgs: ['--create-namespace'],
|
|
21
|
-
k8sServiceName: 'phoenix',
|
|
22
|
-
k8sServicePort: 6006,
|
|
23
|
-
k8sDeploymentName: 'phoenix',
|
|
24
|
-
},
|
|
25
|
-
langfuse: {
|
|
26
|
-
name: 'langfuse',
|
|
27
|
-
helmReleaseName: 'langfuse',
|
|
28
|
-
description: 'Open-source LLM observability and analytics platform with session tracking',
|
|
29
|
-
enabled: true,
|
|
30
|
-
category: 'marketplace',
|
|
31
|
-
namespace: 'telemetry',
|
|
32
|
-
chartPath: `${MARKETPLACE_REGISTRY}/langfuse`,
|
|
33
|
-
installArgs: ['--create-namespace'],
|
|
34
|
-
k8sServiceName: 'langfuse',
|
|
35
|
-
k8sServicePort: 3000,
|
|
36
|
-
k8sDeploymentName: 'langfuse-web',
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
export function getMarketplaceService(name) {
|
|
40
|
-
return marketplaceServices[name];
|
|
13
|
+
export async function getAllMarketplaceServices() {
|
|
14
|
+
return await getMarketplaceServicesFromManifest();
|
|
41
15
|
}
|
|
42
|
-
|
|
43
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Get all marketplace agents, fetching from marketplace.json
|
|
18
|
+
* Returns null if marketplace is unavailable
|
|
19
|
+
*/
|
|
20
|
+
export async function getAllMarketplaceAgents() {
|
|
21
|
+
return await getMarketplaceAgentsFromManifest();
|
|
44
22
|
}
|
|
45
|
-
|
|
46
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Get a marketplace item by path (supports both services and agents)
|
|
25
|
+
* Returns null if marketplace is unavailable
|
|
26
|
+
*/
|
|
27
|
+
export async function getMarketplaceItem(path) {
|
|
28
|
+
if (path.startsWith('marketplace/services/')) {
|
|
29
|
+
const name = path.replace(/^marketplace\/services\//, '');
|
|
30
|
+
const services = await getAllMarketplaceServices();
|
|
31
|
+
if (!services) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return services[name];
|
|
35
|
+
}
|
|
36
|
+
if (path.startsWith('marketplace/agents/')) {
|
|
37
|
+
const name = path.replace(/^marketplace\/agents\//, '');
|
|
38
|
+
const agents = await getAllMarketplaceAgents();
|
|
39
|
+
if (!agents) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return agents[name];
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
47
45
|
}
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
export function isMarketplaceService(name) {
|
|
47
|
+
return (name.startsWith('marketplace/services/') ||
|
|
48
|
+
name.startsWith('marketplace/agents/'));
|
|
51
49
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
const mockGetMarketplaceServicesFromManifest = jest.fn();
|
|
3
|
+
const mockGetMarketplaceAgentsFromManifest = jest.fn();
|
|
4
|
+
const mockFetchMarketplaceManifest = jest.fn();
|
|
5
|
+
jest.unstable_mockModule('./lib/marketplaceFetcher.js', () => ({
|
|
6
|
+
getMarketplaceServicesFromManifest: mockGetMarketplaceServicesFromManifest,
|
|
7
|
+
getMarketplaceAgentsFromManifest: mockGetMarketplaceAgentsFromManifest,
|
|
8
|
+
fetchMarketplaceManifest: mockFetchMarketplaceManifest,
|
|
9
|
+
}));
|
|
10
|
+
const { getAllMarketplaceServices, getAllMarketplaceAgents, getMarketplaceItem, } = await import('./marketplaceServices.js');
|
|
11
|
+
describe('marketplaceServices', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks();
|
|
14
|
+
mockGetMarketplaceServicesFromManifest.mockClear();
|
|
15
|
+
});
|
|
16
|
+
describe('getAllMarketplaceServices', () => {
|
|
17
|
+
it('returns manifest services when available', async () => {
|
|
18
|
+
const mockServices = {
|
|
19
|
+
'new-service': {
|
|
20
|
+
name: 'new-service',
|
|
21
|
+
helmReleaseName: 'new-service',
|
|
22
|
+
description: 'New service',
|
|
23
|
+
enabled: true,
|
|
24
|
+
category: 'marketplace',
|
|
25
|
+
namespace: 'new-ns',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
mockGetMarketplaceServicesFromManifest.mockResolvedValue(mockServices);
|
|
29
|
+
const result = await getAllMarketplaceServices();
|
|
30
|
+
expect(result).toEqual(mockServices);
|
|
31
|
+
expect(mockGetMarketplaceServicesFromManifest).toHaveBeenCalled();
|
|
32
|
+
});
|
|
33
|
+
it('returns null when manifest unavailable', async () => {
|
|
34
|
+
mockGetMarketplaceServicesFromManifest.mockResolvedValue(null);
|
|
35
|
+
const result = await getAllMarketplaceServices();
|
|
36
|
+
expect(result).toBeNull();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe('getMarketplaceItem', () => {
|
|
40
|
+
it('returns service by path from manifest', async () => {
|
|
41
|
+
const mockServices = {
|
|
42
|
+
'test-service': {
|
|
43
|
+
name: 'test-service',
|
|
44
|
+
helmReleaseName: 'test-service',
|
|
45
|
+
description: 'Test',
|
|
46
|
+
enabled: true,
|
|
47
|
+
category: 'marketplace',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
mockGetMarketplaceServicesFromManifest.mockResolvedValue(mockServices);
|
|
51
|
+
const result = await getMarketplaceItem('marketplace/services/test-service');
|
|
52
|
+
expect(result).toEqual(mockServices['test-service']);
|
|
53
|
+
});
|
|
54
|
+
it('returns undefined for non-existent service', async () => {
|
|
55
|
+
const mockServices = {
|
|
56
|
+
'test-service': {
|
|
57
|
+
name: 'test-service',
|
|
58
|
+
helmReleaseName: 'test-service',
|
|
59
|
+
description: 'Test',
|
|
60
|
+
enabled: true,
|
|
61
|
+
category: 'marketplace',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
mockGetMarketplaceServicesFromManifest.mockResolvedValue(mockServices);
|
|
65
|
+
const result = await getMarketplaceItem('marketplace/services/non-existent');
|
|
66
|
+
expect(result).toBeUndefined();
|
|
67
|
+
});
|
|
68
|
+
it('returns null when marketplace unavailable', async () => {
|
|
69
|
+
mockGetMarketplaceServicesFromManifest.mockResolvedValue(null);
|
|
70
|
+
const result = await getMarketplaceItem('marketplace/services/phoenix');
|
|
71
|
+
expect(result).toBeNull();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface AnthropicMarketplaceItem {
|
|
2
|
+
name: string;
|
|
3
|
+
displayName?: string;
|
|
4
|
+
description: string;
|
|
5
|
+
type?: 'service' | 'agent';
|
|
6
|
+
version?: string;
|
|
7
|
+
author?: string;
|
|
8
|
+
homepage?: string;
|
|
9
|
+
repository?: string;
|
|
10
|
+
license?: string;
|
|
11
|
+
tags?: string[];
|
|
12
|
+
category?: string;
|
|
13
|
+
icon?: string;
|
|
14
|
+
screenshots?: string[];
|
|
15
|
+
documentation?: string;
|
|
16
|
+
support?: {
|
|
17
|
+
email?: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
};
|
|
20
|
+
metadata?: Record<string, unknown>;
|
|
21
|
+
ark?: {
|
|
22
|
+
chartPath?: string;
|
|
23
|
+
namespace?: string;
|
|
24
|
+
helmReleaseName?: string;
|
|
25
|
+
installArgs?: string[];
|
|
26
|
+
k8sServiceName?: string;
|
|
27
|
+
k8sServicePort?: number;
|
|
28
|
+
k8sPortForwardLocalPort?: number;
|
|
29
|
+
k8sDeploymentName?: string;
|
|
30
|
+
k8sDevDeploymentName?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface AnthropicMarketplaceManifest {
|
|
34
|
+
version: string;
|
|
35
|
+
marketplace: string;
|
|
36
|
+
items: AnthropicMarketplaceItem[];
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Agent, ArkApiClient } from '../lib/arkApiClient.js';
|
|
2
|
+
interface AgentSelectorProps {
|
|
3
|
+
arkApiClient: ArkApiClient;
|
|
4
|
+
onSelect: (agent: Agent) => void;
|
|
5
|
+
onExit: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function AgentSelector({ arkApiClient, onSelect, onExit, }: AgentSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
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 AgentSelector({ arkApiClient, onSelect, onExit, }) {
|
|
5
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
+
const [agents, setAgents] = useState([]);
|
|
7
|
+
const [loading, setLoading] = useState(true);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
arkApiClient
|
|
11
|
+
.getAgents()
|
|
12
|
+
.then((fetchedAgents) => {
|
|
13
|
+
setAgents(fetchedAgents);
|
|
14
|
+
setLoading(false);
|
|
15
|
+
})
|
|
16
|
+
.catch((err) => {
|
|
17
|
+
setError(err.message || 'Failed to fetch agents');
|
|
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 ? agents.length - 1 : prev - 1));
|
|
27
|
+
}
|
|
28
|
+
else if (key.downArrow || input === 'j') {
|
|
29
|
+
setSelectedIndex((prev) => (prev === agents.length - 1 ? 0 : prev + 1));
|
|
30
|
+
}
|
|
31
|
+
else if (key.return) {
|
|
32
|
+
onSelect(agents[selectedIndex]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Handle number keys for quick selection
|
|
36
|
+
const num = parseInt(input, 10);
|
|
37
|
+
if (!isNaN(num) && num >= 1 && num <= agents.length) {
|
|
38
|
+
onSelect(agents[num - 1]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
if (loading) {
|
|
43
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "Loading agents..." }) }));
|
|
44
|
+
}
|
|
45
|
+
if (error) {
|
|
46
|
+
return (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }));
|
|
47
|
+
}
|
|
48
|
+
if (agents.length === 0) {
|
|
49
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "No agents available" }) }));
|
|
50
|
+
}
|
|
51
|
+
const selectedAgent = agents[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 Agent" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Choose an agent to start a conversation with" }) }), _jsx(Box, { flexDirection: "column", children: agents.map((agent, index) => (_jsx(Box, { marginBottom: 0, children: _jsxs(Text, { color: index === selectedIndex ? 'green' : undefined, children: [index === selectedIndex ? '❯ ' : ' ', index + 1, ". ", agent.name] }) }, agent.name))) }), selectedAgent.description && (_jsx(Box, { marginTop: 1, paddingLeft: 2, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: selectedAgent.description }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter to confirm \u00B7 Number to select \u00B7 Esc to exit" }) })] }));
|
|
53
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Model, ArkApiClient } from '../lib/arkApiClient.js';
|
|
2
|
+
interface ModelSelectorProps {
|
|
3
|
+
arkApiClient: ArkApiClient;
|
|
4
|
+
onSelect: (model: Model) => void;
|
|
5
|
+
onExit: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function ModelSelector({ arkApiClient, onSelect, onExit, }: ModelSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
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 ModelSelector({ arkApiClient, onSelect, onExit, }) {
|
|
5
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
+
const [models, setModels] = useState([]);
|
|
7
|
+
const [loading, setLoading] = useState(true);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
arkApiClient
|
|
11
|
+
.getModels()
|
|
12
|
+
.then((fetchedModels) => {
|
|
13
|
+
setModels(fetchedModels);
|
|
14
|
+
setLoading(false);
|
|
15
|
+
})
|
|
16
|
+
.catch((err) => {
|
|
17
|
+
setError(err.message || 'Failed to fetch models');
|
|
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 ? models.length - 1 : prev - 1));
|
|
27
|
+
}
|
|
28
|
+
else if (key.downArrow || input === 'j') {
|
|
29
|
+
setSelectedIndex((prev) => (prev === models.length - 1 ? 0 : prev + 1));
|
|
30
|
+
}
|
|
31
|
+
else if (key.return) {
|
|
32
|
+
onSelect(models[selectedIndex]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Handle number keys for quick selection
|
|
36
|
+
const num = parseInt(input, 10);
|
|
37
|
+
if (!isNaN(num) && num >= 1 && num <= models.length) {
|
|
38
|
+
onSelect(models[num - 1]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
if (loading) {
|
|
43
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "Loading models..." }) }));
|
|
44
|
+
}
|
|
45
|
+
if (error) {
|
|
46
|
+
return (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }));
|
|
47
|
+
}
|
|
48
|
+
if (models.length === 0) {
|
|
49
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "No models available" }) }));
|
|
50
|
+
}
|
|
51
|
+
const selectedModel = models[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 Model" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Choose a model to start a conversation with" }) }), _jsx(Box, { flexDirection: "column", children: models.map((model, index) => (_jsx(Box, { marginBottom: 0, children: _jsxs(Text, { color: index === selectedIndex ? 'green' : undefined, children: [index === selectedIndex ? '❯ ' : ' ', index + 1, ". ", model.name, model.type ? ` (${model.type})` : ''] }) }, model.name))) }), selectedModel && selectedModel.model && (_jsx(Box, { marginTop: 1, paddingLeft: 2, children: _jsxs(Text, { dimColor: true, wrap: "wrap", children: ["Model: ", selectedModel.model] }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter to confirm \u00B7 Number to select \u00B7 Esc to exit" }) })] }));
|
|
53
|
+
}
|
|
@@ -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,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 {};
|
|
@@ -0,0 +1,53 @@
|
|
|
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 ToolSelector({ arkApiClient, onSelect, onExit, }) {
|
|
5
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
6
|
+
const [tools, setTools] = useState([]);
|
|
7
|
+
const [loading, setLoading] = useState(true);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
arkApiClient
|
|
11
|
+
.getTools()
|
|
12
|
+
.then((fetchedTools) => {
|
|
13
|
+
setTools(fetchedTools);
|
|
14
|
+
setLoading(false);
|
|
15
|
+
})
|
|
16
|
+
.catch((err) => {
|
|
17
|
+
setError(err.message || 'Failed to fetch tools');
|
|
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 ? tools.length - 1 : prev - 1));
|
|
27
|
+
}
|
|
28
|
+
else if (key.downArrow || input === 'j') {
|
|
29
|
+
setSelectedIndex((prev) => (prev === tools.length - 1 ? 0 : prev + 1));
|
|
30
|
+
}
|
|
31
|
+
else if (key.return) {
|
|
32
|
+
onSelect(tools[selectedIndex]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Handle number keys for quick selection
|
|
36
|
+
const num = parseInt(input, 10);
|
|
37
|
+
if (!isNaN(num) && num >= 1 && num <= tools.length) {
|
|
38
|
+
onSelect(tools[num - 1]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
if (loading) {
|
|
43
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "Loading tools..." }) }));
|
|
44
|
+
}
|
|
45
|
+
if (error) {
|
|
46
|
+
return (_jsx(Box, { children: _jsxs(Text, { color: "red", children: ["Error: ", error] }) }));
|
|
47
|
+
}
|
|
48
|
+
if (tools.length === 0) {
|
|
49
|
+
return (_jsx(Box, { children: _jsx(Text, { children: "No tools available" }) }));
|
|
50
|
+
}
|
|
51
|
+
const selectedTool = tools[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 Tool" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { dimColor: true, children: "Choose a tool to start a conversation with" }) }), _jsx(Box, { flexDirection: "column", children: tools.map((tool, index) => (_jsx(Box, { marginBottom: 0, children: _jsxs(Text, { color: index === selectedIndex ? 'green' : undefined, children: [index === selectedIndex ? '❯ ' : ' ', index + 1, ". ", tool.name] }) }, tool.name))) }), selectedTool && selectedTool.description && (_jsx(Box, { marginTop: 1, paddingLeft: 2, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: selectedTool.description }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter to confirm \u00B7 Number to select \u00B7 Esc to exit" }) })] }));
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"marketplace": "ARK Marketplace",
|
|
4
|
+
"items": [
|
|
5
|
+
{
|
|
6
|
+
"name": "phoenix",
|
|
7
|
+
"displayName": "Phoenix",
|
|
8
|
+
"description": "AI/ML observability and evaluation platform with OpenTelemetry integration",
|
|
9
|
+
"version": "0.1.5",
|
|
10
|
+
"author": "ARK Marketplace",
|
|
11
|
+
"homepage": "https://github.com/mckinsey/agents-at-scale-marketplace",
|
|
12
|
+
"repository": "https://github.com/mckinsey/agents-at-scale-marketplace",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"tags": ["observability", "evaluation", "telemetry", "monitoring"],
|
|
15
|
+
"category": "observability",
|
|
16
|
+
"icon": "https://example.com/phoenix-icon.png",
|
|
17
|
+
"documentation": "https://mckinsey.github.io/agents-at-scale-marketplace/services/phoenix/",
|
|
18
|
+
"support": {
|
|
19
|
+
"url": "https://github.com/mckinsey/agents-at-scale-marketplace/issues"
|
|
20
|
+
},
|
|
21
|
+
"ark": {
|
|
22
|
+
"chartPath": "oci://ghcr.io/mckinsey/agents-at-scale-marketplace/charts/phoenix",
|
|
23
|
+
"namespace": "phoenix",
|
|
24
|
+
"helmReleaseName": "phoenix",
|
|
25
|
+
"installArgs": ["--create-namespace"],
|
|
26
|
+
"k8sServiceName": "phoenix",
|
|
27
|
+
"k8sServicePort": 6006,
|
|
28
|
+
"k8sDeploymentName": "phoenix"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "langfuse",
|
|
33
|
+
"displayName": "Langfuse",
|
|
34
|
+
"description": "Open-source LLM observability and analytics platform with session tracking",
|
|
35
|
+
"version": "0.1.4",
|
|
36
|
+
"author": "ARK Marketplace",
|
|
37
|
+
"homepage": "https://github.com/mckinsey/agents-at-scale-marketplace",
|
|
38
|
+
"repository": "https://github.com/mckinsey/agents-at-scale-marketplace",
|
|
39
|
+
"license": "Apache-2.0",
|
|
40
|
+
"tags": ["observability", "analytics", "llm", "tracking"],
|
|
41
|
+
"category": "observability",
|
|
42
|
+
"icon": "https://example.com/langfuse-icon.png",
|
|
43
|
+
"documentation": "https://mckinsey.github.io/agents-at-scale-marketplace/services/langfuse/",
|
|
44
|
+
"support": {
|
|
45
|
+
"url": "https://github.com/mckinsey/agents-at-scale-marketplace/issues"
|
|
46
|
+
},
|
|
47
|
+
"ark": {
|
|
48
|
+
"chartPath": "oci://ghcr.io/mckinsey/agents-at-scale-marketplace/charts/langfuse",
|
|
49
|
+
"namespace": "telemetry",
|
|
50
|
+
"helmReleaseName": "langfuse",
|
|
51
|
+
"installArgs": ["--create-namespace"],
|
|
52
|
+
"k8sServiceName": "langfuse",
|
|
53
|
+
"k8sServicePort": 3000,
|
|
54
|
+
"k8sDeploymentName": "langfuse-web"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
|