@doow/cli 0.1.1 → 0.1.4

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/README.md CHANGED
@@ -27,29 +27,63 @@ doow chat # interactive chat with Derek or Mina
27
27
 
28
28
  ## Commands
29
29
 
30
+ ### Identity & setup
31
+
32
+ | Command | Description |
33
+ |---------|-------------|
34
+ | `doow login` | Authenticate (PKCE browser flow or device-code for headless) |
35
+ | `doow logout` | Revoke tokens and clear local credentials |
36
+ | `doow whoami` | Show current user and organization |
37
+ | `doow profiles` | Switch between multiple organizations |
38
+
39
+ ### Applications & spend
40
+
41
+ | Command | Description |
42
+ |---------|-------------|
43
+ | `doow apps` | List, inspect, compare, and manage SaaS applications |
44
+ | `doow dashboard` | Spend breakdown, renewal timeline, and key metrics |
45
+ | `doow expenses` | View expenses synced from banking, accounting, or billing integrations |
46
+ | `doow insights` | Surface apps that need attention — underused, overspent, or duplicated |
47
+ | `doow search <query>` | Full-text search across apps, contracts, team members, and more |
48
+
49
+ ### Contracts & renewals
50
+
51
+ | Command | Description |
52
+ |---------|-------------|
53
+ | `doow contracts` | Manage PAYG, Enterprise, and subscription contracts — create, update, track renewals |
54
+ | `doow overages` | Track usage overages against contract limits |
55
+ | `doow usage-tuples` | Record metered usage (seats, API calls, storage) against contracts for billing reconciliation |
56
+
57
+ ### Licensing
58
+
59
+ | Command | Description |
60
+ |---------|-------------|
61
+ | `doow licenses` | Manage seat-based, usage-based, and prepaid licenses — assign users, track utilization, manage spend pools and credit vintages |
62
+
63
+ ### Cards & payments
64
+
65
+ | Command | Description |
66
+ |---------|-------------|
67
+ | `doow cards` | Issue virtual/physical cards, fund, freeze, map to apps, view transactions |
68
+
69
+ ### Team & org
70
+
71
+ | Command | Description |
72
+ |---------|-------------|
73
+ | `doow team` | Invite members, manage departments, activate/deactivate users |
74
+ | `doow integrations` | Connect SSO, HRIS, and billing providers — view sync logs, trigger syncs |
75
+
76
+ ### Reports
77
+
78
+ | Command | Description |
79
+ |---------|-------------|
80
+ | `doow reports` | Export expense, contract, license, card, and department reports as CSV or PDF — download or email |
81
+
82
+ ### AI assistant
83
+
30
84
  | Command | Description |
31
85
  |---------|-------------|
32
- | `doow login` | Authenticate with Doow (PKCE or device flow) |
33
- | `doow logout` | Revoke refresh token and clear credentials |
34
- | `doow whoami` | Show current identity |
35
- | `doow profiles` | Manage multi-org profiles |
36
- | `doow apps` | Manage SaaS applications |
37
- | `doow contracts` | Manage contracts |
38
- | `doow licenses` | Manage licenses |
39
- | `doow cards` | Manage virtual and physical cards |
40
- | `doow team` | Manage team members and departments |
41
- | `doow integrations` | Manage third-party integrations |
42
- | `doow insights` | View insights and notifications |
43
- | `doow dashboard` | View spend overview and key metrics |
44
- | `doow search <query>` | Search across apps, contracts, members, and more |
45
- | `doow expenses` | View expenses |
46
- | `doow overages` | View contract overages |
47
- | `doow usage-tuples` | View and manage usage metric tuples |
48
- | `doow reports` | Generate and export reports |
49
- | `doow chat` | Chat with Derek or Mina (interactive) |
50
- | `doow mcp` | Start MCP server over stdio |
51
- | `doow doctor` | Diagnostic: auth, config, network, API version |
52
- | `doow completion` | Output shell completion script |
86
+ | `doow chat` | Interactive chat with Derek (spend analyst) or Mina (procurement advisor) |
53
87
 
54
88
  ## MCP server
55
89
 
@@ -10,7 +10,7 @@ var keyring = require('./keyring.js');
10
10
  * environments where a browser cannot be opened on the same machine.
11
11
  *
12
12
  * Steps:
13
- * 1. POST /v1/auth/device/authorize → get device_code + user_code
13
+ * 1. POST /v1/auth/cli/device → get device_code + user_code
14
14
  * 2. Display verification URI + user_code on stderr
15
15
  * 3. Optionally open the browser (best-effort)
16
16
  * 4. Poll POST /v1/auth/device/token until granted or expired
