@epilot/cli 0.1.194 → 0.1.196

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 (85) hide show
  1. package/README.md +89 -1
  2. package/dist/{access-token-3XCBQDFI.js → access-token-7DZIIHDK.js} +4 -4
  3. package/dist/{add-component-GTIUBZP6.js → add-component-M2NRQPLH.js} +4 -4
  4. package/dist/{add-function-5RIKXAEC.js → add-function-ZA7DR3NM.js} +4 -4
  5. package/dist/{address-ACXTZTLB.js → address-OEHR5MKW.js} +4 -4
  6. package/dist/{address-suggestions-MIUHAFVV.js → address-suggestions-SF3YNSJN.js} +4 -4
  7. package/dist/agent-auth-GV2T4GET.js +42 -0
  8. package/dist/{ai-agents-OWQRQK5A.js → ai-agents-3SI3KJ5H.js} +4 -4
  9. package/dist/{api-PQZEGSUV.js → api-7HGTYTZV.js} +4 -4
  10. package/dist/app-JLV2WOYK.js +26 -0
  11. package/dist/{audit-logs-3DVFWVWL.js → audit-logs-I2MPPQ3V.js} +4 -4
  12. package/dist/auth-6NBJQ6NB.js +235 -0
  13. package/dist/auth-login-7D6YJLCA.js +34 -0
  14. package/dist/{auth-token-APXLIQAO.js → auth-token-CI5L3CCJ.js} +2 -2
  15. package/dist/{automation-NHRRP6J4.js → automation-GTVLSKXA.js} +4 -4
  16. package/dist/{billing-PCSW2TQP.js → billing-TNGDZAJ2.js} +4 -4
  17. package/dist/bin/epilot.js +84 -60
  18. package/dist/{blueprint-manifest-BPWLPHIU.js → blueprint-manifest-KNZRON75.js} +4 -4
  19. package/dist/{calendar-Y6AGKVWR.js → calendar-4RMKSNHL.js} +4 -4
  20. package/dist/{chat-567O35XV.js → chat-3AKMQXQG.js} +4 -4
  21. package/dist/{chunk-5KHD2F3J.js → chunk-BIOWN64A.js} +3 -3
  22. package/dist/chunk-G6KI5Z7X.js +606 -0
  23. package/dist/{chunk-KTCBDUL2.js → chunk-JQW3WOJB.js} +1 -1
  24. package/dist/{auth-login-3AY5U4JU.js → chunk-OI6GYEIX.js} +378 -11
  25. package/dist/{chunk-YHQA2AVG.js → chunk-QPUCHKXS.js} +1 -0
  26. package/dist/{chunk-M3M3C5WH.js → chunk-SQ55BTMV.js} +17 -3
  27. package/dist/{chunk-WWO5RPHF.js → chunk-Y4B3K4IO.js} +7 -7
  28. package/dist/{config-DGZIMLZK.js → config-PJWYWLQH.js} +1 -1
  29. package/dist/{configuration-hub-YPOS6ELC.js → configuration-hub-6HKPZL7E.js} +4 -4
  30. package/dist/{consent-SFI4EUGQ.js → consent-3TMN7LZO.js} +4 -4
  31. package/dist/{customer-portal-UUKBB67Z.js → customer-portal-HS3PVMHL.js} +4 -4
  32. package/dist/{dashboard-GERIZIZV.js → dashboard-WL7NVOF5.js} +4 -4
  33. package/dist/{data-governance-XVJWDVER.js → data-governance-VVEJZIN3.js} +4 -4
  34. package/dist/{deduplication-JJ46Y2CW.js → deduplication-WXROVSZU.js} +4 -4
  35. package/dist/{deploy-GZMQOG6O.js → deploy-Y2EQYBAB.js} +4 -4
  36. package/dist/{design-LYYI4DLQ.js → design-YWSM4GN6.js} +4 -4
  37. package/dist/{dev-HDXS3UPB.js → dev-OFEMDQSS.js} +4 -4
  38. package/dist/{document-5MD75ESX.js → document-HAUPZTDG.js} +4 -4
  39. package/dist/{email-settings-UKM5LYDQ.js → email-settings-47SYOOPL.js} +4 -4
  40. package/dist/{email-template-KT7YPDBF.js → email-template-JN3H6VFT.js} +4 -4
  41. package/dist/{entity-AG73SZKS.js → entity-5T4F2PEC.js} +4 -4
  42. package/dist/{entity-mapping-6MIHNIDB.js → entity-mapping-3L52T4IU.js} +4 -4
  43. package/dist/{environments-W7LRHBDB.js → environments-MKFLKYTI.js} +4 -4
  44. package/dist/{event-catalog-NCAHETDE.js → event-catalog-PZ4SFMRO.js} +4 -4
  45. package/dist/{export-2B5BAXHF.js → export-RNPPIDBT.js} +4 -4
  46. package/dist/{external-values-NHZ2EZMQ.js → external-values-FZHZGV2J.js} +4 -4
  47. package/dist/{file-Y6B2UFNC.js → file-AIIKVSDS.js} +4 -4
  48. package/dist/{iban-33N4BJUC.js → iban-2SDYV2Q6.js} +4 -4
  49. package/dist/{identity-GQ5VOASS.js → identity-CQXELR2Y.js} +4 -4
  50. package/dist/{init-5C4IJDPX.js → init-5PYFSAQA.js} +4 -4
  51. package/dist/{integration-toolkit-KTUXC24K.js → integration-toolkit-CTRGST6J.js} +4 -4
  52. package/dist/{journey-3X6BQOOO.js → journey-3CVYG5KT.js} +4 -4
  53. package/dist/{kanban-F7PRPBGV.js → kanban-2J3VBDUG.js} +4 -4
  54. package/dist/{message-K4ZMKQJE.js → message-PGJ5XXDI.js} +4 -4
  55. package/dist/{metering-ZK6VMFZ7.js → metering-DA5HJTIB.js} +4 -4
  56. package/dist/{notes-6Z42UHWN.js → notes-CUCXKOK6.js} +4 -4
  57. package/dist/{notification-NPY7FMPG.js → notification-3BE3GJLR.js} +4 -4
  58. package/dist/org-YNGJNLKY.js +427 -0
  59. package/dist/{organization-NK3CCP7F.js → organization-5MKK22PI.js} +4 -4
  60. package/dist/{partner-directory-WSFRXNTY.js → partner-directory-4CI3UQXB.js} +4 -4
  61. package/dist/{permissions-Q36SZHXQ.js → permissions-XNFMEENQ.js} +4 -4
  62. package/dist/{pricing-JSFN62BD.js → pricing-3C6LGOLN.js} +4 -4
  63. package/dist/{pricing-tier-XURRWW25.js → pricing-tier-I67ZQHPI.js} +4 -4
  64. package/dist/{profile-OZJL5ZPT.js → profile-G2FH3DXR.js} +1 -1
  65. package/dist/{purpose-GKPVUTBK.js → purpose-BSPOIU7I.js} +4 -4
  66. package/dist/{query-JZUAVWPY.js → query-5KMRWBMY.js} +4 -4
  67. package/dist/{remove-component-KLWF3QZO.js → remove-component-W2E6ZA2E.js} +4 -4
  68. package/dist/{review-L4QLVEXC.js → review-Y5RBCWJX.js} +4 -4
  69. package/dist/{sandbox-EKAOWJSR.js → sandbox-SUR4RZFD.js} +4 -4
  70. package/dist/{sharing-TKHVDJ5B.js → sharing-UZ4QWKBD.js} +4 -4
  71. package/dist/{snapshot-A2FU3NYU.js → snapshot-UAZZXLQF.js} +4 -4
  72. package/dist/{submission-NTQTZ2MG.js → submission-2ISK6IJV.js} +4 -4
  73. package/dist/{targeting-7HCCTEIJ.js → targeting-4RDTQAXT.js} +4 -4
  74. package/dist/{template-variables-ABHPJ6QR.js → template-variables-4Z3MZEGG.js} +4 -4
  75. package/dist/{upgrade-YRZHOL6I.js → upgrade-FPJAHNOK.js} +1 -1
  76. package/dist/{user-WEW5SBST.js → user-YTQDFHMV.js} +4 -4
  77. package/dist/{validate-SX4DIEWH.js → validate-7TSPYKFI.js} +4 -4
  78. package/dist/{validation-rules-PNUE7RIC.js → validation-rules-BCXYX5QO.js} +4 -4
  79. package/dist/{versions-D5NPDKRX.js → versions-LBLHNSOL.js} +4 -4
  80. package/dist/{webhooks-ECQT77EA.js → webhooks-KHULCU4Z.js} +4 -4
  81. package/dist/{workflow-JOZVUSX2.js → workflow-Q74OHJKH.js} +4 -4
  82. package/dist/{workflow-definition-GPBXEKKH.js → workflow-definition-GWMKIEUE.js} +4 -4
  83. package/package.json +3 -2
  84. package/dist/app-EJONBOTI.js +0 -26
  85. package/dist/auth-WMXFMPWE.js +0 -119
