@papercraneai/cli 1.3.0 → 1.4.1

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/papercrane.js CHANGED
@@ -4,11 +4,19 @@ import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
5
  import readline from 'readline';
6
6
  import fs from 'fs/promises';
7
+ import { ProxyAgent, setGlobalDispatcher } from 'undici';
7
8
  import { setApiKey, clearConfig, isLoggedIn, setDefaultWorkspace, getDefaultWorkspace } from '../lib/config.js';
8
9
  import { validateApiKey } from '../lib/cloud-client.js';
9
10
  import { listFunctions, getFunction, runFunction, formatDescribe, formatDescribeRoot, formatFlat, formatResult, formatUnconnected } from '../lib/function-client.js';
10
11
  import { listWorkspaces, resolveWorkspaceId, getFileTree, readFile, writeFile, editFile, deleteFile, getLocalWorkspacePath, pullWorkspace, pushWorkspace } from '../lib/environment-client.js';
11
12
 
13
+ // Configure proxy support for environments like Claude's container
14
+ // Node.js native fetch() doesn't respect HTTP_PROXY/HTTPS_PROXY env vars
15
+ const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY;
16
+ if (proxyUrl) {
17
+ setGlobalDispatcher(new ProxyAgent(proxyUrl));
18
+ }
19
+
12
20
  const program = new Command();
13
21
 
14
22
  program
@@ -21,9 +29,11 @@ program
21
29
  .description('Login to Papercrane. Opens browser for authentication, or use --api-key for direct login.')
22
30
  .option('--api-key <key>', 'API key for direct login (skips browser)')
23
31
  .option('--url <url>', 'API base URL (saves to config)')
32
+ .option('--no-wait', 'Print auth URL and exit immediately (for AI assistants)')
33
+ .option('--check', 'Check if pending login was completed')
24
34
  .action(async (options) => {
25
35
  try {
26
- const { getApiBaseUrl, setApiBaseUrl } = await import('../lib/config.js');
36
+ const { getApiBaseUrl, setApiBaseUrl, getPendingSession, setPendingSession, clearPendingSession } = await import('../lib/config.js');
27
37
 
28
38
  // Resolve API base URL: --url flag > config > default
29
39
  let baseUrl;
@@ -51,9 +61,34 @@ program
51
61
  return;
52
62
  }
53
63
 
54
- // Browser-based login flow (polling)
64
+ // --check: Check if pending login was completed
65
+ if (options.check) {
66
+ const pending = await getPendingSession();
67
+ if (!pending) {
68
+ console.log(chalk.yellow('No pending login session. Run: papercrane login --no-wait'));
69
+ process.exit(1);
70
+ }
71
+
72
+ const statusRes = await fetch(`${pending.baseUrl}/api/cli-auth/status?session=${encodeURIComponent(pending.session)}`);
73
+
74
+ if (statusRes.ok) {
75
+ const data = await statusRes.json();
76
+ if (data.status === 'authorized') {
77
+ await setApiKey(data.key);
78
+ await setApiBaseUrl(pending.baseUrl);
79
+ await clearPendingSession();
80
+ console.log(chalk.green(`✓ Logged in as ${data.email}`));
81
+ console.log(chalk.dim(` API key saved to ~/.papercrane/config.json\n`));
82
+ return;
83
+ }
84
+ }
85
+
86
+ console.log(chalk.yellow('Not yet authorized. Please click the login URL, then run: papercrane login --check'));
87
+ process.exit(1);
88
+ }
89
+
90
+ // Browser-based login flow
55
91
  const { generateState } = await import('../lib/auth-server.js');
56
- const open = (await import('open')).default;
57
92
 
58
93
  const session = generateState();
59
94
 
@@ -70,11 +105,21 @@ program
70
105
 
71
106
  const authUrl = `${baseUrl}/cli-auth?session=${session}`;
72
107
 
108
+ // --no-wait: Print URL and exit immediately (for AI assistants)
109
+ if (options.noWait) {
110
+ await setPendingSession({ session, baseUrl });
111
+ console.log(chalk.cyan('\nOpen this URL to authenticate:\n'));
112
+ console.log(` ${authUrl}\n`);
113
+ console.log(chalk.dim('After authorizing, run: papercrane login --check\n'));
114
+ return;
115
+ }
116
+
73
117
  console.log(chalk.cyan('\nOpen this URL to authenticate:\n'));
74
118
  console.log(` ${authUrl}\n`);
75
119
 
76
120
  // Try to open browser automatically
77
121
  try {
122
+ const open = (await import('open')).default;
78
123
  await open(authUrl);
79
124
  console.log(chalk.dim('(Browser opened automatically)'));
80
125
  } catch {
package/lib/config.js CHANGED
@@ -123,3 +123,31 @@ export async function clearDefaultWorkspace() {
123
123
  delete config.defaultWorkspaceId;
124
124
  await saveConfig(config);
125
125
  }
126
+
127
+ /**
128
+ * Get pending login session (for --no-wait / --check flow)
129
+ * @returns {Promise<{session: string, baseUrl: string}|null>}
130
+ */
131
+ export async function getPendingSession() {
132
+ const config = await loadConfig();
133
+ return config.pendingSession || null;
134
+ }
135
+
136
+ /**
137
+ * Set pending login session
138
+ * @param {{session: string, baseUrl: string}} pendingSession
139
+ */
140
+ export async function setPendingSession(pendingSession) {
141
+ const config = await loadConfig();
142
+ config.pendingSession = pendingSession;
143
+ await saveConfig(config);
144
+ }
145
+
146
+ /**
147
+ * Clear pending login session
148
+ */
149
+ export async function clearPendingSession() {
150
+ const config = await loadConfig();
151
+ delete config.pendingSession;
152
+ await saveConfig(config);
153
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@papercraneai/cli",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "CLI tool for managing OAuth credentials for LLM integrations",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -25,6 +25,7 @@
25
25
  "axios": "^1.6.0",
26
26
  "chalk": "^4.1.2",
27
27
  "inquirer": "^8.2.6",
28
- "open": "^8.4.2"
28
+ "open": "^8.4.2",
29
+ "undici": "^6.0.0"
29
30
  }
30
31
  }