@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.
Files changed (49) hide show
  1. package/README.md +2 -0
  2. package/dist/arkServices.js +13 -1
  3. package/dist/arkServices.spec.js +6 -0
  4. package/dist/commands/agents/index.d.ts +1 -1
  5. package/dist/commands/agents/index.js +4 -2
  6. package/dist/commands/completion/index.js +2 -4
  7. package/dist/commands/install/index.js +20 -10
  8. package/dist/commands/marketplace/index.js +51 -23
  9. package/dist/commands/marketplace/index.spec.d.ts +1 -0
  10. package/dist/commands/marketplace/index.spec.js +88 -0
  11. package/dist/commands/models/index.d.ts +1 -1
  12. package/dist/commands/models/index.js +4 -2
  13. package/dist/commands/query/index.d.ts +1 -1
  14. package/dist/commands/query/index.js +4 -2
  15. package/dist/commands/status/index.js +7 -2
  16. package/dist/commands/teams/index.d.ts +1 -1
  17. package/dist/commands/teams/index.js +4 -2
  18. package/dist/commands/uninstall/index.js +20 -10
  19. package/dist/lib/chatClient.d.ts +1 -0
  20. package/dist/lib/chatClient.js +4 -2
  21. package/dist/lib/config.d.ts +14 -0
  22. package/dist/lib/config.js +41 -0
  23. package/dist/lib/config.spec.js +93 -0
  24. package/dist/lib/constants.d.ts +3 -0
  25. package/dist/lib/constants.js +5 -0
  26. package/dist/lib/executeQuery.js +9 -3
  27. package/dist/lib/executeQuery.spec.js +4 -1
  28. package/dist/lib/kubectl.d.ts +1 -0
  29. package/dist/lib/kubectl.js +62 -0
  30. package/dist/lib/marketplaceFetcher.d.ts +6 -0
  31. package/dist/lib/marketplaceFetcher.js +80 -0
  32. package/dist/lib/marketplaceFetcher.spec.d.ts +1 -0
  33. package/dist/lib/marketplaceFetcher.spec.js +225 -0
  34. package/dist/marketplaceServices.d.ts +15 -6
  35. package/dist/marketplaceServices.js +38 -40
  36. package/dist/marketplaceServices.spec.d.ts +1 -0
  37. package/dist/marketplaceServices.spec.js +74 -0
  38. package/dist/types/marketplace.d.ts +37 -0
  39. package/dist/types/marketplace.js +1 -0
  40. package/dist/ui/AgentSelector.d.ts +8 -0
  41. package/dist/ui/AgentSelector.js +53 -0
  42. package/dist/ui/ModelSelector.d.ts +8 -0
  43. package/dist/ui/ModelSelector.js +53 -0
  44. package/dist/ui/TeamSelector.d.ts +8 -0
  45. package/dist/ui/TeamSelector.js +55 -0
  46. package/dist/ui/ToolSelector.d.ts +8 -0
  47. package/dist/ui/ToolSelector.js +53 -0
  48. package/package.json +1 -1
  49. package/templates/marketplace/marketplace.json.example +59 -0
