@papercraneai/cli 1.4.1 → 1.4.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/bin/papercrane.js CHANGED
@@ -4,19 +4,12 @@ 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
+ import { http } from '../lib/axios-client.js';
8
8
  import { setApiKey, clearConfig, isLoggedIn, setDefaultWorkspace, getDefaultWorkspace } from '../lib/config.js';
9
9
  import { validateApiKey } from '../lib/cloud-client.js';
10
10
  import { listFunctions, getFunction, runFunction, formatDescribe, formatDescribeRoot, formatFlat, formatResult, formatUnconnected } from '../lib/function-client.js';
11
11
  import { listWorkspaces, resolveWorkspaceId, getFileTree, readFile, writeFile, editFile, deleteFile, getLocalWorkspacePath, pullWorkspace, pushWorkspace } from '../lib/environment-client.js';
12
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
-
20
13
  const program = new Command();
21
14
 
22
15
  program
@@ -29,7 +22,7 @@ program
29
22
  .description('Login to Papercrane. Opens browser for authentication, or use --api-key for direct login.')
30
23
  .option('--api-key <key>', 'API key for direct login (skips browser)')
31
24
  .option('--url <url>', 'API base URL (saves to config)')
32
- .option('--no-wait', 'Print auth URL and exit immediately (for AI assistants)')
25
+ .option('--nowait', 'Print auth URL and exit immediately (for AI assistants)')
33
26
  .option('--check', 'Check if pending login was completed')
