peekable 0.1.5 → 0.3.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/dist/command-error.js +7 -2
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +21 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/register.js +15 -2
- package/dist/commands/upgrade.d.ts +2 -0
- package/dist/commands/upgrade.js +73 -0
- package/dist/index.js +2 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/command-error.js
CHANGED
|
@@ -21,10 +21,15 @@ export function errorPayload(err) {
|
|
|
21
21
|
}
|
|
22
22
|
export function getErrorMessage(err) {
|
|
23
23
|
if (err instanceof CommandFailure) {
|
|
24
|
-
if (err.cause
|
|
25
|
-
return err.cause
|
|
24
|
+
if (err.cause !== undefined)
|
|
25
|
+
return getErrorMessage(err.cause);
|
|
26
26
|
return err.message;
|
|
27
27
|
}
|
|
28
|
+
// Neutralized under Early Access: the server no longer emits this code, but
|
|
29
|
+
// keep the branch inert-but-safe in case an old server still sends it.
|
|
30
|
+
if (err instanceof ApiError && err.details.code === "trial_expired") {
|
|
31
|
+
return "This request was blocked. Run `peekable doctor` for details.";
|
|
32
|
+
}
|
|
28
33
|
if (err instanceof Error)
|
|
29
34
|
return err.message;
|
|
30
35
|
return String(err);
|
|
@@ -15,6 +15,8 @@ export interface DoctorReport {
|
|
|
15
15
|
identity: DoctorStatus;
|
|
16
16
|
identityName?: string | null;
|
|
17
17
|
identityEmail?: string | null;
|
|
18
|
+
planState?: string | null;
|
|
19
|
+
daysRemaining?: number | null;
|
|
18
20
|
activeSessions: number | null;
|
|
19
21
|
maxActiveSessions: number | null;
|
|
20
22
|
activeSessionUnlimited?: boolean;
|
package/dist/commands/doctor.js
CHANGED
|
@@ -83,6 +83,8 @@ export async function runDoctor(opts = {}) {
|
|
|
83
83
|
maxActiveSessions: null,
|
|
84
84
|
activeSessionUnlimited: false,
|
|
85
85
|
testPush: "skipped",
|
|
86
|
+
planState: null,
|
|
87
|
+
daysRemaining: null,
|
|
86
88
|
errors: [],
|
|
87
89
|
};
|
|
88
90
|
if (!config) {
|
|
@@ -117,6 +119,8 @@ export async function runDoctor(opts = {}) {
|
|
|
117
119
|
const anyMe = me;
|
|
118
120
|
report.identityName = typeof anyMe.name === "string" ? anyMe.name : null;
|
|
119
121
|
report.identityEmail = typeof anyMe.email === "string" ? anyMe.email : null;
|
|
122
|
+
report.planState = typeof anyMe.plan_state === "string" ? anyMe.plan_state : null;
|
|
123
|
+
report.daysRemaining = typeof anyMe.days_remaining === "number" ? anyMe.days_remaining : null;
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
catch (err) {
|
|
@@ -125,7 +129,10 @@ export async function runDoctor(opts = {}) {
|
|
|
125
129
|
}
|
|
126
130
|
if (opts.testPush && report.auth === "ok") {
|
|
127
131
|
try {
|
|
128
|
-
const session = await api(config, "POST", "/sessions", {
|
|
132
|
+
const session = await api(config, "POST", "/sessions", {
|
|
133
|
+
name: "__peekable_doctor__",
|
|
134
|
+
diagnostic: true,
|
|
135
|
+
});
|
|
129
136
|
try {
|
|
130
137
|
await api(config, "POST", `/sessions/${session.id}/push`, {
|
|
131
138
|
html: "<html><body><p>Peekable doctor test</p></body></html>",
|
|
@@ -173,6 +180,7 @@ export function formatDoctorReport(report) {
|
|
|
173
180
|
`Server: ${formatServer(report)}`,
|
|
174
181
|
`Auth: ${formatAuth(report.auth)}`,
|
|
175
182
|
`Identity: ${formatIdentity(report)}`,
|
|
183
|
+
`Plan: ${formatPlan(report)}`,
|
|
176
184
|
`Active sessions: ${formatQuota(report.activeSessions, report.maxActiveSessions, report.activeSessionUnlimited)}`,
|
|
177
185
|
`Test push: ${report.testPush}`,
|
|
178
186
|
];
|
|
@@ -189,6 +197,18 @@ export function formatDoctorReport(report) {
|
|
|
189
197
|
}
|
|
190
198
|
return lines.join("\n");
|
|
191
199
|
}
|
|
200
|
+
function formatPlan(report) {
|
|
201
|
+
// trial* plan_states are all served for free during Early Access; collapse
|
|
202
|
+
// them to one display string and drop the upgrade nudge.
|
|
203
|
+
if (report.planState === "trial_registered"
|
|
204
|
+
|| report.planState === "trial_active"
|
|
205
|
+
|| report.planState === "trial_expired") {
|
|
206
|
+
return "early access";
|
|
207
|
+
}
|
|
208
|
+
if (report.planState === "paid")
|
|
209
|
+
return "paid";
|
|
210
|
+
return "free";
|
|
211
|
+
}
|
|
192
212
|
function formatServer(report) {
|
|
193
213
|
if (!report.serverUrl)
|
|
194
214
|
return "not configured";
|
package/dist/commands/init.js
CHANGED
|
@@ -87,7 +87,7 @@ export const initCommand = new Command("init")
|
|
|
87
87
|
Object.assign(result, installLocalAgentSkills(skillSource, opts.json));
|
|
88
88
|
// 3. Test push
|
|
89
89
|
try {
|
|
90
|
-
const session = await api(config, "POST", "/sessions", { name: "__share_init_test__" });
|
|
90
|
+
const session = await api(config, "POST", "/sessions", { name: "__share_init_test__", init: true });
|
|
91
91
|
await api(config, "POST", `/sessions/${session.id}/push`, {
|
|
92
92
|
html: "<html><body><p>Share init test</p></body></html>",
|
|
93
93
|
});
|
|
@@ -43,13 +43,26 @@ export const registerCommand = new Command("register")
|
|
|
43
43
|
name: opts.name,
|
|
44
44
|
});
|
|
45
45
|
if (opts.json) {
|
|
46
|
-
console.log(JSON.stringify({
|
|
46
|
+
console.log(JSON.stringify({
|
|
47
|
+
api_key: data.api_key,
|
|
48
|
+
url: opts.url,
|
|
49
|
+
name: opts.name,
|
|
50
|
+
plan_state: data.plan_state ?? null,
|
|
51
|
+
trial_ends_at: data.trial_ends_at ?? null,
|
|
52
|
+
days_remaining: data.days_remaining ?? null,
|
|
53
|
+
invite_source: data.invite_source ?? null,
|
|
54
|
+
}));
|
|
47
55
|
}
|
|
48
56
|
else {
|
|
49
57
|
console.log(`Registered as ${opts.name}.`);
|
|
50
58
|
console.log(`API key saved to ~/.peekable/config.json`);
|
|
51
59
|
console.log("Peekable CLI sends anonymous usage/failure telemetry to improve reliability. Opt out: PEEKABLE_NO_TELEMETRY=1");
|
|
52
|
-
|
|
60
|
+
if (data.invite_source === "trial") {
|
|
61
|
+
console.log("Ready — run `peekable init` to get started.");
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
console.log(`\nNext step: run \`peekable init\` to complete setup.`);
|
|
65
|
+
}
|
|
53
66
|
}
|
|
54
67
|
}
|
|
55
68
|
catch (err) {
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { api, ApiError } from "../api.js";
|
|
4
|
+
import { CommandFailure, printCommandError } from "../command-error.js";
|
|
5
|
+
import { requireConfig } from "../config.js";
|
|
6
|
+
import { runWithTelemetry } from "../telemetry.js";
|
|
7
|
+
export const upgradeCommand = new Command("upgrade")
|
|
8
|
+
.description("Upgrade a paid Peekable account through Stripe Checkout")
|
|
9
|
+
.option("--json", "Output JSON")
|
|
10
|
+
.action(async (opts) => {
|
|
11
|
+
await runWithTelemetry("upgrade", async () => {
|
|
12
|
+
const config = requireConfig();
|
|
13
|
+
try {
|
|
14
|
+
const data = await api(config, "POST", "/billing/checkout", {});
|
|
15
|
+
const url = checkoutUrl(data?.url);
|
|
16
|
+
if (!url)
|
|
17
|
+
throw new Error("Checkout did not return a valid URL.");
|
|
18
|
+
if (opts.json) {
|
|
19
|
+
console.log(JSON.stringify({ url, sessionId: data.sessionId ?? null }));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.log("Complete your Peekable upgrade in Stripe Checkout:");
|
|
23
|
+
console.log(url);
|
|
24
|
+
openBrowserBestEffort(url);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err instanceof ApiError && err.details.code === "early_access_no_billing") {
|
|
29
|
+
const message = "Peekable is free during Early Access — nothing to upgrade yet.";
|
|
30
|
+
if (opts.json) {
|
|
31
|
+
console.log(JSON.stringify({ error: message, code: "early_access_no_billing" }));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(message);
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (!opts.json
|
|
39
|
+
&& err instanceof ApiError
|
|
40
|
+
&& (err.details.code === "billing_account_exists"
|
|
41
|
+
|| err.details.code === "billing_account_requires_support")) {
|
|
42
|
+
console.error("Email support@peekable.fyi from your registered account email for help.");
|
|
43
|
+
}
|
|
44
|
+
printCommandError("Upgrade failed", err, opts.json);
|
|
45
|
+
throw new CommandFailure("Upgrade failed", { cause: err });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
function checkoutUrl(value) {
|
|
50
|
+
if (typeof value !== "string")
|
|
51
|
+
return null;
|
|
52
|
+
try {
|
|
53
|
+
const url = new URL(value);
|
|
54
|
+
return url.protocol === "https:" || url.protocol === "http:" ? url.toString() : null;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function openBrowserBestEffort(url) {
|
|
61
|
+
try {
|
|
62
|
+
const child = process.platform === "darwin"
|
|
63
|
+
? spawn("open", [url], { detached: true, stdio: "ignore" })
|
|
64
|
+
: process.platform === "win32"
|
|
65
|
+
? spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" })
|
|
66
|
+
: spawn("xdg-open", [url], { detached: true, stdio: "ignore" });
|
|
67
|
+
child.on("error", () => undefined);
|
|
68
|
+
child.unref();
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// The URL remains printed for humans and coding agents to relay.
|
|
72
|
+
}
|
|
73
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import { pushUrlCommand } from "./commands/push-url.js";
|
|
|
14
14
|
import { doctorCommand } from "./commands/doctor.js";
|
|
15
15
|
import { uninstallCommand } from "./commands/uninstall.js";
|
|
16
16
|
import { reportCommand } from "./commands/report.js";
|
|
17
|
+
import { upgradeCommand } from "./commands/upgrade.js";
|
|
17
18
|
import { CLI_VERSION } from "./version.js";
|
|
18
19
|
import { CommandFailure } from "./command-error.js";
|
|
19
20
|
import { ConfigError } from "./config.js";
|
|
@@ -36,6 +37,7 @@ program.addCommand(proxyCommand);
|
|
|
36
37
|
program.addCommand(doctorCommand);
|
|
37
38
|
program.addCommand(uninstallCommand);
|
|
38
39
|
program.addCommand(reportCommand);
|
|
40
|
+
program.addCommand(upgradeCommand);
|
|
39
41
|
program.addHelpText("afterAll", `
|
|
40
42
|
Telemetry:
|
|
41
43
|
Peekable CLI sends anonymous usage/failure telemetry to improve reliability.
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.
|
|
1
|
+
export declare const CLI_VERSION = "0.3.0";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "0.
|
|
1
|
+
export const CLI_VERSION = "0.3.0";
|