@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,49 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.loadCredentials = loadCredentials;
4
- exports.saveCredentials = saveCredentials;
5
- const node_fs_1 = require("node:fs");
6
- const node_os_1 = require("node:os");
7
- const node_path_1 = require("node:path");
8
- const CONFIG_DIR = (0, node_path_1.join)((0, node_os_1.homedir)(), '.eve');
9
- const CREDENTIALS_PATH = (0, node_path_1.join)(CONFIG_DIR, 'credentials.json');
10
- function ensureConfigDir() {
11
- if (!(0, node_fs_1.existsSync)(CONFIG_DIR)) {
12
- (0, node_fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
13
- }
14
- }
15
- function readJsonFile(path, fallback) {
16
- if (!(0, node_fs_1.existsSync)(path))
17
- return fallback;
18
- const raw = (0, node_fs_1.readFileSync)(path, 'utf8');
19
- if (!raw.trim())
20
- return fallback;
21
- try {
22
- return JSON.parse(raw);
23
- }
24
- catch (error) {
25
- throw new Error(`Failed to parse ${path}: ${error.message}`);
26
- }
27
- }
28
- function writeJsonFile(path, value) {
29
- ensureConfigDir();
30
- (0, node_fs_1.writeFileSync)(path, JSON.stringify(value, null, 2));
31
- try {
32
- (0, node_fs_1.chmodSync)(path, 0o600);
33
- }
34
- catch {
35
- // Best-effort for platforms that don't support chmod.
36
- }
37
- }
38
- function loadCredentials() {
39
- const fallback = { tokens: {} };
40
- const credentials = readJsonFile(CREDENTIALS_PATH, fallback);
41
- credentials.tokens = credentials.tokens ?? {};
42
- credentials.profiles = credentials.profiles ?? {};
43
- return credentials;
44
- }
45
- function saveCredentials(credentials) {
46
- credentials.tokens = credentials.tokens ?? {};
47
- credentials.profiles = credentials.profiles ?? {};
48
- writeJsonFile(CREDENTIALS_PATH, credentials);
49
- }
@@ -1,187 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getRepoProfilePath = getRepoProfilePath;
4
- exports.loadRepoProfiles = loadRepoProfiles;
5
- exports.saveRepoProfiles = saveRepoProfiles;
6
- exports.removeRepoProfile = removeRepoProfile;
7
- exports.resolveContext = resolveContext;
8
- exports.parseHarnessSpec = parseHarnessSpec;
9
- const node_fs_1 = require("node:fs");
10
- const node_path_1 = require("node:path");
11
- const yaml_1 = require("yaml");
12
- const args_1 = require("./args");
13
- const DEFAULT_PROFILE = 'default';
14
- // Default to Ingress URL for k8s stack (works via lvh.me → 127.0.0.1)
15
- // Override with EVE_API_URL for other environments (docker compose, local dev)
16
- const DEFAULT_API_URL = 'http://api.eve.lvh.me';
17
- /**
18
- * Get the path to the repo profile file
19
- */
20
- function getRepoProfilePath() {
21
- return (0, node_path_1.join)(process.cwd(), '.eve', 'profile.yaml');
22
- }
23
- /**
24
- * Load repository profiles from .eve/profile.yaml if it exists
25
- */
26
- function loadRepoProfiles() {
27
- const profilePath = getRepoProfilePath();
28
- if (!(0, node_fs_1.existsSync)(profilePath)) {
29
- return { profiles: {} };
30
- }
31
- try {
32
- const content = (0, node_fs_1.readFileSync)(profilePath, 'utf-8');
33
- const parsed = (0, yaml_1.parse)(content);
34
- return normalizeRepoProfiles(parsed);
35
- }
36
- catch {
37
- // Silently ignore parse errors
38
- return { profiles: {} };
39
- }
40
- }
41
- /**
42
- * Save repository profiles to .eve/profile.yaml
43
- */
44
- function saveRepoProfiles(repoProfiles) {
45
- const profilePath = getRepoProfilePath();
46
- const dir = (0, node_path_1.dirname)(profilePath);
47
- if (!(0, node_fs_1.existsSync)(dir)) {
48
- (0, node_fs_1.mkdirSync)(dir, { recursive: true });
49
- }
50
- const payload = {
51
- active_profile: repoProfiles.activeProfile,
52
- profiles: repoProfiles.profiles,
53
- };
54
- (0, node_fs_1.writeFileSync)(profilePath, (0, yaml_1.stringify)(payload));
55
- }
56
- /**
57
- * Remove repository profile file
58
- */
59
- function removeRepoProfile() {
60
- const profilePath = getRepoProfilePath();
61
- if (!(0, node_fs_1.existsSync)(profilePath)) {
62
- return false;
63
- }
64
- (0, node_fs_1.unlinkSync)(profilePath);
65
- return true;
66
- }
67
- function resolveContext(flags, credentials) {
68
- const repoProfiles = loadRepoProfiles();
69
- const profileNames = Object.keys(repoProfiles.profiles);
70
- // Determine profile name and source
71
- // Priority: flag > env > local (.eve/profile.yaml) > default
72
- let profileName;
73
- let profileSource;
74
- const flagProfile = (0, args_1.getStringFlag)(flags, ['profile']);
75
- const envProfile = process.env.EVE_PROFILE;
76
- const localProfile = repoProfiles.activeProfile;
77
- if (flagProfile) {
78
- profileName = flagProfile;
79
- profileSource = 'flag';
80
- }
81
- else if (envProfile) {
82
- profileName = envProfile;
83
- profileSource = 'env';
84
- }
85
- else if (localProfile) {
86
- profileName = localProfile;
87
- profileSource = 'local';
88
- }
89
- else if (profileNames.length === 1) {
90
- profileName = profileNames[0];
91
- profileSource = 'local';
92
- }
93
- else if (profileNames.includes(DEFAULT_PROFILE)) {
94
- profileName = DEFAULT_PROFILE;
95
- profileSource = 'local';
96
- }
97
- else if (profileNames.length > 0) {
98
- profileName = profileNames[0];
99
- profileSource = 'local';
100
- }
101
- else {
102
- profileName = DEFAULT_PROFILE;
103
- profileSource = 'default';
104
- }
105
- // Get base profile config from local profiles
106
- const profile = repoProfiles.profiles[profileName] ?? {};
107
- const apiUrl = (0, args_1.getStringFlag)(flags, ['api', 'api-url']) ||
108
- process.env.EVE_API_URL ||
109
- profile.api_url ||
110
- DEFAULT_API_URL;
111
- const orgId = (0, args_1.getStringFlag)(flags, ['org']) ||
112
- process.env.EVE_ORG_ID ||
113
- profile.org_id;
114
- const projectId = (0, args_1.getStringFlag)(flags, ['project']) ||
115
- process.env.EVE_PROJECT_ID ||
116
- profile.project_id;
117
- const authKey = toAuthKey(apiUrl);
118
- const tokenEntry = credentials.tokens[authKey] || credentials.profiles?.[profileName];
119
- return {
120
- apiUrl,
121
- orgId,
122
- projectId,
123
- profileName,
124
- profile,
125
- authKey,
126
- token: tokenEntry?.access_token,
127
- refreshToken: tokenEntry?.refresh_token,
128
- expiresAt: tokenEntry?.expires_at,
129
- profileSource,
130
- };
131
- }
132
- /**
133
- * Parse a harness spec like "mclaude" or "mclaude:fast" into [harness, variant]
134
- */
135
- function parseHarnessSpec(spec) {
136
- if (!spec)
137
- return [undefined, undefined];
138
- const colonIdx = spec.indexOf(':');
139
- if (colonIdx === -1)
140
- return [spec, undefined];
141
- return [spec.slice(0, colonIdx), spec.slice(colonIdx + 1) || undefined];
142
- }
143
- function normalizeRepoProfiles(parsed) {
144
- if (!parsed || typeof parsed !== 'object') {
145
- return { profiles: {} };
146
- }
147
- if (parsed.profiles && typeof parsed.profiles === 'object') {
148
- return {
149
- activeProfile: parsed.active_profile,
150
- profiles: parsed.profiles,
151
- };
152
- }
153
- const legacyConfig = extractProfileConfig(parsed);
154
- const hasLegacyFields = Object.keys(legacyConfig).length > 0;
155
- const legacyName = parsed.profile ?? parsed.active_profile;
156
- if (!hasLegacyFields && !legacyName) {
157
- return { profiles: {} };
158
- }
159
- const name = legacyName ?? DEFAULT_PROFILE;
160
- return {
161
- activeProfile: name,
162
- profiles: { [name]: legacyConfig },
163
- };
164
- }
165
- function extractProfileConfig(raw) {
166
- const config = {};
167
- if (raw.api_url)
168
- config.api_url = raw.api_url;
169
- if (raw.org_id)
170
- config.org_id = raw.org_id;
171
- if (raw.project_id)
172
- config.project_id = raw.project_id;
173
- if (raw.default_harness)
174
- config.default_harness = raw.default_harness;
175
- if (raw.supabase_url)
176
- config.supabase_url = raw.supabase_url;
177
- if (raw.supabase_anon_key)
178
- config.supabase_anon_key = raw.supabase_anon_key;
179
- if (raw.default_email)
180
- config.default_email = raw.default_email;
181
- if (raw.default_ssh_key)
182
- config.default_ssh_key = raw.default_ssh_key;
183
- return config;
184
- }
185
- function toAuthKey(apiUrl) {
186
- return apiUrl.trim().replace(/\/+$/, '');
187
- }
package/dist/lib/git.js DELETED
@@ -1,158 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.isGitSha = isGitSha;
7
- exports.resolveGitRef = resolveGitRef;
8
- exports.getGitRoot = getGitRoot;
9
- exports.isGitDirty = isGitDirty;
10
- exports.getGitBranch = getGitBranch;
11
- exports.resolveGitBranch = resolveGitBranch;
12
- const node_child_process_1 = require("node:child_process");
13
- const node_path_1 = __importDefault(require("node:path"));
14
- const client_js_1 = require("./client.js");
15
- const GIT_SHA_REGEX = /^[0-9a-f]{40}$/;
16
- function isGitSha(ref) {
17
- return GIT_SHA_REGEX.test(ref);
18
- }
19
- async function resolveGitRef(context, projectId, ref, repoDir) {
20
- if (isGitSha(ref)) {
21
- return ref;
22
- }
23
- const resolvedRepoDir = repoDir ?? getGitRoot();
24
- if (!resolvedRepoDir) {
25
- throw new Error(`Failed to resolve git ref '${ref}': not in a git repository.\n` +
26
- 'Run the command from the project repository, pass --repo-dir <path>, or use a 40-character SHA.');
27
- }
28
- if (projectId) {
29
- const project = await (0, client_js_1.requestJson)(context, `/projects/${projectId}`);
30
- const expected = normalizeRepoIdentity(project.repo_url);
31
- const actual = normalizeRepoIdentity(getGitOriginUrl(resolvedRepoDir));
32
- const repoDirIdentity = normalizeRepoIdentity(resolvedRepoDir);
33
- if (expected && actual && expected !== actual) {
34
- throw new Error(`Failed to resolve git ref '${ref}': current repo does not match project repo.\n` +
35
- ` Project repo: ${project.repo_url}\n` +
36
- ` Current repo: ${getGitOriginUrl(resolvedRepoDir)}\n` +
37
- 'Run the command from the project repository, pass --repo-dir <path>, or use a 40-character SHA.');
38
- }
39
- if (expected && !actual && (!repoDirIdentity || repoDirIdentity !== expected)) {
40
- throw new Error(`Failed to resolve git ref '${ref}': current repo has no origin remote to validate against project repo.\n` +
41
- ` Project repo: ${project.repo_url}\n` +
42
- 'Run the command from the project repository, pass --repo-dir <path>, or use a 40-character SHA.');
43
- }
44
- }
45
- try {
46
- return (0, node_child_process_1.execSync)(`git rev-parse ${ref}`, {
47
- cwd: resolvedRepoDir,
48
- encoding: 'utf-8',
49
- stdio: ['pipe', 'pipe', 'pipe'],
50
- }).trim();
51
- }
52
- catch (error) {
53
- throw new Error(`Failed to resolve git ref '${ref}': ${error instanceof Error ? error.message : String(error)}\n` +
54
- 'Make sure the ref exists in the repository, or use a 40-character SHA.');
55
- }
56
- }
57
- function getGitRoot(repoDir) {
58
- try {
59
- return (0, node_child_process_1.execSync)('git rev-parse --show-toplevel', {
60
- cwd: repoDir,
61
- encoding: 'utf-8',
62
- stdio: ['pipe', 'pipe', 'pipe'],
63
- }).trim();
64
- }
65
- catch {
66
- return null;
67
- }
68
- }
69
- function isGitDirty(repoDir) {
70
- try {
71
- const status = (0, node_child_process_1.execSync)('git status --porcelain', {
72
- cwd: repoDir,
73
- encoding: 'utf-8',
74
- stdio: ['pipe', 'pipe', 'pipe'],
75
- }).trim();
76
- return status.length > 0;
77
- }
78
- catch {
79
- return false;
80
- }
81
- }
82
- function getGitBranch(repoDir) {
83
- try {
84
- const branch = (0, node_child_process_1.execSync)('git branch --show-current', {
85
- cwd: repoDir,
86
- encoding: 'utf-8',
87
- stdio: ['pipe', 'pipe', 'pipe'],
88
- }).trim();
89
- return branch || null;
90
- }
91
- catch {
92
- return null;
93
- }
94
- }
95
- function resolveGitBranch(repoDir, ref) {
96
- if (!ref || isGitSha(ref)) {
97
- return null;
98
- }
99
- try {
100
- (0, node_child_process_1.execSync)(`git show-ref --verify --quiet refs/heads/${ref}`, {
101
- cwd: repoDir,
102
- encoding: 'utf-8',
103
- stdio: ['pipe', 'pipe', 'pipe'],
104
- });
105
- return ref;
106
- }
107
- catch {
108
- return null;
109
- }
110
- }
111
- function getGitOriginUrl(repoDir) {
112
- try {
113
- const url = (0, node_child_process_1.execSync)('git config --get remote.origin.url', {
114
- cwd: repoDir,
115
- encoding: 'utf-8',
116
- stdio: ['pipe', 'pipe', 'pipe'],
117
- }).trim();
118
- return url || null;
119
- }
120
- catch {
121
- return null;
122
- }
123
- }
124
- function normalizeRepoIdentity(repoUrl) {
125
- if (!repoUrl) {
126
- return null;
127
- }
128
- if (repoUrl.startsWith('file://')) {
129
- return stripFilePath(node_path_1.default.resolve(repoUrl.replace('file://', '')));
130
- }
131
- if (repoUrl.startsWith('/') || repoUrl.startsWith('./') || repoUrl.startsWith('../')) {
132
- return stripFilePath(node_path_1.default.resolve(repoUrl));
133
- }
134
- if (repoUrl.startsWith('git@')) {
135
- const match = repoUrl.match(/^git@([^:]+):(.+)$/);
136
- if (!match) {
137
- return repoUrl;
138
- }
139
- const host = match[1].toLowerCase();
140
- const pathname = stripGitSuffix(match[2]).toLowerCase();
141
- return `${host}/${pathname}`;
142
- }
143
- try {
144
- const parsed = new URL(repoUrl);
145
- const host = parsed.host.toLowerCase();
146
- const pathname = stripGitSuffix(parsed.pathname.replace(/^\//, '')).toLowerCase();
147
- return `${host}/${pathname}`;
148
- }
149
- catch {
150
- return repoUrl;
151
- }
152
- }
153
- function stripGitSuffix(pathname) {
154
- return pathname.replace(/\.git$/i, '');
155
- }
156
- function stripFilePath(filePath) {
157
- return filePath.replace(/\.git$/i, '');
158
- }
@@ -1,74 +0,0 @@
1
- "use strict";
2
- /**
3
- * Harness capabilities - inlined from @eve/shared to avoid npm dependency
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.HARNESS_CAPABILITIES = void 0;
7
- exports.HARNESS_CAPABILITIES = {
8
- mclaude: {
9
- supports_model: true,
10
- model_notes: 'Model override supported via CLAUDE_MODEL or --model.',
11
- model_examples: ['opus-4.5', 'sonnet-4', 'haiku-4.5'],
12
- reasoning: {
13
- supported: true,
14
- levels: ['low', 'medium', 'high', 'x-high'],
15
- mode: 'thinking_tokens',
16
- notes: 'Reasoning effort maps to thinking-token budget in adapter.',
17
- },
18
- },
19
- claude: {
20
- supports_model: true,
21
- model_notes: 'Model override supported via CLAUDE_MODEL or --model.',
22
- model_examples: ['opus-4.5', 'sonnet-4', 'haiku-4.5'],
23
- reasoning: {
24
- supported: true,
25
- levels: ['low', 'medium', 'high', 'x-high'],
26
- mode: 'thinking_tokens',
27
- notes: 'Reasoning effort maps to thinking-token budget in adapter.',
28
- },
29
- },
30
- zai: {
31
- supports_model: true,
32
- model_notes: 'Model override supported via ZAI_MODEL or --model.',
33
- model_examples: ['glm-4.7', 'glm-4.5-air'],
34
- reasoning: {
35
- supported: true,
36
- levels: ['low', 'medium', 'high', 'x-high'],
37
- mode: 'thinking_tokens',
38
- notes: 'Reasoning effort maps to thinking-token budget in adapter.',
39
- },
40
- },
41
- gemini: {
42
- supports_model: true,
43
- model_notes: 'Gemini CLI supports --model; thinking settings vary by model family.',
44
- model_examples: ['gemini-3', 'gemini-2.5-pro', 'gemini-2.5-flash'],
45
- reasoning: {
46
- supported: true,
47
- levels: ['low', 'medium', 'high', 'x-high'],
48
- mode: 'level',
49
- notes: 'Gemini 2.5 uses thinkingBudget tokens; Gemini 3 uses thinkingLevel enums.',
50
- },
51
- },
52
- code: {
53
- supports_model: true,
54
- model_notes: 'Model override supported via --model.',
55
- model_examples: ['gpt-5.2-codex', 'gpt-4.1'],
56
- reasoning: {
57
- supported: true,
58
- levels: ['low', 'medium', 'high', 'x-high'],
59
- mode: 'effort',
60
- notes: 'Mapped directly to Code/Codex reasoning effort flag.',
61
- },
62
- },
63
- codex: {
64
- supports_model: true,
65
- model_notes: 'Model override supported via --model.',
66
- model_examples: ['gpt-5.2-codex', 'gpt-4.1'],
67
- reasoning: {
68
- supported: true,
69
- levels: ['low', 'medium', 'high', 'x-high'],
70
- mode: 'effort',
71
- notes: 'Mapped directly to Code/Codex reasoning effort flag.',
72
- },
73
- },
74
- };