@eve-horizon/cli 0.2.29 → 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 +153 -37
  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
  }
@@ -51416,6 +51417,7 @@ function showSubcommandHelp(command, subcommand) {
51416
51417
  // src/lib/client.ts
51417
51418
  async function requestJson(context2, path6, options = {}) {
51418
51419
  const response = await requestRaw(context2, path6, options);
51420
+ const method = options.method ?? "GET";
51419
51421
  if (response.status === 401 && options.tokenOverride === void 0) {
51420
51422
  const refreshed = await attemptRefresh(context2);
51421
51423
  if (refreshed?.access_token) {
@@ -51427,14 +51429,16 @@ async function requestJson(context2, path6, options = {}) {
51427
51429
  tokenOverride: refreshed.access_token
51428
51430
  });
51429
51431
  if (!retry.ok && !options.allowError) {
51430
- const message = typeof retry.data === "string" ? retry.data : retry.text;
51431
- throw new Error(`HTTP ${retry.status}: ${message}`);
51432
+ const message = formatErrorMessage(retry);
51433
+ throw new Error(`HTTP ${retry.status}: ${method} ${path6}: ${message}`);
51432
51434
  }
51433
51435
  return retry.data;
51434
51436
  }
51435
51437
  }
51436
51438
  if (!response.ok && !options.allowError) {
51437
- 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}`;
51438
51442
  if ((response.status === 404 || response.status === 500) && message.includes("Project not found")) {
51439
51443
  const projectIdMatch = message.match(/Project not found: (proj_[a-z0-9]+)/);
51440
51444
  const projectId = projectIdMatch?.[1] ?? "unknown";
@@ -51452,7 +51456,7 @@ To fix this, either:
51452
51456
  To list available projects: eve project list`
51453
51457
  );
51454
51458
  }
51455
- throw new Error(`HTTP ${response.status}: ${message}`);
51459
+ throw new Error(`HTTP ${response.status}: ${requestFailedContext}`);
51456
51460
  }
51457
51461
  return response.data;
51458
51462
  }
@@ -51476,11 +51480,19 @@ async function requestRaw(context2, path6, options = {}) {
51476
51480
  if (token) {
51477
51481
  headers.Authorization = `Bearer ${token}`;
51478
51482
  }
51479
- const response = await fetch(`${context2.apiUrl}${path6}`, {
51480
- method: options.method ?? "GET",
51481
- headers,
51482
- body: options.body ? JSON.stringify(options.body) : void 0
51483
- });
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
+ }
51484
51496
  const text = await response.text();
51485
51497
  let data = null;
