@eve-horizon/cli 0.2.19 → 0.2.20

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 +942 -32
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -49861,6 +49861,8 @@ for cloud deployments. Credentials are stored globally per API URL.`,
49861
49861
  "--project <id> Project ID (uses profile default)",
49862
49862
  "--env <name> Environment name (optional source)",
49863
49863
  "--json <payload> JSON body inline or @file",
49864
+ "--data <payload> Alias for --json (curl-style)",
49865
+ "-d <payload> Shorthand alias for --json",
49864
49866
  "--jq <expr> Filter JSON output with jq",
49865
49867
  "--graphql <query> GraphQL query inline or @file",
49866
49868
  "--variables <json> JSON variables for GraphQL query",
@@ -49870,6 +49872,7 @@ for cloud deployments. Credentials are stored globally per API URL.`,
49870
49872
  examples: [
49871
49873
  'eve api call app GET /notes --jq ".items"',
49872
49874
  'eve api call app POST /notes --json "{"title":"Hello"}"',
49875
+ 'eve api call app POST /notes --data "{"title":"Hello"}"',
49873
49876
  'eve api call graphql POST /graphql --graphql "{ notes { id } }"'
49874
49877
  ]
49875
49878
  },
@@ -50833,6 +50836,81 @@ eve-new-project-setup skill to complete configuration.`,
50833
50836
  "eve analytics env-health --org org_xxx"
50834
50837
  ]
50835
50838
  },
50839
+ ollama: {
50840
+ description: "Manage inference targets, installs, models, and aliases for managed model routing.",
50841
+ usage: "eve ollama <subcommand> [options]",
50842
+ subcommands: {
50843
+ targets: {
50844
+ description: "List inference targets",
50845
+ usage: "eve ollama targets [--scope-kind <platform|org|project>] [--scope-id <id>] [--json]"
50846
+ },
50847
+ target: {
50848
+ description: "Manage a single target (add, rm, test)",
50849
+ usage: "eve ollama target <add|rm|test> [options]",
50850
+ options: [
50851
+ "add: --name <name> --base-url <url> [--scope-kind <kind>] [--scope-id <id>] [--target-type <type>] [--transport-profile <profile>] [--api-key-ref <secret-ref>]",
50852
+ "rm: <target-id>",
50853
+ "test: <target-id> [--org-id <id>] [--project-id <id>]"
50854
+ ]
50855
+ },
50856
+ models: {
50857
+ description: "List canonical inference models",
50858
+ usage: "eve ollama models [--json]"
50859
+ },
50860
+ model: {
50861
+ description: "Create canonical inference model",
50862
+ usage: "eve ollama model add --canonical <id> --provider <name> --slug <provider-model-slug>"
50863
+ },
50864
+ aliases: {
50865
+ description: "List alias routes",
50866
+ usage: "eve ollama aliases [--scope-kind <kind>] [--scope-id <id>] [--json]"
50867
+ },
50868
+ alias: {
50869
+ description: "Set or remove alias route",
50870
+ usage: "eve ollama alias <set|rm> [options]",
50871
+ options: [
50872
+ "set: --alias <name> --target-id <target-id> --model-id <model-id> [--scope-kind <kind>] [--scope-id <id>]",
50873
+ "rm: --alias <name> [--scope-kind <kind>] [--scope-id <id>]"
50874
+ ]
50875
+ },
50876
+ installs: {
50877
+ description: "List target-model installs",
50878
+ usage: "eve ollama installs [--target-id <id>] [--model-id <id>] [--json]"
50879
+ },
50880
+ install: {
50881
+ description: "Install or remove model availability on a target",
50882
+ usage: "eve ollama install <add|rm> --target-id <target-id> --model-id <model-id> [options]",
50883
+ options: [
50884
+ "add: --target-id <target-id> --model-id <model-id> [--requires-warm-start true|false] [--min-target-capacity <n>]",
50885
+ "rm: --target-id <target-id> --model-id <model-id>"
50886
+ ]
50887
+ },
50888
+ assignments: {
50889
+ description: "Inspect target assignment/load and queue depth",
50890
+ usage: "eve ollama assignments [--scope-kind <platform|org|project>] [--scope-id <id>] [--json]"
50891
+ },
50892
+ "route-policies": {
50893
+ description: "List route policies by scope",
50894
+ usage: "eve ollama route-policies [--scope-kind <platform|org|project>] [--scope-id <id>] [--json]"
50895
+ },
50896
+ "route-policy": {
50897
+ description: "Set or remove a route policy",
50898
+ usage: "eve ollama route-policy <set|rm> [options]",
50899
+ options: [
50900
+ "set: --scope-kind <kind> [--scope-id <id>] --preferred-target-id <target-id> [--fallback-to-alias-target true|false]",
50901
+ "rm: --scope-kind <kind> [--scope-id <id>]"
50902
+ ]
50903
+ }
50904
+ },
50905
+ examples: [
50906
+ "eve ollama target add --name local --base-url http://localhost:11434 --scope-kind platform --target-type external_ollama",
50907
+ "eve ollama model add --canonical gpt-oss:120b --provider ollama --slug gpt-oss:120b",
50908
+ "eve ollama install add --target-id itgt_xxx --model-id imod_xxx --min-target-capacity 1",
50909
+ "eve ollama alias set --alias gpt-oss --target-id itgt_xxx --model-id imod_xxx --scope-kind project --scope-id proj_xxx",
50910
+ "eve ollama assignments --scope-kind project --scope-id proj_xxx",
50911
+ "eve ollama route-policy set --scope-kind project --scope-id proj_xxx --preferred-target-id itgt_xxx"
50912
+ ]
50913
+ },
50836
50914
  migrate: {
50837
50915
  description: "Migration helpers for upgrading config formats.",
50838
50916
  usage: "eve migrate <subcommand>",
@@ -50886,6 +50964,7 @@ function showMainHelp() {
50886
50964
  console.log(" auth Authentication (login, logout, status)");
50887
50965
  console.log(" webhooks Manage outbound webhook subscriptions");
50888
50966
  console.log(" analytics Org analytics (jobs, pipelines, env health)");
50967
+ console.log(" ollama Manage inference targets, aliases, and model routes");
50889
50968
  console.log(" access Access control: permissions, roles, bindings, policy-as-code sync");
50890
50969
  console.log(" admin User and identity management (invite)");
50891
50970
  console.log(" skills Install skills from skills.txt (skills CLI)");
@@ -51009,6 +51088,15 @@ To list available projects: eve project list`
51009
51088
  }
51010
51089
  return response.data;
51011
51090
  }
