@eve-horizon/cli 0.2.12 → 0.2.13

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.
@@ -1,86 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handleManifest = handleManifest;
4
- const args_1 = require("../lib/args");
5
- const client_1 = require("../lib/client");
6
- const output_1 = require("../lib/output");
7
- const node_fs_1 = require("node:fs");
8
- const node_path_1 = require("node:path");
9
- async function handleManifest(subcommand, positionals, flags, context) {
10
- const json = Boolean(flags.json);
11
- switch (subcommand) {
12
- case 'validate': {
13
- const useLatest = (0, args_1.toBoolean)(flags.latest) ?? false;
14
- const strict = (0, args_1.toBoolean)(flags.strict) ?? false;
15
- const validateSecretsFlag = flags['validate-secrets'] ?? flags.validate_secrets;
16
- const validateSecrets = (0, args_1.toBoolean)(validateSecretsFlag) ?? false;
17
- const dir = typeof flags.dir === 'string' ? flags.dir : process.cwd();
18
- const manifestPath = (0, args_1.getStringFlag)(flags, ['path']) ?? (0, node_path_1.join)(dir, '.eve', 'manifest.yaml');
19
- let manifestYaml;
20
- if (!useLatest) {
21
- try {
22
- manifestYaml = (0, node_fs_1.readFileSync)(manifestPath, 'utf-8');
23
- }
24
- catch (error) {
25
- throw new Error(`Failed to read manifest at ${manifestPath}: ${error.message}`);
26
- }
27
- }
28
- let projectId = (0, args_1.getStringFlag)(flags, ['project']) ?? context.projectId;
29
- if (!projectId && manifestYaml) {
30
- const match = manifestYaml.match(/^project:\s*(\S+)/m);
31
- if (match) {
32
- projectId = match[1];
33
- }
34
- }
35
- if (!projectId) {
36
- throw new Error('Missing project id. Provide --project, set a profile default, or add "project: proj_xxx" to manifest.');
37
- }
38
- const response = await (0, client_1.requestJson)(context, `/projects/${projectId}/manifest/validate`, {
39
- method: 'POST',
40
- body: {
41
- manifest_yaml: manifestYaml,
42
- validate_secrets: validateSecrets || strict,
43
- strict,
44
- },
45
- });
46
- if (json) {
47
- (0, output_1.outputJson)(response, json);
48
- }
49
- else {
50
- if (response.valid) {
51
- console.log('✓ Manifest valid');
52
- }
53
- else {
54
- console.log('✗ Manifest invalid');
55
- }
56
- if (response.manifest_hash) {
57
- console.log(` Hash: ${response.manifest_hash.substring(0, 12)}...`);
58
- }
59
- if (response.errors && response.errors.length > 0) {
60
- console.log('');
61
- console.log('Errors:');
62
- response.errors.forEach((error) => console.log(` - ${error}`));
63
- }
64
- if (response.warnings && response.warnings.length > 0) {
65
- console.log('');
66
- console.log('Warnings:');
67
- response.warnings.forEach((warning) => console.log(` - ${warning}`));
68
- }
69
- if (response.secret_validation?.missing?.length) {
70
- console.log('');
71
- console.log('Missing secrets:');
72
- response.secret_validation.missing.forEach((item) => {
73
- const hint = item.hints?.[0] ? ` (${item.hints[0]})` : '';
74
- console.log(` - ${item.key}${hint}`);
75
- });
76
- }
77
- }
78
- if (!response.valid) {
79
- process.exitCode = 1;
80
- }
81
- return;
82
- }
83
- default:
84
- throw new Error('Usage: eve manifest <validate>');
85
- }
86
- }
@@ -1,136 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handleMigrate = handleMigrate;
4
- const node_fs_1 = require("node:fs");
5
- const node_path_1 = require("node:path");
6
- const yaml_1 = require("yaml");
7
- const git_js_1 = require("../lib/git.js");
8
- // ============================================================================
9
- // Main Handler
10
- // ============================================================================
11
- async function handleMigrate(subcommand, _rest, _flags) {
12
- switch (subcommand) {
13
- case 'skills-to-packs':
14
- await migrateSkillsToPacks();
15
- return;
16
- default:
17
- console.log('Usage: eve migrate <subcommand>');
18
- console.log('');
19
- console.log('Subcommands:');
20
- console.log(' skills-to-packs Generate AgentPack config from skills.txt');
21
- return;
22
- }
23
- }
24
- // ============================================================================
25
- // Subcommand Handlers
26
- // ============================================================================
27
- /**
28
- * Read skills.txt and generate a suggested x-eve.packs YAML fragment
29
- * for migration to AgentPacks.
30
- */
31
- async function migrateSkillsToPacks() {
32
- const repoRoot = (0, git_js_1.getGitRoot)();
33
- if (!repoRoot) {
34
- throw new Error('Not in a git repository. Run this from your project root.');
35
- }
36
- const skillsTxtPath = (0, node_path_1.join)(repoRoot, 'skills.txt');
37
- if (!(0, node_fs_1.existsSync)(skillsTxtPath)) {
38
- console.log('No skills.txt found at repository root. Nothing to migrate.');
39
- return;
40
- }
41
- const content = (0, node_fs_1.readFileSync)(skillsTxtPath, 'utf-8');
42
- const lines = content.split('\n');
43
- const localSources = [];
44
- const remoteSources = [];
45
- for (const rawLine of lines) {
46
- const line = rawLine.split('#')[0].trim();
47
- if (!line)
48
- continue;
49
- // Skip glob patterns -- they need manual review
50
- if (line.includes('*')) {
51
- console.log(` [skip] Glob pattern needs manual review: ${line}`);
52
- continue;
53
- }
54
- const sourceType = classifySource(line);
55
- if (sourceType === 'local') {
56
- localSources.push(line);
57
- }
58
- else {
59
- remoteSources.push(line);
60
- }
61
- }
62
- if (localSources.length === 0 && remoteSources.length === 0) {
63
- console.log('skills.txt is empty or contains only comments/globs. Nothing to migrate.');
64
- return;
65
- }
66
- // Build the packs array
67
- const packs = [];
68
- for (const source of remoteSources) {
69
- packs.push({ source: normalizeRemoteSource(source) });
70
- }
71
- for (const source of localSources) {
72
- packs.push({ source });
73
- }
74
- // Build the YAML fragment
75
- const fragment = {
76
- 'x-eve': {
77
- packs,
78
- },
79
- };
80
- console.log('# Suggested AgentPack configuration for .eve/manifest.yaml');
81
- console.log('# Review and merge into your existing manifest under the x-eve key.');
82
- console.log('#');
83
- if (localSources.length > 0) {
84
- console.log('# Local paths are kept as-is. Consider publishing them as packs.');
85
- }
86
- console.log('');
87
- console.log((0, yaml_1.stringify)(fragment, { indent: 2 }).trimEnd());
88
- console.log('');
89
- console.log('# After adding packs to your manifest:');
90
- console.log('# 1. Run: eve agents sync');
91
- console.log('# 2. Delete skills.txt from your repo');
92
- }
93
- // ============================================================================
94
- // Helper Functions
95
- // ============================================================================
96
- /**
97
- * Classify a skills.txt line as local or remote.
98
- */
99
- function classifySource(line) {
100
- // URLs
101
- if (line.startsWith('https://') || line.startsWith('http://')) {
102
- return 'remote';
103
- }
104
- // Explicit GitHub prefix
105
- if (line.startsWith('github:')) {
106
- return 'remote';
107
- }
108
- // Local paths: absolute, home-relative, or dot-relative
109
- if (line.startsWith('/') || line.startsWith('~') || line.startsWith('./') || line.startsWith('../')) {
110
- return 'local';
111
- }
112
- // GitHub shorthand: owner/repo (single slash, no spaces)
113
- if (line.includes('/') && !line.includes(' ') && !line.startsWith('.')) {
114
- return 'remote';
115
- }
116
- // Default: treat as local
117
- return 'local';
118
- }
119
- /**
120
- * Normalize remote source references for pack config.
121
- * - `github:owner/repo` -> `owner/repo`
122
- * - GitHub URLs -> `owner/repo`
123
- * - owner/repo -> owner/repo (pass through)
124
- */
125
- function normalizeRemoteSource(source) {
126
- // Strip github: prefix
127
- if (source.startsWith('github:')) {
128
- return source.slice(7);
129
- }
130
- // Extract owner/repo from GitHub URL
131
- const ghMatch = source.match(/github\.com\/([^/]+\/[^/]+)/);
132
- if (ghMatch) {
133
- return ghMatch[1].replace(/\.git$/, '');
134
- }
135
- return source;
136
- }
@@ -1,148 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handleOrg = handleOrg;
4
- const args_1 = require("../lib/args");
5
- const client_1 = require("../lib/client");
6
- const output_1 = require("../lib/output");
7
- const DEFAULT_ORG_NAME = process.env.EVE_ORG_NAME || 'default-test-org';
8
- const DEFAULT_ORG_ID = process.env.EVE_ORG_ID || 'org_defaulttestorg';
9
- async function handleOrg(subcommand, positionals, flags, context) {
10
- const json = Boolean(flags.json);
11
- switch (subcommand) {
12
- case 'ensure': {
13
- let orgId = typeof flags.id === 'string' ? flags.id : '';
14
- let orgName = typeof flags.name === 'string' ? flags.name : '';
15
- let orgSlug = typeof flags.slug === 'string' ? flags.slug : '';
16
- const nameOrId = positionals[0];
17
- if (!orgId && nameOrId) {
18
- if (/^org_[a-zA-Z0-9]+$/.test(nameOrId)) {
19
- orgId = nameOrId;
20
- orgName = orgName || nameOrId;
21
- }
22
- else {
23
- orgName = orgName || nameOrId;
24
- orgId = normalizeOrgId(nameOrId);
25
- }
26
- }
27
- orgId = orgId || context.orgId || DEFAULT_ORG_ID;
28
- orgName = orgName || DEFAULT_ORG_NAME;
29
- const body = { id: orgId, name: orgName, ...(orgSlug ? { slug: orgSlug } : {}) };
30
- const org = await (0, client_1.requestJson)(context, '/orgs/ensure', {
31
- method: 'POST',
32
- body,
33
- });
34
- (0, output_1.outputJson)(org, json, `✓ Organization ready: ${org.id} (${org.name})`);
35
- return;
36
- }
37
- case 'list': {
38
- const includeDeletedFlag = flags.include_deleted ?? flags['include-deleted'];
39
- const query = buildQuery({
40
- limit: typeof flags.limit === 'string' ? flags.limit : undefined,
41
- offset: typeof flags.offset === 'string' ? flags.offset : undefined,
42
- include_deleted: (0, args_1.toBoolean)(includeDeletedFlag) ? 'true' : undefined,
43
- name: typeof flags.name === 'string' ? flags.name : undefined,
44
- });
45
- const response = await (0, client_1.requestJson)(context, `/orgs${query}`);
46
- (0, output_1.outputJson)(response, json);
47
- return;
48
- }
49
- case 'get': {
50
- const orgId = positionals[0];
51
- if (!orgId)
52
- throw new Error('Usage: eve org get <org_id>');
53
- const includeDeletedFlag = flags.include_deleted ?? flags['include-deleted'];
54
- const query = buildQuery({
55
- include_deleted: (0, args_1.toBoolean)(includeDeletedFlag) ? 'true' : undefined,
56
- });
57
- const response = await (0, client_1.requestJson)(context, `/orgs/${orgId}${query}`);
58
- (0, output_1.outputJson)(response, json);
59
- return;
60
- }
61
- case 'update': {
62
- const orgId = positionals[0];
63
- if (!orgId) {
64
- throw new Error('Usage: eve org update <org_id> [--name <name>] [--deleted <bool>] [--default-agent <slug>]');
65
- }
66
- const body = {};
67
- if (typeof flags.name === 'string')
68
- body.name = flags.name;
69
- const deleted = (0, args_1.toBoolean)(flags.deleted);
70
- if (deleted !== undefined)
71
- body.deleted = deleted;
72
- if (typeof flags['default-agent'] === 'string') {
73
- const value = flags['default-agent'].trim();
74
- body.default_agent_slug = (value === '' || value === 'none' || value === 'null') ? null : value;
75
- }
76
- const response = await (0, client_1.requestJson)(context, `/orgs/${orgId}`, { method: 'PATCH', body });
77
- (0, output_1.outputJson)(response, json);
78
- return;
79
- }
80
- case 'delete': {
81
- const orgId = positionals[0];
82
- if (!orgId)
83
- throw new Error('Usage: eve org delete <org_id> [--force]');
84
- const response = await (0, client_1.requestJson)(context, `/orgs/${orgId}`, { method: 'PATCH', body: { deleted: true } });
85
- (0, output_1.outputJson)(response, json, `✓ Organization deleted: ${orgId}`);
86
- return;
87
- }
88
- case 'members': {
89
- const action = positionals[0]; // list | add | remove
90
- const orgId = typeof flags.org === 'string' ? flags.org : context.orgId;
91
- if (!orgId) {
92
- throw new Error('Missing org id. Provide --org or set a profile default.');
93
- }
94
- switch (action) {
95
- case 'add': {
96
- const email = (0, args_1.getStringFlag)(flags, ['email']) ?? positionals[1];
97
- const role = (0, args_1.getStringFlag)(flags, ['role']) ?? 'member';
98
- if (!email) {
99
- throw new Error('Usage: eve org members add <email> [--role member|admin|owner]');
100
- }
101
- const response = await (0, client_1.requestJson)(context, `/orgs/${orgId}/members`, {
102
- method: 'POST',
103
- body: { email, role },
104
- });
105
- (0, output_1.outputJson)(response, json, `✓ Member added to org ${orgId}`);
106
- return;
107
- }
108
- case 'remove': {
109
- const userId = positionals[1];
110
- if (!userId) {
111
- throw new Error('Usage: eve org members remove <user_id>');
112
- }
113
- await (0, client_1.requestRaw)(context, `/orgs/${orgId}/members/${userId}`, { method: 'DELETE' });
114
- (0, output_1.outputJson)({ org_id: orgId, user_id: userId, removed: true }, json, `✓ Member ${userId} removed from org ${orgId}`);
115
- return;
116
- }
117
- case 'list':
118
- default: {
119
- const response = await (0, client_1.requestJson)(context, `/orgs/${orgId}/members`);
120
- (0, output_1.outputJson)(response, json);
121
- return;
122
- }
123
- }
124
- }
125
- default:
126
- throw new Error('Usage: eve org <ensure|list|get|update|delete|members>');
127
- }
128
- }
129
- function normalizeOrgId(raw) {
130
- if (/^org_[a-zA-Z0-9]+$/.test(raw)) {
131
- return raw;
132
- }
133
- const stripped = raw.replace(/[^a-zA-Z0-9]/g, '');
134
- if (!stripped) {
135
- throw new Error('Organization id must contain alphanumeric characters');
136
- }
137
- return `org_${stripped}`;
138
- }
139
- function buildQuery(params) {
140
- const search = new URLSearchParams();
141
- Object.entries(params).forEach(([key, value]) => {
142
- if (value === undefined || value === '')
143
- return;
144
- search.set(key, String(value));
145
- });
146
- const query = search.toString();
147
- return query ? `?${query}` : '';
148
- }
@@ -1,197 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.handlePacks = handlePacks;
4
- const node_fs_1 = require("node:fs");
5
- const node_path_1 = require("node:path");
6
- const yaml_1 = require("yaml");
7
- const args_1 = require("../lib/args");
8
- /**
9
- * eve packs <status|resolve> — Manage AgentPack lockfile and resolution.
10
- */
11
- async function handlePacks(subcommand, _rest, flags, _context) {
12
- const repoRoot = (0, node_path_1.resolve)((0, args_1.getStringFlag)(flags, ['repo-dir', 'repo_dir', 'dir', 'path']) ?? process.cwd());
13
- switch (subcommand) {
14
- case 'status': {
15
- printPacksStatus(repoRoot);
16
- return;
17
- }
18
- case 'resolve': {
19
- const dryRun = (0, args_1.getBooleanFlag)(flags, ['dry-run', 'dry_run']) ?? false;
20
- printPacksResolve(repoRoot, dryRun);
21
- return;
22
- }
23
- default:
24
- throw new Error('Usage: eve packs <status|resolve>');
25
- }
26
- }
27
- // ---------------------------------------------------------------------------
28
- // status: read lockfile + manifest, print table, detect drift
29
- // ---------------------------------------------------------------------------
30
- function printPacksStatus(repoRoot) {
31
- const lockfilePath = (0, node_path_1.join)(repoRoot, '.eve', 'packs.lock.yaml');
32
- const manifestPath = (0, node_path_1.join)(repoRoot, '.eve', 'manifest.yaml');
33
- if (!(0, node_fs_1.existsSync)(lockfilePath)) {
34
- console.log('No lockfile found at .eve/packs.lock.yaml');
35
- console.log('Run "eve agents sync" to resolve packs and generate the lockfile.');
36
- return;
37
- }
38
- const lockRaw = (0, node_fs_1.readFileSync)(lockfilePath, 'utf-8');
39
- const lock = (0, yaml_1.parse)(lockRaw);
40
- if (!lock || !lock.packs) {
41
- console.log('Lockfile is empty or malformed.');
42
- return;
43
- }
44
- // Print resolved packs table
45
- console.log(`Pack lockfile: .eve/packs.lock.yaml`);
46
- console.log(`Resolved at: ${lock.resolved_at}`);
47
- console.log(`Project slug: ${lock.project_slug}`);
48
- console.log('');
49
- if (lock.packs.length === 0) {
50
- console.log('No packs resolved.');
51
- }
52
- else {
53
- const idWidth = Math.max(4, ...lock.packs.map((p) => p.id.length));
54
- const sourceWidth = Math.max(6, ...lock.packs.map((p) => p.source.length));
55
- const header = [
56
- padRight('Pack', idWidth),
57
- padRight('Source', sourceWidth),
58
- 'Ref',
59
- ].join(' ');
60
- console.log(header);
61
- console.log('-'.repeat(header.length + 12));
62
- for (const pack of lock.packs) {
63
- console.log([
64
- padRight(pack.id, idWidth),
65
- padRight(pack.source, sourceWidth),
66
- pack.ref.substring(0, 12),
67
- ].join(' '));
68
- }
69
- }
70
- // Effective config stats
71
- console.log('');
72
- console.log('Effective config:');
73
- console.log(` Agents: ${lock.effective.agents_count}`);
74
- console.log(` Teams: ${lock.effective.teams_count}`);
75
- console.log(` Routes: ${lock.effective.routes_count}`);
76
- // Drift detection: compare manifest packs to lockfile
77
- if ((0, node_fs_1.existsSync)(manifestPath)) {
78
- const manifestRaw = (0, node_fs_1.readFileSync)(manifestPath, 'utf-8');
79
- const manifest = (0, yaml_1.parse)(manifestRaw);
80
- if (manifest) {
81
- const xEve = manifest['x-eve'] ??
82
- manifest['x_eve'] ??
83
- {};
84
- const manifestPacks = (xEve.packs ?? []);
85
- const drift = detectDrift(lock, manifestPacks);
86
- if (drift.length > 0) {
87
- console.log('');
88
- console.log('WARNING: Drift detected between manifest and lockfile:');
89
- for (const msg of drift) {
90
- console.log(` - ${msg}`);
91
- }
92
- console.log('');
93
- console.log('Run "eve agents sync" to re-resolve packs.');
94
- }
95
- else if (manifestPacks.length > 0) {
96
- console.log('');
97
- console.log('No drift detected. Lockfile is in sync with manifest.');
98
- }
99
- }
100
- }
101
- }
102
- function detectDrift(lock, manifestPacks) {
103
- const drift = [];
104
- // Build a map of lockfile packs by source for easy lookup
105
- const lockBySource = new Map();
106
- for (const lp of lock.packs) {
107
- lockBySource.set(lp.source, { id: lp.id, ref: lp.ref });
108
- }
109
- // Check manifest packs against lockfile
110
- for (const mp of manifestPacks) {
111
- const locked = lockBySource.get(mp.source);
112
- if (!locked) {
113
- drift.push(`Pack source "${mp.source}" in manifest but not in lockfile`);
114
- }
115
- else if (mp.ref && mp.ref !== locked.ref) {
116
- drift.push(`Pack "${locked.id}" ref changed: lockfile=${locked.ref.substring(0, 12)} manifest=${mp.ref.substring(0, 12)}`);
117
- }
118
- }
119
- // Check lockfile packs not in manifest
120
- const manifestSources = new Set(manifestPacks.map((p) => p.source));
121
- for (const lp of lock.packs) {
122
- if (!manifestSources.has(lp.source)) {
123
- drift.push(`Pack "${lp.id}" in lockfile but not in manifest`);
124
- }
125
- }
126
- return drift;
127
- }
128
- // ---------------------------------------------------------------------------
129
- // resolve: delegate to agents sync (the resolution pipeline lives there)
130
- // ---------------------------------------------------------------------------
131
- function printPacksResolve(repoRoot, dryRun) {
132
- if (dryRun) {
133
- // Dry-run: show current lockfile state and what would happen
134
- const lockfilePath = (0, node_path_1.join)(repoRoot, '.eve', 'packs.lock.yaml');
135
- const manifestPath = (0, node_path_1.join)(repoRoot, '.eve', 'manifest.yaml');
136
- if (!(0, node_fs_1.existsSync)(manifestPath)) {
137
- throw new Error('No manifest found at .eve/manifest.yaml');
138
- }
139
- const manifestRaw = (0, node_fs_1.readFileSync)(manifestPath, 'utf-8');
140
- const manifest = (0, yaml_1.parse)(manifestRaw);
141
- if (!manifest) {
142
- throw new Error('Manifest is empty or malformed.');
143
- }
144
- const xEve = manifest['x-eve'] ??
145
- manifest['x_eve'] ??
146
- {};
147
- const manifestPacks = (xEve.packs ?? []);
148
- if (manifestPacks.length === 0) {
149
- console.log('No packs defined in manifest x-eve.packs. Nothing to resolve.');
150
- return;
151
- }
152
- console.log('Dry run: pack resolution preview');
153
- console.log('');
154
- console.log(`Manifest declares ${manifestPacks.length} pack(s):`);
155
- for (const mp of manifestPacks) {
156
- const refShort = mp.ref ? mp.ref.substring(0, 12) : '(local)';
157
- console.log(` - ${mp.source} @ ${refShort}`);
158
- }
159
- if ((0, node_fs_1.existsSync)(lockfilePath)) {
160
- const lockRaw = (0, node_fs_1.readFileSync)(lockfilePath, 'utf-8');
161
- const lock = (0, yaml_1.parse)(lockRaw);
162
- if (lock?.packs) {
163
- const drift = detectDrift(lock, manifestPacks);
164
- if (drift.length > 0) {
165
- console.log('');
166
- console.log('Changes that would be applied:');
167
- for (const msg of drift) {
168
- console.log(` - ${msg}`);
169
- }
170
- }
171
- else {
172
- console.log('');
173
- console.log('No changes detected. Lockfile is already in sync.');
174
- }
175
- }
176
- }
177
- else {
178
- console.log('');
179
- console.log('No existing lockfile. A new lockfile would be created.');
180
- }
181
- console.log('');
182
- console.log('To apply, run: eve agents sync --project <id> --ref <sha>');
183
- return;
184
- }
185
- // Non-dry-run: delegate to agents sync
186
- console.log('Pack resolution is integrated into the agents sync pipeline.');
187
- console.log('');
188
- console.log('Run: eve agents sync --project <id> --ref <sha>');
189
- console.log('');
190
- console.log('This will resolve packs, merge configs, write the lockfile, and sync to the API.');
191
- }
192
- // ---------------------------------------------------------------------------
193
- // helpers
194
- // ---------------------------------------------------------------------------
195
- function padRight(value, width) {
196
- return value.length >= width ? value : `${value}${' '.repeat(width - value.length)}`;
197
- }