@eve-horizon/cli 0.1.0 → 0.1.2
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 +12 -0
- package/dist/commands/agents.js +78 -0
- package/dist/commands/db.js +127 -4
- package/dist/commands/env.js +34 -2
- package/dist/commands/harness.js +50 -2
- package/dist/commands/init.js +290 -0
- package/dist/commands/job.js +21 -2
- package/dist/commands/project.js +29 -2
- package/dist/commands/secrets.js +79 -8
- package/dist/commands/system.js +72 -1
- package/dist/index.js +9 -0
- package/dist/lib/help.js +121 -5
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -264,8 +264,20 @@ Environment variables for agent context:
|
|
|
264
264
|
```bash
|
|
265
265
|
eve harness list # List available harnesses
|
|
266
266
|
eve harness get mclaude # Show harness details and auth status
|
|
267
|
+
eve harness list --capabilities # Include model/reasoning capability hints
|
|
267
268
|
```
|
|
268
269
|
|
|
270
|
+
### Agents (Orchestration Config)
|
|
271
|
+
|
|
272
|
+
Provide policy + harness context for orchestrating agents (profiles, councils, availability):
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
eve agents config --json
|
|
276
|
+
eve agents config --path /path/to/repo --no-harnesses
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Recommended default policy profile name: `primary-orchestrator`.
|
|
280
|
+
|
|
269
281
|
## Pagination
|
|
270
282
|
|
|
271
283
|
List endpoints accept `--limit` and `--offset`. Default limit is **10**, newest first.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleAgents = handleAgents;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const yaml_1 = require("yaml");
|
|
7
|
+
const shared_1 = require("@eve/shared");
|
|
8
|
+
const args_1 = require("../lib/args");
|
|
9
|
+
const client_1 = require("../lib/client");
|
|
10
|
+
const output_1 = require("../lib/output");
|
|
11
|
+
function readYamlFile(filePath) {
|
|
12
|
+
const raw = (0, node_fs_1.readFileSync)(filePath, 'utf-8');
|
|
13
|
+
const parsed = (0, yaml_1.parse)(raw);
|
|
14
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
15
|
+
throw new Error(`Invalid YAML in ${filePath}`);
|
|
16
|
+
}
|
|
17
|
+
return parsed;
|
|
18
|
+
}
|
|
19
|
+
function loadAgentsConfig(repoRoot) {
|
|
20
|
+
const eveDir = (0, node_path_1.join)(repoRoot, '.eve');
|
|
21
|
+
const manifestPath = (0, node_path_1.join)(eveDir, 'manifest.yaml');
|
|
22
|
+
if ((0, node_fs_1.existsSync)(manifestPath)) {
|
|
23
|
+
const manifest = readYamlFile(manifestPath);
|
|
24
|
+
const xEve = manifest['x-eve'] ||
|
|
25
|
+
manifest['x_eve'] ||
|
|
26
|
+
{};
|
|
27
|
+
const policy = xEve['agents'] || null;
|
|
28
|
+
const defaults = xEve['defaults'] || null;
|
|
29
|
+
return { source: { type: 'manifest', path: manifestPath }, policy, manifest_defaults: defaults };
|
|
30
|
+
}
|
|
31
|
+
return { source: { type: 'none' }, policy: null };
|
|
32
|
+
}
|
|
33
|
+
async function handleAgents(subcommand, positionals, flags, context) {
|
|
34
|
+
const command = subcommand ?? 'config';
|
|
35
|
+
const json = Boolean(flags.json);
|
|
36
|
+
const includeHarnesses = !((0, args_1.getBooleanFlag)(flags, ['no-harnesses']) ?? false);
|
|
37
|
+
const repoRoot = (0, node_path_1.resolve)((0, args_1.getStringFlag)(flags, ['path']) ?? process.cwd());
|
|
38
|
+
if (command !== 'config') {
|
|
39
|
+
throw new Error('Usage: eve agents config [--path <dir>] [--no-harnesses]');
|
|
40
|
+
}
|
|
41
|
+
const result = loadAgentsConfig(repoRoot);
|
|
42
|
+
const response = {
|
|
43
|
+
repo_root: repoRoot,
|
|
44
|
+
source: result.source,
|
|
45
|
+
policy: result.policy,
|
|
46
|
+
};
|
|
47
|
+
if (result.manifest_defaults) {
|
|
48
|
+
response.manifest_defaults = result.manifest_defaults;
|
|
49
|
+
}
|
|
50
|
+
if (includeHarnesses) {
|
|
51
|
+
const harnesses = await (0, client_1.requestJson)(context, '/harnesses');
|
|
52
|
+
response.harnesses = harnesses.data;
|
|
53
|
+
response.capabilities = shared_1.HARNESS_CAPABILITIES;
|
|
54
|
+
}
|
|
55
|
+
if (json) {
|
|
56
|
+
(0, output_1.outputJson)(response, json);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
console.log(`Agents config source: ${result.source.type}`);
|
|
60
|
+
if ('path' in result.source) {
|
|
61
|
+
console.log(`Path: ${result.source.path}`);
|
|
62
|
+
}
|
|
63
|
+
if (!result.policy) {
|
|
64
|
+
console.log('No policy found. Add x-eve.agents to .eve/manifest.yaml.');
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const profiles = result.policy.profiles || {};
|
|
68
|
+
const profileNames = Object.keys(profiles);
|
|
69
|
+
console.log(`Profiles: ${profileNames.length ? profileNames.join(', ') : 'none'}`);
|
|
70
|
+
}
|
|
71
|
+
if (includeHarnesses) {
|
|
72
|
+
const harnesses = response.harnesses;
|
|
73
|
+
if (harnesses?.length) {
|
|
74
|
+
const ready = harnesses.filter((h) => h.auth.available).length;
|
|
75
|
+
console.log(`Harnesses: ${harnesses.length} (${ready} ready)`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
package/dist/commands/db.js
CHANGED
|
@@ -6,6 +6,7 @@ const client_1 = require("../lib/client");
|
|
|
6
6
|
const output_1 = require("../lib/output");
|
|
7
7
|
const node_fs_1 = require("node:fs");
|
|
8
8
|
const node_path_1 = require("node:path");
|
|
9
|
+
const MIGRATION_REGEX = /^(\d{14})_([a-z0-9_]+)\.sql$/;
|
|
9
10
|
async function handleDb(subcommand, positionals, flags, context) {
|
|
10
11
|
const jsonOutput = Boolean(flags.json);
|
|
11
12
|
switch (subcommand) {
|
|
@@ -15,11 +16,21 @@ async function handleDb(subcommand, positionals, flags, context) {
|
|
|
15
16
|
return handleRls(positionals, flags, context, jsonOutput);
|
|
16
17
|
case 'sql':
|
|
17
18
|
return handleSql(positionals, flags, context, jsonOutput);
|
|
19
|
+
case 'migrate':
|
|
20
|
+
return handleMigrate(positionals, flags, context, jsonOutput);
|
|
21
|
+
case 'migrations':
|
|
22
|
+
return handleMigrations(positionals, flags, context, jsonOutput);
|
|
23
|
+
case 'new':
|
|
24
|
+
return handleNew(positionals, flags);
|
|
18
25
|
default:
|
|
19
|
-
throw new Error('Usage: eve db <
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
26
|
+
throw new Error('Usage: eve db <command> [options]\n\n' +
|
|
27
|
+
'Commands:\n' +
|
|
28
|
+
' schema --env <name> Show DB schema info\n' +
|
|
29
|
+
' rls --env <name> Show RLS policies and tables\n' +
|
|
30
|
+
' sql --env <name> --sql <stmt> Run parameterized SQL\n' +
|
|
31
|
+
' migrate --env <name> [--path <dir>] Apply pending migrations\n' +
|
|
32
|
+
' migrations --env <name> List applied migrations\n' +
|
|
33
|
+
' new <description> Create new migration file');
|
|
23
34
|
}
|
|
24
35
|
}
|
|
25
36
|
async function handleSchema(positionals, flags, context, jsonOutput) {
|
|
@@ -79,3 +90,115 @@ function parseJson(value, label) {
|
|
|
79
90
|
throw new Error(`${label} must be valid JSON: ${error.message}`);
|
|
80
91
|
}
|
|
81
92
|
}
|
|
93
|
+
async function handleMigrate(positionals, flags, context, jsonOutput) {
|
|
94
|
+
const { projectId, envName } = resolveProjectEnv(positionals, flags, context);
|
|
95
|
+
const migrationsPath = (0, args_1.getStringFlag)(flags, ['path']) ?? 'db/migrations';
|
|
96
|
+
const fullPath = (0, node_path_1.resolve)(migrationsPath);
|
|
97
|
+
if (!(0, node_fs_1.existsSync)(fullPath)) {
|
|
98
|
+
throw new Error(`Migrations directory not found: ${fullPath}`);
|
|
99
|
+
}
|
|
100
|
+
// Read and validate migration files
|
|
101
|
+
const files = (0, node_fs_1.readdirSync)(fullPath)
|
|
102
|
+
.filter((f) => f.endsWith('.sql'))
|
|
103
|
+
.sort();
|
|
104
|
+
if (files.length === 0) {
|
|
105
|
+
console.log('No migration files found');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// Validate filenames
|
|
109
|
+
for (const file of files) {
|
|
110
|
+
if (!MIGRATION_REGEX.test(file)) {
|
|
111
|
+
throw new Error(`Invalid migration filename: ${file}\n` +
|
|
112
|
+
`Expected format: YYYYMMDDHHmmss_description.sql\n` +
|
|
113
|
+
`Example: 20260128100000_create_users.sql`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Read file contents
|
|
117
|
+
const migrations = files.map((file) => ({
|
|
118
|
+
name: file,
|
|
119
|
+
sql: (0, node_fs_1.readFileSync)((0, node_path_1.join)(fullPath, file), 'utf-8'),
|
|
120
|
+
}));
|
|
121
|
+
console.log(`Found ${migrations.length} migration files`);
|
|
122
|
+
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/db/migrate`, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
body: { migrations },
|
|
125
|
+
});
|
|
126
|
+
if (jsonOutput) {
|
|
127
|
+
(0, output_1.outputJson)(response, jsonOutput);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const applied = response.applied ?? [];
|
|
131
|
+
if (applied.length === 0) {
|
|
132
|
+
console.log('No new migrations to apply');
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
console.log(`Applied ${applied.length} migrations:`);
|
|
136
|
+
for (const m of applied) {
|
|
137
|
+
console.log(` ✓ ${m.name}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function handleMigrations(positionals, flags, context, jsonOutput) {
|
|
143
|
+
const { projectId, envName } = resolveProjectEnv(positionals, flags, context);
|
|
144
|
+
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/db/migrations`);
|
|
145
|
+
if (jsonOutput) {
|
|
146
|
+
(0, output_1.outputJson)(response, jsonOutput);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
const migrations = response.migrations ?? [];
|
|
150
|
+
if (migrations.length === 0) {
|
|
151
|
+
console.log('No migrations have been applied');
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
console.log(`Applied migrations (${migrations.length}):\n`);
|
|
155
|
+
console.log(' Name Applied At');
|
|
156
|
+
console.log(' ' + '-'.repeat(70));
|
|
157
|
+
for (const m of migrations) {
|
|
158
|
+
const date = new Date(m.applied_at).toLocaleString();
|
|
159
|
+
console.log(` ${m.name.padEnd(40)} ${date}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function handleNew(positionals, flags) {
|
|
165
|
+
const description = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['name']);
|
|
166
|
+
if (!description) {
|
|
167
|
+
throw new Error('Usage: eve db new <description>\nExample: eve db new create_users');
|
|
168
|
+
}
|
|
169
|
+
// Validate description format
|
|
170
|
+
const normalizedDescription = description.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, '');
|
|
171
|
+
if (!normalizedDescription || !/^[a-z0-9_]+$/.test(normalizedDescription)) {
|
|
172
|
+
throw new Error('Description must contain only lowercase letters, numbers, and underscores');
|
|
173
|
+
}
|
|
174
|
+
// Generate timestamp (YYYYMMDDHHmmss in UTC)
|
|
175
|
+
const now = new Date();
|
|
176
|
+
const timestamp = [
|
|
177
|
+
now.getUTCFullYear(),
|
|
178
|
+
String(now.getUTCMonth() + 1).padStart(2, '0'),
|
|
179
|
+
String(now.getUTCDate()).padStart(2, '0'),
|
|
180
|
+
String(now.getUTCHours()).padStart(2, '0'),
|
|
181
|
+
String(now.getUTCMinutes()).padStart(2, '0'),
|
|
182
|
+
String(now.getUTCSeconds()).padStart(2, '0'),
|
|
183
|
+
].join('');
|
|
184
|
+
const filename = `${timestamp}_${normalizedDescription}.sql`;
|
|
185
|
+
const migrationsPath = (0, args_1.getStringFlag)(flags, ['path']) ?? 'db/migrations';
|
|
186
|
+
const fullPath = (0, node_path_1.resolve)(migrationsPath);
|
|
187
|
+
// Create directory if it doesn't exist
|
|
188
|
+
if (!(0, node_fs_1.existsSync)(fullPath)) {
|
|
189
|
+
(0, node_fs_1.mkdirSync)(fullPath, { recursive: true });
|
|
190
|
+
}
|
|
191
|
+
const filePath = (0, node_path_1.join)(fullPath, filename);
|
|
192
|
+
// Check if file already exists
|
|
193
|
+
if ((0, node_fs_1.existsSync)(filePath)) {
|
|
194
|
+
throw new Error(`Migration file already exists: ${filePath}`);
|
|
195
|
+
}
|
|
196
|
+
const template = `-- Migration: ${normalizedDescription}
|
|
197
|
+
-- Created: ${now.toISOString()}
|
|
198
|
+
|
|
199
|
+
-- Write your SQL migration here
|
|
200
|
+
|
|
201
|
+
`;
|
|
202
|
+
(0, node_fs_1.writeFileSync)(filePath, template);
|
|
203
|
+
console.log(`Created: ${filePath}`);
|
|
204
|
+
}
|
package/dist/commands/env.js
CHANGED
|
@@ -19,12 +19,15 @@ async function handleEnv(subcommand, positionals, flags, context) {
|
|
|
19
19
|
return handleCreate(positionals, flags, context, json);
|
|
20
20
|
case 'deploy':
|
|
21
21
|
return handleDeploy(positionals, flags, context, json);
|
|
22
|
+
case 'logs':
|
|
23
|
+
return handleLogs(positionals, flags, context, json);
|
|
22
24
|
default:
|
|
23
|
-
throw new Error('Usage: eve env <list|show|create|deploy>\n' +
|
|
25
|
+
throw new Error('Usage: eve env <list|show|create|deploy|logs>\n' +
|
|
24
26
|
' list [project] - list environments for a project\n' +
|
|
25
27
|
' show <project> <name> - show details of an environment\n' +
|
|
26
28
|
' create <name> --type=<type> [options] - create an environment\n' +
|
|
27
|
-
' deploy <project> <name> [--tag=<tag>] [--release-tag=<tag>] - deploy to an environment'
|
|
29
|
+
' deploy <project> <name> [--tag=<tag>] [--release-tag=<tag>] - deploy to an environment\n' +
|
|
30
|
+
' logs <project> <env> <service> [--since <seconds>] [--tail <n>] [--grep <text>] - get service logs');
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
// ============================================================================
|
|
@@ -202,6 +205,35 @@ async function handleDeploy(positionals, flags, context, json) {
|
|
|
202
205
|
console.log(` Namespace: ${response.environment.namespace || '(none)'}`);
|
|
203
206
|
}
|
|
204
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* eve env logs <project> <env> <service>
|
|
210
|
+
* Fetch logs for a service in an environment (k8s-only)
|
|
211
|
+
*/
|
|
212
|
+
async function handleLogs(positionals, flags, context, json) {
|
|
213
|
+
const projectId = positionals[0] ?? (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
|
|
214
|
+
const envName = positionals[1] ?? (0, args_1.getStringFlag)(flags, ['env', 'name']);
|
|
215
|
+
const service = positionals[2] ?? (0, args_1.getStringFlag)(flags, ['service']);
|
|
216
|
+
if (!projectId || !envName || !service) {
|
|
217
|
+
throw new Error('Usage: eve env logs <project> <env> <service> [--since <seconds>] [--tail <n>] [--grep <text>]');
|
|
218
|
+
}
|
|
219
|
+
const query = buildQuery({
|
|
220
|
+
since: (0, args_1.getStringFlag)(flags, ['since']),
|
|
221
|
+
tail: (0, args_1.getStringFlag)(flags, ['tail']),
|
|
222
|
+
grep: (0, args_1.getStringFlag)(flags, ['grep']),
|
|
223
|
+
});
|
|
224
|
+
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/envs/${envName}/services/${service}/logs${query}`);
|
|
225
|
+
if (json) {
|
|
226
|
+
(0, output_1.outputJson)(response, json);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (!response.logs.length) {
|
|
230
|
+
console.log('No logs found.');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
for (const entry of response.logs) {
|
|
234
|
+
console.log(`[${entry.timestamp}] ${entry.line}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
205
237
|
// ============================================================================
|
|
206
238
|
// Helper Functions
|
|
207
239
|
// ============================================================================
|
package/dist/commands/harness.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handleHarness = handleHarness;
|
|
4
|
+
const args_1 = require("../lib/args");
|
|
4
5
|
const client_1 = require("../lib/client");
|
|
5
6
|
const output_1 = require("../lib/output");
|
|
6
7
|
async function handleHarness(subcommand, positionals, flags, context) {
|
|
7
8
|
const json = Boolean(flags.json);
|
|
9
|
+
const includeCapabilities = (0, args_1.getBooleanFlag)(flags, ['capabilities']) ?? false;
|
|
8
10
|
switch (subcommand) {
|
|
9
11
|
case 'list': {
|
|
10
12
|
const response = await (0, client_1.requestJson)(context, '/harnesses');
|
|
@@ -12,7 +14,7 @@ async function handleHarness(subcommand, positionals, flags, context) {
|
|
|
12
14
|
(0, output_1.outputJson)(response, json);
|
|
13
15
|
return;
|
|
14
16
|
}
|
|
15
|
-
renderHarnessList(response.data);
|
|
17
|
+
renderHarnessList(response.data, includeCapabilities);
|
|
16
18
|
return;
|
|
17
19
|
}
|
|
18
20
|
case 'get': {
|
|
@@ -31,7 +33,11 @@ async function handleHarness(subcommand, positionals, flags, context) {
|
|
|
31
33
|
throw new Error('Usage: eve harness <list|get>');
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
|
-
function renderHarnessList(harnesses) {
|
|
36
|
+
function renderHarnessList(harnesses, includeCapabilities) {
|
|
37
|
+
if (includeCapabilities) {
|
|
38
|
+
renderHarnessCapabilities(harnesses);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
35
41
|
const rows = harnesses.map((harness) => {
|
|
36
42
|
const variants = harness.variants
|
|
37
43
|
.map((variant) => variant.name)
|
|
@@ -79,6 +85,48 @@ function renderHarnessDetail(harness) {
|
|
|
79
85
|
for (const instruction of harness.auth.instructions) {
|
|
80
86
|
console.log(` - ${instruction}`);
|
|
81
87
|
}
|
|
88
|
+
if (harness.capabilities) {
|
|
89
|
+
renderCapabilitiesBlock(harness.capabilities);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function renderHarnessCapabilities(harnesses) {
|
|
93
|
+
for (const harness of harnesses) {
|
|
94
|
+
console.log(`Harness: ${formatHarnessLabel(harness)}`);
|
|
95
|
+
console.log(` Auth: ${harness.auth.available ? 'ready' : 'missing'} (${harness.auth.reason})`);
|
|
96
|
+
const variants = harness.variants.length
|
|
97
|
+
? harness.variants.map((variant) => variant.name).join(', ')
|
|
98
|
+
: 'default';
|
|
99
|
+
console.log(` Variants: ${variants}`);
|
|
100
|
+
if (harness.capabilities) {
|
|
101
|
+
renderCapabilitiesBlock(harness.capabilities, ' ');
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
console.log(' Capabilities: (not reported)');
|
|
105
|
+
}
|
|
106
|
+
console.log('');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function renderCapabilitiesBlock(capabilities, prefix = '') {
|
|
110
|
+
const modelSupport = capabilities.supports_model ? 'supported' : 'not supported';
|
|
111
|
+
const examples = capabilities.model_examples?.length
|
|
112
|
+
? ` (examples: ${capabilities.model_examples.join(', ')})`
|
|
113
|
+
: '';
|
|
114
|
+
const modelNotes = capabilities.model_notes ? ` — ${capabilities.model_notes}` : '';
|
|
115
|
+
console.log(`${prefix}Model: ${modelSupport}${examples}${modelNotes}`);
|
|
116
|
+
const reasoning = capabilities.reasoning;
|
|
117
|
+
if (!reasoning) {
|
|
118
|
+
console.log(`${prefix}Reasoning: (unknown)`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (!reasoning.supported) {
|
|
122
|
+
const notes = reasoning.notes ? ` — ${reasoning.notes}` : '';
|
|
123
|
+
console.log(`${prefix}Reasoning: not supported${notes}`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const levels = reasoning.levels?.length ? reasoning.levels.join(', ') : 'unspecified';
|
|
127
|
+
const mode = reasoning.mode ? ` (${reasoning.mode})` : '';
|
|
128
|
+
const notes = reasoning.notes ? ` — ${reasoning.notes}` : '';
|
|
129
|
+
console.log(`${prefix}Reasoning: ${levels}${mode}${notes}`);
|
|
82
130
|
}
|
|
83
131
|
function formatHarnessLabel(harness) {
|
|
84
132
|
if (!harness.aliases?.length)
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.handleInit = handleInit;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const os = __importStar(require("node:os"));
|
|
40
|
+
const node_child_process_1 = require("node:child_process");
|
|
41
|
+
const args_1 = require("../lib/args");
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Constants
|
|
44
|
+
// ============================================================================
|
|
45
|
+
const DEFAULT_TEMPLATE = 'https://github.com/incept5/eve-horizon-starter';
|
|
46
|
+
const DEFAULT_BRANCH = 'main';
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Main Handler
|
|
49
|
+
// ============================================================================
|
|
50
|
+
/**
|
|
51
|
+
* eve init [directory] [--template <url>] [--branch <branch>]
|
|
52
|
+
*
|
|
53
|
+
* Initialize a new Eve Horizon project from a template.
|
|
54
|
+
* Downloads the template, strips git history, and sets up a fresh project.
|
|
55
|
+
*/
|
|
56
|
+
async function handleInit(positionals, flags) {
|
|
57
|
+
const targetDir = positionals[0] || '.';
|
|
58
|
+
const template = (0, args_1.getStringFlag)(flags, ['template', 't']) || DEFAULT_TEMPLATE;
|
|
59
|
+
const branch = (0, args_1.getStringFlag)(flags, ['branch', 'b']) || DEFAULT_BRANCH;
|
|
60
|
+
const skipSkills = Boolean(flags['skip-skills']);
|
|
61
|
+
// Resolve target directory
|
|
62
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
63
|
+
const targetName = path.basename(resolvedTarget);
|
|
64
|
+
const isCurrentDir = targetDir === '.';
|
|
65
|
+
// Validate target directory
|
|
66
|
+
if (isCurrentDir) {
|
|
67
|
+
// Current directory must be empty or not exist
|
|
68
|
+
if (fs.existsSync(resolvedTarget)) {
|
|
69
|
+
const entries = fs.readdirSync(resolvedTarget);
|
|
70
|
+
// Allow hidden files like .git, but fail if there's substantial content
|
|
71
|
+
const nonHiddenEntries = entries.filter(e => !e.startsWith('.'));
|
|
72
|
+
if (nonHiddenEntries.length > 0) {
|
|
73
|
+
throw new Error(`Current directory is not empty. Remove existing files or specify a new directory name:\n` +
|
|
74
|
+
` eve init my-project`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Named directory must not exist or be empty
|
|
80
|
+
if (fs.existsSync(resolvedTarget)) {
|
|
81
|
+
const entries = fs.readdirSync(resolvedTarget);
|
|
82
|
+
if (entries.length > 0) {
|
|
83
|
+
throw new Error(`Directory '${targetDir}' already exists and is not empty.`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
console.log(`Initializing Eve Horizon project${isCurrentDir ? '' : ` in '${targetName}'`}...`);
|
|
88
|
+
console.log(`Template: ${template}`);
|
|
89
|
+
console.log(`Branch: ${branch}`);
|
|
90
|
+
console.log('');
|
|
91
|
+
// Create temp directory for clone
|
|
92
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'eve-init-'));
|
|
93
|
+
try {
|
|
94
|
+
// Clone template
|
|
95
|
+
console.log('Downloading template...');
|
|
96
|
+
const cloneResult = (0, node_child_process_1.spawnSync)('git', ['clone', '--depth=1', `--branch=${branch}`, template, tempDir], {
|
|
97
|
+
encoding: 'utf8',
|
|
98
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
99
|
+
});
|
|
100
|
+
if (cloneResult.status !== 0) {
|
|
101
|
+
throw new Error(`Failed to clone template:\n${cloneResult.stderr || cloneResult.stdout}`);
|
|
102
|
+
}
|
|
103
|
+
// Remove .git from cloned template
|
|
104
|
+
const gitDir = path.join(tempDir, '.git');
|
|
105
|
+
if (fs.existsSync(gitDir)) {
|
|
106
|
+
fs.rmSync(gitDir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
// Create target directory if needed
|
|
109
|
+
if (!fs.existsSync(resolvedTarget)) {
|
|
110
|
+
fs.mkdirSync(resolvedTarget, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
// Copy template contents to target
|
|
113
|
+
console.log('Setting up project...');
|
|
114
|
+
copyDirRecursive(tempDir, resolvedTarget);
|
|
115
|
+
// Initialize git
|
|
116
|
+
console.log('Initializing git repository...');
|
|
117
|
+
(0, node_child_process_1.execSync)('git init', { cwd: resolvedTarget, stdio: 'pipe' });
|
|
118
|
+
(0, node_child_process_1.execSync)('git add -A', { cwd: resolvedTarget, stdio: 'pipe' });
|
|
119
|
+
(0, node_child_process_1.execSync)('git commit -m "Initial commit from eve-horizon-starter"', {
|
|
120
|
+
cwd: resolvedTarget,
|
|
121
|
+
stdio: 'pipe',
|
|
122
|
+
});
|
|
123
|
+
// Install skills
|
|
124
|
+
if (!skipSkills) {
|
|
125
|
+
console.log('');
|
|
126
|
+
console.log('Installing skills...');
|
|
127
|
+
await installSkills(resolvedTarget);
|
|
128
|
+
}
|
|
129
|
+
// Success message
|
|
130
|
+
console.log('');
|
|
131
|
+
console.log('Project initialized successfully!');
|
|
132
|
+
console.log('');
|
|
133
|
+
console.log('Next steps:');
|
|
134
|
+
if (!isCurrentDir) {
|
|
135
|
+
console.log(` 1. cd ${targetName}`);
|
|
136
|
+
console.log(' 2. Start your AI coding agent (e.g., claude, cursor)');
|
|
137
|
+
console.log(' 3. Ask: "Run the eve-new-project-setup skill"');
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.log(' 1. Start your AI coding agent (e.g., claude, cursor)');
|
|
141
|
+
console.log(' 2. Ask: "Run the eve-new-project-setup skill"');
|
|
142
|
+
}
|
|
143
|
+
console.log('');
|
|
144
|
+
console.log('The setup skill will:');
|
|
145
|
+
console.log(' - Install the Eve CLI if needed');
|
|
146
|
+
console.log(' - Configure your profile and authentication');
|
|
147
|
+
console.log(' - Set up your project manifest');
|
|
148
|
+
console.log(' - Help you set up your own Git remote');
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
// Clean up temp directory
|
|
152
|
+
if (fs.existsSync(tempDir)) {
|
|
153
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// Helper Functions
|
|
159
|
+
// ============================================================================
|
|
160
|
+
/**
|
|
161
|
+
* Recursively copy directory contents
|
|
162
|
+
*/
|
|
163
|
+
function copyDirRecursive(src, dest) {
|
|
164
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
165
|
+
for (const entry of entries) {
|
|
166
|
+
const srcPath = path.join(src, entry.name);
|
|
167
|
+
const destPath = path.join(dest, entry.name);
|
|
168
|
+
if (entry.isDirectory()) {
|
|
169
|
+
if (!fs.existsSync(destPath)) {
|
|
170
|
+
fs.mkdirSync(destPath, { recursive: true });
|
|
171
|
+
}
|
|
172
|
+
copyDirRecursive(srcPath, destPath);
|
|
173
|
+
}
|
|
174
|
+
else if (entry.isSymbolicLink()) {
|
|
175
|
+
const linkTarget = fs.readlinkSync(srcPath);
|
|
176
|
+
if (!fs.existsSync(destPath)) {
|
|
177
|
+
fs.symlinkSync(linkTarget, destPath);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
fs.copyFileSync(srcPath, destPath);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Install skills from skills.txt
|
|
187
|
+
* This reuses the logic from the skills command
|
|
188
|
+
*/
|
|
189
|
+
async function installSkills(projectRoot) {
|
|
190
|
+
const skillsTxt = path.join(projectRoot, 'skills.txt');
|
|
191
|
+
if (!fs.existsSync(skillsTxt)) {
|
|
192
|
+
console.log('No skills.txt found, skipping skill installation');
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// Check if openskills is available
|
|
196
|
+
const result = (0, node_child_process_1.spawnSync)('which', ['openskills'], { encoding: 'utf8' });
|
|
197
|
+
if (result.status !== 0) {
|
|
198
|
+
console.log('openskills CLI not found. Skills will be installed when you run:');
|
|
199
|
+
console.log(' npm install -g @anthropic/openskills');
|
|
200
|
+
console.log(' eve skills install');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Import and call the skills install logic
|
|
204
|
+
// We directly call the openskills commands here for simplicity
|
|
205
|
+
try {
|
|
206
|
+
const content = fs.readFileSync(skillsTxt, 'utf-8');
|
|
207
|
+
const lines = content.split('\n')
|
|
208
|
+
.map(line => line.split('#')[0].trim())
|
|
209
|
+
.filter(line => line.length > 0);
|
|
210
|
+
for (const source of lines) {
|
|
211
|
+
console.log(` Installing: ${source}`);
|
|
212
|
+
try {
|
|
213
|
+
(0, node_child_process_1.execSync)(`openskills install ${JSON.stringify(source)} --universal --yes`, {
|
|
214
|
+
cwd: projectRoot,
|
|
215
|
+
stdio: 'inherit',
|
|
216
|
+
timeout: 120000,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
console.log(` Warning: Failed to install ${source}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Ensure symlink
|
|
224
|
+
ensureSkillsSymlink(projectRoot);
|
|
225
|
+
// Sync AGENTS.md
|
|
226
|
+
try {
|
|
227
|
+
(0, node_child_process_1.execSync)('openskills sync --yes', {
|
|
228
|
+
cwd: projectRoot,
|
|
229
|
+
stdio: 'inherit',
|
|
230
|
+
timeout: 30000,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
console.log('Warning: Failed to sync AGENTS.md');
|
|
235
|
+
}
|
|
236
|
+
// Commit skill changes
|
|
237
|
+
try {
|
|
238
|
+
(0, node_child_process_1.execSync)('git add -A', { cwd: projectRoot, stdio: 'pipe' });
|
|
239
|
+
const hasChanges = (0, node_child_process_1.spawnSync)('git', ['diff', '--cached', '--quiet'], {
|
|
240
|
+
cwd: projectRoot,
|
|
241
|
+
encoding: 'utf8',
|
|
242
|
+
});
|
|
243
|
+
if (hasChanges.status !== 0) {
|
|
244
|
+
(0, node_child_process_1.execSync)('git commit -m "chore: install skills from skills.txt"', {
|
|
245
|
+
cwd: projectRoot,
|
|
246
|
+
stdio: 'pipe',
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Ignore commit failures
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
console.log('Warning: Failed to install some skills');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Ensure .claude/skills symlink points to .agent/skills
|
|
260
|
+
*/
|
|
261
|
+
function ensureSkillsSymlink(projectRoot) {
|
|
262
|
+
const agentSkills = path.join(projectRoot, '.agent', 'skills');
|
|
263
|
+
const claudeDir = path.join(projectRoot, '.claude');
|
|
264
|
+
const claudeSkills = path.join(claudeDir, 'skills');
|
|
265
|
+
if (!fs.existsSync(agentSkills)) {
|
|
266
|
+
fs.mkdirSync(agentSkills, { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
if (!fs.existsSync(claudeDir)) {
|
|
269
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
270
|
+
}
|
|
271
|
+
if (fs.existsSync(claudeSkills)) {
|
|
272
|
+
const stat = fs.lstatSync(claudeSkills);
|
|
273
|
+
if (stat.isSymbolicLink()) {
|
|
274
|
+
const target = fs.readlinkSync(claudeSkills);
|
|
275
|
+
if (target === '../.agent/skills' || target === agentSkills) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
fs.unlinkSync(claudeSkills);
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
fs.symlinkSync('../.agent/skills', claudeSkills);
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
// Ignore symlink failures
|
|
289
|
+
}
|
|
290
|
+
}
|
package/dist/commands/job.js
CHANGED
|
@@ -115,6 +115,10 @@ async function handleCreate(flags, context, json) {
|
|
|
115
115
|
const dueAt = (0, args_1.getStringFlag)(flags, ['due-at']);
|
|
116
116
|
// Scheduling hints
|
|
117
117
|
const harness = (0, args_1.getStringFlag)(flags, ['harness']);
|
|
118
|
+
const profile = (0, args_1.getStringFlag)(flags, ['profile']);
|
|
119
|
+
const variant = (0, args_1.getStringFlag)(flags, ['variant']);
|
|
120
|
+
const model = (0, args_1.getStringFlag)(flags, ['model']);
|
|
121
|
+
const reasoning = (0, args_1.getStringFlag)(flags, ['reasoning']);
|
|
118
122
|
const workerType = (0, args_1.getStringFlag)(flags, ['worker-type']);
|
|
119
123
|
const permission = (0, args_1.getStringFlag)(flags, ['permission']);
|
|
120
124
|
const timeout = (0, args_1.getStringFlag)(flags, ['timeout']);
|
|
@@ -171,10 +175,25 @@ async function handleCreate(flags, context, json) {
|
|
|
171
175
|
if (dueAt) {
|
|
172
176
|
body.due_at = dueAt;
|
|
173
177
|
}
|
|
178
|
+
if (harness) {
|
|
179
|
+
body.harness = harness;
|
|
180
|
+
}
|
|
181
|
+
if (profile) {
|
|
182
|
+
body.harness_profile = profile;
|
|
183
|
+
}
|
|
184
|
+
if (variant || model || reasoning) {
|
|
185
|
+
const allowedEfforts = new Set(['low', 'medium', 'high', 'x-high']);
|
|
186
|
+
if (reasoning && !allowedEfforts.has(reasoning)) {
|
|
187
|
+
throw new Error('--reasoning must be one of: low, medium, high, x-high');
|
|
188
|
+
}
|
|
189
|
+
body.harness_options = {
|
|
190
|
+
...(variant ? { variant } : {}),
|
|
191
|
+
...(model ? { model } : {}),
|
|
192
|
+
...(reasoning ? { reasoning_effort: reasoning } : {}),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
174
195
|
// Build hints object if any hint flags are provided
|
|
175
196
|
const hints = {};
|
|
176
|
-
if (harness)
|
|
177
|
-
hints.harness = harness;
|
|
178
197
|
if (workerType)
|
|
179
198
|
hints.worker_type = workerType;
|
|
180
199
|
if (permission)
|
package/dist/commands/project.js
CHANGED
|
@@ -95,6 +95,9 @@ async function handleProject(subcommand, positionals, flags, context) {
|
|
|
95
95
|
case 'sync': {
|
|
96
96
|
const dir = typeof flags.dir === 'string' ? flags.dir : process.cwd();
|
|
97
97
|
const manifestPath = (0, node_path_1.join)(dir, '.eve', 'manifest.yaml');
|
|
98
|
+
const validateSecretsFlag = flags['validate-secrets'] ?? flags.validate_secrets;
|
|
99
|
+
const validateSecrets = (0, args_1.toBoolean)(validateSecretsFlag) ?? false;
|
|
100
|
+
const strict = (0, args_1.toBoolean)(flags.strict) ?? false;
|
|
98
101
|
// Read manifest file
|
|
99
102
|
let yaml;
|
|
100
103
|
try {
|
|
@@ -123,7 +126,13 @@ async function handleProject(subcommand, positionals, flags, context) {
|
|
|
123
126
|
const projectIdFromManifest = projectMatch[1];
|
|
124
127
|
const response = await (0, client_1.requestJson)(context, `/projects/${projectIdFromManifest}/manifest`, {
|
|
125
128
|
method: 'POST',
|
|
126
|
-
body: {
|
|
129
|
+
body: {
|
|
130
|
+
yaml,
|
|
131
|
+
git_sha: gitSha,
|
|
132
|
+
branch,
|
|
133
|
+
validate_secrets: validateSecrets || strict,
|
|
134
|
+
strict,
|
|
135
|
+
},
|
|
127
136
|
});
|
|
128
137
|
if (json) {
|
|
129
138
|
(0, output_1.outputJson)(response, json);
|
|
@@ -141,6 +150,12 @@ async function handleProject(subcommand, positionals, flags, context) {
|
|
|
141
150
|
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
142
151
|
});
|
|
143
152
|
}
|
|
153
|
+
if (response.warnings && response.warnings.length > 0) {
|
|
154
|
+
console.log('\nWarnings:');
|
|
155
|
+
response.warnings.forEach((warning) => {
|
|
156
|
+
console.log(` - ${warning}`);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
144
159
|
}
|
|
145
160
|
return;
|
|
146
161
|
}
|
|
@@ -148,7 +163,13 @@ async function handleProject(subcommand, positionals, flags, context) {
|
|
|
148
163
|
}
|
|
149
164
|
const response = await (0, client_1.requestJson)(context, `/projects/${projectIdRaw}/manifest`, {
|
|
150
165
|
method: 'POST',
|
|
151
|
-
body: {
|
|
166
|
+
body: {
|
|
167
|
+
yaml,
|
|
168
|
+
git_sha: gitSha,
|
|
169
|
+
branch,
|
|
170
|
+
validate_secrets: validateSecrets || strict,
|
|
171
|
+
strict,
|
|
172
|
+
},
|
|
152
173
|
});
|
|
153
174
|
if (json) {
|
|
154
175
|
(0, output_1.outputJson)(response, json);
|
|
@@ -166,6 +187,12 @@ async function handleProject(subcommand, positionals, flags, context) {
|
|
|
166
187
|
console.log(` ${key}: ${JSON.stringify(value)}`);
|
|
167
188
|
});
|
|
168
189
|
}
|
|
190
|
+
if (response.warnings && response.warnings.length > 0) {
|
|
191
|
+
console.log('\nWarnings:');
|
|
192
|
+
response.warnings.forEach((warning) => {
|
|
193
|
+
console.log(` - ${warning}`);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
169
196
|
}
|
|
170
197
|
return;
|
|
171
198
|
}
|
package/dist/commands/secrets.js
CHANGED
|
@@ -60,22 +60,79 @@ async function handleSecrets(subcommand, positionals, flags, context) {
|
|
|
60
60
|
const filePath = typeof flags.file === 'string' ? flags.file : '.env';
|
|
61
61
|
const fileContents = (0, node_fs_1.readFileSync)(filePath, 'utf8');
|
|
62
62
|
const entries = parseEnvFile(fileContents);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
throw new Error(`No EVE_SECRET_* entries found in ${filePath}`);
|
|
63
|
+
if (entries.length === 0) {
|
|
64
|
+
throw new Error(`No entries found in ${filePath}`);
|
|
66
65
|
}
|
|
67
|
-
for (const [
|
|
68
|
-
const key = rawKey.slice('EVE_SECRET_'.length);
|
|
66
|
+
for (const [key, value] of entries) {
|
|
69
67
|
await (0, client_1.requestJson)(context, `${scopeBasePath(scope)}`, {
|
|
70
68
|
method: 'POST',
|
|
71
|
-
body: { key, value
|
|
69
|
+
body: { key, value },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
(0, output_1.outputJson)({ imported: entries.length }, json, `✓ Imported ${entries.length} secrets`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
case 'validate': {
|
|
76
|
+
const projectId = resolveProjectScope(flags, context);
|
|
77
|
+
const keys = parseKeys(positionals, flags);
|
|
78
|
+
const body = {};
|
|
79
|
+
if (keys.length > 0)
|
|
80
|
+
body.keys = keys;
|
|
81
|
+
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/secrets/validate`, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
body,
|
|
84
|
+
});
|
|
85
|
+
if (json) {
|
|
86
|
+
(0, output_1.outputJson)(response, json);
|
|
87
|
+
}
|
|
88
|
+
else if (response.missing.length === 0) {
|
|
89
|
+
console.log('✓ All required secrets are present');
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log('Missing secrets:');
|
|
93
|
+
response.missing.forEach((item) => {
|
|
94
|
+
console.log(`- ${item.key}`);
|
|
95
|
+
item.hints.forEach((hint) => console.log(` ${hint}`));
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
case 'ensure': {
|
|
101
|
+
const projectId = resolveProjectScope(flags, context);
|
|
102
|
+
const keys = parseKeys(positionals, flags);
|
|
103
|
+
if (keys.length === 0) {
|
|
104
|
+
throw new Error('Usage: eve secrets ensure --project <id> --keys <key1,key2>');
|
|
105
|
+
}
|
|
106
|
+
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/secrets/ensure`, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
body: { keys },
|
|
109
|
+
});
|
|
110
|
+
(0, output_1.outputJson)(response, json, `✓ Secrets ensured (${response.created.length} created)`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
case 'export': {
|
|
114
|
+
const projectId = resolveProjectScope(flags, context);
|
|
115
|
+
const keys = parseKeys(positionals, flags);
|
|
116
|
+
if (keys.length === 0) {
|
|
117
|
+
throw new Error('Usage: eve secrets export --project <id> --keys <key1,key2>');
|
|
118
|
+
}
|
|
119
|
+
const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/secrets/export`, {
|
|
120
|
+
method: 'POST',
|
|
121
|
+
body: { keys },
|
|
122
|
+
});
|
|
123
|
+
if (json) {
|
|
124
|
+
(0, output_1.outputJson)(response, json);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
console.log('Exported secrets (handle carefully):');
|
|
128
|
+
response.data.forEach((item) => {
|
|
129
|
+
console.log(`${item.key}=${item.value}`);
|
|
72
130
|
});
|
|
73
131
|
}
|
|
74
|
-
(0, output_1.outputJson)({ imported: filtered.length }, json, `✓ Imported ${filtered.length} secrets`);
|
|
75
132
|
return;
|
|
76
133
|
}
|
|
77
134
|
default:
|
|
78
|
-
throw new Error('Usage: eve secrets <set|list|show|delete|import>');
|
|
135
|
+
throw new Error('Usage: eve secrets <set|list|show|delete|import|validate|ensure|export>');
|
|
79
136
|
}
|
|
80
137
|
}
|
|
81
138
|
function resolveScope(flags, context) {
|
|
@@ -117,6 +174,13 @@ function scopeBasePath(scope) {
|
|
|
117
174
|
return `/users/${scope.scopeId}/secrets`;
|
|
118
175
|
}
|
|
119
176
|
}
|
|
177
|
+
function resolveProjectScope(flags, context) {
|
|
178
|
+
const scope = resolveScope(flags, context);
|
|
179
|
+
if (scope.scopeType !== 'project') {
|
|
180
|
+
throw new Error('This command requires --project (or a project default profile).');
|
|
181
|
+
}
|
|
182
|
+
return scope.scopeId;
|
|
183
|
+
}
|
|
120
184
|
function buildQuery(params) {
|
|
121
185
|
const search = new URLSearchParams();
|
|
122
186
|
Object.entries(params).forEach(([key, value]) => {
|
|
@@ -145,3 +209,10 @@ function parseEnvFile(contents) {
|
|
|
145
209
|
}
|
|
146
210
|
return entries;
|
|
147
211
|
}
|
|
212
|
+
function parseKeys(positionals, flags) {
|
|
213
|
+
const positionalKeys = positionals.filter((value) => typeof value === 'string' && value.length > 0);
|
|
214
|
+
const flagKeys = typeof flags.keys === 'string'
|
|
215
|
+
? flags.keys.split(',').map((value) => value.trim()).filter(Boolean)
|
|
216
|
+
: [];
|
|
217
|
+
return Array.from(new Set([...positionalKeys, ...flagKeys]));
|
|
218
|
+
}
|
package/dist/commands/system.js
CHANGED
|
@@ -32,8 +32,10 @@ async function handleSystem(subcommand, positionals, flags, context) {
|
|
|
32
32
|
return handleEvents(flags, context, json);
|
|
33
33
|
case 'config':
|
|
34
34
|
return handleConfig(context, json);
|
|
35
|
+
case 'settings':
|
|
36
|
+
return handleSettings(positionals, flags, context, json);
|
|
35
37
|
default:
|
|
36
|
-
throw new Error('Usage: eve system <status|health|jobs|envs|logs|pods|events|config>');
|
|
38
|
+
throw new Error('Usage: eve system <status|health|jobs|envs|logs|pods|events|config|settings>');
|
|
37
39
|
}
|
|
38
40
|
}
|
|
39
41
|
// ============================================================================
|
|
@@ -316,6 +318,75 @@ async function handleConfig(context, json) {
|
|
|
316
318
|
response.deployments.forEach((deployment) => console.log(` - ${deployment}`));
|
|
317
319
|
}
|
|
318
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* eve system settings [get <key>] [set <key> <value>]
|
|
323
|
+
* Admin only: Get or set system settings
|
|
324
|
+
*/
|
|
325
|
+
async function handleSettings(positionals, flags, context, json) {
|
|
326
|
+
const action = positionals[0];
|
|
327
|
+
if (action === 'set') {
|
|
328
|
+
const key = positionals[1];
|
|
329
|
+
const value = positionals[2];
|
|
330
|
+
if (!key || !value) {
|
|
331
|
+
throw new Error('Usage: eve system settings set <key> <value>');
|
|
332
|
+
}
|
|
333
|
+
const body = { value };
|
|
334
|
+
const response = await (0, client_1.requestJson)(context, `/system/settings/${key}`, {
|
|
335
|
+
method: 'PUT',
|
|
336
|
+
body: JSON.stringify(body),
|
|
337
|
+
});
|
|
338
|
+
if (json) {
|
|
339
|
+
(0, output_1.outputJson)(response, json);
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
console.log(`Setting '${key}' updated:`);
|
|
343
|
+
console.log(` Value: ${response.value}`);
|
|
344
|
+
console.log(` Updated: ${response.updated_at}`);
|
|
345
|
+
console.log(` By: ${response.updated_by}`);
|
|
346
|
+
}
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
// Default: get all or get specific
|
|
350
|
+
const key = positionals[0];
|
|
351
|
+
if (key) {
|
|
352
|
+
const response = await (0, client_1.requestJson)(context, `/system/settings/${key}`);
|
|
353
|
+
if (json) {
|
|
354
|
+
(0, output_1.outputJson)(response, json);
|
|
355
|
+
}
|
|
356
|
+
else {
|
|
357
|
+
console.log(`Setting: ${response.key}`);
|
|
358
|
+
console.log(` Value: ${response.value}`);
|
|
359
|
+
if (response.description) {
|
|
360
|
+
console.log(` Description: ${response.description}`);
|
|
361
|
+
}
|
|
362
|
+
console.log(` Updated: ${response.updated_at}`);
|
|
363
|
+
console.log(` By: ${response.updated_by}`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
const response = await (0, client_1.requestJson)(context, '/system/settings');
|
|
368
|
+
if (json) {
|
|
369
|
+
(0, output_1.outputJson)(response, json);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
if (response.length === 0) {
|
|
373
|
+
console.log('No system settings found.');
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
console.log('System Settings:');
|
|
377
|
+
console.log('');
|
|
378
|
+
for (const setting of response) {
|
|
379
|
+
console.log(` ${setting.key}:`);
|
|
380
|
+
console.log(` Value: ${setting.value}`);
|
|
381
|
+
if (setting.description) {
|
|
382
|
+
console.log(` Description: ${setting.description}`);
|
|
383
|
+
}
|
|
384
|
+
console.log(` Updated: ${setting.updated_at} by ${setting.updated_by}`);
|
|
385
|
+
console.log('');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
319
390
|
// ============================================================================
|
|
320
391
|
// Helper Functions
|
|
321
392
|
// ============================================================================
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,8 @@ const db_1 = require("./commands/db");
|
|
|
21
21
|
const event_1 = require("./commands/event");
|
|
22
22
|
const skills_1 = require("./commands/skills");
|
|
23
23
|
const admin_1 = require("./commands/admin");
|
|
24
|
+
const agents_1 = require("./commands/agents");
|
|
25
|
+
const init_1 = require("./commands/init");
|
|
24
26
|
async function main() {
|
|
25
27
|
const { flags, positionals } = (0, args_1.parseArgs)(process.argv.slice(2));
|
|
26
28
|
const command = positionals[0];
|
|
@@ -91,9 +93,16 @@ async function main() {
|
|
|
91
93
|
case 'skills':
|
|
92
94
|
await (0, skills_1.handleSkills)(subcommand, rest, flags);
|
|
93
95
|
return;
|
|
96
|
+
case 'agents':
|
|
97
|
+
await (0, agents_1.handleAgents)(subcommand, rest, flags, context);
|
|
98
|
+
return;
|
|
94
99
|
case 'admin':
|
|
95
100
|
await (0, admin_1.handleAdmin)(subcommand, rest, flags, context);
|
|
96
101
|
return;
|
|
102
|
+
case 'init':
|
|
103
|
+
// init doesn't use subcommands - first positional is directory name
|
|
104
|
+
await (0, init_1.handleInit)(subcommand ? [subcommand, ...rest] : rest, flags);
|
|
105
|
+
return;
|
|
97
106
|
default:
|
|
98
107
|
(0, help_1.showMainHelp)();
|
|
99
108
|
}
|
package/dist/lib/help.js
CHANGED
|
@@ -89,6 +89,8 @@ exports.HELP = {
|
|
|
89
89
|
options: [
|
|
90
90
|
'<project> Project ID (uses profile default if omitted)',
|
|
91
91
|
'--path <path> Path to manifest (default: .eve/manifest.yaml)',
|
|
92
|
+
'--validate-secrets Validate manifest required secrets',
|
|
93
|
+
'--strict Fail sync if required secrets are missing',
|
|
92
94
|
],
|
|
93
95
|
examples: [
|
|
94
96
|
'eve project sync',
|
|
@@ -125,16 +127,44 @@ exports.HELP = {
|
|
|
125
127
|
usage: 'eve secrets delete <key> [--project <id>|--org <id>|--user <id>]',
|
|
126
128
|
},
|
|
127
129
|
import: {
|
|
128
|
-
description: 'Import
|
|
130
|
+
description: 'Import env entries from an env file',
|
|
129
131
|
usage: 'eve secrets import [--file <path>] [--project <id>|--org <id>|--user <id>]',
|
|
130
132
|
options: [
|
|
131
133
|
'--file <path> Defaults to .env',
|
|
132
134
|
],
|
|
133
135
|
},
|
|
136
|
+
validate: {
|
|
137
|
+
description: 'Validate manifest-required secrets for a project',
|
|
138
|
+
usage: 'eve secrets validate --project <id> [--keys <k1,k2>]',
|
|
139
|
+
options: [
|
|
140
|
+
'--project <id> Project ID (uses profile default)',
|
|
141
|
+
'--keys <k1,k2> Explicit keys to validate (default: latest manifest)',
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
ensure: {
|
|
145
|
+
description: 'Ensure safe secrets exist at project scope',
|
|
146
|
+
usage: 'eve secrets ensure --project <id> --keys <k1,k2>',
|
|
147
|
+
options: [
|
|
148
|
+
'--project <id> Project ID (uses profile default)',
|
|
149
|
+
'--keys <k1,k2> Keys to ensure (allowlist only)',
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
export: {
|
|
153
|
+
description: 'Export safe secrets for external configuration',
|
|
154
|
+
usage: 'eve secrets export --project <id> --keys <k1,k2> [--json]',
|
|
155
|
+
options: [
|
|
156
|
+
'--project <id> Project ID (uses profile default)',
|
|
157
|
+
'--keys <k1,k2> Keys to export (allowlist only)',
|
|
158
|
+
'--json JSON output',
|
|
159
|
+
],
|
|
160
|
+
},
|
|
134
161
|
},
|
|
135
162
|
examples: [
|
|
136
163
|
'eve secrets set GITHUB_TOKEN ghp_xxx --project proj_xxx --type github_token',
|
|
137
164
|
'eve secrets show GITHUB_TOKEN --project proj_xxx',
|
|
165
|
+
'eve secrets validate --project proj_xxx',
|
|
166
|
+
'eve secrets ensure --project proj_xxx --keys GITHUB_WEBHOOK_SECRET',
|
|
167
|
+
'eve secrets export --project proj_xxx --keys GITHUB_WEBHOOK_SECRET',
|
|
138
168
|
],
|
|
139
169
|
},
|
|
140
170
|
job: {
|
|
@@ -161,8 +191,14 @@ Jobs default to 'ready' phase, making them immediately schedulable.`,
|
|
|
161
191
|
'--defer-until <date> Hide until date (ISO 8601)',
|
|
162
192
|
'--due-at <date> Deadline (ISO 8601)',
|
|
163
193
|
'',
|
|
194
|
+
'Harness selection (top-level job fields):',
|
|
195
|
+
'--harness <name> Preferred harness, e.g., mclaude',
|
|
196
|
+
'--profile <name> Harness profile name',
|
|
197
|
+
'--variant <name> Harness variant preset',
|
|
198
|
+
'--model <name> Model override for harness',
|
|
199
|
+
'--reasoning <level> Reasoning effort: low|medium|high|x-high',
|
|
200
|
+
'',
|
|
164
201
|
'Scheduling hints (used by scheduler when claiming):',
|
|
165
|
-
'--harness <name> Preferred harness, e.g., mclaude:fast',
|
|
166
202
|
'--worker-type <type> Worker type preference',
|
|
167
203
|
'--permission <policy> Permission policy: default, auto_edit, yolo',
|
|
168
204
|
'--timeout <seconds> Execution timeout',
|
|
@@ -318,7 +354,7 @@ Jobs default to 'ready' phase, making them immediately schedulable.`,
|
|
|
318
354
|
usage: 'eve job claim <job-id> [--agent <id>] [--harness <name>]',
|
|
319
355
|
options: [
|
|
320
356
|
'--agent <id> Agent identifier (default: $EVE_AGENT_ID or cli-user)',
|
|
321
|
-
'--harness <name> Harness to use (overrides
|
|
357
|
+
'--harness <name> Harness to use (overrides job harness)',
|
|
322
358
|
'',
|
|
323
359
|
'NOTE: This is typically called by the scheduler or by agents creating',
|
|
324
360
|
'sub-jobs. For normal workflows, jobs are auto-scheduled when ready.',
|
|
@@ -408,7 +444,10 @@ Jobs default to 'ready' phase, making them immediately schedulable.`,
|
|
|
408
444
|
subcommands: {
|
|
409
445
|
list: {
|
|
410
446
|
description: 'List available harnesses',
|
|
411
|
-
usage: 'eve harness list',
|
|
447
|
+
usage: 'eve harness list [--capabilities]',
|
|
448
|
+
options: [
|
|
449
|
+
'--capabilities Show model/reasoning capability hints',
|
|
450
|
+
],
|
|
412
451
|
},
|
|
413
452
|
get: {
|
|
414
453
|
description: 'Get harness details and auth requirements',
|
|
@@ -418,6 +457,26 @@ Jobs default to 'ready' phase, making them immediately schedulable.`,
|
|
|
418
457
|
},
|
|
419
458
|
examples: ['eve harness list', 'eve harness get mclaude'],
|
|
420
459
|
},
|
|
460
|
+
agents: {
|
|
461
|
+
description: 'Inspect agent policy config and harness capabilities for orchestration. Default profile: primary-orchestrator.',
|
|
462
|
+
usage: 'eve agents config [--path <dir>] [--no-harnesses]',
|
|
463
|
+
subcommands: {
|
|
464
|
+
config: {
|
|
465
|
+
description: 'Show agent policy (profiles/councils) and harness availability',
|
|
466
|
+
usage: 'eve agents config [--path <dir>] [--no-harnesses]',
|
|
467
|
+
options: [
|
|
468
|
+
'--path <dir> Repository root to inspect (default: cwd)',
|
|
469
|
+
'--no-harnesses Skip harness availability lookup',
|
|
470
|
+
],
|
|
471
|
+
examples: [
|
|
472
|
+
'eve agents config',
|
|
473
|
+
'eve agents config --json',
|
|
474
|
+
'eve agents config --path ../my-repo',
|
|
475
|
+
],
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
examples: ['eve agents config --json'],
|
|
479
|
+
},
|
|
421
480
|
profile: {
|
|
422
481
|
description: `Manage CLI profiles. Profiles store defaults (API URL, org, project) so you don't
|
|
423
482
|
have to specify them on every command. Useful when working with multiple environments.`,
|
|
@@ -608,8 +667,29 @@ for cloud deployments. Credentials are stored per-profile.`,
|
|
|
608
667
|
'eve env deploy proj_xxx staging --release-tag v1.2.3',
|
|
609
668
|
],
|
|
610
669
|
},
|
|
670
|
+
logs: {
|
|
671
|
+
description: 'Fetch logs for a service in an environment (k8s-only)',
|
|
672
|
+
usage: 'eve env logs <project> <env> <service> [--since <seconds>] [--tail <n>] [--grep <text>]',
|
|
673
|
+
options: [
|
|
674
|
+
'<project> Project ID or slug',
|
|
675
|
+
'<env> Environment name (staging, production, test)',
|
|
676
|
+
'<service> Service name from manifest',
|
|
677
|
+
'--since <seconds> Seconds since now (optional)',
|
|
678
|
+
'--tail <n> Tail line count (optional)',
|
|
679
|
+
'--grep <text> Filter lines containing text (optional)',
|
|
680
|
+
],
|
|
681
|
+
examples: [
|
|
682
|
+
'eve env logs proj_xxx staging api --tail 200',
|
|
683
|
+
'eve env logs proj_xxx staging api --since 3600 --grep ERROR',
|
|
684
|
+
],
|
|
685
|
+
},
|
|
611
686
|
},
|
|
612
|
-
examples: [
|
|
687
|
+
examples: [
|
|
688
|
+
'eve env list',
|
|
689
|
+
'eve env create test --type=persistent',
|
|
690
|
+
'eve env deploy proj_xxx staging',
|
|
691
|
+
'eve env logs proj_xxx staging api --tail 200',
|
|
692
|
+
],
|
|
613
693
|
},
|
|
614
694
|
api: {
|
|
615
695
|
description: 'Explore project API sources and call them with Eve auth.',
|
|
@@ -873,6 +953,38 @@ for cloud deployments. Credentials are stored per-profile.`,
|
|
|
873
953
|
'eve admin invite --email user@example.com --github octocat --org org_xxx',
|
|
874
954
|
],
|
|
875
955
|
},
|
|
956
|
+
init: {
|
|
957
|
+
description: `Initialize a new Eve Horizon project from a template.
|
|
958
|
+
|
|
959
|
+
Downloads the starter template, strips git history, initializes a fresh repo,
|
|
960
|
+
and installs skills. After init, start your AI coding agent and run the
|
|
961
|
+
eve-new-project-setup skill to complete configuration.`,
|
|
962
|
+
usage: 'eve init [directory] [--template <url>] [--branch <branch>]',
|
|
963
|
+
subcommands: {
|
|
964
|
+
'': {
|
|
965
|
+
description: 'Initialize project in current or specified directory',
|
|
966
|
+
usage: 'eve init [directory] [options]',
|
|
967
|
+
options: [
|
|
968
|
+
'[directory] Target directory (default: current directory)',
|
|
969
|
+
'--template <url> Template repository URL',
|
|
970
|
+
' (default: https://github.com/incept5/eve-horizon-starter)',
|
|
971
|
+
'--branch <branch> Branch to use (default: main)',
|
|
972
|
+
'--skip-skills Skip automatic skill installation',
|
|
973
|
+
],
|
|
974
|
+
examples: [
|
|
975
|
+
'eve init',
|
|
976
|
+
'eve init my-project',
|
|
977
|
+
'eve init my-project --template https://github.com/myorg/my-template',
|
|
978
|
+
'eve init . --branch develop',
|
|
979
|
+
],
|
|
980
|
+
},
|
|
981
|
+
},
|
|
982
|
+
examples: [
|
|
983
|
+
'eve init my-project',
|
|
984
|
+
'eve init',
|
|
985
|
+
'eve init my-app --template https://github.com/myorg/custom-starter',
|
|
986
|
+
],
|
|
987
|
+
},
|
|
876
988
|
system: {
|
|
877
989
|
description: 'System administration and health checks.',
|
|
878
990
|
usage: 'eve system <subcommand> [options]',
|
|
@@ -961,6 +1073,9 @@ function showMainHelp() {
|
|
|
961
1073
|
console.log('');
|
|
962
1074
|
console.log('Usage: eve <command> [subcommand] [options]');
|
|
963
1075
|
console.log('');
|
|
1076
|
+
console.log('Getting Started:');
|
|
1077
|
+
console.log(' init Initialize a new project from template');
|
|
1078
|
+
console.log('');
|
|
964
1079
|
console.log('Commands:');
|
|
965
1080
|
console.log(' org Manage organizations');
|
|
966
1081
|
console.log(' project Manage projects');
|
|
@@ -973,6 +1088,7 @@ function showMainHelp() {
|
|
|
973
1088
|
console.log(' event Emit and inspect events (app integration)');
|
|
974
1089
|
console.log(' secrets Manage secrets (project/org/user scope)');
|
|
975
1090
|
console.log(' harness Inspect harnesses and auth status');
|
|
1091
|
+
console.log(' agents Inspect agent policy and harness capabilities');
|
|
976
1092
|
console.log(' profile Manage CLI profiles (API URL, defaults)');
|
|
977
1093
|
console.log(' auth Authentication (login, logout, status)');
|
|
978
1094
|
console.log(' admin User and identity management (invite)');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eve-horizon/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Eve Horizon CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -17,9 +17,6 @@
|
|
|
17
17
|
"dist",
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "tsc -p tsconfig.json"
|
|
22
|
-
},
|
|
23
20
|
"publishConfig": {
|
|
24
21
|
"access": "public"
|
|
25
22
|
},
|
|
@@ -27,10 +24,14 @@
|
|
|
27
24
|
"node": ">=22.0.0"
|
|
28
25
|
},
|
|
29
26
|
"dependencies": {
|
|
30
|
-
"yaml": "^2.5.1"
|
|
27
|
+
"yaml": "^2.5.1",
|
|
28
|
+
"@eve/shared": "0.0.1"
|
|
31
29
|
},
|
|
32
30
|
"devDependencies": {
|
|
33
31
|
"@types/node": "^22.0.0",
|
|
34
32
|
"typescript": "^5.7.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.json"
|
|
35
36
|
}
|
|
36
|
-
}
|
|
37
|
+
}
|