51486
51498
  if (text) {
@@ -51492,6 +51504,19 @@ async function requestRaw(context2, path6, options = {}) {
51492
51504
  }
51493
51505
  return { status: response.status, ok: response.ok, data, text };
51494
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
+ }
51495
51520
  async function attemptRefresh(context2) {
51496
51521
  if (!context2.refreshToken) return void 0;
51497
51522
  if (!context2.profile.supabase_url || !context2.profile.supabase_anon_key) return void 0;
@@ -56784,6 +56809,9 @@ var EnvironmentListResponseSchema = external_exports.object({
56784
56809
  data: external_exports.array(EnvironmentResponseSchema),
56785
56810
  pagination: PaginationSchema
56786
56811
  });
56812
+ var DeleteEnvironmentRequestSchema = external_exports.object({
56813
+ force: external_exports.boolean().optional()
56814
+ }).optional().default({});
56787
56815
  var EnvLogEntrySchema = external_exports.object({
56788
56816
  timestamp: external_exports.string(),
56789
56817
  line: external_exports.string(),
@@ -57838,7 +57866,8 @@ var SecretResolveResponseSchema = external_exports.object({
57838
57866
  });
57839
57867
  var SecretMissingItemSchema = external_exports.object({
57840
57868
  key: external_exports.string(),
57841
- hints: external_exports.array(external_exports.string())
57869
+ hints: external_exports.array(external_exports.string()),
57870
+ suggestion: external_exports.string().optional()
57842
57871
  });
57843
57872
  var SecretValidationResultSchema = external_exports.object({
57844
57873
  missing: external_exports.array(SecretMissingItemSchema)
@@ -59578,7 +59607,7 @@ var ManagedModelRegistrySchema = external_exports.record(ManagedModelConfigSchem
59578
59607
  var InferenceScopeKindSchema = external_exports.enum(["platform", "org", "project"]);
59579
59608
  var InferenceTargetTypeSchema = external_exports.enum(["ollama_pool", "external_ollama", "openai_compat"]);
59580
59609
  var InferenceTransportProfileSchema = external_exports.enum(["ollama_api", "openai_compat"]);
59581
- var InferenceTargetStatusSchema = external_exports.enum(["unknown", "healthy", "unhealthy", "draining", "disabled"]);
59610
+ var InferenceTargetStatusSchema = external_exports.enum(["unknown", "healthy", "unhealthy", "waking", "draining", "disabled"]);
59582
59611
  var InferenceTargetSchema = external_exports.object({
59583
59612
  id: external_exports.string(),
59584
59613
  scope_kind: InferenceScopeKindSchema,
@@ -61731,6 +61760,8 @@ var HARNESS_ENV_MAP = deriveHarnessEnvMap();
61731
61760
 
61732
61761
  // ../shared/dist/permissions.js
61733
61762
  var ALL_PERMISSIONS = [
61763
+ // Inference
61764
+ "inference:write",
61734
61765
  // Jobs
61735
61766
  "jobs:read",
61736
61767
  "jobs:write",
@@ -67315,7 +67346,8 @@ async function handleDelete(positionals, flags, context2, json) {
67315
67346
  context2,
67316
67347
  `/projects/${projectId}/envs/${envName}`,
67317
67348
  {
67318
- method: "DELETE"
67349
+ method: "DELETE",
67350
+ ...force ? { body: { force: true } } : {}
67319
67351
  }
67320
67352
  );
67321
67353
  if (json) {
@@ -71459,6 +71491,7 @@ async function applyMigrations(options) {
71459
71491
  `;
71460
71492
  const appliedMap = new Map(appliedRows.map((row) => [row.name, row.checksum]));
71461
71493
  const results = [];
71494
+ const isBaseline = appliedMap.size === 0;
71462
71495
  for (const migration of migrations) {
71463
71496
  const checksum = (0, import_crypto6.createHash)("sha256").update(migration.sql).digest("hex");
71464
71497
  const existingChecksum = appliedMap.get(migration.name);
@@ -71475,10 +71508,25 @@ Current checksum: ${checksum}`);
71475
71508
  });
71476
71509
  continue;
71477
71510
  }
71478
- await db.begin(async (tx) => {
71479
- await tx.unsafe(migration.sql);
71480
- await tx.unsafe("INSERT INTO schema_migrations (name, checksum) VALUES ($1, $2)", [migration.name, checksum]);
71481
- });
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
+ }
71482
71530
  results.push({
71483
71531
  filename: migration.name,
71484
71532
  applied: true,
@@ -78113,7 +78161,36 @@ async function handleOllama(subcommand, positionals, flags, context2) {
78113
78161
  if (!json) console.log("Target test completed");
78114
78162
  return;
78115
78163
  }
78116
- 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> ...");
78117
78194
  }
78118
78195
  case "models": {
78119
78196
  const models = await requestJson(context2, "/inference/models");
@@ -78662,6 +78739,10 @@ var KUBECTL_STABLE_URL = "https://dl.k8s.io/release/stable.txt";
78662
78739
  var LOCAL_STACK_ROOT = (0, import_node_path18.resolve)(__dirname, "..", "assets", "local-k8s");
78663
78740
  var LOCAL_STACK_OVERLAY = (0, import_node_path18.join)(LOCAL_STACK_ROOT, "overlays", "local");
78664
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();
78665
78746
  var SERVICE_DEFINITIONS = [
78666
78747
  { id: "api", workload: "eve-api", kind: "deployment" },
78667
78748
  { id: "orchestrator", workload: "eve-orchestrator", kind: "deployment" },
@@ -78672,14 +78753,7 @@ var SERVICE_DEFINITIONS = [
78672
78753
  { id: "mailpit", workload: "mailpit", kind: "deployment" },
78673
78754
  { id: "sso", workload: "eve-sso", kind: "deployment" }
78674
78755
  ];
78675
- var PLATFORM_IMAGES = [
78676
- { component: "api", remote: "ghcr.io/eve-horizon/api", local: "eve-horizon/api:local" },
78677
- { component: "orchestrator", remote: "ghcr.io/eve-horizon/orchestrator", local: "eve-horizon/orchestrator:local" },
78678
- { component: "worker", remote: "ghcr.io/eve-horizon/worker", local: "eve-horizon/worker:local" },
78679
- { component: "gateway", remote: "ghcr.io/eve-horizon/gateway", local: "eve-horizon/gateway:local" },
78680
- { component: "agent-runtime", remote: "ghcr.io/eve-horizon/agent-runtime", local: "eve-horizon/agent-runtime:local" },
78681
- { component: "sso", remote: "ghcr.io/eve-horizon/sso", local: "eve-horizon/sso:local" }
78682
- ];
78756
+ var PLATFORM_IMAGES = buildPlatformImages();
78683
78757
  var LOG_TARGETS = {
78684
78758
  api: { resource: "eve-api", kind: "deployment" },
78685
78759
  orchestrator: { resource: "eve-orchestrator", kind: "deployment" },
@@ -78734,9 +78808,21 @@ async function handleUp(flags, json) {
78734
78808
  await ensureClusterReady(runtimeOptions);
78735
78809
  let deployedVersion = null;
78736
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
+ }
78737
78822
  deployedVersion = await resolveRequestedVersion(requestedVersion, runtimeOptions);
78738
78823
  await importPlatformImages(deployedVersion, runtimeOptions);
78739
78824
  applyLocalManifests(runtimeOptions);
78825
+ writeManagerMarker(kubectl, runtimeOptions);
78740
78826
  waitForStatefulSetRollout("postgres", Math.max(timeoutSeconds, 180), runtimeOptions);
78741
78827
  runDbMigration(Math.max(timeoutSeconds, 180), runtimeOptions);
78742
78828
  generateAuthSecrets(runtimeOptions);
@@ -79224,22 +79310,21 @@ async function resolveLatestPlatformVersion() {
79224
79310
  const candidates = Array.from(intersection);
79225
79311
  if (candidates.length === 0) {
79226
79312
  throw new Error(
79227
- "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>."
79228
79314
  );
79229
79315
  }
79230
79316
  candidates.sort(compareSemverDesc);
79231
79317
  return candidates[0];
79232
79318
  }
79233
79319
  async function fetchRegistryTags(imageRef) {
79234
- const repository = imageRef.replace(/^ghcr\.io\//, "");
79235
- const tokenPayload = await fetchText(`https://ghcr.io/token?scope=repository:${repository}:pull`);
79236
- const token = JSON.parse(tokenPayload).token;
79237
- if (!token) {
79238
- 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}'.`);
79239
79323
  }
79324
+ const registry = imageRef.slice(0, slashIndex);
79325
+ const repository = imageRef.slice(slashIndex + 1);
79240
79326
  const tagsPayload = await fetchText(
79241
- `https://ghcr.io/v2/${repository}/tags/list?n=200`,
79242
- { Authorization: `Bearer ${token}` }
79327
+ `https://${registry}/v2/${repository}/tags/list?n=200`
79243
79328
  );
79244
79329
  return JSON.parse(tagsPayload).tags ?? [];
79245
79330
  }
@@ -79275,7 +79360,7 @@ async function importPlatformImages(version2, runtimeOptions) {
79275
79360
  const pull = pullImageWithRetry(docker, remoteTag, stdio, runtimeOptions);
79276
79361
  if (pull.status !== 0) {
79277
79362
  throw new Error(
79278
- `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>`
79279
79364
  );
79280
79365
  }
79281
79366
  run(docker, ["tag", remoteTag, image.local], { stdio });
@@ -79324,6 +79409,37 @@ function applyLocalManifests(runtimeOptions) {
79324
79409
  { stdio: runtimeOptions.verbose && !runtimeOptions.quiet ? "inherit" : "pipe" }
79325
79410
  );
79326
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
+ }
79327
79443
  function runDbMigration(timeoutSeconds, runtimeOptions) {
79328
79444
  const kubectl = requireToolPath("kubectl", "Run 'eve local up' again to auto-install managed tools.");
79329
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.29",
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
+ }