@@ -30,6 +30,15 @@ function sleep(ms) {
30
30
  function expiresAtFromSecondsIn(secondsIn) {
31
31
  return new Date(Date.now() + secondsIn * 1000).toISOString();
32
32
  }
33
+ function isLegacyPendingPollResponse(status, body) {
34
+ const legacyBody = body;
35
+ return (status === 400 &&
36
+ body != null &&
37
+ typeof body === 'object' &&
38
+ legacyBody.name === 'HttpException' &&
39
+ legacyBody.message === 'Bad Request Exception' &&
40
+ legacyBody.response === 'Bad Request Exception');
41
+ }
33
42
  // ---------------------------------------------------------------------------
34
43
  // Core function
35
44
  // ---------------------------------------------------------------------------
@@ -52,7 +61,7 @@ async function executeDeviceFlow(options = {}) {
52
61
  // -------------------------------------------------------------------------
53
62
  // Step 1: Request device authorization
54
63
  // -------------------------------------------------------------------------
55
- const authorizeRes = await fetch(`${apiUrl}/v1/auth/device/authorize`, {
64
+ const authorizeRes = await fetch(`${apiUrl}/v1/auth/cli/device`, {
56
65
  method: 'POST',
57
66
  headers: { 'Content-Type': 'application/json' },
58
67
  body: JSON.stringify({ client_id: 'doow-cli' }),
@@ -62,6 +71,7 @@ async function executeDeviceFlow(options = {}) {
62
71
  throw new Error(`Device authorization request failed: HTTP ${authorizeRes.status}${body ? ` — ${body}` : ''}`);
63
72
  }
64
73
  const auth = (await authorizeRes.json());
74
+ const deviceCodeExpiresAt = Date.now() + auth.expires_in * 1000;
65
75
  // -------------------------------------------------------------------------
66
76
  // Step 2: Display instructions on stderr
67
77
  // -------------------------------------------------------------------------
@@ -81,6 +91,9 @@ async function executeDeviceFlow(options = {}) {
81
91
  let pollInterval = auth.interval; // seconds; RFC 8628 §3.5
82
92
  while (true) {
83
93
  await sleep(pollInterval * 1000);
94
+ if (Date.now() > deviceCodeExpiresAt) {
95
+ throw new Error('Device code expired. Run doow login --device again.');
96
+ }
84
97
  const tokenRes = await fetch(`${apiUrl}/v1/auth/device/token`, {
85
98
  method: 'POST',
86
99
  headers: { 'Content-Type': 'application/json' },
@@ -125,6 +138,9 @@ async function executeDeviceFlow(options = {}) {
125
138
  case 'access_denied':
126
139
  throw new Error('Authorization denied by user.');
127
140
  default:
141
+ if (isLegacyPendingPollResponse(tokenRes.status, errBody)) {
142
+ continue;
143
+ }
128
144
  throw new Error(`Token polling failed: ${errBody.error}${errBody.error_description ? ` — ${errBody.error_description}` : ''}`);
129
145
  }
130
146
  }
@@ -1 +1 @@
1
- {"version":3,"file":"device-flow.js","sources":["../../../../src/auth/device-flow.ts"],"sourcesContent":[null],"names":["getApiUrl","createCredentialStore","shouldShowUI"],"mappings":";;;;;AAAA;;;;;;;;;;;;AAYG;AAuDH;AACA;AACA;AAEA;AACA,SAAS,KAAK,CAAC,EAAU,EAAA;AACvB,IAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC1D;AAEA;;;AAGG;AACG,SAAU,sBAAsB,CAAC,SAAiB,EAAA;AACtD,IAAA,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;AAC9D;AAEA;AACA;AACA;AAEA;;;;;;AAMG;AACI,eAAe,iBAAiB,CACrC,UAA6B,EAAE,EAAA;IAE/B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAIA,aAAS,EAAE;AAC5C,IAAA,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,SAAS;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,eAAe,KAAK,MAAMC,6BAAqB,EAAE,CAAC;AACxE,IAAA,MAAM,OAAO,GACX,OAAO,CAAC,OAAO;AACf,SAAC,OAAO,GAAW,KAAI;YACrB,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,MAAM,CAAC;AAC9C,YAAA,MAAM,IAAI,CAAC,GAAG,CAAC;AACjB,QAAA,CAAC,CAAC;;;;IAMJ,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,CAAA,EAAG,MAAM,2BAA2B,EAAE;AACrE,QAAA,MAAM,EAAE,MAAM;AACd,QAAA,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AAChD,KAAA,CAAC;AAEF,IAAA,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE;AACpB,QAAA,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CACb,CAAA,0CAAA,EAA6C,YAAY,CAAC,MAAM,GAAG,IAAI,GAAG,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,GAAG,EAAE,CAAA,CAAE,CAC9F;IACH;IAEA,MAAM,IAAI,IAAI,MAAM,YAAY,CAAC,IAAI,EAAE,CAAuB;;;;AAM9D,IAAA,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,CAAA,+CAAA,EAAkD,IAAI,CAAC,gBAAgB,wBAAwB,IAAI,CAAC,SAAS,CAAA,IAAA,CAAM,CACpH;;IAGD,IAAIC,gBAAY,EAAE,EAAE;AAClB,QAAA,IAAI;AACF,YAAA,MAAM,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC;QACtC;AAAE,QAAA,MAAM;;QAER;IACF;;;;AAMA,IAAA,IAAI,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC;IAEjC,OAAO,IAAI,EAAE;AACX,QAAA,MAAM,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;QAEhC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAA,EAAG,MAAM,uBAAuB,EAAE;AAC7D,YAAA,MAAM,EAAE,MAAM;AACd,YAAA,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;AAC/C,YAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,WAAW,EAAE,IAAI,CAAC,WAAW;AAC7B,gBAAA,UAAU,EAAE,8CAA8C;aAC3D,CAAC;AACH,SAAA,CAAC;AAEF,QAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;;YAEf,MAAM,MAAM,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB;;;;YAM9D,MAAM,SAAS,GAAG,sBAAsB,CAAC,MAAM,CAAC,UAAU,CAAC;AAE3D,YAAA,MAAM,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE;gBAC3B,WAAW,EAAE,MAAM,CAAC,YAAY;gBAChC,YAAY,EAAE,MAAM,CAAC,aAAa;gBAClC,SAAS;AACV,aAAA,CAAC;;;;YAMF,OAAO;gBACL,WAAW,EAAE,MAAM,CAAC,YAAY;gBAChC,YAAY,EAAE,MAAM,CAAC,aAAa;gBAClC,SAAS;aACV;QACH;;QAGA,MAAM,OAAO,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAuB;AAEjG,QAAA,QAAQ,OAAO,CAAC,KAAK;AACnB,YAAA,KAAK,uBAAuB;;gBAE1B;AAEF,YAAA,KAAK,WAAW;;gBAEd,YAAY,IAAI,CAAC;gBACjB;AAEF,YAAA,KAAK,eAAe;AAClB,gBAAA,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC;AAExE,YAAA,KAAK,eAAe;AAClB,gBAAA,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC;AAElD,YAAA;gBACE,MAAM,IAAI,KAAK,CACb,CAAA,sBAAA,EAAyB,OAAO,CAAC,KAAK,CAAA,EAAG,OAAO,CAAC,iBAAiB,GAAG,CAAA,GAAA,EAAM,OAAO,CAAC,iBAAiB,CAAA,CAAE,GAAG,EAAE,CAAA,CAAE,CAC9G;;IAEP;AACF;;;;;"}
1
+ {"version":3,"file":"device-flow.js","sources":["../../../../src/auth/device-flow.ts"],"sourcesContent":[null],"names":["getApiUrl","createCredentialStore","shouldShowUI"],"mappings":"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"}
@@ -157,13 +157,12 @@ function startCallbackServer(expectedState, timeoutMs) {
157
157
  // ---------------------------------------------------------------------------
158
158
  // Token exchange
159
159
  // ---------------------------------------------------------------------------
160
- async function exchangeCodeForTokens(apiUrl, code, codeVerifier, state) {
160
+ async function exchangeCodeForTokens(apiUrl, codeVerifier, state) {
161
161
  const response = await fetch(`${apiUrl}/v1/auth/cli/token`, {
162
162
  method: 'POST',
163
163
  headers: { 'Content-Type': 'application/json' },
164
164
  body: JSON.stringify({
165
165
  grant_type: 'authorization_code',
166
- code,
167
166
  code_verifier: codeVerifier,
168
167
  state,
169
168
  }),
@@ -174,6 +173,31 @@ async function exchangeCodeForTokens(apiUrl, code, codeVerifier, state) {
174
173
  }
175
174
  return response.json();
176
175
  }
176
+ async function requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri) {
177
+ const response = await fetch(`${apiUrl}/v1/auth/cli/authorize`, {
178
+ method: 'POST',
179
+ headers: { 'Content-Type': 'application/json' },
180
+ body: JSON.stringify({
181
+ client_id: 'doow-cli',
182
+ code_challenge: codeChallenge,
183
+ code_challenge_method: 'S256',
184
+ redirect_uri: redirectUri,
185
+ state,
186
+ }),
187
+ });
188
+ if (!response.ok) {
189
+ const body = await response.text().catch(() => '(no body)');
190
+ throw new Error(`Authorize request failed: HTTP ${response.status} — ${body}`);
191
+ }
192
+ const payload = (await response.json());
193
+ if (payload.state !== state) {
194
+ throw new Error('Authorize response state mismatch — possible server bug. Try again.');
195
+ }
196
+ if (!payload.authorization_url) {
197
+ throw new Error('Authorize response did not include authorization_url.');
198
+ }
199
+ return payload.authorization_url;
200
+ }
177
201
  // ---------------------------------------------------------------------------
178
202
  // Main flow
179
203
  // ---------------------------------------------------------------------------
@@ -197,14 +221,9 @@ async function executePkceFlow(options = {}) {
197
221
  // Step 3: Start callback server
198
222
  const { server, port, callbackPromise } = await startCallbackServer(state, timeout);
199
223
  try {
200
- // Step 4: Build authorize URL
224
+ // Step 4: Request an authorization URL from the API
201
225
  const redirectUri = `http://127.0.0.1:${port}/callback`;
202
- const authorizeUrl = `${apiUrl}/v1/auth/cli/authorize` +
203
- `?response_type=code` +
204
- `&code_challenge=${codeChallenge}` +
205
- `&code_challenge_method=S256` +
206
- `&state=${state}` +
207
- `&redirect_uri=${encodeURIComponent(redirectUri)}`;
226
+ const authorizeUrl = await requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri);
208
227
  // Step 5: Open browser
209
228
  try {
210
229
  const { default: open } = await import('open');
@@ -215,9 +234,9 @@ async function executePkceFlow(options = {}) {
215
234
  throw new Error(`Failed to open browser: ${msg}. Try doow login --device for headless environments.`);
216
235
  }
217
236
  // Step 6: Wait for callback
218
- const { code } = await callbackPromise;
237
+ await callbackPromise;
219
238
  // Step 7: Exchange code for tokens
220
- const tokenResponse = await exchangeCodeForTokens(apiUrl, code, codeVerifier, state);
239
+ const tokenResponse = await exchangeCodeForTokens(apiUrl, codeVerifier, state);
221
240
  // Step 8: Store tokens
222
241
  const expiresAt = new Date(Date.now() + tokenResponse.expires_in * 1000).toISOString();
223
242
  const result = {
@@ -1 +1 @@
1
- {"version":3,"file":"pkce.js","sources":["../../../../src/auth/pkce.ts"],"sourcesContent":[null],"names":["crypto","http","getActiveProfile","getApiUrl","createCredentialStore"],"mappings":"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"}
1
+ {"version":3,"file":"pkce.js","sources":["../../../../src/auth/pkce.ts"],"sourcesContent":[null],"names":["crypto","http","getActiveProfile","getApiUrl","createCredentialStore"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;AAcG;AAsCH;AACA;AACA;AAEA,MAAM,YAAY,GAAG,CAAA;;eAEN;AAEf,MAAM,UAAU,GAAG,CAAA;;eAEJ;AAEf;AACA;AACA;AAEA;;;;AAIG;SACa,gBAAgB,GAAA;IAC9B,MAAM,aAAa,GAAGA,iBAAM,CAAC,WAAW,CAAC,EAAE,CAAC;IAC5C,MAAM,YAAY,GAAG;SAClB,QAAQ,CAAC,QAAQ;AACjB,SAAA,OAAO,CAAC,KAAK,EAAE,GAAG;AAClB,SAAA,OAAO,CAAC,KAAK,EAAE,GAAG;AAClB,SAAA,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;AAEpB,IAAA,MAAM,cAAc,GAAGA,iBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE;IAChF,MAAM,aAAa,GAAG;SACnB,QAAQ,CAAC,QAAQ;AACjB,SAAA,OAAO,CAAC,KAAK,EAAE,GAAG;AAClB,SAAA,OAAO,CAAC,KAAK,EAAE,GAAG;AAClB,SAAA,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;AAEpB,IAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE;AACxC;AAEA;;AAEG;AACH,SAAS,aAAa,GAAA;AACpB,IAAA,OAAOA;SACJ,WAAW,CAAC,EAAE;SACd,QAAQ,CAAC,QAAQ;AACjB,SAAA,OAAO,CAAC,KAAK,EAAE,GAAG;AAClB,SAAA,OAAO,CAAC,KAAK,EAAE,GAAG;AAClB,SAAA,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;AACtB;AAWA;;;;AAIG;AACH,SAAS,mBAAmB,CAC1B,aAAqB,EACrB,SAAiB,EAAA;IAEjB,OAAO,IAAI,OAAO,CAAC,CAAC,aAAa,EAAE,YAAY,KAAI;AACjD,QAAA,MAAM,MAAM,GAAGC,eAAI,CAAC,YAAY,EAAE;QAElC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAiB,CAAC,eAAe,EAAE,cAAc,KAAI;AACtF,YAAA,IAAI,aAAwD;;;AAI5D,YAAA,aAAa,GAAG,UAAU,CAAC,MAAK;AAC9B,gBAAA,cAAc,CACZ,IAAI,KAAK,CACP,uFAAuF,CACxF,CACF;YACH,CAAC,EAAE,SAAS,CAAC;YAEb,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAI;;gBAEhC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,EAAE;AACrC,oBAAA,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC;AAClB,oBAAA,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC;oBACpB;gBACF;gBAEA,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC;gBAChD,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;gBACzC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;gBAC3C,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;;gBAGhD,IAAI,UAAU,EAAE;oBACd,YAAY,CAAC,aAAa,CAAC;oBAC3B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AACnD,oBAAA,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;oBACnB,cAAc,CAAC,IAAI,KAAK,CAAC,yBAAyB,UAAU,CAAA,CAAE,CAAC,CAAC;oBAChE;gBACF;;AAGA,gBAAA,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE;oBACnB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AACnD,oBAAA,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;oBACnB;gBACF;;AAGA,gBAAA,IAAI,KAAK,KAAK,aAAa,EAAE;oBAC3B,YAAY,CAAC,aAAa,CAAC;oBAC3B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AACnD,oBAAA,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;AACnB,oBAAA,cAAc,CAAC,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;oBAC9E;gBACF;;gBAGA,YAAY,CAAC,aAAa,CAAC;gBAC3B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AACnD,gBAAA,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;AACrB,gBAAA,eAAe,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAClC,YAAA,CAAC,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,KAAI;YACzB,YAAY,CACV,IAAI,KAAK,CACP,CAAA,uCAAA,EAA0C,GAAG,CAAC,OAAO,CAAA,oDAAA,CAAsD,CAC5G,CACF;AACH,QAAA,CAAC,CAAC;;QAGF,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,MAAK;AACjC,YAAA,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE;YAC7B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;gBACrC,MAAM,CAAC,KAAK,EAAE;AACd,gBAAA,YAAY,CACV,IAAI,KAAK,CACP,8FAA8F,CAC/F,CACF;gBACD;YACF;AACA,YAAA,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,eAAe,EAAE,CAAC;AAC7D,QAAA,CAAC,CAAC;AACJ,IAAA,CAAC,CAAC;AACJ;AAEA;AACA;AACA;AAEA,eAAe,qBAAqB,CAClC,MAAc,EACd,YAAoB,EACpB,KAAa,EAAA;IAEb,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAA,EAAG,MAAM,oBAAoB,EAAE;AAC1D,QAAA,MAAM,EAAE,MAAM;AACd,QAAA,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;AAC/C,QAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;AACnB,YAAA,UAAU,EAAE,oBAAoB;AAChC,YAAA,aAAa,EAAE,YAAY;YAC3B,KAAK;SACN,CAAC;AACH,KAAA,CAAC;AAEF,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,QAAA,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,CAAA,4BAAA,EAA+B,QAAQ,CAAC,MAAM,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,CAAC;IAC7E;AAEA,IAAA,OAAO,QAAQ,CAAC,IAAI,EAA4B;AAClD;AAEA,eAAe,uBAAuB,CACpC,MAAc,EACd,aAAqB,EACrB,KAAa,EACb,WAAmB,EAAA;IAEnB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,CAAA,EAAG,MAAM,wBAAwB,EAAE;AAC9D,QAAA,MAAM,EAAE,MAAM;AACd,QAAA,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;AAC/C,QAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;AACnB,YAAA,SAAS,EAAE,UAAU;AACrB,YAAA,cAAc,EAAE,aAAa;AAC7B,YAAA,qBAAqB,EAAE,MAAM;AAC7B,YAAA,YAAY,EAAE,WAAW;YACzB,KAAK;SACN,CAAC;AACH,KAAA,CAAC;AAEF,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,QAAA,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,CAAA,+BAAA,EAAkC,QAAQ,CAAC,MAAM,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,CAAC;IAChF;IAEA,MAAM,OAAO,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsB;AAE5D,IAAA,IAAI,OAAO,CAAC,KAAK,KAAK,KAAK,EAAE;AAC3B,QAAA,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC;IACxF;AAEA,IAAA,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;AAC9B,QAAA,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC;IAC1E;IAEA,OAAO,OAAO,CAAC,iBAAiB;AAClC;AAEA;AACA;AACA;AAEA;;;;;;AAMG;AACI,eAAe,eAAe,CAAC,UAA2B,EAAE,EAAA;;AAEjE,IAAA,MAAM,OAAO,GAAG,MAAMC,sBAAgB,EAAE;IACxC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAIC,aAAS,CAAC,OAAO,CAAC;IACnD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI;IACvD,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,KAAK,MAAMC,6BAAqB,EAAE,CAAC;AAClF,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO;;IAG1C,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,gBAAgB,EAAE;AAC1D,IAAA,MAAM,KAAK,GAAG,aAAa,EAAE;;AAG7B,IAAA,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,MAAM,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC;AAEnF,IAAA,IAAI;;AAEF,QAAA,MAAM,WAAW,GAAG,CAAA,iBAAA,EAAoB,IAAI,WAAW;AACvD,QAAA,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAChD,MAAM,EACN,aAAa,EACb,KAAK,EACL,WAAW,CACZ;;AAGD,QAAA,IAAI;YACF,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,MAAM,CAAC;AAC9C,YAAA,MAAM,IAAI,CAAC,YAAY,CAAC;QAC1B;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC;AAC5D,YAAA,MAAM,IAAI,KAAK,CACb,2BAA2B,GAAG,CAAA,oDAAA,CAAsD,CACrF;QACH;;AAGA,QAAA,MAAM,eAAe;;QAGrB,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC;;AAG9E,QAAA,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;AACtF,QAAA,MAAM,MAAM,GAAmB;YAC7B,WAAW,EAAE,aAAa,CAAC,YAAY;YACvC,YAAY,EAAE,aAAa,CAAC,aAAa;YACzC,SAAS;SACV;AAED,QAAA,MAAM,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE;YACrC,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,SAAS,EAAE,MAAM,CAAC,SAAS;AAC5B,SAAA,CAAC;AAEF,QAAA,OAAO,MAAM;IACf;YAAU;;QAER,MAAM,CAAC,KAAK,EAAE;IAChB;AACF;;;;;"}
@@ -33,7 +33,7 @@ function getApiUrl(profile) {
33
33
  return profile.apiUrl;
34
34
  if (process.env['DOOW_API_URL'])
35
35
  return process.env['DOOW_API_URL'];
36
- return 'https://api.doow.com';
36
+ return 'https://dev-api.doow.co';
37
37
  }
38
38
 
39
39
  exports.getApiUrl = getApiUrl;
@@ -1 +1 @@
1
- {"version":3,"file":"env.js","sources":["../../../../src/config/env.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA;SACgB,KAAK,GAAA;AACnB,IAAA,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;AACtC;AAEA;SACgB,IAAI,GAAA;IAClB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B;AAEA;;;;;AAKG;SACa,WAAW,GAAA;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACzC;AAEA;;;AAGG;SACa,YAAY,GAAA;IAC1B,OAAO,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE;AAC7C;AAEA;;;AAGG;AACG,SAAU,SAAS,CAAC,OAAiB,EAAA;IACzC,IAAI,OAAO,EAAE,MAAM;QAAE,OAAO,OAAO,CAAC,MAAM;AAC1C,IAAA,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAAE,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AACnE,IAAA,OAAO,sBAAsB;AAC/B;;;;;;;;"}
1
+ {"version":3,"file":"env.js","sources":["../../../../src/config/env.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA;SACgB,KAAK,GAAA;AACnB,IAAA,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;AACtC;AAEA;SACgB,IAAI,GAAA;IAClB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B;AAEA;;;;;AAKG;SACa,WAAW,GAAA;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACzC;AAEA;;;AAGG;SACa,YAAY,GAAA;IAC1B,OAAO,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE;AAC7C;AAEA;;;AAGG;AACG,SAAU,SAAS,CAAC,OAAiB,EAAA;IACzC,IAAI,OAAO,EAAE,MAAM;QAAE,OAAO,OAAO,CAAC,MAAM;AAC1C,IAAA,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAAE,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AACnE,IAAA,OAAO,yBAAyB;AAClC;;;;;;;;"}
package/dist/cjs/index.js CHANGED
@@ -11,7 +11,7 @@ var detect = require('./auth/detect.js');
11
11
 
12
12
  // @doow/cli library entry point
13
13
  // Re-exports for programmatic usage
14
- const VERSION = '0.1.0';
14
+ const VERSION = "0.1.4" ;
15
15
 
16
16
  exports.clearProfileCredentials = store.clearProfileCredentials;
17
17
  exports.deleteProfile = store.deleteProfile;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;AAAA;AACA;AAEO,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;AAAA;AACA;AAIO,MAAM,OAAO,GACuB,OAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/cli.cjs CHANGED
@@ -231,7 +231,7 @@ function getApiUrl(profile) {
231
231
  return profile.apiUrl;
232
232
  if (process.env['DOOW_API_URL'])
233
233
  return process.env['DOOW_API_URL'];
234
- return 'https://api.doow.com';
234
+ return 'https://dev-api.doow.co';
235
235
  }
236
236
 
237
237
  // ---------------------------------------------------------------------------
@@ -626,13 +626,12 @@ function startCallbackServer(expectedState, timeoutMs) {
626
626
  // ---------------------------------------------------------------------------
627
627
  // Token exchange
628
628
  // ---------------------------------------------------------------------------
629
- async function exchangeCodeForTokens(apiUrl, code, codeVerifier, state) {
629
+ async function exchangeCodeForTokens(apiUrl, codeVerifier, state) {
630
630
  const response = await fetch(`${apiUrl}/v1/auth/cli/token`, {
631
631
  method: 'POST',
632
632
  headers: { 'Content-Type': 'application/json' },
633
633
  body: JSON.stringify({
634
634
  grant_type: 'authorization_code',
635
- code,
636
635
  code_verifier: codeVerifier,
637
636
  state,
638
637
  }),
@@ -643,6 +642,31 @@ async function exchangeCodeForTokens(apiUrl, code, codeVerifier, state) {
643
642
  }
644
643
  return response.json();
645
644
  }
645
+ async function requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri) {
646
+ const response = await fetch(`${apiUrl}/v1/auth/cli/authorize`, {
647
+ method: 'POST',
648
+ headers: { 'Content-Type': 'application/json' },
649
+ body: JSON.stringify({
650
+ client_id: 'doow-cli',
651
+ code_challenge: codeChallenge,
652
+ code_challenge_method: 'S256',
653
+ redirect_uri: redirectUri,
654
+ state,
655
+ }),
656
+ });
657
+ if (!response.ok) {
658
+ const body = await response.text().catch(() => '(no body)');
659
+ throw new Error(`Authorize request failed: HTTP ${response.status} — ${body}`);
660
+ }
661
+ const payload = (await response.json());
662
+ if (payload.state !== state) {
663
+ throw new Error('Authorize response state mismatch — possible server bug. Try again.');
664
+ }
665
+ if (!payload.authorization_url) {
666
+ throw new Error('Authorize response did not include authorization_url.');
667
+ }
668
+ return payload.authorization_url;
669
+ }
646
670
  // ---------------------------------------------------------------------------
647
671
  // Main flow
648
672
  // ---------------------------------------------------------------------------
@@ -666,14 +690,9 @@ async function executePkceFlow(options = {}) {
666
690
  // Step 3: Start callback server
667
691
  const { server, port, callbackPromise } = await startCallbackServer(state, timeout);
668
692
  try {
669
- // Step 4: Build authorize URL
693
+ // Step 4: Request an authorization URL from the API
670
694
  const redirectUri = `http://127.0.0.1:${port}/callback`;
671
- const authorizeUrl = `${apiUrl}/v1/auth/cli/authorize` +
672
- `?response_type=code` +
673
- `&code_challenge=${codeChallenge}` +
674
- `&code_challenge_method=S256` +
675
- `&state=${state}` +
676
- `&redirect_uri=${encodeURIComponent(redirectUri)}`;
695
+ const authorizeUrl = await requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri);
677
696
  // Step 5: Open browser
678
697
  try {
679
698
  const { default: open } = await import('open');
@@ -684,9 +703,9 @@ async function executePkceFlow(options = {}) {
684
703
  throw new Error(`Failed to open browser: ${msg}. Try doow login --device for headless environments.`);
685
704
  }
686
705
  // Step 6: Wait for callback
687
- const { code } = await callbackPromise;
706
+ await callbackPromise;
688
707
  // Step 7: Exchange code for tokens
689
- const tokenResponse = await exchangeCodeForTokens(apiUrl, code, codeVerifier, state);
708
+ const tokenResponse = await exchangeCodeForTokens(apiUrl, codeVerifier, state);
690
709
  // Step 8: Store tokens
691
710
  const expiresAt = new Date(Date.now() + tokenResponse.expires_in * 1000).toISOString();
692
711
  const result = {
@@ -714,7 +733,7 @@ async function executePkceFlow(options = {}) {
714
733
  * environments where a browser cannot be opened on the same machine.
715
734
  *
716
735
  * Steps:
717
- * 1. POST /v1/auth/device/authorize → get device_code + user_code
736
+ * 1. POST /v1/auth/cli/device → get device_code + user_code
718
737
  * 2. Display verification URI + user_code on stderr
719
738
  * 3. Optionally open the browser (best-effort)
720
739
  * 4. Poll POST /v1/auth/device/token until granted or expired
@@ -734,6 +753,15 @@ function sleep$1(ms) {
734
753
  function expiresAtFromSecondsIn(secondsIn) {
735
754
  return new Date(Date.now() + secondsIn * 1000).toISOString();
736
755
  }
756
+ function isLegacyPendingPollResponse(status, body) {
757
+ const legacyBody = body;
758
+ return (status === 400 &&
759
+ body != null &&
760
+ typeof body === 'object' &&
761
+ legacyBody.name === 'HttpException' &&
762
+ legacyBody.message === 'Bad Request Exception' &&
763
+ legacyBody.response === 'Bad Request Exception');
764
+ }
737
765
  // ---------------------------------------------------------------------------
738
766
  // Core function
739
767
  // ---------------------------------------------------------------------------
@@ -756,7 +784,7 @@ async function executeDeviceFlow(options = {}) {
756
784
  // -------------------------------------------------------------------------
757
785
  // Step 1: Request device authorization
758
786
  // -------------------------------------------------------------------------
759
- const authorizeRes = await fetch(`${apiUrl}/v1/auth/device/authorize`, {
787
+ const authorizeRes = await fetch(`${apiUrl}/v1/auth/cli/device`, {
760
788
  method: 'POST',
761
789
  headers: { 'Content-Type': 'application/json' },
762
790
  body: JSON.stringify({ client_id: 'doow-cli' }),
@@ -766,6 +794,7 @@ async function executeDeviceFlow(options = {}) {
766
794
  throw new Error(`Device authorization request failed: HTTP ${authorizeRes.status}${body ? ` — ${body}` : ''}`);
767
795
  }
768
796
  const auth = (await authorizeRes.json());
797
+ const deviceCodeExpiresAt = Date.now() + auth.expires_in * 1000;
769
798
  // -------------------------------------------------------------------------
770
799
  // Step 2: Display instructions on stderr
771
800
  // -------------------------------------------------------------------------
@@ -785,6 +814,9 @@ async function executeDeviceFlow(options = {}) {
785
814
  let pollInterval = auth.interval; // seconds; RFC 8628 §3.5
786
815
  while (true) {
787
816
  await sleep$1(pollInterval * 1000);
817
+ if (Date.now() > deviceCodeExpiresAt) {
818
+ throw new Error('Device code expired. Run doow login --device again.');
819
+ }
788
820
  const tokenRes = await fetch(`${apiUrl}/v1/auth/device/token`, {
789
821
  method: 'POST',
790
822
  headers: { 'Content-Type': 'application/json' },
@@ -829,6 +861,9 @@ async function executeDeviceFlow(options = {}) {
829
861
  case 'access_denied':
830
862
  throw new Error('Authorization denied by user.');
831
863
  default:
864
+ if (isLegacyPendingPollResponse(tokenRes.status, errBody)) {
865
+ continue;
866
+ }
832
867
  throw new Error(`Token polling failed: ${errBody.error}${errBody.error_description ? ` — ${errBody.error_description}` : ''}`);
833
868
  }
834
869
  }
@@ -9137,29 +9172,45 @@ async function checkNetwork(apiUrl) {
9137
9172
  }
9138
9173
  }
9139
9174
  async function checkApiVersion(apiUrl) {
9175
+ const healthPaths = ['/health', '/v1/health'];
9140
9176
  try {
9141
9177
  const controller = new AbortController();
9142
9178
  const timeoutId = setTimeout(() => controller.abort(), 5000);
9143
- const res = await fetch(`${apiUrl}/v1/health`, { signal: controller.signal });
9144
- clearTimeout(timeoutId);
9145
- if (!res.ok) {
9146
- return { name: 'api_version', status: 'warn', detail: `HTTP ${res.status} from /v1/health` };
9147
- }
9148
- let version;
9149
- try {
9150
- const body = await res.json();
9151
- if (typeof body['version'] === 'string')
9152
- version = body['version'];
9153
- else if (typeof body['server_version'] === 'string')
9154
- version = body['server_version'];
9155
- }
9156
- catch {
9157
- // non-JSON body is acceptable
9179
+ let lastPath = healthPaths[0];
9180
+ let lastStatus;
9181
+ for (const path of healthPaths) {
9182
+ lastPath = path;
9183
+ const res = await fetch(`${apiUrl}${path}`, { signal: controller.signal });
9184
+ if (res.ok) {
9185
+ clearTimeout(timeoutId);
9186
+ let version;
9187
+ try {
9188
+ const body = await res.json();
9189
+ if (typeof body['version'] === 'string')
9190
+ version = body['version'];
9191
+ else if (typeof body['server_version'] === 'string')
9192
+ version = body['server_version'];
9193
+ }
9194
+ catch {
9195
+ // non-JSON body is acceptable
9196
+ }
9197
+ return {
9198
+ name: 'api_version',
9199
+ status: 'pass',
9200
+ detail: version ? `server ${version}` : 'reachable (no version in response)',
9201
+ };
9202
+ }
9203
+ lastStatus = res.status;
9204
+ if (res.status !== 404 && res.status !== 410) {
9205
+ clearTimeout(timeoutId);
9206
+ return { name: 'api_version', status: 'warn', detail: `HTTP ${res.status} from ${path}` };
9207
+ }
9158
9208
  }
9209
+ clearTimeout(timeoutId);
9159
9210
  return {
9160
9211
  name: 'api_version',
9161
- status: 'pass',
9162
- detail: version ? `server ${version}` : 'reachable (no version in response)',
9212
+ status: 'warn',
9213
+ detail: `HTTP ${lastStatus ?? 404} from ${lastPath}`,
9163
9214
  };
9164
9215
  }
9165
9216
  catch (err) {
@@ -33863,7 +33914,7 @@ async function startStdioServer(options) {
33863
33914
  await server.connect(transport);
33864
33915
  }
33865
33916
 
33866
- const VERSION = "0.1.1" ;
33917
+ const VERSION = "0.1.4" ;
33867
33918
  const ASCII_LOGO = `
33868
33919
  _
33869
33920
  __| | ___ ___ __ __
@@ -33880,6 +33931,10 @@ function printLogo() {
33880
33931
  process.stdout.write(' Not logged in.\n\n');
33881
33932
  process.stdout.write(' Run \x1b[36mdoow login\x1b[0m to get started.\n\n');
33882
33933
  }
33934
+ function readString(data, key) {
33935
+ const value = data[key];
33936
+ return typeof value === 'string' ? value : undefined;
33937
+ }
33883
33938
  // ---------------------------------------------------------------------------
33884
33939
  // loginHandler — exported for testability
33885
33940
  // ---------------------------------------------------------------------------
@@ -33989,14 +34044,28 @@ async function whoamiHandler(globalOpts, credentialStore) {
33989
34044
  process.exit(1);
33990
34045
  }
33991
34046
  const data = (await res.json());
33992
- const email = data['email'] ?? '(unknown)';
33993
- const org = data['organization'] ?? '(unknown)';
34047
+ const email = readString(data, 'email') ?? '(unknown)';
34048
+ const organizationId = readString(data, 'organization_id');
34049
+ const org = readString(data, 'organization') ?? organizationId ?? '(unknown)';
34050
+ const role = readString(data, 'role');
34051
+ const capabilities = Array.isArray(data['capabilities'])
34052
+ ? data['capabilities'].filter((value) => typeof value === 'string')
34053
+ : undefined;
33994
34054
  if (isJson) {
33995
- process.stdout.write(JSON.stringify({ email, organization: org, profile: profileName }) + '\n');
34055
+ process.stdout.write(JSON.stringify({
34056
+ email,
34057
+ organization: org,
34058
+ organizationId,
34059
+ role,
34060
+ capabilities,
34061
+ profile: profileName,
34062
+ }) + '\n');
33996
34063
  }
33997
34064
  else {
33998
34065
  process.stderr.write(`Logged in as ${email}\n`);
33999
34066
  process.stderr.write(`Organization: ${org}\n`);
34067
+ if (role)
34068
+ process.stderr.write(`Role: ${role}\n`);
34000
34069
  process.stderr.write(`Auth: ${resolved.source}\n`);
34001
34070
  process.stderr.write(`Profile: ${profileName}\n`);
34002
34071
  }