@eve-horizon/cli 0.2.43 → 0.2.44

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.
@@ -45,6 +45,8 @@ spec:
45
45
  value: http://eve-api:4701
46
46
  - name: EVE_PUBLIC_API_URL
47
47
  value: http://api.eve.lvh.me
48
+ - name: EVE_SSO_URL
49
+ value: http://sso.eve.lvh.me
48
50
  - name: DATABASE_URL
49
51
  value: postgres://eve:eve@postgres.eve.svc.cluster.local:5432/eve
50
52
  - name: WORKER_PORT
package/dist/index.js CHANGED
@@ -50320,6 +50320,24 @@ for cloud deployments. Credentials are stored globally per API URL.`,
50320
50320
  "eve skills install"
50321
50321
  ]
50322
50322
  },
50323
+ user: {
50324
+ description: "Look up user profiles and memberships.",
50325
+ usage: "eve user <subcommand> [options]",
50326
+ subcommands: {
50327
+ show: {
50328
+ description: "Show user profile with org and project memberships",
50329
+ usage: "eve user show [user_id|me]",
50330
+ options: [
50331
+ "--json Output as JSON"
50332
+ ],
50333
+ examples: [
50334
+ "eve user show me",
50335
+ "eve user show usr_abc123",
50336
+ "eve user show me --json"
50337
+ ]
50338
+ }
50339
+ }
50340
+ },
50323
50341
  admin: {
50324
50342
  description: "Administrative commands for user, identity, and platform operations.",
50325
50343
  usage: "eve admin <subcommand> [options]",
@@ -50899,21 +50917,27 @@ Requires Docker Desktop; k3d and kubectl are auto-managed by the CLI.`,
50899
50917
  usage: "eve chat <subcommand> [options]",
50900
50918
  subcommands: {
50901
50919
  simulate: {
50902
- description: "Simulate an inbound chat message",
50903
- usage: "eve chat simulate --project <id> --team-id <team> --text <message>",
50920
+ description: "Simulate an inbound chat message via the gateway",
50921
+ usage: "eve chat simulate --team-id <team> --text <message>",
50904
50922
  options: [
50905
- "--project <id> Project ID (uses profile default)",
50906
- "--provider <name> Provider name (default: slack)",
50907
- "--team-id <id> Slack team ID",
50908
- "--channel-id <id> Channel ID",
50909
- "--user-id <id> User ID",
50910
- "--thread-key <key> Thread key override",
50911
- "--metadata <json> Extra metadata JSON"
50923
+ "--team-id <id> Slack team ID (required)",
50924
+ "--text <msg> Message text (required)",
50925
+ "--provider <name> Provider name (default: slack)",
50926
+ "--channel-id <id> Channel ID",
50927
+ "--user-id <id> User ID",
50928
+ "--external-email <e> Email hint for Tier 1 identity auto-match",
50929
+ "--dedupe-key <key> Deduplication key",
50930
+ "--event-type <type> Event type (default: app_mention)",
50931
+ "--thread-id <id> Thread ID override",
50932
+ "--metadata <json> Extra metadata JSON",
50933
+ "--project <id> [deprecated] Legacy API simulate path"
50912
50934
  ]
50913
50935
  }
50914
50936
  },
50915
50937
  examples: [
50916
- 'eve chat simulate --project proj_xxx --team-id T123 --text "hello"'
50938
+ 'eve chat simulate --team-id T123 --text "hello"',
50939
+ 'eve chat simulate --team-id T123 --text "@eve deploy" --external-email alice@example.com',
50940
+ 'eve chat simulate --team-id T123 --text "hello" --dedupe-key test-dedup-1'
50917
50941
  ]
50918
50942
  },
50919
50943
  docs: {
@@ -51460,6 +51484,7 @@ function showMainHelp() {
51460
51484
  console.log(" analytics Org analytics (jobs, pipelines, env health)");
51461
51485
  console.log(" ollama Manage inference targets, aliases, and model routes");
51462
51486
  console.log(" access Access control: permissions, roles, bindings, policy-as-code sync");
51487
+ console.log(" user Look up user profiles and memberships");
51463
51488
  console.log(" admin User and platform admin operations");
51464
51489
  console.log(" skills Install skills from skills.txt (skills CLI)");
51465
51490
  console.log(" migrate Migration helpers for upgrading config formats");
@@ -51863,8 +51888,52 @@ async function handleOrg(subcommand, positionals, flags, context2) {
51863
51888
  }
51864
51889
  }
51865
51890
  }