51091
+ function unwrapListResponse(value) {
51092
+ if (Array.isArray(value)) {
51093
+ return value;
51094
+ }
51095
+ if (value && typeof value === "object" && Array.isArray(value.data)) {
51096
+ return value.data;
51097
+ }
51098
+ throw new Error("Expected list response envelope with data[]");
51099
+ }
51012
51100
  async function requestRaw(context2, path6, options = {}) {
51013
51101
  const headers = {
51014
51102
  ...options.headers
@@ -55691,6 +55779,8 @@ var configSchema = external_exports.object({
55691
55779
  ORCHESTRATOR_PORT: external_exports.coerce.number().default(4802),
55692
55780
  // Max concurrent jobs the orchestrator can process per replica (default: half of ORCH_CONCURRENCY_MAX)
55693
55781
  ORCH_CONCURRENCY: external_exports.coerce.number().int().min(1).default(4),
55782
+ // Main orchestrator claim/dispatch loop cadence (milliseconds)
55783
+ ORCH_LOOP_INTERVAL_MS: external_exports.coerce.number().int().min(100).default(5e3),
55694
55784
  // Phase 3: Auto-tuner configuration
55695
55785
  ORCH_CONCURRENCY_MIN: external_exports.coerce.number().int().min(1).default(1),
55696
55786
  // Minimum concurrency for auto-tuner
@@ -55976,6 +56066,17 @@ var PaginationSchema = external_exports.object({
55976
56066
  offset: external_exports.number().int().nonnegative(),
55977
56067
  count: external_exports.number().int().nonnegative()
55978
56068
  });
56069
+ var ApiListPaginationSchema = external_exports.object({
56070
+ total: external_exports.number().int().nonnegative(),
56071
+ limit: external_exports.number().int().nonnegative(),
56072
+ offset: external_exports.number().int().nonnegative(),
56073
+ has_more: external_exports.boolean().optional(),
56074
+ next_offset: external_exports.number().int().nonnegative().nullable().optional()
56075
+ });
56076
+ var createApiListResponseSchema = (itemSchema) => external_exports.object({
56077
+ data: external_exports.array(itemSchema),
56078
+ pagination: ApiListPaginationSchema.optional()
56079
+ });
55979
56080
  var GitShaSchema = external_exports.string().length(40, "git_sha must be exactly 40 characters").regex(/^[a-f0-9]{40}$/, {
55980
56081
  message: "git_sha must be a 40-character lowercase hex SHA. Did you pass a branch name or uppercase SHA? Use the CLI to resolve refs automatically."
55981
56082
  });
@@ -56665,10 +56766,16 @@ var AttemptListResponseSchema = external_exports.object({
56665
56766
  var AuthStatusResponseSchema = external_exports.object({
56666
56767
  auth_enabled: external_exports.boolean(),
56667
56768
  authenticated: external_exports.boolean(),
56769
+ type: external_exports.enum(["user", "job", "service_principal"]).optional(),
56668
56770
  user_id: external_exports.string().optional(),
56669
56771
  email: external_exports.string().optional(),
56772
+ org_id: external_exports.string().nullable().optional(),
56773
+ project_id: external_exports.string().optional(),
56774
+ job_id: external_exports.string().optional(),
56670
56775
  role: external_exports.string().optional(),
56671
56776
  is_admin: external_exports.boolean().optional(),
56777
+ is_job_token: external_exports.boolean().optional(),
56778
+ is_service_principal: external_exports.boolean().optional(),
56672
56779
  permissions: external_exports.array(external_exports.string()).optional()
56673
56780
  });
56674
56781
  var AuthChallengeRequestSchema = external_exports.object({
@@ -56783,6 +56890,22 @@ var OrgInviteResponseSchema = external_exports.object({
56783
56890
  used_at: external_exports.string().nullable(),
56784
56891
  created_at: external_exports.string()
56785
56892
  });
56893
+ var OrgInviteListResponseSchema = createApiListResponseSchema(OrgInviteResponseSchema);
56894
+ var AccessRequestResponseSchema = external_exports.object({
56895
+ id: external_exports.string(),
56896
+ provider: external_exports.string(),
56897
+ fingerprint: external_exports.string(),
56898
+ email: external_exports.string().nullable(),
56899
+ desired_org_name: external_exports.string(),
56900
+ desired_org_slug: external_exports.string().nullable(),
56901
+ status: external_exports.string(),
56902
+ reviewed_at: external_exports.string().nullable(),
56903
+ review_notes: external_exports.string().nullable(),
56904
+ user_id: external_exports.string().nullable(),
56905
+ org_id: external_exports.string().nullable(),
56906
+ created_at: external_exports.string()
56907
+ });
56908
+ var AccessRequestListResponseSchema = createApiListResponseSchema(AccessRequestResponseSchema);
56786
56909
  var CreateServicePrincipalRequestSchema = external_exports.object({
56787
56910
  name: external_exports.string().min(1).max(100).regex(/^[a-z0-9_-]+$/),
56788
56911
  description: external_exports.string().max(500).optional()
@@ -56800,6 +56923,7 @@ var ServicePrincipalResponseSchema = external_exports.object({
56800
56923
  created_at: external_exports.string(),
56801
56924
  updated_at: external_exports.string()
56802
56925
  });
56926
+ var ServicePrincipalListResponseSchema = createApiListResponseSchema(ServicePrincipalResponseSchema);
56803
56927
  var ServicePrincipalTokenResponseSchema = external_exports.object({
56804
56928
  id: external_exports.string(),
56805
56929
  principal_id: external_exports.string(),
@@ -56808,6 +56932,7 @@ var ServicePrincipalTokenResponseSchema = external_exports.object({
56808
56932
  last_used_at: external_exports.string().nullable(),
56809
56933
  created_at: external_exports.string()
56810
56934
  });
56935
+ var ServicePrincipalTokenListResponseSchema = createApiListResponseSchema(ServicePrincipalTokenResponseSchema);
56811
56936
  var MintServicePrincipalTokenResponseSchema = external_exports.object({
56812
56937
  token_id: external_exports.string(),
56813
56938
  access_token: external_exports.string(),
@@ -56835,6 +56960,7 @@ var AccessRoleResponseSchema = external_exports.object({
56835
56960
  created_at: external_exports.string(),
56836
56961
  updated_at: external_exports.string()
56837
56962
  });
56963
+ var AccessRoleListResponseSchema = createApiListResponseSchema(AccessRoleResponseSchema);
56838
56964
  var CreateAccessBindingRequestSchema = external_exports.object({
56839
56965
  role_name: external_exports.string().min(1),
56840
56966
  principal_type: external_exports.enum(["user", "service_principal"]),
@@ -56851,6 +56977,7 @@ var AccessBindingResponseSchema = external_exports.object({
56851
56977
  created_by: external_exports.string().nullable(),
56852
56978
  created_at: external_exports.string()
56853
56979
  });
56980
+ var AccessBindingListResponseSchema = createApiListResponseSchema(AccessBindingResponseSchema);
56854
56981
  var AccessCanResponseSchema = external_exports.object({
56855
56982
  allowed: external_exports.boolean(),
56856
56983
  source: external_exports.string()
@@ -58249,6 +58376,7 @@ var ResolvedResourceSchema = external_exports.object({
58249
58376
  version: external_exports.number().int().optional(),
58250
58377
  resolved_at: external_exports.string()
58251
58378
  });
58379
+ var ResolveResourcesListResponseSchema = createApiListResponseSchema(ResolvedResourceSchema);
58252
58380
 
58253
58381
  // ../shared/dist/schemas/error.js
58254
58382
  var ApiErrorDetailSchema = external_exports.object({
@@ -58291,6 +58419,7 @@ var WebhookResponseSchema = external_exports.object({
58291
58419
  created_at: external_exports.string(),
58292
58420
  updated_at: external_exports.string()
58293
58421
  });
58422
+ var WebhookListResponseSchema = createApiListResponseSchema(WebhookResponseSchema);
58294
58423
  var WebhookDeliveryResponseSchema = external_exports.object({
58295
58424
  id: external_exports.string(),
58296
58425
  subscription_id: external_exports.string(),
@@ -58302,6 +58431,7 @@ var WebhookDeliveryResponseSchema = external_exports.object({
58302
58431
  response_status: external_exports.number().nullable().optional(),
58303
58432
  created_at: external_exports.string()
58304
58433
  });
58434
+ var WebhookDeliveryListResponseSchema = createApiListResponseSchema(WebhookDeliveryResponseSchema);
58305
58435
  var WebhookReplayDryRunResponseSchema = external_exports.object({
58306
58436
  event_count: external_exports.number().int(),
58307
58437
  earliest: external_exports.string().nullable().optional(),
@@ -58427,6 +58557,170 @@ var BatchValidateResponseSchema = external_exports.object({
58427
58557
  errors: external_exports.array(BatchValidationErrorSchema)
58428
58558
  });
58429
58559
 
58560
+ // ../shared/dist/schemas/managed-models.js
58561
+ var ManagedModelCapabilitySchema = external_exports.object({
58562
+ streaming: external_exports.boolean(),
58563
+ tool_calling: external_exports.boolean(),
58564
+ reasoning: external_exports.boolean()
58565
+ });
58566
+ var ManagedModelConfigV1Schema = external_exports.object({
58567
+ display_name: external_exports.string().min(1),
58568
+ inference_provider: external_exports.string().min(1),
58569
+ harness: external_exports.string().optional(),
58570
+ api_model_id: external_exports.string().min(1),
58571
+ base_url: external_exports.string().min(1),
58572
+ auth_header: external_exports.string().min(1),
58573
+ auth_scheme: external_exports.string(),
58574
+ secret_ref: external_exports.string().min(1),
58575
+ extra_headers: external_exports.record(external_exports.string()),
58576
+ capabilities: ManagedModelCapabilitySchema
58577
+ }).passthrough();
58578
+ var ManagedModelConfigV2Schema = external_exports.object({
58579
+ display_name: external_exports.string().min(1),
58580
+ provider: external_exports.string().min(1),
58581
+ api_model_id: external_exports.string().min(1),
58582
+ capabilities: ManagedModelCapabilitySchema,
58583
+ harness: external_exports.string().optional(),
58584
+ base_url: external_exports.string().optional(),
58585
+ secret_ref: external_exports.string().optional(),
58586
+ extra_headers: external_exports.record(external_exports.string()).optional()
58587
+ }).passthrough();
58588
+ var ManagedModelConfigSchema = external_exports.union([
58589
+ ManagedModelConfigV1Schema,
58590
+ ManagedModelConfigV2Schema
58591
+ ]);
58592
+ var ManagedModelRegistrySchema = external_exports.record(ManagedModelConfigSchema);
58593
+
58594
+ // ../shared/dist/schemas/inference.js
58595
+ var InferenceScopeKindSchema = external_exports.enum(["platform", "org", "project"]);
58596
+ var InferenceTargetTypeSchema = external_exports.enum(["ollama_pool", "external_ollama", "openai_compat"]);
58597
+ var InferenceTransportProfileSchema = external_exports.enum(["ollama_api", "openai_compat"]);
58598
+ var InferenceTargetStatusSchema = external_exports.enum(["unknown", "healthy", "unhealthy", "draining", "disabled"]);
58599
+ var InferenceTargetSchema = external_exports.object({
58600
+ id: external_exports.string(),
58601
+ scope_kind: InferenceScopeKindSchema,
58602
+ scope_id: external_exports.string().nullable(),
58603
+ name: external_exports.string(),
58604
+ target_type: InferenceTargetTypeSchema,
58605
+ transport_profile: InferenceTransportProfileSchema,
58606
+ base_url: external_exports.string(),
58607
+ health_probe_url: external_exports.string().nullable(),
58608
+ capacity: external_exports.number().int(),
58609
+ max_concurrent_inflight: external_exports.number().int(),
58610
+ status: InferenceTargetStatusSchema,
58611
+ transport_metadata: external_exports.record(external_exports.unknown()),
58612
+ created_by: external_exports.string().nullable(),
58613
+ updated_by: external_exports.string().nullable(),
58614
+ created_at: external_exports.string(),
58615
+ updated_at: external_exports.string()
58616
+ });
58617
+ var InferenceModelSchema = external_exports.object({
58618
+ id: external_exports.string(),
58619
+ canonical_model_id: external_exports.string(),
58620
+ provider: external_exports.string(),
58621
+ provider_model_slug: external_exports.string(),
58622
+ max_context: external_exports.number().int().nullable(),
58623
+ supports_json_schema: external_exports.boolean(),
58624
+ metadata: external_exports.record(external_exports.unknown()),
58625
+ created_at: external_exports.string(),
58626
+ updated_at: external_exports.string()
58627
+ });
58628
+ var InferenceAliasSchema = external_exports.object({
58629
+ id: external_exports.string(),
58630
+ scope_kind: InferenceScopeKindSchema,
58631
+ scope_id: external_exports.string().nullable(),
58632
+ alias: external_exports.string(),
58633
+ target_id: external_exports.string(),
58634
+ model_id: external_exports.string(),
58635
+ pin_model_id: external_exports.string().nullable(),
58636
+ pinned_at: external_exports.string().nullable(),
58637
+ created_by: external_exports.string().nullable(),
58638
+ updated_by: external_exports.string().nullable(),
58639
+ created_at: external_exports.string(),
58640
+ updated_at: external_exports.string()
58641
+ });
58642
+ var InferenceInstallSchema = external_exports.object({
58643
+ id: external_exports.string(),
58644
+ target_id: external_exports.string(),
58645
+ model_id: external_exports.string(),
58646
+ requires_warm_start: external_exports.boolean(),
58647
+ min_target_capacity: external_exports.number().int(),
58648
+ allowed_scopes: external_exports.record(external_exports.unknown()),
58649
+ route_hints: external_exports.record(external_exports.unknown()),
58650
+ created_at: external_exports.string(),
58651
+ updated_at: external_exports.string()
58652
+ });
58653
+ var InferenceRoutePolicySchema = external_exports.object({
58654
+ id: external_exports.string(),
58655
+ scope_kind: InferenceScopeKindSchema,
58656
+ scope_id: external_exports.string().nullable(),
58657
+ preferred_target_id: external_exports.string(),
58658
+ fallback_to_alias_target: external_exports.boolean(),
58659
+ created_by: external_exports.string().nullable(),
58660
+ updated_by: external_exports.string().nullable(),
58661
+ created_at: external_exports.string(),
58662
+ updated_at: external_exports.string()
58663
+ });
58664
+ var CreateInferenceTargetRequestSchema = external_exports.object({
58665
+ scope_kind: InferenceScopeKindSchema,
58666
+ scope_id: external_exports.string().optional(),
58667
+ name: external_exports.string().min(1),
58668
+ target_type: InferenceTargetTypeSchema,
58669
+ transport_profile: InferenceTransportProfileSchema.default("ollama_api"),
58670
+ base_url: external_exports.string().min(1),
58671
+ health_probe_url: external_exports.string().optional(),
58672
+ capacity: external_exports.number().int().positive().optional(),
58673
+ max_concurrent_inflight: external_exports.number().int().positive().optional(),
58674
+ status: InferenceTargetStatusSchema.optional(),
58675
+ transport_metadata: external_exports.record(external_exports.unknown()).optional()
58676
+ });
58677
+ var UpdateInferenceTargetRequestSchema = external_exports.object({
58678
+ name: external_exports.string().min(1).optional(),
58679
+ target_type: InferenceTargetTypeSchema.optional(),
58680
+ transport_profile: InferenceTransportProfileSchema.optional(),
58681
+ base_url: external_exports.string().min(1).optional(),
58682
+ health_probe_url: external_exports.string().optional(),
58683
+ capacity: external_exports.number().int().positive().optional(),
58684
+ max_concurrent_inflight: external_exports.number().int().positive().optional(),
58685
+ status: InferenceTargetStatusSchema.optional(),
58686
+ transport_metadata: external_exports.record(external_exports.unknown()).optional()
58687
+ });
58688
+ var CreateInferenceModelRequestSchema = external_exports.object({
58689
+ canonical_model_id: external_exports.string().min(1),
58690
+ provider: external_exports.string().min(1),
58691
+ provider_model_slug: external_exports.string().min(1),
58692
+ max_context: external_exports.number().int().positive().optional(),
58693
+ supports_json_schema: external_exports.boolean().optional(),
58694
+ metadata: external_exports.record(external_exports.unknown()).optional()
58695
+ });
58696
+ var CreateInferenceInstallRequestSchema = external_exports.object({
58697
+ requires_warm_start: external_exports.boolean().optional(),
58698
+ min_target_capacity: external_exports.number().int().positive().optional(),
58699
+ allowed_scopes: external_exports.record(external_exports.unknown()).optional(),
58700
+ route_hints: external_exports.record(external_exports.unknown()).optional()
58701
+ });
58702
+ var UpsertInferenceRoutePolicyRequestSchema = external_exports.object({
58703
+ scope_kind: InferenceScopeKindSchema,
58704
+ scope_id: external_exports.string().optional(),
58705
+ preferred_target_id: external_exports.string().min(1),
58706
+ fallback_to_alias_target: external_exports.boolean().optional()
58707
+ });
58708
+ var UpsertInferenceAliasRequestSchema = external_exports.object({
58709
+ scope_kind: InferenceScopeKindSchema,
58710
+ scope_id: external_exports.string().optional(),
58711
+ alias: external_exports.string().min(1),
58712
+ target_id: external_exports.string().min(1),
58713
+ model_id: external_exports.string().min(1),
58714
+ pin_model_id: external_exports.string().optional()
58715
+ });
58716
+ var InferenceChatCompletionsRequestSchema = external_exports.object({
58717
+ model: external_exports.string().min(1),
58718
+ messages: external_exports.array(external_exports.record(external_exports.unknown())).min(1),
58719
+ stream: external_exports.boolean().optional(),
58720
+ project_id: external_exports.string().optional(),
58721
+ org_id: external_exports.string().optional()
58722
+ }).passthrough();
58723
+
58430
58724
  // ../shared/dist/observability.js
58431
58725
  var import_async_hooks = require("async_hooks");
58432
58726
  var correlationStorage = new import_async_hooks.AsyncLocalStorage();
@@ -60766,7 +61060,7 @@ async function handleCreate(flags, context2, json) {
60766
61060
  `/projects/${resolvedProjectId}/apis`
60767
61061
  );
60768
61062
  const availableApis = new Map(
60769
- (apiListResponse.data || []).map((a) => [a.name, a.type])
61063
+ (apiListResponse.data || []).map((a) => [a.name, { type: a.type, base_url: a.base_url }])
60770
61064
  );
60771
61065
  const missing2 = apiNames.filter((name) => !availableApis.has(name));
60772
61066
  if (missing2.length > 0) {
@@ -60775,11 +61069,67 @@ async function handleCreate(flags, context2, json) {
60775
61069
  Available APIs: ${[...availableApis.keys()].join(", ") || "(none)"}`
60776
61070
  );
60777
61071
  }
61072
+ const contextArgs = [`--project ${resolvedProjectId}`];
61073
+ if (envName) {
61074
+ contextArgs.push(`--env ${envName}`);
61075
+ }
61076
+ const contextSuffix = contextArgs.join(" ");
60778
61077
  const apiLines = apiNames.map((name) => {
60779
- const type = availableApis.get(name) ?? "openapi";
60780
- return `- \`${name}\` (${type}) \u2014 Use \`eve api call ${name} <METHOD> <path>\` to interact.
60781
- Run \`eve api spec ${name}\` to see all endpoints.
60782
- Auth is handled automatically via EVE_JOB_TOKEN.`;
61078
+ const info = availableApis.get(name);
61079
+ const type = info?.type ?? "openapi";
61080
+ const baseUrl = info?.base_url || "<base_url>";
61081
+ return `- \`${name}\` (${type})
61082
+ - Use this runtime-safe Node helper for in-job API calls (no extra tools required).
61083
+ \`\`\`bash
61084
+ API_URL="${baseUrl}" node - <<'NODE'
61085
+ const fs = require("fs");
61086
+ const tokenFromJob = process.env.EVE_JOB_TOKEN;
61087
+ const tokenFromCreds = () => {
61088
+ const credsPath = \`\${process.env.HOME}/.eve/credentials.json\`;
61089
+ if (!fs.existsSync(credsPath)) {
61090
+ return undefined;
61091
+ }
61092
+ const creds = JSON.parse(fs.readFileSync(credsPath, "utf8"));
61093
+ const apiKey = \`\${(process.env.EVE_API_URL || "").replace(/\\/+$/, "")}\`;
61094
+ return creds.tokens?.[apiKey]?.access_token;
61095
+ };
61096
+ const token = tokenFromJob ?? tokenFromCreds();
61097
+ const apiUrl = process.env.API_URL;
61098
+ if (!apiUrl) {
61099
+ throw new Error("Set API_URL before running the script.");
61100
+ }
61101
+ const method = process.env.EVE_APP_API_METHOD ?? "GET";
61102
+ const path = process.env.EVE_APP_API_PATH ?? "/";
61103
+ const bodyArg = process.env.EVE_APP_API_BODY;
61104
+ if (!token) {
61105
+ throw new Error("Missing token. Set EVE_JOB_TOKEN or keep ~/.eve/credentials.json for external shells.");
61106
+ }
61107
+ const options = {
61108
+ method: method.toUpperCase(),
61109
+ headers: {
61110
+ Authorization: \`Bearer \${token}\`,
61111
+ "Content-Type": "application/json",
61112
+ },
61113
+ };
61114
+ if (bodyArg) {
61115
+ options.body = bodyArg;
61116
+ }
61117
+ (async () => {
61118
+ const response = await fetch(new URL(path, apiUrl).toString(), options);
61119
+ const text = await response.text();
61120
+ console.log(text);
61121
+ if (!response.ok) {
61122
+ process.exitCode = 1;
61123
+ }
61124
+ })().catch((error) => {
61125
+ console.error(error);
61126
+ process.exit(1);
61127
+ });
61128
+ NODE
61129
+ # Example:
61130
+ # API_URL="${baseUrl}" EVE_APP_API_METHOD=GET EVE_APP_API_PATH=/api/auth-config node - <<'NODE'
61131
+ \`\`\`
61132
+ - Discover endpoints with \`eve api spec ${name} ${contextSuffix}\` in your own shell (outside the job runtime).`;
60783
61133
  });
60784
61134
  body.description = body.description + `
60785
61135
 
@@ -61615,6 +61965,25 @@ function formatDiagnose(job, attempts, latestResult, logs, receipt) {
61615
61965
  }
61616
61966
  console.log("");
61617
61967
  }
61968
+ const llmRouting = latest.runtime_meta?.llm_routing;
61969
+ if (llmRouting) {
61970
+ const mode = llmRouting.mode === "bridge" ? "bridge" : "direct";
61971
+ const bridgeId = typeof llmRouting.bridge_id === "string" ? llmRouting.bridge_id : null;
61972
+ const harnessCompat = typeof llmRouting.harness_compatibility === "string" ? llmRouting.harness_compatibility : "unknown";
61973
+ const providerCompat = typeof llmRouting.provider_compatibility === "string" ? llmRouting.provider_compatibility : "unknown";
61974
+ const effectiveBaseUrl = typeof llmRouting.effective_base_url === "string" ? redactUrlForDisplay(llmRouting.effective_base_url) : null;
61975
+ console.log("LLM Routing:");
61976
+ console.log(` Mode: ${mode}`);
61977
+ console.log(` Harness Protocol: ${harnessCompat}`);
61978
+ console.log(` Provider Protocol: ${providerCompat}`);
61979
+ if (bridgeId) {
61980
+ console.log(` Bridge ID: ${bridgeId}`);
61981
+ }
61982
+ if (effectiveBaseUrl) {
61983
+ console.log(` Effective Base URL: ${effectiveBaseUrl}`);
61984
+ }
61985
+ console.log("");
61986
+ }
61618
61987
  }
61619
61988
  if (receipt) {
61620
61989
  console.log("Receipt Summary:");
@@ -61652,7 +62021,14 @@ function formatDiagnose(job, attempts, latestResult, logs, receipt) {
61652
62021
  console.log("");
61653
62022
  return;
61654
62023
  }
61655
- if (latestResult?.errorMessage?.includes("git clone")) {
62024
+ if (latestResult?.errorMessage?.includes("No protocol bridge")) {
62025
+ console.log(" \u2717 Protocol bridge routing failed");
62026
+ console.log(" Hint: Configure a bridge for this harness/provider protocol pair");
62027
+ console.log(" Hint: Verify bridge registry and managed model harness/provider settings");
62028
+ } else if (latestResult?.errorMessage?.includes("Bridge") && latestResult.errorMessage.includes("missing")) {
62029
+ console.log(" \u2717 Bridge runtime configuration missing");
62030
+ console.log(" Hint: Set EVE_BRIDGE_LITELLM_ANTHROPIC_OPENAI_URL and EVE_BRIDGE_LITELLM_ANTHROPIC_OPENAI_KEY");
62031
+ } else if (latestResult?.errorMessage?.includes("git clone")) {
61656
62032
  console.log(" \u2717 Git clone failed - check repo URL and credentials");
61657
62033
  console.log(" Hint: Ensure GITHUB_TOKEN is set in project/org secrets");
61658
62034
  } else if (latestResult?.errorMessage?.includes("Service")) {
@@ -61732,6 +62108,20 @@ function formatDate(dateStr) {
61732
62108
  return dateStr;
61733
62109
  }
61734
62110
  }
62111
+ function redactUrlForDisplay(value) {
62112
+ try {
62113
+ const url = new URL(value);
62114
+ if (url.username || url.password) {
62115
+ url.username = "***";
62116
+ url.password = "";
62117
+ }
62118
+ url.search = "";
62119
+ url.hash = "";
62120
+ return url.toString();
62121
+ } catch {
62122
+ return value;
62123
+ }
62124
+ }
61735
62125
  function formatDependencies(response) {
61736
62126
  console.log("");
61737
62127
  if (response.dependencies.length > 0) {
@@ -64158,9 +64548,13 @@ No token minted (use --scopes to mint a token).`);
64158
64548
  if (!orgId) {
64159
64549
  throw new Error("Usage: eve auth list-service-accounts --org <org_id>");
64160
64550
  }
64161
- const principals = await requestJson(context2, `/orgs/${orgId}/service-principals`);
64551
+ const principalsResponse = await requestJson(
64552
+ context2,
64553
+ `/orgs/${orgId}/service-principals`
64554
+ );
64555
+ const principals = unwrapListResponse(principalsResponse);
64162
64556
  if (json) {
64163
- outputJson(principals, json);
64557
+ outputJson({ data: principals }, json);
64164
64558
  return;
64165
64559
  }
64166
64560
  if (!principals || principals.length === 0) {
@@ -64186,7 +64580,11 @@ No token minted (use --scopes to mint a token).`);
64186
64580
  }
64187
64581
  let resolvedId = spId;
64188
64582
  if (!resolvedId && name) {
64189
- const principals = await requestJson(context2, `/orgs/${orgId}/service-principals`);
64583
+ const principalsResponse = await requestJson(
64584
+ context2,
64585
+ `/orgs/${orgId}/service-principals`
64586
+ );
64587
+ const principals = unwrapListResponse(principalsResponse);
64190
64588
  const match = principals?.find((sp) => sp.name === name);
64191
64589
  if (!match) {
64192
64590
  throw new Error(`Service account not found: ${name}`);
@@ -67189,7 +67587,7 @@ async function handleList5(positionals, flags, context2, jsonOutput) {
67189
67587
  throw new Error("Usage: eve api list [project] [--project=<id>] [--env=<name>]");
67190
67588
  }
67191
67589
  const query = buildQuery8({
67192
- env: getStringFlag(flags, ["env"])
67590
+ env: resolveEnv(flags)
67193
67591
  });
67194
67592
  const response = await requestJson(
67195
67593
  context2,
@@ -67208,7 +67606,7 @@ async function handleList5(positionals, flags, context2, jsonOutput) {
67208
67606
  async function handleShow5(positionals, flags, context2, jsonOutput) {
67209
67607
  const name = positionals[0] ?? getStringFlag(flags, ["name"]);
67210
67608
  const projectId = positionals[1] ?? getStringFlag(flags, ["project"]) ?? context2.projectId;
67211
- const env = getStringFlag(flags, ["env"]);
67609
+ const env = resolveEnv(flags);
67212
67610
  if (!name || !projectId) {
67213
67611
  throw new Error("Usage: eve api show <name> [project] [--project=<id>] [--env=<name>]");
67214
67612
  }
@@ -67219,7 +67617,7 @@ async function handleShow5(positionals, flags, context2, jsonOutput) {
67219
67617
  async function handleSpec(positionals, flags, context2, jsonOutput) {
67220
67618
  const name = positionals[0] ?? getStringFlag(flags, ["name"]);
67221
67619
  const projectId = positionals[1] ?? getStringFlag(flags, ["project"]) ?? context2.projectId;
67222
- const env = getStringFlag(flags, ["env"]);
67620
+ const env = resolveEnv(flags);
67223
67621
  if (!name || !projectId) {
67224
67622
  throw new Error("Usage: eve api spec <name> [project] [--project=<id>] [--env=<name>]");
67225
67623
  }
@@ -67233,7 +67631,7 @@ async function handleSpec(positionals, flags, context2, jsonOutput) {
67233
67631
  async function handleRefresh(positionals, flags, context2, jsonOutput) {
67234
67632
  const name = positionals[0] ?? getStringFlag(flags, ["name"]);
67235
67633
  const projectId = positionals[1] ?? getStringFlag(flags, ["project"]) ?? context2.projectId;
67236
- const env = getStringFlag(flags, ["env"]);
67634
+ const env = resolveEnv(flags);
67237
67635
  if (!name || !projectId) {
67238
67636
  throw new Error("Usage: eve api refresh <name> [project] [--project=<id>] [--env=<name>]");
67239
67637
  }
@@ -67246,7 +67644,7 @@ async function handleRefresh(positionals, flags, context2, jsonOutput) {
67246
67644
  async function handleExamples(positionals, flags, context2, jsonOutput) {
67247
67645
  const name = positionals[0] ?? getStringFlag(flags, ["name"]);
67248
67646
  const projectId = positionals[1] ?? getStringFlag(flags, ["project"]) ?? context2.projectId;
67249
- const env = getStringFlag(flags, ["env"]);
67647
+ const env = resolveEnv(flags);
67250
67648
  if (!name || !projectId) {
67251
67649
  throw new Error("Usage: eve api examples <name> [project] [--project=<id>] [--env=<name>]");
67252
67650
  }
@@ -67309,7 +67707,7 @@ async function handleCall(positionals, flags, context2) {
67309
67707
  throw new Error("Usage: eve api call <name> <method> <path> [--json <payload>] [--jq <expr>]");
67310
67708
  }
67311
67709
  const projectId = getStringFlag(flags, ["project"]) ?? context2.projectId;
67312
- const env = getStringFlag(flags, ["env"]);
67710
+ const env = resolveEnv(flags);
67313
67711
  if (!projectId) {
67314
67712
  throw new Error("Missing project id. Provide --project or set a profile default.");
67315
67713
  }
@@ -67317,9 +67715,10 @@ async function handleCall(positionals, flags, context2) {
67317
67715
  const api = await requestJson(context2, `/projects/${projectId}/apis/${name}${query}`);
67318
67716
  const jqExpr = getStringFlag(flags, ["jq"]);
67319
67717
  const printCurl = Boolean(flags["print-curl"]);
67320
- const jsonPayloadFlag = flags.json;
67718
+ const extraPositionals = positionals.slice(3);
67719
+ const jsonPayloadFlag = resolveJsonPayloadFlag(flags, extraPositionals);
67321
67720
  if (jsonPayloadFlag === true) {
67322
- throw new Error("Usage: --json <payload|@file>");
67721
+ throw new Error("Usage: --json <payload|@file> (or --data/-d)");
67323
67722
  }
67324
67723
  const graphqlFlag = flags.graphql;
67325
67724
  const graphqlQuery = graphqlFlag === true ? void 0 : getStringFlag(flags, ["graphql"]);
@@ -67327,7 +67726,7 @@ async function handleCall(positionals, flags, context2) {
67327
67726
  throw new Error("Usage: --graphql <query|@file>");
67328
67727
  }
67329
67728
  if (graphqlQuery && jsonPayloadFlag) {
67330
- throw new Error("Use --variables for GraphQL variables; --json is for JSON bodies.");
67729
+ throw new Error("Use --variables for GraphQL variables; --json/--data/-d is for JSON bodies.");
67331
67730
  }
67332
67731
  const variablesFlag = getStringFlag(flags, ["variables"]);
67333
67732
  const variables = variablesFlag ? resolveJsonInput(variablesFlag) : void 0;
@@ -67338,7 +67737,8 @@ async function handleCall(positionals, flags, context2) {
67338
67737
  } : void 0;
67339
67738
  const body = graphqlBody ?? jsonBody;
67340
67739
  const method = methodInput.toUpperCase();
67341
- const path6 = resolveApiPath(api.base_url, pathInput);
67740
+ const resolvedBaseUrl = resolveApiBaseUrlForRuntime(api.base_url, context2.apiUrl);
67741
+ const path6 = resolveApiPath(resolvedBaseUrl, pathInput);
67342
67742
  const tokenOverride = getStringFlag(flags, ["token"]);
67343
67743
  const authToken = tokenOverride ?? process.env.EVE_JOB_TOKEN ?? context2.token;
67344
67744
  if (printCurl) {
@@ -67376,10 +67776,49 @@ async function handleCall(positionals, flags, context2) {
67376
67776
  }
67377
67777
  process.stdout.write(text);
67378
67778
  }
67779
+ function resolveJsonPayloadFlag(flags, extraPositionals) {
67780
+ const jsonFlag = flags.json;
67781
+ const dataFlag = flags.data;
67782
+ const shorthandDataFlag = resolveShorthandDataFlag(extraPositionals);
67783
+ const candidates = [jsonFlag, dataFlag, shorthandDataFlag].filter(
67784
+ (value) => value !== void 0
67785
+ );
67786
+ if (candidates.length <= 1) {
67787
+ return candidates[0];
67788
+ }
67789
+ const [first, ...rest] = candidates;
67790
+ const conflicts = rest.some((value) => value !== first);
67791
+ if (conflicts) {
67792
+ throw new Error("Use only one JSON body flag: --json, --data, or -d.");
67793
+ }
67794
+ return first;
67795
+ }
67796
+ function resolveShorthandDataFlag(extraPositionals) {
67797
+ for (let i = 0; i < extraPositionals.length; i += 1) {
67798
+ const arg = extraPositionals[i];
67799
+ if (arg.startsWith("--data=")) {
67800
+ return arg.slice("--data=".length);
67801
+ }
67802
+ if (arg.startsWith("-d=")) {
67803
+ return arg.slice("-d=".length);
67804
+ }
67805
+ if (arg === "--data" || arg === "-d") {
67806
+ const next = extraPositionals[i + 1];
67807
+ if (!next || next.startsWith("-")) {
67808
+ return true;
67809
+ }
67810
+ return next;
67811
+ }
67812
+ }
67813
+ return void 0;
67814
+ }
67379
67815
  function buildQuery8(params) {
67380
67816
  const query = Object.entries(params).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`).join("&");
67381
67817
  return query ? `?${query}` : "";
67382
67818
  }
67819
+ function resolveEnv(flags) {
67820
+ return getStringFlag(flags, ["env"]) ?? process.env.EVE_ENV_NAME;
67821
+ }
67383
67822
  function formatApiSourcesTable(apis) {
67384
67823
  const nameWidth = Math.max(4, ...apis.map((api) => api.name.length));
67385
67824
  const typeWidth = Math.max(4, ...apis.map((api) => api.type.length));
@@ -67453,6 +67892,96 @@ function resolveApiPath(baseUrl, path6) {
67453
67892
  const trimmedPath = path6.startsWith("/") ? path6 : `/${path6}`;
67454
67893
  return `${trimmedBase}${trimmedPath}`;
67455
67894
  }
67895
+ function resolveApiBaseUrlForRuntime(baseUrl, eveApiUrl) {
67896
+ if (!baseUrl) return baseUrl;
67897
+ const inK8s = Boolean(process.env.KUBERNETES_SERVICE_HOST);
67898
+ if (inK8s) {
67899
+ return rewriteIngressToServiceDns(baseUrl) ?? baseUrl;
67900
+ }
67901
+ return rewriteServiceDnsToIngress(baseUrl, eveApiUrl) ?? baseUrl;
67902
+ }
67903
+ function rewriteIngressToServiceDns(baseUrl) {
67904
+ try {
67905
+ const url = new URL(baseUrl);
67906
+ if (url.hostname.endsWith(".svc.cluster.local")) {
67907
+ return baseUrl;
67908
+ }
67909
+ const labels = url.hostname.split(".");
67910
+ if (labels.length < 3) {
67911
+ return null;
67912
+ }
67913
+ const component = labels[0];
67914
+ const slug = labels[1];
67915
+ const slugParts = slug.split("-");
67916
+ if (slugParts.length < 3) {
67917
+ return null;
67918
+ }
67919
+ const envName = slugParts[slugParts.length - 1];
67920
+ const namespace = `eve-${slug}`;
67921
+ const internalHost = `${envName}-${component}.${namespace}.svc.cluster.local`;
67922
+ url.hostname = internalHost;
67923
+ return stripTrailingSlash(url.toString());
67924
+ } catch {
67925
+ return null;
67926
+ }
67927
+ }
67928
+ function rewriteServiceDnsToIngress(baseUrl, eveApiUrl) {
67929
+ try {
67930
+ const url = new URL(baseUrl);
67931
+ if (!url.hostname.endsWith(".svc.cluster.local")) {
67932
+ return null;
67933
+ }
67934
+ const labels = url.hostname.split(".");
67935
+ if (labels.length < 5) {
67936
+ return null;
67937
+ }
67938
+ const serviceLabel = labels[0];
67939
+ const namespace = labels[1];
67940
+ if (!namespace.startsWith("eve-")) {
67941
+ return null;
67942
+ }
67943
+ const slug = namespace.slice(4);
67944
+ const slugParts = slug.split("-");
67945
+ if (slugParts.length < 3) {
67946
+ return null;
67947
+ }
67948
+ const envName = slugParts[slugParts.length - 1];
67949
+ const envPrefix = `${envName}-`;
67950
+ if (!serviceLabel.startsWith(envPrefix)) {
67951
+ return null;
67952
+ }
67953
+ const component = serviceLabel.slice(envPrefix.length);
67954
+ if (!component) {
67955
+ return null;
67956
+ }
67957
+ const ingressDomain = inferIngressDomain(eveApiUrl);
67958
+ if (!ingressDomain) {
67959
+ return null;
67960
+ }
67961
+ url.hostname = `${component}.${slug}.${ingressDomain}`;
67962
+ url.port = "";
67963
+ return stripTrailingSlash(url.toString());
67964
+ } catch {
67965
+ return null;
67966
+ }
67967
+ }
67968
+ function inferIngressDomain(eveApiUrl) {
67969
+ try {
67970
+ const apiHost = new URL(eveApiUrl).hostname;
67971
+ if (apiHost.startsWith("api.eve.")) {
67972
+ return apiHost.slice("api.eve.".length);
67973
+ }
67974
+ if (apiHost.startsWith("api.")) {
67975
+ return apiHost.slice("api.".length);
67976
+ }
67977
+ return process.env.EVE_DEFAULT_DOMAIN ?? null;
67978
+ } catch {
67979
+ return process.env.EVE_DEFAULT_DOMAIN ?? null;
67980
+ }
67981
+ }
67982
+ function stripTrailingSlash(url) {
67983
+ return url.endsWith("/") ? url.slice(0, -1) : url;
67984
+ }
67456
67985
  function resolveRepoRoot() {
67457
67986
  let current = process.cwd();
67458
67987
  while (true) {
@@ -68777,12 +69306,13 @@ ${response.length} record(s)`);
68777
69306
  return;
68778
69307
  }
68779
69308
  default: {
68780
- const requests = await requestJson(
69309
+ const requestsResponse = await requestJson(
68781
69310
  context2,
68782
69311
  "/admin/access-requests"
68783
69312
  );
69313
+ const requests = unwrapListResponse(requestsResponse);
68784
69314
  if (json) {
68785
- outputJson(requests, true);
69315
+ outputJson({ data: requests }, true);
68786
69316
  return;
68787
69317
  }
68788
69318
  if (requests.length === 0) {
@@ -70979,12 +71509,13 @@ async function handleRoles(action, positionals, flags, context2, json) {
70979
71509
  return;
70980
71510
  }
70981
71511
  case "list": {
70982
- const roles = await requestJson(
71512
+ const rolesResponse = await requestJson(
70983
71513
  context2,
70984
71514
  `/orgs/${orgId}/access/roles`
70985
71515
  );
71516
+ const roles = unwrapListResponse(rolesResponse);
70986
71517
  if (json) {
70987
- outputJson(roles, json);
71518
+ outputJson({ data: roles }, json);
70988
71519
  return;
70989
71520
  }
70990
71521
  if (roles.length === 0) {
@@ -71002,10 +71533,11 @@ async function handleRoles(action, positionals, flags, context2, json) {
71002
71533
  if (!name) {
71003
71534
  throw new Error("Role name is required: eve access roles show <name> --org <org_id>");
71004
71535
  }
71005
- const roles = await requestJson(
71536
+ const rolesResponse = await requestJson(
71006
71537
  context2,
71007
71538
  `/orgs/${orgId}/access/roles`
71008
71539
  );
71540
+ const roles = unwrapListResponse(rolesResponse);
71009
71541
  const role = roles.find((r) => r.name === name);
71010
71542
  if (!role) {
71011
71543
  throw new Error(`Role '${name}' not found in this org`);
@@ -71030,10 +71562,11 @@ async function handleRoles(action, positionals, flags, context2, json) {
71030
71562
  if (!name) {
71031
71563
  throw new Error("Role name is required: eve access roles update <name> --org <org_id> [--permissions <perms>] [--add-permissions <perms>] [--description <desc>]");
71032
71564
  }
71033
- const roles = await requestJson(
71565
+ const rolesResponse = await requestJson(
71034
71566
  context2,
71035
71567
  `/orgs/${orgId}/access/roles`
71036
71568
  );
71569
+ const roles = unwrapListResponse(rolesResponse);
71037
71570
  const role = roles.find((r) => r.name === name);
71038
71571
  if (!role) {
71039
71572
  throw new Error(`Role '${name}' not found in this org`);
@@ -71076,10 +71609,11 @@ async function handleRoles(action, positionals, flags, context2, json) {
71076
71609
  if (!name) {
71077
71610
  throw new Error("Role name is required: eve access roles delete <name> --org <org_id>");
71078
71611
  }
71079
- const roles = await requestJson(
71612
+ const rolesResponse = await requestJson(
71080
71613
  context2,
71081
71614
  `/orgs/${orgId}/access/roles`
71082
71615
  );
71616
+ const roles = unwrapListResponse(rolesResponse);
71083
71617
  const role = roles.find((r) => r.name === name);
71084
71618
  if (!role) {
71085
71619
  throw new Error(`Role '${name}' not found in this org`);
@@ -71169,10 +71703,11 @@ async function handleUnbind(flags, context2, json) {
71169
71703
  if (projectId) {
71170
71704
  params.set("project_id", projectId);
71171
71705
  }
71172
- const bindings = await requestJson(
71706
+ const bindingsResponse = await requestJson(
71173
71707
  context2,
71174
71708
  `/orgs/${orgId}/access/bindings?${params.toString()}`
71175
71709
  );
71710
+ const bindings = unwrapListResponse(bindingsResponse);
71176
71711
  const matching = bindings.find((b) => {
71177
71712
  if (b.role_name !== roleName) return false;
71178
71713
  if (b.principal_type !== principalType) return false;
@@ -71212,9 +71747,10 @@ async function handleBindings(action, flags, context2, json) {
71212
71747
  }
71213
71748
  const queryString = params.toString();
71214
71749
  const path6 = queryString ? `/orgs/${orgId}/access/bindings?${queryString}` : `/orgs/${orgId}/access/bindings`;
71215
- const bindings = await requestJson(context2, path6);
71750
+ const bindingsResponse = await requestJson(context2, path6);
71751
+ const bindings = unwrapListResponse(bindingsResponse);
71216
71752
  if (json) {
71217
- outputJson(bindings, json);
71753
+ outputJson({ data: bindings }, json);
71218
71754
  return;
71219
71755
  }
71220
71756
  if (bindings.length === 0) {
@@ -71323,10 +71859,12 @@ function bindingKey(roleName, principalType, principalId, projectId) {
71323
71859
  return `${roleName}|${principalType}|${principalId}|${scope}`;
71324
71860
  }
71325
71861
  async function computePlan(yaml, orgId, context2) {
71326
- const [apiRoles, apiBindings] = await Promise.all([
71862
+ const [apiRolesResponse, apiBindingsResponse] = await Promise.all([
71327
71863
  requestJson(context2, `/orgs/${orgId}/access/roles`),
71328
71864
  requestJson(context2, `/orgs/${orgId}/access/bindings`)
71329
71865
  ]);
71866
+ const apiRoles = unwrapListResponse(apiRolesResponse);
71867
+ const apiBindings = unwrapListResponse(apiBindingsResponse);
71330
71868
  const rolesByName = new Map(apiRoles.map((r) => [r.name, r]));
71331
71869
  const plan = {
71332
71870
  roles: [],
@@ -71945,7 +72483,7 @@ async function handleResources(subcommand, positionals, flags, context2) {
71945
72483
  if (!uri) {
71946
72484
  throw new Error("Usage: eve resources cat <uri>");
71947
72485
  }
71948
- const result = await requestJson(
72486
+ const resultResponse = await requestJson(
71949
72487
  context2,
71950
72488
  `/orgs/${orgId}/resources/resolve`,
71951
72489
  {
@@ -71953,8 +72491,9 @@ async function handleResources(subcommand, positionals, flags, context2) {
71953
72491
  body: { uris: [uri], include_content: true }
71954
72492
  }
71955
72493
  );
72494
+ const result = unwrapListResponse(resultResponse);
71956
72495
  if (json) {
71957
- outputJson(result, json);
72496
+ outputJson({ data: result }, json);
71958
72497
  return;
71959
72498
  }
71960
72499
  const content = result?.[0]?.content;
@@ -72310,6 +72849,374 @@ async function handleAnalytics(subcommand, _positionals, flags, context2) {
72310
72849
  }
72311
72850
  }
72312
72851
 
72852
+ // src/commands/ollama.ts
72853
+ function asString(flags, key) {
72854
+ const value = flags[key];
72855
+ return typeof value === "string" ? value : void 0;
72856
+ }
72857
+ function requireString(flags, key) {
72858
+ const value = asString(flags, key);
72859
+ if (!value) throw new Error(`Missing required flag --${key}`);
72860
+ return value;
72861
+ }
72862
+ function printTable(headers, rows) {
72863
+ const widths = headers.map((header, idx) => Math.max(header.length, ...rows.map((row) => row[idx]?.length ?? 0)));
72864
+ const line = `+${widths.map((w) => "-".repeat(w + 2)).join("+")}+`;
72865
+ console.log(line);
72866
+ console.log(formatRow3(headers, widths));
72867
+ console.log(line);
72868
+ for (const row of rows) {
72869
+ console.log(formatRow3(row, widths));
72870
+ }
72871
+ console.log(line);
72872
+ }
72873
+ function formatRow3(columns, widths) {
72874
+ const padded = columns.map((value, idx) => ` ${pad2(value, widths[idx])} `);
72875
+ return `|${padded.join("|")}|`;
72876
+ }
72877
+ function pad2(value, width) {
72878
+ return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
72879
+ }
72880
+ async function handleOllama(subcommand, positionals, flags, context2) {
72881
+ const json = Boolean(flags.json);
72882
+ switch (subcommand) {
72883
+ case "targets": {
72884
+ const scopeKind = asString(flags, "scope-kind");
72885
+ const scopeId = asString(flags, "scope-id");
72886
+ const query = new URLSearchParams();
72887
+ if (scopeKind) query.set("scope_kind", scopeKind);
72888
+ if (scopeId) query.set("scope_id", scopeId);
72889
+ const suffix = query.toString() ? `?${query.toString()}` : "";
72890
+ const targets = await requestJson(context2, `/inference/targets${suffix}`);
72891
+ if (json) {
72892
+ outputJson(targets, json);
72893
+ return;
72894
+ }
72895
+ if (targets.length === 0) {
72896
+ console.log("No inference targets found.");
72897
+ return;
72898
+ }
72899
+ printTable(
72900
+ ["ID", "Name", "Scope", "Type", "Transport", "Status", "Base URL"],
72901
+ targets.map((item) => [
72902
+ item.id,
72903
+ item.name,
72904
+ item.scope_id ? `${item.scope_kind}:${item.scope_id}` : item.scope_kind,
72905
+ item.target_type,
72906
+ item.transport_profile,
72907
+ item.status,
72908
+ item.base_url
72909
+ ])
72910
+ );
72911
+ return;
72912
+ }
72913
+ case "target": {
72914
+ const action = positionals[0];
72915
+ if (action === "add") {
72916
+ const body = {
72917
+ scope_kind: asString(flags, "scope-kind") ?? "platform",
72918
+ name: requireString(flags, "name"),
72919
+ target_type: asString(flags, "target-type") ?? "external_ollama",
72920
+ transport_profile: asString(flags, "transport-profile") ?? "ollama_api",
72921
+ base_url: requireString(flags, "base-url")
72922
+ };
72923
+ const scopeId = asString(flags, "scope-id");
72924
+ if (scopeId) body.scope_id = scopeId;
72925
+ const apiKeyRef = asString(flags, "api-key-ref");
72926
+ if (apiKeyRef) {
72927
+ body.transport_metadata = {
72928
+ api_key_ref: apiKeyRef,
72929
+ auth_header: asString(flags, "auth-header") ?? "Authorization",
72930
+ auth_scheme: asString(flags, "auth-scheme") ?? "Bearer"
72931
+ };
72932
+ }
72933
+ const created = await requestJson(context2, "/inference/targets", {
72934
+ method: "POST",
72935
+ body
72936
+ });
72937
+ outputJson(created, json);
72938
+ if (!json) console.log(`Created target ${created.id}`);
72939
+ return;
72940
+ }
72941
+ if (action === "rm") {
72942
+ const targetId = positionals[1];
72943
+ if (!targetId) throw new Error("Usage: eve ollama target rm <target-id>");
72944
+ await requestJson(context2, `/inference/targets/${targetId}`, {
72945
+ method: "DELETE"
72946
+ });
72947
+ if (!json) console.log(`Deleted target ${targetId}`);
72948
+ return;
72949
+ }
72950
+ if (action === "test") {
72951
+ const targetId = positionals[1];
72952
+ if (!targetId) throw new Error("Usage: eve ollama target test <target-id> [--org-id <id>] [--project-id <id>]");
72953
+ const query = new URLSearchParams();
72954
+ const orgId = asString(flags, "org-id");
72955
+ const projectId = asString(flags, "project-id");
72956
+ if (orgId) query.set("org_id", orgId);
72957
+ if (projectId) query.set("project_id", projectId);
72958
+ const suffix = query.toString() ? `?${query.toString()}` : "";
72959
+ const result = await requestJson(context2, `/inference/targets/${targetId}/test${suffix}`, {
72960
+ method: "POST"
72961
+ });
72962
+ outputJson(result, json);
72963
+ if (!json) console.log("Target test completed");
72964
+ return;
72965
+ }
72966
+ throw new Error("Usage: eve ollama target <add|rm|test> ...");
72967
+ }
72968
+ case "models": {
72969
+ const models = await requestJson(context2, "/inference/models");
72970
+ if (json) {
72971
+ outputJson(models, json);
72972
+ return;
72973
+ }
72974
+ if (models.length === 0) {
72975
+ console.log("No inference models found.");
72976
+ return;
72977
+ }
72978
+ printTable(
72979
+ ["ID", "Canonical", "Provider", "Provider Slug"],
72980
+ models.map((item) => [item.id, item.canonical_model_id, item.provider, item.provider_model_slug])
72981
+ );
72982
+ return;
72983
+ }
72984
+ case "model": {
72985
+ const action = positionals[0];
72986
+ if (action !== "add") throw new Error("Usage: eve ollama model add --canonical <id> --provider <name> --slug <provider-model-slug>");
72987
+ const created = await requestJson(context2, "/inference/models", {
72988
+ method: "POST",
72989
+ body: {
72990
+ canonical_model_id: requireString(flags, "canonical"),
72991
+ provider: requireString(flags, "provider"),
72992
+ provider_model_slug: requireString(flags, "slug")
72993
+ }
72994
+ });
72995
+ outputJson(created, json);
72996
+ if (!json) console.log(`Model available as ${created.id}`);
72997
+ return;
72998
+ }
72999
+ case "aliases": {
73000
+ const scopeKind = asString(flags, "scope-kind");
73001
+ const scopeId = asString(flags, "scope-id");
73002
+ const query = new URLSearchParams();
73003
+ if (scopeKind) query.set("scope_kind", scopeKind);
73004
+ if (scopeId) query.set("scope_id", scopeId);
73005
+ const suffix = query.toString() ? `?${query.toString()}` : "";
73006
+ const aliases = await requestJson(context2, `/inference/aliases${suffix}`);
73007
+ if (json) {
73008
+ outputJson(aliases, json);
73009
+ return;
73010
+ }
73011
+ if (aliases.length === 0) {
73012
+ console.log("No inference aliases found.");
73013
+ return;
73014
+ }
73015
+ printTable(
73016
+ ["Alias", "Scope", "Target ID", "Model ID"],
73017
+ aliases.map((item) => [
73018
+ item.alias,
73019
+ item.scope_id ? `${item.scope_kind}:${item.scope_id}` : item.scope_kind,
73020
+ item.target_id,
73021
+ item.model_id
73022
+ ])
73023
+ );
73024
+ return;
73025
+ }
73026
+ case "alias": {
73027
+ const action = positionals[0];
73028
+ if (action === "set") {
73029
+ const alias = requireString(flags, "alias");
73030
+ const targetId = requireString(flags, "target-id");
73031
+ const modelId = requireString(flags, "model-id");
73032
+ const scopeKind = asString(flags, "scope-kind") ?? "platform";
73033
+ const scopeId = asString(flags, "scope-id");
73034
+ const body = {
73035
+ alias,
73036
+ target_id: targetId,
73037
+ model_id: modelId,
73038
+ scope_kind: scopeKind
73039
+ };
73040
+ if (scopeId) body.scope_id = scopeId;
73041
+ const saved = await requestJson(context2, "/inference/aliases", {
73042
+ method: "POST",
73043
+ body
73044
+ });
73045
+ outputJson(saved, json);
73046
+ if (!json) console.log(`Alias ${alias} saved`);
73047
+ return;
73048
+ }
73049
+ if (action === "rm") {
73050
+ const scopeKind = asString(flags, "scope-kind") ?? "platform";
73051
+ const alias = requireString(flags, "alias");
73052
+ const scopeId = asString(flags, "scope-id");
73053
+ const query = new URLSearchParams();
73054
+ if (scopeId) query.set("scope_id", scopeId);
73055
+ const suffix = query.toString() ? `?${query.toString()}` : "";
73056
+ await requestJson(context2, `/inference/aliases/${scopeKind}/${alias}${suffix}`, {
73057
+ method: "DELETE"
73058
+ });
73059
+ if (!json) console.log(`Alias ${alias} deleted`);
73060
+ return;
73061
+ }
73062
+ throw new Error("Usage: eve ollama alias <set|rm> ...");
73063
+ }
73064
+ case "installs": {
73065
+ const targetId = asString(flags, "target-id");
73066
+ const modelId = asString(flags, "model-id");
73067
+ const query = new URLSearchParams();
73068
+ if (targetId) query.set("target_id", targetId);
73069
+ if (modelId) query.set("model_id", modelId);
73070
+ const suffix = query.toString() ? `?${query.toString()}` : "";
73071
+ const installs = await requestJson(context2, `/inference/installs${suffix}`);
73072
+ if (json) {
73073
+ outputJson(installs, json);
73074
+ return;
73075
+ }
73076
+ if (installs.length === 0) {
73077
+ console.log("No inference installs found.");
73078
+ return;
73079
+ }
73080
+ printTable(
73081
+ ["ID", "Target ID", "Model ID", "Warm Start", "Min Capacity"],
73082
+ installs.map((item) => [
73083
+ item.id,
73084
+ item.target_id,
73085
+ item.model_id,
73086
+ item.requires_warm_start ? "yes" : "no",
73087
+ String(item.min_target_capacity)
73088
+ ])
73089
+ );
73090
+ return;
73091
+ }
73092
+ case "assignments": {
73093
+ const scopeKind = asString(flags, "scope-kind");
73094
+ const scopeId = asString(flags, "scope-id");
73095
+ const query = new URLSearchParams();
73096
+ if (scopeKind) query.set("scope_kind", scopeKind);
73097
+ if (scopeId) query.set("scope_id", scopeId);
73098
+ const suffix = query.toString() ? `?${query.toString()}` : "";
73099
+ const assignments = await requestJson(context2, `/inference/assignments${suffix}`);
73100
+ if (json) {
73101
+ outputJson(assignments, json);
73102
+ return;
73103
+ }
73104
+ if (assignments.length === 0) {
73105
+ console.log("No inference assignments found.");
73106
+ return;
73107
+ }
73108
+ printTable(
73109
+ ["Target", "Scope", "Inflight", "Queue", "Max Inflight", "Status"],
73110
+ assignments.map((item) => [
73111
+ item.target_name,
73112
+ item.scope_id ? `${item.scope_kind}:${item.scope_id}` : item.scope_kind,
73113
+ String(item.inflight),
73114
+ String(item.queue_depth),
73115
+ String(item.max_concurrent_inflight),
73116
+ item.status
73117
+ ])
73118
+ );
73119
+ return;
73120
+ }
73121
+ case "route-policies": {
73122
+ const scopeKind = asString(flags, "scope-kind");
73123
+ const scopeId = asString(flags, "scope-id");
73124
+ const query = new URLSearchParams();
73125
+ if (scopeKind) query.set("scope_kind", scopeKind);
73126
+ if (scopeId) query.set("scope_id", scopeId);
73127
+ const suffix = query.toString() ? `?${query.toString()}` : "";
73128
+ const policies = await requestJson(context2, `/inference/route-policies${suffix}`);
73129
+ if (json) {
73130
+ outputJson(policies, json);
73131
+ return;
73132
+ }
73133
+ if (policies.length === 0) {
73134
+ console.log("No inference route policies found.");
73135
+ return;
73136
+ }
73137
+ printTable(
73138
+ ["Scope", "Preferred Target", "Fallback"],
73139
+ policies.map((item) => [
73140
+ item.scope_id ? `${item.scope_kind}:${item.scope_id}` : item.scope_kind,
73141
+ item.preferred_target_id,
73142
+ item.fallback_to_alias_target ? "yes" : "no"
73143
+ ])
73144
+ );
73145
+ return;
73146
+ }
73147
+ case "route-policy": {
73148
+ const action = positionals[0];
73149
+ if (action === "set") {
73150
+ const scopeKind = asString(flags, "scope-kind") ?? "platform";
73151
+ const scopeId = asString(flags, "scope-id");
73152
+ const preferredTargetId = requireString(flags, "preferred-target-id");
73153
+ const fallback = asString(flags, "fallback-to-alias-target");
73154
+ const body = {
73155
+ scope_kind: scopeKind,
73156
+ preferred_target_id: preferredTargetId
73157
+ };
73158
+ if (scopeId) body.scope_id = scopeId;
73159
+ if (fallback !== void 0) body.fallback_to_alias_target = fallback === "true" || fallback === "1";
73160
+ const saved = await requestJson(context2, "/inference/route-policies", {
73161
+ method: "POST",
73162
+ body
73163
+ });
73164
+ outputJson(saved, json);
73165
+ if (!json) console.log("Route policy saved");
73166
+ return;
73167
+ }
73168
+ if (action === "rm") {
73169
+ const scopeKind = asString(flags, "scope-kind") ?? "platform";
73170
+ const scopeId = asString(flags, "scope-id");
73171
+ const query = new URLSearchParams();
73172
+ if (scopeId) query.set("scope_id", scopeId);
73173
+ const suffix = query.toString() ? `?${query.toString()}` : "";
73174
+ await requestJson(context2, `/inference/route-policies/${scopeKind}${suffix}`, {
73175
+ method: "DELETE"
73176
+ });
73177
+ if (!json) console.log("Route policy deleted");
73178
+ return;
73179
+ }
73180
+ throw new Error("Usage: eve ollama route-policy <set|rm> [options]");
73181
+ }
73182
+ case "install": {
73183
+ const action = positionals[0];
73184
+ if (action === "add") {
73185
+ const targetId = requireString(flags, "target-id");
73186
+ const modelId = requireString(flags, "model-id");
73187
+ const body = {};
73188
+ const requiresWarmStart = asString(flags, "requires-warm-start");
73189
+ if (requiresWarmStart !== void 0) {
73190
+ body.requires_warm_start = requiresWarmStart === "true" || requiresWarmStart === "1";
73191
+ }
73192
+ const minTargetCapacity = asString(flags, "min-target-capacity");
73193
+ if (minTargetCapacity) {
73194
+ body.min_target_capacity = Number(minTargetCapacity);
73195
+ }
73196
+ const saved = await requestJson(context2, `/inference/targets/${targetId}/models/${modelId}`, {
73197
+ method: "POST",
73198
+ body
73199
+ });
73200
+ outputJson(saved, json);
73201
+ if (!json) console.log(`Installed model ${modelId} on target ${targetId}`);
73202
+ return;
73203
+ }
73204
+ if (action === "rm") {
73205
+ const targetId = requireString(flags, "target-id");
73206
+ const modelId = requireString(flags, "model-id");
73207
+ await requestJson(context2, `/inference/targets/${targetId}/models/${modelId}`, {
73208
+ method: "DELETE"
73209
+ });
73210
+ if (!json) console.log(`Removed model ${modelId} from target ${targetId}`);
73211
+ return;
73212
+ }
73213
+ throw new Error("Usage: eve ollama install <add|rm> --target-id <id> --model-id <id>");
73214
+ }
73215
+ default:
73216
+ throw new Error("Usage: eve ollama <targets|target|models|model|aliases|alias|installs|install|assignments|route-policies|route-policy>");
73217
+ }
73218
+ }
73219
+
72313
73220
  // src/index.ts
72314
73221
  async function main() {
72315
73222
  const { flags, positionals } = parseArgs(process.argv.slice(2));
@@ -72433,6 +73340,9 @@ async function main() {
72433
73340
  case "analytics":
72434
73341
  await handleAnalytics(subcommand, rest, flags, context2);
72435
73342
  return;
73343
+ case "ollama":
73344
+ await handleOllama(subcommand, rest, flags, context2);
73345
+ return;
72436
73346
  default:
72437
73347
  showMainHelp();
72438
73348
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eve-horizon/cli",
3
- "version": "0.2.19",
3
+ "version": "0.2.20",
4
4
  "description": "Eve Horizon CLI",
5
5
  "license": "MIT",
6
6
  "repository": {