@eve-horizon/cli 0.2.28 → 0.2.30

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.
Files changed (2) hide show
  1. package/dist/index.js +272 -46
  2. package/package.json +8 -8
package/dist/index.js CHANGED
@@ -48721,6 +48721,7 @@ function resolveContext(flags, credentials) {
48721
48721
  const projectId = getStringFlag(flags, ["project"]) || process.env.EVE_PROJECT_ID || profile.project_id;
48722
48722
  const authKey = toAuthKey(apiUrl);
48723
48723
  const tokenEntry = credentials.tokens[authKey] || credentials.profiles?.[profileName];
48724
+ const jobToken = process.env.EVE_JOB_TOKEN;
48724
48725
  return {
48725
48726
  apiUrl,
48726
48727
  orgId,
@@ -48728,9 +48729,9 @@ function resolveContext(flags, credentials) {
48728
48729
  profileName,
48729
48730
  profile,
48730
48731
  authKey,
48731
- token: tokenEntry?.access_token,
48732
- refreshToken: tokenEntry?.refresh_token,
48733
- expiresAt: tokenEntry?.expires_at,
48732
+ token: jobToken || tokenEntry?.access_token,
48733
+ refreshToken: jobToken ? void 0 : tokenEntry?.refresh_token,
48734
+ expiresAt: jobToken ? void 0 : tokenEntry?.expires_at,
48734
48735
  profileSource
48735
48736
  };
48736
48737
  }
@@ -50288,7 +50289,7 @@ for cloud deployments. Credentials are stored globally per API URL.`,
50288
50289
  ]
50289
50290
  },
50290
50291
  admin: {
50291
- description: "Administrative commands for user and identity management.",
50292
+ description: "Administrative commands for user, identity, and platform operations.",
50292
50293
  usage: "eve admin <subcommand> [options]",
50293
50294
  subcommands: {
50294
50295
  invite: {
@@ -50304,11 +50305,24 @@ for cloud deployments. Credentials are stored globally per API URL.`,
50304
50305
  "eve admin invite --email user@example.com --github octocat",
50305
50306
  "eve admin invite --email user@example.com --github octocat --role admin --org org_xxx"
50306
50307
  ]
50308
+ },
50309
+ "ingress-aliases": {
50310
+ description: "Inspect and reclaim ingress alias claims (system admin)",
50311
+ usage: "eve admin ingress-aliases <list|reclaim> [options]",
50312
+ options: [
50313
+ "list options: --alias <name> --project <id> --environment <id|null> --limit <n> --offset <n>",
50314
+ 'reclaim usage: eve admin ingress-aliases reclaim <alias> --reason "<text>"'
50315
+ ],
50316
+ examples: [
50317
+ "eve admin ingress-aliases list --project proj_xxx",
50318
+ 'eve admin ingress-aliases reclaim eve-pm --reason "Reserved org rename"'
50319
+ ]
50307
50320
  }
50308
50321
  },
50309
50322
  examples: [
50310
50323
  "eve admin invite --email user@example.com --github octocat",
50311
- "eve admin invite --email user@example.com --github octocat --org org_xxx"
50324
+ "eve admin invite --email user@example.com --github octocat --org org_xxx",
50325
+ "eve admin ingress-aliases list"
50312
50326
  ]
50313
50327
  },
