@thinkingai/ae-cli 6.1.18 → 6.1.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 (127) hide show
  1. package/README.md +97 -38
  2. package/README.zh.md +101 -38
  3. package/dist/{auth-ROB2EDYV.js → auth-FUM37MHF.js} +241 -126
  4. package/dist/{capability-DKMYUTLC.js → capability-AXFQW5WM.js} +49 -35
  5. package/dist/{chunk-JHENBQ5B.js → chunk-4P355ZWB.js} +70 -1
  6. package/dist/chunk-6ZIQV5GW.js +26 -0
  7. package/dist/{chunk-TUKQZTMI.js → chunk-7K24F7T2.js} +2 -0
  8. package/dist/{chunk-OO6XR6LK.js → chunk-AMBFK2K3.js} +2 -0
  9. package/dist/chunk-ATSM5XAW.js +623 -0
  10. package/dist/{chunk-4XXOWOTA.js → chunk-BBEFP4SB.js} +31 -38
  11. package/dist/{chunk-BYYS3ANB.js → chunk-CZU3V3DQ.js} +5 -15
  12. package/dist/{chunk-VTWMIC5L.js → chunk-E2JKXMVO.js} +2 -0
  13. package/dist/chunk-ECBLHAZO.js +15 -0
  14. package/dist/{sync-HKIOZXQE.js → chunk-I4WQAEYB.js} +31 -540
  15. package/dist/{chunk-DWO43OIB.js → chunk-JQ3ENZZH.js} +2 -0
  16. package/dist/chunk-LNZBEQXW.js +25216 -0
  17. package/dist/{chunk-ZQ47LWTI.js → chunk-QJQZH5GQ.js} +49 -79
  18. package/dist/{chunk-QZ3AS4KK.js → chunk-RSG4ONOI.js} +9 -8
  19. package/dist/{chunk-4NN5IWVN.js → chunk-T6OSFQZD.js} +2 -0
  20. package/dist/{chunk-Y3LOALAV.js → chunk-TAL6CZH6.js} +8 -7
  21. package/dist/{chunk-3KWQYGYI.js → chunk-TKHSULJT.js} +2 -0
  22. package/dist/chunk-VXNMYUXU.js +202 -0
  23. package/dist/{chunk-3FY3RJ26.js → chunk-WZ6YVQSF.js} +15 -14
  24. package/dist/{chunk-6EIJSNBD.js → chunk-Y74WTIKJ.js} +2 -0
  25. package/dist/{community-report-client-C7WDGET3.js → community-report-client-XXWGSBSD.js} +3 -4
  26. package/dist/{config-BMYZX2UE.js → config-EXUGQN5T.js} +10 -10
  27. package/dist/{data-integration-QEKDWQDY.js → data-integration-4NZ53OMT.js} +920 -97
  28. package/dist/index.js +56 -81
  29. package/dist/{local-data-upload-client-4YYHSYD6.js → local-data-upload-client-KYOKVYZV.js} +3 -4
  30. package/dist/{memory-I2WXDTV2.js → memory-ATNKZNW5.js} +6 -7
  31. package/dist/{metadata-I4C2EWUN.js → metadata-VZVC7YMH.js} +10 -11
  32. package/dist/{model-HLHIEFMU.js → model-E4JMQ4V2.js} +8 -9
  33. package/dist/{personal-semantic-preference-LIPACBDX.js → personal-semantic-preference-7S2SQ3UV.js} +9 -10
  34. package/dist/{project-semantic-RT3R2VQD.js → project-semantic-2SZP2OPO.js} +13 -14
  35. package/dist/sync-YV3E66IF.js +520 -0
  36. package/dist/{te-agent-BR6VDBNX.js → te-agent-JB5T3PO7.js} +396 -92
  37. package/dist/{te-analysis-7VUNUYWZ.js → te-analysis-3YJAAT2D.js} +196 -43
  38. package/dist/{te-community-5DMNKJWY.js → te-community-UDBI672N.js} +12 -34
  39. package/dist/{te-dataops-6P5IKWNJ.js → te-dataops-ZLYOCXZ4.js} +480 -81
  40. package/dist/{te-engage-KZPR5R22.js → te-engage-4XG6OJML.js} +88 -16
  41. package/dist/{te-experiment-6BITX4RD.js → te-experiment-VXUWPINJ.js} +83 -12
  42. package/dist/te-kb-WYQWHFSC.js +1732 -0
  43. package/dist/{te-system-FXITO2JG.js → te-system-7G6F2LJA.js} +569 -35
  44. package/dist/{te-team-ADOC2ROP.js → te-team-E7FBBXMQ.js} +8 -7
  45. package/dist/{update-YCYCKJOO.js → update-D47BUG25.js} +8 -8
  46. package/package.json +22 -10
  47. package/skills/ae-agent/SKILL.md +30 -13
  48. package/skills/ae-agent/references/agent-distribution.md +94 -0
  49. package/skills/ae-agent/references/approval-request.md +4 -0
  50. package/skills/ae-agent/references/command_index.md +9 -2
  51. package/skills/ae-agent/references/create-automation.md +20 -2
  52. package/skills/ae-agent/references/get-agent-context.md +70 -0
  53. package/skills/ae-agent/references/list-automations.md +18 -3
  54. package/skills/ae-agent/references/list-mcp-credentials.md +1 -1
  55. package/skills/ae-agent/references/mcp-token.md +3 -3
  56. package/skills/ae-agent/references/set-mcp-credential.md +0 -1
  57. package/skills/ae-agent/references/update-automation.md +18 -0
  58. package/skills/ae-analysis/SKILL.md +11 -2
  59. package/skills/ae-analysis/references/adhoc_run.md +2 -0
  60. package/skills/ae-analysis/references/ai_models.md +23 -3
  61. package/skills/ae-analysis/references/analysis_gateway_assets.md +3 -3
  62. package/skills/ae-analysis/references/audience_models.md +18 -0
  63. package/skills/ae-analysis/references/command_index.md +9 -9
  64. package/skills/ae-analysis/references/cross_source_config.md +84 -0
  65. package/skills/ae-analysis/references/dashboard_update.md +1 -1
  66. package/skills/ae-analysis/references/project_timezone_update.md +13 -4
  67. package/skills/ae-analysis/references/property_create.md +2 -0
  68. package/skills/ae-analysis/references/super_metadata_batch_create.md +2 -0
  69. package/skills/ae-analysis/references/user_cluster_models.md +2 -0
  70. package/skills/ae-analysis/references/user_cluster_update.md +8 -4
  71. package/skills/ae-analysis/references/user_tag_create.md +30 -2
  72. package/skills/ae-analysis/references/user_tag_models.md +17 -3
  73. package/skills/ae-analysis/references/user_tag_update.md +14 -2
  74. package/skills/ae-data-integration/SKILL.md +3 -1
  75. package/skills/ae-data-integration/references/dimension-routing.md +36 -0
  76. package/skills/ae-data-integration/references/error-handling.md +54 -1
  77. package/skills/ae-data-integration/references/local-analysis.md +2 -0
  78. package/skills/ae-data-integration/references/source-inspect.md +18 -2
  79. package/skills/ae-data-integration/references/tracking-plan.md +1 -1
  80. package/skills/ae-data-integration/references/transform.md +4 -2
  81. package/skills/ae-data-integration/references/ue-mapping.md +5 -2
  82. package/skills/ae-data-integration/references/ue-routing.md +40 -1
  83. package/skills/ae-dataops/SKILL.md +11 -1
  84. package/skills/ae-dataops/references/dataops-backfill.md +135 -0
  85. package/skills/ae-engage/SKILL.md +5 -0
  86. package/skills/ae-engage/references/build-task-save-guide.md +5 -1
  87. package/skills/ae-engage/references/save-flow.md +37 -1
  88. package/skills/ae-engage/references/save-task.md +6 -0
  89. package/skills/ae-experiment/SKILL.md +6 -2
  90. package/skills/ae-experiment/references/save_metric.md +20 -8
  91. package/skills/ae-generate-tracking-plan/SKILL.md +25 -13
  92. package/skills/ae-generate-tracking-plan/references/business-dimension-mapping.md +1 -1
  93. package/skills/ae-kb/SKILL.md +218 -36
  94. package/skills/ae-kb/references/query-workflow.md +59 -29
  95. package/skills/ae-kb/references/versions.md +46 -0
  96. package/skills/ae-system/SKILL.md +29 -31
  97. package/skills/ae-system/references/channel-management.md +303 -0
  98. package/skills/ae-use-agent/SKILL.md +42 -0
  99. package/skills/ae-use-agent/references/local-agent.md +114 -0
  100. package/dist/auth-GBMV6TEJ.js +0 -14
  101. package/dist/capability-HYVVPG25.js +0 -352
  102. package/dist/chunk-EFH4XWYC.js +0 -556
  103. package/dist/chunk-J2DEBMRF.js +0 -313
  104. package/dist/chunk-JRJY5DMJ.js +0 -71
  105. package/dist/chunk-OMPRXM3V.js +0 -349
  106. package/dist/chunk-QNOLN2LJ.js +0 -509
  107. package/dist/chunk-RJDU7NYP.js +0 -1198
  108. package/dist/chunk-RNAALWJK.js +0 -98
  109. package/dist/chunk-SERWF6G5.js +0 -13
  110. package/dist/chunk-UW5UN47B.js +0 -70
  111. package/dist/chunk-ZQKDZXDO.js +0 -317
  112. package/dist/client-L2YDMHQ6.js +0 -203
  113. package/dist/memory-3ORCR7JH.js +0 -893
  114. package/dist/metadata-VUOQJE26.js +0 -339
  115. package/dist/model-UGRDX4MW.js +0 -139
  116. package/dist/personal-semantic-preference-OEISBRHM.js +0 -239
  117. package/dist/project-semantic-FFPWFPIW.js +0 -1114
  118. package/dist/sync-TFHU2UTG.js +0 -10261
  119. package/dist/te-agent-VLYOV7S4.js +0 -3894
  120. package/dist/te-analysis-4YGQL5RC.js +0 -9357
  121. package/dist/te-community-ISDQWJU7.js +0 -1859
  122. package/dist/te-dataops-CVULXNVB.js +0 -2209
  123. package/dist/te-engage-N5WI32H6.js +0 -4898
  124. package/dist/te-experiment-UVR4HLND.js +0 -988
  125. package/dist/te-kb-RCLSSH2Q.js +0 -935
  126. package/dist/te-system-K2GYMCTB.js +0 -2213
  127. package/skills/ae-agent/references/auto-provision-mcp-credentials.md +0 -57
