@clawpow/cli 0.1.7 → 0.1.9
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/dist/commands/auth/login.js +40 -45
- package/dist/commands/auth/login.js.map +1 -1
- package/dist/commands/auth/status.js +12 -5
- package/dist/commands/auth/status.js.map +1 -1
- package/dist/commands/setup.js +25 -31
- package/dist/commands/setup.js.map +1 -1
- package/dist/lib/__tests__/auth.test.d.ts +1 -0
- package/dist/lib/__tests__/auth.test.js +93 -0
- package/dist/lib/__tests__/auth.test.js.map +1 -0
- package/dist/lib/__tests__/client.test.d.ts +1 -0
- package/dist/lib/__tests__/client.test.js +108 -0
- package/dist/lib/__tests__/client.test.js.map +1 -0
- package/dist/lib/__tests__/config.test.d.ts +1 -0
- package/dist/lib/__tests__/config.test.js +96 -0
- package/dist/lib/__tests__/config.test.js.map +1 -0
- package/dist/lib/auth.d.ts +9 -0
- package/dist/lib/auth.js +42 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/client.d.ts +3 -5
- package/dist/lib/client.js +31 -15
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/config.d.ts +3 -2
- package/dist/lib/config.js +7 -6
- package/dist/lib/config.js.map +1 -1
- package/package.json +8 -4
|
@@ -1,44 +1,50 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
|
-
import { randomBytes } from "node:crypto";
|
|
4
3
|
import chalk from "chalk";
|
|
5
4
|
import ora from "ora";
|
|
6
5
|
import open from "open";
|
|
7
6
|
import { saveCredentials, getCredentials, isTokenExpired } from "../../lib/config.js";
|
|
7
|
+
import { getWorkOS, getWorkOSClientId, getTokenExpiry } from "../../lib/auth.js";
|
|
8
8
|
import { handleError } from "../../lib/errors.js";
|
|
9
|
-
const APP_URL = process.env.CLAWPOW_APP_URL ?? "http://localhost:3000";
|
|
10
|
-
function generateToken() {
|
|
11
|
-
return "cpw_" + randomBytes(48).toString("base64url");
|
|
12
|
-
}
|
|
13
9
|
export const loginCommand = new Command("login")
|
|
14
10
|
.description("Authenticate with ClawPow")
|
|
15
11
|
.action(async () => {
|
|
16
12
|
try {
|
|
17
|
-
// Check if already logged in
|
|
18
13
|
const existing = getCredentials();
|
|
19
14
|
if (existing && !isTokenExpired(existing)) {
|
|
20
15
|
console.log(chalk.green("✓") + ` Already logged in as ${chalk.bold(existing.email)}`);
|
|
21
16
|
return;
|
|
22
17
|
}
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
const {
|
|
27
|
-
const
|
|
18
|
+
const { port, waitForCode, close } = await startCallbackServer();
|
|
19
|
+
const workos = getWorkOS();
|
|
20
|
+
const clientId = getWorkOSClientId();
|
|
21
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
22
|
+
const { url: authorizationUrl, codeVerifier } = await workos.userManagement.getAuthorizationUrlWithPKCE({
|
|
23
|
+
provider: "authkit",
|
|
24
|
+
redirectUri,
|
|
25
|
+
clientId,
|
|
26
|
+
});
|
|
28
27
|
console.log("Opening browser for authentication...");
|
|
29
|
-
console.log(chalk.dim(`If the browser doesn't open, visit: ${
|
|
30
|
-
await open(
|
|
28
|
+
console.log(chalk.dim(`If the browser doesn't open, visit: ${authorizationUrl}`));
|
|
29
|
+
await open(authorizationUrl);
|
|
31
30
|
const spinner = ora("Waiting for authentication...").start();
|
|
32
31
|
try {
|
|
33
|
-
const
|
|
32
|
+
const code = await waitForCode();
|
|
33
|
+
spinner.text = "Exchanging authorization code...";
|
|
34
|
+
const result = await workos.userManagement.authenticateWithCode({
|
|
35
|
+
code,
|
|
36
|
+
clientId,
|
|
37
|
+
codeVerifier,
|
|
38
|
+
});
|
|
34
39
|
spinner.stop();
|
|
35
|
-
|
|
40
|
+
const email = result.user?.email ?? "unknown";
|
|
36
41
|
saveCredentials({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
accessToken: result.accessToken,
|
|
43
|
+
refreshToken: result.refreshToken ?? null,
|
|
44
|
+
expiresAt: getTokenExpiry(result.accessToken),
|
|
45
|
+
email,
|
|
40
46
|
});
|
|
41
|
-
console.log(chalk.green("✓") + ` Logged in as ${chalk.bold(
|
|
47
|
+
console.log(chalk.green("✓") + ` Logged in as ${chalk.bold(email)}`);
|
|
42
48
|
}
|
|
43
49
|
catch (error) {
|
|
44
50
|
spinner.stop();
|
|
@@ -52,43 +58,33 @@ export const loginCommand = new Command("login")
|
|
|
52
58
|
handleError(error);
|
|
53
59
|
}
|
|
54
60
|
});
|
|
55
|
-
function startCallbackServer(
|
|
61
|
+
function startCallbackServer() {
|
|
56
62
|
return new Promise((resolve, reject) => {
|
|
57
|
-
let
|
|
58
|
-
let
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
let codeResolve;
|
|
64
|
+
let codeReject;
|
|
65
|
+
const codePromise = new Promise((res, rej) => {
|
|
66
|
+
codeResolve = res;
|
|
67
|
+
codeReject = rej;
|
|
62
68
|
});
|
|
63
69
|
const server = createServer(async (req, res) => {
|
|
64
70
|
const url = new URL(req.url, `http://localhost`);
|
|
65
71
|
if (url.pathname === "/callback") {
|
|
66
|
-
const
|
|
67
|
-
const expiresAt = url.searchParams.get("expiresAt");
|
|
68
|
-
const state = url.searchParams.get("state");
|
|
72
|
+
const code = url.searchParams.get("code");
|
|
69
73
|
const error = url.searchParams.get("error");
|
|
70
74
|
if (error) {
|
|
71
75
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
72
76
|
res.end("<html><body><h2>Authentication failed</h2><p>You can close this tab.</p></body></html>");
|
|
73
|
-
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (state !== expectedState) {
|
|
77
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
78
|
-
res.end("<html><body><h2>Invalid state</h2></body></html>");
|
|
77
|
+
codeReject(new Error(`Authentication failed: ${error}`));
|
|
79
78
|
return;
|
|
80
79
|
}
|
|
81
|
-
if (!
|
|
80
|
+
if (!code) {
|
|
82
81
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
83
|
-
res.end("<html><body><h2>Missing
|
|
82
|
+
res.end("<html><body><h2>Missing authorization code</h2></body></html>");
|
|
84
83
|
return;
|
|
85
84
|
}
|
|
86
85
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
87
86
|
res.end("<html><body><h2>Authenticated!</h2><p>You can close this tab and return to your terminal.</p></body></html>");
|
|
88
|
-
|
|
89
|
-
email,
|
|
90
|
-
expiresAt: parseInt(expiresAt, 10),
|
|
91
|
-
});
|
|
87
|
+
codeResolve(code);
|
|
92
88
|
}
|
|
93
89
|
else {
|
|
94
90
|
res.writeHead(404);
|
|
@@ -103,15 +99,14 @@ function startCallbackServer(expectedState) {
|
|
|
103
99
|
}
|
|
104
100
|
resolve({
|
|
105
101
|
port: addr.port,
|
|
106
|
-
|
|
107
|
-
// Set a 5-minute timeout
|
|
102
|
+
waitForCode: async () => {
|
|
108
103
|
const timeout = setTimeout(() => {
|
|
109
|
-
|
|
104
|
+
codeReject(new Error("Authentication timed out. Please try again."));
|
|
110
105
|
}, 5 * 60 * 1000);
|
|
111
106
|
try {
|
|
112
|
-
const
|
|
107
|
+
const code = await codePromise;
|
|
113
108
|
clearTimeout(timeout);
|
|
114
|
-
return
|
|
109
|
+
return code;
|
|
115
110
|
}
|
|
116
111
|
catch (error) {
|
|
117
112
|
clearTimeout(timeout);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/auth/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/auth/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,12 +10,19 @@ export const statusCommand = new Command("status")
|
|
|
10
10
|
process.exit(1);
|
|
11
11
|
}
|
|
12
12
|
if (isTokenExpired(creds)) {
|
|
13
|
-
console.log(chalk.yellow("Session expired.") + "
|
|
14
|
-
|
|
13
|
+
console.log(chalk.yellow("Session expired.") + " Token will be refreshed on next command, or run `clawpow auth login`.");
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
console.log(chalk.green("✓") + ` Logged in as ${chalk.bold(creds.email)}`);
|
|
15
17
|
}
|
|
16
18
|
const expiresDate = new Date(creds.expiresAt);
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
const minutesLeft = Math.ceil((creds.expiresAt - Date.now()) / (60 * 1000));
|
|
20
|
+
if (minutesLeft > 0) {
|
|
21
|
+
console.log(` Access token expires: ${expiresDate.toLocaleString()} (${minutesLeft} min)`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.log(` Access token expired: ${expiresDate.toLocaleString()}`);
|
|
25
|
+
}
|
|
26
|
+
console.log(` Refresh token: ${creds.refreshToken ? "present" : "missing"}`);
|
|
20
27
|
});
|
|
21
28
|
//# sourceMappingURL=status.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/auth/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,4CAA4C,CAAC,CAAC;QAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/auth/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,oCAAoC,CAAC;KACjD,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,4CAA4C,CAAC,CAAC;QAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,wEAAwE,CAAC,CAAC;IAC3H,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,iBAAiB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAE5E,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,2BAA2B,WAAW,CAAC,cAAc,EAAE,KAAK,WAAW,OAAO,CAAC,CAAC;IAC9F,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,2BAA2B,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;AAChF,CAAC,CAAC,CAAC"}
|
package/dist/commands/setup.js
CHANGED
|
@@ -4,11 +4,12 @@ import ora from "ora";
|
|
|
4
4
|
import open from "open";
|
|
5
5
|
import { select, checkbox } from "@inquirer/prompts";
|
|
6
6
|
import { getCredentials, isTokenExpired } from "../lib/config.js";
|
|
7
|
-
import {
|
|
7
|
+
import { getConvexClientWithRefresh } from "../lib/client.js";
|
|
8
8
|
import { handleError } from "../lib/errors.js";
|
|
9
9
|
import { AGENTS, installSkillFile } from "../lib/skills.js";
|
|
10
10
|
import { loginCommand } from "./auth/login.js";
|
|
11
|
-
|
|
11
|
+
import { anyApi } from "convex/server";
|
|
12
|
+
const APP_URL = process.env.CLAWPOW_APP_URL ?? "https://clawpow.vercel.app";
|
|
12
13
|
export const setupCommand = new Command("setup")
|
|
13
14
|
.description("Set up ClawPow for your AI agents")
|
|
14
15
|
.action(async () => {
|
|
@@ -24,9 +25,7 @@ export const setupCommand = new Command("setup")
|
|
|
24
25
|
console.log(chalk.green("✓") + ` Logged in as ${chalk.bold(creds.email)}`);
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
|
-
// Run the login flow
|
|
28
28
|
await loginCommand.parseAsync([], { from: "user" });
|
|
29
|
-
// Verify login succeeded
|
|
30
29
|
const newCreds = getCredentials();
|
|
31
30
|
if (!newCreds || isTokenExpired(newCreds)) {
|
|
32
31
|
console.error("Login failed. Please try again.");
|
|
@@ -38,12 +37,8 @@ export const setupCommand = new Command("setup")
|
|
|
38
37
|
// ── Step 2: Select superskills ──────────────────────
|
|
39
38
|
console.log(chalk.bold("Step 2: Select superskills"));
|
|
40
39
|
console.log(chalk.dim("─".repeat(40)));
|
|
41
|
-
const client =
|
|
42
|
-
const
|
|
43
|
-
if (!listRes.ok) {
|
|
44
|
-
throw new Error("Failed to fetch superskills");
|
|
45
|
-
}
|
|
46
|
-
const { superskills } = (await listRes.json());
|
|
40
|
+
const client = await getConvexClientWithRefresh();
|
|
41
|
+
const superskills = await client.query(anyApi.superskills.list, {});
|
|
47
42
|
const activeSuperskills = superskills.filter((s) => s.status === "active");
|
|
48
43
|
const comingSoonSuperskills = superskills.filter((s) => s.status !== "active");
|
|
49
44
|
if (activeSuperskills.length === 0) {
|
|
@@ -74,15 +69,13 @@ export const setupCommand = new Command("setup")
|
|
|
74
69
|
for (const id of selectedIds) {
|
|
75
70
|
const ss = activeSuperskills.find((s) => s.id === id);
|
|
76
71
|
if (!ss?.enabled) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
if (enableRes.ok) {
|
|
72
|
+
try {
|
|
73
|
+
await client.mutation(anyApi.superskills.enable, { superskillId: id });
|
|
81
74
|
console.log(chalk.green("✓") + ` ${ss?.name ?? id} enabled`);
|
|
82
75
|
}
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
console.log(chalk.yellow("!") + ` Could not enable ${id}: ${
|
|
76
|
+
catch (err) {
|
|
77
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
78
|
+
console.log(chalk.yellow("!") + ` Could not enable ${id}: ${message}`);
|
|
86
79
|
}
|
|
87
80
|
}
|
|
88
81
|
else {
|
|
@@ -97,12 +90,14 @@ export const setupCommand = new Command("setup")
|
|
|
97
90
|
continue;
|
|
98
91
|
console.log(chalk.bold(`Step 3: ${ss.name} setup`));
|
|
99
92
|
console.log(chalk.dim("─".repeat(40)));
|
|
100
|
-
|
|
101
|
-
|
|
93
|
+
let status;
|
|
94
|
+
try {
|
|
95
|
+
status = await client.query(anyApi.superskills.getStatus, { superskillId: id });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
102
98
|
console.log(chalk.yellow("!") + ` Could not check status for ${ss.name}`);
|
|
103
99
|
continue;
|
|
104
100
|
}
|
|
105
|
-
const status = (await statusRes.json());
|
|
106
101
|
if (status.setupComplete) {
|
|
107
102
|
const accountList = status.connectedAccounts
|
|
108
103
|
.filter((a) => a.status === "active")
|
|
@@ -162,13 +157,15 @@ export const setupCommand = new Command("setup")
|
|
|
162
157
|
});
|
|
163
158
|
// Fetch and install skill files
|
|
164
159
|
for (const superskillId of selectedIds) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
160
|
+
let content;
|
|
161
|
+
try {
|
|
162
|
+
content = await client.query(anyApi.superskills.getSkillFile, { superskillId });
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
const message = err instanceof Error ? err.message : "Unknown error";
|
|
166
|
+
console.log(chalk.yellow("!") + ` Could not fetch skill file for ${superskillId}: ${message}`);
|
|
169
167
|
continue;
|
|
170
168
|
}
|
|
171
|
-
const { content } = (await skillRes.json());
|
|
172
169
|
for (const agentId of selectedAgents) {
|
|
173
170
|
const filePath = installSkillFile(agentId, superskillId, content, scope);
|
|
174
171
|
console.log(chalk.green("✓") + ` Installed ${chalk.dim(filePath)}`);
|
|
@@ -186,12 +183,9 @@ async function pollForSetup(client, superskillId, timeoutMs) {
|
|
|
186
183
|
while (Date.now() < deadline) {
|
|
187
184
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
188
185
|
try {
|
|
189
|
-
const
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
if (status.setupComplete) {
|
|
193
|
-
return status;
|
|
194
|
-
}
|
|
186
|
+
const status = await client.query(anyApi.superskills.getStatus, { superskillId });
|
|
187
|
+
if (status.setupComplete) {
|
|
188
|
+
return status;
|
|
195
189
|
}
|
|
196
190
|
}
|
|
197
191
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
// Mock WorkOS before importing auth module
|
|
3
|
+
vi.mock("@workos-inc/node", () => ({
|
|
4
|
+
WorkOS: vi.fn().mockImplementation(function () {
|
|
5
|
+
return {
|
|
6
|
+
userManagement: {
|
|
7
|
+
authenticateWithRefreshToken: vi.fn(),
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
}),
|
|
11
|
+
}));
|
|
12
|
+
import { WorkOS } from "@workos-inc/node";
|
|
13
|
+
import { getTokenExpiry, refreshAccessToken } from "../auth.js";
|
|
14
|
+
const MockWorkOS = vi.mocked(WorkOS);
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
// Helper to create a JWT with a given exp claim
|
|
19
|
+
function makeJwt(payload) {
|
|
20
|
+
const header = btoa(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
21
|
+
const body = btoa(JSON.stringify(payload));
|
|
22
|
+
return `${header}.${body}.fake-signature`;
|
|
23
|
+
}
|
|
24
|
+
describe("getTokenExpiry", () => {
|
|
25
|
+
it("extracts exp from a valid JWT", () => {
|
|
26
|
+
const expSeconds = Math.floor(Date.now() / 1000) + 3600;
|
|
27
|
+
const jwt = makeJwt({ exp: expSeconds, sub: "user_123" });
|
|
28
|
+
expect(getTokenExpiry(jwt)).toBe(expSeconds * 1000);
|
|
29
|
+
});
|
|
30
|
+
it("falls back to 1 hour for non-JWT strings", () => {
|
|
31
|
+
const before = Date.now();
|
|
32
|
+
const result = getTokenExpiry("not-a-jwt");
|
|
33
|
+
expect(result).toBeGreaterThanOrEqual(before + 3600 * 1000 - 100);
|
|
34
|
+
expect(result).toBeLessThanOrEqual(Date.now() + 3600 * 1000 + 100);
|
|
35
|
+
});
|
|
36
|
+
it("falls back to 1 hour when exp claim is missing", () => {
|
|
37
|
+
const jwt = makeJwt({ sub: "user_123" });
|
|
38
|
+
const before = Date.now();
|
|
39
|
+
const result = getTokenExpiry(jwt);
|
|
40
|
+
expect(result).toBeGreaterThanOrEqual(before + 3600 * 1000 - 100);
|
|
41
|
+
});
|
|
42
|
+
it("falls back to 1 hour for malformed base64 payload", () => {
|
|
43
|
+
const before = Date.now();
|
|
44
|
+
const result = getTokenExpiry("header.!!!invalid-base64!!!.signature");
|
|
45
|
+
expect(result).toBeGreaterThanOrEqual(before + 3600 * 1000 - 100);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("refreshAccessToken", () => {
|
|
49
|
+
it("returns new tokens on success", async () => {
|
|
50
|
+
const expSeconds = Math.floor(Date.now() / 1000) + 1800;
|
|
51
|
+
const mockAccessToken = makeJwt({ exp: expSeconds, sub: "user_123" });
|
|
52
|
+
const mockAuth = vi.fn().mockResolvedValue({
|
|
53
|
+
accessToken: mockAccessToken,
|
|
54
|
+
refreshToken: "new-refresh-token",
|
|
55
|
+
});
|
|
56
|
+
MockWorkOS.mockImplementation(function () {
|
|
57
|
+
return {
|
|
58
|
+
userManagement: { authenticateWithRefreshToken: mockAuth },
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
const result = await refreshAccessToken("old-refresh-token");
|
|
62
|
+
expect(result).not.toBeNull();
|
|
63
|
+
expect(result.accessToken).toBe(mockAccessToken);
|
|
64
|
+
expect(result.refreshToken).toBe("new-refresh-token");
|
|
65
|
+
expect(result.expiresAt).toBe(expSeconds * 1000);
|
|
66
|
+
});
|
|
67
|
+
it("returns null refreshToken when WorkOS omits it", async () => {
|
|
68
|
+
const mockAccessToken = makeJwt({ exp: Math.floor(Date.now() / 1000) + 3600 });
|
|
69
|
+
const mockAuth = vi.fn().mockResolvedValue({
|
|
70
|
+
accessToken: mockAccessToken,
|
|
71
|
+
refreshToken: undefined,
|
|
72
|
+
});
|
|
73
|
+
MockWorkOS.mockImplementation(function () {
|
|
74
|
+
return {
|
|
75
|
+
userManagement: { authenticateWithRefreshToken: mockAuth },
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
const result = await refreshAccessToken("old-refresh-token");
|
|
79
|
+
expect(result).not.toBeNull();
|
|
80
|
+
expect(result.refreshToken).toBeNull();
|
|
81
|
+
});
|
|
82
|
+
it("returns null on failure", async () => {
|
|
83
|
+
const mockAuth = vi.fn().mockRejectedValue(new Error("invalid token"));
|
|
84
|
+
MockWorkOS.mockImplementation(function () {
|
|
85
|
+
return {
|
|
86
|
+
userManagement: { authenticateWithRefreshToken: mockAuth },
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
const result = await refreshAccessToken("bad-token");
|
|
90
|
+
expect(result).toBeNull();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=auth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/auth.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
// Mock dependencies
|
|
3
|
+
const mockSetAuth = vi.fn();
|
|
4
|
+
vi.mock("convex/browser", () => ({
|
|
5
|
+
ConvexHttpClient: class MockConvexHttpClient {
|
|
6
|
+
setAuth = mockSetAuth;
|
|
7
|
+
constructor(_url) { }
|
|
8
|
+
},
|
|
9
|
+
}));
|
|
10
|
+
vi.mock("../config.js", () => ({
|
|
11
|
+
getCredentials: vi.fn(),
|
|
12
|
+
getConfig: vi.fn(() => ({ convexUrl: "https://test.convex.cloud" })),
|
|
13
|
+
isTokenExpired: vi.fn(),
|
|
14
|
+
saveCredentials: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
vi.mock("../auth.js", () => ({
|
|
17
|
+
refreshAccessToken: vi.fn(),
|
|
18
|
+
}));
|
|
19
|
+
import { getCredentials, isTokenExpired, saveCredentials } from "../config.js";
|
|
20
|
+
import { refreshAccessToken } from "../auth.js";
|
|
21
|
+
import { getConvexClient, getConvexClientWithRefresh } from "../client.js";
|
|
22
|
+
import { ClawpowError } from "../errors.js";
|
|
23
|
+
const mockGetCredentials = vi.mocked(getCredentials);
|
|
24
|
+
const mockIsTokenExpired = vi.mocked(isTokenExpired);
|
|
25
|
+
const mockRefreshAccessToken = vi.mocked(refreshAccessToken);
|
|
26
|
+
const mockSaveCredentials = vi.mocked(saveCredentials);
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
vi.clearAllMocks();
|
|
29
|
+
});
|
|
30
|
+
describe("getConvexClient", () => {
|
|
31
|
+
it("throws when not logged in", () => {
|
|
32
|
+
mockGetCredentials.mockReturnValue(null);
|
|
33
|
+
expect(() => getConvexClient()).toThrow(ClawpowError);
|
|
34
|
+
expect(() => getConvexClient()).toThrow("Not logged in");
|
|
35
|
+
});
|
|
36
|
+
it("returns client with auth set", () => {
|
|
37
|
+
mockGetCredentials.mockReturnValue({
|
|
38
|
+
accessToken: "token-abc",
|
|
39
|
+
refreshToken: "refresh-xyz",
|
|
40
|
+
expiresAt: Date.now() + 3600_000,
|
|
41
|
+
email: "test@example.com",
|
|
42
|
+
});
|
|
43
|
+
const client = getConvexClient();
|
|
44
|
+
expect(client).toBeDefined();
|
|
45
|
+
expect(mockSetAuth).toHaveBeenCalledWith("token-abc");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
describe("getConvexClientWithRefresh", () => {
|
|
49
|
+
it("throws when not logged in", async () => {
|
|
50
|
+
mockGetCredentials.mockReturnValue(null);
|
|
51
|
+
await expect(getConvexClientWithRefresh()).rejects.toThrow("Not logged in");
|
|
52
|
+
});
|
|
53
|
+
it("returns client directly when token is fresh", async () => {
|
|
54
|
+
mockGetCredentials.mockReturnValue({
|
|
55
|
+
accessToken: "token-abc",
|
|
56
|
+
refreshToken: "refresh-xyz",
|
|
57
|
+
expiresAt: Date.now() + 3600_000,
|
|
58
|
+
email: "test@example.com",
|
|
59
|
+
});
|
|
60
|
+
mockIsTokenExpired.mockReturnValue(false);
|
|
61
|
+
const client = await getConvexClientWithRefresh();
|
|
62
|
+
expect(client).toBeDefined();
|
|
63
|
+
expect(mockRefreshAccessToken).not.toHaveBeenCalled();
|
|
64
|
+
});
|
|
65
|
+
it("refreshes token when expired", async () => {
|
|
66
|
+
const creds = {
|
|
67
|
+
accessToken: "old-token",
|
|
68
|
+
refreshToken: "refresh-xyz",
|
|
69
|
+
expiresAt: Date.now() - 1000,
|
|
70
|
+
email: "test@example.com",
|
|
71
|
+
};
|
|
72
|
+
mockGetCredentials
|
|
73
|
+
.mockReturnValueOnce(creds)
|
|
74
|
+
.mockReturnValueOnce({ ...creds, accessToken: "new-token", expiresAt: Date.now() + 3600_000 });
|
|
75
|
+
mockIsTokenExpired.mockReturnValue(true);
|
|
76
|
+
mockRefreshAccessToken.mockResolvedValue({
|
|
77
|
+
accessToken: "new-token",
|
|
78
|
+
refreshToken: "new-refresh",
|
|
79
|
+
expiresAt: Date.now() + 3600_000,
|
|
80
|
+
});
|
|
81
|
+
const client = await getConvexClientWithRefresh();
|
|
82
|
+
expect(client).toBeDefined();
|
|
83
|
+
expect(mockRefreshAccessToken).toHaveBeenCalledWith("refresh-xyz");
|
|
84
|
+
expect(mockSaveCredentials).toHaveBeenCalled();
|
|
85
|
+
});
|
|
86
|
+
it("throws when expired and refreshToken is null", async () => {
|
|
87
|
+
mockGetCredentials.mockReturnValue({
|
|
88
|
+
accessToken: "old-token",
|
|
89
|
+
refreshToken: null,
|
|
90
|
+
expiresAt: Date.now() - 1000,
|
|
91
|
+
email: "test@example.com",
|
|
92
|
+
});
|
|
93
|
+
mockIsTokenExpired.mockReturnValue(true);
|
|
94
|
+
await expect(getConvexClientWithRefresh()).rejects.toThrow("expired");
|
|
95
|
+
});
|
|
96
|
+
it("throws when refresh fails", async () => {
|
|
97
|
+
mockGetCredentials.mockReturnValue({
|
|
98
|
+
accessToken: "old-token",
|
|
99
|
+
refreshToken: "refresh-xyz",
|
|
100
|
+
expiresAt: Date.now() - 1000,
|
|
101
|
+
email: "test@example.com",
|
|
102
|
+
});
|
|
103
|
+
mockIsTokenExpired.mockReturnValue(true);
|
|
104
|
+
mockRefreshAccessToken.mockResolvedValue(null);
|
|
105
|
+
await expect(getConvexClientWithRefresh()).rejects.toThrow("could not be refreshed");
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
vi.mock("node:fs", () => ({
|
|
3
|
+
existsSync: vi.fn(),
|
|
4
|
+
mkdirSync: vi.fn(),
|
|
5
|
+
readFileSync: vi.fn(),
|
|
6
|
+
writeFileSync: vi.fn(),
|
|
7
|
+
unlinkSync: vi.fn(),
|
|
8
|
+
chmodSync: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
vi.mock("node:os", () => ({
|
|
11
|
+
homedir: vi.fn(() => "/mock-home"),
|
|
12
|
+
}));
|
|
13
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from "node:fs";
|
|
14
|
+
import { getCredentials, saveCredentials, deleteCredentials, isTokenExpired } from "../config.js";
|
|
15
|
+
const mockExistsSync = vi.mocked(existsSync);
|
|
16
|
+
const mockReadFileSync = vi.mocked(readFileSync);
|
|
17
|
+
const mockWriteFileSync = vi.mocked(writeFileSync);
|
|
18
|
+
const mockUnlinkSync = vi.mocked(unlinkSync);
|
|
19
|
+
const mockChmodSync = vi.mocked(chmodSync);
|
|
20
|
+
const validCreds = {
|
|
21
|
+
accessToken: "token-abc",
|
|
22
|
+
refreshToken: "refresh-xyz",
|
|
23
|
+
expiresAt: Date.now() + 3600_000,
|
|
24
|
+
email: "test@example.com",
|
|
25
|
+
};
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
vi.clearAllMocks();
|
|
28
|
+
});
|
|
29
|
+
describe("getCredentials", () => {
|
|
30
|
+
it("returns null when credentials file does not exist", () => {
|
|
31
|
+
mockExistsSync.mockReturnValue(false);
|
|
32
|
+
expect(getCredentials()).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
it("returns credentials when file is valid", () => {
|
|
35
|
+
mockExistsSync.mockReturnValue(true);
|
|
36
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(validCreds));
|
|
37
|
+
const result = getCredentials();
|
|
38
|
+
expect(result).toEqual(validCreds);
|
|
39
|
+
});
|
|
40
|
+
it("returns null when accessToken is missing", () => {
|
|
41
|
+
mockExistsSync.mockReturnValue(true);
|
|
42
|
+
mockReadFileSync.mockReturnValue(JSON.stringify({ ...validCreds, accessToken: "" }));
|
|
43
|
+
expect(getCredentials()).toBeNull();
|
|
44
|
+
});
|
|
45
|
+
it("returns credentials when refreshToken is null", () => {
|
|
46
|
+
mockExistsSync.mockReturnValue(true);
|
|
47
|
+
const creds = { ...validCreds, refreshToken: null };
|
|
48
|
+
mockReadFileSync.mockReturnValue(JSON.stringify(creds));
|
|
49
|
+
expect(getCredentials()).toEqual(creds);
|
|
50
|
+
});
|
|
51
|
+
it("returns null when file contains invalid JSON", () => {
|
|
52
|
+
mockExistsSync.mockReturnValue(true);
|
|
53
|
+
mockReadFileSync.mockReturnValue("not json");
|
|
54
|
+
expect(getCredentials()).toBeNull();
|
|
55
|
+
});
|
|
56
|
+
it("returns null when email is missing", () => {
|
|
57
|
+
mockExistsSync.mockReturnValue(true);
|
|
58
|
+
mockReadFileSync.mockReturnValue(JSON.stringify({ ...validCreds, email: "" }));
|
|
59
|
+
expect(getCredentials()).toBeNull();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe("saveCredentials", () => {
|
|
63
|
+
it("writes credentials with chmod 600", () => {
|
|
64
|
+
mockExistsSync.mockReturnValue(true);
|
|
65
|
+
saveCredentials(validCreds);
|
|
66
|
+
expect(mockWriteFileSync).toHaveBeenCalledWith(expect.stringContaining("credentials.json"), JSON.stringify(validCreds, null, 2), "utf-8");
|
|
67
|
+
expect(mockChmodSync).toHaveBeenCalledWith(expect.stringContaining("credentials.json"), 0o600);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
describe("deleteCredentials", () => {
|
|
71
|
+
it("removes file when it exists", () => {
|
|
72
|
+
mockExistsSync.mockReturnValue(true);
|
|
73
|
+
deleteCredentials();
|
|
74
|
+
expect(mockUnlinkSync).toHaveBeenCalledWith(expect.stringContaining("credentials.json"));
|
|
75
|
+
});
|
|
76
|
+
it("does nothing when file does not exist", () => {
|
|
77
|
+
mockExistsSync.mockReturnValue(false);
|
|
78
|
+
deleteCredentials();
|
|
79
|
+
expect(mockUnlinkSync).not.toHaveBeenCalled();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe("isTokenExpired", () => {
|
|
83
|
+
it("returns false when token is fresh", () => {
|
|
84
|
+
const creds = { ...validCreds, expiresAt: Date.now() + 120_000 };
|
|
85
|
+
expect(isTokenExpired(creds)).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it("returns true when token is past expiry", () => {
|
|
88
|
+
const creds = { ...validCreds, expiresAt: Date.now() - 1000 };
|
|
89
|
+
expect(isTokenExpired(creds)).toBe(true);
|
|
90
|
+
});
|
|
91
|
+
it("returns true when token is within 60-second buffer", () => {
|
|
92
|
+
const creds = { ...validCreds, expiresAt: Date.now() + 30_000 };
|
|
93
|
+
expect(isTokenExpired(creds)).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=config.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../../src/lib/__tests__/config.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { WorkOS } from "@workos-inc/node";
|
|
2
|
+
export declare function getWorkOS(): WorkOS;
|
|
3
|
+
export declare function getWorkOSClientId(): string;
|
|
4
|
+
export declare function getTokenExpiry(jwt: string): number;
|
|
5
|
+
export declare function refreshAccessToken(refreshToken: string): Promise<{
|
|
6
|
+
accessToken: string;
|
|
7
|
+
refreshToken: string | null;
|
|
8
|
+
expiresAt: number;
|
|
9
|
+
} | null>;
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { WorkOS } from "@workos-inc/node";
|
|
2
|
+
const WORKOS_CLIENT_ID = process.env.CLAWPOW_WORKOS_CLIENT_ID ?? "client_01KA6B3HHV243WCC23AJE79T04";
|
|
3
|
+
export function getWorkOS() {
|
|
4
|
+
return new WorkOS("", { clientId: WORKOS_CLIENT_ID });
|
|
5
|
+
}
|
|
6
|
+
export function getWorkOSClientId() {
|
|
7
|
+
return WORKOS_CLIENT_ID;
|
|
8
|
+
}
|
|
9
|
+
export function getTokenExpiry(jwt) {
|
|
10
|
+
const parts = jwt.split(".");
|
|
11
|
+
if (parts.length !== 3) {
|
|
12
|
+
return Date.now() + 3600 * 1000;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
16
|
+
if (typeof payload.exp === "number") {
|
|
17
|
+
return payload.exp * 1000;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Fallback to 1 hour if decoding fails
|
|
22
|
+
}
|
|
23
|
+
return Date.now() + 3600 * 1000;
|
|
24
|
+
}
|
|
25
|
+
export async function refreshAccessToken(refreshToken) {
|
|
26
|
+
try {
|
|
27
|
+
const workos = getWorkOS();
|
|
28
|
+
const result = await workos.userManagement.authenticateWithRefreshToken({
|
|
29
|
+
clientId: WORKOS_CLIENT_ID,
|
|
30
|
+
refreshToken,
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
accessToken: result.accessToken,
|
|
34
|
+
refreshToken: result.refreshToken ?? null,
|
|
35
|
+
expiresAt: getTokenExpiry(result.accessToken),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,mCAAmC,CAAC;AAErG,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,MAAM,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;IAClC,CAAC;IACD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,IAAI,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YACpC,OAAO,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC;QAC5B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,YAAoB;IAMpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,4BAA4B,CAAC;YACtE,QAAQ,EAAE,gBAAgB;YAC1B,YAAY;SACb,CAAC,CAAC;QACH,OAAO;YACL,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,IAAI;YACzC,SAAS,EAAE,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC;SAC9C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/lib/client.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function
|
|
3
|
-
|
|
4
|
-
apiUrl: string;
|
|
5
|
-
};
|
|
1
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
2
|
+
export declare function getConvexClient(): ConvexHttpClient;
|
|
3
|
+
export declare function getConvexClientWithRefresh(): Promise<ConvexHttpClient>;
|
package/dist/lib/client.js
CHANGED
|
@@ -1,25 +1,41 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
2
|
+
import { getCredentials, getConfig, isTokenExpired, saveCredentials } from "./config.js";
|
|
2
3
|
import { ClawpowError } from "./errors.js";
|
|
3
|
-
|
|
4
|
+
import { refreshAccessToken } from "./auth.js";
|
|
5
|
+
export function getConvexClient() {
|
|
4
6
|
const creds = getCredentials();
|
|
5
7
|
if (!creds) {
|
|
6
8
|
throw new ClawpowError("Not logged in. Run `clawpow auth login` first.", "AUTH_REQUIRED");
|
|
7
9
|
}
|
|
8
|
-
if (isTokenExpired(creds)) {
|
|
9
|
-
throw new ClawpowError("Your session has expired. Run `clawpow auth login` to re-authenticate.", "TOKEN_EXPIRED");
|
|
10
|
-
}
|
|
11
10
|
const config = getConfig();
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
const client = new ConvexHttpClient(config.convexUrl);
|
|
12
|
+
client.setAuth(creds.accessToken);
|
|
13
|
+
return client;
|
|
14
|
+
}
|
|
15
|
+
export async function getConvexClientWithRefresh() {
|
|
16
|
+
let creds = getCredentials();
|
|
17
|
+
if (!creds) {
|
|
18
|
+
throw new ClawpowError("Not logged in. Run `clawpow auth login` first.", "AUTH_REQUIRED");
|
|
19
|
+
}
|
|
20
|
+
if (isTokenExpired(creds)) {
|
|
21
|
+
if (!creds.refreshToken) {
|
|
22
|
+
throw new ClawpowError("Your session has expired. Run `clawpow auth login` to re-authenticate.", "TOKEN_EXPIRED");
|
|
20
23
|
}
|
|
21
|
-
|
|
24
|
+
const refreshed = await refreshAccessToken(creds.refreshToken);
|
|
25
|
+
if (!refreshed) {
|
|
26
|
+
throw new ClawpowError("Your session has expired and could not be refreshed. Run `clawpow auth login` to re-authenticate.", "TOKEN_EXPIRED");
|
|
27
|
+
}
|
|
28
|
+
saveCredentials({
|
|
29
|
+
...creds,
|
|
30
|
+
accessToken: refreshed.accessToken,
|
|
31
|
+
refreshToken: refreshed.refreshToken ?? creds.refreshToken,
|
|
32
|
+
expiresAt: refreshed.expiresAt,
|
|
33
|
+
});
|
|
34
|
+
creds = getCredentials();
|
|
22
35
|
}
|
|
23
|
-
|
|
36
|
+
const config = getConfig();
|
|
37
|
+
const client = new ConvexHttpClient(config.convexUrl);
|
|
38
|
+
client.setAuth(creds.accessToken);
|
|
39
|
+
return client;
|
|
24
40
|
}
|
|
25
41
|
//# sourceMappingURL=client.js.map
|
package/dist/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,YAAY,CACpB,gDAAgD,EAChD,eAAe,CAChB,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,IAAI,KAAK,GAAG,cAAc,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,YAAY,CACpB,gDAAgD,EAChD,eAAe,CAChB,CAAC;IACJ,CAAC;IAED,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YACxB,MAAM,IAAI,YAAY,CACpB,wEAAwE,EACxE,eAAe,CAChB,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,YAAY,CACpB,mGAAmG,EACnG,eAAe,CAChB,CAAC;QACJ,CAAC;QACD,eAAe,CAAC;YACd,GAAG,KAAK;YACR,WAAW,EAAE,SAAS,CAAC,WAAW;YAClC,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY;YAC1D,SAAS,EAAE,SAAS,CAAC,SAAS;SAC/B,CAAC,CAAC;QACH,KAAK,GAAG,cAAc,EAAG,CAAC;IAC5B,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export interface Credentials {
|
|
2
|
-
|
|
2
|
+
accessToken: string;
|
|
3
|
+
refreshToken: string | null;
|
|
3
4
|
expiresAt: number;
|
|
4
5
|
email: string;
|
|
5
6
|
}
|
|
6
7
|
export interface Config {
|
|
7
|
-
|
|
8
|
+
convexUrl: string;
|
|
8
9
|
}
|
|
9
10
|
export declare function getCredentials(): Credentials | null;
|
|
10
11
|
export declare function saveCredentials(creds: Credentials): void;
|
package/dist/lib/config.js
CHANGED
|
@@ -4,8 +4,8 @@ import { homedir } from "node:os";
|
|
|
4
4
|
const CONFIG_DIR = join(homedir(), ".clawpow");
|
|
5
5
|
const CREDENTIALS_PATH = join(CONFIG_DIR, "credentials.json");
|
|
6
6
|
const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
7
|
-
//
|
|
8
|
-
const
|
|
7
|
+
// Convex deployment URL (for ConvexHttpClient)
|
|
8
|
+
const DEFAULT_CONVEX_URL = "https://intent-chipmunk-988.convex.cloud";
|
|
9
9
|
function ensureConfigDir() {
|
|
10
10
|
if (!existsSync(CONFIG_DIR)) {
|
|
11
11
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
@@ -17,7 +17,7 @@ export function getCredentials() {
|
|
|
17
17
|
try {
|
|
18
18
|
const raw = readFileSync(CREDENTIALS_PATH, "utf-8");
|
|
19
19
|
const parsed = JSON.parse(raw);
|
|
20
|
-
if (!parsed.
|
|
20
|
+
if (!parsed.accessToken || !parsed.expiresAt || !parsed.email)
|
|
21
21
|
return null;
|
|
22
22
|
return parsed;
|
|
23
23
|
}
|
|
@@ -36,20 +36,21 @@ export function deleteCredentials() {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
export function isTokenExpired(creds) {
|
|
39
|
-
|
|
39
|
+
// Consider expired 60 seconds before actual expiry to avoid edge cases
|
|
40
|
+
return creds.expiresAt - 60_000 < Date.now();
|
|
40
41
|
}
|
|
41
42
|
export function getConfig() {
|
|
42
43
|
if (existsSync(CONFIG_PATH)) {
|
|
43
44
|
try {
|
|
44
45
|
const raw = readFileSync(CONFIG_PATH, "utf-8");
|
|
45
46
|
const parsed = JSON.parse(raw);
|
|
46
|
-
return {
|
|
47
|
+
return { convexUrl: parsed.convexUrl ?? DEFAULT_CONVEX_URL };
|
|
47
48
|
}
|
|
48
49
|
catch {
|
|
49
50
|
// fall through
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
|
-
return {
|
|
53
|
+
return { convexUrl: DEFAULT_CONVEX_URL };
|
|
53
54
|
}
|
|
54
55
|
export function saveConfig(config) {
|
|
55
56
|
ensureConfigDir();
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAC/C,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAC/C,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAC9D,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEpD,+CAA+C;AAC/C,MAAM,kBAAkB,GAAG,0CAA0C,CAAC;AAatE,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;QAC9C,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAC3E,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACzE,SAAS,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACjC,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAkB;IAC/C,uEAAuE;IACvE,OAAO,KAAK,CAAC,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;YAClD,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,kBAAkB,EAAE,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACvE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawpow/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "ClawPow CLI — Superpowers for your AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"build": "tsc",
|
|
18
18
|
"dev": "tsc --watch",
|
|
19
19
|
"start": "node dist/index.js",
|
|
20
|
-
"
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"release": "bun run test && bun run build && npm version patch --no-git-tag-version --no-workspaces-update && bun publish --access public"
|
|
21
22
|
},
|
|
22
23
|
"keywords": [
|
|
23
24
|
"cli",
|
|
@@ -31,14 +32,17 @@
|
|
|
31
32
|
"access": "public"
|
|
32
33
|
},
|
|
33
34
|
"dependencies": {
|
|
35
|
+
"@inquirer/prompts": "^7.0.0",
|
|
36
|
+
"@workos-inc/node": "^8.5.0",
|
|
34
37
|
"chalk": "^5.4.0",
|
|
35
38
|
"commander": "^14.0.0",
|
|
36
|
-
"
|
|
39
|
+
"convex": "^1.31.7",
|
|
37
40
|
"open": "^10.0.0",
|
|
38
41
|
"ora": "^8.0.0"
|
|
39
42
|
},
|
|
40
43
|
"devDependencies": {
|
|
41
44
|
"@types/node": "^22.0.0",
|
|
42
|
-
"typescript": "^5.0.0"
|
|
45
|
+
"typescript": "^5.0.0",
|
|
46
|
+
"vitest": "^4.0.18"
|
|
43
47
|
}
|
|
44
48
|
}
|