@empirical-gauzza/cli 1.0.35 → 1.0.37

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.
package/bin/empirical.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  'use strict';
4
4
 
@@ -25,6 +25,7 @@ const { showVersion } = require('../lib/help');
25
25
  const { isPluginCommand, runPluginCommand } = require('../lib/pluginCommands');
26
26
  const { runPolicyCommand } = require('../lib/policyCommands');
27
27
  const { runSetupCommand } = require('../lib/setupCommands');
28
+ const { runUsageCommand } = require('../lib/usageCommands');
28
29
  const { runBlueprintCommand } = require('../lib/blueprintCommands');
29
30
  const { checkNativePluginUpdates } = require('../lib/pluginUpdateCheck');
30
31
 
@@ -112,6 +113,11 @@ async function main() {
112
113
  return;
113
114
  }
114
115
 
116
+ if (args[0] === 'usage') {
117
+ await runUsageCommand(args.slice(1));
118
+ return;
119
+ }
120
+
115
121
  if (args[0] === 'setup') {
116
122
  await runSetupCommand(args.slice(1));
117
123
  return;
package/lib/auth.js CHANGED
@@ -361,7 +361,7 @@ function inspectToken(token) {
361
361
  // Gathers the same identity/workspace facts `doctor` reports (token presence/type/expiry, plus
362
362
  // user + workspace from /api/v1/users/me), formatted for `auth status` / `whoami` as a single
363
363
  // JSON object instead of doctor's multi-check report.
364
- async function gatherAuthStatus() {
364
+ async function gatherAuthStatus({ includeEmpiricalTokens = false } = {}) {
365
365
  const token = resolveAccessToken();
366
366
  const tokenInfo = inspectToken(token);
367
367
 
@@ -385,6 +385,31 @@ async function gatherAuthStatus() {
385
385
  }
386
386
  }
387
387
 
388
+ // What the CLI itself will scope the next memory command to (env, project binding, or the
389
+ // global selection), beside the server-reported account workspace above. The two can differ,
390
+ // and when they do this is the field that explains a "[]" recall. Lazy require: workspaceContext
391
+ // depends on this module.
392
+ let cliWorkspace = null;
393
+ try {
394
+ const { resolveLocalWorkspaceSelection } = require('./workspaceContext');
395
+ const local = resolveLocalWorkspaceSelection();
396
+ if (local) cliWorkspace = { workspaceId: local.workspaceId, label: local.label || null, source: local.source, path: local.path };
397
+ } catch (_error) {
398
+ cliWorkspace = null;
399
+ }
400
+
401
+ // `whoami` / `auth status` add one Empirical Tokens line while they are enforced (spec 8.4).
402
+ // Best effort with a short timeout; doctor does not ask for it.
403
+ let empiricalTokens = null;
404
+ if (includeEmpiricalTokens && token && !error) {
405
+ try {
406
+ const { fetchBillingMe, empiricalTokensLine } = require('./usageCommands');
407
+ empiricalTokens = empiricalTokensLine((await fetchBillingMe(3000)).empiricalTokenUsage);
408
+ } catch (_error) {
409
+ empiricalTokens = null;
410
+ }
411
+ }
412
+
388
413
  return {
389
414
  authenticated: Boolean(token) && !error && tokenInfo.expired !== true,
390
415
  tokenPresent: tokenInfo.present,
@@ -393,6 +418,9 @@ async function gatherAuthStatus() {
393
418
  tokenExpired: tokenInfo.expired,
394
419
  user,
395
420
  workspaceId,
421
+ cliWorkspace,
422
+ // Present only while enforced for this account: a dark account's JSON has no such key.
423
+ ...(empiricalTokens ? { empiricalTokens } : {}),
396
424
  error
397
425
  };
398
426
  }
@@ -408,7 +436,7 @@ async function runAuthCommand(args) {
408
436
  }
409
437
 
410
438
  if (action === 'status' || action === 'whoami') {
411
- const status = await gatherAuthStatus();
439
+ const status = await gatherAuthStatus({ includeEmpiricalTokens: true });
412
440
  log(JSON.stringify(status));
413
441
  if (!status.authenticated) {
414
442
  process.exitCode = 1;
@@ -3,7 +3,9 @@
3
3
  const { httpJson, printApiError } = require('./http');
4
4
  const { parseOption } = require('./env');
5
5
  const { requireAccessToken, resolveApiBaseUrl, buildApiAuthHeaders } = require('./auth');
6
- const { warn, log } = require('./ui');
6
+ const { warn, log, createPrompter } = require('./ui');
7
+ const { sanitizeForTerminal } = require('./setupCommands');
8
+ const { confirmCostOrExit, isCostPreview, isInteractiveTerminal } = require('./empiricalTokensFormat');
7
9
 
8
10
  function apiUrl(pathSuffix) {
9
11
  return new URL(`/api/v1/blueprints${pathSuffix}`, resolveApiBaseUrl()).toString();
@@ -61,17 +63,35 @@ async function runClaim(args) {
61
63
  async function runInstall(args) {
62
64
  const blueprintId = args[0] && !args[0].startsWith('--') ? args[0] : '';
63
65
  if (!blueprintId) {
64
- warn('Usage: empirical blueprint install <blueprintId> [--version <v>]');
66
+ warn('Usage: empirical blueprint install <blueprintId> [--version <v>] [--accept-cost]');
65
67
  process.exit(1);
66
68
  }
67
69
  const version = parseOption(args, '--version', '');
70
+ const acceptCost = args.includes('--accept-cost');
68
71
 
69
72
  const detail = await callApi('GET', `/${blueprintId}`, undefined);
70
73
  if (!detail.owned && detail.priceModel === 'free') {
71
74
  await callApi('POST', `/${blueprintId}/claim`, {});
72
75
  }
73
76
 
74
- const installResult = await callApi('POST', `/${blueprintId}/install`, version ? { version } : {});
77
+ const installBody = { ...(version ? { version } : {}), ...(acceptCost ? { acceptEmpiricalTokenCost: true } : {}) };
78
+ let installResult = await callApi('POST', `/${blueprintId}/install`, installBody);
79
+ if (isCostPreview(installResult)) {
80
+ // A priced blueprint in enforce answers 200 with the cost and starts nothing (no installId yet).
81
+ // Acceptance is sent only from --accept-cost or an explicit y at a real terminal, never for the person.
82
+ const prompter = isInteractiveTerminal() ? createPrompter(process.stderr) : null;
83
+ try {
84
+ await confirmCostOrExit(installResult, { prompter, warn, sanitize: sanitizeForTerminal });
85
+ } finally {
86
+ if (prompter) prompter.close();
87
+ }
88
+ installResult = await callApi('POST', `/${blueprintId}/install`, { ...installBody, acceptEmpiricalTokenCost: true });
89
+ }
90
+ if (!installResult || !installResult.installId) {
91
+ // Never poll /installs/undefined: a reply with no install id is not a started install.
92
+ log(JSON.stringify(installResult, null, 2));
93
+ return;
94
+ }
75
95
  const finalStatus = await waitForInstall(installResult.installId);
76
96
  log(JSON.stringify(finalStatus, null, 2));
77
97
  }