@@ -1,37 +1,47 @@
1
+ import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
+ import {
3
+ MultiselectCancelled,
4
+ promptSingleSelect
5
+ } from "./chunk-7K24F7T2.js";
6
+ import {
7
+ missingAeHostGuidance,
8
+ missingAeHostHint
9
+ } from "./chunk-6ZIQV5GW.js";
1
10
  import {
2
11
  getLocalCliPackageInfo
3
- } from "./chunk-VTWMIC5L.js";
12
+ } from "./chunk-E2JKXMVO.js";
13
+ import {
14
+ resolveHost
15
+ } from "./chunk-ECBLHAZO.js";
4
16
  import {
5
17
  printError,
6
18
  printOutput,
7
19
  runHostCompatCheck
8
- } from "./chunk-BYYS3ANB.js";
20
+ } from "./chunk-CZU3V3DQ.js";
9
21
  import {
10
- clearCliToken,
22
+ CliTokenValidationUnavailableError,
23
+ SecureStoreAuthError,
24
+ activateCredential,
25
+ clearAllCredentials,
26
+ clearCliTokenCache,
27
+ getActiveCredential,
28
+ listCredentials,
11
29
  mintCliToken,
30
+ removeActiveCredential,
31
+ saveCredential,
32
+ updateCredentialMetadata,
12
33
  validateCliTokenOnServer
13
- } from "./chunk-J2DEBMRF.js";
14
- import {
15
- SecureStoreAuthError,
16
- clear,
17
- load,
18
- missingAeHostGuidance,
19
- missingAeHostHint,
20
- resolveHost,
21
- save
22
- } from "./chunk-ZQKDZXDO.js";
34
+ } from "./chunk-ATSM5XAW.js";
23
35
  import {
24
36
  getFallbackCliToken,
25
37
  loadConfig,
26
38
  normalizeUrl,
27
39
  saveConfig
28
- } from "./chunk-3FY3RJ26.js";
29
- import {
30
- PermissionError
31
- } from "./chunk-UW5UN47B.js";
40
+ } from "./chunk-WZ6YVQSF.js";
32
41
  import {
42
+ PermissionError,
33
43
  logger
34
- } from "./chunk-JHENBQ5B.js";
44
+ } from "./chunk-4P355ZWB.js";
35
45
 