34
27
  .action(async (options) => {
35
28
  try {
@@ -65,14 +58,16 @@ program
65
58
  if (options.check) {
66
59
  const pending = await getPendingSession();
67
60
  if (!pending) {
68
- console.log(chalk.yellow('No pending login session. Run: papercrane login --no-wait'));
61
+ console.log(chalk.yellow('No pending login session. Run: papercrane login --nowait'));
69
62
  process.exit(1);
70
63
  }
71
64
 
72
- const statusRes = await fetch(`${pending.baseUrl}/api/cli-auth/status?session=${encodeURIComponent(pending.session)}`);
65
+ const statusRes = await http.get(`${pending.baseUrl}/api/cli-auth/status?session=${encodeURIComponent(pending.session)}`, {
66
+ validateStatus: () => true
67
+ });
73
68
 
74
- if (statusRes.ok) {
75
- const data = await statusRes.json();
69
+ if (statusRes.status >= 200 && statusRes.status < 300) {
70
+ const data = statusRes.data;
76
71
  if (data.status === 'authorized') {
77
72
  await setApiKey(data.key);
78
73
  await setApiBaseUrl(pending.baseUrl);
@@ -93,25 +88,24 @@ program
93
88
  const session = generateState();
94
89
 
95
90
  // Initialize session on server
96
- const initRes = await fetch(`${baseUrl}/api/cli-auth/init`, {
97
- method: 'POST',
91
+ const initRes = await http.post(`${baseUrl}/api/cli-auth/init`, { session }, {
98
92
  headers: { 'Content-Type': 'application/json' },
99
- body: JSON.stringify({ session })
93
+ validateStatus: () => true
100
94
  });
101
95
 
102
- if (!initRes.ok) {
96
+ if (initRes.status < 200 || initRes.status >= 300) {
103
97
  throw new Error('Failed to initialize login session');
104
98
  }
105
99
 
106
100
  const authUrl = `${baseUrl}/cli-auth?session=${session}`;
107
101
 
108
- // --no-wait: Print URL and exit immediately (for AI assistants)
109
- if (options.noWait) {
102
+ // --nowait: Print URL and exit immediately (for AI assistants)
103
+ if (options.nowait) {
110
104
  await setPendingSession({ session, baseUrl });
111
105
  console.log(chalk.cyan('\nOpen this URL to authenticate:\n'));
112
106
  console.log(` ${authUrl}\n`);
113
107
  console.log(chalk.dim('After authorizing, run: papercrane login --check\n'));
114
- return;
108
+ process.exit(0);
115
109
  }
116
110
 
117
111
  console.log(chalk.cyan('\nOpen this URL to authenticate:\n'));
@@ -134,10 +128,12 @@ program
134
128
  const startTime = Date.now();
135
129
 
136
130
  while (Date.now() - startTime < timeout) {
137
- const statusRes = await fetch(`${baseUrl}/api/cli-auth/status?session=${encodeURIComponent(session)}`);
131
+ const statusRes = await http.get(`${baseUrl}/api/cli-auth/status?session=${encodeURIComponent(session)}`, {
132
+ validateStatus: () => true
133
+ });
138
134
 
139
- if (statusRes.ok) {
140
- const data = await statusRes.json();
135
+ if (statusRes.status >= 200 && statusRes.status < 300) {
136
+ const data = statusRes.data;
141
137
 
142
138
  if (data.status === 'authorized') {
143
139
  // Save the API key
@@ -840,4 +836,4 @@ program.action(async (_, cmd) => {
840
836
  }
841
837
  });
842
838
 
843
- program.parse();
839
+ program.parse();
@@ -0,0 +1,14 @@
1
+ import axios from "axios"
2
+ import { HttpsProxyAgent } from "https-proxy-agent"
3
+
4
+ const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY
5
+
6
+ const axiosConfig = proxyUrl
7
+ ? {
8
+ httpAgent: new HttpsProxyAgent(proxyUrl),
9
+ httpsAgent: new HttpsProxyAgent(proxyUrl),
10
+ proxy: false
11
+ }
12
+ : {}
13
+
14
+ export const http = axios.create(axiosConfig)
@@ -1,4 +1,4 @@
1
- import axios from 'axios';
1
+ import { http } from './axios-client.js';
2
2
  import { getApiKey, getApiBaseUrl } from './config.js';
3
3
 
4
4
  /**
@@ -16,7 +16,7 @@ export async function fetchCloudCredentials(provider, instanceName = 'Default')
16
16
  const baseUrl = await getApiBaseUrl();
17
17
 
18
18
  try {
19
- const response = await axios.get(`${baseUrl}/api/sdk/credentials/${provider}/${instanceName}`, {
19
+ const response = await http.get(`${baseUrl}/api/sdk/credentials/${provider}/${instanceName}`, {
20
20
  headers: {
21
21
  'Authorization': `Bearer ${apiKey}`
22
22
  }
@@ -52,7 +52,7 @@ export async function listCloudCredentials() {
52
52
  const baseUrl = await getApiBaseUrl();
53
53
 
54
54
  try {
55
- const response = await axios.get(`${baseUrl}/api/sdk/credentials`, {
55
+ const response = await http.get(`${baseUrl}/api/sdk/credentials`, {
56
56
  headers: {
57
57
  'Authorization': `Bearer ${apiKey}`
58
58
  }
@@ -84,7 +84,7 @@ export async function validateApiKey() {
84
84
  // We expect either a 404 (integration not found, but key is valid)
85
85
  // or a 200 (key is valid and integration exists)
86
86
  // A 401 means the key is invalid
87
- await axios.get(`${baseUrl}/api/sdk/credentials/google/Default`, {
87
+ await http.get(`${baseUrl}/api/sdk/credentials/google/Default`, {
88
88
  headers: {
89
89
  'Authorization': `Bearer ${apiKey}`
90
90
  }
@@ -120,7 +120,7 @@ export async function refreshCloudCredentials(provider, instanceName = 'Default'
120
120
  const baseUrl = await getApiBaseUrl();
121
121
 
122
122
  try {
123
- const response = await axios.post(`${baseUrl}/api/sdk/credentials/${provider}/${instanceName}/refresh`, {}, {
123
+ const response = await http.post(`${baseUrl}/api/sdk/credentials/${provider}/${instanceName}/refresh`, {}, {
124
124
  headers: {
125
125
  'Authorization': `Bearer ${apiKey}`
126
126
  }
@@ -155,7 +155,7 @@ export async function pushCredentials(provider, credentialId, credentials, scope
155
155
 
156
156
  const baseUrl = await getApiBaseUrl();
157
157
 
158
- const response = await axios.post(`${baseUrl}/api/sdk/credentials/push`, {
158
+ const response = await http.post(`${baseUrl}/api/sdk/credentials/push`, {
159
159
  provider,
160
160
  credential_id: credentialId,
161
161
  credentials,
@@ -183,11 +183,11 @@ export async function pullCredentials() {
183
183
 
184
184
  const baseUrl = await getApiBaseUrl();
185
185
 
186
- const response = await axios.get(`${baseUrl}/api/sdk/credentials/pull`, {
186
+ const response = await http.get(`${baseUrl}/api/sdk/credentials/pull`, {
187
187
  headers: {
188
188
  'Authorization': `Bearer ${apiKey}`
189
189
  }
190
190
  });
191
191
 
192
192
  return response.data.credentials || [];
193
- }
193
+ }
package/lib/config.js CHANGED
@@ -125,7 +125,7 @@ export async function clearDefaultWorkspace() {
125
125
  }
126
126
 
127
127
  /**
128
- * Get pending login session (for --no-wait / --check flow)
128
+ * Get pending login session (for --nowait / --check flow)
129
129
  * @returns {Promise<{session: string, baseUrl: string}|null>}
130
130
  */
131
131
  export async function getPendingSession() {
@@ -1,4 +1,4 @@
1
- import axios from 'axios';
1
+ import { http } from './axios-client.js';
2
2
  import { homedir } from 'os';
3
3
  import { join } from 'path';
4
4
  import { getApiKey, getApiBaseUrl, getDefaultWorkspace, setDefaultWorkspace } from './config.js';
@@ -62,7 +62,7 @@ export async function listWorkspaces() {
62
62
  const headers = await getAuthHeaders();
63
63
  const baseUrl = await getApiBaseUrl();
64
64
 
65
- const response = await axios.get(`${baseUrl}/sdk/workspaces`, { headers });
65
+ const response = await http.get(`${baseUrl}/sdk/workspaces`, { headers });
66
66
  return response.data.workspaces;
67
67
  }
68
68
 
@@ -80,7 +80,7 @@ export async function getFileTree(workspaceId, path = '') {
80
80
  ? `${baseUrl}/sdk/workspaces/${workspaceId}/files?path=${encodeURIComponent(path)}`
81
81
  : `${baseUrl}/sdk/workspaces/${workspaceId}/files`;
82
82
 
83
- const response = await axios.get(url, { headers });
83
+ const response = await http.get(url, { headers });
84
84
  return response.data;
85
85
  }
86
86
 
@@ -94,7 +94,7 @@ export async function readFile(workspaceId, path) {
94
94
  const headers = await getAuthHeaders();
95
95
  const baseUrl = await getApiBaseUrl();
96
96
 
97
- const response = await axios.get(
97
+ const response = await http.get(
98
98
  `${baseUrl}/sdk/workspaces/${workspaceId}/files/read?path=${encodeURIComponent(path)}`,
99
99
  { headers }
100
100
  );
@@ -112,7 +112,7 @@ export async function writeFile(workspaceId, path, content) {
112
112
  const headers = await getAuthHeaders();
113
113
  const baseUrl = await getApiBaseUrl();
114
114
 
115
- const response = await axios.post(
115
+ const response = await http.post(
116
116
  `${baseUrl}/sdk/workspaces/${workspaceId}/files/write`,
117
117
  { path, content },
118
118
  { headers }
@@ -133,7 +133,7 @@ export async function editFile(workspaceId, path, oldString, newString, replaceA
133
133
  const headers = await getAuthHeaders();
134
134
  const baseUrl = await getApiBaseUrl();
135
135
 
136
- const response = await axios.post(
136
+ const response = await http.post(
137
137
  `${baseUrl}/sdk/workspaces/${workspaceId}/files/edit`,
138
138
  { path, old_string: oldString, new_string: newString, replace_all: replaceAll },
139
139
  { headers }
@@ -151,7 +151,7 @@ export async function deleteFile(workspaceId, path) {
151
151
  const headers = await getAuthHeaders();
152
152
  const baseUrl = await getApiBaseUrl();
153
153
 
154
- const response = await axios.delete(
154
+ const response = await http.delete(
155
155
  `${baseUrl}/sdk/workspaces/${workspaceId}/files?path=${encodeURIComponent(path)}`,
156
156
  { headers }
157
157
  );
@@ -1,4 +1,4 @@
1
- import axios from 'axios';
1
+ import { http } from './axios-client.js';
2
2
  import chalk from 'chalk';
3
3
  import { saveFacebookCredentials } from './storage.js';
4
4
 
@@ -46,7 +46,7 @@ export async function handleFacebookAuth(scopes, appId, clientToken) {
46
46
 
47
47
  // Step 1: Request device code
48
48
  console.log(chalk.cyan('📱 Requesting device code...'));
49
- const deviceResponse = await axios.post(DEVICE_LOGIN_URL, null, {
49
+ const deviceResponse = await http.post(DEVICE_LOGIN_URL, null, {
50
50
  params: {
51
51
  access_token: accessToken,
52
52
  scope: scopeString
@@ -80,7 +80,7 @@ export async function handleFacebookAuth(scopes, appId, clientToken) {
80
80
  await new Promise(resolve => setTimeout(resolve, pollInterval));
81
81
 
82
82
  try {
83
- const statusResponse = await axios.post(DEVICE_STATUS_URL, null, {
83
+ const statusResponse = await http.post(DEVICE_STATUS_URL, null, {
84
84
  params: {
85
85
  access_token: accessToken,
86
86
  code: code
@@ -145,4 +145,4 @@ export async function handleFacebookAuth(scopes, appId, clientToken) {
145
145
  throw error;
146
146
  }
147
147
  }
148
- }
148
+ }
@@ -1,4 +1,4 @@
1
- import axios from "axios"
1
+ import { http } from "./axios-client.js"
2
2
  import chalk from "chalk"
3
3
  import { getApiKey, getApiBaseUrl } from "./config.js"
4
4
 
@@ -55,7 +55,7 @@ async function functionRequest(
55
55
 
56
56
  // For POST requests, use streaming to handle large/streaming responses
57
57
  if (method === "POST") {
58
- const response = await axios({
58
+ const response = await http({
59
59
  method,
60
60
  url,
61
61
  headers: {
@@ -125,7 +125,7 @@ async function functionRequest(
125
125
  }
126
126
 
127
127
  // GET requests - use regular axios behavior
128
- const response = await axios({
128
+ const response = await http({
129
129
  method,
130
130
  url,
131
131
  headers: {
@@ -1,4 +1,4 @@
1
- import axios from 'axios';
1
+ import { http } from './axios-client.js';
2
2
  import chalk from 'chalk';
3
3
  import open from 'open';
4
4
  import { generatePKCE } from './pkce.js';
@@ -88,7 +88,7 @@ export async function handleGoogleAuth(scopes, clientId, clientSecret) {
88
88
  // Exchange authorization code for tokens
89
89
  console.log(chalk.cyan('🔄 Exchanging authorization code for tokens...'));
90
90
 
91
- const tokenResponse = await axios.post(
91
+ const tokenResponse = await http.post(
92
92
  GOOGLE_TOKEN_URL,
93
93
  new URLSearchParams({
94
94
  code,
@@ -131,4 +131,4 @@ export async function handleGoogleAuth(scopes, clientId, clientSecret) {
131
131
  throw error;
132
132
  }
133
133
  }
134
- }
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@papercraneai/cli",
3
- "version": "1.4.1",
3
+ "version": "1.4.4",
4
4
  "description": "CLI tool for managing OAuth credentials for LLM integrations",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -17,15 +17,20 @@
17
17
  "scripts": {
18
18
  "start": "node bin/papercrane.js"
19
19
  },
20
- "keywords": ["oauth", "cli", "authentication", "google"],
20
+ "keywords": [
21
+ "oauth",
22
+ "cli",
23
+ "authentication",
24
+ "google"
25
+ ],
21
26
  "author": "",
22
27
  "license": "MIT",
23
28
  "dependencies": {
24
29
  "commander": "^12.0.0",
25
30
  "axios": "^1.6.0",
26
31
  "chalk": "^4.1.2",
32
+ "https-proxy-agent": "^7.0.4",
27
33
  "inquirer": "^8.2.6",
28
- "open": "^8.4.2",
29
- "undici": "^6.0.0"
34
+ "open": "^8.4.2"
30
35
  }
31
- }
36
+ }