@hasna/skills 0.1.36 → 0.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +335 -97
- package/bin/mcp.js +34 -9
- package/dist/index.js +20 -7
- package/package.json +1 -1
- package/skills/_common/auth.ts +8 -12
- package/skills/_common/http-client.ts +4 -4
- package/skills/audio/SKILL.md +1 -1
- package/skills/codefix/package.json +4 -4
- package/skills/codefix/src/index-local.ts +2 -1
- package/skills/codefix/src/index.ts +2 -108
- package/skills/convert/SKILL.md +2 -2
- package/skills/convert/package.json +4 -4
- package/skills/convert/src/index-local.ts +2 -1
- package/skills/convert/src/index.ts +2 -108
- package/skills/deploy/package.json +3 -3
- package/skills/deploy/src/http-client.ts +4 -4
- package/skills/deploy/src/index-local.ts +2 -1
- package/skills/deploy/src/index.ts +2 -109
- package/skills/extract/package.json +4 -4
- package/skills/extract/src/index-local.ts +2 -1
- package/skills/extract/src/index.ts +2 -108
- package/skills/image/SKILL.md +2 -2
- package/skills/music/SKILL.md +1 -1
- package/skills/transcript/SKILL.md +2 -2
- package/skills/video/SKILL.md +1 -1
- package/skills/write/SKILL.md +2 -2
- package/skills/write/package.json +4 -4
- package/skills/write/src/index-local.ts +2 -1
- package/skills/write/src/index.ts +2 -108
package/bin/index.js
CHANGED
|
@@ -1910,7 +1910,7 @@ var package_default;
|
|
|
1910
1910
|
var init_package = __esm(() => {
|
|
1911
1911
|
package_default = {
|
|
1912
1912
|
name: "@hasna/skills",
|
|
1913
|
-
version: "0.1.
|
|
1913
|
+
version: "0.1.38",
|
|
1914
1914
|
description: "Skills library for AI coding agents",
|
|
1915
1915
|
type: "module",
|
|
1916
1916
|
bin: {
|
|
@@ -6661,6 +6661,7 @@ var init_pricing = __esm(() => {
|
|
|
6661
6661
|
init_skill_aliases();
|
|
6662
6662
|
MUSIC_ALBUM_SONG_COUNTS = [7, 14, 21];
|
|
6663
6663
|
PREMIUM_SKILLS = [
|
|
6664
|
+
{ slug: "icon-pack", displayName: "Icon Pack", tier: "premium", costCents: 200, providers: ["hosted"], description: "Hosted coordinated icon pack with SVGs, transparent PNGs, size variants, and manifest" },
|
|
6664
6665
|
{ slug: "logo-design", displayName: "Logo Design", tier: "premium", costCents: 50, providers: ["hosted"], description: "Hosted multi-variant logo package with transparent PNGs, vector-style SVGs, usage notes, and manifest" },
|
|
6665
6666
|
{ slug: "deepresearch", displayName: "Deep Research", tier: "premium", costCents: 20, providers: ["exa"], description: "Agentic web research with semantic search and synthesis" },
|
|
6666
6667
|
{ slug: "playlist-maker", displayName: "Playlist Maker", tier: "premium", costCents: 30, providers: ["exa", "gemini-3-pro"], description: "Curated playlist with research, track selection, and album art" },
|
|
@@ -6773,8 +6774,8 @@ function sanitizePublicDiscoveryText(text) {
|
|
|
6773
6774
|
function publicDiscoveryEnvVars(skillName, envVars) {
|
|
6774
6775
|
if (!isPremiumSkill(skillName))
|
|
6775
6776
|
return envVars;
|
|
6776
|
-
const filtered = envVars.filter((envVar) => !VENDOR_ENV_PREFIXES.some((prefix) => envVar.startsWith(prefix)));
|
|
6777
|
-
return filtered.includes("
|
|
6777
|
+
const filtered = envVars.filter((envVar) => envVar !== "SKILL_API_KEY" && !VENDOR_ENV_PREFIXES.some((prefix) => envVar.startsWith(prefix)));
|
|
6778
|
+
return filtered.includes("SKILLS_API_KEY") ? filtered : ["SKILLS_API_KEY", ...filtered];
|
|
6778
6779
|
}
|
|
6779
6780
|
function publicDiscoveryDependencies(skillName, dependencies) {
|
|
6780
6781
|
if (!isPremiumSkill(skillName))
|
|
@@ -6790,7 +6791,7 @@ function publicDiscoveryDocumentation(skill, documentation) {
|
|
|
6790
6791
|
`# ${skill.displayName || skill.name}`,
|
|
6791
6792
|
sanitizePublicDiscoveryText(skill.description),
|
|
6792
6793
|
`Pricing: ${getPublicSkillPricing(skill.name).formattedCost}.`,
|
|
6793
|
-
"Set `
|
|
6794
|
+
"Set `SKILLS_API_KEY` or run `skills auth login` for hosted runtime execution. Runtime routing and model selection are managed by the hosted Skills runtime."
|
|
6794
6795
|
].join(`
|
|
6795
6796
|
|
|
6796
6797
|
`);
|
|
@@ -20907,6 +20908,8 @@ function clearAuthConfig() {
|
|
|
20907
20908
|
function getApiKey() {
|
|
20908
20909
|
if (process.env.SKILLS_API_KEY)
|
|
20909
20910
|
return process.env.SKILLS_API_KEY;
|
|
20911
|
+
if (process.env.SKILL_API_KEY)
|
|
20912
|
+
return process.env.SKILL_API_KEY;
|
|
20910
20913
|
return getAuthConfig()?.apiKey || null;
|
|
20911
20914
|
}
|
|
20912
20915
|
function normalizeSkillsApiOrigin(apiUrl) {
|
|
@@ -21315,6 +21318,18 @@ function handleBrowseError(error48) {
|
|
|
21315
21318
|
console.error(chalk3.red(error48.message));
|
|
21316
21319
|
process.exitCode = 1;
|
|
21317
21320
|
}
|
|
21321
|
+
async function writeJson(value, space) {
|
|
21322
|
+
const text = `${JSON.stringify(value, null, space)}
|
|
21323
|
+
`;
|
|
21324
|
+
await new Promise((resolve, reject) => {
|
|
21325
|
+
process.stdout.write(text, (error48) => {
|
|
21326
|
+
if (error48)
|
|
21327
|
+
reject(error48);
|
|
21328
|
+
else
|
|
21329
|
+
resolve();
|
|
21330
|
+
});
|
|
21331
|
+
});
|
|
21332
|
+
}
|
|
21318
21333
|
async function getBrowseRegistry(options) {
|
|
21319
21334
|
if (options.remote)
|
|
21320
21335
|
return loadRemoteRegistry();
|
|
@@ -21339,11 +21354,11 @@ async function handleList(options) {
|
|
|
21339
21354
|
if (options.json) {
|
|
21340
21355
|
const meta4 = getInstallMeta();
|
|
21341
21356
|
const registry4 = loadRegistry();
|
|
21342
|
-
|
|
21357
|
+
await writeJson(installed.map((name) => {
|
|
21343
21358
|
const m = meta4.skills[name];
|
|
21344
21359
|
const s = registry4.find((r) => r.name === name);
|
|
21345
21360
|
return { name, version: m?.version ?? null, installedAt: m?.installedAt ?? null, source: s?.source ?? "official" };
|
|
21346
|
-
}))
|
|
21361
|
+
}));
|
|
21347
21362
|
return;
|
|
21348
21363
|
}
|
|
21349
21364
|
if (installed.length === 0) {
|
|
@@ -21382,7 +21397,7 @@ Available: ${categories.join(", ")}`);
|
|
|
21382
21397
|
skills = skills.filter((s) => s.tags.some((tag) => tagFilter.includes(tag.toLowerCase())));
|
|
21383
21398
|
const output = enrichDiscovery(skills);
|
|
21384
21399
|
if (options.json) {
|
|
21385
|
-
|
|
21400
|
+
await writeJson(output, 2);
|
|
21386
21401
|
return;
|
|
21387
21402
|
}
|
|
21388
21403
|
if (brief) {
|
|
@@ -21401,7 +21416,7 @@ ${category} (${skills.length}):
|
|
|
21401
21416
|
const skills = registry2.filter((s) => s.tags.some((tag) => tagFilter.includes(tag.toLowerCase())));
|
|
21402
21417
|
const output = enrichDiscovery(skills);
|
|
21403
21418
|
if (options.json) {
|
|
21404
|
-
|
|
21419
|
+
await writeJson(output, 2);
|
|
21405
21420
|
return;
|
|
21406
21421
|
}
|
|
21407
21422
|
if (brief) {
|
|
@@ -21418,7 +21433,7 @@ Skills matching tags [${tagFilter.join(", ")}] (${skills.length}):
|
|
|
21418
21433
|
}
|
|
21419
21434
|
const allSkills = enrichDiscovery(registry2);
|
|
21420
21435
|
if (options.json) {
|
|
21421
|
-
|
|
21436
|
+
await writeJson(allSkills, 2);
|
|
21422
21437
|
return;
|
|
21423
21438
|
}
|
|
21424
21439
|
if (fmt === "compact") {
|
|
@@ -21480,7 +21495,7 @@ Available: ${categories.join(", ")}`);
|
|
|
21480
21495
|
const fmt = !options.json ? options.format : undefined;
|
|
21481
21496
|
const output = enrichDiscovery(results);
|
|
21482
21497
|
if (options.json) {
|
|
21483
|
-
|
|
21498
|
+
await writeJson(output, 2);
|
|
21484
21499
|
return;
|
|
21485
21500
|
}
|
|
21486
21501
|
if (results.length === 0) {
|
|
@@ -21524,7 +21539,7 @@ async function handleCategories(options) {
|
|
|
21524
21539
|
count: registry2.filter((skill) => skill.category === category).length
|
|
21525
21540
|
}));
|
|
21526
21541
|
if (options.json) {
|
|
21527
|
-
|
|
21542
|
+
await writeJson(cats, 2);
|
|
21528
21543
|
return;
|
|
21529
21544
|
}
|
|
21530
21545
|
console.log(chalk3.bold(`
|
|
@@ -21541,7 +21556,7 @@ async function handleTags(options) {
|
|
|
21541
21556
|
}
|
|
21542
21557
|
const sorted = Array.from(tagCounts.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([name, count]) => ({ name, count }));
|
|
21543
21558
|
if (options.json) {
|
|
21544
|
-
|
|
21559
|
+
await writeJson(sorted, 2);
|
|
21545
21560
|
return;
|
|
21546
21561
|
}
|
|
21547
21562
|
console.log(chalk3.bold(`
|
|
@@ -21607,7 +21622,8 @@ function getSkillRequirements(name) {
|
|
|
21607
21622
|
envVars.delete(envVar);
|
|
21608
21623
|
}
|
|
21609
21624
|
}
|
|
21610
|
-
envVars.
|
|
21625
|
+
envVars.delete("SKILL_API_KEY");
|
|
21626
|
+
envVars.add("SKILLS_API_KEY");
|
|
21611
21627
|
}
|
|
21612
21628
|
const systemDeps = new Set;
|
|
21613
21629
|
const depPatterns = [
|
|
@@ -38590,7 +38606,7 @@ var MCP_CONTRACT_SCHEMA_VERSION = 1, stringSchema = (description) => ({
|
|
|
38590
38606
|
type: "array",
|
|
38591
38607
|
items,
|
|
38592
38608
|
...description ? { description } : {}
|
|
38593
|
-
}), skillNameInput, optionalAgentInput, scopeInput, runInputSchema, runArgsSchema, errorSchema, pricingSchema, skillSummarySchema, validationMessageSchema, validationOutputSchema, installOutputSchema, runOutputSchema, toolContracts, contracts, resourceContracts;
|
|
38609
|
+
}), skillNameInput, optionalAgentInput, scopeInput, runInputSchema, runArgsSchema, paidRunApprovalSchema, errorSchema, pricingSchema, skillSummarySchema, validationMessageSchema, validationOutputSchema, installOutputSchema, runOutputSchema, toolContracts, contracts, resourceContracts;
|
|
38594
38610
|
var init_mcp_contracts = __esm(() => {
|
|
38595
38611
|
skillNameInput = stringSchema("skill name or alias.");
|
|
38596
38612
|
optionalAgentInput = stringSchema("Optional target agent slug. Use MCP registration instead of direct skill-folder installs.");
|
|
@@ -38610,6 +38626,10 @@ var init_mcp_contracts = __esm(() => {
|
|
|
38610
38626
|
default: [],
|
|
38611
38627
|
description: "CLI-style string arguments passed to the skill."
|
|
38612
38628
|
};
|
|
38629
|
+
paidRunApprovalSchema = {
|
|
38630
|
+
type: "boolean",
|
|
38631
|
+
description: "Set true only after the user has approved the quoted cost for a paid hosted run."
|
|
38632
|
+
};
|
|
38613
38633
|
errorSchema = objectSchema({
|
|
38614
38634
|
code: stringSchema("Stable error code."),
|
|
38615
38635
|
message: stringSchema("Human-readable error message."),
|
|
@@ -38837,11 +38857,16 @@ var init_mcp_contracts = __esm(() => {
|
|
|
38837
38857
|
name: "run_skill",
|
|
38838
38858
|
title: "Run Skill",
|
|
38839
38859
|
description: "Run a skill locally or through a configured remote runner.",
|
|
38840
|
-
params: ["name", "input?", "args?"],
|
|
38860
|
+
params: ["name", "input?", "args?", "approved?"],
|
|
38841
38861
|
category: "execution",
|
|
38842
38862
|
sideEffects: "local-process-or-remote-run",
|
|
38843
38863
|
stable: true,
|
|
38844
|
-
inputSchema: objectSchema({
|
|
38864
|
+
inputSchema: objectSchema({
|
|
38865
|
+
name: skillNameInput,
|
|
38866
|
+
input: runInputSchema,
|
|
38867
|
+
args: runArgsSchema,
|
|
38868
|
+
approved: paidRunApprovalSchema
|
|
38869
|
+
}, ["name"]),
|
|
38845
38870
|
outputSchema: runOutputSchema
|
|
38846
38871
|
},
|
|
38847
38872
|
{
|
|
@@ -39529,9 +39554,10 @@ function registerOperationTools(server) {
|
|
|
39529
39554
|
inputSchema: {
|
|
39530
39555
|
name: exports_external.string(),
|
|
39531
39556
|
input: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
39532
|
-
args: exports_external.array(exports_external.string()).optional()
|
|
39557
|
+
args: exports_external.array(exports_external.string()).optional(),
|
|
39558
|
+
approved: exports_external.boolean().optional()
|
|
39533
39559
|
}
|
|
39534
|
-
}, async ({ name, input, args }) => {
|
|
39560
|
+
}, async ({ name, input, args, approved }) => {
|
|
39535
39561
|
const skill = getSkill(name);
|
|
39536
39562
|
if (!skill) {
|
|
39537
39563
|
return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
|
|
@@ -39569,6 +39595,17 @@ function registerOperationTools(server) {
|
|
|
39569
39595
|
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
39570
39596
|
return mcpError("AUTH_REQUIRED", `${error48}. Local run metadata: ${run.paths.runDir}/run.json`, ["skills auth login"]);
|
|
39571
39597
|
}
|
|
39598
|
+
if (isPremiumSkill2(skillName) && apiKey && approved !== true) {
|
|
39599
|
+
const cost = formatCost2(costCents ?? 0);
|
|
39600
|
+
const error48 = `${skillName} is a paid hosted skill (${cost}). Call quote_skill first, then call run_skill with approved: true after user approval.`;
|
|
39601
|
+
writeRunLogs(runContext, "", error48 + `
|
|
39602
|
+
`);
|
|
39603
|
+
const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
|
|
39604
|
+
return mcpError("APPROVAL_REQUIRED", `${error48}. Local run metadata: ${run.paths.runDir}/run.json`, [
|
|
39605
|
+
"quote_skill",
|
|
39606
|
+
"run_skill approved=true"
|
|
39607
|
+
]);
|
|
39608
|
+
}
|
|
39572
39609
|
if (isPremiumSkill2(skillName) && apiKey) {
|
|
39573
39610
|
try {
|
|
39574
39611
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
@@ -40724,7 +40761,7 @@ import { dirname as dirname5, join as join16 } from "path";
|
|
|
40724
40761
|
import { createInterface } from "readline";
|
|
40725
40762
|
function registerRuntime(parent) {
|
|
40726
40763
|
parent.command("quote").argument("<skill>", "Skill name").argument("[args...]", "Arguments that affect pricing, such as --count 8").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output quote as JSON", false).description("Quote a skill run before spending account balance").action((name, args2, options) => handleQuote(name, args2, options));
|
|
40727
|
-
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options) => handleRun(name, args2, options));
|
|
40764
|
+
parent.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output result as JSON", false).option("-y, --yes", "Approve paid hosted execution without an interactive prompt", false).option("--wait", "Poll remote runs until a terminal status", false).option("--poll-interval-ms <ms>", "Remote polling interval in milliseconds", "1000").option("--poll-timeout-ms <ms>", "Maximum time to wait for a remote run", "300000").description("Run a skill directly").action(async (name, args2, options) => handleRun(name, args2, options));
|
|
40728
40765
|
const runs = parent.command("runs").description("Inspect local skill run records");
|
|
40729
40766
|
runs.command("list").option("--json", "Output as JSON", false).option("--limit <n>", "Maximum number of runs", "20").description("List recent skill runs").action((options) => handleRunsList(options));
|
|
40730
40767
|
runs.command("show").argument("<run-id>", "Run id").option("--json", "Output as JSON", false).description("Show a skill run record").action((runId, options) => handleRunsShow(runId, options));
|
|
@@ -40919,6 +40956,34 @@ async function handleRun(name, args2, options) {
|
|
|
40919
40956
|
process.exitCode = 1;
|
|
40920
40957
|
return;
|
|
40921
40958
|
}
|
|
40959
|
+
const approval = await approvePaidHostedRun({
|
|
40960
|
+
skill: skill.name,
|
|
40961
|
+
formattedCost: publicPricing.formattedCost,
|
|
40962
|
+
json: options.json,
|
|
40963
|
+
yes: Boolean(options.yes)
|
|
40964
|
+
});
|
|
40965
|
+
if (!approval.approved) {
|
|
40966
|
+
writeRunLogs(runContext, "", approval.error + `
|
|
40967
|
+
`);
|
|
40968
|
+
const run = completeSkillRun(runContext, { status: "failed", error: approval.error, costCents });
|
|
40969
|
+
if (options.json) {
|
|
40970
|
+
console.log(JSON.stringify({
|
|
40971
|
+
contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
|
|
40972
|
+
skill: skill.name,
|
|
40973
|
+
args: args2,
|
|
40974
|
+
exitCode: 1,
|
|
40975
|
+
remote: true,
|
|
40976
|
+
approvalRequired: true,
|
|
40977
|
+
error: approval.error,
|
|
40978
|
+
pricing: publicPricing,
|
|
40979
|
+
run
|
|
40980
|
+
}, null, 2));
|
|
40981
|
+
} else {
|
|
40982
|
+
console.error(chalk8.red(approval.error));
|
|
40983
|
+
}
|
|
40984
|
+
process.exitCode = 1;
|
|
40985
|
+
return;
|
|
40986
|
+
}
|
|
40922
40987
|
try {
|
|
40923
40988
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
40924
40989
|
const client = new RemoteSkillsClient2(apiKey);
|
|
@@ -41029,6 +41094,18 @@ async function handleRun(name, args2, options) {
|
|
|
41029
41094
|
}
|
|
41030
41095
|
process.exitCode = result.exitCode;
|
|
41031
41096
|
}
|
|
41097
|
+
async function approvePaidHostedRun(params) {
|
|
41098
|
+
if (params.yes)
|
|
41099
|
+
return { approved: true };
|
|
41100
|
+
const error48 = `${params.skill} is a paid hosted skill (${params.formattedCost}). Run skills quote ${params.skill} first, then rerun with --yes to approve the charge.`;
|
|
41101
|
+
if (params.json || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
41102
|
+
return { approved: false, error: error48 };
|
|
41103
|
+
}
|
|
41104
|
+
const answer = await promptLine(`Run paid hosted skill ${params.skill} for ${params.formattedCost}? [y/N] `);
|
|
41105
|
+
if (/^(y|yes)$/i.test(answer.trim()))
|
|
41106
|
+
return { approved: true };
|
|
41107
|
+
return { approved: false, error: `Paid hosted run for ${params.skill} was not approved.` };
|
|
41108
|
+
}
|
|
41032
41109
|
function writeBlogArticleValidationError(errors4, json2) {
|
|
41033
41110
|
const payload = {
|
|
41034
41111
|
error: "invalid blog article options",
|
|
@@ -41829,26 +41906,46 @@ Scheduled skills (${schedules.length}):
|
|
|
41829
41906
|
if (!ok)
|
|
41830
41907
|
process.exitCode = 1;
|
|
41831
41908
|
});
|
|
41832
|
-
scheduleCmd.command("run").option("--dry-run", "Show which schedules are due without running them", false).option("--json", "Output as JSON", false).description("Execute all due schedules now").action(async (options) => {
|
|
41909
|
+
scheduleCmd.command("run").option("--dry-run", "Show which schedules are due without running them", false).option("--allow-paid", "Allow due paid hosted schedules to spend account balance", false).option("--max-paid-cents <cents>", "Maximum paid hosted spend approved for this run").option("--json", "Output as JSON", false).description("Execute all due schedules now").action(async (options) => {
|
|
41833
41910
|
const due = getDueSchedules();
|
|
41834
41911
|
if (!due.length) {
|
|
41835
41912
|
console.log(options.json ? JSON.stringify({ ran: 0, schedules: [] }) : chalk10.dim("No schedules are due."));
|
|
41836
41913
|
return;
|
|
41837
41914
|
}
|
|
41915
|
+
const dueDetails = await Promise.all(due.map((schedule) => describeDueSchedule(schedule)));
|
|
41916
|
+
const paidTotalCents = dueDetails.reduce((total, schedule) => total + (schedule.costCents ?? 0), 0);
|
|
41838
41917
|
if (options.dryRun) {
|
|
41839
|
-
console.log(options.json ? JSON.stringify({ due:
|
|
41918
|
+
console.log(options.json ? JSON.stringify({ due: dueDetails, paidTotalCents, paidTotal: formatCost2(paidTotalCents) }) : chalk10.bold(`${due.length} schedule(s) due:
|
|
41840
41919
|
`));
|
|
41841
41920
|
if (!options.json)
|
|
41842
|
-
for (const s of
|
|
41843
|
-
console.log(` ${chalk10.cyan(s.name)} \u2014 ${s.skill} (${s.cron})`);
|
|
41921
|
+
for (const s of dueDetails)
|
|
41922
|
+
console.log(` ${chalk10.cyan(s.name)} \u2014 ${s.skill} (${s.cron})${s.cost ? ` \u2014 ${s.cost}` : ""}`);
|
|
41923
|
+
return;
|
|
41924
|
+
}
|
|
41925
|
+
const approvedMaxCents = parseMaxPaidCents(options.maxPaidCents);
|
|
41926
|
+
if (paidTotalCents > 0 && (!options.allowPaid || approvedMaxCents === null || approvedMaxCents < paidTotalCents)) {
|
|
41927
|
+
const error48 = `Due paid hosted schedules cost ${formatCost2(paidTotalCents)} total. Review with skills schedule run --dry-run, then rerun with --allow-paid --max-paid-cents ${paidTotalCents}.`;
|
|
41928
|
+
if (options.json) {
|
|
41929
|
+
console.log(JSON.stringify({
|
|
41930
|
+
ran: 0,
|
|
41931
|
+
approvalRequired: true,
|
|
41932
|
+
error: error48,
|
|
41933
|
+
paidTotalCents,
|
|
41934
|
+
paidTotal: formatCost2(paidTotalCents),
|
|
41935
|
+
schedules: dueDetails.filter((schedule) => schedule.paid)
|
|
41936
|
+
}));
|
|
41937
|
+
} else {
|
|
41938
|
+
console.error(chalk10.red(`\u2717 ${error48}`));
|
|
41939
|
+
}
|
|
41940
|
+
process.exitCode = 1;
|
|
41844
41941
|
return;
|
|
41845
41942
|
}
|
|
41846
41943
|
const results = [];
|
|
41847
41944
|
for (const s of due) {
|
|
41848
41945
|
try {
|
|
41849
|
-
await executeScheduledSkill(s.skill, s.args ?? []);
|
|
41946
|
+
const execution = await executeScheduledSkill(s.skill, s.args ?? [], { allowPaid: options.allowPaid });
|
|
41850
41947
|
recordScheduleRun(s.id, "success");
|
|
41851
|
-
results.push({ name: s.name, skill: s.skill, status: "success" });
|
|
41948
|
+
results.push({ name: s.name, skill: s.skill, status: "success", ...execution });
|
|
41852
41949
|
} catch (err) {
|
|
41853
41950
|
recordScheduleRun(s.id, "error");
|
|
41854
41951
|
results.push({ name: s.name, skill: s.skill, status: "error", error: err.message });
|
|
@@ -41894,13 +41991,17 @@ Next 5 run times:`));
|
|
|
41894
41991
|
console.log(` ${new Date(nextRun).toLocaleString()}`);
|
|
41895
41992
|
});
|
|
41896
41993
|
}
|
|
41897
|
-
async function executeScheduledSkill(skillName, args2) {
|
|
41994
|
+
async function executeScheduledSkill(skillName, args2, options) {
|
|
41898
41995
|
const { getSkill: getSkill2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
41899
41996
|
const skill = getSkill2(skillName);
|
|
41900
41997
|
if (!skill)
|
|
41901
41998
|
throw new Error(`Skill '${skillName}' not found`);
|
|
41902
41999
|
const pricing = await Promise.resolve().then(() => (init_pricing(), exports_pricing));
|
|
41903
42000
|
if (pricing.isPremiumSkill(skill.name)) {
|
|
42001
|
+
const publicPricing = pricing.getPublicSkillPricing(skill.name, {}, args2);
|
|
42002
|
+
if (!options.allowPaid) {
|
|
42003
|
+
throw new Error(`${skill.name} is a paid hosted skill (${publicPricing.formattedCost}). Review with skills schedule run --dry-run, then rerun with --allow-paid --max-paid-cents ${publicPricing.costCents}.`);
|
|
42004
|
+
}
|
|
41904
42005
|
const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
|
|
41905
42006
|
const apiKey = getApiKey2();
|
|
41906
42007
|
if (!apiKey) {
|
|
@@ -41911,13 +42012,40 @@ async function executeScheduledSkill(skillName, args2) {
|
|
|
41911
42012
|
const run = await client.submitRun(skill.name, {}, args2);
|
|
41912
42013
|
if (run.error)
|
|
41913
42014
|
throw new Error(String(run.error));
|
|
41914
|
-
return;
|
|
42015
|
+
return { paid: true, costCents: publicPricing.costCents, cost: publicPricing.formattedCost };
|
|
41915
42016
|
}
|
|
41916
42017
|
const { runSkill: runSkill2 } = await Promise.resolve().then(() => (init_skillinfo(), exports_skillinfo));
|
|
41917
42018
|
const result = await runSkill2(skill.name, args2);
|
|
41918
42019
|
if (result.exitCode !== 0) {
|
|
41919
42020
|
throw new Error(result.error || result.stderr || `Skill '${skill.name}' exited with ${result.exitCode}`);
|
|
41920
42021
|
}
|
|
42022
|
+
return { paid: false };
|
|
42023
|
+
}
|
|
42024
|
+
async function describeDueSchedule(schedule) {
|
|
42025
|
+
const { getSkill: getSkill2 } = await Promise.resolve().then(() => (init_registry(), exports_registry));
|
|
42026
|
+
const pricing = await Promise.resolve().then(() => (init_pricing(), exports_pricing));
|
|
42027
|
+
const skill = getSkill2(schedule.skill);
|
|
42028
|
+
const paid = Boolean(skill && pricing.isPremiumSkill(skill.name));
|
|
42029
|
+
const publicPricing = paid && skill ? pricing.getPublicSkillPricing(skill.name, {}, schedule.args ?? []) : null;
|
|
42030
|
+
return {
|
|
42031
|
+
name: schedule.name,
|
|
42032
|
+
skill: schedule.skill,
|
|
42033
|
+
cron: schedule.cron,
|
|
42034
|
+
paid,
|
|
42035
|
+
costCents: publicPricing?.costCents,
|
|
42036
|
+
cost: publicPricing?.formattedCost
|
|
42037
|
+
};
|
|
42038
|
+
}
|
|
42039
|
+
function parseMaxPaidCents(value) {
|
|
42040
|
+
if (!value)
|
|
42041
|
+
return null;
|
|
42042
|
+
const parsed = Number(value);
|
|
42043
|
+
if (!Number.isInteger(parsed) || parsed < 0)
|
|
42044
|
+
return null;
|
|
42045
|
+
return parsed;
|
|
42046
|
+
}
|
|
42047
|
+
function formatCost2(cents) {
|
|
42048
|
+
return `$${(cents / 100).toFixed(2)}`;
|
|
41921
42049
|
}
|
|
41922
42050
|
var init_schedule = __esm(() => {
|
|
41923
42051
|
init_scheduler();
|
|
@@ -42062,11 +42190,58 @@ function prompt(question) {
|
|
|
42062
42190
|
}
|
|
42063
42191
|
async function apiRequest(path, options) {
|
|
42064
42192
|
const url2 = getApiUrl();
|
|
42065
|
-
|
|
42066
|
-
|
|
42067
|
-
|
|
42068
|
-
|
|
42069
|
-
|
|
42193
|
+
let res;
|
|
42194
|
+
try {
|
|
42195
|
+
res = await fetch(`${url2}${path}`, {
|
|
42196
|
+
...options,
|
|
42197
|
+
headers: { "Content-Type": "application/json", ...options?.headers }
|
|
42198
|
+
});
|
|
42199
|
+
} catch (err) {
|
|
42200
|
+
throw new HostedApiError(`Unable to reach hosted Skills API: ${err.message}`);
|
|
42201
|
+
}
|
|
42202
|
+
const text = await res.text();
|
|
42203
|
+
const body = text ? parseJsonBody(text) : {};
|
|
42204
|
+
if (!res.ok) {
|
|
42205
|
+
const record3 = isRecord2(body) ? body : {};
|
|
42206
|
+
const detail = typeof record3.detail === "string" ? record3.detail : undefined;
|
|
42207
|
+
const error48 = typeof record3.error === "string" ? record3.error : undefined;
|
|
42208
|
+
const code = typeof record3.code === "string" ? record3.code : undefined;
|
|
42209
|
+
throw new HostedApiError(detail || error48 || `${res.status} ${res.statusText}`, {
|
|
42210
|
+
status: res.status,
|
|
42211
|
+
code,
|
|
42212
|
+
detail
|
|
42213
|
+
});
|
|
42214
|
+
}
|
|
42215
|
+
return body;
|
|
42216
|
+
}
|
|
42217
|
+
function parseJsonBody(text) {
|
|
42218
|
+
try {
|
|
42219
|
+
return JSON.parse(text);
|
|
42220
|
+
} catch {
|
|
42221
|
+
return { detail: text };
|
|
42222
|
+
}
|
|
42223
|
+
}
|
|
42224
|
+
function isRecord2(value) {
|
|
42225
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
42226
|
+
}
|
|
42227
|
+
function commandErrorPayload(err, fallback) {
|
|
42228
|
+
if (err instanceof HostedApiError) {
|
|
42229
|
+
return {
|
|
42230
|
+
error: err.message || fallback,
|
|
42231
|
+
...err.status !== undefined ? { status: err.status } : {},
|
|
42232
|
+
...err.code ? { code: err.code } : {},
|
|
42233
|
+
...err.detail && err.detail !== err.message ? { detail: err.detail } : {}
|
|
42234
|
+
};
|
|
42235
|
+
}
|
|
42236
|
+
return { error: err?.message || fallback };
|
|
42237
|
+
}
|
|
42238
|
+
function writeCommandError(err, fallback, json2) {
|
|
42239
|
+
const payload = commandErrorPayload(err, fallback);
|
|
42240
|
+
if (json2)
|
|
42241
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
42242
|
+
else
|
|
42243
|
+
console.error(chalk12.red(String(payload.detail || payload.error || fallback)));
|
|
42244
|
+
process.exitCode = 1;
|
|
42070
42245
|
}
|
|
42071
42246
|
function sleep(ms) {
|
|
42072
42247
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -42128,55 +42303,77 @@ function printLoginSuccess(loginResult, json2) {
|
|
|
42128
42303
|
console.log(chalk12.dim(` API key saved to ~/.hasna/skills/auth.json`));
|
|
42129
42304
|
}
|
|
42130
42305
|
}
|
|
42131
|
-
async function doLogin(email3, code) {
|
|
42306
|
+
async function doLogin(email3, code, json2) {
|
|
42132
42307
|
if (!email3 || !email3.includes("@")) {
|
|
42133
|
-
|
|
42308
|
+
writeCommandError(new Error("Invalid email"), "Invalid email", json2);
|
|
42134
42309
|
process.exitCode = 1;
|
|
42135
42310
|
return;
|
|
42136
42311
|
}
|
|
42137
42312
|
if (!code) {
|
|
42138
|
-
|
|
42139
|
-
|
|
42140
|
-
|
|
42141
|
-
|
|
42142
|
-
|
|
42313
|
+
if (!json2)
|
|
42314
|
+
console.log(chalk12.dim("Sending code..."));
|
|
42315
|
+
let sendRes;
|
|
42316
|
+
try {
|
|
42317
|
+
sendRes = await apiRequest("/api/auth/login", {
|
|
42318
|
+
method: "POST",
|
|
42319
|
+
body: JSON.stringify({ email: email3 })
|
|
42320
|
+
});
|
|
42321
|
+
} catch (err) {
|
|
42322
|
+
writeCommandError(err, "Failed to request login code", json2);
|
|
42323
|
+
return;
|
|
42324
|
+
}
|
|
42143
42325
|
if (sendRes.error) {
|
|
42144
|
-
|
|
42145
|
-
process.exitCode = 1;
|
|
42326
|
+
writeCommandError(new Error(sendRes.error), "Failed to request login code", json2);
|
|
42146
42327
|
return;
|
|
42147
42328
|
}
|
|
42148
|
-
|
|
42149
|
-
|
|
42329
|
+
if (!json2)
|
|
42330
|
+
console.log(chalk12.green("\u2713 Code sent to " + email3));
|
|
42331
|
+
if (json2 || !isTTY) {
|
|
42150
42332
|
console.log(JSON.stringify({ status: "code_sent", email: email3, message: "Check email for 6-digit code, then run: skills auth login --email " + email3 + " --code <CODE>" }));
|
|
42151
42333
|
return;
|
|
42152
42334
|
}
|
|
42153
42335
|
code = await prompt(chalk12.bold("Code: "));
|
|
42154
42336
|
}
|
|
42155
|
-
|
|
42156
|
-
|
|
42157
|
-
|
|
42158
|
-
|
|
42337
|
+
let verifyRes;
|
|
42338
|
+
try {
|
|
42339
|
+
verifyRes = await apiRequest("/api/auth/verify", {
|
|
42340
|
+
method: "POST",
|
|
42341
|
+
body: JSON.stringify({ email: email3, code })
|
|
42342
|
+
});
|
|
42343
|
+
} catch (err) {
|
|
42344
|
+
writeCommandError(err, "Failed to verify login code", json2);
|
|
42345
|
+
return;
|
|
42346
|
+
}
|
|
42159
42347
|
if (verifyRes.error) {
|
|
42160
|
-
|
|
42161
|
-
|
|
42348
|
+
writeCommandError(new Error(verifyRes.error), "Failed to verify login code", json2);
|
|
42349
|
+
return;
|
|
42350
|
+
}
|
|
42351
|
+
let storedKey;
|
|
42352
|
+
try {
|
|
42353
|
+
storedKey = await persistLoginResult(verifyRes);
|
|
42354
|
+
} catch (err) {
|
|
42355
|
+
writeCommandError(err, "Login succeeded but API key creation failed", json2);
|
|
42162
42356
|
return;
|
|
42163
42357
|
}
|
|
42164
|
-
const storedKey = await persistLoginResult(verifyRes);
|
|
42165
42358
|
if (!storedKey) {
|
|
42166
|
-
|
|
42167
|
-
process.exitCode = 1;
|
|
42359
|
+
writeCommandError(new Error("Login succeeded but API key creation failed"), "Login succeeded but API key creation failed", json2);
|
|
42168
42360
|
return;
|
|
42169
42361
|
}
|
|
42170
|
-
printLoginSuccess(verifyRes,
|
|
42362
|
+
printLoginSuccess(verifyRes, Boolean(json2));
|
|
42171
42363
|
}
|
|
42172
42364
|
async function doDeviceLogin(options) {
|
|
42173
|
-
|
|
42174
|
-
|
|
42175
|
-
|
|
42176
|
-
|
|
42365
|
+
let start;
|
|
42366
|
+
try {
|
|
42367
|
+
start = await apiRequest("/api/auth/device/start", {
|
|
42368
|
+
method: "POST",
|
|
42369
|
+
body: JSON.stringify({ client: "skills-cli" })
|
|
42370
|
+
});
|
|
42371
|
+
} catch (err) {
|
|
42372
|
+
writeCommandError(err, "Failed to start device login", options.json);
|
|
42373
|
+
return;
|
|
42374
|
+
}
|
|
42177
42375
|
if (start.error) {
|
|
42178
|
-
|
|
42179
|
-
process.exitCode = 1;
|
|
42376
|
+
writeCommandError(new Error(start.error), "Failed to start device login", options.json);
|
|
42180
42377
|
return;
|
|
42181
42378
|
}
|
|
42182
42379
|
const verificationUrl = start.verificationUriComplete || start.verificationUri;
|
|
@@ -42218,23 +42415,33 @@ Waiting for authentication...`));
|
|
|
42218
42415
|
const timeoutMs = Number(options.pollTimeoutMs || DEFAULT_DEVICE_POLL_TIMEOUT_MS);
|
|
42219
42416
|
const deadline = Date.now() + timeoutMs;
|
|
42220
42417
|
while (Date.now() < deadline) {
|
|
42221
|
-
|
|
42222
|
-
|
|
42223
|
-
|
|
42224
|
-
|
|
42418
|
+
let tokenRes;
|
|
42419
|
+
try {
|
|
42420
|
+
tokenRes = await apiRequest("/api/auth/device/token", {
|
|
42421
|
+
method: "POST",
|
|
42422
|
+
body: JSON.stringify({ deviceCode: start.deviceCode })
|
|
42423
|
+
});
|
|
42424
|
+
} catch (err) {
|
|
42425
|
+
writeCommandError(err, "Failed to poll device login", options.json);
|
|
42426
|
+
return;
|
|
42427
|
+
}
|
|
42225
42428
|
if (tokenRes.error === "authorization_pending" || tokenRes.status === "pending") {
|
|
42226
42429
|
await sleep(intervalMs);
|
|
42227
42430
|
continue;
|
|
42228
42431
|
}
|
|
42229
42432
|
if (tokenRes.error) {
|
|
42230
|
-
|
|
42231
|
-
|
|
42433
|
+
writeCommandError(new Error(tokenRes.detail || tokenRes.error), "Failed to poll device login", options.json);
|
|
42434
|
+
return;
|
|
42435
|
+
}
|
|
42436
|
+
let storedKey;
|
|
42437
|
+
try {
|
|
42438
|
+
storedKey = await persistLoginResult(tokenRes);
|
|
42439
|
+
} catch (err) {
|
|
42440
|
+
writeCommandError(err, "Login succeeded but API key creation failed", options.json);
|
|
42232
42441
|
return;
|
|
42233
42442
|
}
|
|
42234
|
-
const storedKey = await persistLoginResult(tokenRes);
|
|
42235
42443
|
if (!storedKey) {
|
|
42236
|
-
|
|
42237
|
-
process.exitCode = 1;
|
|
42444
|
+
writeCommandError(new Error("Login succeeded but API key creation failed"), "Login succeeded but API key creation failed", options.json);
|
|
42238
42445
|
return;
|
|
42239
42446
|
}
|
|
42240
42447
|
printLoginSuccess(tokenRes, Boolean(options.json));
|
|
@@ -42270,7 +42477,7 @@ function registerAuth(parent) {
|
|
|
42270
42477
|
process.exitCode = 1;
|
|
42271
42478
|
return;
|
|
42272
42479
|
}
|
|
42273
|
-
await doLogin(email3, options.code);
|
|
42480
|
+
await doLogin(email3, options.code, options.json);
|
|
42274
42481
|
});
|
|
42275
42482
|
auth.command("signup").description("Create or sign in with your email (passwordless)").option("--email <email>", "Email address (non-interactive)").option("--code <code>", "Verification code (non-interactive)").action(async (options) => {
|
|
42276
42483
|
let email3 = options.email;
|
|
@@ -42358,22 +42565,26 @@ async function handleBillingStatus(options = {}) {
|
|
|
42358
42565
|
}
|
|
42359
42566
|
console.log(chalk12.bold("Plan: ") + res.plan);
|
|
42360
42567
|
console.log(chalk12.bold("Balance: ") + res.balance);
|
|
42361
|
-
} catch {
|
|
42362
|
-
|
|
42363
|
-
process.exitCode = 1;
|
|
42568
|
+
} catch (err) {
|
|
42569
|
+
writeCommandError(err, "Failed to fetch billing status", options.json);
|
|
42364
42570
|
}
|
|
42365
42571
|
}
|
|
42366
42572
|
async function handleCheckout(options = {}) {
|
|
42367
42573
|
const config2 = requireHostedAuth(options.json);
|
|
42368
42574
|
if (!config2)
|
|
42369
42575
|
return;
|
|
42370
|
-
|
|
42371
|
-
|
|
42372
|
-
|
|
42373
|
-
|
|
42576
|
+
let res;
|
|
42577
|
+
try {
|
|
42578
|
+
res = await apiRequest("/api/v1/billing/checkout", {
|
|
42579
|
+
method: "POST",
|
|
42580
|
+
headers: { Authorization: `Bearer ${config2.apiKey}` }
|
|
42581
|
+
});
|
|
42582
|
+
} catch (err) {
|
|
42583
|
+
writeCommandError(err, "Failed to create checkout session", options.json);
|
|
42584
|
+
return;
|
|
42585
|
+
}
|
|
42374
42586
|
if (res.error || !res.url) {
|
|
42375
|
-
|
|
42376
|
-
process.exitCode = 1;
|
|
42587
|
+
writeCommandError(new Error(res.detail || res.error || "Failed to create checkout session"), "Failed to create checkout session", options.json);
|
|
42377
42588
|
return;
|
|
42378
42589
|
}
|
|
42379
42590
|
if (options.json)
|
|
@@ -42385,13 +42596,18 @@ async function handlePortal(options = {}) {
|
|
|
42385
42596
|
const config2 = requireHostedAuth(options.json);
|
|
42386
42597
|
if (!config2)
|
|
42387
42598
|
return;
|
|
42388
|
-
|
|
42389
|
-
|
|
42390
|
-
|
|
42391
|
-
|
|
42599
|
+
let res;
|
|
42600
|
+
try {
|
|
42601
|
+
res = await apiRequest("/api/v1/billing/portal", {
|
|
42602
|
+
method: "POST",
|
|
42603
|
+
headers: { Authorization: `Bearer ${config2.apiKey}` }
|
|
42604
|
+
});
|
|
42605
|
+
} catch (err) {
|
|
42606
|
+
writeCommandError(err, "Failed to create customer portal session", options.json);
|
|
42607
|
+
return;
|
|
42608
|
+
}
|
|
42392
42609
|
if (res.error || !res.url) {
|
|
42393
|
-
|
|
42394
|
-
process.exitCode = 1;
|
|
42610
|
+
writeCommandError(new Error(res.detail || res.error || "Failed to create customer portal session"), "Failed to create customer portal session", options.json);
|
|
42395
42611
|
return;
|
|
42396
42612
|
}
|
|
42397
42613
|
if (options.json)
|
|
@@ -42403,14 +42619,19 @@ async function handleBuyCredits(amount, options = {}) {
|
|
|
42403
42619
|
const config2 = requireHostedAuth(options.json);
|
|
42404
42620
|
if (!config2)
|
|
42405
42621
|
return;
|
|
42406
|
-
|
|
42407
|
-
|
|
42408
|
-
|
|
42409
|
-
|
|
42410
|
-
|
|
42622
|
+
let res;
|
|
42623
|
+
try {
|
|
42624
|
+
res = await apiRequest("/api/v1/billing/credits", {
|
|
42625
|
+
method: "POST",
|
|
42626
|
+
headers: { Authorization: `Bearer ${config2.apiKey}` },
|
|
42627
|
+
body: JSON.stringify({ amount })
|
|
42628
|
+
});
|
|
42629
|
+
} catch (err) {
|
|
42630
|
+
writeCommandError(err, "Failed to create credit checkout session", options.json);
|
|
42631
|
+
return;
|
|
42632
|
+
}
|
|
42411
42633
|
if (res.error || !res.url) {
|
|
42412
|
-
|
|
42413
|
-
process.exitCode = 1;
|
|
42634
|
+
writeCommandError(new Error(res.detail || res.error || "Failed to create credit checkout session"), "Failed to create credit checkout session", options.json);
|
|
42414
42635
|
return;
|
|
42415
42636
|
}
|
|
42416
42637
|
if (options.json)
|
|
@@ -42422,12 +42643,17 @@ async function handleListCreditPacks(options = {}) {
|
|
|
42422
42643
|
const config2 = requireHostedAuth(options.json);
|
|
42423
42644
|
if (!config2)
|
|
42424
42645
|
return;
|
|
42425
|
-
|
|
42426
|
-
|
|
42427
|
-
|
|
42646
|
+
let res;
|
|
42647
|
+
try {
|
|
42648
|
+
res = await apiRequest("/api/v1/billing/credits", {
|
|
42649
|
+
headers: { Authorization: `Bearer ${config2.apiKey}` }
|
|
42650
|
+
});
|
|
42651
|
+
} catch (err) {
|
|
42652
|
+
writeCommandError(err, "Failed to list credit packs", options.json);
|
|
42653
|
+
return;
|
|
42654
|
+
}
|
|
42428
42655
|
if (res.error) {
|
|
42429
|
-
|
|
42430
|
-
process.exitCode = 1;
|
|
42656
|
+
writeCommandError(new Error(res.detail || res.error || "Failed to list credit packs"), "Failed to list credit packs", options.json);
|
|
42431
42657
|
return;
|
|
42432
42658
|
}
|
|
42433
42659
|
if (options.json) {
|
|
@@ -42451,11 +42677,23 @@ function registerCredits(parent) {
|
|
|
42451
42677
|
credits.command("buy").description("Create a credit pack checkout session").argument("<amount>", "Credit pack amount: 1, 5, 20, 50, or 100").option("--json", "Output as JSON", false).action(handleBuyCredits);
|
|
42452
42678
|
credits.command("packs").description("List available credit packs").option("--json", "Output as JSON", false).action(handleListCreditPacks);
|
|
42453
42679
|
}
|
|
42454
|
-
var isTTY, DEFAULT_DEVICE_POLL_TIMEOUT_MS;
|
|
42680
|
+
var isTTY, DEFAULT_DEVICE_POLL_TIMEOUT_MS, HostedApiError;
|
|
42455
42681
|
var init_auth = __esm(() => {
|
|
42456
42682
|
init_auth_store();
|
|
42457
42683
|
isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
42458
42684
|
DEFAULT_DEVICE_POLL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
42685
|
+
HostedApiError = class HostedApiError extends Error {
|
|
42686
|
+
status;
|
|
42687
|
+
code;
|
|
42688
|
+
detail;
|
|
42689
|
+
constructor(message, options = {}) {
|
|
42690
|
+
super(message);
|
|
42691
|
+
this.name = "HostedApiError";
|
|
42692
|
+
this.status = options.status;
|
|
42693
|
+
this.code = options.code;
|
|
42694
|
+
this.detail = options.detail;
|
|
42695
|
+
}
|
|
42696
|
+
};
|
|
42459
42697
|
});
|
|
42460
42698
|
|
|
42461
42699
|
// src/cli/commands/feedback.ts
|