51891
+ case "membership-requests": {
51892
+ const action = positionals[0];
51893
+ const orgId = typeof flags.org === "string" ? flags.org : context2.orgId;
51894
+ if (!orgId) {
51895
+ throw new Error("Missing org id. Provide --org or set a profile default.");
51896
+ }
51897
+ switch (action) {
51898
+ case "approve": {
51899
+ const requestId = positionals[1];
51900
+ if (!requestId) {
51901
+ throw new Error("Usage: eve org membership-requests approve <request_id> [--role member|admin]");
51902
+ }
51903
+ const role = getStringFlag(flags, ["role"]) ?? "member";
51904
+ const email = getStringFlag(flags, ["email"]);
51905
+ const body = { role };
51906
+ if (email) body.email = email;
51907
+ const response = await requestJson(context2, `/orgs/${orgId}/membership-requests/${requestId}/approve`, {
51908
+ method: "POST",
51909
+ body
51910
+ });
51911
+ outputJson(response, json, `\u2713 Membership request ${requestId} approved`);
51912
+ return;
51913
+ }
51914
+ case "deny": {
51915
+ const requestId = positionals[1];
51916
+ if (!requestId) {
51917
+ throw new Error("Usage: eve org membership-requests deny <request_id>");
51918
+ }
51919
+ const response = await requestJson(context2, `/orgs/${orgId}/membership-requests/${requestId}/deny`, {
51920
+ method: "POST"
51921
+ });
51922
+ outputJson(response, json, `\u2713 Membership request ${requestId} denied`);
51923
+ return;
51924
+ }
51925
+ case "list":
51926
+ default: {
51927
+ const status = getStringFlag(flags, ["status"]);
51928
+ const query = status ? `?status=${status}` : "";
51929
+ const response = await requestJson(context2, `/orgs/${orgId}/membership-requests${query}`);
51930
+ outputJson(response, json);
51931
+ return;
51932
+ }
51933
+ }
51934
+ }
51866
51935
  default:
51867
- throw new Error("Usage: eve org <ensure|list|get|spend|update|delete|members>");
51936
+ throw new Error("Usage: eve org <ensure|list|get|spend|update|delete|members|membership-requests>");
51868
51937
  }
51869
51938
  }