package/README.md CHANGED
@@ -76,3 +76,5 @@ services:
76
76
  ```
77
77
 
78
78
  Replace `YOUR_USERNAME` and `YOUR_PASSWORD` with your JFrog credentials.
79
+
80
+ See [.arkrc.yaml.sample](.arkrc.yaml.sample) for a complete example with all available options.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Centralized ARK service definitions used by both install and status commands
3
3
  */
4
- import { loadConfig } from './lib/config.js';
4
+ import { loadConfig, getMarketplaceRegistry } from './lib/config.js';
5
5
  const REGISTRY_BASE = 'oci://ghcr.io/mckinsey/agents-at-scale-ark/charts';
6
6
  /**
7
7
  * Dependencies that should be installed before ARK services
@@ -153,6 +153,18 @@ const defaultArkServices = {
153
153
  chartPath: `${REGISTRY_BASE}/localhost-gateway`,
154
154
  installArgs: [],
155
155
  },
156
+ 'noah': {
157
+ name: 'noah',
158
+ helmReleaseName: 'noah',
159
+ description: 'Runtime administration agent with cluster privileges',
160
+ enabled: true,
161
+ category: 'service',
162
+ chartPath: `${getMarketplaceRegistry()}/noah`,
163
+ installArgs: [],
164
+ k8sServiceName: 'noah-mcp',
165
+ k8sServicePort: 8639,
166
+ k8sDeploymentName: 'noah-mcp',
167
+ },
156
168
  };
157
169
  function applyConfigOverrides(defaults) {
158
170
  const config = loadConfig();
@@ -1,12 +1,18 @@
1
1
  import { jest } from '@jest/globals';
2
2
  const mockLoadConfig = jest.fn();
3
+ const mockGetMarketplaceRegistry = jest.fn();
3
4
  jest.unstable_mockModule('./lib/config.js', () => ({
4
5
  loadConfig: mockLoadConfig,
6
+ getMarketplaceRegistry: mockGetMarketplaceRegistry,
5
7
  }));
8
+ mockLoadConfig.mockReturnValue({});
9
+ mockGetMarketplaceRegistry.mockReturnValue('oci://test-registry/charts');
6
10
  const { arkDependencies, arkServices: originalArkServices, getInstallableServices, } = await import('./arkServices.js');
7
11
  describe('arkServices', () => {
8
12
  beforeEach(() => {
9
13
  jest.clearAllMocks();
14
+ mockLoadConfig.mockReturnValue({});
15
+ mockGetMarketplaceRegistry.mockReturnValue('oci://test-registry/charts');
10
16
  });
11
17
  it('exports arkDependencies with expected structure', () => {
12
18
  expect(arkDependencies).toBeDefined();
@@ -1,3 +1,3 @@
1
1
  import { Command } from 'commander';
2
2
  import type { ArkConfig } from '../../lib/config.js';
3
- export declare function createAgentsCommand(_: ArkConfig): Command;
3
+ export declare function createAgentsCommand(config: ArkConfig): Command;
@@ -30,7 +30,7 @@ async function listAgents(options) {
30
30
  process.exit(1);
31
31
  }
32
32
  }
33
- export function createAgentsCommand(_) {
33
+ export function createAgentsCommand(config) {
34
34
  const agentsCommand = new Command('agents');
35
35
  agentsCommand
36
36
  .description('list available agents')
@@ -54,11 +54,13 @@ export function createAgentsCommand(_) {
54
54
  .description('Query an agent')
55
55
  .argument('<name>', 'Agent name')
56
56
  .argument('<message>', 'Message to send')
57
- .action(async (name, message) => {
57
+ .option('--timeout <timeout>', 'Query timeout (e.g., 30s, 5m, 1h)')
58
+ .action(async (name, message, options) => {
58
59
  await executeQuery({
59
60
  targetType: 'agent',
60
61
  targetName: name,
61
62
  message,
63
+ timeout: options.timeout || config.queryTimeout,
62
64
  });
63
65
  });
64
66
  return agentsCommand;
@@ -85,14 +85,12 @@ _ark_completion() {
85
85
  return 0
86
86
  ;;
87
87
  install)
88
- # Suggest marketplace services with marketplace/services/ prefix
89
- opts="marketplace/services/phoenix marketplace/services/langfuse"
88
+ opts="marketplace/services/phoenix marketplace/services/langfuse marketplace/agents/noah"
90
89
  COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
91
90
  return 0
92
91
  ;;
93
92
  uninstall)
94
- # Suggest marketplace services with marketplace/services/ prefix
95
- opts="marketplace/services/phoenix marketplace/services/langfuse"
93
+ opts="marketplace/services/phoenix marketplace/services/langfuse marketplace/agents/noah"
96
94
  COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) )
97
95
  return 0
98
96
  ;;
@@ -5,7 +5,7 @@ import inquirer from 'inquirer';
5
5
  import { showNoClusterError } from '../../lib/startup.js';
6
6
  import output from '../../lib/output.js';
7
7
  import { getInstallableServices, arkDependencies, arkServices, } from '../../arkServices.js';
8
- import { isMarketplaceService, extractMarketplaceServiceName, getMarketplaceService, getAllMarketplaceServices, } from '../../marketplaceServices.js';
8
+ import { isMarketplaceService, getMarketplaceItem, getAllMarketplaceServices, getAllMarketplaceAgents, } from '../../marketplaceServices.js';
9
9
  import { printNextSteps } from '../../lib/nextSteps.js';
10
10
  import ora from 'ora';
11
11
  import { waitForServicesReady, } from '../../lib/waitForReady.js';
@@ -42,20 +42,30 @@ export async function installArk(config, serviceName, options = {}) {
42
42
  console.log(); // Add blank line after cluster info
43
43
  // If a specific service is requested, install only that service
44
44
  if (serviceName) {
45
- // Check if it's a marketplace service
45
+ // Check if it's a marketplace item
46
46
  if (isMarketplaceService(serviceName)) {
47
- const marketplaceServiceName = extractMarketplaceServiceName(serviceName);
48
- const service = getMarketplaceService(marketplaceServiceName);
47
+ const service = await getMarketplaceItem(serviceName);
49
48
  if (!service) {
50
- output.error(`marketplace service '${marketplaceServiceName}' not found`);
51
- output.info('available marketplace services:');
52
- const marketplaceServices = getAllMarketplaceServices();
53
- for (const serviceName of Object.keys(marketplaceServices)) {
54
- output.info(` marketplace/services/${serviceName}`);
49
+ output.error(`marketplace item '${serviceName}' not found`);
50
+ output.info('available marketplace items:');
51
+ const marketplaceServices = await getAllMarketplaceServices();
52
+ if (marketplaceServices) {
53
+ for (const name of Object.keys(marketplaceServices)) {
54
+ output.info(` marketplace/services/${name}`);
55
+ }
56
+ }
57
+ const marketplaceAgents = await getAllMarketplaceAgents();
58
+ if (marketplaceAgents) {
59
+ for (const name of Object.keys(marketplaceAgents)) {
60
+ output.info(` marketplace/agents/${name}`);
61
+ }
62
+ }
63
+ if (!marketplaceServices && !marketplaceAgents) {
64
+ output.warning('Marketplace unavailable');
55
65
  }
56
66
  process.exit(1);
57
67
  }
58
- output.info(`installing marketplace service ${service.name}...`);
68
+ output.info(`installing marketplace item ${service.name}...`);
59
69
  try {
60
70
  await installService(service, options.verbose);
61
71
  output.success(`${service.name} installed successfully`);
@@ -1,7 +1,11 @@
1
1
  import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
- import { getAllMarketplaceServices } from '../../marketplaceServices.js';
3
+ import { getMarketplaceRepoUrl, getMarketplaceRegistry, } from '../../lib/config.js';
4
+ import { getAllMarketplaceServices, getAllMarketplaceAgents, } from '../../marketplaceServices.js';
5
+ import { fetchMarketplaceManifest } from '../../lib/marketplaceFetcher.js';
4
6
  function createMarketplaceCommand(_config) {
7
+ const repoUrl = getMarketplaceRepoUrl();
8
+ const registry = getMarketplaceRegistry();
5
9
  const marketplace = new Command('marketplace');
6
10
  marketplace
7
11
  .description('Manage marketplace services')
@@ -9,39 +13,63 @@ function createMarketplaceCommand(_config) {
9
13
  ${chalk.blue('🏪 ARK Marketplace')}
10
14
  Install community-contributed services from the ARK Marketplace.
11
15
 
12
- Repository: ${chalk.cyan('https://github.com/mckinsey/agents-at-scale-marketplace')}
13
- Registry: ${chalk.cyan('ghcr.io/mckinsey/agents-at-scale-marketplace/charts')}
16
+ Repository: ${chalk.cyan(repoUrl)}
17
+ Registry: ${chalk.cyan(registry.replace('oci://', ''))}
14
18
  `)
