@clawapps/cli 0.3.0 → 0.5.0

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
@@ -1,10 +1,9 @@
1
1
  # @clawapps/cli
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/@clawapps/cli.svg)](https://www.npmjs.com/package/@clawapps/cli)
3
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
5
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)](https://nodejs.org/)
5
6
 
6
- **[中文文档](README_zh.md)**
7
-
8
7
  A command-line tool for authenticating with the [ClawApps](https://www.clawapps.ai) platform. Sign in via Google or Apple directly from your terminal — tokens are stored locally for use by AI agents and scripts.
9
8
 
10
9
  ## Install
@@ -13,31 +12,24 @@ A command-line tool for authenticating with the [ClawApps](https://www.clawapps.
13
12
  npm install -g @clawapps/cli
14
13
  ```
15
14
 
16
- > **Not yet on npm?** Install from source:
17
- > ```bash
18
- > git clone git@github.com:ClawApps/clawapps-cli.git
19
- > cd clawapps-cli && npm install && npm run build && npm link
20
- > ```
21
-
22
15
  ## Commands
23
16
 
24
- ### `claw login`
17
+ ### `clawapps login`
25
18
 
26
- Sign in with Google or Apple. Opens a browser for OAuth, then stores tokens locally.
19
+ Sign in with Google or Apple. Opens a browser for OAuth, then stores tokens locally. If already logged in, auto-refreshes the token and extends the session.
27
20
 
28
21
  ```bash
29
- $ claw login
30
- ? Choose login method: Google
31
- Opening browser for Google login...
22
+ $ clawapps login
23
+ Opening browser for login...
32
24
  ✔ Logged in as user@gmail.com
33
25
  ```
34
26
 
35
- ### `claw whoami`
27
+ ### `clawapps whoami`
36
28
 
37
29
  Show current account info. Auto-refreshes expired tokens.
38
30
 
39
31
  ```bash
40
- $ claw whoami
32
+ $ clawapps whoami
41
33
  ClawApps Account
42
34
  ──────────────────────────────
43
35
  Name: Username
@@ -46,30 +38,79 @@ ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
46
38
  Provider: google
47
39
  ```
48
40
 
49
- ### `claw logout`
41
+ ### `clawapps token`
42
+
43
+ Print current valid access token. Auto-refreshes if expired. Designed for scripting.
44
+
45
+ ```bash
46
+ $ clawapps token
47
+ eyJhbGciOiJIUzI1NiIs...
48
+ ```
49
+
50
+ Use in scripts:
51
+
52
+ ```bash
53
+ curl -H "Authorization: Bearer $(clawapps token)" https://api.clawapps.ai/api/v1/...
54
+ ```
55
+
56
+ ### `clawapps credit`
57
+
58
+ Open credit recharge page in browser.
59
+
60
+ ```bash
61
+ $ clawapps credit
62
+ Opening credit recharge page...
63
+ Page opened in your browser.
64
+ ```
65
+
66
+ ### `clawapps membership`
67
+
68
+ Open membership subscription page in browser.
69
+
70
+ ```bash
71
+ $ clawapps membership
72
+ Opening membership subscription page...
73
+ Page opened in your browser.
74
+ ```
75
+
76
+ ### `clawapps payment-grant <skill_id>`
77
+
78
+ Open payment grant page for a skill. Starts a local callback server to receive the payment token after authorization.
79
+
80
+ ```bash
81
+ $ clawapps payment-grant c0ff42a9-2b54-48b3-b570-cb16be363ad6
82
+ Opening payment grant page...
83
+ Waiting for payment confirmation...
84
+
85
+ Payment grant confirmed!
86
+ Payment Token: 8d6d2e514eb241559a4dfcb3176ce3a4
87
+ Auto Payment: disabled
88
+ ```
89
+
90
+ ### `clawapps logout`
50
91
 
51
92
  Sign out and clear local credentials.
52
93
 
53
94
  ```bash
54
- $ claw logout
95
+ $ clawapps logout
55
96
  Logged out successfully.
56
97
  ```
57
98
 
58
99
  ## How It Works
59
100
 
60
101
  ```
61
- claw login
62
- → Choose Google or Apple
102
+ clawapps login
63
103
  → Local HTTP server starts on localhost (random port)
64
- → Browser opens for OAuth
65
- → Callback returns token to local server
66
- → Token exchange: Google/Apple → OpenDigits → ClawApps
104
+ → Browser opens for OAuth (Google or Apple)
105
+ → Callback returns tokens to local server
67
106
  → Credentials saved to ~/.clawapps/credentials.json (0600)
68
- ```
69
-
70
- **Google flow**: Implicit OAuth → local callback page extracts token from URL hash → POST to local server → exchange for ClawApps tokens.
71
107
 
72
- **Apple flow**: OpenDigits handles Apple OAuth → redirects to local callback with tokens in query params → exchange for ClawApps tokens.
108
+ clawapps token
109
+ → Load local credentials
110
+ → Validate access token via API
111
+ → If expired, auto-refresh using refresh token
112
+ → Output valid access token to stdout
113
+ ```
73
114
 
74
115
  ## Credentials
75
116
 
@@ -80,41 +121,42 @@ Tokens are stored at `~/.clawapps/credentials.json` with file permissions `0600`
80
121
  "provider": "google",
81
122
  "access_token": "eyJ...",
82
123
  "refresh_token": "eyJ...",
83
- "logged_in_at": "2026-02-24T11:11:35.871Z"
124
+ "logged_in_at": "2026-03-12T11:00:00.000Z"
84
125
  }
85
126
  ```
86
127
 
87
- Use in scripts:
88
-
89
- ```bash
90
- TOKEN=$(cat ~/.clawapps/credentials.json | jq -r .access_token)
91
- curl -H "Authorization: Bearer $TOKEN" https://api.clawapps.ai/api/v1/...
92
- ```
93
-
94
128
  ## Project Structure
95
129
 
96
130
  ```
97
131
  clawapps-cli/
98
- ├── bin/claw.js # Entry point
132
+ ├── bin/claw.js # Entry point
99
133
  ├── src/
100
- │ ├── index.ts # Commander setup
134
+ │ ├── index.ts # Commander setup
101
135
  │ ├── commands/
102
- │ │ ├── login.ts # OAuth flow orchestration
103
- │ │ ├── logout.ts # Clear credentials
104
- │ │ └── whoami.ts # User info with auto-refresh
136
+ │ │ ├── login.ts # OAuth flow with auto-refresh
137
+ │ │ ├── logout.ts # Clear credentials
138
+ │ │ ├── whoami.ts # User info with auto-refresh
139
+ │ │ ├── token.ts # Print valid access token
140
+ │ │ ├── credit.ts # Open credit page
141
+ │ │ ├── membership.ts # Open membership page
142
+ │ │ ├── payment-grant.ts # Payment authorization flow
143
+ │ │ └── helpers/
144
+ │ │ └── ensure-token.ts # Token validation & refresh
105
145
  │ ├── auth/
106
- │ │ ├── server.ts # Local HTTP callback server
107
- │ │ ├── google.ts # Google OAuth URL builder
108
- │ │ ├── apple.ts # Apple OAuth URL builder (via OD)
109
- │ │ └── exchange.ts # Token exchange (OD → ClawApps)
146
+ │ │ ├── login-server.ts # Login callback server
147
+ │ │ ├── payment-server.ts # Payment callback server
148
+ │ │ ├── server.ts # Google OAuth callback server
149
+ │ │ ├── google.ts # Google OAuth URL builder
150
+ │ │ ├── apple.ts # Apple OAuth URL builder
151
+ │ │ └── exchange.ts # Token exchange
110
152
  │ ├── lib/
111
- │ │ ├── config.ts # API endpoints & constants
112
- │ │ ├── credentials.ts # Read/write ~/.clawapps/credentials.json
113
- │ │ ├── api.ts # HTTP request helpers
114
- │ │ └── types.ts # TypeScript interfaces
153
+ │ │ ├── config.ts # API endpoints & constants
154
+ │ │ ├── credentials.ts # Read/write credentials
155
+ │ │ ├── api.ts # HTTP request helpers
156
+ │ │ └── types.ts # TypeScript interfaces
115
157
  │ └── html/
116
- │ ├── callback.ts # OAuth callback HTML templates
117
- │ └── logo-data.ts # Logo (base64 embedded)
158
+ │ ├── callback.ts # OAuth callback HTML templates
159
+ │ └── logo-data.ts # Logo (base64 embedded)
118
160
  ├── package.json
119
161
  └── tsconfig.json
120
162
  ```
@@ -0,0 +1,32 @@
1
+ export interface CreateLoginCodeResult {
2
+ code: string;
3
+ expires_at: string;
4
+ qr_url: string;
5
+ }
6
+ export interface CreatePaymentCodeResult {
7
+ code: string;
8
+ type: string;
9
+ skill_id: string;
10
+ expires_at: string;
11
+ qr_url: string;
12
+ }
13
+ /**
14
+ * Call POST /agent/create-login-code to create a login code on the server.
15
+ * No authentication required.
16
+ */
17
+ export declare function createLoginCode(): Promise<CreateLoginCodeResult>;
18
+ /**
19
+ * Call POST /agent/create-payment-code to create a payment code on the server.
20
+ * Requires authentication (Bearer token).
21
+ */
22
+ export declare function createPaymentCode(token: string, skillId: string, type?: string): Promise<CreatePaymentCodeResult>;
23
+ /**
24
+ * Display a QR code in the terminal.
25
+ */
26
+ export declare function displayQRCode(url: string): void;
27
+ /**
28
+ * Poll the agent auth-code verification API.
29
+ * Resolves with the response data when the code is verified.
30
+ * Rejects on timeout or error.
31
+ */
32
+ export declare function pollAuthCode<T>(code: string, type: 'login' | 'payment', timeoutMs?: number): Promise<T>;
@@ -0,0 +1,72 @@
1
+ import qrcode from 'qrcode-terminal';
2
+ import { CONFIG } from '../lib/config.js';
3
+ /**
4
+ * Call POST /agent/create-login-code to create a login code on the server.
5
+ * No authentication required.
6
+ */
7
+ export async function createLoginCode() {
8
+ const res = await fetch(CONFIG.AGENT_CREATE_LOGIN_CODE, { method: 'POST' });
9
+ const json = await res.json();
10
+ if (json.code === 'OK' && json.data?.code === 0 && json.data.data) {
11
+ return json.data.data;
12
+ }
13
+ throw new Error(json.data?.message || 'Failed to create login code');
14
+ }
15
+ /**
16
+ * Call POST /agent/create-payment-code to create a payment code on the server.
17
+ * Requires authentication (Bearer token).
18
+ */
19
+ export async function createPaymentCode(token, skillId, type = 'one_time') {
20
+ const url = `${CONFIG.AGENT_CREATE_PAYMENT_CODE}?skill_id=${encodeURIComponent(skillId)}&type=${encodeURIComponent(type)}`;
21
+ const res = await fetch(url, {
22
+ method: 'POST',
23
+ headers: { 'Authorization': `Bearer ${token}` },
24
+ });
25
+ const json = await res.json();
26
+ if (json.code === 'OK' && json.data?.code === 0 && json.data.data) {
27
+ return json.data.data;
28
+ }
29
+ throw new Error(json.data?.message || 'Failed to create payment code');
30
+ }
31
+ /**
32
+ * Display a QR code in the terminal.
33
+ */
34
+ export function displayQRCode(url) {
35
+ qrcode.generate(url, { small: true });
36
+ }
37
+ /**
38
+ * Poll the agent auth-code verification API.
39
+ * Resolves with the response data when the code is verified.
40
+ * Rejects on timeout or error.
41
+ */
42
+ export function pollAuthCode(code, type, timeoutMs = CONFIG.AUTH_TIMEOUT_MS) {
43
+ return new Promise((resolve, reject) => {
44
+ const url = `${CONFIG.AGENT_AUTH_CODE}?code=${encodeURIComponent(code)}&type=${type}`;
45
+ const startTime = Date.now();
46
+ async function poll() {
47
+ if (Date.now() - startTime >= timeoutMs) {
48
+ reject(new Error('Verification timed out. Please try again.'));
49
+ return;
50
+ }
51
+ try {
52
+ const res = await fetch(url);
53
+ const json = await res.json();
54
+ // Outer envelope: code "OK", then check inner code
55
+ if (json.code === 'OK' && json.data) {
56
+ if (json.data.code === 0 && json.data.data) {
57
+ resolve(json.data.data);
58
+ return;
59
+ }
60
+ // Inner code non-zero (e.g. 4007 "Code not found"), keep polling
61
+ }
62
+ // Other responses, keep polling
63
+ }
64
+ catch {
65
+ // Network error, keep polling
66
+ }
67
+ setTimeout(poll, CONFIG.AUTH_POLL_INTERVAL_MS);
68
+ }
69
+ poll();
70
+ });
71
+ }
72
+ //# sourceMappingURL=qr-poll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qr-poll.js","sourceRoot":"","sources":["../../src/auth/qr-poll.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,10 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
- import open from 'open';
4
3
  import { loadCredentials, saveCredentials } from '../lib/credentials.js';
5
4
  import { apiGet } from '../lib/api.js';
6
5
  import { CONFIG } from '../lib/config.js';
7
- import { startLoginCallbackServer } from '../auth/login-server.js';
8
6
  import { ensureValidToken } from './helpers/ensure-token.js';
7
+ import { createLoginCode, displayQRCode, pollAuthCode } from '../auth/qr-poll.js';
9
8
  export async function loginCommand() {
10
9
  // Check if already logged in, refresh token if needed
11
10
  const existing = await loadCredentials();
@@ -23,54 +22,52 @@ export async function loginCommand() {
23
22
  }
24
23
  }
25
24
  catch {
26
- // Token validation/refresh failed, continue with browser login
25
+ // Token validation/refresh failed, continue with login
27
26
  }
28
27
  }
29
- // Start local callback server to receive tokens from web
30
- const { port, result, close } = await startLoginCallbackServer();
31
- const callbackUrl = `http://localhost:${port}/callback`;
32
- // Open web login page with callback
33
- const loginUrl = `${CONFIG.CLAW_WEB_BASE}/login?callback=${encodeURIComponent(callbackUrl)}`;
34
- console.log(chalk.gray('\nOpening browser for login...'));
35
- console.log(chalk.gray(`If the browser doesn't open, visit:\n${loginUrl}\n`));
28
+ // Create login code via API and display QR code
29
+ let loginCode;
36
30
  try {
37
- await open(loginUrl);
31
+ loginCode = await createLoginCode();
38
32
  }
39
- catch {
40
- console.log(chalk.yellow('Could not open browser automatically.'));
41
- console.log(chalk.yellow('Please open the URL above manually.'));
33
+ catch (err) {
34
+ const message = err instanceof Error ? err.message : 'Unknown error';
35
+ console.error(chalk.red(`\nFailed to create login code: ${message}`));
36
+ process.exit(1);
42
37
  }
38
+ console.log(chalk.gray('\nScan the QR code to login:\n'));
39
+ displayQRCode(loginCode.qr_url);
40
+ console.log(chalk.gray(`\nOr visit: ${loginCode.qr_url}\n`));
41
+ console.log(chalk.yellow('Waiting for QR code verification (valid for 3 minutes)...\n'));
43
42
  const spinner = ora('Waiting for authentication...').start();
44
43
  try {
45
- const tokens = await result;
44
+ const result = await pollAuthCode(loginCode.code, 'login');
46
45
  // Save credentials
47
46
  await saveCredentials({
48
47
  provider: 'google', // web login handles provider selection
49
- access_token: tokens.access_token,
50
- refresh_token: tokens.refresh_token,
48
+ access_token: result.access_token,
49
+ refresh_token: result.refresh_token,
51
50
  logged_in_at: new Date().toISOString(),
52
51
  });
53
52
  spinner.text = 'Fetching user info...';
54
- const userRes = await apiGet(CONFIG.CLAW_ME, tokens.access_token);
53
+ const userRes = await apiGet(CONFIG.CLAW_ME, result.access_token);
55
54
  spinner.stop();
55
+ console.log(chalk.green('\nLogin successful!'));
56
+ console.log(chalk.gray(`Access Token: ${result.access_token}`));
56
57
  if (userRes.ok) {
57
58
  const user = userRes.data.data;
58
59
  const name = user.name || user.email || 'user';
59
- console.log(chalk.green(`\nLogged in as ${chalk.bold(name)}`));
60
+ console.log(chalk.gray(`User: ${name}`));
60
61
  if (user.email) {
61
62
  console.log(chalk.gray(`Email: ${user.email}`));
62
63
  }
63
64
  }
64
- else {
65
- console.log(chalk.green('\nLogin successful!'));
66
- console.log(chalk.gray('Run `clawapps whoami` to see your account info.'));
67
- }
68
65
  }
69
66
  catch (err) {
70
67
  spinner.stop();
71
- close();
72
68
  const message = err instanceof Error ? err.message : 'Unknown error';
73
69
  console.error(chalk.red(`\nLogin failed: ${message}`));
70
+ console.error(chalk.yellow('QR code has expired. Please run `clawapps login` to generate a new one.'));
74
71
  process.exit(1);
75
72
  }
76
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,MAAM,EAAwB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlF,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,sDAAsD;IACtD,MAAM,QAAQ,GAAG,MAAM,eAAe,EAAE,CAAC;IACzC,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YACnD,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,MAAM,MAAM,CAA4B,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;gBAC5F,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;oBACX,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;oBAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wBAAwB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;oBACnG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC,CAAC;oBAC9F,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,IAAI,SAAS,CAAC;IACd,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,eAAe,EAAE,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,kCAAkC,OAAO,EAAE,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAC1D,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,6DAA6D,CAAC,CAAC,CAAC;IAEzF,MAAM,OAAO,GAAG,GAAG,CAAC,+BAA+B,CAAC,CAAC,KAAK,EAAE,CAAC;IAE7D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAsB,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEhF,mBAAmB;QACnB,MAAM,eAAe,CAAC;YACpB,QAAQ,EAAE,QAAQ,EAAE,uCAAuC;YAC3D,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,GAAG,uBAAuB,CAAC;QAEvC,MAAM,OAAO,GAAG,MAAM,MAAM,CAA4B,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;QAE7F,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAEhE,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,yEAAyE,CAAC,CAAC,CAAC;QACvG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -1,10 +1,8 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
- import open from 'open';
4
3
  import { loadCredentials } from '../lib/credentials.js';
5
- import { CONFIG } from '../lib/config.js';
6
4
  import { ensureValidToken } from './helpers/ensure-token.js';
7
- import { startPaymentCallbackServer } from '../auth/payment-server.js';
5
+ import { createPaymentCode, displayQRCode, pollAuthCode } from '../auth/qr-poll.js';
8
6
  export async function paymentGrantCommand(skillId) {
9
7
  const credentials = await loadCredentials();
10
8
  if (!credentials) {
@@ -16,34 +14,42 @@ export async function paymentGrantCommand(skillId) {
16
14
  console.log(chalk.red('Session expired. Please run `clawapps login` again.'));
17
15
  process.exit(1);
18
16
  }
19
- // Start local callback server to receive payment token
20
- const { port, result, close } = await startPaymentCallbackServer();
21
- const callbackUrl = `http://localhost:${port}/callback`;
22
- const url = `${CONFIG.CLAW_WEB_BASE}/payment-grant?skill_id=${encodeURIComponent(skillId)}&token=${encodeURIComponent(validated.access_token)}&callback=${encodeURIComponent(callbackUrl)}`;
23
- console.log(chalk.gray('\nOpening payment grant page...'));
24
- console.log(chalk.gray(`If the browser doesn't open, visit:\n${url}\n`));
17
+ // Create payment code via API and display QR code
18
+ let paymentCode;
25
19
  try {
26
- await open(url);
20
+ paymentCode = await createPaymentCode(validated.access_token, skillId);
27
21
  }
28
- catch {
29
- console.log(chalk.yellow('Could not open browser automatically.'));
30
- console.log(chalk.yellow('Please open the URL above manually.'));
22
+ catch (err) {
23
+ const message = err instanceof Error ? err.message : 'Unknown error';
24
+ console.error(chalk.red(`\nFailed to create payment code: ${message}`));
25
+ process.exit(1);
31
26
  }
27
+ console.log(chalk.gray('\nScan the QR code to authorize payment:\n'));
28
+ displayQRCode(paymentCode.qr_url);
29
+ console.log(chalk.gray(`\nOr visit: ${paymentCode.qr_url}\n`));
30
+ console.log(chalk.yellow('Waiting for QR code verification (valid for 3 minutes)...\n'));
32
31
  const spinner = ora('Waiting for payment confirmation...').start();
33
32
  try {
34
- const payment = await result;
33
+ const result = await pollAuthCode(paymentCode.code, 'payment');
35
34
  spinner.stop();
36
- console.log(chalk.green('\nPayment grant confirmed!'));
37
- if (payment.payment_token) {
38
- console.log(chalk.gray(`Payment Token: ${payment.payment_token}`));
35
+ if (result.one_time_pay_token) {
36
+ console.log(chalk.green('\nPayment grant confirmed!'));
37
+ console.log(chalk.gray(`Payment Token: ${result.one_time_pay_token}`));
38
+ console.log(chalk.gray(`Auto Payment: ${result.auto_pay_enabled ? 'enabled' : 'disabled'}`));
39
+ }
40
+ else if (result.auto_pay_enabled) {
41
+ console.log(chalk.green('\nAuto-pay is enabled, proceeding...'));
42
+ }
43
+ else {
44
+ console.error(chalk.red('\nPayment grant failed: no payment token received.'));
45
+ process.exit(1);
39
46
  }
40
- console.log(chalk.gray(`Auto Payment: ${payment.auto_payment ? 'enabled' : 'disabled'}`));
41
47
  }
42
48
  catch (err) {
43
49
  spinner.stop();
44
- close();
45
50
  const message = err instanceof Error ? err.message : 'Unknown error';
46
51
  console.error(chalk.red(`\nPayment grant failed: ${message}`));
52
+ console.error(chalk.yellow('QR code has expired. Please run `clawapps payment-grant <skill_id>` to generate a new one.'));
47
53
  process.exit(1);
48
54
  }
49
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"payment-grant.js","sourceRoot":"","sources":["../../src/commands/payment-grant.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"payment-grant.js","sourceRoot":"","sources":["../../src/commands/payment-grant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGpF,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe;IACvD,MAAM,WAAW,GAAG,MAAM,eAAe,EAAE,CAAC;IAE5C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,4CAA4C,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACtD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,kDAAkD;IAClD,IAAI,WAAW,CAAC;IAChB,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACzE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC,CAAC;IACtE,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,WAAW,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,6DAA6D,CAAC,CAAC,CAAC;IAEzF,MAAM,OAAO,GAAG,GAAG,CAAC,qCAAqC,CAAC,CAAC,KAAK,EAAE,CAAC;IAEnE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAwB,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAEtF,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC/F,CAAC;aAAM,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;YAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACrE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,2BAA2B,OAAO,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,4FAA4F,CAAC,CAAC,CAAC;QAC1H,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function rechargeCreditsCommand(): Promise<void>;
@@ -0,0 +1,10 @@
1
+ import chalk from 'chalk';
2
+ import { CONFIG } from '../lib/config.js';
3
+ import { displayQRCode } from '../auth/qr-poll.js';
4
+ export async function rechargeCreditsCommand() {
5
+ const url = `${CONFIG.CLAW_WEB_BASE}/credit`;
6
+ console.log(chalk.yellow('\nInsufficient credits. Please scan the QR code to recharge.\n'));
7
+ displayQRCode(url);
8
+ console.log(chalk.gray(`\nOr visit: ${url}\n`));
9
+ }
10
+ //# sourceMappingURL=recharge-credits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recharge-credits.js","sourceRoot":"","sources":["../../src/commands/recharge-credits.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,aAAa,SAAS,CAAC;IAE7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gEAAgE,CAAC,CAAC,CAAC;IAC5F,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function subscribeCommand(): Promise<void>;
@@ -0,0 +1,10 @@
1
+ import chalk from 'chalk';
2
+ import { CONFIG } from '../lib/config.js';
3
+ import { displayQRCode } from '../auth/qr-poll.js';
4
+ export async function subscribeCommand() {
5
+ const url = `${CONFIG.CLAW_WEB_BASE}/membership`;
6
+ console.log(chalk.yellow('\nScan the QR code to subscribe membership.\n'));
7
+ displayQRCode(url);
8
+ console.log(chalk.gray(`\nOr visit: ${url}\n`));
9
+ }
10
+ //# sourceMappingURL=subscribe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribe.js","sourceRoot":"","sources":["../../src/commands/subscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,aAAa,aAAa,CAAC;IAEjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,+CAA+C,CAAC,CAAC,CAAC;IAC3E,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC"}
package/dist/index.js CHANGED
@@ -2,18 +2,18 @@ import { Command } from 'commander';
2
2
  import { loginCommand } from './commands/login.js';
3
3
  import { logoutCommand } from './commands/logout.js';
4
4
  import { whoamiCommand } from './commands/whoami.js';
5
- import { creditCommand } from './commands/credit.js';
6
- import { membershipCommand } from './commands/membership.js';
7
5
  import { tokenCommand } from './commands/token.js';
8
6
  import { paymentGrantCommand } from './commands/payment-grant.js';
7
+ import { rechargeCreditsCommand } from './commands/recharge-credits.js';
8
+ import { subscribeCommand } from './commands/subscribe.js';
9
9
  const program = new Command();
10
10
  program
11
11
  .name('clawapps')
12
- .description('ClawApps CLI - Manage your ClawApps account')
13
- .version('0.3.0');
12
+ .description('ClawApps CLI - Authenticate, manage payments, and recharge credits via QR code')
13
+ .version('0.5.0');
14
14
  program
15
15
  .command('login')
16
- .description('Log in to your ClawApps account via Google or Apple')
16
+ .description('Log in via QR code (scan to authenticate, valid for 3 minutes)')
17
17
  .action(loginCommand);
18
18
  program
19
19
  .command('logout')
@@ -23,22 +23,22 @@ program
23
23
  .command('whoami')
24
24
  .description('Show your ClawApps account info')
25
25
  .action(whoamiCommand);
26
- program
27
- .command('credit')
28
- .description('Open credit recharge page in browser')
29
- .action(creditCommand);
30
- program
31
- .command('membership')
32
- .description('Open membership subscription page in browser')
33
- .action(membershipCommand);
34
26
  program
35
27
  .command('token')
36
- .description('Print current valid access token (refreshes if needed)')
28
+ .description('Print valid access token (auto-refreshes if expired)')
37
29
  .action(tokenCommand);
38
30
  program
39
31
  .command('payment-grant')
40
- .description('Open payment grant page for a skill')
32
+ .description('Authorize skill payment via QR code (valid for 3 minutes)')
41
33
  .argument('<skill_id>', 'The skill ID to grant payment for')
42
34
  .action(paymentGrantCommand);
35
+ program
36
+ .command('recharge-credits')
37
+ .description('Display QR code to recharge credits')
38
+ .action(rechargeCreditsCommand);
39
+ program
40
+ .command('subscribe')
41
+ .description('Display QR code to subscribe membership')
42
+ .action(subscribeCommand);
43
43
  program.parse();
44
44
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,6CAA6C,CAAC;KAC1D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,qDAAqD,CAAC;KAClE,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,iCAAiC,CAAC;KAC9C,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,YAAY,CAAC;KACrB,WAAW,CAAC,8CAA8C,CAAC;KAC3D,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAE7B,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,qCAAqC,CAAC;KAClD,QAAQ,CAAC,YAAY,EAAE,mCAAmC,CAAC;KAC3D,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAE/B,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,gFAAgF,CAAC;KAC7F,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,iCAAiC,CAAC;KAC9C,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,sDAAsD,CAAC;KACnE,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,eAAe,CAAC;KACxB,WAAW,CAAC,2DAA2D,CAAC;KACxE,QAAQ,CAAC,YAAY,EAAE,mCAAmC,CAAC;KAC3D,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAE/B,OAAO;KACJ,OAAO,CAAC,kBAAkB,CAAC;KAC3B,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAElC,OAAO;KACJ,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAE5B,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -8,7 +8,11 @@ export declare const CONFIG: {
8
8
  readonly CLAW_ME: "https://api.clawapps.ai/api/v1/auth/me";
9
9
  readonly CLAW_REFRESH: "https://api.clawapps.ai/api/v1/auth/refresh";
10
10
  readonly CLAW_LOGOUT: "https://api.clawapps.ai/api/v1/auth/logout";
11
- readonly CLAW_WEB_BASE: "https://www.clawapps.ai";
11
+ readonly CLAW_WEB_BASE: "https://clawapps.ai";
12
+ readonly AGENT_CREATE_LOGIN_CODE: "https://api.clawapps.ai/api/v1/agent/create-login-code";
13
+ readonly AGENT_CREATE_PAYMENT_CODE: "https://api.clawapps.ai/api/v1/agent/create-payment-code";
14
+ readonly AGENT_AUTH_CODE: "https://api.clawapps.ai/api/v1/agent/auth-code";
15
+ readonly AUTH_POLL_INTERVAL_MS: number;
12
16
  readonly AUTH_TIMEOUT_MS: number;
13
17
  readonly CREDENTIALS_DIR: ".clawapps";
14
18
  readonly CREDENTIALS_FILE: "credentials.json";
@@ -11,9 +11,14 @@ export const CONFIG = {
11
11
  CLAW_REFRESH: 'https://api.clawapps.ai/api/v1/auth/refresh',
12
12
  CLAW_LOGOUT: 'https://api.clawapps.ai/api/v1/auth/logout',
13
13
  // Web
14
- CLAW_WEB_BASE: 'https://www.clawapps.ai',
14
+ CLAW_WEB_BASE: 'https://clawapps.ai',
15
+ // Agent code endpoints
16
+ AGENT_CREATE_LOGIN_CODE: 'https://api.clawapps.ai/api/v1/agent/create-login-code',
17
+ AGENT_CREATE_PAYMENT_CODE: 'https://api.clawapps.ai/api/v1/agent/create-payment-code',
18
+ AGENT_AUTH_CODE: 'https://api.clawapps.ai/api/v1/agent/auth-code',
19
+ AUTH_POLL_INTERVAL_MS: 3 * 1000, // 3 seconds
15
20
  // Timeouts
16
- AUTH_TIMEOUT_MS: 2 * 60 * 1000, // 2 minutes
21
+ AUTH_TIMEOUT_MS: 3 * 60 * 1000, // 3 minutes
17
22
  // Credentials
18
23
  CREDENTIALS_DIR: '.clawapps',
19
24
  CREDENTIALS_FILE: 'credentials.json',
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,gBAAgB,EAAE,yEAAyE;IAE3F,WAAW,EAAE,kCAAkC;IAC/C,aAAa,EAAE,gCAAgC;IAE/C,eAAe;IACf,cAAc,EAAE,oDAAoD;IACpE,kBAAkB,EAAE,6DAA6D;IAEjF,qBAAqB;IACrB,aAAa,EAAE,8CAA8C;IAC7D,OAAO,EAAE,wCAAwC;IACjD,YAAY,EAAE,6CAA6C;IAC3D,WAAW,EAAE,4CAA4C;IAEzD,MAAM;IACN,aAAa,EAAE,yBAAyB;IAExC,WAAW;IACX,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY;IAE5C,cAAc;IACd,eAAe,EAAE,WAAW;IAC5B,gBAAgB,EAAE,kBAAkB;CAC5B,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,gBAAgB,EAAE,yEAAyE;IAE3F,WAAW,EAAE,kCAAkC;IAC/C,aAAa,EAAE,gCAAgC;IAE/C,eAAe;IACf,cAAc,EAAE,oDAAoD;IACpE,kBAAkB,EAAE,6DAA6D;IAEjF,qBAAqB;IACrB,aAAa,EAAE,8CAA8C;IAC7D,OAAO,EAAE,wCAAwC;IACjD,YAAY,EAAE,6CAA6C;IAC3D,WAAW,EAAE,4CAA4C;IAEzD,MAAM;IACN,aAAa,EAAE,qBAAqB;IAEpC,uBAAuB;IACvB,uBAAuB,EAAE,wDAAwD;IACjF,yBAAyB,EAAE,0DAA0D;IACrF,eAAe,EAAE,gDAAgD;IACjE,qBAAqB,EAAE,CAAC,GAAG,IAAI,EAAE,YAAY;IAE7C,WAAW;IACX,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY;IAE5C,cAAc;IACd,eAAe,EAAE,WAAW;IAC5B,gBAAgB,EAAE,kBAAkB;CAC5B,CAAC"}
@@ -19,6 +19,14 @@ export interface PaymentGrantResult {
19
19
  payment_token?: string;
20
20
  auto_payment: boolean;
21
21
  }
22
+ export interface AuthCodeLoginResult {
23
+ access_token: string;
24
+ refresh_token: string;
25
+ }
26
+ export interface AuthCodePaymentResult {
27
+ one_time_pay_token?: string;
28
+ auto_pay_enabled: boolean;
29
+ }
22
30
  export interface UserInfo {
23
31
  id: string;
24
32
  email: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawapps/cli",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "ClawApps CLI - Login and manage your ClawApps account from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -30,7 +30,8 @@
30
30
  "chalk": "^5.6.2",
31
31
  "commander": "^14.0.3",
32
32
  "open": "^11.0.0",
33
- "ora": "^8.2.0"
33
+ "ora": "^8.2.0",
34
+ "qrcode-terminal": "^0.12.0"
34
35
  },
35
36
  "devDependencies": {
36
37
  "@types/node": "^25.3.0",