51870
51939
  function parseSinceValue(since) {
@@ -56602,6 +56671,8 @@ var configSchema = external_exports.object({
56602
56671
  EVE_GITHUB_WEBHOOK_SECRET: external_exports.string().optional(),
56603
56672
  EVE_GITHUB_TOKEN: external_exports.string().optional(),
56604
56673
  EVE_SLACK_SIGNING_SECRET: external_exports.string().optional(),
56674
+ EVE_SLACK_CLIENT_ID: external_exports.string().optional(),
56675
+ EVE_SLACK_CLIENT_SECRET: external_exports.string().optional(),
56605
56676
  EVE_INTERNAL_API_KEY: external_exports.string().optional(),
56606
56677
  EVE_ORG_FS_LINK_TOKEN_SECRET: external_exports.string().optional(),
56607
56678
  EVE_ORG_FS_LINK_TOKEN_TTL_SECONDS: external_exports.coerce.number().int().min(60).default(900),
@@ -57178,6 +57249,8 @@ var OrgMemberRequestSchema = external_exports.object({
57178
57249
  var OrgMemberResponseSchema = external_exports.object({
57179
57250
  org_id: OrgIdSchema,
57180
57251
  user_id: external_exports.string(),
57252
+ email: external_exports.string(),
57253
+ display_name: external_exports.string().nullable(),
57181
57254
  role: OrgMemberRoleSchema,
57182
57255
  created_at: external_exports.string(),
57183
57256
  updated_at: external_exports.string()
@@ -57403,6 +57476,8 @@ var ProjectMemberRequestSchema = external_exports.object({
57403
57476
  var ProjectMemberResponseSchema = external_exports.object({
57404
57477
  project_id: external_exports.string(),
57405
57478
  user_id: external_exports.string(),
57479
+ email: external_exports.string(),
57480
+ display_name: external_exports.string().nullable(),
57406
57481
  role: ProjectMemberRoleSchema,
57407
57482
  created_at: external_exports.string(),
57408
57483
  updated_at: external_exports.string()
@@ -59222,7 +59297,8 @@ var SlackConnectRequestSchema = external_exports.object({
59222
59297
  status: external_exports.string().optional()
59223
59298
  });
59224
59299
  var IntegrationTestResponseSchema = external_exports.object({
59225
- ok: external_exports.boolean()
59300
+ ok: external_exports.boolean(),
59301
+ detail: external_exports.string().optional()
59226
59302
  });
59227
59303
  var IntegrationResolveRequestSchema = external_exports.object({
59228
59304
  provider: external_exports.string().min(1),
@@ -59236,13 +59312,54 @@ var ExternalIdentityResolveRequestSchema = external_exports.object({
59236
59312
  provider: external_exports.string().min(1),
59237
59313
  account_id: external_exports.string().min(1),
59238
59314
  external_user_id: external_exports.string().min(1),
59239
- org_id: external_exports.string().min(1)
59315
+ org_id: external_exports.string().min(1),
59316
+ external_email: external_exports.string().email().optional()
59240
59317
  });
59241
59318
  var ExternalIdentityResolveResponseSchema = external_exports.object({
59242
59319
  external_identity_id: external_exports.string(),
59243
59320
  eve_user_id: external_exports.string().nullable(),
59244
59321
  membership_request_id: external_exports.string().nullable()
59245
59322
  });
59323
+ var MembershipRequestResponseSchema = external_exports.object({
59324
+ id: external_exports.string(),
59325
+ org_id: external_exports.string(),
59326
+ external_identity_id: external_exports.string(),
59327
+ status: external_exports.string(),
59328
+ approved_by: external_exports.string().nullable(),
59329
+ approved_at: external_exports.string().nullable(),
59330
+ created_at: external_exports.string(),
59331
+ updated_at: external_exports.string()
59332
+ });
59333
+ var MembershipRequestListResponseSchema = external_exports.object({
59334
+ requests: external_exports.array(MembershipRequestResponseSchema)
59335
+ });
59336
+ var MembershipRequestApproveRequestSchema = external_exports.object({
59337
+ role: external_exports.string().default("member"),
59338
+ email: external_exports.string().email().optional()
59339
+ });
59340
+ var IdentityLinkTokenRequestSchema = external_exports.object({
59341
+ provider: external_exports.string().min(1),
59342
+ org_id: external_exports.string().min(1)
59343
+ });
59344
+ var IdentityLinkTokenResponseSchema = external_exports.object({
59345
+ token: external_exports.string(),
59346
+ expires_in: external_exports.number(),
59347
+ instructions: external_exports.string()
59348
+ });
59349
+ var IdentityLinkRedeemRequestSchema = external_exports.object({
59350
+ token: external_exports.string().min(1),
59351
+ provider: external_exports.string().min(1),
59352
+ account_id: external_exports.string().min(1),
59353
+ external_user_id: external_exports.string().min(1)
59354
+ });
59355
+ var IdentityLinkRedeemResponseSchema = external_exports.object({
59356
+ ok: external_exports.boolean(),
59357
+ external_identity_id: external_exports.string().optional(),
59358
+ error: external_exports.string().optional()
59359
+ });
59360
+ var IntegrationSettingsUpdateRequestSchema = external_exports.object({
59361
+ settings: external_exports.record(external_exports.unknown())
59362
+ });
59246
59363
 
59247
59364
  // ../shared/dist/schemas/builds.js
59248
59365
  var CreateBuildSpecRequestSchema = external_exports.object({
@@ -67052,17 +67169,18 @@ async function handleStatus2(context2, json) {
67052
67169
  }
67053
67170
  async function handleHealth(context2, json) {
67054
67171
  try {
67055
- const health = await requestJson(context2, "/health");
67172
+ const response = await requestRaw(context2, "/health", { allowError: true });
67173
+ const health = response.data ?? {};
67056
67174
  if (json) {
67057
67175
  outputJson(health, json);
67058
67176
  } else {
67059
- const isHealthy = health.status === "ok" || health.status === "healthy";
67177
+ const isHealthy = response.ok && (health.status === "ok" || health.status === "healthy");
67060
67178
  const icon = isHealthy ? "\u2713" : "\u2717";
67061
- const status = isHealthy ? "Healthy" : "Unhealthy";
67179
+ const statusLabel = isHealthy ? "Healthy" : "Degraded";
67062
67180
  console.log("System Health Check");
67063
67181
  console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
67064
67182
  console.log("");
67065
- console.log(` ${icon} API: ${status}`);
67183
+ console.log(` ${icon} API: ${statusLabel}`);
67066
67184
  if (health.database) {
67067
67185
  console.log(` Database: ${health.database}`);
67068
67186
  }
@@ -67073,7 +67191,7 @@ async function handleHealth(context2, json) {
67073
67191
  if (isHealthy) {
67074
67192
  console.log("API is operational.");
67075
67193
  } else {
67076
- console.log("API is not healthy. Check server logs.");
67194
+ console.log("API is degraded. Check server logs and database connectivity.");
67077
67195
  }
67078
67196
  }
67079
67197
  } catch (error) {
@@ -74186,17 +74304,21 @@ async function handleUsers(flags, context2, json) {
74186
74304
  const rows = [];
74187
74305
  for (const user of users) {
74188
74306
  const base = {
74189
- id: user.id,
74190
74307
  email: user.email,
74191
74308
  name: user.display_name ?? "-",
74192
74309
  admin: user.is_admin ? "yes" : "",
74193
74310
  created: user.created_at?.split("T")[0] ?? ""
74194
74311
  };
74195
- if (user.memberships.length === 0) {
74196
- rows.push({ ...base, org: "-", role: "-" });
74312
+ const hasOrg = user.memberships.length > 0;
74313
+ const hasProj = (user.project_memberships ?? []).length > 0;
74314
+ if (!hasOrg && !hasProj) {
74315
+ rows.push({ ...base, scope: "-", target: "-", role: "-" });
74197
74316
  } else {
74198
74317
  for (const m of user.memberships) {
74199
- rows.push({ ...base, org: m.org_slug || m.org_name, role: m.role });
74318
+ rows.push({ ...base, scope: "org", target: m.org_slug || m.org_name, role: m.role });
74319
+ }
74320
+ for (const pm of user.project_memberships ?? []) {
74321
+ rows.push({ ...base, scope: "project", target: `${pm.org_slug}/${pm.project_slug}`, role: pm.role });
74200
74322
  }
74201
74323
  }
74202
74324
  }
@@ -74205,7 +74327,8 @@ async function handleUsers(flags, context2, json) {
74205
74327
  email: col("email", "Email"),
74206
74328
  name: col("name", "Name"),
74207
74329
  admin: col("admin", "Admin"),
74208
- org: col("org", "Org"),
74330
+ scope: col("scope", "Scope"),
74331
+ target: col("target", "Target"),
74209
74332
  role: col("role", "Role"),
74210
74333
  created: col("created", "Created")
74211
74334
  };
@@ -74214,7 +74337,8 @@ async function handleUsers(flags, context2, json) {
74214
74337
  pad3("Email", w.email),
74215
74338
  pad3("Name", w.name),
74216
74339
  pad3("Admin", w.admin),
74217
- pad3("Org", w.org),
74340
+ pad3("Scope", w.scope),
74341
+ pad3("Target", w.target),
74218
74342
  pad3("Role", w.role),
74219
74343
  pad3("Created", w.created)
74220
74344
  ].join(" ");
@@ -74225,7 +74349,8 @@ async function handleUsers(flags, context2, json) {
74225
74349
  pad3(row.email, w.email),
74226
74350
  pad3(row.name, w.name),
74227
74351
  pad3(row.admin, w.admin),
74228
- pad3(row.org, w.org),
74352
+ pad3(row.scope, w.scope),
74353
+ pad3(row.target, w.target),
74229
74354
  pad3(row.role, w.role),
74230
74355
  pad3(row.created, w.created)
74231
74356
  ].join(" "));
@@ -75663,8 +75788,24 @@ async function handleIntegrations(subcommand, positionals, flags, context2) {
75663
75788
  }
75664
75789
  case "slack": {
75665
75790
  const action = positionals[0];
75791
+ if (action === "install-url") {
75792
+ if (!orgId) {
75793
+ throw new Error("Missing org id. Provide --org or set a profile default.");
75794
+ }
75795
+ const url = `${context2.apiUrl}/orgs/${orgId}/integrations/slack/authorize`;
75796
+ if (json) {
75797
+ outputJson({ url, org_id: orgId }, json);
75798
+ } else {
75799
+ console.log(`Slack install URL:
75800
+
75801
+ ${url}
75802
+
75803
+ Share this URL with your Slack workspace admin.`);
75804
+ }
75805
+ return;
75806
+ }
75666
75807
  if (action !== "connect") {
75667
- throw new Error("Usage: eve integrations slack connect --org <org_id> --team-id <team_id> [--token <token>]");
75808
+ throw new Error("Usage: eve integrations slack <connect|install-url> --org <org_id>");
75668
75809
  }
75669
75810
  if (!orgId) {
75670
75811
  throw new Error("Missing org id. Provide --org or set a profile default.");
@@ -75717,8 +75858,35 @@ async function handleIntegrations(subcommand, positionals, flags, context2) {
75717
75858
  outputJson(response, json, response.ok ? "\u2713 Integration test ok" : "Integration test failed");
75718
75859
  return;
75719
75860
  }
75861
+ case "update": {
75862
+ const integrationId = positionals[0];
75863
+ if (!integrationId) {
75864
+ throw new Error("Usage: eve integrations update <integration_id> --setting key=value");
75865
+ }
75866
+ if (!orgId) {
75867
+ throw new Error("Missing org id. Provide --org or set a profile default.");
75868
+ }
75869
+ const settingFlag = getStringFlag(flags, ["setting"]);
75870
+ if (!settingFlag) {
75871
+ throw new Error("Missing --setting flag. Usage: --setting admin_channel_id=C12345");
75872
+ }
75873
+ const eqIdx = settingFlag.indexOf("=");
75874
+ if (eqIdx < 1) {
75875
+ throw new Error("Invalid --setting format. Use key=value (e.g., admin_channel_id=C12345)");
75876
+ }
75877
+ const key = settingFlag.slice(0, eqIdx);
75878
+ const value = settingFlag.slice(eqIdx + 1);
75879
+ const settings = { [key]: value };
75880
+ const response = await requestJson(
75881
+ context2,
75882
+ `/orgs/${orgId}/integrations/${integrationId}/settings`,
75883
+ { method: "PATCH", body: { settings } }
75884
+ );
75885
+ outputJson(response, json, `\u2713 Integration ${integrationId} settings updated`);
75886
+ return;
75887
+ }
75720
75888
  default:
75721
- throw new Error("Usage: eve integrations <list|slack|test>");
75889
+ throw new Error("Usage: eve integrations <list|slack|test|update>");
75722
75890
  }
75723
75891
  }
75724
75892
 
@@ -75727,26 +75895,66 @@ async function handleChat(subcommand, _positionals, flags, context2) {
75727
75895
  const json = Boolean(flags.json);
75728
75896
  switch (subcommand) {
75729
75897
  case "simulate": {
75730
- const projectId = getStringFlag(flags, ["project"]) ?? context2.projectId;
75731
- if (!projectId) {
75732
- throw new Error("Missing project id. Provide --project or set a profile default.");
75733
- }
75734
- const provider = getStringFlag(flags, ["provider"]) ?? "slack";
75898
+ const projectId = getStringFlag(flags, ["project"]);
75735
75899
  const teamId = getStringFlag(flags, ["team-id"]);
75736
75900
  const text = getStringFlag(flags, ["text"]);
75901
+ if (projectId) {
75902
+ if (!teamId || !text) {
75903
+ throw new Error("Usage: eve chat simulate --project <id> --team-id <team> --text <message>");
75904
+ }
75905
+ process.stderr.write("\u26A0 --project routes through the legacy API simulate path. Use --team-id without --project for gateway routing.\n");
75906
+ const provider2 = getStringFlag(flags, ["provider"]) ?? "slack";
75907
+ const channelId2 = getStringFlag(flags, ["channel-id"]);
75908
+ const userId2 = getStringFlag(flags, ["user-id"]);
75909
+ const threadKey = getStringFlag(flags, ["thread-key"]);
75910
+ const metadataFlag2 = getStringFlag(flags, ["metadata"]);
75911
+ let metadata;
75912
+ if (metadataFlag2) {
75913
+ try {
75914
+ const parsed = JSON.parse(metadataFlag2);
75915
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
75916
+ metadata = parsed;
75917
+ }
75918
+ } catch {
75919
+ throw new Error("Invalid --metadata (must be JSON object)");
75920
+ }
75921
+ }
75922
+ const response2 = await requestJson(
75923
+ context2,
75924
+ `/projects/${projectId}/chat/simulate`,
75925
+ {
75926
+ method: "POST",
75927
+ body: {
75928
+ provider: provider2,
75929
+ team_id: teamId,
75930
+ channel_id: channelId2,
75931
+ user_id: userId2,
75932
+ text,
75933
+ thread_key: threadKey,
75934
+ metadata
75935
+ }
75936
+ }
75937
+ );
75938
+ outputJson(response2, json, `\u2713 Chat simulated (thread: ${response2.thread_id})`);
75939
+ return;
75940
+ }
75737
75941
  if (!teamId || !text) {
75738
- throw new Error("Usage: eve chat simulate --project <id> --team-id <team> --text <message>");
75942
+ throw new Error("Usage: eve chat simulate --team-id <team> --text <message>");
75739
75943
  }
75944
+ const provider = getStringFlag(flags, ["provider"]) ?? "slack";
75740
75945
  const channelId = getStringFlag(flags, ["channel-id"]);
75741
75946
  const userId = getStringFlag(flags, ["user-id"]);
75742
- const threadKey = getStringFlag(flags, ["thread-key"]);
75947
+ const threadId = getStringFlag(flags, ["thread-id", "thread-key"]);
75948
+ const externalEmail = getStringFlag(flags, ["external-email"]);
75949
+ const dedupeKey = getStringFlag(flags, ["dedupe-key"]);
75950
+ const eventType = getStringFlag(flags, ["event-type"]);
75743
75951
  const metadataFlag = getStringFlag(flags, ["metadata"]);
75744
- let metadata;
75952
+ let metadataEmail;
75745
75953
  if (metadataFlag) {
75746
75954
  try {
75747
75955
  const parsed = JSON.parse(metadataFlag);
75748
75956
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
75749
- metadata = parsed;
75957
+ metadataEmail = typeof parsed.external_email === "string" ? parsed.external_email : void 0;
75750
75958
  }
75751
75959
  } catch {
75752
75960
  throw new Error("Invalid --metadata (must be JSON object)");
@@ -75754,21 +75962,33 @@ async function handleChat(subcommand, _positionals, flags, context2) {
75754
75962
  }
75755
75963
  const response = await requestJson(
75756
75964
  context2,
75757
- `/projects/${projectId}/chat/simulate`,
75965
+ "/gateway/providers/simulate",
75758
75966
  {
75759
75967
  method: "POST",
75760
75968
  body: {
75761
75969
  provider,
75762
- team_id: teamId,
75763
- channel_id: channelId,
75764
- user_id: userId,
75970
+ account_id: teamId,
75971
+ channel_id: channelId || void 0,
75972
+ user_id: userId || void 0,
75765
75973
  text,
75766
- thread_key: threadKey,
75767
- metadata
75974
+ external_email: externalEmail ?? metadataEmail,
75975
+ event_type: eventType || void 0,
75976
+ thread_id: threadId || void 0,
75977
+ dedupe_key: dedupeKey || void 0
75768
75978
  }
75769
75979
  }
75770
75980
  );
75771
- outputJson(response, json, `\u2713 Chat simulated (thread: ${response.thread_id})`);
75981
+ const normalized = {
75982
+ thread_id: response.route?.thread_id ?? null,
75983
+ route_id: response.route?.route_id ?? null,
75984
+ target: response.route?.target ?? null,
75985
+ job_ids: response.route?.job_ids ?? [],
75986
+ event_id: response.route?.event_id ?? null,
75987
+ immediate_reply: response.immediate_reply,
75988
+ duplicate: response.duplicate
75989
+ };
75990
+ const summary = response.duplicate ? "\u2713 Duplicate (deduplicated)" : response.route?.job_ids?.length ? `\u2713 Chat routed via gateway (thread: ${response.route.thread_id})` : response.immediate_reply ? `\u2713 Gateway reply: ${response.immediate_reply.text.slice(0, 80)}` : "\u2713 Chat simulated via gateway";
75991
+ outputJson(normalized, json, summary);
75772
75992
  return;
75773
75993
  }
75774
75994
  default:
@@ -81155,6 +81375,77 @@ function printManualInstructions(result) {
81155
81375
  console.log(' 6. Click "Add webhook"');
81156
81376
  }
81157
81377
 
81378
+ // src/commands/identity.ts
81379
+ async function handleIdentity(subcommand, positionals, flags, context2) {
81380
+ const json = Boolean(flags.json);
81381
+ switch (subcommand) {
81382
+ case "link": {
81383
+ const provider = positionals[0];
81384
+ if (!provider) {
81385
+ throw new Error("Usage: eve identity link <provider> --org <org_id>\n\nSupported providers: slack");
81386
+ }
81387
+ const orgId = getStringFlag(flags, ["org"]) ?? context2.orgId;
81388
+ if (!orgId) {
81389
+ throw new Error("Missing org id. Provide --org or set a profile default.");
81390
+ }
81391
+ const response = await requestJson(
81392
+ context2,
81393
+ "/users/me/identity-link-tokens",
81394
+ {
81395
+ method: "POST",
81396
+ body: { provider, org_id: orgId }
81397
+ }
81398
+ );
81399
+ if (json) {
81400
+ outputJson(response, json);
81401
+ } else {
81402
+ console.log(response.instructions);
81403
+ }
81404
+ return;
81405
+ }
81406
+ default:
81407
+ throw new Error("Usage: eve identity <link>");
81408
+ }
81409
+ }
81410
+
81411
+ // src/commands/user.ts
81412
+ async function handleUser(subcommand, positionals, flags, context2) {
81413
+ const json = Boolean(flags.json);
81414
+ switch (subcommand) {
81415
+ case "show": {
81416
+ const userId = positionals[0] ?? "me";
81417
+ const user = await requestJson(context2, `/users/${userId}`);
81418
+ if (json) {
81419
+ outputJson(user, true);
81420
+ return;
81421
+ }
81422
+ console.log(`User: ${user.email}`);
81423
+ if (user.display_name) console.log(`Name: ${user.display_name}`);
81424
+ console.log(`ID: ${user.id}`);
81425
+ if (user.is_admin) console.log(`Role: system_admin`);
81426
+ console.log(`Since: ${user.created_at?.split("T")[0] ?? ""}`);
81427
+ if (user.memberships.length > 0) {
81428
+ console.log("\nOrg memberships:");
81429
+ for (const m of user.memberships) {
81430
+ console.log(` ${m.org_slug || m.org_name} ${m.role}`);
81431
+ }
81432
+ }
81433
+ if ((user.project_memberships ?? []).length > 0) {
81434
+ console.log("\nProject memberships:");
81435
+ for (const pm of user.project_memberships) {
81436
+ console.log(` ${pm.org_slug}/${pm.project_slug} ${pm.role}`);
81437
+ }
81438
+ }
81439
+ if (user.memberships.length === 0 && (user.project_memberships ?? []).length === 0) {
81440
+ console.log("\nNo memberships.");
81441
+ }
81442
+ return;
81443
+ }
81444
+ default:
81445
+ throw new Error("Usage: eve user <show> [user_id|me]");
81446
+ }
81447
+ }
81448
+
81158
81449
  // src/index.ts
81159
81450
  function getCliVersion() {
81160
81451
  try {
@@ -81350,6 +81641,12 @@ async function main2() {
81350
81641
  case "github":
81351
81642
  await handleGithub(subcommand, rest, flags, context2);
81352
81643
  return;
81644
+ case "identity":
81645
+ await handleIdentity(subcommand, rest, flags, context2);
81646
+ return;
81647
+ case "user":
81648
+ await handleUser(subcommand, rest, flags, context2);
81649
+ return;
81353
81650
  default:
81354
81651
  showMainHelp();
81355
81652
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eve-horizon/cli",
3
- "version": "0.2.43",
3
+ "version": "0.2.44",
4
4
  "description": "Eve Horizon CLI",
5
5
  "license": "MIT",
6
6
  "repository": {