percher 0.5.15 → 0.5.17
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/bin/percher.js +178 -33
- package/dist/package.json +2 -2
- package/dist/src/commands/token.d.ts +4 -0
- package/dist/src/commands/token.d.ts.map +1 -0
- package/dist/src/commands/token.js +97 -0
- package/dist/src/commands/token.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/templates/capsule/src/lib/ai.ts +59 -0
- package/package.json +2 -2
package/dist/bin/percher.js
CHANGED
|
@@ -105969,6 +105969,9 @@ class AccountResource {
|
|
|
105969
105969
|
listTokens() {
|
|
105970
105970
|
return this.http.get("/account/tokens");
|
|
105971
105971
|
}
|
|
105972
|
+
createToken(input) {
|
|
105973
|
+
return this.http.post("/account/tokens", input);
|
|
105974
|
+
}
|
|
105972
105975
|
revokeToken(id) {
|
|
105973
105976
|
return this.http.delete(`/account/tokens/${encodeURIComponent(id)}`);
|
|
105974
105977
|
}
|
|
@@ -114802,6 +114805,12 @@ function classifyPublishApiError(err, input) {
|
|
|
114802
114805
|
const auth = matchAuthError(err);
|
|
114803
114806
|
if (auth)
|
|
114804
114807
|
return buildResult(auth, input);
|
|
114808
|
+
const tooLarge = matchInlinePublishTooLarge(err);
|
|
114809
|
+
if (tooLarge)
|
|
114810
|
+
return buildResult(tooLarge, input);
|
|
114811
|
+
const repoMissingConfig = matchRepoMissingConfig(err);
|
|
114812
|
+
if (repoMissingConfig)
|
|
114813
|
+
return buildResult(repoMissingConfig, input);
|
|
114805
114814
|
const retryLimit = matchRetryLimitReached(err, input);
|
|
114806
114815
|
if (retryLimit)
|
|
114807
114816
|
return buildResult(retryLimit, input);
|
|
@@ -115086,6 +115095,40 @@ function matchDailyQuotaExceeded(err, input) {
|
|
|
115086
115095
|
summary: `Daily ${kind}-deploy quota reached (${used}/${limit}). Resets ${resetAt}.`
|
|
115087
115096
|
};
|
|
115088
115097
|
}
|
|
115098
|
+
function matchInlinePublishTooLarge(err) {
|
|
115099
|
+
if (err.code !== "INLINE_PUBLISH_TOO_LARGE")
|
|
115100
|
+
return null;
|
|
115101
|
+
return {
|
|
115102
|
+
title: "Inline source too large",
|
|
115103
|
+
explanation: err.message,
|
|
115104
|
+
suggestion: "Inline publishing is for small, text-generated apps. Publish a larger or on-disk app another way: on-disk project → the local `bunx percher publish` CLI (or `npx -y @percher/mcp`); public repo → percher_publish_from_git; private repo → connect it via the GitHub App, then percher_deploy.",
|
|
115105
|
+
recovery: recoveryAsk({
|
|
115106
|
+
prompt: `${err.message} Publish by source instead: on-disk → local \`bunx percher publish\` / \`npx -y @percher/mcp\`; public repo → percher_publish_from_git; private repo → connect via the GitHub App, then percher_deploy.`,
|
|
115107
|
+
options: [
|
|
115108
|
+
"publish on-disk (bunx percher publish / npx @percher/mcp)",
|
|
115109
|
+
"public repo (percher_publish_from_git)",
|
|
115110
|
+
"private repo (GitHub App + percher_deploy)"
|
|
115111
|
+
],
|
|
115112
|
+
reasonCode: "unknown"
|
|
115113
|
+
}),
|
|
115114
|
+
summary: `Inline source too large: ${err.message}`
|
|
115115
|
+
};
|
|
115116
|
+
}
|
|
115117
|
+
function matchRepoMissingConfig(err) {
|
|
115118
|
+
if (err.code !== "REPO_MISSING_CONFIG")
|
|
115119
|
+
return null;
|
|
115120
|
+
return {
|
|
115121
|
+
title: "Repo has no percher.toml",
|
|
115122
|
+
explanation: err.message,
|
|
115123
|
+
suggestion: "Add a percher.toml (with [app] name + runtime) to the repo root and push, then retry — or publish the source inline with percher_publish instead.",
|
|
115124
|
+
recovery: recoveryAsk({
|
|
115125
|
+
prompt: `${err.message} Add a percher.toml to the repo root (then retry percher_publish_from_git), or publish the source inline with percher_publish.`,
|
|
115126
|
+
options: ["add percher.toml to the repo", "publish inline (percher_publish)"],
|
|
115127
|
+
reasonCode: "config_missing"
|
|
115128
|
+
}),
|
|
115129
|
+
summary: `Repo missing percher.toml: ${err.message}`
|
|
115130
|
+
};
|
|
115131
|
+
}
|
|
115089
115132
|
function matchGenericClientError(err) {
|
|
115090
115133
|
if (err.status < 400 || err.status >= 500)
|
|
115091
115134
|
return null;
|
|
@@ -117039,6 +117082,34 @@ function summarize2(verdict, health) {
|
|
|
117039
117082
|
}
|
|
117040
117083
|
return "API responded but reported a non-ok status";
|
|
117041
117084
|
}
|
|
117085
|
+
// ../core/dist/commands/token.js
|
|
117086
|
+
var tokenCreateInputSchema = exports_external.object({
|
|
117087
|
+
name: exports_external.string().trim().min(1).max(80).describe("Human label for the token (shown in the list)."),
|
|
117088
|
+
scope: exports_external.enum(["deploy", "env", "read", "full"]).default("full").describe("Least-privilege scope: deploy (publish/rollback/logs), env (set/read env), read (GETs only), or full (account-wide). Prefer the narrowest that works for CI/agents."),
|
|
117089
|
+
app: exports_external.string().trim().min(1).optional().describe("Bind the token to a single app by name. Omit for all of your apps."),
|
|
117090
|
+
ttlDays: exports_external.number().int().positive().max(365).optional().describe("Token lifetime in days (server default ≈ 90).")
|
|
117091
|
+
});
|
|
117092
|
+
var tokenRevokeInputSchema = exports_external.object({
|
|
117093
|
+
id: exports_external.string().min(1).describe("Token id from `percher token list`.")
|
|
117094
|
+
});
|
|
117095
|
+
async function tokenCreate(ctx, input) {
|
|
117096
|
+
ctx.status("Minting token…");
|
|
117097
|
+
return ctx.client.account.createToken({
|
|
117098
|
+
name: input.name,
|
|
117099
|
+
scope: input.scope,
|
|
117100
|
+
app: input.app,
|
|
117101
|
+
ttlDays: input.ttlDays
|
|
117102
|
+
});
|
|
117103
|
+
}
|
|
117104
|
+
async function tokenList(ctx) {
|
|
117105
|
+
ctx.status("Loading tokens…");
|
|
117106
|
+
const { tokens } = await ctx.client.account.listTokens();
|
|
117107
|
+
return tokens;
|
|
117108
|
+
}
|
|
117109
|
+
async function tokenRevoke(ctx, input) {
|
|
117110
|
+
ctx.status("Revoking token…");
|
|
117111
|
+
await ctx.client.account.revokeToken(input.id);
|
|
117112
|
+
}
|
|
117042
117113
|
// ../core/dist/commands/transfers.js
|
|
117043
117114
|
function resolveApp5(ctx, app) {
|
|
117044
117115
|
const name = app ?? readPercherTomlAppName(ctx.cwd);
|
|
@@ -119168,18 +119239,91 @@ async function renderHumanStatus(ctx, result) {
|
|
|
119168
119239
|
}
|
|
119169
119240
|
}
|
|
119170
119241
|
|
|
119171
|
-
// src/commands/
|
|
119242
|
+
// src/commands/token.ts
|
|
119172
119243
|
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
119244
|
+
var VALID_SCOPES = ["deploy", "env", "read", "full"];
|
|
119245
|
+
function scopeLabel(scopes, appName) {
|
|
119246
|
+
const s = scopes && scopes.length > 0 ? scopes.join("+") : "full";
|
|
119247
|
+
return appName ? `${s} · ${appName}` : `${s} · all apps`;
|
|
119248
|
+
}
|
|
119249
|
+
function registerTokenCommands(cli, ctx) {
|
|
119250
|
+
cli.command("token [action] [arg]", "Manage API tokens: create | list | revoke").option("--scope <scope>", "(create) deploy | env | read | full (default: full)").option("--app <name>", "(create) bind the token to a single app").option("--ttl-days <n>", "(create) token lifetime in days").action(async (action, arg, options) => {
|
|
119251
|
+
if (!ctx.client.token) {
|
|
119252
|
+
await writeLine(ctx, `${import_picocolors14.default.red("✗")} Not logged in. Run: percher login`);
|
|
119253
|
+
throw new SilentExitError;
|
|
119254
|
+
}
|
|
119255
|
+
if (action === "create") {
|
|
119256
|
+
if (!arg) {
|
|
119257
|
+
await writeLine(ctx, `${import_picocolors14.default.red("✗")} A name is required. Usage: percher token create <name> [--scope deploy] [--app <name>]`);
|
|
119258
|
+
throw new SilentExitError;
|
|
119259
|
+
}
|
|
119260
|
+
const scope = options.scope ?? "full";
|
|
119261
|
+
if (!VALID_SCOPES.includes(scope)) {
|
|
119262
|
+
await writeLine(ctx, `${import_picocolors14.default.red("✗")} Invalid --scope "${options.scope}". Use one of: ${VALID_SCOPES.join(", ")}.`);
|
|
119263
|
+
throw new SilentExitError;
|
|
119264
|
+
}
|
|
119265
|
+
const ttlDays = options.ttlDays !== undefined ? Number(options.ttlDays) : undefined;
|
|
119266
|
+
if (ttlDays !== undefined && (!Number.isInteger(ttlDays) || ttlDays <= 0)) {
|
|
119267
|
+
await writeLine(ctx, `${import_picocolors14.default.red("✗")} --ttl-days must be a positive whole number.`);
|
|
119268
|
+
throw new SilentExitError;
|
|
119269
|
+
}
|
|
119270
|
+
const created = await tokenCreate(ctx, {
|
|
119271
|
+
name: arg,
|
|
119272
|
+
scope,
|
|
119273
|
+
app: options.app,
|
|
119274
|
+
ttlDays
|
|
119275
|
+
});
|
|
119276
|
+
await writeLine(ctx, `${import_picocolors14.default.green("✓")} Token created: ${import_picocolors14.default.bold(created.name)} ${import_picocolors14.default.dim(`(${scopeLabel(created.scopes, created.appName)})`)}`);
|
|
119277
|
+
await writeLine(ctx, "");
|
|
119278
|
+
await writeLine(ctx, ` ${import_picocolors14.default.bold(created.token)}`);
|
|
119279
|
+
await writeLine(ctx, import_picocolors14.default.yellow(" ↑ Store this now — the secret is shown only once and can't be retrieved."));
|
|
119280
|
+
await writeLine(ctx, "");
|
|
119281
|
+
await writeLine(ctx, import_picocolors14.default.dim(" Use it in CI / an agent:"));
|
|
119282
|
+
await writeLine(ctx, import_picocolors14.default.dim(` PERCHER_TOKEN=${created.token} bunx percher publish`));
|
|
119283
|
+
return;
|
|
119284
|
+
}
|
|
119285
|
+
if (action === "list") {
|
|
119286
|
+
const tokens = await tokenList(ctx);
|
|
119287
|
+
if (tokens.length === 0) {
|
|
119288
|
+
await writeLine(ctx, import_picocolors14.default.dim("No API tokens."));
|
|
119289
|
+
return;
|
|
119290
|
+
}
|
|
119291
|
+
for (const t of tokens) {
|
|
119292
|
+
const expires = t.expiresAt ? `expires ${new Date(t.expiresAt).toISOString().slice(0, 10)}` : "no expiry";
|
|
119293
|
+
await writeLine(ctx, `${import_picocolors14.default.bold(t.id)} ${t.name.padEnd(20)} ${import_picocolors14.default.dim(scopeLabel(t.scopes, t.appName))} ${import_picocolors14.default.dim(expires)}`);
|
|
119294
|
+
}
|
|
119295
|
+
await writeLine(ctx, "");
|
|
119296
|
+
await writeLine(ctx, import_picocolors14.default.dim("Revoke one with: percher token revoke <id>"));
|
|
119297
|
+
return;
|
|
119298
|
+
}
|
|
119299
|
+
if (action === "revoke") {
|
|
119300
|
+
if (!arg) {
|
|
119301
|
+
await writeLine(ctx, `${import_picocolors14.default.red("✗")} A token id is required. Usage: percher token revoke <id> (list ids with \`percher token list\`).`);
|
|
119302
|
+
throw new SilentExitError;
|
|
119303
|
+
}
|
|
119304
|
+
await tokenRevoke(ctx, { id: arg });
|
|
119305
|
+
await writeLine(ctx, `${import_picocolors14.default.green("✓")} Token revoked.`);
|
|
119306
|
+
return;
|
|
119307
|
+
}
|
|
119308
|
+
throw new Error(`Unknown token action "${action ?? ""}". Use: create | list | revoke.`);
|
|
119309
|
+
});
|
|
119310
|
+
cli.command("token create <name>", "Mint a scoped API token (the secret is shown once)").option("--scope <scope>", "deploy | env | read | full (default: full)").option("--app <name>", "Bind the token to a single app").option("--ttl-days <n>", "Token lifetime in days").action(async () => {});
|
|
119311
|
+
cli.command("token list", "List your API tokens with scope + bound app").action(async () => {});
|
|
119312
|
+
cli.command("token revoke <id>", "Revoke an API token by id").action(async () => {});
|
|
119313
|
+
}
|
|
119314
|
+
|
|
119315
|
+
// src/commands/transfers.ts
|
|
119316
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
119173
119317
|
function registerTransfersCommands(cli, ctx) {
|
|
119174
119318
|
cli.command("transfer [emailOrTransferId]", "Transfer ownership of an app: `transfer <email>` initiates; `transfer --cancel <id>` cancels; `transfer --list` shows history").option("--app <name>", "App name (overrides percher.toml)").option("--cancel", "Cancel a pending transfer by id (positional arg is the transferId)").option("--list", "List the transfer history for this app").action(async (emailOrTransferId, options) => {
|
|
119175
119319
|
if (options.list) {
|
|
119176
119320
|
const rows = await transferListForApp(ctx, { app: options.app });
|
|
119177
119321
|
if (rows.length === 0) {
|
|
119178
|
-
await writeLine(ctx,
|
|
119322
|
+
await writeLine(ctx, import_picocolors15.default.dim("No transfers for this app."));
|
|
119179
119323
|
return;
|
|
119180
119324
|
}
|
|
119181
119325
|
for (const r of rows) {
|
|
119182
|
-
const status2 = r.status === "pending" ?
|
|
119326
|
+
const status2 = r.status === "pending" ? import_picocolors15.default.yellow("pending") : r.status === "accepted" ? import_picocolors15.default.green("accepted") : import_picocolors15.default.dim(r.status);
|
|
119183
119327
|
await writeLine(ctx, `${r.id} ${status2.padEnd(20)} → ${r.toEmail} (${r.createdAt})`);
|
|
119184
119328
|
}
|
|
119185
119329
|
return;
|
|
@@ -119192,7 +119336,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
119192
119336
|
app: options.app,
|
|
119193
119337
|
transferId: emailOrTransferId
|
|
119194
119338
|
});
|
|
119195
|
-
await writeLine(ctx, `${
|
|
119339
|
+
await writeLine(ctx, `${import_picocolors15.default.green("✓")} Cancelled transfer ${emailOrTransferId}`);
|
|
119196
119340
|
return;
|
|
119197
119341
|
}
|
|
119198
119342
|
if (!emailOrTransferId) {
|
|
@@ -119202,17 +119346,17 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
119202
119346
|
app: options.app,
|
|
119203
119347
|
email: emailOrTransferId
|
|
119204
119348
|
});
|
|
119205
|
-
await writeLine(ctx, `${
|
|
119206
|
-
await writeLine(ctx,
|
|
119349
|
+
await writeLine(ctx, `${import_picocolors15.default.green("✓")} Transfer initiated to ${initiated.toEmail} (id ${initiated.id})`);
|
|
119350
|
+
await writeLine(ctx, import_picocolors15.default.dim(`Expires ${new Date(initiated.expiresAt).toLocaleDateString()}. The recipient must accept via 'percher transfers accept ${initiated.id}'.`));
|
|
119207
119351
|
if (initiated.notes) {
|
|
119208
|
-
await writeLine(ctx,
|
|
119352
|
+
await writeLine(ctx, import_picocolors15.default.yellow(` ⚠ ${initiated.notes}`));
|
|
119209
119353
|
}
|
|
119210
119354
|
});
|
|
119211
119355
|
cli.command("transfers [action] [transferId]", "Incoming ownership transfers: list (default) | accept <transferId> | decline <transferId>").action(async (action, transferId) => {
|
|
119212
119356
|
if (action === undefined || action === "list") {
|
|
119213
119357
|
const rows = await transfersIncoming(ctx, {});
|
|
119214
119358
|
if (rows.length === 0) {
|
|
119215
|
-
await writeLine(ctx,
|
|
119359
|
+
await writeLine(ctx, import_picocolors15.default.dim("No pending incoming transfers."));
|
|
119216
119360
|
return;
|
|
119217
119361
|
}
|
|
119218
119362
|
for (const r of rows) {
|
|
@@ -119225,7 +119369,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
119225
119369
|
throw new Error("Usage: percher transfers accept <transferId>");
|
|
119226
119370
|
}
|
|
119227
119371
|
const accepted = await transfersAccept(ctx, { transferId });
|
|
119228
|
-
await writeLine(ctx, `${
|
|
119372
|
+
await writeLine(ctx, `${import_picocolors15.default.green("✓")} You now own ${import_picocolors15.default.cyan(accepted.appName)}. Run 'percher open --app ${accepted.appName}' to see it.`);
|
|
119229
119373
|
return;
|
|
119230
119374
|
}
|
|
119231
119375
|
if (action === "decline") {
|
|
@@ -119233,7 +119377,7 @@ function registerTransfersCommands(cli, ctx) {
|
|
|
119233
119377
|
throw new Error("Usage: percher transfers decline <transferId>");
|
|
119234
119378
|
}
|
|
119235
119379
|
await transfersDecline(ctx, { transferId });
|
|
119236
|
-
await writeLine(ctx, `${
|
|
119380
|
+
await writeLine(ctx, `${import_picocolors15.default.green("✓")} Declined transfer ${transferId}.`);
|
|
119237
119381
|
return;
|
|
119238
119382
|
}
|
|
119239
119383
|
throw new Error(`Unknown transfers action "${action}". Use list | accept <id> | decline <id>.`);
|
|
@@ -119302,52 +119446,52 @@ async function createCliContext() {
|
|
|
119302
119446
|
}
|
|
119303
119447
|
|
|
119304
119448
|
// src/output.ts
|
|
119305
|
-
var
|
|
119449
|
+
var import_picocolors16 = __toESM(require_picocolors(), 1);
|
|
119306
119450
|
async function renderError(stderr, error48) {
|
|
119307
119451
|
const writer = stderr.getWriter();
|
|
119308
119452
|
const encoder = new TextEncoder;
|
|
119309
119453
|
const lines = [];
|
|
119310
119454
|
if (error48 instanceof PercherTomlError) {
|
|
119311
|
-
lines.push(`${
|
|
119455
|
+
lines.push(`${import_picocolors16.default.red(`error (${error48.code}):`)} ${error48.message}`);
|
|
119312
119456
|
if (error48.tomlLine !== undefined) {
|
|
119313
|
-
lines.push(
|
|
119457
|
+
lines.push(import_picocolors16.default.dim(` at percher.toml line ${error48.tomlLine}`));
|
|
119314
119458
|
}
|
|
119315
119459
|
for (const issue2 of error48.issues ?? []) {
|
|
119316
|
-
lines.push(`${
|
|
119460
|
+
lines.push(`${import_picocolors16.default.dim(" · ") + import_picocolors16.default.yellow(issue2.path.join("."))}: ${issue2.message}`);
|
|
119317
119461
|
}
|
|
119318
119462
|
} else if (error48 instanceof SunsetError) {
|
|
119319
119463
|
if (error48.gateCode === "platform_delete_gated") {
|
|
119320
|
-
lines.push(`${
|
|
119464
|
+
lines.push(`${import_picocolors16.default.yellow("Percher is shutting down — deletes are paused.")}`);
|
|
119321
119465
|
lines.push(error48.message);
|
|
119322
|
-
lines.push(
|
|
119323
|
-
lines.push(
|
|
119466
|
+
lines.push(import_picocolors16.default.dim(` To delete and permanently forfeit your export window, confirm with your password in the dashboard: ${error48.dashboardUrl}`));
|
|
119467
|
+
lines.push(import_picocolors16.default.dim(" The CLI cannot perform this delete during sunset — it must go through the dashboard."));
|
|
119324
119468
|
} else {
|
|
119325
|
-
lines.push(`${
|
|
119469
|
+
lines.push(`${import_picocolors16.default.yellow("Percher is in read-only mode ahead of shutdown.")}`);
|
|
119326
119470
|
lines.push(error48.message);
|
|
119327
|
-
lines.push(
|
|
119471
|
+
lines.push(import_picocolors16.default.dim(` Your apps keep running. Export them any time from the dashboard: ${error48.dashboardUrl}`));
|
|
119328
119472
|
}
|
|
119329
|
-
lines.push(
|
|
119473
|
+
lines.push(import_picocolors16.default.dim(` Final data deletion: ${error48.finalDeletionDate}`));
|
|
119330
119474
|
} else if (error48 instanceof PercherApiError) {
|
|
119331
119475
|
if (error48.status === 502 || error48.status === 503) {
|
|
119332
|
-
lines.push(`${
|
|
119476
|
+
lines.push(`${import_picocolors16.default.red("error:")} Percher API is temporarily unavailable (HTTP ${error48.status}). Try again in a few seconds.`);
|
|
119333
119477
|
} else {
|
|
119334
|
-
lines.push(`${
|
|
119335
|
-
lines.push(
|
|
119478
|
+
lines.push(`${import_picocolors16.default.red("error:")} ${error48.message}`);
|
|
119479
|
+
lines.push(import_picocolors16.default.dim(` ${error48.code} (HTTP ${error48.status})`));
|
|
119336
119480
|
}
|
|
119337
119481
|
if (error48.requestId)
|
|
119338
|
-
lines.push(
|
|
119482
|
+
lines.push(import_picocolors16.default.dim(` request: ${error48.requestId}`));
|
|
119339
119483
|
} else if (error48 instanceof PercherCoreError) {
|
|
119340
|
-
lines.push(`${
|
|
119484
|
+
lines.push(`${import_picocolors16.default.red(`error (${error48.code}):`)} ${error48.message}`);
|
|
119341
119485
|
if (error48.hint)
|
|
119342
|
-
lines.push(
|
|
119486
|
+
lines.push(import_picocolors16.default.dim(` ${error48.hint}`));
|
|
119343
119487
|
} else if (error48 instanceof Error) {
|
|
119344
|
-
lines.push(`${
|
|
119488
|
+
lines.push(`${import_picocolors16.default.red("unexpected error:")} ${error48.message}`);
|
|
119345
119489
|
if (error48.stack)
|
|
119346
|
-
lines.push(
|
|
119490
|
+
lines.push(import_picocolors16.default.dim(error48.stack.split(`
|
|
119347
119491
|
`).slice(1, 4).join(`
|
|
119348
119492
|
`)));
|
|
119349
119493
|
} else {
|
|
119350
|
-
lines.push(`${
|
|
119494
|
+
lines.push(`${import_picocolors16.default.red("unexpected error:")} ${String(error48)}`);
|
|
119351
119495
|
}
|
|
119352
119496
|
try {
|
|
119353
119497
|
await writer.write(encoder.encode(`${lines.join(`
|
|
@@ -119360,7 +119504,7 @@ async function renderError(stderr, error48) {
|
|
|
119360
119504
|
// package.json
|
|
119361
119505
|
var package_default = {
|
|
119362
119506
|
name: "percher",
|
|
119363
|
-
version: "0.5.
|
|
119507
|
+
version: "0.5.17",
|
|
119364
119508
|
description: "CLI for the Percher hosting platform — publish apps with one command",
|
|
119365
119509
|
type: "module",
|
|
119366
119510
|
bin: {
|
|
@@ -119457,7 +119601,7 @@ async function showTelemetryNotice() {
|
|
|
119457
119601
|
}
|
|
119458
119602
|
|
|
119459
119603
|
// src/version-check.ts
|
|
119460
|
-
var
|
|
119604
|
+
var import_picocolors17 = __toESM(require_picocolors(), 1);
|
|
119461
119605
|
async function checkForUpdates() {
|
|
119462
119606
|
try {
|
|
119463
119607
|
const res = await fetch("https://registry.npmjs.org/percher/latest", {
|
|
@@ -119468,9 +119612,9 @@ async function checkForUpdates() {
|
|
|
119468
119612
|
const data2 = await res.json();
|
|
119469
119613
|
const latest = data2.version;
|
|
119470
119614
|
if (latest && latest !== VERSION) {
|
|
119471
|
-
console.error(
|
|
119615
|
+
console.error(import_picocolors17.default.yellow(`
|
|
119472
119616
|
Update available: ${VERSION} → ${latest}`));
|
|
119473
|
-
console.error(
|
|
119617
|
+
console.error(import_picocolors17.default.dim(`Run: bunx percher@latest
|
|
119474
119618
|
`));
|
|
119475
119619
|
}
|
|
119476
119620
|
} catch {}
|
|
@@ -119491,6 +119635,7 @@ async function run(argv, ctxOverride) {
|
|
|
119491
119635
|
registerMigrateCommands(cli, ctx);
|
|
119492
119636
|
registerSharingCommands(cli, ctx);
|
|
119493
119637
|
registerStatusCommands(cli, ctx);
|
|
119638
|
+
registerTokenCommands(cli, ctx);
|
|
119494
119639
|
registerTransfersCommands(cli, ctx);
|
|
119495
119640
|
registerAdminCommands(cli, ctx);
|
|
119496
119641
|
cli.help();
|
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "percher",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "CLI for the Percher hosting platform
|
|
3
|
+
"version": "0.5.17",
|
|
4
|
+
"description": "CLI for the Percher hosting platform — publish apps with one command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"percher": "./dist/bin/percher.js"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/commands/token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAY/B,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAwHlE"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as core from "@percher/core";
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
import { SilentExitError, writeLine } from "../cli-utils";
|
|
4
|
+
const VALID_SCOPES = ["deploy", "env", "read", "full"];
|
|
5
|
+
function scopeLabel(scopes, appName) {
|
|
6
|
+
const s = scopes && scopes.length > 0 ? scopes.join("+") : "full";
|
|
7
|
+
return appName ? `${s} · ${appName}` : `${s} · all apps`;
|
|
8
|
+
}
|
|
9
|
+
export function registerTokenCommands(cli, ctx) {
|
|
10
|
+
// cac matches commands by single first-token equality, so `token create
|
|
11
|
+
// <name>` routes here with action="create". `[arg]` is the token label for
|
|
12
|
+
// create and the token id for revoke.
|
|
13
|
+
cli
|
|
14
|
+
.command("token [action] [arg]", "Manage API tokens: create | list | revoke")
|
|
15
|
+
.option("--scope <scope>", "(create) deploy | env | read | full (default: full)")
|
|
16
|
+
.option("--app <name>", "(create) bind the token to a single app")
|
|
17
|
+
.option("--ttl-days <n>", "(create) token lifetime in days")
|
|
18
|
+
.action(async (action, arg, options) => {
|
|
19
|
+
if (!ctx.client.token) {
|
|
20
|
+
await writeLine(ctx, `${pc.red("✗")} Not logged in. Run: percher login`);
|
|
21
|
+
throw new SilentExitError();
|
|
22
|
+
}
|
|
23
|
+
if (action === "create") {
|
|
24
|
+
if (!arg) {
|
|
25
|
+
await writeLine(ctx, `${pc.red("✗")} A name is required. Usage: percher token create <name> [--scope deploy] [--app <name>]`);
|
|
26
|
+
throw new SilentExitError();
|
|
27
|
+
}
|
|
28
|
+
const scope = (options.scope ?? "full");
|
|
29
|
+
if (!VALID_SCOPES.includes(scope)) {
|
|
30
|
+
await writeLine(ctx, `${pc.red("✗")} Invalid --scope "${options.scope}". Use one of: ${VALID_SCOPES.join(", ")}.`);
|
|
31
|
+
throw new SilentExitError();
|
|
32
|
+
}
|
|
33
|
+
const ttlDays = options.ttlDays !== undefined ? Number(options.ttlDays) : undefined;
|
|
34
|
+
if (ttlDays !== undefined && (!Number.isInteger(ttlDays) || ttlDays <= 0)) {
|
|
35
|
+
await writeLine(ctx, `${pc.red("✗")} --ttl-days must be a positive whole number.`);
|
|
36
|
+
throw new SilentExitError();
|
|
37
|
+
}
|
|
38
|
+
const created = await core.tokenCreate(ctx, {
|
|
39
|
+
name: arg,
|
|
40
|
+
scope,
|
|
41
|
+
app: options.app,
|
|
42
|
+
ttlDays,
|
|
43
|
+
});
|
|
44
|
+
await writeLine(ctx, `${pc.green("✓")} Token created: ${pc.bold(created.name)} ${pc.dim(`(${scopeLabel(created.scopes, created.appName)})`)}`);
|
|
45
|
+
await writeLine(ctx, "");
|
|
46
|
+
await writeLine(ctx, ` ${pc.bold(created.token)}`);
|
|
47
|
+
await writeLine(ctx, pc.yellow(" ↑ Store this now — the secret is shown only once and can't be retrieved."));
|
|
48
|
+
await writeLine(ctx, "");
|
|
49
|
+
await writeLine(ctx, pc.dim(" Use it in CI / an agent:"));
|
|
50
|
+
await writeLine(ctx, pc.dim(` PERCHER_TOKEN=${created.token} bunx percher publish`));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (action === "list") {
|
|
54
|
+
const tokens = await core.tokenList(ctx);
|
|
55
|
+
if (tokens.length === 0) {
|
|
56
|
+
await writeLine(ctx, pc.dim("No API tokens."));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
for (const t of tokens) {
|
|
60
|
+
const expires = t.expiresAt
|
|
61
|
+
? `expires ${new Date(t.expiresAt).toISOString().slice(0, 10)}`
|
|
62
|
+
: "no expiry";
|
|
63
|
+
await writeLine(ctx, `${pc.bold(t.id)} ${t.name.padEnd(20)} ${pc.dim(scopeLabel(t.scopes, t.appName))} ${pc.dim(expires)}`);
|
|
64
|
+
}
|
|
65
|
+
await writeLine(ctx, "");
|
|
66
|
+
await writeLine(ctx, pc.dim("Revoke one with: percher token revoke <id>"));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (action === "revoke") {
|
|
70
|
+
if (!arg) {
|
|
71
|
+
await writeLine(ctx, `${pc.red("✗")} A token id is required. Usage: percher token revoke <id> (list ids with \`percher token list\`).`);
|
|
72
|
+
throw new SilentExitError();
|
|
73
|
+
}
|
|
74
|
+
await core.tokenRevoke(ctx, { id: arg });
|
|
75
|
+
await writeLine(ctx, `${pc.green("✓")} Token revoked.`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
throw new Error(`Unknown token action "${action ?? ""}". Use: create | list | revoke.`);
|
|
79
|
+
});
|
|
80
|
+
// Help-only registrations (unreachable — cac falls through to the parent
|
|
81
|
+
// `token [action] ...`), so `--help` surfaces each subcommand.
|
|
82
|
+
cli
|
|
83
|
+
.command("token create <name>", "Mint a scoped API token (the secret is shown once)")
|
|
84
|
+
.option("--scope <scope>", "deploy | env | read | full (default: full)")
|
|
85
|
+
.option("--app <name>", "Bind the token to a single app")
|
|
86
|
+
.option("--ttl-days <n>", "Token lifetime in days")
|
|
87
|
+
.action(async () => {
|
|
88
|
+
/* Unreachable — handled by `token [action] ...`. */
|
|
89
|
+
});
|
|
90
|
+
cli.command("token list", "List your API tokens with scope + bound app").action(async () => {
|
|
91
|
+
/* Unreachable — handled by `token [action] ...`. */
|
|
92
|
+
});
|
|
93
|
+
cli.command("token revoke <id>", "Revoke an API token by id").action(async () => {
|
|
94
|
+
/* Unreachable — handled by `token [action] ...`. */
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/commands/token.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAGhE,SAAS,UAAU,CAAC,MAAuB,EAAE,OAAsB;IACjE,MAAM,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAClE,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAQ,EAAE,GAAY;IAC1D,wEAAwE;IACxE,2EAA2E;IAC3E,sCAAsC;IACtC,GAAG;SACA,OAAO,CAAC,sBAAsB,EAAE,2CAA2C,CAAC;SAC5E,MAAM,CAAC,iBAAiB,EAAE,qDAAqD,CAAC;SAChF,MAAM,CAAC,cAAc,EAAE,yCAAyC,CAAC;SACjE,MAAM,CAAC,gBAAgB,EAAE,iCAAiC,CAAC;SAC3D,MAAM,CACL,KAAK,EACH,MAA0B,EAC1B,GAAuB,EACvB,OAAoE,EACpE,EAAE;QACF,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACtB,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YACzE,MAAM,IAAI,eAAe,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,SAAS,CACb,GAAG,EACH,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,yFAAyF,CACxG,CAAC;gBACF,MAAM,IAAI,eAAe,EAAE,CAAC;YAC9B,CAAC;YACD,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,MAAM,CAAU,CAAC;YACjD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,MAAM,SAAS,CACb,GAAG,EACH,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,qBAAqB,OAAO,CAAC,KAAK,kBAAkB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC7F,CAAC;gBACF,MAAM,IAAI,eAAe,EAAE,CAAC;YAC9B,CAAC;YACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACpF,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC1E,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;gBACnF,MAAM,IAAI,eAAe,EAAE,CAAC;YAC9B,CAAC;YACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE;gBAC1C,IAAI,EAAE,GAAG;gBACT,KAAK;gBACL,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,OAAO;aACR,CAAC,CAAC;YACH,MAAM,SAAS,CACb,GAAG,EACH,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CACjE,IAAI,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CACnD,EAAE,CACJ,CAAC;YACF,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACzB,MAAM,SAAS,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,CACb,GAAG,EACH,EAAE,CAAC,MAAM,CAAC,4EAA4E,CAAC,CACxF,CAAC;YACF,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACzB,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC;YAC3D,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,qBAAqB,OAAO,CAAC,KAAK,uBAAuB,CAAC,CAAC,CAAC;YACxF,OAAO;QACT,CAAC;QAED,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;gBACvB,MAAM,OAAO,GAAG,CAAC,CAAC,SAAS;oBACzB,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;oBAC/D,CAAC,CAAC,WAAW,CAAC;gBAChB,MAAM,SAAS,CACb,GAAG,EACH,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAC9C,UAAU,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAChC,KAAK,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CACxB,CAAC;YACJ,CAAC;YACD,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACzB,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,SAAS,CACb,GAAG,EACH,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,mGAAmG,CAClH,CAAC;gBACF,MAAM,IAAI,eAAe,EAAE,CAAC;YAC9B,CAAC;YACD,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YACzC,MAAM,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,IAAI,EAAE,iCAAiC,CAAC,CAAC;IAC1F,CAAC,CACF,CAAC;IAEJ,yEAAyE;IACzE,+DAA+D;IAC/D,GAAG;SACA,OAAO,CAAC,qBAAqB,EAAE,oDAAoD,CAAC;SACpF,MAAM,CAAC,iBAAiB,EAAE,4CAA4C,CAAC;SACvE,MAAM,CAAC,cAAc,EAAE,gCAAgC,CAAC;SACxD,MAAM,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;SAClD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,oDAAoD;IACtD,CAAC,CAAC,CAAC;IACL,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,6CAA6C,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;QACzF,oDAAoD;IACtD,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,2BAA2B,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;QAC9E,oDAAoD;IACtD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAsB7C,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAqEhF"}
|
package/dist/src/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { registerGithubCommands } from "./commands/github";
|
|
|
12
12
|
import { registerMigrateCommands } from "./commands/migrate";
|
|
13
13
|
import { registerSharingCommands } from "./commands/sharing";
|
|
14
14
|
import { registerStatusCommands } from "./commands/status";
|
|
15
|
+
import { registerTokenCommands } from "./commands/token";
|
|
15
16
|
import { registerTransfersCommands } from "./commands/transfers";
|
|
16
17
|
import { createCliContext } from "./context";
|
|
17
18
|
import { renderError } from "./output";
|
|
@@ -31,6 +32,7 @@ export async function run(argv, ctxOverride) {
|
|
|
31
32
|
registerMigrateCommands(cli, ctx);
|
|
32
33
|
registerSharingCommands(cli, ctx);
|
|
33
34
|
registerStatusCommands(cli, ctx);
|
|
35
|
+
registerTokenCommands(cli, ctx);
|
|
34
36
|
registerTransfersCommands(cli, ctx);
|
|
35
37
|
registerAdminCommands(cli, ctx);
|
|
36
38
|
cli.help();
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,3 +30,62 @@ export async function complete(
|
|
|
30
30
|
const data = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> };
|
|
31
31
|
return data.choices?.[0]?.message?.content ?? "";
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Streaming variant of {@link complete} — calls `onToken` with each text delta
|
|
36
|
+
* as it arrives and resolves with the full text. Same auth + billing as
|
|
37
|
+
* `complete` (keyless, billed to the app owner). Use it for a typewriter UI:
|
|
38
|
+
*
|
|
39
|
+
* const full = await streamComplete("Write a haiku", (t) => { output.value += t; });
|
|
40
|
+
*/
|
|
41
|
+
export async function streamComplete(
|
|
42
|
+
prompt: string,
|
|
43
|
+
onToken: (delta: string) => void,
|
|
44
|
+
opts?: { model?: string; maxTokens?: number },
|
|
45
|
+
): Promise<string> {
|
|
46
|
+
if (!AI_URL) throw new Error("Managed inference isn't configured for this app.");
|
|
47
|
+
if (!pb.authStore.isValid) throw new Error("Sign in to use AI.");
|
|
48
|
+
const res = await fetch(AI_URL, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: { "content-type": "application/json", authorization: pb.authStore.token },
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
model: opts?.model,
|
|
53
|
+
max_tokens: opts?.maxTokens ?? 512,
|
|
54
|
+
messages: [{ role: "user", content: prompt }],
|
|
55
|
+
stream: true,
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok || !res.body) throw new Error(`AI request failed (${res.status})`);
|
|
59
|
+
|
|
60
|
+
const reader = res.body.getReader();
|
|
61
|
+
const decoder = new TextDecoder();
|
|
62
|
+
let buffer = "";
|
|
63
|
+
let full = "";
|
|
64
|
+
for (;;) {
|
|
65
|
+
const { done, value } = await reader.read();
|
|
66
|
+
if (done) break;
|
|
67
|
+
buffer += decoder.decode(value, { stream: true });
|
|
68
|
+
// SSE events are separated by a blank line; parse each complete one.
|
|
69
|
+
let sep = buffer.indexOf("\n\n");
|
|
70
|
+
while (sep !== -1) {
|
|
71
|
+
const event = buffer.slice(0, sep);
|
|
72
|
+
buffer = buffer.slice(sep + 2);
|
|
73
|
+
sep = buffer.indexOf("\n\n");
|
|
74
|
+
const line = event.startsWith("data:") ? event.slice(5).trim() : "";
|
|
75
|
+
if (!line || line === "[DONE]") continue;
|
|
76
|
+
try {
|
|
77
|
+
const chunk = JSON.parse(line) as {
|
|
78
|
+
choices?: Array<{ delta?: { content?: string } }>;
|
|
79
|
+
};
|
|
80
|
+
const delta = chunk.choices?.[0]?.delta?.content ?? "";
|
|
81
|
+
if (delta) {
|
|
82
|
+
full += delta;
|
|
83
|
+
onToken(delta);
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
/* ignore keep-alive / non-JSON lines */
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return full;
|
|
91
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "percher",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "CLI for the Percher hosting platform
|
|
3
|
+
"version": "0.5.17",
|
|
4
|
+
"description": "CLI for the Percher hosting platform — publish apps with one command",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"percher": "./dist/bin/percher.js"
|