15
19
  .addHelpText('after', `
16
20
  ${chalk.cyan('Examples:')}
17
- ${chalk.yellow('ark marketplace list')} # List available services
18
- ${chalk.yellow('ark install marketplace/services/phoenix')} # Install Phoenix
21
+ ${chalk.yellow('ark marketplace list')} # List available services and agents
22
+ ${chalk.yellow('ark install marketplace/services/phoenix')} # Install Phoenix service
23
+ ${chalk.yellow('ark install marketplace/agents/noah')} # Install Noah agent
19
24
  ${chalk.yellow('ark uninstall marketplace/services/phoenix')} # Uninstall Phoenix
20
-
21
- ${chalk.cyan('Available Services:')}
22
- • phoenix - AI/ML observability and evaluation platform
23
- • langfuse - Open-source LLM observability and analytics
24
25
  `);
25
26
  // List command
26
27
  const list = new Command('list');
27
28
  list
28
29
  .alias('ls')
29
- .description('List available marketplace services')
30
- .action(() => {
31
- const services = getAllMarketplaceServices();
32
- console.log(chalk.blue('\n🏪 ARK Marketplace Services\n'));
33
- console.log(chalk.gray('Install with: ark install marketplace/services/<service-name>\n'));
34
- for (const [key, service] of Object.entries(services)) {
35
- const icon = '📦';
36
- const serviceName = `marketplace/services/${key.padEnd(12)}`;
37
- const serviceDesc = service.description;
38
- console.log(`${icon} ${chalk.green(serviceName)} ${chalk.gray(serviceDesc)}`);
39
- const namespaceInfo = `namespace: ${service.namespace || 'default'}`;
40
- console.log(` ${chalk.dim(namespaceInfo)}`);
30
+ .description('List available marketplace services and agents')
31
+ .action(async () => {
32
+ const services = await getAllMarketplaceServices();
33
+ const agents = await getAllMarketplaceAgents();
34
+ const manifest = await fetchMarketplaceManifest();
35
+ console.log(chalk.blue('\n🏪 ARK Marketplace\n'));
36
+ if (!manifest) {
37
+ console.log(chalk.yellow('⚠️ Marketplace unavailable\n'));
38
+ console.log(chalk.gray('Could not fetch marketplace.json from repository.\n'));
39
+ console.log(chalk.cyan(`Repository: ${repoUrl}`));
40
+ console.log(chalk.cyan(`Registry: ${registry}`));
41
41
  console.log();
42
+ return;
42
43
  }
43
- console.log(chalk.cyan('Repository: https://github.com/mckinsey/agents-at-scale-marketplace'));
44
- console.log(chalk.cyan('Registry: oci://ghcr.io/mckinsey/agents-at-scale-marketplace/charts'));
44
+ console.log(chalk.dim(`Using marketplace.json (version: ${manifest.version})\n`));
45
+ if (services && Object.keys(services).length > 0) {
46
+ console.log(chalk.bold('Services:'));
47
+ console.log(chalk.gray('Install with: ark install marketplace/services/<name>\n'));
48
+ for (const [key, service] of Object.entries(services)) {
49
+ const icon = '📦';
50
+ const serviceName = `marketplace/services/${key.padEnd(12)}`;
51
+ const serviceDesc = service.description;
52
+ console.log(`${icon} ${chalk.green(serviceName)} ${chalk.gray(serviceDesc)}`);
53
+ const namespaceInfo = `namespace: ${service.namespace || 'default'}`;
54
+ console.log(` ${chalk.dim(namespaceInfo)}`);
55
+ console.log();
56
+ }
57
+ }
58
+ if (agents && Object.keys(agents).length > 0) {
59
+ console.log(chalk.bold('Agents:'));
60
+ console.log(chalk.gray('Install with: ark install marketplace/agents/<name>\n'));
61
+ for (const [key, agent] of Object.entries(agents)) {
62
+ const icon = '🤖';
63
+ const agentName = `marketplace/agents/${key.padEnd(12)}`;
64
+ const agentDesc = agent.description;
65
+ console.log(`${icon} ${chalk.green(agentName)} ${chalk.gray(agentDesc)}`);
66
+ const namespaceInfo = `namespace: ${agent.namespace || 'default'}`;
67
+ console.log(` ${chalk.dim(namespaceInfo)}`);
68
+ console.log();
69
+ }
70
+ }
71
+ console.log(chalk.cyan(`Repository: ${repoUrl}`));
72
+ console.log(chalk.cyan(`Registry: ${registry}`));
45
73
  console.log();
46
74
  });
47
75
  marketplace.addCommand(list);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,88 @@
1
+ import { jest } from '@jest/globals';
2
+ import { Command } from 'commander';
3
+ const mockGetAllMarketplaceServices = jest.fn();
4
+ const mockGetAllMarketplaceAgents = jest.fn();
5
+ const mockFetchMarketplaceManifest = jest.fn();
6
+ const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => { });
7
+ jest.unstable_mockModule('../../marketplaceServices.js', () => ({
8
+ getAllMarketplaceServices: mockGetAllMarketplaceServices,
9
+ getAllMarketplaceAgents: mockGetAllMarketplaceAgents,
10
+ }));
11
+ jest.unstable_mockModule('../../lib/marketplaceFetcher.js', () => ({
12
+ fetchMarketplaceManifest: mockFetchMarketplaceManifest,
13
+ }));
14
+ const { createMarketplaceCommand } = await import('./index.js');
15
+ describe('marketplace command', () => {
16
+ beforeEach(() => {
17
+ jest.clearAllMocks();
18
+ });
19
+ it('creates marketplace command with correct structure', () => {
20
+ const command = createMarketplaceCommand({});
21
+ expect(command).toBeInstanceOf(Command);
22
+ expect(command.name()).toBe('marketplace');
23
+ });
24
+ it('lists services and agents from manifest', async () => {
25
+ const mockServices = {
26
+ 'test-service': {
27
+ name: 'test-service',
28
+ helmReleaseName: 'test-service',
29
+ description: 'Test service description',
30
+ enabled: true,
31
+ category: 'marketplace',
32
+ namespace: 'test-ns',
33
+ },
34
+ };
35
+ const mockAgents = {
36
+ 'test-agent': {
37
+ name: 'test-agent',
38
+ helmReleaseName: 'test-agent',
39
+ description: 'Test agent description',
40
+ enabled: true,
41
+ category: 'marketplace',
42
+ namespace: 'test-ns',
43
+ },
44
+ };
45
+ const mockManifest = {
46
+ version: '1.0.0',
47
+ marketplace: 'ARK Marketplace',
48
+ items: [
49
+ {
50
+ name: 'test-service',
51
+ description: 'Test service',
52
+ type: 'service',
53
+ ark: {
54
+ chartPath: 'oci://registry/test-service',
55
+ namespace: 'test',
56
+ },
57
+ },
58
+ {
59
+ name: 'test-agent',
60
+ description: 'Test agent',
61
+ type: 'agent',
62
+ ark: {
63
+ chartPath: 'oci://registry/test-agent',
64
+ namespace: 'test',
65
+ },
66
+ },
67
+ ],
68
+ };
69
+ mockGetAllMarketplaceServices.mockResolvedValue(mockServices);
70
+ mockGetAllMarketplaceAgents.mockResolvedValue(mockAgents);
71
+ mockFetchMarketplaceManifest.mockResolvedValue(mockManifest);
72
+ const command = createMarketplaceCommand({});
73
+ await command.parseAsync(['node', 'test', 'list']);
74
+ expect(mockGetAllMarketplaceServices).toHaveBeenCalled();
75
+ expect(mockGetAllMarketplaceAgents).toHaveBeenCalled();
76
+ expect(mockConsoleLog).toHaveBeenCalled();
77
+ });
78
+ it('shows unavailable message when marketplace unavailable', async () => {
79
+ mockGetAllMarketplaceServices.mockResolvedValue(null);
80
+ mockGetAllMarketplaceAgents.mockResolvedValue(null);
81
+ mockFetchMarketplaceManifest.mockResolvedValue(null);
82
+ const command = createMarketplaceCommand({});
83
+ await command.parseAsync(['node', 'test', 'list']);
84
+ expect(mockConsoleLog).toHaveBeenCalled();
85
+ const logCalls = mockConsoleLog.mock.calls.map((c) => c[0]).join(' ');
86
+ expect(logCalls).toContain('unavailable');
87
+ });
88
+ });
@@ -1,3 +1,3 @@
1
1
  import { Command } from 'commander';
2
2
  import type { ArkConfig } from '../../lib/config.js';
3
- export declare function createModelsCommand(_: ArkConfig): Command;
3
+ export declare function createModelsCommand(config: ArkConfig): Command;
@@ -31,7 +31,7 @@ async function listModels(options) {
31
31
  process.exit(1);
32
32
  }
33
33
  }
34
- export function createModelsCommand(_) {
34
+ export function createModelsCommand(config) {
35
35
  const modelsCommand = new Command('models');
36
36
  modelsCommand
37
37
  .description('List available models')
@@ -69,11 +69,13 @@ export function createModelsCommand(_) {
69
69
  .description('Query a model')
70
70
  .argument('<name>', 'Model name (e.g., default)')
71
71
  .argument('<message>', 'Message to send')
72
- .action(async (name, message) => {
72
+ .option('--timeout <timeout>', 'Query timeout (e.g., 30s, 5m, 1h)')
73
+ .action(async (name, message, options) => {
73
74
  await executeQuery({
74
75
  targetType: 'model',
75
76
  targetName: name,
76
77
  message,
78
+ timeout: options.timeout || config.queryTimeout,
77
79
  });
78
80
  });
79
81
  modelsCommand.addCommand(queryCommand);
@@ -1,3 +1,3 @@
1
1
  import { Command } from 'commander';
2
2
  import type { ArkConfig } from '../../lib/config.js';
3
- export declare function createQueryCommand(_: ArkConfig): Command;
3
+ export declare function createQueryCommand(config: ArkConfig): Command;
@@ -2,13 +2,14 @@ import { Command } from 'commander';
2
2
  import chalk from 'chalk';
3
3
  import { executeQuery, parseTarget } from '../../lib/executeQuery.js';
4
4
  import { ExitCodes } from '../../lib/errors.js';
5
- export function createQueryCommand(_) {
5
+ export function createQueryCommand(config) {
6
6
  const queryCommand = new Command('query');
7
7
  queryCommand
8
8
  .description('Execute a single query against a model or agent')
9
9
  .argument('<target>', 'Query target (e.g., model/default, agent/my-agent)')
10
10
  .argument('<message>', 'Message to send')
11
- .option('-o, --output <format>', 'Output format: yaml, json, or name (prints only resource name)')
11
+ .option('-o, --output <format>', 'Output format: yaml, json, name or events (shows structured event data)')
12
+ .option('--timeout <timeout>', 'Query timeout (e.g., 30s, 5m, 1h)')
12
13
  .option('--session-id <sessionId>', 'Session ID to associate with the query for conversation continuity')
13
14
  .action(async (target, message, options) => {
14
15
  const parsed = parseTarget(target);
@@ -21,6 +22,7 @@ export function createQueryCommand(_) {
21
22
  targetName: parsed.name,
22
23
  message,
23
24
  outputFormat: options.output,
25
+ timeout: options.timeout || config.queryTimeout,
24
26
  sessionId: options.sessionId,
25
27
  });
26
28
  });
@@ -327,7 +327,12 @@ export function createStatusCommand() {
327
327
  statusCommand
328
328
  .description('Check ARK system status')
329
329
  .argument('[services...]', 'specific services to check (optional)')
330
- .option('--wait-for-ready <timeout>', 'wait for services to be ready (e.g., 30s, 2m, 1h)')
331
- .action((services, options) => checkStatus(services, options));
330
+ .option('--wait-for-ready [timeout]', 'wait for services to be ready, e.g, 30s, 2m, 1h (default: 30m)')
331
+ .action((services, options) => {
332
+ if (options.waitForReady === true) {
333
+ options.waitForReady = '30m';
334
+ }
335
+ checkStatus(services, options);
336
+ });
332
337
  return statusCommand;
333
338
  }
@@ -1,3 +1,3 @@
1
1
  import { Command } from 'commander';
2
2
  import type { ArkConfig } from '../../lib/config.js';
3
- export declare function createTeamsCommand(_: ArkConfig): Command;
3
+ export declare function createTeamsCommand(config: ArkConfig): Command;
@@ -29,7 +29,7 @@ async function listTeams(options) {
29
29
  process.exit(1);
30
30
  }
31
31
  }
32
- export function createTeamsCommand(_) {
32
+ export function createTeamsCommand(config) {
33
33
  const teamsCommand = new Command('teams');
34
34
  teamsCommand
35
35
  .description('List available teams')
@@ -52,11 +52,13 @@ export function createTeamsCommand(_) {
52
52
  .description('Query a team')
53
53
  .argument('<name>', 'Team name')
54
54
  .argument('<message>', 'Message to send')
55
- .action(async (name, message) => {
55
+ .option('--timeout <timeout>', 'Query timeout (e.g., 30s, 5m, 1h)')
56
+ .action(async (name, message, options) => {
56
57
  await executeQuery({
57
58
  targetType: 'team',
58
59
  targetName: name,
59
60
  message,
61
+ timeout: options.timeout || config.queryTimeout,
60
62
  });
61
63
  });
62
64
  teamsCommand.addCommand(queryCommand);
@@ -5,7 +5,7 @@ import inquirer from 'inquirer';
5
5
  import { showNoClusterError } from '../../lib/startup.js';
6
6
  import output from '../../lib/output.js';
7
7
  import { getInstallableServices } from '../../arkServices.js';
8
- import { isMarketplaceService, extractMarketplaceServiceName, getMarketplaceService, getAllMarketplaceServices, } from '../../marketplaceServices.js';
8
+ import { isMarketplaceService, getMarketplaceItem, getAllMarketplaceServices, getAllMarketplaceAgents, } from '../../marketplaceServices.js';
9
9
  async function uninstallService(service, verbose = false) {
10
10
  const helmArgs = ['uninstall', service.helmReleaseName, '--ignore-not-found'];
11
11
  // Only add namespace flag if service has explicit namespace
@@ -26,20 +26,30 @@ async function uninstallArk(config, serviceName, options = {}) {
26
26
  console.log(); // Add blank line after cluster info
27
27
  // If a specific service is requested, uninstall only that service
28
28
  if (serviceName) {
29
- // Check if it's a marketplace service
29
+ // Check if it's a marketplace item
30
30
  if (isMarketplaceService(serviceName)) {
31
- const marketplaceServiceName = extractMarketplaceServiceName(serviceName);
32
- const service = getMarketplaceService(marketplaceServiceName);
31
+ const service = await getMarketplaceItem(serviceName);
33
32
  if (!service) {
34
- output.error(`marketplace service '${marketplaceServiceName}' not found`);
35
- output.info('available marketplace services:');
36
- const marketplaceServices = getAllMarketplaceServices();
37
- for (const serviceName of Object.keys(marketplaceServices)) {
38
- output.info(` marketplace/services/${serviceName}`);
33
+ output.error(`marketplace item '${serviceName}' not found`);
34
+ output.info('available marketplace items:');
35
+ const marketplaceServices = await getAllMarketplaceServices();
36
+ if (marketplaceServices) {
37
+ for (const name of Object.keys(marketplaceServices)) {
38
+ output.info(` marketplace/services/${name}`);
39
+ }
40
+ }
41
+ const marketplaceAgents = await getAllMarketplaceAgents();
42
+ if (marketplaceAgents) {
43
+ for (const name of Object.keys(marketplaceAgents)) {
44
+ output.info(` marketplace/agents/${name}`);
45
+ }
46
+ }
47
+ if (!marketplaceServices && !marketplaceAgents) {
48
+ output.warning('Marketplace unavailable');
39
49
  }
40
50
  process.exit(1);
41
51
  }
42
- output.info(`uninstalling marketplace service ${service.name}...`);
52
+ output.info(`uninstalling marketplace item ${service.name}...`);
43
53
  try {
44
54
  await uninstallService(service, options.verbose);
45
55
  output.success(`${service.name} uninstalled successfully`);
@@ -6,6 +6,7 @@ export interface ChatConfig {
6
6
  currentTarget?: QueryTarget;
7
7
  a2aContextId?: string;
8
8
  sessionId?: string;
9
+ queryTimeout?: string;
9
10
  }
10
11
  export interface ToolCall {
11
12
  id: string;
@@ -17,12 +17,14 @@ export class ChatClient {
17
17
  signal: signal,
18
18
  };
19
19
  // Build metadata object - only add if we have something to include
20
- if (config.sessionId || config.a2aContextId) {
20
+ if (config.sessionId || config.a2aContextId || config.queryTimeout) {
21
21
  params.metadata = {};
22
- // Add sessionId directly to metadata (goes to spec, not annotations)
23
22
  if (config.sessionId) {
24
23
  params.metadata.sessionId = config.sessionId;
25
24
  }
25
+ if (config.queryTimeout) {
26
+ params.metadata.timeout = config.queryTimeout;
27
+ }
26
28
  // Add A2A context ID to queryAnnotations (goes to annotations)
27
29
  if (config.a2aContextId) {
28
30
  const queryAnnotations = {
@@ -4,11 +4,17 @@ export interface ChatConfig {
4
4
  streaming?: boolean;
5
5
  outputFormat?: 'text' | 'markdown';
6
6
  }
7
+ export interface MarketplaceConfig {
8
+ repoUrl?: string;
9
+ registry?: string;
10
+ }
7
11
  export interface ArkConfig {
8
12
  chat?: ChatConfig;
13
+ marketplace?: MarketplaceConfig;
9
14
  services?: {
10
15
  [serviceName: string]: Partial<ArkService>;
11
16
  };
17
+ queryTimeout?: string;
12
18
  clusterInfo?: ClusterInfo;
13
19
  }
14
20
  /**
@@ -30,3 +36,11 @@ export declare function getConfigPaths(): {
30
36
  * Format config as YAML for display
31
37
  */
32
38
  export declare function formatConfig(config: ArkConfig): string;
39
+ /**
40
+ * Get marketplace repository URL from config
41
+ */
42
+ export declare function getMarketplaceRepoUrl(): string;
43
+ /**
44
+ * Get marketplace registry from config
45
+ */
46
+ export declare function getMarketplaceRegistry(): string;
@@ -16,6 +16,10 @@ export function loadConfig() {
16
16
  streaming: true,
17
17
  outputFormat: 'text',
18
18
  },
19
+ marketplace: {
20
+ repoUrl: 'https://github.com/mckinsey/agents-at-scale-marketplace',
21
+ registry: 'oci://ghcr.io/mckinsey/agents-at-scale-marketplace/charts',
22
+ },
19
23
  };
20
24
  // Load user config from home directory
21
25
  const userConfigPath = path.join(os.homedir(), '.arkrc.yaml');
@@ -55,6 +59,17 @@ export function loadConfig() {
55
59
  config.chat.outputFormat = format;
56
60
  }
57
61
  }
62
+ if (process.env.ARK_QUERY_TIMEOUT !== undefined) {
63
+ config.queryTimeout = process.env.ARK_QUERY_TIMEOUT;
64
+ }
65
+ if (process.env.ARK_MARKETPLACE_REPO_URL !== undefined) {
66
+ config.marketplace = config.marketplace || {};
67
+ config.marketplace.repoUrl = process.env.ARK_MARKETPLACE_REPO_URL;
68
+ }
69
+ if (process.env.ARK_MARKETPLACE_REGISTRY !== undefined) {
70
+ config.marketplace = config.marketplace || {};
71
+ config.marketplace.registry = process.env.ARK_MARKETPLACE_REGISTRY;
72
+ }
58
73
  return config;
59
74
  }
60
75
  /**
@@ -70,6 +85,15 @@ function mergeConfig(target, source) {
70
85
  target.chat.outputFormat = source.chat.outputFormat;
71
86
  }
72
87
  }
88
+ if (source.marketplace) {
89
+ target.marketplace = target.marketplace || {};
90
+ if (source.marketplace.repoUrl !== undefined) {
91
+ target.marketplace.repoUrl = source.marketplace.repoUrl;
92
+ }
93
+ if (source.marketplace.registry !== undefined) {
94
+ target.marketplace.registry = source.marketplace.registry;
95
+ }
96
+ }
73
97
  if (source.services) {
74
98
  target.services = target.services || {};
75
99
  for (const [serviceName, overrides] of Object.entries(source.services)) {
@@ -79,6 +103,9 @@ function mergeConfig(target, source) {
79
103
  };
80
104
  }
81
105
  }
106
+ if (source.queryTimeout !== undefined) {
107
+ target.queryTimeout = source.queryTimeout;
108
+ }
82
109
  }
83
110
  /**
84
111
  * Get the paths checked for config files
@@ -95,3 +122,17 @@ export function getConfigPaths() {
95
122
  export function formatConfig(config) {
96
123
  return yaml.stringify(config);
97
124
  }
125
+ /**
126
+ * Get marketplace repository URL from config
127
+ */
128
+ export function getMarketplaceRepoUrl() {
129
+ const config = loadConfig();
130
+ return config.marketplace.repoUrl;
131
+ }
132
+ /**
133
+ * Get marketplace registry from config
134
+ */
135
+ export function getMarketplaceRegistry() {
136
+ const config = loadConfig();
137
+ return config.marketplace.registry;
138
+ }