@eve-horizon/cli 0.1.4 → 0.2.0

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.
@@ -2,39 +2,109 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleProfile = handleProfile;
4
4
  const config_1 = require("../lib/config");
5
+ const context_1 = require("../lib/context");
5
6
  const output_1 = require("../lib/output");
6
7
  function handleProfile(subcommand, positionals, flags, config) {
7
8
  const json = Boolean(flags.json);
8
9
  switch (subcommand) {
9
10
  case 'list': {
11
+ const repoProfile = (0, context_1.loadRepoProfile)();
12
+ const localProfileName = repoProfile?.profile;
10
13
  const profiles = Object.entries(config.profiles).map(([name, profile]) => ({
11
14
  name,
12
15
  active: name === config.active_profile,
16
+ local: name === localProfileName,
13
17
  ...profile,
14
18
  }));
15
- (0, output_1.outputJson)({ active_profile: config.active_profile, profiles }, json);
19
+ (0, output_1.outputJson)({
20
+ active_profile: config.active_profile,
21
+ local_profile: localProfileName ?? null,
22
+ profiles,
23
+ }, json);
16
24
  return;
17
25
  }
18
26
  case 'show': {
19
- const name = positionals[0] ?? config.active_profile;
27
+ // Check for local profile first
28
+ const repoProfile = (0, context_1.loadRepoProfile)();
29
+ const localProfileName = repoProfile?.profile;
30
+ // Determine which profile to show
31
+ const requestedName = positionals[0];
32
+ let name;
33
+ let source;
34
+ if (requestedName) {
35
+ // Explicit name requested
36
+ name = requestedName;
37
+ source = localProfileName === requestedName ? 'local' : 'global';
38
+ }
39
+ else if (localProfileName) {
40
+ // No name specified, use local profile if exists
41
+ name = localProfileName;
42
+ source = 'local';
43
+ }
44
+ else {
45
+ // Fall back to global active profile
46
+ name = config.active_profile;
47
+ source = 'global';
48
+ }
20
49
  const profile = config.profiles[name];
21
50
  if (!profile) {
22
51
  throw new Error(`Profile ${name} not found`);
23
52
  }
24
- (0, output_1.outputJson)({ name, ...profile }, json);
53
+ // Merge local overrides if showing local profile
54
+ const effectiveProfile = source === 'local' && repoProfile
55
+ ? {
56
+ ...profile,
57
+ ...(repoProfile.api_url && { api_url: repoProfile.api_url }),
58
+ ...(repoProfile.org_id && { org_id: repoProfile.org_id }),
59
+ ...(repoProfile.project_id && { project_id: repoProfile.project_id }),
60
+ }
61
+ : profile;
62
+ const sourceLabel = source === 'local' ? ` (local: .eve/profile.yaml)` : ' (global)';
63
+ (0, output_1.outputJson)({ name, source, ...effectiveProfile }, json, `${name}${sourceLabel}`);
25
64
  return;
26
65
  }
27
66
  case 'use': {
67
+ const isLocal = Boolean(flags.local);
68
+ const isClear = Boolean(flags.clear);
69
+ // Handle --local --clear: remove local profile
70
+ if (isLocal && isClear) {
71
+ const removed = (0, context_1.removeRepoProfile)();
72
+ if (removed) {
73
+ (0, output_1.outputJson)({ cleared: true, path: (0, context_1.getRepoProfilePath)() }, json, `✓ Removed local profile`);
74
+ }
75
+ else {
76
+ (0, output_1.outputJson)({ cleared: false }, json, `No local profile to remove`);
77
+ }
78
+ return;
79
+ }
28
80
  const name = positionals[0];
29
81
  if (!name) {
30
- throw new Error('Usage: eve profile use <name>');
82
+ throw new Error('Usage: eve profile use <name> [--local]');
31
83
  }
84
+ // Validate profile exists in global config
32
85
  if (!config.profiles[name]) {
33
86
  config.profiles[name] = {};
87
+ (0, config_1.saveConfig)(config);
88
+ }
89
+ if (isLocal) {
90
+ // Write to .eve/profile.yaml
91
+ const repoProfile = { profile: name };
92
+ // Apply any override flags
93
+ if (typeof flags['api-url'] === 'string')
94
+ repoProfile.api_url = flags['api-url'];
95
+ if (typeof flags.org === 'string')
96
+ repoProfile.org_id = flags.org;
97
+ if (typeof flags.project === 'string')
98
+ repoProfile.project_id = flags.project;
99
+ (0, context_1.saveRepoProfile)(repoProfile);
100
+ (0, output_1.outputJson)({ profile: name, local: true, path: (0, context_1.getRepoProfilePath)(), ...repoProfile }, json, `✓ Local profile set: ${name} (${(0, context_1.getRepoProfilePath)()})`);
101
+ }
102
+ else {
103
+ // Set global active profile
104
+ config.active_profile = name;
105
+ (0, config_1.saveConfig)(config);
106
+ (0, output_1.outputJson)({ active_profile: name }, json, `✓ Active profile: ${name}`);
34
107
  }
35
- config.active_profile = name;
36
- (0, config_1.saveConfig)(config);
37
- (0, output_1.outputJson)({ active_profile: name }, json, `✓ Active profile: ${name}`);
38
108
  return;
39
109
  }
40
110
  case 'create': {
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRepoProfilePath = getRepoProfilePath;
4
+ exports.loadRepoProfile = loadRepoProfile;
5
+ exports.saveRepoProfile = saveRepoProfile;
6
+ exports.removeRepoProfile = removeRepoProfile;
3
7
  exports.resolveContext = resolveContext;
4
8
  exports.parseHarnessSpec = parseHarnessSpec;
5
9
  const node_fs_1 = require("node:fs");
@@ -9,45 +13,95 @@ const args_1 = require("./args");
9
13
  // Default to Ingress URL for k8s stack (works via lvh.me → 127.0.0.1)
10
14
  // Override with EVE_API_URL for other environments (docker compose, local dev)
11
15
  const DEFAULT_API_URL = 'http://api.eve.lvh.me';
16
+ /**
17
+ * Get the path to the repo profile file
18
+ */
19
+ function getRepoProfilePath() {
20
+ return (0, node_path_1.join)(process.cwd(), '.eve', 'profile.yaml');
21
+ }
12
22
  /**
13
23
  * Load repository profile from .eve/profile.yaml if it exists
14
- * Returns empty object if file not found
24
+ * Returns null if file not found
15
25
  */
16
26
  function loadRepoProfile() {
17
- const profilePath = (0, node_path_1.join)(process.cwd(), '.eve', 'profile.yaml');
27
+ const profilePath = getRepoProfilePath();
18
28
  if (!(0, node_fs_1.existsSync)(profilePath)) {
19
- return {};
29
+ return null;
20
30
  }
21
31
  try {
22
32
  const content = (0, node_fs_1.readFileSync)(profilePath, 'utf-8');
23
33
  const parsed = (0, yaml_1.parse)(content);
24
- return parsed || {};
34
+ return parsed || null;
25
35
  }
26
- catch (error) {
27
- // Silently ignore parse errors and return empty object
28
- return {};
36
+ catch {
37
+ // Silently ignore parse errors
38
+ return null;
39
+ }
40
+ }
41
+ /**
42
+ * Save repository profile to .eve/profile.yaml
43
+ */
44
+ function saveRepoProfile(repoProfile) {
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
+ (0, node_fs_1.writeFileSync)(profilePath, (0, yaml_1.stringify)(repoProfile));
51
+ }
52
+ /**
53
+ * Remove repository profile file
54
+ */
55
+ function removeRepoProfile() {
56
+ const profilePath = getRepoProfilePath();
57
+ if (!(0, node_fs_1.existsSync)(profilePath)) {
58
+ return false;
29
59
  }
60
+ (0, node_fs_1.unlinkSync)(profilePath);
61
+ return true;
30
62
  }
31
63
  function resolveContext(flags, config, credentials) {
32
- const profileName = (0, args_1.getStringFlag)(flags, ['profile']) ||
33
- process.env.EVE_PROFILE ||
34
- config.active_profile ||
35
- 'default';
36
- const profile = config.profiles[profileName] ?? {};
37
64
  const repoProfile = loadRepoProfile();
65
+ // Determine profile name and source
66
+ // Priority: flag > env > local (.eve/profile.yaml) > global active
67
+ let profileName;
68
+ let profileSource;
69
+ const flagProfile = (0, args_1.getStringFlag)(flags, ['profile']);
70
+ const envProfile = process.env.EVE_PROFILE;
71
+ const localProfile = repoProfile?.profile;
72
+ if (flagProfile) {
73
+ profileName = flagProfile;
74
+ profileSource = 'flag';
75
+ }
76
+ else if (envProfile) {
77
+ profileName = envProfile;
78
+ profileSource = 'env';
79
+ }
80
+ else if (localProfile) {
81
+ profileName = localProfile;
82
+ profileSource = 'local';
83
+ }
84
+ else {
85
+ profileName = config.active_profile || 'default';
86
+ profileSource = 'global';
87
+ }
88
+ // Get base profile config from global profiles
89
+ const profile = config.profiles[profileName] ?? {};
90
+ // Apply overrides from repo profile on top of base profile
38
91
  const apiUrl = (0, args_1.getStringFlag)(flags, ['api', 'api-url']) ||
39
- repoProfile.api_url ||
92
+ repoProfile?.api_url ||
40
93
  process.env.EVE_API_URL ||
41
94
  profile.api_url ||
42
95
  DEFAULT_API_URL;
43
96
  const orgId = (0, args_1.getStringFlag)(flags, ['org']) ||
44
- repoProfile.org_id ||
97
+ repoProfile?.org_id ||
45
98
  process.env.EVE_ORG_ID ||
46
99
  profile.org_id;
47
100
  const projectId = (0, args_1.getStringFlag)(flags, ['project']) ||
48
- repoProfile.project_id ||
101
+ repoProfile?.project_id ||
49
102
  process.env.EVE_PROJECT_ID ||
50
103
  profile.project_id;
104
+ // Credentials are always keyed by profile name (from global credentials file)
51
105
  const tokenEntry = credentials.profiles[profileName];
52
106
  return {
53
107
  apiUrl,
@@ -58,6 +112,7 @@ function resolveContext(flags, config, credentials) {
58
112
  token: tokenEntry?.access_token,
59
113
  refreshToken: tokenEntry?.refresh_token,
60
114
  expiresAt: tokenEntry?.expires_at,
115
+ profileSource,
61
116
  };
62
117
  }
63
118
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eve-horizon/cli",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Eve Horizon CLI",
5
5
  "license": "MIT",
6
6
  "repository": {