@@ -1,8 +1,31 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ isInteractive
4
+ } from "./chunk-IOLKUHUB.js";
5
+ import {
6
+ ACCESS_PROFILES,
7
+ ACCESS_PROFILE_INFO,
8
+ AgentAuthError,
9
+ EPILOT_CAPABILITIES,
10
+ agentProfileKey,
11
+ ensureHostKey,
12
+ forgetAgentForProfile,
13
+ formatExpiresIn,
14
+ generateKeyPair,
15
+ getAgentAuthClient,
16
+ isAccessProfile,
17
+ isReadProfile,
18
+ issueTokenForOrg,
19
+ listEpilotOrganizations,
20
+ loadAgentIdentity,
21
+ organizationAccessCapability,
22
+ resolveAgentAuthIssuer,
23
+ saveAgentRecord,
24
+ validateReason
25
+ } from "./chunk-G6KI5Z7X.js";
2
26
  import {
3
27
  saveCredentials
4
- } from "./chunk-M3M3C5WH.js";
5
- import "./chunk-YHQA2AVG.js";
28
+ } from "./chunk-SQ55BTMV.js";
6
29
  import {
7
30
  BOLD,
8
31
  CYAN,
@@ -17,6 +40,7 @@ import {
17
40
  import { defineCommand } from "citty";
18
41
  import { randomBytes } from "crypto";
19
42
  import { createServer } from "http";
43
+ import { hostname } from "os";
20
44
 
21
45
  // src/lib/environment.ts
22
46
  var PORTAL_URLS = {
@@ -34,6 +58,7 @@ var resolveEnvironment = (useDev, useStaging) => {
34
58
  };
35
59
 
36
60
  // src/commands/auth-login.ts
61
+ var AGENT_FLAG_DESCRIPTION = "Register this CLI as an Agent Auth agent (org switching, silent token refresh, scoped access profiles)";
37
62
  var auth_login_default = defineCommand({
38
63
  meta: { name: "login", description: "Authenticate with epilot" },
39
64
  args: {
@@ -44,6 +69,25 @@ var auth_login_default = defineCommand({
44
69
  type: "boolean",
45
70
  description: "Generate an anonymized token (personal data is masked in all API responses)"
46
71
  },
72
+ agent: { type: "boolean", description: AGENT_FLAG_DESCRIPTION },
73
+ org: {
74
+ type: "string",
75
+ description: "Agent mode: organization ID to request access to (default: your login organization)"
76
+ },
77
+ access: {
78
+ type: "string",
79
+ description: `Agent mode: access profile (${ACCESS_PROFILES.join(", ")}; default: read)`
80
+ },
81
+ reason: {
82
+ type: "string",
83
+ description: "Agent mode: purpose shown to the approving user (required for profiles other than read)"
84
+ },
85
+ json: { type: "boolean", description: "Agent mode: output the login result as JSON" },
86
+ interactive: {
87
+ type: "boolean",
88
+ default: true,
89
+ description: "Agent mode: interactive approval (--no-interactive to disable)"
90
+ },
47
91
  "use-dev": { type: "boolean", description: "Use dev environment (portal.dev.epilot.cloud)" },
48
92
  "use-staging": { type: "boolean", description: "Use staging environment (portal.staging.epilot.cloud)" }
49
93
  },
@@ -53,32 +97,343 @@ var auth_login_default = defineCommand({
53
97
  const readonly = Boolean(args.readonly);
54
98
  const anonymize = Boolean(args.anonymize);
55
99
  if (args.token) {
100
+ await forgetAgentForProfile(profileName);
56
101
  saveCredentials({ token: args.token }, profileName);
57
102
  const suffix = profileName ? ` to profile "${profileName}"` : "";
58
103
  process.stdout.write(`${GREEN}Token saved${suffix}.${RESET}
59
104
  `);
60
105
  return;
61
106
  }
62
- if (!process.stdin.isTTY) {
63
- process.stderr.write(`${RED}Browser login requires an interactive terminal.${RESET}
107
+ if (!args.agent) {
108
+ const agentOnly = ["org", "access", "reason"].filter((flag) => args[flag] !== void 0);
109
+ if (agentOnly.length) {
110
+ process.stderr.write(
111
+ `${RED}${agentOnly.map((f) => `--${f}`).join(", ")} require${agentOnly.length === 1 ? "s" : ""} --agent.${RESET}
112
+ `
113
+ );
114
+ process.stderr.write(
115
+ `Run ${BOLD}epilot auth login --agent ${agentOnly.map((f) => `--${f} \u2026`).join(" ")}${RESET}.
116
+ `
117
+ );
118
+ process.exit(1);
119
+ }
120
+ if (!process.stdin.isTTY) {
121
+ process.stderr.write(`${RED}Browser login requires an interactive terminal.${RESET}
122
+ `);
123
+ process.stderr.write(
124
+ `Use ${BOLD}epilot auth login --token <token>${RESET} or ${BOLD}epilot auth token${RESET} instead.
125
+ `
126
+ );
127
+ process.exit(1);
128
+ }
129
+ const token = await browserLogin(profileName, env, readonly, anonymize);
130
+ if (token) {
131
+ await forgetAgentForProfile(profileName);
132
+ process.stdout.write(`${GREEN}${BOLD}Login successful!${RESET}
133
+ `);
134
+ } else {
135
+ process.stderr.write(`${RED}Login failed or was cancelled.${RESET}
136
+ `);
137
+ process.exit(1);
138
+ }
139
+ return;
140
+ }
141
+ const interactive = isInteractive({ interactive: args.interactive }) && !!process.stdin.isTTY;
142
+ if (!interactive && !args.org) {
143
+ process.stderr.write(`${RED}Non-interactive agent login requires --org <organization-id>.${RESET}
64
144
  `);
65
145
  process.stderr.write(
66
- `Use ${BOLD}epilot auth login --token <token>${RESET} or ${BOLD}epilot auth token${RESET} instead.
146
+ `Run ${BOLD}epilot auth login --agent --org <id> --no-interactive${RESET}, or use ${BOLD}--token <token>${RESET}.
67
147
  `
68
148
  );
69
149
  process.exit(1);
70
150
  }
71
- const token = await browserLogin(profileName, env, readonly, anonymize);
72
- if (token) {
73
- process.stdout.write(`${GREEN}${BOLD}Login successful!${RESET}
151
+ try {
152
+ const profile = resolveLoginProfile(args.access, readonly, anonymize);
153
+ const reason = await resolveReason(profile, args.reason, interactive && !args.json);
154
+ const result = await agentLogin({
155
+ profileName,
156
+ env,
157
+ org: args.org,
158
+ profile,
159
+ reason,
160
+ readonly,
161
+ anonymize,
162
+ interactive,
163
+ json: Boolean(args.json)
164
+ });
165
+ if (args.json) {
166
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
74
167
  `);
75
- } else {
76
- process.stderr.write(`${RED}Login failed or was cancelled.${RESET}
168
+ }
169
+ } catch (error) {
170
+ if (error instanceof AgentAuthError) {
171
+ process.stderr.write(`${RED}Login failed: ${error.message}${RESET} ${DIM}(${error.code})${RESET}
172
+ `);
173
+ } else {
174
+ process.stderr.write(`${RED}Login failed: ${error instanceof Error ? error.message : String(error)}${RESET}
77
175
  `);
176
+ }
78
177
  process.exit(1);
79
178
  }
80
179
  }
81
180
  });
181
+ var readOnlySibling = (profile) => profile === "config:write" ? "config:read" : profile === "data:write" ? "data:read" : profile === "full" ? "read" : profile;
182
+ var parseAccessProfile = (value) => {
183
+ if (value === void 0 || value === null || value === "") return void 0;
184
+ if (isAccessProfile(value)) return value;
185
+ throw new AgentAuthError(
186
+ 400,
187
+ "invalid_access_profile",
188
+ `Unknown access profile "${String(value)}". Use one of: ${ACCESS_PROFILES.join(", ")}.`
189
+ );
190
+ };
191
+ var resolveLoginProfile = (access, readonly, anonymize) => {
192
+ let profile = parseAccessProfile(access) ?? "read";
193
+ if (readonly && !isReadProfile(profile)) {
194
+ const downgraded = readOnlySibling(profile);
195
+ process.stderr.write(`${DIM}--readonly downgrades ${profile} to ${downgraded}.${RESET}
196
+ `);
197
+ profile = downgraded;
198
+ }
199
+ if (anonymize && !ACCESS_PROFILE_INFO[profile].anonymizeAllowed) {
200
+ throw new AgentAuthError(400, "invalid_capabilities", "anonymize is only available with read profiles");
201
+ }
202
+ return profile;
203
+ };
204
+ var resolveReason = async (profile, reason, canPrompt) => {
205
+ try {
206
+ return validateReason(profile, reason);
207
+ } catch (error) {
208
+ if (!(error instanceof AgentAuthError) || error.code !== "reason_required" || !canPrompt) {
209
+ if (error instanceof AgentAuthError && error.code === "reason_required") {
210
+ throw new AgentAuthError(
211
+ 400,
212
+ "reason_required",
213
+ `${error.message} Pass --reason "<why you need ${profile} access>".`
214
+ );
215
+ }
216
+ throw error;
217
+ }
218
+ }
219
+ const { input } = await import("@inquirer/prompts");
220
+ const answer = await input({
221
+ message: `Why do you need ${profile} (${ACCESS_PROFILE_INFO[profile].title}) access? Shown to the approving user:`,
222
+ validate: (value) => {
223
+ try {
224
+ validateReason(profile, value);
225
+ return true;
226
+ } catch (error) {
227
+ return error instanceof Error ? error.message : String(error);
228
+ }
229
+ }
230
+ });
231
+ return validateReason(profile, answer);
232
+ };
233
+ var describeAccess = (options) => {
234
+ const profile = isAccessProfile(options.profile) ? options.profile : "read";
235
+ const parts = [`${profile} ${DIM}(${ACCESS_PROFILE_INFO[profile].title})${RESET}`];
236
+ if (options.anonymized) parts.push(`${YELLOW}anonymized${RESET}`);
237
+ const expiry = formatExpiresIn(options.expiresAt);
238
+ if (expiry) parts.push(`${DIM}${expiry}${RESET}`);
239
+ return parts.join(", ");
240
+ };
241
+ var isDeviceAuthorization = (approval) => !!approval && approval.method === "device_authorization";
242
+ var printApproval = (approval, out) => {
243
+ out("\n");
244
+ out(` ${YELLOW}Verification code: ${BOLD}${approval.user_code}${RESET}
245
+ `);
246
+ out("\n");
247
+ out(`${DIM}Verify this code matches what is shown in your browser before approving.${RESET}
248
+ `);
249
+ out(`${DIM}This ensures you are approving the correct CLI session.${RESET}
250
+ `);
251
+ out("\n");
252
+ out(`${DIM}Approval URL: ${approval.verification_uri_complete}${RESET}
253
+
254
+ `);
255
+ };
256
+ var openBrowser = async (url, out) => {
257
+ try {
258
+ const open = (await import("open")).default;
259
+ await open(url);
260
+ out(`${CYAN}Browser opened.${RESET} Waiting for approval`);
261
+ } catch {
262
+ out(`Could not open browser. Please visit this URL manually:
263
+
264
+ ${url}
265
+
266
+ Waiting for approval`);
267
+ }
268
+ };
269
+ var agentLogin = async (options) => {
270
+ const out = (s) => (options.json ? process.stderr : process.stdout).write(s);
271
+ const profile = options.profile ?? "read";
272
+ const suffix = options.profileName ? ` ${DIM}(profile: ${options.profileName})${RESET}` : "";
273
+ out(`
274
+ ${BOLD}epilot CLI Login${RESET} ${DIM}(agent mode)${RESET}${suffix}
275
+
276
+ `);
277
+ out("This registers the epilot CLI on this machine as an agent and asks you to approve it in your browser.\n");
278
+ out(` Access: ${describeAccess({ profile, anonymized: options.anonymize })}
279
+ `);
280
+ if (options.reason) out(` Reason: ${options.reason}
281
+ `);
282
+ if (options.anonymize) {
283
+ out(`${YELLOW}Anonymize mode: personal data will be masked in all API responses for this CLI session.${RESET}
284
+ `);
285
+ }
286
+ const hostKey = ensureHostKey();
287
+ const agentKey = generateKeyPair();
288
+ const issuer = resolveAgentAuthIssuer(options.env);
289
+ const client = getAgentAuthClient(issuer);
290
+ const machine = hostname();
291
+ const registration = await client.registerAgent(hostKey, agentKey, {
292
+ name: `epilot CLI @ ${machine}`,
293
+ host_name: machine,
294
+ mode: "delegated",
295
+ reason: options.reason ?? "epilot CLI login",
296
+ capabilities: [
297
+ EPILOT_CAPABILITIES.organizationsList,
298
+ // read-only is implied by the profile (resolveLoginProfile already folded --readonly into it)
299
+ organizationAccessCapability({
300
+ organizationId: options.org,
301
+ profile,
302
+ anonymize: options.anonymize
303
+ })
304
+ ]
305
+ });
306
+ const record = {
307
+ agent_id: registration.agent_id,
308
+ host_id: registration.host_id,
309
+ privateKey: agentKey.privateKey,
310
+ issuer,
311
+ name: registration.name,
312
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
313
+ };
314
+ let status;
315
+ if (registration.status === "pending") {
316
+ if (!isDeviceAuthorization(registration.approval)) {
317
+ throw new AgentAuthError(
318
+ 0,
319
+ "unsupported_approval",
320
+ `The server requires an unsupported approval method (${String(registration.approval?.method)}).`
321
+ );
322
+ }
323
+ printApproval(registration.approval, out);
324
+ if (options.interactive) {
325
+ await openBrowser(registration.approval.verification_uri_complete, out);
326
+ } else {
327
+ out("Waiting for approval");
328
+ }
329
+ status = await client.waitForApproval(hostKey, registration.agent_id, registration.approval, {
330
+ onPoll: () => out(".")
331
+ });
332
+ out("\n");
333
+ }
334
+ const agentStatus = status?.status ?? registration.status;
335
+ if (agentStatus !== "active") {
336
+ throw new AgentAuthError(0, `agent_${agentStatus}`, `The agent was not approved (status: ${agentStatus}).`);
337
+ }
338
+ saveAgentRecord(record, options.profileName);
339
+ const loaded = loadAgentIdentity(options.profileName);
340
+ if (!loaded) throw new Error("Failed to store the agent identity.");
341
+ const { organizations } = await listEpilotOrganizations(client, loaded.identity);
342
+ const org = await chooseOrganization(organizations, options);
343
+ const grantedProfile = org.access?.access_profile ?? profile;
344
+ const issued = await issueTokenForOrg(loaded, org.organization_id, {
345
+ profile: grantedProfile,
346
+ ...isReadProfile(grantedProfile) && options.anonymize ? { anonymize: true } : {},
347
+ profileName: options.profileName
348
+ });
349
+ if (grantedProfile !== profile) {
350
+ out(`${YELLOW}Access was granted as ${grantedProfile} instead of the requested ${profile}.${RESET}
351
+ `);
352
+ }
353
+ out(`${GREEN}${BOLD}Login successful!${RESET}
354
+ `);
355
+ out(
356
+ ` Organization: ${org.organization_name ? `${org.organization_name} ${DIM}(${org.organization_id})${RESET}` : org.organization_id}
357
+ `
358
+ );
359
+ out(
360
+ ` Access: ${describeAccess({
361
+ profile: issued.access_profile ?? grantedProfile,
362
+ anonymized: issued.anonymize,
363
+ expiresAt: org.access?.expires_at
364
+ })}
365
+ `
366
+ );
367
+ out(` Token expires: ${issued.expires_at} ${DIM}(refreshed automatically while the agent is active)${RESET}
368
+ `);
369
+ out(`${DIM}Switch organizations with ${RESET}epilot org list${DIM} / ${RESET}epilot org use <id>${DIM}.${RESET}
370
+ `);
371
+ return {
372
+ agent_id: registration.agent_id,
373
+ host_id: registration.host_id,
374
+ issuer,
375
+ organization_id: org.organization_id,
376
+ organization_name: org.organization_name,
377
+ user_id: issued.user_id,
378
+ access_profile: issued.access_profile ?? grantedProfile,
379
+ read_only: issued.read_only,
380
+ anonymize: issued.anonymize,
381
+ expires_at: issued.expires_at,
382
+ ...org.access?.expires_at ? { grant_expires_at: org.access.expires_at } : {},
383
+ ...options.reason ? { reason: options.reason } : {},
384
+ profile: agentProfileKey(options.profileName)
385
+ };
386
+ };
387
+ var chooseOrganization = async (organizations, options) => {
388
+ const granted = organizations.filter((o) => o.access?.granted);
389
+ if (options.org) {
390
+ const match = organizations.find((o) => o.organization_id === options.org);
391
+ if (!match) {
392
+ throw new AgentAuthError(
393
+ 0,
394
+ "organization_not_found",
395
+ `Organization ${options.org} is not available to your user.`
396
+ );
397
+ }
398
+ if (!match.access?.granted) {
399
+ const hint = match.access?.pending ? "is still pending approval" : "was not granted";
400
+ throw new AgentAuthError(
401
+ 0,
402
+ "organization_not_granted",
403
+ `Access to organization ${options.org} ${hint}. Run \`epilot org request ${options.org}\` to ask for access.`
404
+ );
405
+ }
406
+ return match;
407
+ }
408
+ if (granted.length === 1) return granted[0];
409
+ if (granted.length === 0) {
410
+ throw new AgentAuthError(
411
+ 0,
412
+ "no_organization_granted",
413
+ "No organization was granted. Approve the request in your browser or run `epilot org request <id>`."
414
+ );
415
+ }
416
+ if (!options.interactive) {
417
+ throw new AgentAuthError(
418
+ 0,
419
+ "organization_required",
420
+ `Several organizations are granted (${granted.map((o) => o.organization_id).join(", ")}). Pass --org <id>.`
421
+ );
422
+ }
423
+ const { select } = await import("@inquirer/prompts");
424
+ const organizationId = await select({
425
+ message: "Select the organization to use:",
426
+ choices: granted.map((o) => ({
427
+ name: `${o.organization_name ?? o.organization_id} ${DIM}${o.organization_id}${accessLabel(o)}${RESET}`,
428
+ value: o.organization_id
429
+ }))
430
+ });
431
+ return granted.find((o) => o.organization_id === organizationId);
432
+ };
433
+ var accessLabel = (o) => {
434
+ const parts = [o.access?.access_profile ?? "read", o.access?.anonymized ? "anonymized" : ""].filter(Boolean);
435
+ return parts.length ? ` \xB7 ${parts.join(", ")}` : "";
436
+ };
82
437
  var browserLogin = async (profileName, env = "production", readonly = false, anonymize = false) => {
83
438
  const state = randomBytes(32).toString("hex");
84
439
  const verificationCode = randomBytes(3).toString("hex").toUpperCase();
@@ -361,6 +716,18 @@ var renderPage = (title, message, status, code) => {
361
716
  </html>`;
362
717
  };
363
718
  var escapeHtml = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
719
+
364
720
  export {
365
- auth_login_default as default
721
+ AGENT_FLAG_DESCRIPTION,
722
+ auth_login_default,
723
+ readOnlySibling,
724
+ parseAccessProfile,
725
+ resolveLoginProfile,
726
+ resolveReason,
727
+ describeAccess,
728
+ printApproval,
729
+ openBrowser,
730
+ agentLogin,
731
+ chooseOrganization,
732
+ browserLogin
366
733
  };
@@ -77,6 +77,7 @@ var listProfiles = () => {
77
77
  };
78
78
 
79
79
  export {
80
+ getConfigDir,
80
81
  loadProfiles,
81
82
  resolveProfileName,
82
83
  getResolvedProfile,
@@ -3,7 +3,7 @@ import {
3
3
  getResolvedProfile,
4
4
  resolveProfileName,
5
5
  upsertProfile
6
- } from "./chunk-YHQA2AVG.js";
6
+ } from "./chunk-QPUCHKXS.js";
7
7
 
8
8
  // src/lib/auth-store.ts
9
9
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
@@ -39,7 +39,8 @@ var saveCredentials = (creds, profileName) => {
39
39
  token: creds.token,
40
40
  org_id: creds.org_id,
41
41
  user_id: creds.user_id,
42
- expires_at: creds.expires_at
42
+ expires_at: creds.expires_at,
43
+ access_profile: creds.access_profile
43
44
  });
44
45
  }
45
46
  const dir = getConfigDir();
@@ -67,10 +68,23 @@ var resolveToken = (flagToken, flagProfile) => {
67
68
  const creds = loadCredentials();
68
69
  return creds?.token ?? null;
69
70
  };
71
+ var resolveTokenAsync = async (flagToken, flagProfile) => {
72
+ if (flagToken) return flagToken;
73
+ if (process.env.EPILOT_TOKEN) return process.env.EPILOT_TOKEN;
74
+ const { refreshTokenIfNeeded, isAgentGoneError, printLoginAgainHint } = await import("./agent-auth-GV2T4GET.js");
75
+ try {
76
+ const refreshed = await refreshTokenIfNeeded(flagProfile);
77
+ if (refreshed) return refreshed;
78
+ } catch (error) {
79
+ if (isAgentGoneError(error)) printLoginAgainHint(error);
80
+ }
81
+ return resolveToken(flagToken, flagProfile);
82
+ };
70
83
 
71
84
  export {
72
85
  loadCredentials,
73
86
  saveCredentials,
74
87
  removeCredentials,
75
- resolveToken
88
+ resolveToken,
89
+ resolveTokenAsync
76
90
  };
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ CLI_USER_AGENT
4
+ } from "./chunk-JQW3WOJB.js";
2
5
  import {
3
6
  formatOperationsTable,
4
7
  isInteractive,
@@ -6,15 +9,12 @@ import {
6
9
  promptParam
7
10
  } from "./chunk-IOLKUHUB.js";
8
11
  import {
9
- CLI_USER_AGENT
10
- } from "./chunk-KTCBDUL2.js";
11
- import {
12
- resolveToken
13
- } from "./chunk-M3M3C5WH.js";
12
+ resolveTokenAsync
13
+ } from "./chunk-SQ55BTMV.js";
14
14
  import {
15
15
  getResolvedProfile,
16
16
  getStage
17
- } from "./chunk-YHQA2AVG.js";
17
+ } from "./chunk-QPUCHKXS.js";
18
18
  import {
19
19
  BG_GREEN,
20
20
  BG_RED,
@@ -738,7 +738,7 @@ ${BOLD}Available operations:${RESET}
738
738
  `);
739
739
  process.exit(1);
740
740
  }
741
- let token = resolveToken(args.token, args.profile);
741
+ let token = await resolveTokenAsync(args.token, args.profile);
742
742
  if (!token) {
743
743
  if (isInteractive({ interactive: args.interactive })) {
744
744
  const { promptToken } = await import("./interactive-LSY5SADM.js");
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getStage,
4
4
  setStage
5
- } from "./chunk-YHQA2AVG.js";
5
+ } from "./chunk-QPUCHKXS.js";
6
6
  import {
7
7
  BOLD,
8
8
  DIM,
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-WWO5RPHF.js";
4
+ } from "./chunk-Y4B3K4IO.js";
5
+ import "./chunk-JQW3WOJB.js";
5
6
  import "./chunk-IOLKUHUB.js";
6
- import "./chunk-KTCBDUL2.js";
7
- import "./chunk-M3M3C5WH.js";
8
- import "./chunk-YHQA2AVG.js";
7
+ import "./chunk-SQ55BTMV.js";
8
+ import "./chunk-QPUCHKXS.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
10
10
 
11
11
  // src/commands/apis/configuration-hub.ts
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-WWO5RPHF.js";
4
+ } from "./chunk-Y4B3K4IO.js";
5
+ import "./chunk-JQW3WOJB.js";
5
6
  import "./chunk-IOLKUHUB.js";
6
- import "./chunk-KTCBDUL2.js";
7
- import "./chunk-M3M3C5WH.js";
8
- import "./chunk-YHQA2AVG.js";
7
+ import "./chunk-SQ55BTMV.js";
8
+ import "./chunk-QPUCHKXS.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
10
10
 
11
11
  // src/commands/apis/consent.ts
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-WWO5RPHF.js";
4
+ } from "./chunk-Y4B3K4IO.js";
5
+ import "./chunk-JQW3WOJB.js";
5
6
  import "./chunk-IOLKUHUB.js";
6
- import "./chunk-KTCBDUL2.js";
7
- import "./chunk-M3M3C5WH.js";
8
- import "./chunk-YHQA2AVG.js";
7
+ import "./chunk-SQ55BTMV.js";
8
+ import "./chunk-QPUCHKXS.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
10
10
 
11
11
  // src/commands/apis/customer-portal.ts
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-WWO5RPHF.js";
4
+ } from "./chunk-Y4B3K4IO.js";
5
+ import "./chunk-JQW3WOJB.js";
5
6
  import "./chunk-IOLKUHUB.js";
6
- import "./chunk-KTCBDUL2.js";
7
- import "./chunk-M3M3C5WH.js";
8
- import "./chunk-YHQA2AVG.js";
7
+ import "./chunk-SQ55BTMV.js";
8
+ import "./chunk-QPUCHKXS.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
10
10
 
11
11
  // src/commands/apis/dashboard.ts
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-WWO5RPHF.js";
4
+ } from "./chunk-Y4B3K4IO.js";
5
+ import "./chunk-JQW3WOJB.js";
5
6
  import "./chunk-IOLKUHUB.js";
6
- import "./chunk-KTCBDUL2.js";
7
- import "./chunk-M3M3C5WH.js";
8
- import "./chunk-YHQA2AVG.js";
7
+ import "./chunk-SQ55BTMV.js";
8
+ import "./chunk-QPUCHKXS.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
10
10
 
11
11
  // src/commands/apis/data-governance.ts
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-WWO5RPHF.js";
4
+ } from "./chunk-Y4B3K4IO.js";
5
+ import "./chunk-JQW3WOJB.js";
5
6
  import "./chunk-IOLKUHUB.js";
6
- import "./chunk-KTCBDUL2.js";
7
- import "./chunk-M3M3C5WH.js";
8
- import "./chunk-YHQA2AVG.js";
7
+ import "./chunk-SQ55BTMV.js";
8
+ import "./chunk-QPUCHKXS.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
10
10
 
11
11
  // src/commands/apis/deduplication.ts
@@ -8,10 +8,10 @@ import {
8
8
  uploadDirectoryAsZip,
9
9
  uploadFileToPresignedUrl,
10
10
  writeManifest
11
- } from "./chunk-5KHD2F3J.js";
12
- import "./chunk-KTCBDUL2.js";
13
- import "./chunk-M3M3C5WH.js";
14
- import "./chunk-YHQA2AVG.js";
11
+ } from "./chunk-BIOWN64A.js";
12
+ import "./chunk-JQW3WOJB.js";
13
+ import "./chunk-SQ55BTMV.js";
14
+ import "./chunk-QPUCHKXS.js";
15
15
  import "./chunk-7ZQ666ZQ.js";
16
16
 
17
17
  // src/commands/app/deploy.ts
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-WWO5RPHF.js";
4
+ } from "./chunk-Y4B3K4IO.js";
5
+ import "./chunk-JQW3WOJB.js";
5
6
  import "./chunk-IOLKUHUB.js";
6
- import "./chunk-KTCBDUL2.js";
7
- import "./chunk-M3M3C5WH.js";
8
- import "./chunk-YHQA2AVG.js";
7
+ import "./chunk-SQ55BTMV.js";
8
+ import "./chunk-QPUCHKXS.js";
9
9
  import "./chunk-7ZQ666ZQ.js";
10
10
 
11
11
  // src/commands/apis/design.ts