@agents-at-scale/ark 0.1.36-rc1 → 0.1.37
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 +53 -70
- package/dist/arkServices.d.ts +3 -27
- package/dist/arkServices.js +31 -3
- package/dist/arkServices.spec.js +118 -10
- package/dist/commands/completion/index.js +0 -2
- package/dist/commands/install/index.js +49 -58
- package/dist/commands/models/create.d.ts +9 -1
- package/dist/commands/models/create.js +97 -90
- package/dist/commands/models/create.spec.js +9 -37
- package/dist/commands/models/index.js +8 -2
- package/dist/commands/models/index.spec.js +1 -1
- package/dist/commands/status/index.d.ts +3 -1
- package/dist/commands/status/index.js +54 -2
- package/dist/components/ChatUI.js +19 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/arkApiClient.d.ts +1 -2
- package/dist/lib/arkApiClient.js +5 -6
- package/dist/lib/config.d.ts +4 -0
- package/dist/lib/config.js +9 -0
- package/dist/lib/nextSteps.js +1 -1
- package/dist/lib/nextSteps.spec.js +1 -1
- package/dist/lib/security.js +4 -0
- package/dist/lib/startup.js +6 -2
- package/dist/lib/startup.spec.js +1 -1
- package/dist/lib/timeout.d.ts +1 -0
- package/dist/lib/timeout.js +20 -0
- package/dist/lib/timeout.spec.js +14 -0
- package/dist/lib/waitForReady.d.ts +8 -0
- package/dist/lib/waitForReady.js +32 -0
- package/dist/lib/waitForReady.spec.js +104 -0
- package/dist/types/arkService.d.ts +27 -0
- package/package.json +3 -3
- package/dist/charts/charts.d.ts +0 -5
- package/dist/charts/charts.js +0 -6
- package/dist/charts/dependencies.d.ts +0 -6
- package/dist/charts/dependencies.js +0 -50
- package/dist/charts/types.d.ts +0 -40
- package/dist/commands/agents/selector.d.ts +0 -8
- package/dist/commands/agents/selector.js +0 -53
- package/dist/commands/agents.d.ts +0 -2
- package/dist/commands/agents.js +0 -53
- package/dist/commands/chat.d.ts +0 -2
- package/dist/commands/chat.js +0 -45
- package/dist/commands/cluster/get-ip.d.ts +0 -2
- package/dist/commands/cluster/get-ip.js +0 -32
- package/dist/commands/cluster/get-type.d.ts +0 -2
- package/dist/commands/cluster/get-type.js +0 -26
- package/dist/commands/completion.d.ts +0 -2
- package/dist/commands/completion.js +0 -265
- package/dist/commands/config.d.ts +0 -2
- package/dist/commands/config.js +0 -44
- package/dist/commands/dashboard.d.ts +0 -3
- package/dist/commands/dashboard.js +0 -39
- package/dist/commands/dev/index.d.ts +0 -3
- package/dist/commands/dev/index.js +0 -9
- package/dist/commands/dev/tool/check.d.ts +0 -2
- package/dist/commands/dev/tool/check.js +0 -142
- package/dist/commands/dev/tool/clean.d.ts +0 -2
- package/dist/commands/dev/tool/clean.js +0 -153
- package/dist/commands/dev/tool/generate.d.ts +0 -2
- package/dist/commands/dev/tool/generate.js +0 -28
- package/dist/commands/dev/tool/index.d.ts +0 -2
- package/dist/commands/dev/tool/index.js +0 -14
- package/dist/commands/dev/tool/init.d.ts +0 -2
- package/dist/commands/dev/tool/init.js +0 -320
- package/dist/commands/dev/tool/shared.d.ts +0 -5
- package/dist/commands/dev/tool/shared.js +0 -258
- package/dist/commands/dev/tool/status.d.ts +0 -2
- package/dist/commands/dev/tool/status.js +0 -136
- package/dist/commands/dev/tool-generate.spec.js +0 -163
- package/dist/commands/dev/tool.d.ts +0 -2
- package/dist/commands/dev/tool.js +0 -559
- package/dist/commands/dev/tool.spec.js +0 -48
- package/dist/commands/install.d.ts +0 -3
- package/dist/commands/install.js +0 -147
- package/dist/commands/models/selector.d.ts +0 -8
- package/dist/commands/models/selector.js +0 -53
- package/dist/commands/routes.d.ts +0 -2
- package/dist/commands/routes.js +0 -101
- package/dist/commands/status.d.ts +0 -3
- package/dist/commands/status.js +0 -33
- package/dist/commands/targets.d.ts +0 -2
- package/dist/commands/targets.js +0 -65
- package/dist/commands/teams/selector.d.ts +0 -8
- package/dist/commands/teams/selector.js +0 -55
- package/dist/commands/tools/selector.d.ts +0 -8
- package/dist/commands/tools/selector.js +0 -53
- package/dist/commands/uninstall.d.ts +0 -2
- package/dist/commands/uninstall.js +0 -83
- package/dist/components/DashboardCLI.d.ts +0 -3
- package/dist/components/DashboardCLI.js +0 -149
- package/dist/components/StatusView.d.ts +0 -10
- package/dist/components/StatusView.js +0 -39
- package/dist/config.d.ts +0 -23
- package/dist/config.js +0 -92
- package/dist/lib/arkClient.d.ts +0 -32
- package/dist/lib/arkClient.js +0 -43
- package/dist/lib/commandUtils.d.ts +0 -4
- package/dist/lib/commandUtils.js +0 -18
- package/dist/lib/commandUtils.test.d.ts +0 -1
- package/dist/lib/commandUtils.test.js +0 -44
- package/dist/lib/config.test.d.ts +0 -1
- package/dist/lib/config.test.js +0 -93
- package/dist/lib/consts.d.ts +0 -9
- package/dist/lib/consts.js +0 -13
- package/dist/lib/consts.spec.d.ts +0 -1
- package/dist/lib/consts.spec.js +0 -15
- package/dist/lib/dev/tools/analyzer.d.ts +0 -30
- package/dist/lib/dev/tools/analyzer.js +0 -190
- package/dist/lib/dev/tools/discover_tools.py +0 -392
- package/dist/lib/dev/tools/mcp-types.d.ts +0 -28
- package/dist/lib/dev/tools/mcp-types.js +0 -86
- package/dist/lib/dev/tools/types.d.ts +0 -50
- package/dist/lib/dev/tools/types.js +0 -1
- package/dist/lib/exec.d.ts +0 -1
- package/dist/lib/exec.js +0 -9
- package/dist/lib/gatewayManager.d.ts +0 -24
- package/dist/lib/gatewayManager.js +0 -85
- package/dist/lib/kubernetes.d.ts +0 -28
- package/dist/lib/kubernetes.js +0 -122
- package/dist/lib/portUtils.d.ts +0 -8
- package/dist/lib/portUtils.js +0 -39
- package/dist/lib/progress.d.ts +0 -128
- package/dist/lib/progress.js +0 -273
- package/dist/lib/queryRunner.d.ts +0 -22
- package/dist/lib/queryRunner.js +0 -142
- package/dist/lib/wrappers/git.d.ts +0 -2
- package/dist/lib/wrappers/git.js +0 -43
- /package/dist/{charts/types.js → lib/timeout.spec.d.ts} +0 -0
- /package/dist/{commands/dev/tool-generate.spec.d.ts → lib/waitForReady.spec.d.ts} +0 -0
- /package/dist/{commands/dev/tool.spec.d.ts → types/arkService.js} +0 -0
package/README.md
CHANGED
|
@@ -1,95 +1,78 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<h1 align="center"><code>ark</code></h1>
|
|
3
|
+
<h4 align="center">Ark Command Line Interface</h4>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<hr>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="#quickstart">Quickstart</a> •
|
|
9
|
+
<a href="https://mckinsey.github.io/agents-at-scale-ark/">Documentation</a>
|
|
10
|
+
</p>
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://github.com/mckinsey/agents-at-scale-ark/actions/workflows/cicd.yaml"><img src="https://github.com/mckinsey/agents-at-scale-ark/actions/workflows/cicd.yaml/badge.svg" alt="CI/CD"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/@agents-at-scale/ark"><img src="https://img.shields.io/npm/v/@agents-at-scale/ark.svg" alt="npm version"></a>
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
6
16
|
|
|
7
|
-
|
|
8
|
-
2. **Gateway setup** for service discovery:
|
|
9
|
-
```bash
|
|
10
|
-
# From agents-at-scale project root
|
|
11
|
-
make localhost-gateway-install
|
|
12
|
-
```
|
|
17
|
+
## Quickstart
|
|
13
18
|
|
|
14
|
-
|
|
19
|
+
Ensure you have [Node.js](https://nodejs.org/en/download) and [Helm](https://helm.sh/docs/intro/install/) installed. Then run the following commands to install Ark:
|
|
15
20
|
|
|
16
21
|
```bash
|
|
17
|
-
|
|
18
|
-
npm
|
|
19
|
-
npm install -g .
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Usage
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
# Interactive mode (no arguments)
|
|
26
|
-
ark
|
|
22
|
+
# Install the 'ark' CLI:
|
|
23
|
+
npm install -g @agents-at-scale/ark
|
|
27
24
|
|
|
28
|
-
#
|
|
29
|
-
ark
|
|
30
|
-
ark cluster --help
|
|
25
|
+
# Install Ark:
|
|
26
|
+
ark install
|
|
31
27
|
|
|
32
|
-
#
|
|
33
|
-
ark
|
|
28
|
+
# Optionally configure a 'default' model to use for agents:
|
|
29
|
+
ark models create default
|
|
34
30
|
|
|
35
|
-
#
|
|
36
|
-
ark
|
|
31
|
+
# Run the dashboard:
|
|
32
|
+
ark dashboard
|
|
33
|
+
```
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
ark cluster get-type
|
|
40
|
-
ark cluster get-ip
|
|
41
|
-
ark cluster get-ip --verbose
|
|
42
|
-
ark cluster get-ip --context minikube
|
|
35
|
+
In most cases the default installation options will be sufficient. This will install the Ark dependencies, the controller, the APIs and the dashboard. You can optionally setup a `default` model that will be the default used by agents. You will need a Kubernetes cluster to install Ark into, you can use [Minikube](https://minikube.sigs.k8s.io/docs/start), [Kind](https://kind.sigs.k8s.io/docs/user/quick-start/), [Docker Desktop](https://docs.docker.com/desktop/kubernetes/) or similar to run a local cluster. The `install` command will warn if any required dependencies are missing.
|
|
43
36
|
|
|
44
|
-
|
|
45
|
-
ark autocomplete
|
|
46
|
-
```
|
|
37
|
+
User guides, developer guides, operations guides and API reference documentation is all available at:
|
|
47
38
|
|
|
48
|
-
|
|
39
|
+
https://mckinsey.github.io/agents-at-scale-ark/
|
|
49
40
|
|
|
50
|
-
|
|
41
|
+
The [Quickstart](https://mckinsey.github.io/agents-at-scale-ark/quickstart/) guide will walk you through the process of configuring a model, creating an agent and running basic queries.
|
|
51
42
|
|
|
52
|
-
|
|
53
|
-
2. **Kubernetes service discovery** - for internal services
|
|
54
|
-
3. **Default localhost URLs** - fallback
|
|
43
|
+
To troubleshoot an installation, run `ark status`.
|
|
55
44
|
|
|
56
|
-
|
|
45
|
+
## Configuration
|
|
57
46
|
|
|
58
|
-
|
|
47
|
+
You can customize Ark service installations using a `.arkrc.yaml` file in your home directory (`~/.arkrc.yaml`) or project directory. This allows you to override service properties like enabled status, namespace, or chart location.
|
|
59
48
|
|
|
60
|
-
|
|
49
|
+
Example `.arkrc.yaml`:
|
|
61
50
|
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
# From tools/ark-cli directory
|
|
70
|
-
npm run lint # Run linting and formatting
|
|
71
|
-
npm run lint:check # Check linting without fixing
|
|
51
|
+
```yaml
|
|
52
|
+
services:
|
|
53
|
+
localhost-gateway:
|
|
54
|
+
enabled: true
|
|
55
|
+
ark-controller:
|
|
56
|
+
namespace: custom-namespace
|
|
72
57
|
```
|
|
73
58
|
|
|
74
|
-
|
|
59
|
+
This example enables the `localhost-gateway` service (disabled by default) and changes the namespace for `ark-controller`.
|
|
75
60
|
|
|
76
|
-
|
|
61
|
+
### Installing Agents @ Scale
|
|
77
62
|
|
|
78
|
-
|
|
79
|
-
# Debug configuration discovery and service resolution
|
|
80
|
-
DEBUG=ark:config ark check status
|
|
63
|
+
To install the Agents @ Scale platform with JFrog container registry credentials:
|
|
81
64
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
65
|
+
```yaml
|
|
66
|
+
services:
|
|
67
|
+
agents-at-scale:
|
|
68
|
+
enabled: true
|
|
69
|
+
installArgs:
|
|
70
|
+
- --set
|
|
71
|
+
- containerRegistry.enabled=true
|
|
72
|
+
- --set
|
|
73
|
+
- containerRegistry.username=YOUR_USERNAME
|
|
74
|
+
- --set
|
|
75
|
+
- containerRegistry.password=YOUR_PASSWORD
|
|
89
76
|
```
|
|
90
77
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
- **Wrong URL detected**: See which discovery method is being used
|
|
94
|
-
- **Service timeouts**: Check localhost-gateway and kubernetes connectivity
|
|
95
|
-
- **Config issues**: Trace fallback logic through multiple discovery methods
|
|
78
|
+
Replace `YOUR_USERNAME` and `YOUR_PASSWORD` with your JFrog credentials.
|
package/dist/arkServices.d.ts
CHANGED
|
@@ -1,39 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Centralized ARK service definitions used by both install and status commands
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
helmReleaseName: string;
|
|
7
|
-
description: string;
|
|
8
|
-
enabled: boolean;
|
|
9
|
-
namespace?: string;
|
|
10
|
-
chartPath?: string;
|
|
11
|
-
installArgs?: string[];
|
|
12
|
-
k8sServiceName?: string;
|
|
13
|
-
k8sServicePort?: number;
|
|
14
|
-
k8sPortForwardLocalPort?: number;
|
|
15
|
-
k8sDeploymentName?: string;
|
|
16
|
-
k8sDevDeploymentName?: string;
|
|
17
|
-
}
|
|
18
|
-
export interface ServiceCollection {
|
|
19
|
-
[key: string]: ArkService;
|
|
20
|
-
}
|
|
21
|
-
export interface ArkDependency {
|
|
22
|
-
name: string;
|
|
23
|
-
command: string;
|
|
24
|
-
args: string[];
|
|
25
|
-
description: string;
|
|
26
|
-
}
|
|
27
|
-
export interface DependencyCollection {
|
|
28
|
-
[key: string]: ArkDependency;
|
|
29
|
-
}
|
|
4
|
+
import type { ArkService, ServiceCollection, ArkDependency, DependencyCollection } from './types/arkService.js';
|
|
5
|
+
export type { ArkService, ServiceCollection, ArkDependency, DependencyCollection, };
|
|
30
6
|
/**
|
|
31
7
|
* Dependencies that should be installed before ARK services
|
|
32
8
|
* Note: Dependencies will be installed in the order they are defined here
|
|
33
9
|
*/
|
|
34
10
|
export declare const arkDependencies: DependencyCollection;
|
|
35
11
|
/**
|
|
36
|
-
* Core ARK services with
|
|
12
|
+
* Core ARK services - initialized with defaults and config overrides applied
|
|
37
13
|
*/
|
|
38
14
|
export declare const arkServices: ServiceCollection;
|
|
39
15
|
/**
|
package/dist/arkServices.js
CHANGED
|
@@ -1,6 +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
5
|
const REGISTRY_BASE = 'oci://ghcr.io/mckinsey/agents-at-scale-ark/charts';
|
|
5
6
|
/**
|
|
6
7
|
* Dependencies that should be installed before ARK services
|
|
@@ -53,14 +54,15 @@ export const arkDependencies = {
|
|
|
53
54
|
},
|
|
54
55
|
};
|
|
55
56
|
/**
|
|
56
|
-
*
|
|
57
|
+
* Default ARK services with their installation and status check configurations
|
|
57
58
|
*/
|
|
58
|
-
|
|
59
|
+
const defaultArkServices = {
|
|
59
60
|
'ark-controller': {
|
|
60
61
|
name: 'ark-controller',
|
|
61
62
|
helmReleaseName: 'ark-controller',
|
|
62
63
|
description: 'Core Ark controller for managing AI resources',
|
|
63
64
|
enabled: true,
|
|
65
|
+
category: 'core',
|
|
64
66
|
namespace: 'ark-system',
|
|
65
67
|
chartPath: `${REGISTRY_BASE}/ark-controller`,
|
|
66
68
|
installArgs: ['--create-namespace', '--set', 'rbac.enable=true'],
|
|
@@ -72,7 +74,7 @@ export const arkServices = {
|
|
|
72
74
|
helmReleaseName: 'ark-api',
|
|
73
75
|
description: 'API layer for interacting with Ark resources',
|
|
74
76
|
enabled: true,
|
|
75
|
-
|
|
77
|
+
category: 'service',
|
|
76
78
|
chartPath: `${REGISTRY_BASE}/ark-api`,
|
|
77
79
|
installArgs: [],
|
|
78
80
|
k8sServiceName: 'ark-api',
|
|
@@ -86,6 +88,7 @@ export const arkServices = {
|
|
|
86
88
|
helmReleaseName: 'ark-dashboard',
|
|
87
89
|
description: 'Ark Dashboard',
|
|
88
90
|
enabled: true,
|
|
91
|
+
category: 'service',
|
|
89
92
|
// namespace: undefined - uses current context namespace
|
|
90
93
|
chartPath: `${REGISTRY_BASE}/ark-dashboard`,
|
|
91
94
|
installArgs: [],
|
|
@@ -100,6 +103,7 @@ export const arkServices = {
|
|
|
100
103
|
helmReleaseName: 'ark-api-a2a',
|
|
101
104
|
description: 'Ark API agent-to-agent communication service',
|
|
102
105
|
enabled: false, // Disabled - not currently used
|
|
106
|
+
category: 'service',
|
|
103
107
|
// namespace: undefined - uses current context namespace
|
|
104
108
|
// Note: This service might be installed as part of ark-api or separately
|
|
105
109
|
},
|
|
@@ -108,22 +112,46 @@ export const arkServices = {
|
|
|
108
112
|
helmReleaseName: 'ark-mcp',
|
|
109
113
|
description: 'Ark Model Context Protocol server',
|
|
110
114
|
enabled: true,
|
|
115
|
+
category: 'service',
|
|
111
116
|
// namespace: undefined - uses current context namespace
|
|
112
117
|
chartPath: `${REGISTRY_BASE}/ark-mcp`,
|
|
113
118
|
installArgs: [],
|
|
114
119
|
k8sDeploymentName: 'ark-mcp',
|
|
115
120
|
k8sDevDeploymentName: 'ark-mcp-devspace',
|
|
116
121
|
},
|
|
122
|
+
'agents-at-scale': {
|
|
123
|
+
name: 'agents-at-scale',
|
|
124
|
+
helmReleaseName: 'agents-at-scale',
|
|
125
|
+
description: 'Agents @ Scale Platform',
|
|
126
|
+
enabled: false,
|
|
127
|
+
category: 'service',
|
|
128
|
+
chartPath: 'oci://ghcr.io/mck-private/qb-fm-labs-legacyx/charts/legacyx',
|
|
129
|
+
installArgs: [],
|
|
130
|
+
},
|
|
117
131
|
'localhost-gateway': {
|
|
118
132
|
name: 'localhost-gateway',
|
|
119
133
|
helmReleaseName: 'localhost-gateway',
|
|
120
134
|
description: 'Gateway for local development clusters',
|
|
121
135
|
enabled: false, // Disabled - not needed for most users
|
|
136
|
+
category: 'service',
|
|
122
137
|
namespace: 'ark-system',
|
|
123
138
|
chartPath: `${REGISTRY_BASE}/localhost-gateway`,
|
|
124
139
|
installArgs: [],
|
|
125
140
|
},
|
|
126
141
|
};
|
|
142
|
+
function applyConfigOverrides(defaults) {
|
|
143
|
+
const config = loadConfig();
|
|
144
|
+
const overrides = config?.services || {};
|
|
145
|
+
const result = {};
|
|
146
|
+
for (const [key, service] of Object.entries(defaults)) {
|
|
147
|
+
result[key] = overrides[key] ? { ...service, ...overrides[key] } : service;
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Core ARK services - initialized with defaults and config overrides applied
|
|
153
|
+
*/
|
|
154
|
+
export const arkServices = applyConfigOverrides(defaultArkServices);
|
|
127
155
|
/**
|
|
128
156
|
* Get services that can be installed via Helm charts (only enabled services)
|
|
129
157
|
*/
|
package/dist/arkServices.spec.js
CHANGED
|
@@ -1,24 +1,132 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jest } from '@jest/globals';
|
|
2
|
+
const mockLoadConfig = jest.fn();
|
|
3
|
+
jest.unstable_mockModule('./lib/config.js', () => ({
|
|
4
|
+
loadConfig: mockLoadConfig,
|
|
5
|
+
}));
|
|
6
|
+
const { arkDependencies, arkServices: originalArkServices, getInstallableServices, } = await import('./arkServices.js');
|
|
2
7
|
describe('arkServices', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
jest.clearAllMocks();
|
|
10
|
+
});
|
|
3
11
|
it('exports arkDependencies with expected structure', () => {
|
|
4
12
|
expect(arkDependencies).toBeDefined();
|
|
5
13
|
expect(arkDependencies['cert-manager']).toBeDefined();
|
|
6
14
|
expect(arkDependencies['cert-manager'].command).toBe('helm');
|
|
7
15
|
});
|
|
8
16
|
it('exports arkServices with expected structure', () => {
|
|
9
|
-
expect(
|
|
10
|
-
expect(
|
|
11
|
-
expect(
|
|
12
|
-
|
|
13
|
-
expect(
|
|
14
|
-
expect(
|
|
15
|
-
// System services should have explicit namespace
|
|
16
|
-
expect(arkServices['localhost-gateway'].namespace).toBe('ark-system');
|
|
17
|
+
expect(originalArkServices).toBeDefined();
|
|
18
|
+
expect(originalArkServices['ark-controller']).toBeDefined();
|
|
19
|
+
expect(originalArkServices['ark-controller'].namespace).toBe('ark-system');
|
|
20
|
+
expect(originalArkServices['ark-api'].namespace).toBeUndefined();
|
|
21
|
+
expect(originalArkServices['ark-dashboard'].namespace).toBeUndefined();
|
|
22
|
+
expect(originalArkServices['localhost-gateway'].namespace).toBe('ark-system');
|
|
17
23
|
});
|
|
18
24
|
it('getInstallableServices returns services with chartPath', () => {
|
|
19
25
|
const installable = getInstallableServices();
|
|
20
26
|
expect(installable['ark-controller']).toBeDefined();
|
|
21
27
|
expect(installable['ark-api']).toBeDefined();
|
|
22
|
-
expect(installable['ark-api-a2a']).toBeUndefined();
|
|
28
|
+
expect(installable['ark-api-a2a']).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
describe('applyConfigOverrides', () => {
|
|
31
|
+
it('applies no overrides when config has no services section', async () => {
|
|
32
|
+
mockLoadConfig.mockReturnValue({});
|
|
33
|
+
jest.resetModules();
|
|
34
|
+
const { arkServices } = await import('./arkServices.js');
|
|
35
|
+
expect(arkServices['ark-controller'].enabled).toBe(true);
|
|
36
|
+
expect(arkServices['ark-api'].enabled).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('applies overrides to enable a disabled service', async () => {
|
|
39
|
+
mockLoadConfig.mockReturnValue({
|
|
40
|
+
services: {
|
|
41
|
+
'localhost-gateway': { enabled: true },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
jest.resetModules();
|
|
45
|
+
const { arkServices } = await import('./arkServices.js');
|
|
46
|
+
expect(arkServices['localhost-gateway'].enabled).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
it('applies overrides to disable an enabled service', async () => {
|
|
49
|
+
mockLoadConfig.mockReturnValue({
|
|
50
|
+
services: {
|
|
51
|
+
'ark-controller': { enabled: false },
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
jest.resetModules();
|
|
55
|
+
const { arkServices } = await import('./arkServices.js');
|
|
56
|
+
expect(arkServices['ark-controller'].enabled).toBe(false);
|
|
57
|
+
});
|
|
58
|
+
it('applies overrides to multiple services', async () => {
|
|
59
|
+
mockLoadConfig.mockReturnValue({
|
|
60
|
+
services: {
|
|
61
|
+
'ark-controller': { enabled: false },
|
|
62
|
+
'ark-api': { enabled: false },
|
|
63
|
+
'localhost-gateway': { enabled: true },
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
jest.resetModules();
|
|
67
|
+
const { arkServices } = await import('./arkServices.js');
|
|
68
|
+
expect(arkServices['ark-controller'].enabled).toBe(false);
|
|
69
|
+
expect(arkServices['ark-api'].enabled).toBe(false);
|
|
70
|
+
expect(arkServices['localhost-gateway'].enabled).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
it('applies overrides to namespace', async () => {
|
|
73
|
+
mockLoadConfig.mockReturnValue({
|
|
74
|
+
services: {
|
|
75
|
+
'ark-api': { namespace: 'custom-namespace' },
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
jest.resetModules();
|
|
79
|
+
const { arkServices } = await import('./arkServices.js');
|
|
80
|
+
expect(arkServices['ark-api'].namespace).toBe('custom-namespace');
|
|
81
|
+
});
|
|
82
|
+
it('applies overrides to chartPath', async () => {
|
|
83
|
+
mockLoadConfig.mockReturnValue({
|
|
84
|
+
services: {
|
|
85
|
+
'ark-controller': {
|
|
86
|
+
chartPath: 'oci://custom-registry/charts/ark-controller',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
jest.resetModules();
|
|
91
|
+
const { arkServices } = await import('./arkServices.js');
|
|
92
|
+
expect(arkServices['ark-controller'].chartPath).toBe('oci://custom-registry/charts/ark-controller');
|
|
93
|
+
});
|
|
94
|
+
it('applies partial overrides without affecting other properties', async () => {
|
|
95
|
+
mockLoadConfig.mockReturnValue({
|
|
96
|
+
services: {
|
|
97
|
+
'ark-controller': { enabled: false },
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
jest.resetModules();
|
|
101
|
+
const { arkServices } = await import('./arkServices.js');
|
|
102
|
+
expect(arkServices['ark-controller'].enabled).toBe(false);
|
|
103
|
+
expect(arkServices['ark-controller'].namespace).toBe('ark-system');
|
|
104
|
+
expect(arkServices['ark-controller'].category).toBe('core');
|
|
105
|
+
expect(arkServices['ark-controller'].description).toBe('Core Ark controller for managing AI resources');
|
|
106
|
+
});
|
|
107
|
+
it('applies overrides to installArgs', async () => {
|
|
108
|
+
mockLoadConfig.mockReturnValue({
|
|
109
|
+
services: {
|
|
110
|
+
'ark-controller': { installArgs: ['--set', 'custom.value=true'] },
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
jest.resetModules();
|
|
114
|
+
const { arkServices } = await import('./arkServices.js');
|
|
115
|
+
expect(arkServices['ark-controller'].installArgs).toEqual([
|
|
116
|
+
'--set',
|
|
117
|
+
'custom.value=true',
|
|
118
|
+
]);
|
|
119
|
+
});
|
|
120
|
+
it('does not affect services without overrides', async () => {
|
|
121
|
+
mockLoadConfig.mockReturnValue({
|
|
122
|
+
services: {
|
|
123
|
+
'ark-controller': { enabled: false },
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
jest.resetModules();
|
|
127
|
+
const { arkServices } = await import('./arkServices.js');
|
|
128
|
+
expect(arkServices['ark-api'].enabled).toBe(true);
|
|
129
|
+
expect(arkServices['ark-dashboard'].enabled).toBe(true);
|
|
130
|
+
});
|
|
23
131
|
});
|
|
24
132
|
});
|
|
@@ -114,7 +114,6 @@ complete -F _ark_completion ark
|
|
|
114
114
|
.description('Generate zsh completion script')
|
|
115
115
|
.action(() => {
|
|
116
116
|
// Shell script requires escaped $ characters
|
|
117
|
-
/* eslint-disable no-useless-escape */
|
|
118
117
|
console.log(`
|
|
119
118
|
#compdef ark
|
|
120
119
|
|
|
@@ -224,7 +223,6 @@ _ark() {
|
|
|
224
223
|
|
|
225
224
|
_ark
|
|
226
225
|
`.trim());
|
|
227
|
-
/* eslint-enable no-useless-escape */
|
|
228
226
|
});
|
|
229
227
|
return completion;
|
|
230
228
|
}
|
|
@@ -4,10 +4,11 @@ import { execute } from '../../lib/commands.js';
|
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
5
|
import { showNoClusterError } from '../../lib/startup.js';
|
|
6
6
|
import output from '../../lib/output.js';
|
|
7
|
-
import { getInstallableServices, arkDependencies, } from '../../arkServices.js';
|
|
8
|
-
import { isArkReady } from '../../lib/arkStatus.js';
|
|
7
|
+
import { getInstallableServices, arkDependencies, arkServices, } from '../../arkServices.js';
|
|
9
8
|
import { printNextSteps } from '../../lib/nextSteps.js';
|
|
10
9
|
import ora from 'ora';
|
|
10
|
+
import { waitForServicesReady, } from '../../lib/waitForReady.js';
|
|
11
|
+
import { parseTimeoutToSeconds } from '../../lib/timeout.js';
|
|
11
12
|
async function installService(service, verbose = false) {
|
|
12
13
|
const helmArgs = [
|
|
13
14
|
'upgrade',
|
|
@@ -67,6 +68,12 @@ export async function installArk(config, serviceName, options = {}) {
|
|
|
67
68
|
console.log(chalk.cyan.bold('\nSelect components to install:'));
|
|
68
69
|
console.log(chalk.gray('Use arrow keys to navigate, space to toggle, enter to confirm\n'));
|
|
69
70
|
// Build choices for the checkbox prompt
|
|
71
|
+
const coreServices = Object.values(arkServices)
|
|
72
|
+
.filter((s) => s.category === 'core')
|
|
73
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
74
|
+
const otherServices = Object.values(arkServices)
|
|
75
|
+
.filter((s) => s.category === 'service')
|
|
76
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
70
77
|
const allChoices = [
|
|
71
78
|
new inquirer.Separator(chalk.bold('──── Dependencies ────')),
|
|
72
79
|
{
|
|
@@ -80,32 +87,17 @@ export async function installArk(config, serviceName, options = {}) {
|
|
|
80
87
|
checked: true,
|
|
81
88
|
},
|
|
82
89
|
new inquirer.Separator(chalk.bold('──── Ark Core ────')),
|
|
83
|
-
{
|
|
84
|
-
name:
|
|
85
|
-
value:
|
|
86
|
-
checked:
|
|
87
|
-
},
|
|
90
|
+
...coreServices.map((service) => ({
|
|
91
|
+
name: `${service.name} ${chalk.gray(`- ${service.description}`)}`,
|
|
92
|
+
value: service.helmReleaseName,
|
|
93
|
+
checked: Boolean(service.enabled),
|
|
94
|
+
})),
|
|
88
95
|
new inquirer.Separator(chalk.bold('──── Ark Services ────')),
|
|
89
|
-
{
|
|
90
|
-
name:
|
|
91
|
-
value:
|
|
92
|
-
checked:
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
name: `ark-dashboard ${chalk.gray('- Web dashboard')}`,
|
|
96
|
-
value: 'ark-dashboard',
|
|
97
|
-
checked: true,
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
name: `ark-mcp ${chalk.gray('- MCP services')}`,
|
|
101
|
-
value: 'ark-mcp',
|
|
102
|
-
checked: true,
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
name: `localhost-gateway ${chalk.gray('- Gateway for local access')}`,
|
|
106
|
-
value: 'localhost-gateway',
|
|
107
|
-
checked: true,
|
|
108
|
-
},
|
|
96
|
+
...otherServices.map((service) => ({
|
|
97
|
+
name: `${service.name} ${chalk.gray(`- ${service.description}`)}`,
|
|
98
|
+
value: service.helmReleaseName,
|
|
99
|
+
checked: Boolean(service.enabled),
|
|
100
|
+
})),
|
|
109
101
|
];
|
|
110
102
|
let selectedComponents = [];
|
|
111
103
|
try {
|
|
@@ -190,11 +182,9 @@ export async function installArk(config, serviceName, options = {}) {
|
|
|
190
182
|
}
|
|
191
183
|
}
|
|
192
184
|
// Install selected services
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const serviceKey = service.helmReleaseName;
|
|
197
|
-
if (!selectedComponents.includes(serviceKey)) {
|
|
185
|
+
for (const serviceName of selectedComponents) {
|
|
186
|
+
const service = Object.values(arkServices).find((s) => s.helmReleaseName === serviceName);
|
|
187
|
+
if (!service || !service.chartPath) {
|
|
198
188
|
continue;
|
|
199
189
|
}
|
|
200
190
|
output.info(`installing ${service.name}...`);
|
|
@@ -203,8 +193,8 @@ export async function installArk(config, serviceName, options = {}) {
|
|
|
203
193
|
console.log(); // Add blank line after command output
|
|
204
194
|
}
|
|
205
195
|
catch {
|
|
206
|
-
// Continue with remaining services on error
|
|
207
196
|
console.log(); // Add blank line after error output
|
|
197
|
+
process.exit(1);
|
|
208
198
|
}
|
|
209
199
|
}
|
|
210
200
|
}
|
|
@@ -234,8 +224,8 @@ export async function installArk(config, serviceName, options = {}) {
|
|
|
234
224
|
console.log(); // Add blank line after command output
|
|
235
225
|
}
|
|
236
226
|
catch {
|
|
237
|
-
// Continue with remaining services on error
|
|
238
227
|
console.log(); // Add blank line after error output
|
|
228
|
+
process.exit(1);
|
|
239
229
|
}
|
|
240
230
|
}
|
|
241
231
|
}
|
|
@@ -245,34 +235,35 @@ export async function installArk(config, serviceName, options = {}) {
|
|
|
245
235
|
}
|
|
246
236
|
// Wait for Ark to be ready if requested
|
|
247
237
|
if (options.waitForReady) {
|
|
248
|
-
// Parse timeout value (e.g., '30s', '2m', '60')
|
|
249
|
-
const parseTimeout = (value) => {
|
|
250
|
-
const match = value.match(/^(\d+)([sm])?$/);
|
|
251
|
-
if (!match) {
|
|
252
|
-
throw new Error('Invalid timeout format. Use format like 30s or 2m');
|
|
253
|
-
}
|
|
254
|
-
const num = parseInt(match[1], 10);
|
|
255
|
-
const unit = match[2] || 's';
|
|
256
|
-
return unit === 'm' ? num * 60 : num;
|
|
257
|
-
};
|
|
258
238
|
try {
|
|
259
|
-
const timeoutSeconds =
|
|
260
|
-
const
|
|
261
|
-
|
|
239
|
+
const timeoutSeconds = parseTimeoutToSeconds(options.waitForReady);
|
|
240
|
+
const servicesToWait = Object.values(arkServices).filter((s) => s.enabled &&
|
|
241
|
+
s.category === 'core' &&
|
|
242
|
+
s.k8sDeploymentName &&
|
|
243
|
+
s.namespace);
|
|
262
244
|
const spinner = ora(`Waiting for Ark to be ready (timeout: ${timeoutSeconds}s)...`).start();
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
245
|
+
const statusMap = new Map();
|
|
246
|
+
servicesToWait.forEach((s) => statusMap.set(s.name, false));
|
|
247
|
+
const startTime = Date.now();
|
|
248
|
+
const result = await waitForServicesReady(servicesToWait, timeoutSeconds, (progress) => {
|
|
249
|
+
statusMap.set(progress.serviceName, progress.ready);
|
|
268
250
|
const elapsed = Math.floor((Date.now() - startTime) / 1000);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
251
|
+
const lines = servicesToWait.map((s) => {
|
|
252
|
+
const ready = statusMap.get(s.name);
|
|
253
|
+
const icon = ready ? '✓' : '⋯';
|
|
254
|
+
const status = ready ? 'ready' : 'waiting...';
|
|
255
|
+
const color = ready ? chalk.green : chalk.yellow;
|
|
256
|
+
return ` ${color(icon)} ${chalk.bold(s.name)} ${chalk.blue(`(${s.namespace})`)} - ${status}`;
|
|
257
|
+
});
|
|
258
|
+
spinner.text = `Waiting for Ark to be ready (${elapsed}/${timeoutSeconds}s)...\n${lines.join('\n')}`;
|
|
259
|
+
});
|
|
260
|
+
if (result) {
|
|
261
|
+
spinner.succeed('Ark is ready');
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
spinner.fail(`Ark did not become ready within ${timeoutSeconds} seconds`);
|
|
265
|
+
process.exit(1);
|
|
272
266
|
}
|
|
273
|
-
// Timeout reached
|
|
274
|
-
spinner.fail(`Ark did not become ready within ${timeoutSeconds} seconds`);
|
|
275
|
-
process.exit(1);
|
|
276
267
|
}
|
|
277
268
|
catch (error) {
|
|
278
269
|
output.error(`Failed to wait for ready: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface CreateModelOptions {
|
|
2
|
+
type?: string;
|
|
3
|
+
model?: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
apiVersion?: string;
|
|
7
|
+
yes?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function createModel(modelName?: string, options?: CreateModelOptions): Promise<boolean>;
|