50314
50328
  release: {
@@ -51321,7 +51335,7 @@ function showMainHelp() {
51321
51335
  console.log(" analytics Org analytics (jobs, pipelines, env health)");
51322
51336
  console.log(" ollama Manage inference targets, aliases, and model routes");
51323
51337
  console.log(" access Access control: permissions, roles, bindings, policy-as-code sync");
51324
- console.log(" admin User and identity management (invite)");
51338
+ console.log(" admin User and platform admin operations");
51325
51339
  console.log(" skills Install skills from skills.txt (skills CLI)");
51326
51340
  console.log(" migrate Migration helpers for upgrading config formats");
51327
51341
  console.log(" system System health and status checks");
@@ -51403,6 +51417,7 @@ function showSubcommandHelp(command, subcommand) {
51403
51417
  // src/lib/client.ts
51404
51418
  async function requestJson(context2, path6, options = {}) {
51405
51419
  const response = await requestRaw(context2, path6, options);
51420
+ const method = options.method ?? "GET";
51406
51421
  if (response.status === 401 && options.tokenOverride === void 0) {
51407
51422
  const refreshed = await attemptRefresh(context2);
51408
51423
  if (refreshed?.access_token) {
@@ -51414,14 +51429,16 @@ async function requestJson(context2, path6, options = {}) {
51414
51429
  tokenOverride: refreshed.access_token
51415
51430
  });
51416
51431
  if (!retry.ok && !options.allowError) {
51417
- const message = typeof retry.data === "string" ? retry.data : retry.text;
51418
- throw new Error(`HTTP ${retry.status}: ${message}`);
51432
+ const message = formatErrorMessage(retry);
51433
+ throw new Error(`HTTP ${retry.status}: ${method} ${path6}: ${message}`);
51419
51434
  }
51420
51435
  return retry.data;
51421
51436
  }
51422
51437
  }
51423
51438
  if (!response.ok && !options.allowError) {
51424
- const message = typeof response.data === "string" ? response.data : response.text;
51439
+ const message = formatErrorMessage(response);
51440
+ const requestTarget = `${method} ${path6}`;
51441
+ const requestFailedContext = `while calling ${requestTarget}: ${message}`;
51425
51442
  if ((response.status === 404 || response.status === 500) && message.includes("Project not found")) {
51426
51443
  const projectIdMatch = message.match(/Project not found: (proj_[a-z0-9]+)/);
51427
51444
  const projectId = projectIdMatch?.[1] ?? "unknown";
@@ -51439,7 +51456,7 @@ To fix this, either:
51439
51456
  To list available projects: eve project list`
51440
51457
  );
51441
51458
  }
51442
- throw new Error(`HTTP ${response.status}: ${message}`);
51459
+ throw new Error(`HTTP ${response.status}: ${requestFailedContext}`);
51443
51460
  }
51444
51461
  return response.data;
51445
51462
  }
@@ -51463,11 +51480,19 @@ async function requestRaw(context2, path6, options = {}) {
51463
51480
  if (token) {
51464
51481
  headers.Authorization = `Bearer ${token}`;
51465
51482
  }
51466
- const response = await fetch(`${context2.apiUrl}${path6}`, {
51467
- method: options.method ?? "GET",
51468
- headers,
51469
- body: options.body ? JSON.stringify(options.body) : void 0
51470
- });
51483
+ const url = `${context2.apiUrl}${path6}`;
51484
+ const method = options.method ?? "GET";
51485
+ let response;
51486
+ try {
51487
+ response = await fetch(url, {
51488
+ method: options.method ?? "GET",
51489
+ headers,
51490
+ body: options.body ? JSON.stringify(options.body) : void 0
51491
+ });
51492
+ } catch (error) {
51493
+ const message = error instanceof Error ? error.message : String(error);
51494
+ throw new Error(`Request failed for ${method} ${url}: ${message}`);
51495
+ }
51471
51496
  const text = await response.text();
51472
51497
  let data = null;
51473
51498
  if (text) {
@@ -51479,6 +51504,19 @@ async function requestRaw(context2, path6, options = {}) {
51479
51504
  }
51480
51505
  return { status: response.status, ok: response.ok, data, text };
51481
51506
  }
51507
+ function formatErrorMessage(response) {
51508
+ if (typeof response.data === "string") {
51509
+ return response.data;
51510
+ }
51511
+ if (response.data && typeof response.data === "object") {
51512
+ const payload = response.data;
51513
+ return [payload.message, payload.error, payload.detail, response.text].map((entry) => {
51514
+ if (typeof entry === "string" && entry.trim()) return entry;
51515
+ return "";
51516
+ }).find((entry) => entry.length > 0) ?? response.text;
51517
+ }
51518
+ return response.text;
51519
+ }
51482
51520
  async function attemptRefresh(context2) {
51483
51521
  if (!context2.refreshToken) return void 0;
51484
51522
  if (!context2.profile.supabase_url || !context2.profile.supabase_anon_key) return void 0;
@@ -52116,7 +52154,12 @@ async function fetchProfileStatus(ctx, envFilter) {
52116
52154
  let services = [];
52117
52155
  try {
52118
52156
  const diagnose = await requestJson(ctx, `/projects/${ctx.projectId}/envs/${env.name}/diagnose`);
52119
- services = buildStatusServices(diagnose.pods, diagnose.namespace ?? env.namespace, domain);
52157
+ services = buildStatusServices(
52158
+ diagnose.pods,
52159
+ diagnose.namespace ?? env.namespace,
52160
+ domain,
52161
+ env.ingress_aliases ?? []
52162
+ );
52120
52163
  } catch {
52121
52164
  }
52122
52165
  environments.push({
@@ -52135,7 +52178,7 @@ async function fetchProfileStatus(ctx, envFilter) {
52135
52178
  environments
52136
52179
  };
52137
52180
  }
52138
- function buildStatusServices(pods, namespace, domain) {
52181
+ function buildStatusServices(pods, namespace, domain, ingressAliases) {
52139
52182
  const services = /* @__PURE__ */ new Map();
52140
52183
  for (const pod of pods) {
52141
52184
  const component = pod.labels["eve.component"] || pod.labels["app.kubernetes.io/name"] || pod.labels["app"] || pod.labels["component"] || "unknown";
@@ -52149,12 +52192,14 @@ function buildStatusServices(pods, namespace, domain) {
52149
52192
  const allDone = info.phases.size > 0 && [...info.phases].every((p) => p === "Succeeded" || p === "Failed");
52150
52193
  const status = allDone ? "completed" : info.ready === info.total ? "ready" : "not-ready";
52151
52194
  const url = !allDone && namespace && domain ? buildServiceUrl(name, namespace, domain) : null;
52195
+ const aliasUrls = !allDone && domain ? ingressAliases.filter((entry) => entry.service_name === name).map((entry) => buildAliasUrl(entry.alias, domain)).sort((a, b2) => a.localeCompare(b2)) : [];
52152
52196
  return {
52153
52197
  name,
52154
52198
  pods_ready: info.ready,
52155
52199
  pods_total: info.total,
52156
52200
  status,
52157
- url
52201
+ url,
52202
+ alias_urls: aliasUrls
52158
52203
  };
52159
52204
  });
52160
52205
  }
@@ -52173,6 +52218,10 @@ function buildServiceUrl(component, namespace, domain) {
52173
52218
  const secure = !domain.includes("lvh.me") && !domain.includes("localhost");
52174
52219
  return `${secure ? "https" : "http"}://${component}.${slug}.${domain}`;
52175
52220
  }
52221
+ function buildAliasUrl(alias, domain) {
52222
+ const secure = !domain.includes("lvh.me") && !domain.includes("localhost");
52223
+ return `${secure ? "https" : "http"}://${alias}.${domain}`;
52224
+ }
52176
52225
  function formatStatusOutput(results) {
52177
52226
  for (let i = 0; i < results.length; i++) {
52178
52227
  const r = results[i];
@@ -52211,10 +52260,25 @@ function formatStatusOutput(results) {
52211
52260
  const podsW = Math.max(...env.services.map((s) => `${s.pods_ready}/${s.pods_total}`.length));
52212
52261
  for (const svc of env.services) {
52213
52262
  const pods = `${svc.pods_ready}/${svc.pods_total}`;
52214
- const urlPart = svc.url ? ` ${svc.url}` : "";
52263
+ const urls = [];
52264
+ if (svc.url) {
52265
+ urls.push(svc.url);
52266
+ }
52267
+ for (const aliasUrl of svc.alias_urls ?? []) {
52268
+ if (!urls.includes(aliasUrl)) {
52269
+ urls.push(aliasUrl);
52270
+ }
52271
+ }
52272
+ const urlPart = urls.length > 0 ? ` ${urls[0]}` : "";
52215
52273
  console.log(
52216
52274
  ` ${padRight(svc.name, nameW)} ${padRight(pods, podsW)} ${padRight(svc.status, 9)}${urlPart}`
52217
52275
  );
52276
+ if (urls.length > 1) {
52277
+ const prefix = ` ${padRight("", nameW)} ${padRight("", podsW)} ${padRight("", 9)}`;
52278
+ for (const aliasUrl of urls.slice(1)) {
52279
+ console.log(`${prefix} ${aliasUrl}`);
52280
+ }
52281
+ }
52218
52282
  }
52219
52283
  }
52220
52284
  }
@@ -56731,6 +56795,10 @@ var EnvironmentResponseSchema = external_exports.object({
56731
56795
  labels: EnvironmentLabelsSchema.nullable(),
56732
56796
  current_release_id: external_exports.string().nullable(),
56733
56797
  last_failed_release_id: external_exports.string().nullable(),
56798
+ ingress_aliases: external_exports.array(external_exports.object({
56799
+ alias: external_exports.string(),
56800
+ service_name: external_exports.string()
56801
+ })).optional(),
56734
56802
  status: EnvironmentStatusSchema,
56735
56803
  suspended_at: external_exports.string().nullable(),
56736
56804
  suspension_reason: external_exports.string().nullable(),
@@ -56741,6 +56809,9 @@ var EnvironmentListResponseSchema = external_exports.object({
56741
56809
  data: external_exports.array(EnvironmentResponseSchema),
56742
56810
  pagination: PaginationSchema
56743
56811
  });
56812
+ var DeleteEnvironmentRequestSchema = external_exports.object({
56813
+ force: external_exports.boolean().optional()
56814
+ }).optional().default({});
56744
56815
  var EnvLogEntrySchema = external_exports.object({
56745
56816
  timestamp: external_exports.string(),
56746
56817
  line: external_exports.string(),
@@ -57795,7 +57866,8 @@ var SecretResolveResponseSchema = external_exports.object({
57795
57866
  });
57796
57867
  var SecretMissingItemSchema = external_exports.object({
57797
57868
  key: external_exports.string(),
57798
- hints: external_exports.array(external_exports.string())
57869
+ hints: external_exports.array(external_exports.string()),
57870
+ suggestion: external_exports.string().optional()
57799
57871
  });
57800
57872
  var SecretValidationResultSchema = external_exports.object({
57801
57873
  missing: external_exports.array(SecretMissingItemSchema)
@@ -58109,9 +58181,15 @@ var ManagedDbConfigSchema = external_exports.object({
58109
58181
  engine_version: external_exports.string().optional()
58110
58182
  // e.g., '16'
58111
58183
  });
58184
+ var IngressAliasPattern = /^[a-z][a-z0-9-]*[a-z0-9]$/;
58185
+ var IngressConfigSchema = external_exports.object({
58186
+ public: external_exports.boolean().optional(),
58187
+ port: external_exports.number().optional(),
58188
+ alias: external_exports.string().min(3).max(63).regex(IngressAliasPattern).optional()
58189
+ }).passthrough();
58112
58190
  var ServiceXeveSchema = external_exports.object({
58113
58191
  role: external_exports.string().optional(),
58114
- ingress: external_exports.record(external_exports.unknown()).optional(),
58192
+ ingress: IngressConfigSchema.optional(),
58115
58193
  api_spec: ApiSpecSchema.optional(),
58116
58194
  api_specs: external_exports.array(ApiSpecSchema).optional(),
58117
58195
  external: external_exports.boolean().optional(),
@@ -59529,7 +59607,7 @@ var ManagedModelRegistrySchema = external_exports.record(ManagedModelConfigSchem
59529
59607
  var InferenceScopeKindSchema = external_exports.enum(["platform", "org", "project"]);
59530
59608
  var InferenceTargetTypeSchema = external_exports.enum(["ollama_pool", "external_ollama", "openai_compat"]);
59531
59609
  var InferenceTransportProfileSchema = external_exports.enum(["ollama_api", "openai_compat"]);
59532
- var InferenceTargetStatusSchema = external_exports.enum(["unknown", "healthy", "unhealthy", "draining", "disabled"]);
59610
+ var InferenceTargetStatusSchema = external_exports.enum(["unknown", "healthy", "unhealthy", "waking", "draining", "disabled"]);
59533
59611
  var InferenceTargetSchema = external_exports.object({
59534
59612
  id: external_exports.string(),
59535
59613
  scope_kind: InferenceScopeKindSchema,
@@ -61682,6 +61760,8 @@ var HARNESS_ENV_MAP = deriveHarnessEnvMap();
61682
61760
 
61683
61761
  // ../shared/dist/permissions.js
61684
61762
  var ALL_PERMISSIONS = [
61763
+ // Inference
61764
+ "inference:write",
61685
61765
  // Jobs
61686
61766
  "jobs:read",
61687
61767
  "jobs:write",
@@ -67266,7 +67346,8 @@ async function handleDelete(positionals, flags, context2, json) {
67266
67346
  context2,
67267
67347
  `/projects/${projectId}/envs/${envName}`,
67268
67348
  {
67269
- method: "DELETE"
67349
+ method: "DELETE",
67350
+ ...force ? { body: { force: true } } : {}
67270
67351
  }
67271
67352
  );
67272
67353
  if (json) {
@@ -67479,6 +67560,12 @@ function formatEnvironmentDetails(env, health) {
67479
67560
  console.log(` Database Ref: ${env.db_ref || "(none)"}`);
67480
67561
  console.log(` Current Release: ${env.current_release_id || "(none)"}`);
67481
67562
  console.log(` Last Failed: ${env.last_failed_release_id || "(none)"}`);
67563
+ if (env.ingress_aliases && env.ingress_aliases.length > 0) {
67564
+ console.log(" Ingress Aliases:");
67565
+ for (const entry of env.ingress_aliases) {
67566
+ console.log(` ${entry.alias} -> ${entry.service_name}`);
67567
+ }
67568
+ }
67482
67569
  if (health) {
67483
67570
  console.log("");
67484
67571
  console.log(` Deployment Status: ${health.status}`);
@@ -71404,6 +71491,7 @@ async function applyMigrations(options) {
71404
71491
  `;
71405
71492
  const appliedMap = new Map(appliedRows.map((row) => [row.name, row.checksum]));
71406
71493
  const results = [];
71494
+ const isBaseline = appliedMap.size === 0;
71407
71495
  for (const migration of migrations) {
71408
71496
  const checksum = (0, import_crypto6.createHash)("sha256").update(migration.sql).digest("hex");
71409
71497
  const existingChecksum = appliedMap.get(migration.name);
@@ -71420,10 +71508,25 @@ Current checksum: ${checksum}`);
71420
71508
  });
71421
71509
  continue;
71422
71510
  }
71423
- await db.begin(async (tx) => {
71424
- await tx.unsafe(migration.sql);
71425
- await tx.unsafe("INSERT INTO schema_migrations (name, checksum) VALUES ($1, $2)", [migration.name, checksum]);
71426
- });
71511
+ try {
71512
+ await db.begin(async (tx) => {
71513
+ await tx.unsafe(migration.sql);
71514
+ await tx.unsafe("INSERT INTO schema_migrations (name, checksum) VALUES ($1, $2)", [migration.name, checksum]);
71515
+ });
71516
+ } catch (error) {
71517
+ const msg = error instanceof Error ? error.message : String(error);
71518
+ const isAlreadyExists = /already exists/i.test(msg);
71519
+ if (isBaseline && isAlreadyExists) {
71520
+ console.log(` \u2192 ${migration.name} (baselined \u2014 schema already present)`);
71521
+ await db`
71522
+ INSERT INTO schema_migrations (name, checksum)
71523
+ VALUES (${migration.name}, ${checksum})
71524
+ `;
71525
+ results.push({ filename: migration.name, applied: true, checksum });
71526
+ continue;
71527
+ }
71528
+ throw error;
71529
+ }
71427
71530
  results.push({
71428
71531
  filename: migration.name,
71429
71532
  applied: true,
@@ -73035,6 +73138,61 @@ ${response.length} record(s)`);
73035
73138
  throw new Error("Usage: eve admin usage <list|summary> --org <orgId> [--since] [--until] [--limit] [--json]");
73036
73139
  }
73037
73140
  }
73141
+ case "ingress-aliases": {
73142
+ const action = positionals[0] ?? "list";
73143
+ switch (action) {
73144
+ case "list": {
73145
+ const params = new URLSearchParams();
73146
+ const alias = getStringFlag(flags, ["alias"]);
73147
+ const projectId = getStringFlag(flags, ["project", "project_id"]);
73148
+ const environmentId = getStringFlag(flags, ["environment", "env", "environment_id"]);
73149
+ const limit = getStringFlag(flags, ["limit"]);
73150
+ const offset = getStringFlag(flags, ["offset"]);
73151
+ if (alias) params.set("alias", alias);
73152
+ if (projectId) params.set("project_id", projectId);
73153
+ if (environmentId) params.set("environment_id", environmentId);
73154
+ if (limit) params.set("limit", limit);
73155
+ if (offset) params.set("offset", offset);
73156
+ const query = params.toString();
73157
+ const path6 = `/admin/ingress-aliases${query ? `?${query}` : ""}`;
73158
+ const response = await requestJson(context2, path6);
73159
+ if (json) {
73160
+ outputJson(response, true);
73161
+ return;
73162
+ }
73163
+ const rows = Array.isArray(response.data) ? response.data : [];
73164
+ if (rows.length === 0) {
73165
+ console.log("No ingress aliases found.");
73166
+ return;
73167
+ }
73168
+ for (const row of rows) {
73169
+ console.log(`${row.alias} project=${row.project_id} env=${row.environment_id ?? "(reserved)"} service=${row.service_name}`);
73170
+ }
73171
+ console.log(`
73172
+ ${rows.length} alias(es)`);
73173
+ return;
73174
+ }
73175
+ case "reclaim": {
73176
+ const alias = positionals[1] ?? getStringFlag(flags, ["alias"]);
73177
+ const reason = getStringFlag(flags, ["reason"]);
73178
+ if (!alias || !reason) {
73179
+ throw new Error('Usage: eve admin ingress-aliases reclaim <alias> --reason "<text>"');
73180
+ }
73181
+ const response = await requestJson(context2, `/admin/ingress-aliases/${encodeURIComponent(alias)}/reclaim`, {
73182
+ method: "POST",
73183
+ body: { reason }
73184
+ });
73185
+ outputJson(
73186
+ response,
73187
+ json,
73188
+ `+ Reclaimed ${response.alias} (project=${response.project_id}, env=${response.environment_id ?? "(reserved)"})`
73189
+ );
73190
+ return;
73191
+ }
73192
+ default:
73193
+ throw new Error("Usage: eve admin ingress-aliases <list|reclaim> [options]");
73194
+ }
73195
+ }
73038
73196
  case "access-requests": {
73039
73197
  const action = positionals[0];
73040
73198
  switch (action) {
@@ -73097,7 +73255,7 @@ ${response.length} record(s)`);
73097
73255
  }
73098
73256
  }
73099
73257
  default:
73100
- throw new Error("Usage: eve admin <invite|pricing|receipts|balance|usage|access-requests>");
73258
+ throw new Error("Usage: eve admin <invite|pricing|receipts|balance|usage|ingress-aliases|access-requests>");
73101
73259
  }
73102
73260
  }
73103
73261
  function formatBalanceSummary(data) {
@@ -78003,7 +78161,36 @@ async function handleOllama(subcommand, positionals, flags, context2) {
78003
78161
  if (!json) console.log("Target test completed");
78004
78162
  return;
78005
78163
  }
78006
- throw new Error("Usage: eve ollama target <add|rm|test> ...");
78164
+ if (action === "wake") {
78165
+ const targetId = positionals[1];
78166
+ if (!targetId) throw new Error("Usage: eve ollama target wake <target-id> [--wait=true] [--timeout-ms <ms>]");
78167
+ const query = new URLSearchParams();
78168
+ const wait = asString(flags, "wait");
78169
+ const timeoutMs = asString(flags, "timeout-ms");
78170
+ if (wait === "true" || wait === "1") query.set("wait", "true");
78171
+ if (timeoutMs) query.set("timeout_ms", timeoutMs);
78172
+ const suffix = query.toString() ? `?${query.toString()}` : "";
78173
+ const result = await requestJson(context2, `/inference/targets/${targetId}/wake${suffix}`, {
78174
+ method: "POST"
78175
+ });
78176
+ outputJson(result, json);
78177
+ if (!json) {
78178
+ const nextState = result.ready ? "ready" : result.state;
78179
+ console.log(`Wake request state: ${result.state}`);
78180
+ console.log(`Target: ${result.target_id}`);
78181
+ if (result.waited_ms !== void 0) {
78182
+ console.log(`Waited: ${result.waited_ms}ms`);
78183
+ } else {
78184
+ console.log(`Retry after: ${result.retry_after_seconds}s`);
78185
+ }
78186
+ console.log(`Message: ${result.message}`);
78187
+ if (result.ready) {
78188
+ console.log(`Wake result: ${nextState}`);
78189
+ }
78190
+ }
78191
+ return;
78192
+ }
78193
+ throw new Error("Usage: eve ollama target <add|rm|test|wake> ...");
78007
78194
  }
78008
78195
  case "models": {
78009
78196
  const models = await requestJson(context2, "/inference/models");
@@ -78552,6 +78739,10 @@ var KUBECTL_STABLE_URL = "https://dl.k8s.io/release/stable.txt";
78552
78739
  var LOCAL_STACK_ROOT = (0, import_node_path18.resolve)(__dirname, "..", "assets", "local-k8s");
78553
78740
  var LOCAL_STACK_OVERLAY = (0, import_node_path18.join)(LOCAL_STACK_ROOT, "overlays", "local");
78554
78741
  var LOCAL_STACK_BASE = (0, import_node_path18.join)(LOCAL_STACK_ROOT, "base");
78742
+ var DEFAULT_PLATFORM_NAMESPACE = "eve-horizon";
78743
+ var CONFIGURED_REGISTRY = process.env.ECR_REGISTRY?.trim();
78744
+ var CONFIGURED_NAMESPACE = process.env.ECR_NAMESPACE?.trim() || DEFAULT_PLATFORM_NAMESPACE;
78745
+ var PLATFORM_IMAGE_REGISTRY = buildPlatformImageRegistry();
78555
78746
  var SERVICE_DEFINITIONS = [
78556
78747
  { id: "api", workload: "eve-api", kind: "deployment" },
78557
78748
  { id: "orchestrator", workload: "eve-orchestrator", kind: "deployment" },
@@ -78562,14 +78753,7 @@ var SERVICE_DEFINITIONS = [
78562
78753
  { id: "mailpit", workload: "mailpit", kind: "deployment" },
78563
78754
  { id: "sso", workload: "eve-sso", kind: "deployment" }
78564
78755
  ];
78565
- var PLATFORM_IMAGES = [
78566
- { component: "api", remote: "ghcr.io/eve-horizon/api", local: "eve-horizon/api:local" },
78567
- { component: "orchestrator", remote: "ghcr.io/eve-horizon/orchestrator", local: "eve-horizon/orchestrator:local" },
78568
- { component: "worker", remote: "ghcr.io/eve-horizon/worker", local: "eve-horizon/worker:local" },
78569
- { component: "gateway", remote: "ghcr.io/eve-horizon/gateway", local: "eve-horizon/gateway:local" },
78570
- { component: "agent-runtime", remote: "ghcr.io/eve-horizon/agent-runtime", local: "eve-horizon/agent-runtime:local" },
78571
- { component: "sso", remote: "ghcr.io/eve-horizon/sso", local: "eve-horizon/sso:local" }
78572
- ];
78756
+ var PLATFORM_IMAGES = buildPlatformImages();
78573
78757
  var LOG_TARGETS = {
78574
78758
  api: { resource: "eve-api", kind: "deployment" },
78575
78759
  orchestrator: { resource: "eve-orchestrator", kind: "deployment" },
@@ -78624,9 +78808,21 @@ async function handleUp(flags, json) {
78624
78808
  await ensureClusterReady(runtimeOptions);
78625
78809
  let deployedVersion = null;
78626
78810
  if (!skipDeploy) {
78811
+ const kubectl = requireToolPath("kubectl", "Run 'eve local up' again to auto-install managed tools.");
78812
+ const marker = readManagerMarker(kubectl);
78813
+ if (marker && marker !== "cli") {
78814
+ throw new Error(
78815
+ `This local stack is managed by './bin/eh k8s deploy' (marker: ${marker}).
78816
+ 'eve local up' would overwrite source-built images with released registry images.
78817
+
78818
+ To switch to CLI management: eve local reset --force
78819
+ To continue with repo scripts: ./bin/eh k8s deploy`
78820
+ );
78821
+ }
78627
78822
  deployedVersion = await resolveRequestedVersion(requestedVersion, runtimeOptions);
78628
78823
  await importPlatformImages(deployedVersion, runtimeOptions);
78629
78824
  applyLocalManifests(runtimeOptions);
78825
+ writeManagerMarker(kubectl, runtimeOptions);
78630
78826
  waitForStatefulSetRollout("postgres", Math.max(timeoutSeconds, 180), runtimeOptions);
78631
78827
  runDbMigration(Math.max(timeoutSeconds, 180), runtimeOptions);
78632
78828
  generateAuthSecrets(runtimeOptions);
@@ -79114,22 +79310,21 @@ async function resolveLatestPlatformVersion() {
79114
79310
  const candidates = Array.from(intersection);
79115
79311
  if (candidates.length === 0) {
79116
79312
  throw new Error(
79117
- "Unable to resolve a common platform version from GHCR tags. Re-run with --version <x.y.z>."
79313
+ "Unable to resolve a common platform version from configured registry tags. Re-run with --version <x.y.z>."
79118
79314
  );
79119
79315
  }
79120
79316
  candidates.sort(compareSemverDesc);
79121
79317
  return candidates[0];
79122
79318
  }
79123
79319
  async function fetchRegistryTags(imageRef) {
79124
- const repository = imageRef.replace(/^ghcr\.io\//, "");
79125
- const tokenPayload = await fetchText(`https://ghcr.io/token?scope=repository:${repository}:pull`);
79126
- const token = JSON.parse(tokenPayload).token;
79127
- if (!token) {
79128
- throw new Error(`Unable to fetch GHCR token for ${imageRef}.`);
79320
+ const slashIndex = imageRef.indexOf("/");
79321
+ if (slashIndex < 0) {
79322
+ throw new Error(`Invalid image reference '${imageRef}'.`);
79129
79323
  }
79324
+ const registry = imageRef.slice(0, slashIndex);
79325
+ const repository = imageRef.slice(slashIndex + 1);
79130
79326
  const tagsPayload = await fetchText(
79131
- `https://ghcr.io/v2/${repository}/tags/list?n=200`,
79132
- { Authorization: `Bearer ${token}` }
79327
+ `https://${registry}/v2/${repository}/tags/list?n=200`
79133
79328
  );
79134
79329
  return JSON.parse(tagsPayload).tags ?? [];
79135
79330
  }
@@ -79165,7 +79360,7 @@ async function importPlatformImages(version2, runtimeOptions) {
79165
79360
  const pull = pullImageWithRetry(docker, remoteTag, stdio, runtimeOptions);
79166
79361
  if (pull.status !== 0) {
79167
79362
  throw new Error(
79168
- `Failed to pull ${remoteTag}. Ensure GHCR image visibility is public and the version exists. Try: eve local up --version <x.y.z>`
79363
+ `Failed to pull ${remoteTag}. Ensure image availability/access at ${image.remote} and the version exists. Try: eve local up --version <x.y.z>`
79169
79364
  );
79170
79365
  }
79171
79366
  run(docker, ["tag", remoteTag, image.local], { stdio });
@@ -79214,6 +79409,37 @@ function applyLocalManifests(runtimeOptions) {
79214
79409
  { stdio: runtimeOptions.verbose && !runtimeOptions.quiet ? "inherit" : "pipe" }
79215
79410
  );
79216
79411
  }
79412
+ function buildPlatformImageRegistry() {
79413
+ if (CONFIGURED_REGISTRY) {
79414
+ return `${CONFIGURED_REGISTRY}/${CONFIGURED_NAMESPACE}`;
79415
+ }
79416
+ return `public.ecr.aws/w7c4v0w3/${DEFAULT_PLATFORM_NAMESPACE}`;
79417
+ }
79418
+ function buildPlatformImages() {
79419
+ return [
79420
+ { component: "api", remote: `${PLATFORM_IMAGE_REGISTRY}/api`, local: "eve-horizon/api:local" },
79421
+ { component: "orchestrator", remote: `${PLATFORM_IMAGE_REGISTRY}/orchestrator`, local: "eve-horizon/orchestrator:local" },
79422
+ { component: "worker", remote: `${PLATFORM_IMAGE_REGISTRY}/worker`, local: "eve-horizon/worker:local" },
79423
+ { component: "gateway", remote: `${PLATFORM_IMAGE_REGISTRY}/gateway`, local: "eve-horizon/gateway:local" },
79424
+ { component: "agent-runtime", remote: `${PLATFORM_IMAGE_REGISTRY}/agent-runtime`, local: "eve-horizon/agent-runtime:local" },
79425
+ { component: "sso", remote: `${PLATFORM_IMAGE_REGISTRY}/sso`, local: "eve-horizon/sso:local" }
79426
+ ];
79427
+ }
79428
+ function readManagerMarker(kubectl) {
79429
+ const result = run(
79430
+ kubectl,
79431
+ ["--context", DEFAULT_KUBE_CONTEXT, "get", "namespace", "eve", "-o", "jsonpath={.metadata.annotations.eve-managed-by}"],
79432
+ { stdio: "pipe", allowFailure: true }
79433
+ );
79434
+ return result.status === 0 ? result.stdout.trim() : "";
79435
+ }
79436
+ function writeManagerMarker(kubectl, runtimeOptions) {
79437
+ run(
79438
+ kubectl,
79439
+ ["--context", DEFAULT_KUBE_CONTEXT, "annotate", "namespace", "eve", "eve-managed-by=cli", "--overwrite"],
79440
+ { stdio: runtimeOptions.verbose && !runtimeOptions.quiet ? "inherit" : "pipe", allowFailure: true }
79441
+ );
79442
+ }
79217
79443
  function runDbMigration(timeoutSeconds, runtimeOptions) {
79218
79444
  const kubectl = requireToolPath("kubectl", "Run 'eve local up' again to auto-install managed tools.");
79219
79445
  const migrateJobPath = (0, import_node_path18.join)(LOCAL_STACK_BASE, "db-migrate-job.yaml");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eve-horizon/cli",
3
- "version": "0.2.28",
3
+ "version": "0.2.30",
4
4
  "description": "Eve Horizon CLI",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -18,9 +18,6 @@
18
18
  "assets",
19
19
  "README.md"
20
20
  ],
21
- "scripts": {
22
- "build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node22 --outfile=dist/index.js --format=cjs --external:yaml"
23
- },
24
21
  "publishConfig": {
25
22
  "access": "public"
26
23
  },
@@ -31,11 +28,14 @@
31
28
  "yaml": "^2.5.1"
32
29
  },
33
30
  "devDependencies": {
34
- "@eve/migrate": "workspace:*",
35
- "@eve/shared": "workspace:*",
36
31
  "@types/node": "^22.0.0",
37
32
  "esbuild": "^0.27.3",
38
33
  "postgres": "^3.4.0",
39
- "typescript": "^5.7.0"
34
+ "typescript": "^5.7.0",
35
+ "@eve/shared": "0.0.1",
36
+ "@eve/migrate": "0.0.1"
37
+ },
38
+ "scripts": {
39
+ "build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node22 --outfile=dist/index.js --format=cjs --external:yaml"
40
40
  }
41
- }
41
+ }