36
46
  // src/core/device-auth.ts
37
47
  import { execFileSync } from "child_process";
@@ -261,51 +271,141 @@ function resolveAuthHost(program, opts) {
261
271
  }
262
272
  async function validateExistingCliToken(host, cliToken) {
263
273
  try {
264
- await validateCliTokenOnServer(host, cliToken);
265
- return true;
274
+ return { valid: true, trusted: false, details: await validateCliTokenOnServer(host, cliToken) };
266
275
  } catch (error) {
267
- if (!(error instanceof SecureStoreAuthError)) {
268
- throw error;
276
+ if (error instanceof CliTokenValidationUnavailableError) {
277
+ logger.warn(`auth status: ${error.message}; trusting the stored CLI token for compatibility`);
278
+ return { valid: true, trusted: true, details: {} };
269
279
  }
280
+ if (!(error instanceof SecureStoreAuthError)) throw error;
270
281
  printError("auth", error.message);
271
282
  process.exitCode = 1;
272
- return false;
283
+ return { valid: false, trusted: false, details: {} };
273
284
  }
274
285
  }
275
286
  function activateHostAfterLogin(host, explicitHostOverride) {
276
287
  if (!explicitHostOverride) return;
277
288
  const normalized = normalizeUrl(host);
278
289
  const config = loadConfig();
279
- if (!config.hosts[normalized]) {
280
- config.hosts[normalized] = { label: normalized };
281
- }
290
+ if (!config.hosts[normalized]) config.hosts[normalized] = { label: normalized };
282
291
  config.activeHost = normalized;
283
292
  saveConfig(config);
284
293
  logger.info(`Active host set to ${normalized} after login`);
285
294
  }
286
- async function persistDeviceTokens(host, tokens) {
287
- const DEFAULT_EXPIRES_IN = 72e3;
288
- const MAX_EXPIRES_IN = 86400 * 365;
289
- let expiresInSeconds = tokens.expires_in ?? DEFAULT_EXPIRES_IN;
290
- if (!Number.isFinite(expiresInSeconds) || expiresInSeconds <= 0 || expiresInSeconds > MAX_EXPIRES_IN) {
291
- logger.warn(`auth login: expires_in=${tokens.expires_in} is out of range, falling back to ${DEFAULT_EXPIRES_IN}s`);
292
- expiresInSeconds = DEFAULT_EXPIRES_IN;
293
- }
294
- const expiresAt = new Date(Date.now() + expiresInSeconds * 1e3).toISOString();
295
- const cliToken = await mintCliToken(host, tokens.access_token, false);
296
- save(host, {
297
- accessToken: tokens.access_token,
298
- refreshToken: tokens.refresh_token ?? "",
299
- accessExpiresAt: expiresAt,
300
- cliToken
295
+ function accountOutput(account) {
296
+ return {
297
+ open_id: account.openId,
298
+ login_name: account.loginName,
299
+ user_name: account.userName
300
+ };
301
+ }
302
+ function credentialOutput(credential, active) {
303
+ return {
304
+ credential_id: credential.id,
305
+ active,
306
+ ...credential.account ? { account: accountOutput(credential.account) } : {},
307
+ cli_token: {
308
+ ...credential.cliTokenExpiresAt ? { expires_at: credential.cliTokenExpiresAt } : {},
309
+ ...credential.lastRenewedOn ? { last_renewed_on: credential.lastRenewedOn } : {}
310
+ }
311
+ };
312
+ }
313
+ function buildAccountSelectionItems(credentials, activeCredentialId) {
314
+ return credentials.filter((credential) => Boolean(credential.account)).sort((left, right) => Number(right.id === activeCredentialId) - Number(left.id === activeCredentialId)).map((credential) => {
315
+ const account = credential.account;
316
+ const displayName = account.userName && account.userName !== account.loginName ? `${account.loginName} (${account.userName})` : account.loginName;
317
+ const active = credential.id === activeCredentialId ? " [active]" : "";
318
+ return {
319
+ value: account.openId,
320
+ label: `${displayName} \xB7 ${account.openId}${active}`
321
+ };
301
322
  });
323
+ }
324
+ async function switchActiveAccount(program, opts) {
325
+ const host = resolveAuthHost(program, opts);
326
+ if (!host) {
327
+ printError("config", "No AE host configured.", missingAeHostHint());
328
+ process.exitCode = 1;
329
+ return;
330
+ }
331
+ let account = opts.account;
332
+ if (!account) {
333
+ if (!process.stdin.isTTY || !process.stderr.isTTY) {
334
+ printError(
335
+ "validation",
336
+ "Interactive account selection requires a TTY.",
337
+ `Run: ae-cli auth list --host ${host}, then ae-cli auth use --host ${host} --account <login-name-or-open-id>`
338
+ );
339
+ process.exitCode = 1;
340
+ return;
341
+ }
342
+ const active = getActiveCredential(host);
343
+ const items = buildAccountSelectionItems(listCredentials(host), active?.id);
344
+ if (items.length === 0) {
345
+ printError(
346
+ "auth",
347
+ `No stored accounts with identity metadata for ${host}.`,
348
+ `Upgrade the AE server if needed, then run: ae-cli auth login --host ${host}`
349
+ );
350
+ process.exitCode = 1;
351
+ return;
352
+ }
353
+ try {
354
+ account = await promptSingleSelect({
355
+ title: `Select an account for ${host} (up/down: move, enter: select, q: cancel)`,
356
+ items
357
+ });
358
+ } catch (error) {
359
+ if (error instanceof MultiselectCancelled) return;
360
+ throw error;
361
+ }
362
+ }
363
+ try {
364
+ const selected = activateCredential(host, account);
365
+ clearCliTokenCache(host);
366
+ await printOutput({
367
+ host,
368
+ active: true,
369
+ account: accountOutput(selected.account)
370
+ }, program.opts().format || "json");
371
+ } catch (error) {
372
+ printError("auth", error.message);
373
+ process.exitCode = 1;
374
+ }
375
+ }
376
+ async function persistDeviceTokens(host, tokens, options = {}) {
377
+ const cliToken = await mintCliToken(host, tokens.access_token);
378
+ let validation = {};
379
+ try {
380
+ validation = await validateCliTokenOnServer(host, cliToken);
381
+ } catch (error) {
382
+ if (error instanceof CliTokenValidationUnavailableError) {
383
+ logger.warn(`auth login: ${error.message}; saving CLI token without account metadata for compatibility`);
384
+ } else {
385
+ clearCliTokenCache(host);
386
+ throw error;
387
+ }
388
+ }
389
+ let saved;
390
+ try {
391
+ saved = saveCredential(host, {
392
+ cliToken,
393
+ ...validation.account ? { account: validation.account } : {},
394
+ ...validation.cliTokenExpiresAt ? { cliTokenExpiresAt: validation.cliTokenExpiresAt } : {}
395
+ }, options);
396
+ } catch (error) {
397
+ clearCliTokenCache(host);
398
+ throw error;
399
+ }
400
+ clearCliTokenCache(host);
302
401
  await runHostCompatCheck(getLocalCliPackageInfo(), host);
402
+ return saved;
303
403
  }
304
- function loginSummary(host, tokens) {
404
+ function loginSummary(host, credential) {
305
405
  return {
306
406
  authenticated: true,
307
407
  host,
308
- token: tokens.access_token.slice(0, 8) + "..."
408
+ ...credential.account ? { account: accountOutput(credential.account) } : {}
309
409
  };
310
410
  }
311
411
  function resolveLoginTeClaudeBase(host) {
@@ -314,8 +414,10 @@ function resolveLoginTeClaudeBase(host) {
314
414
  return base.endsWith(basePath) ? base : base + basePath;
315
415
  }
316
416
  function registerAuth(program) {
317
- const auth = program.command("auth").description("Authentication management");
318
- auth.command("login").description("Log in to AE using the device code flow (cross-platform; --no-browser to print URL only)").option("--host <url>", HOST_OPTION_DESC).option("--no-browser", "Do not auto-open the browser; only print the authorization URL (headless / Linux)").option("--no-wait", "Request the device code and print the authorization URL as JSON, then exit without polling (for AI agents / split-flow). Resume with --device-code").option("--device-code <code>", "Resume a split-flow login: poll for the given device code until authorized, then save the token").action(async (opts) => {
417
+ const auth = program.command("auth").description("Manage authentication or switch the active account interactively").action(async () => {
418
+ await switchActiveAccount(program, {});
419
+ });
420
+ auth.command("login").description("Log in to AE; by default replaces this host credentials, --add keeps existing accounts").option("--host <url>", HOST_OPTION_DESC).option("--add", "Add another account for the host and keep existing accounts").option("--no-browser", "Do not auto-open the browser; only print the authorization URL").option("--no-wait", "Print device authorization data and exit; resume with --device-code").option("--device-code <code>", "Resume a split-flow login with the given device code").action(async (opts) => {
319
421
  const explicitHost = getExplicitAuthHostOverride(program, opts);
320
422
  const host = resolveAuthHost(program, opts);
321
423
  if (!host) {
@@ -325,135 +427,148 @@ function registerAuth(program) {
325
427
  const config = loadConfig();
326
428
  if (!config.hosts[host]) {
327
429
  config.hosts[host] = { label: host };
328
- if (!config.activeHost) {
329
- config.activeHost = host;
330
- }
430
+ if (!config.activeHost) config.activeHost = host;
331
431
  saveConfig(config);
332
- logger.info(`Host config auto-saved for ${host}`);
333
432
  process.stderr.write(`[ae-cli] Config saved for ${host}
334
433
  `);
335
434
  }
336
435
  const noBrowser = !opts.browser;
337
- const fmt = program.opts().format || "json";
436
+ const format = program.opts().format || "json";
338
437
  const teClaudeBase = resolveLoginTeClaudeBase(host);
339
- const emit = (msg) => process.stderr.write(`[ae-cli] ${msg}
438
+ const emit = (message) => process.stderr.write(`[ae-cli] ${message}
340
439
  `);
341
440
  try {
342
441
  if (opts.deviceCode) {
343
442
  const tokens2 = await pollDeviceFlow(teClaudeBase, opts.deviceCode, {}, emit);
344
- await persistDeviceTokens(host, tokens2);
443
+ const saved2 = await persistDeviceTokens(host, tokens2, { add: opts.add });
345
444
  activateHostAfterLogin(host, explicitHost);
346
- logger.info(`Device flow login successful for ${host} (resumed)`);
347
- emit("Login successful! Token saved securely.");
348
- await printOutput(loginSummary(host, tokens2), fmt);
445
+ emit("Login successful! CLI token saved securely.");
446
+ await printOutput(loginSummary(host, saved2), format);
349
447
  return;
350
448
  }
351
449
  if (opts.wait === false) {
352
450
  const authResp = await authorizeDevice(teClaudeBase);
353
- await printOutput(
354
- {
355
- device_code: authResp.device_code,
356
- user_code: authResp.user_code,
357
- verification_url: buildVerificationUrl(teClaudeBase, authResp.user_code),
358
- interval: authResp.interval,
359
- expires_in: authResp.expires_in,
360
- next: `Open verification_url in a browser to authorize, then run: ae-cli auth login --device-code ${authResp.device_code}`
361
- },
362
- fmt
363
- );
451
+ const addFlag = opts.add ? " --add" : "";
452
+ await printOutput({
453
+ device_code: authResp.device_code,
454
+ user_code: authResp.user_code,
455
+ verification_url: buildVerificationUrl(teClaudeBase, authResp.user_code),
456
+ interval: authResp.interval,
457
+ expires_in: authResp.expires_in,
458
+ next: `Open verification_url in a browser to authorize, then run: ae-cli auth login${addFlag} --device-code ${authResp.device_code}`
459
+ }, format);
364
460
  return;
365
461
  }
366
462
  const tokens = await runDeviceFlow(teClaudeBase, { noBrowser }, emit);
367
- await persistDeviceTokens(host, tokens);
463
+ const saved = await persistDeviceTokens(host, tokens, { add: opts.add });
368
464
  activateHostAfterLogin(host, explicitHost);
369
- logger.info(`Device flow login successful for ${host}`);
370
- emit("Login successful! Token saved securely.");
371
- await printOutput(loginSummary(host, tokens), fmt);
372
- } catch (err) {
373
- if (err instanceof DeviceFlowUnsupportedError) {
374
- printError(
375
- "auth",
376
- err.message,
377
- "Upgrade the AE server to a version that supports device login."
378
- );
465
+ emit("Login successful! CLI token saved securely.");
466
+ await printOutput(loginSummary(host, saved), format);
467
+ } catch (error) {
468
+ if (error instanceof DeviceFlowUnsupportedError) {
469
+ printError("auth", error.message, "Upgrade the AE server to a version that supports device login.");
379
470
  process.exit(1);
380
471
  }
381
- if (err instanceof PermissionError) {
382
- printError("permission", err.message, err.hint, err.code);
472
+ if (error instanceof PermissionError) {
473
+ printError("permission", error.message, error.hint, error.code);
383
474
  process.exit(1);
384
475
  }
385
- printError("auth", err.message);
476
+ printError("auth", error.message);
386
477
  process.exit(1);
387
478
  }
388
479
  });
389
- auth.command("status").description("Show authentication status for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action(async (opts) => {
480
+ auth.command("status").description("Show the active CLI-token authentication status for a host").option("--host <url>", HOST_OPTION_DESC).action(async (opts) => {
390
481
  const host = resolveAuthHost(program, opts);
391
482
  if (!host) {
392
- await printOutput(
393
- {
394
- authenticated: false,
395
- host: "(none)",
396
- hint: missingAeHostHint(),
397
- next_steps: missingAeHostGuidance()
398
- },
399
- program.opts().format || "json"
400
- );
483
+ await printOutput({
484
+ authenticated: false,
485
+ host: "(none)",
486
+ hint: missingAeHostHint(),
487
+ next_steps: missingAeHostGuidance()
488
+ }, program.opts().format || "json");
401
489
  return;
402
490
  }
403
- const secureEntry = load(host);
404
- if (secureEntry) {
405
- if (secureEntry.cliToken && !await validateExistingCliToken(host, secureEntry.cliToken)) {
406
- return;
491
+ const active = getActiveCredential(host);
492
+ if (active) {
493
+ const state = await validateExistingCliToken(host, active.cliToken);
494
+ if (!state.valid) return;
495
+ if (state.details.account || state.details.cliTokenExpiresAt) {
496
+ updateCredentialMetadata(host, active.cliToken, state.details);
407
497
  }
408
- const pastStaticExpiry = new Date(secureEntry.accessExpiresAt).getTime() < Date.now();
409
- await printOutput(
410
- {
411
- authenticated: true,
412
- host,
413
- source: "secure-store",
414
- accessExpiresAt: secureEntry.accessExpiresAt,
415
- accessExpiresAtNote: "advisory: access token auto-slides on use server-side; re-login only if a command returns an auth error",
416
- pastStaticExpiry,
417
- hasCliToken: !!secureEntry.cliToken
498
+ const current = getActiveCredential(host) ?? active;
499
+ await printOutput({
500
+ authenticated: true,
501
+ host,
502
+ source: "secure-store",
503
+ cli_token: {
504
+ status: state.trusted ? "trusted" : "valid",
505
+ ...current.cliTokenExpiresAt ? { expires_at: current.cliTokenExpiresAt } : {},
506
+ ...current.lastRenewedOn ? { last_renewed_on: current.lastRenewedOn } : {}
418
507
  },
419
- program.opts().format || "json"
420
- );
508
+ ...current.account ? { account: accountOutput(current.account) } : {}
509
+ }, program.opts().format || "json");
421
510
  return;
422
511
  }
423
- const fallbackCliToken = getFallbackCliToken(host);
424
- if (fallbackCliToken) {
425
- if (!await validateExistingCliToken(host, fallbackCliToken)) {
426
- return;
427
- }
428
- await printOutput(
429
- {
430
- authenticated: true,
431
- host,
432
- source: "sandbox-cli-token",
433
- hasCliToken: true,
434
- note: "sandbox-provisioned cli-token.json; no user access token in secure-store"
512
+ const fallback = getFallbackCliToken(host);
513
+ if (fallback) {
514
+ const state = await validateExistingCliToken(host, fallback);
515
+ if (!state.valid) return;
516
+ await printOutput({
517
+ authenticated: true,
518
+ host,
519
+ source: "sandbox-cli-token",
520
+ cli_token: {
521
+ status: state.trusted ? "trusted" : "valid",
522
+ ...state.details.cliTokenExpiresAt ? { expires_at: state.details.cliTokenExpiresAt } : {}
435
523
  },
436
- program.opts().format || "json"
437
- );
524
+ ...state.details.account ? { account: accountOutput(state.details.account) } : {}
525
+ }, program.opts().format || "json");
438
526
  return;
439
527
  }
440
528
  await printOutput({ authenticated: false, host, source: "none" }, program.opts().format || "json");
441
529
  });
442
- auth.command("logout").description("Clear stored credentials (access token, refresh token, and CLI token) for a host (--host or active host)").option("--host <url>", HOST_OPTION_DESC).action(async (opts) => {
530
+ auth.command("list").description("List stored accounts for one host (does not call the server)").option("--host <url>", HOST_OPTION_DESC).action(async (opts) => {
443
531
  const host = resolveAuthHost(program, opts);
444
532
  if (!host) {
445
533
  printError("config", "No AE host configured.", missingAeHostHint());
446
534
  process.exit(1);
447
535
  }
448
- clearCliToken(host);
449
- clear(host);
450
- process.stderr.write(`[ae-cli] Credentials cleared for ${host}
451
- `);
452
- await printOutput({ cleared: true, host }, program.opts().format || "json");
536
+ const active = getActiveCredential(host);
537
+ const credentials = listCredentials(host);
538
+ await printOutput({
539
+ host,
540
+ accounts: credentials.map((credential) => credentialOutput(credential, credential.id === active?.id))
541
+ }, program.opts().format || "json");
542
+ });
543
+ auth.command("use").description("Switch the active account for a host; omit --account to choose interactively").option("--account <login-name-or-open-id>", "Login name or open_id returned by auth list").option("--host <url>", HOST_OPTION_DESC).action(async (opts) => {
544
+ await switchActiveAccount(program, opts);
545
+ });
546
+ auth.command("logout").description("Remove the active account, or all accounts with --all").option("--host <url>", HOST_OPTION_DESC).option("--all", "Remove all accounts stored for this host").action(async (opts) => {
547
+ const host = resolveAuthHost(program, opts);
548
+ if (!host) {
549
+ printError("config", "No AE host configured.", missingAeHostHint());
550
+ process.exit(1);
551
+ }
552
+ clearCliTokenCache(host);
553
+ if (opts.all) {
554
+ clearAllCredentials(host);
555
+ await printOutput({ cleared: true, all: true, host }, program.opts().format || "json");
556
+ return;
557
+ }
558
+ const result = removeActiveCredential(host);
559
+ await printOutput({
560
+ cleared: !!result.removed,
561
+ all: false,
562
+ host,
563
+ remaining_accounts: listCredentials(host).length,
564
+ ...result.active?.account ? { active_account: accountOutput(result.active.account) } : {}
565
+ }, program.opts().format || "json");
453
566
  });
454
567
  }
455
568
  export {
456
569
  activateHostAfterLogin,
570
+ buildAccountSelectionItems,
571
+ persistDeviceTokens,
457
572
  registerAuth,
458
573
  resolveLoginTeClaudeBase
459
574
  };
@@ -1,37 +1,40 @@
1
+ import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
1
2
  import {
2
3
  normalizeRiskLevel,
3
4
  requiresConfirmation
4
- } from "./chunk-OO6XR6LK.js";
5
+ } from "./chunk-AMBFK2K3.js";
6
+ import {
7
+ CapabilityGatewayError,
8
+ dryRunCapabilityWithEnvelope,
9
+ executeCapabilityWithEnvelope,
10
+ inspectCapability,
11
+ inspectCapabilityWithEnvelope,
12
+ listCapabilitiesWithEnvelope,
13
+ validateCapabilityWithEnvelope
14
+ } from "./chunk-QJQZH5GQ.js";
5
15
  import {
6
16
  findGatewayDomain,
7
17
  listRegisteredCapabilityDomains,
8
18
  resolveGatewayDomain
9
- } from "./chunk-3KWQYGYI.js";
19
+ } from "./chunk-TKHSULJT.js";
10
20
  import {
11
- printError,
12
- printOutput
13
- } from "./chunk-BYYS3ANB.js";
21
+ resolveHost
22
+ } from "./chunk-ECBLHAZO.js";
14
23
  import {
15
- CapabilityGatewayError,
16
- dryRunCapability,
17
- executeCapability,
18
- inspectCapability,
19
- listCapabilities,
20
- validateCapability
21
- } from "./chunk-ZQ47LWTI.js";
22
- import "./chunk-SERWF6G5.js";
23
- import "./chunk-J2DEBMRF.js";
24
+ printError,
25
+ printOutput,
26
+ withOutputMetadata
27
+ } from "./chunk-CZU3V3DQ.js";
28
+ import "./chunk-Y74WTIKJ.js";
24
29
  import {
25
- SecureStoreAuthError,
26
- resolveHost
27
- } from "./chunk-ZQKDZXDO.js";
30
+ SecureStoreAuthError
31
+ } from "./chunk-ATSM5XAW.js";
28
32
  import {
29
33
  safeJsonParse
30
- } from "./chunk-3FY3RJ26.js";
34
+ } from "./chunk-WZ6YVQSF.js";
31
35
  import {
32
36
  PermissionError
33
- } from "./chunk-UW5UN47B.js";
34
- import "./chunk-JHENBQ5B.js";
37
+ } from "./chunk-4P355ZWB.js";
35
38
 
36
39
  // src/commands/capability/index.ts
37
40
  import * as readline from "readline";
@@ -177,15 +180,16 @@ function registerCapability(program) {
177
180
  await executeAndPrint(program, async (host) => {
178
181
  const gatewayDomain = resolveCapabilityListDomain(opts.domain);
179
182
  const projectId = parseOptionalProjectId(opts.projectId);
180
- const catalog = normalizeCapabilityList(await listCapabilities(host, gatewayDomain, projectId));
183
+ const envelope = await listCapabilitiesWithEnvelope(host, gatewayDomain, projectId);
184
+ const catalog = normalizeCapabilityList(envelope.data);
181
185
  const capabilities = filterCapabilities(catalog, opts.domain);
182
186
  const warning = emptyCapabilityCatalogWarning(catalog);
183
- return {
187
+ return withOutputMetadata({
184
188
  domain: opts.domain,
185
189
  count: capabilities.length,
186
190
  capabilities,
187
191
  ...warning ? { warning } : {}
188
- };
192
+ }, envelope.meta);
189
193
  });
190
194
  }).addHelpText(
191
195
  "after",
@@ -198,16 +202,17 @@ function registerCapability(program) {
198
202
  await executeAndPrint(program, async (host) => {
199
203
  const gatewayDomain = resolveCapabilityListDomain(opts.domain);
200
204
  const projectId = parseOptionalProjectId(opts.projectId);
201
- const catalog = normalizeCapabilityList(await listCapabilities(host, gatewayDomain, projectId));
205
+ const envelope = await listCapabilitiesWithEnvelope(host, gatewayDomain, projectId);
206
+ const catalog = normalizeCapabilityList(envelope.data);
202
207
  const capabilities = filterCapabilities(catalog, opts.domain, query);
203
208
  const warning = emptyCapabilityCatalogWarning(catalog);
204
- return {
209
+ return withOutputMetadata({
205
210
  domain: opts.domain,
206
211
  query,
207
212
  count: capabilities.length,
208
213
  capabilities,
209
214
  ...warning ? { warning } : {}
210
- };
215
+ }, envelope.meta);
211
216
  });
212
217
  }).addHelpText(
213
218
  "after",
@@ -216,7 +221,7 @@ function registerCapability(program) {
216
221
  capability.command("inspect").description("Inspect one capability schema, risk, auth, and output metadata").argument("<capability-id>", "Capability ID, such as analysis.report.list").option("--domain <domain>", "Override the capability namespace used for gateway routing").option("--project-id <project-id>", "Check availability in a project before returning metadata").action(async (capabilityId, opts) => {
217
222
  await executeAndPrint(program, async (host) => {
218
223
  const gatewayDomain = resolveCapabilityGatewayDomain(capabilityId, opts.domain);
219
- return inspectCapability(host, gatewayDomain, capabilityId, parseOptionalProjectId(opts.projectId));
224
+ return gatewayOutput(await inspectCapabilityWithEnvelope(host, gatewayDomain, capabilityId, parseOptionalProjectId(opts.projectId)), host);
220
225
  });
221
226
  }).addHelpText(
222
227
  "after",
@@ -227,7 +232,7 @@ function registerCapability(program) {
227
232
  ).argument("<capability-id>", "Capability ID, such as metadata.data_table.sql_write").option("--domain <domain>", "Override the capability namespace used for gateway routing").option("--input <json-or-path>", "Input JSON object, file path, @<path>, or - for stdin").action(async (capabilityId, opts) => {
228
233
  await executeAndPrint(program, async (host) => {
229
234
  const gatewayDomain = resolveCapabilityGatewayDomain(capabilityId, opts.domain);
230
- return validateCapability(host, gatewayDomain, capabilityId, parseCapabilityInput(opts.input));
235
+ return gatewayOutput(await validateCapabilityWithEnvelope(host, gatewayDomain, capabilityId, parseCapabilityInput(opts.input)), host);
231
236
  });
232
237
  }).addHelpText(
233
238
  "after",
@@ -249,7 +254,7 @@ Examples:
249
254
  ).argument("<capability-id>", "Capability ID, such as analysis.query.export").option("--domain <domain>", "Override the capability namespace used for gateway routing").option("--input <json-or-path>", "Input JSON object, file path, @<path>, or - for stdin").action(async (capabilityId, opts) => {
250
255
  await executeAndPrint(program, async (host) => {
251
256
  const gatewayDomain = resolveCapabilityGatewayDomain(capabilityId, opts.domain);
252
- return dryRunCapability(host, gatewayDomain, capabilityId, parseCapabilityInput(opts.input));
257
+ return gatewayOutput(await dryRunCapabilityWithEnvelope(host, gatewayDomain, capabilityId, parseCapabilityInput(opts.input)), host);
253
258
  });
254
259
  }).addHelpText(
255
260
  "after",
@@ -269,10 +274,10 @@ Examples:
269
274
  );
270
275
  }
271
276
  if (globalOpts.validate) {
272
- return validateCapability(host, gatewayDomain, capabilityId, input);
277
+ return gatewayOutput(await validateCapabilityWithEnvelope(host, gatewayDomain, capabilityId, input), host);
273
278
  }
274
279
  if (globalOpts.dryRun) {
275
- return dryRunCapability(host, gatewayDomain, capabilityId, input);
280
+ return gatewayOutput(await dryRunCapabilityWithEnvelope(host, gatewayDomain, capabilityId, input), host);
276
281
  }
277
282
  if (!globalOpts.yes) {
278
283
  const metadata = await inspectCapability(host, gatewayDomain, capabilityId);
@@ -285,7 +290,7 @@ Examples:
285
290
  }
286
291
  }
287
292
  }
288
- return executeCapability(host, gatewayDomain, capabilityId, input);
293
+ return gatewayOutput(await executeCapabilityWithEnvelope(host, gatewayDomain, capabilityId, input), host);
289
294
  });
290
295
  }).addHelpText(
291
296
  "after",
@@ -295,6 +300,15 @@ Examples:
295
300
  ae-cli capability run analysis.dashboard.list --input input.json`
296
301
  );
297
302
  }
303
+ function gatewayOutput(envelope, host) {
304
+ return withOutputMetadata(withPageUrl(envelope.data, host), envelope.meta);
305
+ }
306
+ function withPageUrl(value, host) {
307
+ if (!value || typeof value !== "object" || Array.isArray(value)) return value;
308
+ const record = value;
309
+ if (typeof record.page_path !== "string" || !/^\/(?![\\/])/.test(record.page_path) || record.page_url !== void 0) return value;
310
+ return { ...record, page_url: new URL(record.page_path, host).toString() };
311
+ }
298
312
  async function executeAndPrint(program, action) {
299
313
  const globalOpts = program.opts();
300
314
  const host = resolveHost(globalOpts.host);
@@ -314,11 +328,11 @@ async function executeAndPrint(program, action) {
314
328
  process.exitCode = 1;
315
329
  return;
316
330
  }
317
- printCapabilityError(error);
331
+ printCapabilityError(error, host);
318
332
  process.exitCode = 1;
319
333
  }
320
334
  }
321
- function printCapabilityError(error) {
335
+ function printCapabilityError(error, host) {
322
336
  if (error instanceof CapabilityCommandValidationError) {
323
337
  printError("validation", error.message, error.hint, error.code);
324
338
  return;
@@ -332,7 +346,7 @@ function printCapabilityError(error) {
332
346
  return;
333
347
  }
334
348
  if (error instanceof CapabilityGatewayError) {
335
- printError("api", error.message, error.hint, error.code);
349
+ printError("api", error.message, error.hint, error.code, withPageUrl(error.meta, host));
336
350
  return;
337
351
  }
338
352
  const message = error instanceof Error ? error.message : String(error);