@hasna/skills 0.3.0 → 0.4.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/README.md +94 -10
- package/bin/index.js +1398 -571
- package/bin/mcp.js +899 -211
- package/bin/server.js +14 -5
- package/bin/worker.js +2 -3
- package/dist/cli/commands/remote-account.d.ts +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +770 -210
- package/dist/lib/auth-store.d.ts +1 -1
- package/dist/lib/fleet-credentials.d.ts +8 -2
- package/dist/lib/instance-credentials-race.fixture.d.ts +1 -0
- package/dist/lib/instance-credentials.d.ts +13 -0
- package/dist/lib/mcp-contracts.d.ts +4 -0
- package/dist/lib/portable-skills-files.d.ts +4 -0
- package/dist/lib/portable-skills-types.d.ts +2 -0
- package/dist/lib/remote-account.d.ts +42 -0
- package/dist/lib/remote-auth.d.ts +32 -0
- package/dist/lib/remote-client.d.ts +56 -1
- package/dist/lib/remote-customer-operations.d.ts +106 -0
- package/dist/lib/remote-files.d.ts +21 -0
- package/dist/lib/run-routing.d.ts +1 -0
- package/dist/lib/run-state.d.ts +3 -0
- package/dist/mcp/remote-customer-tools.d.ts +2 -0
- package/dist/sdk/index.d.ts +4 -0
- package/dist/sdk/index.js +1057 -280
- package/dist/sdk/runs.d.ts +4 -4
- package/package.json +2 -3
package/bin/index.js
CHANGED
|
@@ -36860,7 +36860,7 @@ var package_default;
|
|
|
36860
36860
|
var init_package = __esm(() => {
|
|
36861
36861
|
package_default = {
|
|
36862
36862
|
name: "@hasna/skills",
|
|
36863
|
-
version: "0.
|
|
36863
|
+
version: "0.4.0",
|
|
36864
36864
|
description: "Skills library for AI coding agents",
|
|
36865
36865
|
type: "module",
|
|
36866
36866
|
bin: {
|
|
@@ -36919,8 +36919,7 @@ var init_package = __esm(() => {
|
|
|
36919
36919
|
"verify:release": "bun run scripts/release-guard.ts",
|
|
36920
36920
|
prepare: "bun run build:js",
|
|
36921
36921
|
prepack: "bun run build && bun run verify:release",
|
|
36922
|
-
prepublishOnly: "bun run typecheck && bun run test"
|
|
36923
|
-
postinstall: "mkdir -p $HOME/.hasna/skills/custom 2>/dev/null || true"
|
|
36922
|
+
prepublishOnly: "bun run typecheck && bun run test"
|
|
36924
36923
|
},
|
|
36925
36924
|
keywords: [
|
|
36926
36925
|
"skills",
|
|
@@ -39056,6 +39055,16 @@ function isHostedMetadataSkill(skillName, frontmatter, registryMeta, packageDecl
|
|
|
39056
39055
|
return true;
|
|
39057
39056
|
return false;
|
|
39058
39057
|
}
|
|
39058
|
+
function frontmatterString(raw) {
|
|
39059
|
+
if (raw.startsWith('"') && raw.endsWith('"')) {
|
|
39060
|
+
try {
|
|
39061
|
+
const decoded = JSON.parse(raw);
|
|
39062
|
+
if (typeof decoded === "string")
|
|
39063
|
+
return decoded;
|
|
39064
|
+
} catch {}
|
|
39065
|
+
}
|
|
39066
|
+
return raw.replace(/^["']|["']$/g, "");
|
|
39067
|
+
}
|
|
39059
39068
|
function parseSkillFrontmatter(content) {
|
|
39060
39069
|
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
39061
39070
|
if (!match)
|
|
@@ -39075,12 +39084,12 @@ function parseSkillFrontmatter(content) {
|
|
|
39075
39084
|
const tags = [];
|
|
39076
39085
|
while (i + 1 < lines.length && /^\s+-\s+/.test(lines[i + 1])) {
|
|
39077
39086
|
i++;
|
|
39078
|
-
tags.push(lines[i].replace(/^\s+-\s+/, "").trim());
|
|
39087
|
+
tags.push(frontmatterString(lines[i].replace(/^\s+-\s+/, "").trim()));
|
|
39079
39088
|
}
|
|
39080
39089
|
result2.tags = tags;
|
|
39081
39090
|
continue;
|
|
39082
39091
|
}
|
|
39083
|
-
const value = rawValue
|
|
39092
|
+
const value = frontmatterString(rawValue);
|
|
39084
39093
|
if (!value)
|
|
39085
39094
|
continue;
|
|
39086
39095
|
if (key === "name")
|
|
@@ -39745,8 +39754,8 @@ function createInstructionManifest(name, options) {
|
|
|
39745
39754
|
description: options.description,
|
|
39746
39755
|
version: PORTABLE_SKILL_DEFAULT_VERSION,
|
|
39747
39756
|
displayName: displayName(name),
|
|
39748
|
-
category: "Development Tools",
|
|
39749
|
-
tags: ["custom", name],
|
|
39757
|
+
category: options.category ?? "Development Tools",
|
|
39758
|
+
tags: options.tags ?? ["custom", name],
|
|
39750
39759
|
kind: "instruction",
|
|
39751
39760
|
inputs: [],
|
|
39752
39761
|
commands: [],
|
|
@@ -39761,16 +39770,16 @@ function writeInstructionSkillTemplate(skillPath, manifest) {
|
|
|
39761
39770
|
}
|
|
39762
39771
|
function renderInstructionSkillMd(manifest) {
|
|
39763
39772
|
const tags = manifest.tags?.length ? `tags:
|
|
39764
|
-
${manifest.tags.map((tag) => ` - ${tag}`).join(`
|
|
39773
|
+
${manifest.tags.map((tag) => ` - ${yamlString(tag)}`).join(`
|
|
39765
39774
|
`)}
|
|
39766
39775
|
` : "";
|
|
39767
39776
|
return `---
|
|
39768
39777
|
name: ${manifest.name}
|
|
39769
|
-
description: ${manifest.description}
|
|
39778
|
+
description: ${yamlString(manifest.description)}
|
|
39770
39779
|
kind: instruction
|
|
39771
39780
|
version: ${manifest.version}
|
|
39772
39781
|
source: custom
|
|
39773
|
-
category: ${manifest.category ?? "Development Tools"}
|
|
39782
|
+
category: ${yamlString(manifest.category ?? "Development Tools")}
|
|
39774
39783
|
${tags}---
|
|
39775
39784
|
|
|
39776
39785
|
# ${manifest.displayName ?? displayName(manifest.name)}
|
|
@@ -39791,8 +39800,8 @@ function createPortableManifest(name, options) {
|
|
|
39791
39800
|
description: options.description,
|
|
39792
39801
|
version: PORTABLE_SKILL_DEFAULT_VERSION,
|
|
39793
39802
|
displayName: displayName(name),
|
|
39794
|
-
category: "Development Tools",
|
|
39795
|
-
tags: ["custom", name],
|
|
39803
|
+
category: options.category ?? "Development Tools",
|
|
39804
|
+
tags: options.tags ?? ["custom", name],
|
|
39796
39805
|
inputs: DEFAULT_INPUTS,
|
|
39797
39806
|
commands: [{
|
|
39798
39807
|
name,
|
|
@@ -39983,10 +39992,13 @@ function isExcludedCopyEntry(name, isFirstSegment) {
|
|
|
39983
39992
|
return true;
|
|
39984
39993
|
return false;
|
|
39985
39994
|
}
|
|
39995
|
+
function yamlString(value) {
|
|
39996
|
+
return JSON.stringify(value);
|
|
39997
|
+
}
|
|
39986
39998
|
function renderSkillMd(manifest) {
|
|
39987
39999
|
return `---
|
|
39988
40000
|
name: ${manifest.name}
|
|
39989
|
-
description: ${manifest.description}
|
|
40001
|
+
description: ${yamlString(manifest.description)}
|
|
39990
40002
|
---
|
|
39991
40003
|
|
|
39992
40004
|
# ${manifest.displayName ?? displayName(manifest.name)}
|
|
@@ -40396,11 +40408,11 @@ function scaffoldPortableSkill(name, options = {}) {
|
|
|
40396
40408
|
const kind = options.kind ?? "executable";
|
|
40397
40409
|
const description = options.description ?? `${displayName(skillName)} skill`;
|
|
40398
40410
|
if (kind === "instruction") {
|
|
40399
|
-
const manifest2 = createInstructionManifest(skillName, { description });
|
|
40411
|
+
const manifest2 = createInstructionManifest(skillName, { description, category: options.category, tags: options.tags });
|
|
40400
40412
|
writeInstructionSkillTemplate(skillPath, manifest2);
|
|
40401
40413
|
return { name: skillName, path: skillPath, manifest: manifest2, created: true };
|
|
40402
40414
|
}
|
|
40403
|
-
const manifest = createPortableManifest(skillName, { description });
|
|
40415
|
+
const manifest = createPortableManifest(skillName, { description, category: options.category, tags: options.tags });
|
|
40404
40416
|
writePortableSkillTemplate(skillPath, manifest);
|
|
40405
40417
|
return { name: skillName, path: skillPath, manifest, created: true };
|
|
40406
40418
|
}
|
|
@@ -48335,93 +48347,7 @@ function toV1BaseUrl(apiUrl) {
|
|
|
48335
48347
|
url.pathname = `${path}/v1`;
|
|
48336
48348
|
return url.toString().replace(/\/+$/, "");
|
|
48337
48349
|
}
|
|
48338
|
-
|
|
48339
|
-
env3 = snapshotClientEnvironment(name, env3);
|
|
48340
|
-
const keys2 = clientTransportEnvKeys(name);
|
|
48341
|
-
const definedUrlEntries = keys2.apiUrlKeys.filter((key) => Object.prototype.hasOwnProperty.call(env3, key) && env3[key] !== undefined).map((key) => ({ key, raw: String(env3[key]) }));
|
|
48342
|
-
const blankUrl = definedUrlEntries.find((entry) => entry.raw.trim().length === 0);
|
|
48343
|
-
if (blankUrl) {
|
|
48344
|
-
throw new ClientTransportConfigurationError(name, `${blankUrl.key} is set but blank; public clients require an explicit HTTPS API URL and never select local storage.`, [blankUrl.key]);
|
|
48345
|
-
}
|
|
48346
|
-
const controlledUrl = definedUrlEntries.find((entry) => ASCII_CONTROL_PATTERN.test(entry.raw));
|
|
48347
|
-
if (controlledUrl) {
|
|
48348
|
-
throw new ClientTransportConfigurationError(name, `${controlledUrl.key} contains ASCII control characters.`, [controlledUrl.key]);
|
|
48349
|
-
}
|
|
48350
|
-
const usableUrlEntries = definedUrlEntries.map((entry) => ({ key: entry.key, value: entry.raw.trim() }));
|
|
48351
|
-
if (usableUrlEntries.length > 1 && new Set(usableUrlEntries.map((entry) => entry.value)).size > 1) {
|
|
48352
|
-
throw new ClientTransportConfigurationError(name, `${usableUrlEntries.map((entry) => entry.key).join(" and ")} disagree; client authority aliases must be identical or only one may be set.`, usableUrlEntries.map((entry) => entry.key));
|
|
48353
|
-
}
|
|
48354
|
-
const envUrlHit = usableUrlEntries[0] ?? null;
|
|
48355
|
-
const keychainUrlHit = keychainConfigValue(name, env3, options.credentials?.keychain);
|
|
48356
|
-
const diskConfigUrlHit = appConfigDiskValue(name, env3, keys2.apiUrlKeys);
|
|
48357
|
-
if (diskConfigUrlHit?.unusable) {
|
|
48358
|
-
throw new ClientTransportConfigurationError(name, `${diskConfigUrlHit.key} in ${diskConfigUrlHit.path} is declared but blank or malformed; public clients require a valid HTTPS service authority.`, [diskConfigUrlHit.path]);
|
|
48359
|
-
}
|
|
48360
|
-
const urlCandidates = [
|
|
48361
|
-
...envUrlHit ? [envUrlHit] : [],
|
|
48362
|
-
...keychainUrlHit ? [{ key: keychainUrlHit.source, value: keychainUrlHit.value }] : [],
|
|
48363
|
-
...diskConfigUrlHit ? [{ key: diskConfigUrlHit.path, value: diskConfigUrlHit.value.trim() }] : []
|
|
48364
|
-
];
|
|
48365
|
-
const configuredUrl = urlCandidates[0] ?? null;
|
|
48366
|
-
const divergentUrls = urlCandidates.filter((candidate) => candidate.value !== configuredUrl?.value);
|
|
48367
|
-
if (configuredUrl && divergentUrls.length > 0) {
|
|
48368
|
-
throw new ClientTransportConfigurationError(name, `${configuredUrl.key} and ${divergentUrls.map((candidate) => candidate.key).join(" and ")} select different service authorities; refusing to send a credential written for one authority to the other.`, urlCandidates.map((candidate) => candidate.key));
|
|
48369
|
-
}
|
|
48370
|
-
const warnings = [];
|
|
48371
|
-
if (configuredUrl && !envUrlHit) {
|
|
48372
|
-
warnings.push(`No ${keys2.apiUrlKeys[0]} in the environment; the server URL in ${configuredUrl.key} was used, so this client connects to the server. ` + `Keep that entry aligned with the intended service authority.`);
|
|
48373
|
-
}
|
|
48374
|
-
const credential = resolveCredential(name, env3, options.credentials);
|
|
48375
|
-
if (!credential) {
|
|
48376
|
-
const diskHint = credentialDiskSourcesForMessage(name, env3);
|
|
48377
|
-
const lead = configuredUrl ? `${configuredUrl.key} selects the HTTP server for '${name}', but no API key could be resolved` : `${keys2.apiUrlKeys[0]} is not set and no API key could be resolved for '${name}'; a credential is required before the default fleet gateway authority applies`;
|
|
48378
|
-
warnings.push(`${lead}; refusing to create an unauthenticated client \u2014 public clients never fall back to SQLite or another local store. ` + `Looked in the Keychain (macOS only), then for a credential file at ${diskHint}, then for ${keys2.apiKeyKeys[0]} in the environment.`);
|
|
48379
|
-
throw new ClientTransportConfigurationError(name, warnings.join(" "), [configuredUrl?.key ?? keys2.apiUrlKeys[0]]);
|
|
48380
|
-
}
|
|
48381
|
-
if (credential.warning)
|
|
48382
|
-
warnings.push(credential.warning);
|
|
48383
|
-
let urlHit;
|
|
48384
|
-
if (configuredUrl) {
|
|
48385
|
-
urlHit = configuredUrl;
|
|
48386
|
-
} else {
|
|
48387
|
-
try {
|
|
48388
|
-
urlHit = { key: DEFAULT_AUTHORITY_SOURCE, value: defaultFleetGatewayBaseUrl(name) };
|
|
48389
|
-
} catch (error) {
|
|
48390
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
48391
|
-
throw new ClientTransportConfigurationError(name, `No ${keys2.apiUrlKeys[0]} is configured and the default fleet gateway authority cannot be composed for '${name}': ${message}`, [keys2.apiUrlKeys[0]]);
|
|
48392
|
-
}
|
|
48393
|
-
}
|
|
48394
|
-
const apiUrlSource = urlHit.key;
|
|
48395
|
-
let baseUrl;
|
|
48396
|
-
try {
|
|
48397
|
-
baseUrl = toV1BaseUrl(urlHit.value);
|
|
48398
|
-
} catch (error) {
|
|
48399
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
48400
|
-
throw new ClientTransportConfigurationError(name, `Invalid API URL from ${apiUrlSource}: ${message}`, [apiUrlSource]);
|
|
48401
|
-
}
|
|
48402
|
-
return {
|
|
48403
|
-
resolution: {
|
|
48404
|
-
transport: "http",
|
|
48405
|
-
transportSource: urlHit.key,
|
|
48406
|
-
baseUrl,
|
|
48407
|
-
apiUrlSource,
|
|
48408
|
-
apiKeyPresent: true,
|
|
48409
|
-
apiKeySource: credential.source,
|
|
48410
|
-
apiKeyTier: credential.tier,
|
|
48411
|
-
misconfigured: false,
|
|
48412
|
-
warning: warnings.length > 0 ? warnings.join(" ") : null
|
|
48413
|
-
},
|
|
48414
|
-
credential
|
|
48415
|
-
};
|
|
48416
|
-
}
|
|
48417
|
-
function resolveClientTransport(name, env3 = process.env, options = {}) {
|
|
48418
|
-
return resolveClientTransportSnapshot(name, env3, options).resolution;
|
|
48419
|
-
}
|
|
48420
|
-
function credentialDiskSourcesForMessage(name, env3) {
|
|
48421
|
-
const paths = credentialDiskSources(name, env3);
|
|
48422
|
-
return paths.length > 0 ? paths.join(" or ") : "<no HOME or HASNA_HOME set in this environment, so no credential file was consulted>";
|
|
48423
|
-
}
|
|
48424
|
-
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, CredentialFileUnsafeError, HASNA_HOME_ENV_KEY = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY = "HASNA_STATION", HASNA_HOME_DIR = ".hasna", CONFIG_SUBDIR = "config", CREDENTIALS_FILE = "credentials", KEYCHAIN_SECURITY_BIN = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44, KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4, MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, AMBIENT_ENVIRONMENT, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk, DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com", DEFAULT_AUTHORITY_SOURCE = "default", ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, ClientTransportConfigurationError, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS;
|
|
48350
|
+
var CREDENTIAL_PROFILE_ENV_KEY = "HASNA_PROFILE", CredentialResolutionError, CredentialFileUnsafeError, HASNA_HOME_ENV_KEY = "HASNA_HOME", HASNA_CONFIG_HOME_ENV_KEY = "HASNA_CONFIG_HOME", KEYCHAIN_STATION_ENV_KEY = "HASNA_STATION", HASNA_HOME_DIR = ".hasna", CONFIG_SUBDIR = "config", CREDENTIALS_FILE = "credentials", KEYCHAIN_SECURITY_BIN = "/usr/bin/security", KEYCHAIN_SERVICE_PREFIX = "hasna.credentials", KEYCHAIN_ITEM_NOT_FOUND_STATUS = 44, KEYCHAIN_SPAWN_TIMEOUT_MS = 1e4, MAX_CREDENTIAL_FILE_BYTES, SAFE_APP_SLUG, SAFE_PROFILE, ILLEGAL_IN_HEADER_VALUE, VAULT_POINTER_SHAPE, CREDENTIAL_SHAPED_KEY, INSPECT_CUSTOM, CREDENTIAL_SEAL, AMBIENT_ENVIRONMENT, SECRETS_PACKAGE_SPECIFIER, requireSecretsSdk, DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com", ASCII_CONTROL_PATTERN, DNS_LABEL_PATTERN, IDEMPOTENT_METHODS, AUTHORITY_OVERRIDE_HEADERS;
|
|
48425
48351
|
var init_transport = __esm(() => {
|
|
48426
48352
|
CredentialResolutionError = class CredentialResolutionError extends Error {
|
|
48427
48353
|
appName;
|
|
@@ -48454,16 +48380,6 @@ var init_transport = __esm(() => {
|
|
|
48454
48380
|
requireSecretsSdk = createRequire(import.meta.url);
|
|
48455
48381
|
ASCII_CONTROL_PATTERN = /[\u0000-\u001f\u007f]/;
|
|
48456
48382
|
DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
48457
|
-
ClientTransportConfigurationError = class ClientTransportConfigurationError extends Error {
|
|
48458
|
-
appName;
|
|
48459
|
-
sources;
|
|
48460
|
-
constructor(appName, message, sources = []) {
|
|
48461
|
-
super(message);
|
|
48462
|
-
this.name = "ClientTransportConfigurationError";
|
|
48463
|
-
this.appName = appName;
|
|
48464
|
-
this.sources = Object.freeze([...sources]);
|
|
48465
|
-
}
|
|
48466
|
-
};
|
|
48467
48383
|
IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
48468
48384
|
AUTHORITY_OVERRIDE_HEADERS = new Set([
|
|
48469
48385
|
"host",
|
|
@@ -48474,6 +48390,97 @@ var init_transport = __esm(() => {
|
|
|
48474
48390
|
]);
|
|
48475
48391
|
});
|
|
48476
48392
|
|
|
48393
|
+
// src/lib/instance-credentials.ts
|
|
48394
|
+
import { closeSync as closeSync2, constants as constants2, fstatSync as fstatSync2, lstatSync as lstatSync3, openSync as openSync2, readSync } from "fs";
|
|
48395
|
+
function selectedSkillsProfile(env3, explicit) {
|
|
48396
|
+
const selected = explicit ?? env3.HASNA_PROFILE;
|
|
48397
|
+
if (selected === undefined)
|
|
48398
|
+
return null;
|
|
48399
|
+
const profile = selected.trim();
|
|
48400
|
+
if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(profile))
|
|
48401
|
+
throw new Error("Invalid Skills credential profile");
|
|
48402
|
+
return profile;
|
|
48403
|
+
}
|
|
48404
|
+
function skillsProfileCredentialFiles(env3, explicit) {
|
|
48405
|
+
return credentialDiskSourceList("skills", env3, selectedSkillsProfile(env3, explicit)).map((source) => source.path);
|
|
48406
|
+
}
|
|
48407
|
+
function fileIdentity(file) {
|
|
48408
|
+
try {
|
|
48409
|
+
return lstatSync3(file);
|
|
48410
|
+
} catch (error) {
|
|
48411
|
+
if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
|
|
48412
|
+
return null;
|
|
48413
|
+
throw new Error("Cannot inspect Skills instance configuration");
|
|
48414
|
+
}
|
|
48415
|
+
}
|
|
48416
|
+
function unchanged(before2, after2) {
|
|
48417
|
+
return before2 === null || after2 === null ? before2 === after2 : ["dev", "ino", "size", "mtimeMs", "ctimeMs", "mode", "uid"].every((key) => before2[key] === after2[key]);
|
|
48418
|
+
}
|
|
48419
|
+
function captureSkillsCredentialFiles(files) {
|
|
48420
|
+
const identities = files.map((file) => [file, fileIdentity(file)]);
|
|
48421
|
+
return () => {
|
|
48422
|
+
if (identities.some(([file, before2]) => !unchanged(before2, fileIdentity(file)))) {
|
|
48423
|
+
throw new Error("Skills instance configuration changed while resolving credentials; retry without sending a credential");
|
|
48424
|
+
}
|
|
48425
|
+
};
|
|
48426
|
+
}
|
|
48427
|
+
function readMetadataText(file) {
|
|
48428
|
+
let fd;
|
|
48429
|
+
try {
|
|
48430
|
+
fd = openSync2(file, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
|
|
48431
|
+
} catch (error) {
|
|
48432
|
+
if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
|
|
48433
|
+
return null;
|
|
48434
|
+
throw new Error("Cannot safely read Skills instance configuration");
|
|
48435
|
+
}
|
|
48436
|
+
try {
|
|
48437
|
+
const before2 = fstatSync2(fd);
|
|
48438
|
+
const uid = process.getuid?.() ?? process.geteuid?.();
|
|
48439
|
+
if (!before2.isFile() || ![256, 384].includes(before2.mode & 4095) || uid !== undefined && before2.uid !== uid || before2.size > 64 * 1024) {
|
|
48440
|
+
throw new Error("Unsafe Skills instance configuration; expected a bounded owner-only regular file");
|
|
48441
|
+
}
|
|
48442
|
+
const bytes = Buffer.alloc(64 * 1024 + 1);
|
|
48443
|
+
let length = 0;
|
|
48444
|
+
while (length < bytes.length) {
|
|
48445
|
+
const count = readSync(fd, bytes, length, bytes.length - length, null);
|
|
48446
|
+
if (!count)
|
|
48447
|
+
break;
|
|
48448
|
+
length += count;
|
|
48449
|
+
}
|
|
48450
|
+
if (length > 64 * 1024 || !unchanged(before2, fstatSync2(fd)) || !unchanged(before2, fileIdentity(file))) {
|
|
48451
|
+
throw new Error("Skills instance configuration changed while reading");
|
|
48452
|
+
}
|
|
48453
|
+
return bytes.subarray(0, length).toString("utf8");
|
|
48454
|
+
} finally {
|
|
48455
|
+
closeSync2(fd);
|
|
48456
|
+
}
|
|
48457
|
+
}
|
|
48458
|
+
function readSkillsInstanceMetadata(file) {
|
|
48459
|
+
const text = readMetadataText(file);
|
|
48460
|
+
if (text === null)
|
|
48461
|
+
return {};
|
|
48462
|
+
const values2 = new Map;
|
|
48463
|
+
for (const line of text.split(/\r?\n/)) {
|
|
48464
|
+
const match = /^\s*(?:export\s+)?(HASNA_SKILLS_API_URL|SKILLS_API_URL|HASNA_SKILLS_BOUND_API_URL)\s*=\s*(.*)$/.exec(line);
|
|
48465
|
+
if (!match)
|
|
48466
|
+
continue;
|
|
48467
|
+
let value = match[2].trim();
|
|
48468
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))
|
|
48469
|
+
value = value.slice(1, -1);
|
|
48470
|
+
if (!value || /[\x00-\x20\x7f]/.test(value) || values2.has(match[1]))
|
|
48471
|
+
throw new Error("Invalid Skills instance configuration");
|
|
48472
|
+
values2.set(match[1], value);
|
|
48473
|
+
}
|
|
48474
|
+
const urls = [values2.get("HASNA_SKILLS_API_URL"), values2.get("SKILLS_API_URL")].filter(Boolean);
|
|
48475
|
+
if (new Set(urls).size > 1)
|
|
48476
|
+
throw new Error("Skills API URL aliases disagree");
|
|
48477
|
+
return { apiUrl: urls[0], binding: values2.get(SKILLS_BOUND_API_URL) };
|
|
48478
|
+
}
|
|
48479
|
+
var SKILLS_BOUND_API_URL = "HASNA_SKILLS_BOUND_API_URL";
|
|
48480
|
+
var init_instance_credentials = __esm(() => {
|
|
48481
|
+
init_transport();
|
|
48482
|
+
});
|
|
48483
|
+
|
|
48477
48484
|
// src/lib/fleet-credentials.ts
|
|
48478
48485
|
var exports_fleet_credentials = {};
|
|
48479
48486
|
__export(exports_fleet_credentials, {
|
|
@@ -48481,6 +48488,7 @@ __export(exports_fleet_credentials, {
|
|
|
48481
48488
|
skillsCredentialFiles: () => skillsCredentialFiles,
|
|
48482
48489
|
skillsCredentialFilePath: () => skillsCredentialFilePath,
|
|
48483
48490
|
resolveSkillsFleet: () => resolveSkillsFleet,
|
|
48491
|
+
resolveSkillsConnection: () => resolveSkillsConnection,
|
|
48484
48492
|
resolveSkillsApiOrigin: () => resolveSkillsApiOrigin,
|
|
48485
48493
|
resolveSkillsApiKey: () => resolveSkillsApiKey,
|
|
48486
48494
|
resetLocalSkillsModeNotice: () => resetLocalSkillsModeNotice,
|
|
@@ -48498,9 +48506,6 @@ __export(exports_fleet_credentials, {
|
|
|
48498
48506
|
SKILLS_API_KEY_ENV: () => SKILLS_API_KEY_ENV,
|
|
48499
48507
|
MissingSkillsFleetError: () => MissingSkillsFleetError
|
|
48500
48508
|
});
|
|
48501
|
-
function isClientTransportConfigurationError(error) {
|
|
48502
|
-
return error instanceof ClientTransportConfigurationError || typeof error === "object" && error !== null && error.name === "ClientTransportConfigurationError";
|
|
48503
|
-
}
|
|
48504
48509
|
function isCredentialResolutionError(error) {
|
|
48505
48510
|
return error instanceof CredentialResolutionError || typeof error === "object" && error !== null && error.name === "CredentialResolutionError";
|
|
48506
48511
|
}
|
|
@@ -48511,6 +48516,9 @@ function asSkillsFleetCredentialError(error) {
|
|
|
48511
48516
|
}
|
|
48512
48517
|
function normalizeSkillsApiOrigin(apiUrl) {
|
|
48513
48518
|
const url = new URL(apiUrl);
|
|
48519
|
+
if (url.username || url.password || url.search || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) {
|
|
48520
|
+
throw new SkillsFleetCredentialError("A Skills API URL must use HTTPS (or loopback HTTP), without credentials, query or fragment", "INVALID_API_URL");
|
|
48521
|
+
}
|
|
48514
48522
|
const pathname = url.pathname.replace(/\/+$/, "");
|
|
48515
48523
|
if (pathname === "/api" || pathname === "/api/v1") {
|
|
48516
48524
|
url.pathname = "/";
|
|
@@ -48521,11 +48529,24 @@ function normalizeSkillsApiOrigin(apiUrl) {
|
|
|
48521
48529
|
}
|
|
48522
48530
|
return url.toString().replace(/\/+$/, "");
|
|
48523
48531
|
}
|
|
48524
|
-
function configuredSkillsApiUrl(env3 = process.env, keychain) {
|
|
48525
|
-
|
|
48526
|
-
|
|
48527
|
-
if (value)
|
|
48528
|
-
|
|
48532
|
+
function configuredSkillsApiUrl(env3 = process.env, keychain, profile) {
|
|
48533
|
+
const declared = SKILLS_API_URL_ENV_KEYS.filter((key) => env3[key] !== undefined).map((key) => ({ key, value: env3[key] }));
|
|
48534
|
+
for (const entry of declared) {
|
|
48535
|
+
if (!entry.value.trim() || /[\x00-\x1f\x7f]/.test(entry.value))
|
|
48536
|
+
throw new SkillsFleetCredentialError(`${entry.key} is blank or contains control characters`, "INVALID_API_URL");
|
|
48537
|
+
}
|
|
48538
|
+
const normalized = declared.map((entry) => ({ value: normalizeSkillsApiOrigin(entry.value), source: entry.key }));
|
|
48539
|
+
if (new Set(normalized.map((entry) => entry.value)).size > 1)
|
|
48540
|
+
throw new SkillsFleetCredentialError("Skills API URL aliases disagree", "INVALID_API_URL");
|
|
48541
|
+
if (normalized[0])
|
|
48542
|
+
return normalized[0];
|
|
48543
|
+
if (selectedSkillsProfile(env3, profile)) {
|
|
48544
|
+
for (const file of skillsProfileCredentialFiles(env3, profile)) {
|
|
48545
|
+
const metadata = readSkillsInstanceMetadata(file);
|
|
48546
|
+
if (metadata.apiUrl || metadata.binding)
|
|
48547
|
+
return { value: metadata.apiUrl ?? metadata.binding, source: file };
|
|
48548
|
+
}
|
|
48549
|
+
return { value: defaultFleetGatewayBaseUrl(SKILLS_APP), source: "default" };
|
|
48529
48550
|
}
|
|
48530
48551
|
const fromKeychain = keychainConfigValue(SKILLS_APP, env3, keychain);
|
|
48531
48552
|
if (fromKeychain)
|
|
@@ -48539,7 +48560,7 @@ function configuredSkillsApiUrl(env3 = process.env, keychain) {
|
|
|
48539
48560
|
return null;
|
|
48540
48561
|
}
|
|
48541
48562
|
function skillsCredentialFiles(env3 = process.env) {
|
|
48542
|
-
return
|
|
48563
|
+
return skillsProfileCredentialFiles(env3);
|
|
48543
48564
|
}
|
|
48544
48565
|
function skillsCredentialFilePath(env3 = process.env) {
|
|
48545
48566
|
const paths = skillsCredentialFiles(env3);
|
|
@@ -48560,7 +48581,11 @@ function resetLocalSkillsModeNotice() {
|
|
|
48560
48581
|
}
|
|
48561
48582
|
function resolveSkillsFleet(env3 = process.env, options = {}) {
|
|
48562
48583
|
try {
|
|
48563
|
-
|
|
48584
|
+
const snapshot = snapshotSkillsEnvironment(env3);
|
|
48585
|
+
const resolved = resolveSkillsFleetOrThrow(snapshot, snapshotSkillsOptions(env3, options));
|
|
48586
|
+
if (resolved.mode === "local" && env3 === process.env)
|
|
48587
|
+
noticeLocalSkillsMode();
|
|
48588
|
+
return resolved;
|
|
48564
48589
|
} catch (error) {
|
|
48565
48590
|
const translated = asSkillsFleetCredentialError(error);
|
|
48566
48591
|
if (translated)
|
|
@@ -48568,38 +48593,46 @@ function resolveSkillsFleet(env3 = process.env, options = {}) {
|
|
|
48568
48593
|
throw error;
|
|
48569
48594
|
}
|
|
48570
48595
|
}
|
|
48571
|
-
function
|
|
48572
|
-
|
|
48573
|
-
|
|
48574
|
-
|
|
48575
|
-
|
|
48576
|
-
|
|
48577
|
-
|
|
48578
|
-
const configured2 = configuredSkillsApiUrl(env3, options.credentials?.keychain);
|
|
48579
|
-
const credential2 = resolveCredential(SKILLS_APP, env3, options.credentials);
|
|
48580
|
-
if (!configured2 && !credential2) {
|
|
48581
|
-
if (env3 === process.env)
|
|
48582
|
-
noticeLocalSkillsMode();
|
|
48583
|
-
return { mode: "local", apiOrigin: null, apiKey: null };
|
|
48584
|
-
}
|
|
48585
|
-
if (configured2 && !credential2) {
|
|
48586
|
-
throw new SkillsFleetCredentialError(`${configured2.source} points this CLI at a Skills service but no API key resolved \u2014 ` + `refusing to run locally instead. Looked in the Keychain item ` + `hasna.credentials.${SKILLS_APP}.api-key, then ${skillsCredentialFiles(env3).join(" or ") || "no credentials file (no HOME)"}, ` + `then ${SKILLS_API_KEY_ENV}. Sign in with: skills auth login`);
|
|
48596
|
+
function snapshotSkillsEnvironment(env3) {
|
|
48597
|
+
const snapshot = {};
|
|
48598
|
+
for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(env3))) {
|
|
48599
|
+
if (!("value" in descriptor)) {
|
|
48600
|
+
if (/^(?:HASNA_|SKILLS_|HOME$|USER$)/.test(key))
|
|
48601
|
+
throw new SkillsFleetCredentialError("Accessor-backed Skills configuration is unsupported");
|
|
48602
|
+
continue;
|
|
48587
48603
|
}
|
|
48588
|
-
|
|
48604
|
+
snapshot[key] = descriptor.value;
|
|
48589
48605
|
}
|
|
48590
|
-
|
|
48591
|
-
|
|
48606
|
+
return Object.freeze(snapshot);
|
|
48607
|
+
}
|
|
48608
|
+
function snapshotSkillsOptions(env3, options) {
|
|
48609
|
+
if (env3 !== process.env)
|
|
48610
|
+
return options;
|
|
48611
|
+
return { ...options, credentials: { ...options.credentials, keychain: {
|
|
48612
|
+
...options.credentials?.keychain,
|
|
48613
|
+
enabled: options.credentials?.keychain?.enabled ?? true
|
|
48614
|
+
} } };
|
|
48615
|
+
}
|
|
48616
|
+
function resolveSkillsFleetOrThrow(env3, options) {
|
|
48617
|
+
const assertFilesUnchanged = captureSkillsCredentialFiles(skillsProfileCredentialFiles(env3, options.credentials?.profile));
|
|
48618
|
+
const configured = configuredSkillsApiUrl(env3, options.credentials?.keychain, options.credentials?.profile);
|
|
48592
48619
|
const credential = resolveCredential(SKILLS_APP, env3, options.credentials);
|
|
48593
48620
|
if (!credential) {
|
|
48594
|
-
|
|
48621
|
+
if (!configured)
|
|
48622
|
+
return { mode: "local", apiOrigin: null, apiKey: null };
|
|
48623
|
+
throw new SkillsFleetCredentialError(`${configured.source} points this CLI at a Skills service but no API key resolved \u2014 refusing to run locally instead. ` + `Looked in hasna.credentials.skills.api-key, ${skillsCredentialFiles(env3).join(" or ") || "no credentials file"}, and ${SKILLS_API_KEY_ENV}. Sign in with: skills auth login`);
|
|
48595
48624
|
}
|
|
48625
|
+
const apiOrigin = normalizeSkillsApiOrigin(configured?.value ?? defaultFleetGatewayBaseUrl(SKILLS_APP));
|
|
48626
|
+
toV1BaseUrl(apiOrigin);
|
|
48627
|
+
assertCredentialInstance(credential, apiOrigin, env3, options);
|
|
48628
|
+
assertFilesUnchanged();
|
|
48596
48629
|
const base2 = {
|
|
48597
48630
|
mode: "hosted",
|
|
48598
48631
|
apiOrigin,
|
|
48599
|
-
apiUrlSource:
|
|
48600
|
-
apiKeySource:
|
|
48601
|
-
apiKeyTier:
|
|
48602
|
-
warning:
|
|
48632
|
+
apiUrlSource: configured?.source ?? "default",
|
|
48633
|
+
apiKeySource: credential.source,
|
|
48634
|
+
apiKeyTier: credential.tier,
|
|
48635
|
+
warning: credential.warning
|
|
48603
48636
|
};
|
|
48604
48637
|
if (credential.tier === "pointer") {
|
|
48605
48638
|
return { ...base2, apiKey: null, apiKeyPointer: credential };
|
|
@@ -48609,19 +48642,37 @@ function resolveSkillsFleetOrThrow(env3, options) {
|
|
|
48609
48642
|
}
|
|
48610
48643
|
return { ...base2, apiKey: credential.apiKey, apiKeyPointer: null };
|
|
48611
48644
|
}
|
|
48645
|
+
function assertCredentialInstance(credential, apiOrigin, env3, options) {
|
|
48646
|
+
let bound;
|
|
48647
|
+
if (credential.tier === "disk" || credential.tier === "profile") {
|
|
48648
|
+
const metadata = readSkillsInstanceMetadata(credential.source);
|
|
48649
|
+
bound = metadata.binding ?? metadata.apiUrl ?? defaultFleetGatewayBaseUrl(SKILLS_APP);
|
|
48650
|
+
} else if (credential.tier === "keychain") {
|
|
48651
|
+
bound = keychainConfigValue(SKILLS_APP, env3, options.credentials?.keychain)?.value ?? defaultFleetGatewayBaseUrl(SKILLS_APP);
|
|
48652
|
+
}
|
|
48653
|
+
if (bound && normalizeSkillsApiOrigin(bound) !== apiOrigin) {
|
|
48654
|
+
throw new SkillsFleetCredentialError("The selected Skills API does not match this credential's instance. Select its profile or sign in to the new instance; no credential was sent.", "INSTANCE_CREDENTIAL_MISMATCH");
|
|
48655
|
+
}
|
|
48656
|
+
}
|
|
48612
48657
|
async function resolveSkillsApiKey(env3 = process.env, options = {}) {
|
|
48613
|
-
|
|
48658
|
+
return (await resolveSkillsConnection(env3, options))?.apiKey ?? null;
|
|
48659
|
+
}
|
|
48660
|
+
async function resolveSkillsConnection(env3 = process.env, options = {}) {
|
|
48661
|
+
const snapshotEnv = snapshotSkillsEnvironment(env3);
|
|
48662
|
+
const fleet = resolveSkillsFleet(snapshotEnv, snapshotSkillsOptions(env3, options));
|
|
48663
|
+
if (fleet.mode === "local" && env3 === process.env)
|
|
48664
|
+
noticeLocalSkillsMode();
|
|
48614
48665
|
if (fleet.mode !== "hosted")
|
|
48615
48666
|
return null;
|
|
48616
48667
|
if (fleet.apiKey)
|
|
48617
|
-
return fleet.apiKey;
|
|
48668
|
+
return { ...fleet, apiKey: fleet.apiKey };
|
|
48618
48669
|
const pointer = fleet.apiKeyPointer;
|
|
48619
48670
|
if (!pointer) {
|
|
48620
48671
|
throw new SkillsFleetCredentialError(`A Skills authority resolved but no API key did. Sign in with: skills auth login`);
|
|
48621
48672
|
}
|
|
48622
48673
|
let completed;
|
|
48623
48674
|
try {
|
|
48624
|
-
completed = await completePointerCredential(SKILLS_APP, pointer,
|
|
48675
|
+
completed = await completePointerCredential(SKILLS_APP, pointer, snapshotEnv);
|
|
48625
48676
|
} catch (error) {
|
|
48626
48677
|
const translated = asSkillsFleetCredentialError(error);
|
|
48627
48678
|
if (translated)
|
|
@@ -48631,7 +48682,7 @@ async function resolveSkillsApiKey(env3 = process.env, options = {}) {
|
|
|
48631
48682
|
if (!completed.apiKey?.trim()) {
|
|
48632
48683
|
throw new SkillsFleetCredentialError(`${credentialPointerEnvKey(SKILLS_APP)} names a vault item that produced an empty Skills API key \u2014 ` + `refusing to send an unauthenticated request.`);
|
|
48633
48684
|
}
|
|
48634
|
-
return completed.apiKey;
|
|
48685
|
+
return { ...fleet, apiKey: completed.apiKey, apiKeyPointer: null };
|
|
48635
48686
|
}
|
|
48636
48687
|
async function requireSkillsApiKey(action = "This command", env3 = process.env, options = {}) {
|
|
48637
48688
|
const apiKey = await resolveSkillsApiKey(env3, options);
|
|
@@ -48639,22 +48690,19 @@ async function requireSkillsApiKey(action = "This command", env3 = process.env,
|
|
|
48639
48690
|
throw new MissingSkillsFleetError(action);
|
|
48640
48691
|
return apiKey;
|
|
48641
48692
|
}
|
|
48642
|
-
function stripV1(baseUrl) {
|
|
48643
|
-
return baseUrl.replace(/\/v1$/, "").replace(/\/+$/, "");
|
|
48644
|
-
}
|
|
48645
48693
|
async function skillsCredentialOrReason(env3 = process.env, options = {}) {
|
|
48646
48694
|
try {
|
|
48647
|
-
const
|
|
48648
|
-
return
|
|
48695
|
+
const connection = await resolveSkillsConnection(env3, options);
|
|
48696
|
+
return connection ? { apiKey: connection.apiKey, apiOrigin: connection.apiOrigin, reason: null } : { apiKey: null, apiOrigin: null, reason: null };
|
|
48649
48697
|
} catch (error) {
|
|
48650
48698
|
if (error instanceof SkillsFleetCredentialError || error?.name === "SkillsFleetCredentialError") {
|
|
48651
|
-
return { apiKey: null, reason: error.message };
|
|
48699
|
+
return { apiKey: null, apiOrigin: null, reason: error.message };
|
|
48652
48700
|
}
|
|
48653
48701
|
throw error;
|
|
48654
48702
|
}
|
|
48655
48703
|
}
|
|
48656
48704
|
function resolveSkillsApiOrigin(env3 = process.env, options = {}) {
|
|
48657
|
-
const configured = configuredSkillsApiUrl(env3, options.credentials?.keychain);
|
|
48705
|
+
const configured = configuredSkillsApiUrl(env3, options.credentials?.keychain, options.credentials?.profile);
|
|
48658
48706
|
if (configured) {
|
|
48659
48707
|
toV1BaseUrl(configured.value);
|
|
48660
48708
|
return { origin: normalizeSkillsApiOrigin(configured.value), source: configured.source };
|
|
@@ -48677,6 +48725,7 @@ function requireSkillsFleet(action = "This command", env3 = process.env, options
|
|
|
48677
48725
|
var SKILLS_APP = "skills", ENV_KEYS, SKILLS_API_URL_ENV_KEYS, SKILLS_API_KEY_ENV_KEYS, SKILLS_API_URL_ENV, SKILLS_API_KEY_ENV, SkillsFleetCredentialError, localNoticePrinted = false, MissingSkillsFleetError;
|
|
48678
48726
|
var init_fleet_credentials = __esm(() => {
|
|
48679
48727
|
init_transport();
|
|
48728
|
+
init_instance_credentials();
|
|
48680
48729
|
ENV_KEYS = clientTransportEnvKeys(SKILLS_APP);
|
|
48681
48730
|
SKILLS_API_URL_ENV_KEYS = ENV_KEYS.apiUrlKeys;
|
|
48682
48731
|
SKILLS_API_KEY_ENV_KEYS = ENV_KEYS.apiKeyKeys;
|
|
@@ -48889,12 +48938,13 @@ var init_remote_registry = __esm(() => {
|
|
|
48889
48938
|
|
|
48890
48939
|
// src/lib/auth-store.ts
|
|
48891
48940
|
import { chmodSync, existsSync as existsSync15, mkdirSync as mkdirSync7, readFileSync as readFileSync12, renameSync as renameSync4, statSync as statSync9, unlinkSync, writeFileSync as writeFileSync7 } from "fs";
|
|
48892
|
-
import { dirname as dirname6, join as join16 } from "path";
|
|
48941
|
+
import { basename as basename4, dirname as dirname6, join as join16 } from "path";
|
|
48893
48942
|
function getAuthFilePath(env3 = process.env) {
|
|
48894
48943
|
return skillsCredentialFilePath(env3);
|
|
48895
48944
|
}
|
|
48896
48945
|
function getIdentityFilePath(env3 = process.env) {
|
|
48897
|
-
|
|
48946
|
+
const file = skillsCredentialFilePath(env3);
|
|
48947
|
+
return join16(dirname6(file), basename4(file).replace(/^credentials/, "identity") + ".json");
|
|
48898
48948
|
}
|
|
48899
48949
|
function getAuthIdentity(env3 = process.env) {
|
|
48900
48950
|
return readIdentity(env3);
|
|
@@ -48905,6 +48955,10 @@ function readIdentity(env3 = process.env) {
|
|
|
48905
48955
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
48906
48956
|
return {};
|
|
48907
48957
|
const record = parsed;
|
|
48958
|
+
const selected = resolveSkillsApiOrigin(env3)?.origin;
|
|
48959
|
+
const bound = typeof record.apiUrl === "string" ? record.apiUrl : readCredentialValue(SKILLS_BOUND_API_URL, env3) ?? readStoredApiUrl(env3) ?? defaultFleetGatewayBaseUrl("skills");
|
|
48960
|
+
if (selected && normalizeSkillsApiOrigin(bound) !== selected)
|
|
48961
|
+
return {};
|
|
48908
48962
|
const identity2 = {};
|
|
48909
48963
|
for (const field of ["email", "orgId", "orgSlug", "userId"]) {
|
|
48910
48964
|
const value = record[field];
|
|
@@ -48982,14 +49036,15 @@ function readCredentialValue(key, env3 = process.env) {
|
|
|
48982
49036
|
}
|
|
48983
49037
|
return null;
|
|
48984
49038
|
}
|
|
48985
|
-
function saveAuthConfig(config, env3 = process.env) {
|
|
49039
|
+
function saveAuthConfig(config, env3 = process.env, authenticatedOrigin) {
|
|
48986
49040
|
const apiKey = config.apiKey.trim();
|
|
48987
49041
|
if (!apiKey)
|
|
48988
49042
|
throw new Error("Refusing to store an empty Skills API key.");
|
|
48989
49043
|
if (/[^\t\x20-\x7e]/.test(apiKey)) {
|
|
48990
49044
|
throw new Error("Refusing to store a Skills API key containing control characters or non-ASCII bytes.");
|
|
48991
49045
|
}
|
|
48992
|
-
const
|
|
49046
|
+
const apiUrl = authenticatedOrigin ? normalizeSkillsApiOrigin(authenticatedOrigin) : resolveSkillsApiOrigin(env3)?.origin ?? defaultFleetGatewayBaseUrl("skills");
|
|
49047
|
+
const file = writeCredentialValues({ SKILLS_API_KEY: null, SKILLS_API_URL: null, [SKILLS_API_KEY_ENV]: apiKey, [SKILLS_BOUND_API_URL]: apiUrl, [SKILLS_API_URL_ENV]: apiUrl }, env3);
|
|
48993
49048
|
const identity2 = {};
|
|
48994
49049
|
for (const field of ["email", "orgId", "orgSlug", "userId"]) {
|
|
48995
49050
|
const value = config[field];
|
|
@@ -48998,8 +49053,9 @@ function saveAuthConfig(config, env3 = process.env) {
|
|
|
48998
49053
|
}
|
|
48999
49054
|
const identityFile = getIdentityFilePath(env3);
|
|
49000
49055
|
if (Object.keys(identity2).length > 0) {
|
|
49001
|
-
writeFileSync7(identityFile, JSON.stringify(identity2, null, 2) + `
|
|
49056
|
+
writeFileSync7(identityFile, JSON.stringify({ ...identity2, apiUrl }, null, 2) + `
|
|
49002
49057
|
`, { mode: 384 });
|
|
49058
|
+
chmodSync(identityFile, 384);
|
|
49003
49059
|
} else {
|
|
49004
49060
|
try {
|
|
49005
49061
|
unlinkSync(identityFile);
|
|
@@ -49008,23 +49064,29 @@ function saveAuthConfig(config, env3 = process.env) {
|
|
|
49008
49064
|
return file;
|
|
49009
49065
|
}
|
|
49010
49066
|
function saveApiUrl(apiUrl, env3 = process.env) {
|
|
49011
|
-
|
|
49067
|
+
const next = apiUrl === null ? null : normalizeSkillsApiOrigin(apiUrl);
|
|
49068
|
+
const values2 = { [SKILLS_API_URL_ENV]: next, SKILLS_API_URL: null };
|
|
49069
|
+
if (!readCredentialValue(SKILLS_BOUND_API_URL, env3) && (readCredentialValue(SKILLS_API_KEY_ENV, env3) || readCredentialValue("SKILLS_API_KEY", env3))) {
|
|
49070
|
+
values2[SKILLS_BOUND_API_URL] = normalizeSkillsApiOrigin(readStoredApiUrl(env3) ?? defaultFleetGatewayBaseUrl("skills"));
|
|
49071
|
+
}
|
|
49072
|
+
return writeCredentialValues(values2, env3);
|
|
49012
49073
|
}
|
|
49013
49074
|
function readStoredApiUrl(env3 = process.env) {
|
|
49014
|
-
return readCredentialValue(SKILLS_API_URL_ENV, env3);
|
|
49075
|
+
return readCredentialValue(SKILLS_API_URL_ENV, env3) ?? readCredentialValue("SKILLS_API_URL", env3);
|
|
49015
49076
|
}
|
|
49016
49077
|
function clearAuthConfig(env3 = process.env) {
|
|
49017
49078
|
try {
|
|
49018
|
-
writeCredentialValues({ [SKILLS_API_KEY_ENV]: null }, env3);
|
|
49079
|
+
writeCredentialValues({ [SKILLS_API_KEY_ENV]: null, SKILLS_API_KEY: null, [SKILLS_BOUND_API_URL]: null }, env3);
|
|
49019
49080
|
} catch {}
|
|
49020
49081
|
try {
|
|
49021
49082
|
unlinkSync(getIdentityFilePath(env3));
|
|
49022
49083
|
} catch {}
|
|
49023
49084
|
let stillResolves;
|
|
49024
49085
|
try {
|
|
49025
|
-
stillResolves =
|
|
49086
|
+
stillResolves = resolveCredential("skills", env3) !== null;
|
|
49026
49087
|
} catch {
|
|
49027
|
-
|
|
49088
|
+
const emptyProfile = selectedSkillsProfile(env3) && !env3.HASNA_SKILLS_API_KEY_OVERRIDE && !env3.HASNA_SKILLS_API_KEY_REF && !readCredentialValue(SKILLS_API_KEY_ENV, env3) && !readCredentialValue("SKILLS_API_KEY", env3);
|
|
49089
|
+
stillResolves = !emptyProfile;
|
|
49028
49090
|
}
|
|
49029
49091
|
return { stillResolves };
|
|
49030
49092
|
}
|
|
@@ -49039,7 +49101,10 @@ function credentialFileMode(env3 = process.env) {
|
|
|
49039
49101
|
}
|
|
49040
49102
|
}
|
|
49041
49103
|
var init_auth_store = __esm(() => {
|
|
49104
|
+
init_transport();
|
|
49105
|
+
init_instance_credentials();
|
|
49042
49106
|
init_fleet_credentials();
|
|
49107
|
+
init_transport();
|
|
49043
49108
|
init_fleet_credentials();
|
|
49044
49109
|
});
|
|
49045
49110
|
|
|
@@ -49087,6 +49152,169 @@ function pickNumber(record, key) {
|
|
|
49087
49152
|
}
|
|
49088
49153
|
var REMOTE_SKILL_RUN_CONTRACT_VERSION = 1;
|
|
49089
49154
|
|
|
49155
|
+
// src/lib/remote-account.ts
|
|
49156
|
+
function creditCount(value) {
|
|
49157
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 2147483647) {
|
|
49158
|
+
throw new Error("The Skills server returned an invalid credit count");
|
|
49159
|
+
}
|
|
49160
|
+
return value;
|
|
49161
|
+
}
|
|
49162
|
+
function parseRemoteRunQuote(value) {
|
|
49163
|
+
const quote = object(value);
|
|
49164
|
+
const pricing = object(quote.pricing);
|
|
49165
|
+
if (typeof quote.skill !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(quote.skill))
|
|
49166
|
+
throw new Error("Invalid quoted skill");
|
|
49167
|
+
const costCents = creditCount(pricing.costCredits ?? pricing.costCents);
|
|
49168
|
+
if (pricing.costCredits !== undefined && pricing.costCents !== undefined && pricing.costCents !== costCents)
|
|
49169
|
+
throw new Error("Inconsistent quoted credit count");
|
|
49170
|
+
if (quote.availability && object(quote.availability).status !== "available")
|
|
49171
|
+
throw new Error("This skill is unavailable for remote execution");
|
|
49172
|
+
return { ...quote, skill: quote.skill, pricing: { ...pricing, costCredits: costCents, costCents, formattedCost: `${costCents} credits` } };
|
|
49173
|
+
}
|
|
49174
|
+
function parseRemoteCreditPacks(value) {
|
|
49175
|
+
if (!Array.isArray(value))
|
|
49176
|
+
throw new Error("Invalid credit pack response");
|
|
49177
|
+
const ids = new Set;
|
|
49178
|
+
return value.map((value2) => {
|
|
49179
|
+
const row = object(value2);
|
|
49180
|
+
const counts = [row.credits, row.creditsCents, row.amountCents].filter((value3) => value3 !== undefined).map(creditCount);
|
|
49181
|
+
if (!counts.length || counts[0] === 0 || counts.some((count) => count !== counts[0]))
|
|
49182
|
+
throw new Error("Inconsistent credit pack counts");
|
|
49183
|
+
const credits = counts[0];
|
|
49184
|
+
const id = row.id ?? `credits_${credits}`;
|
|
49185
|
+
if (typeof id !== "string" || !/^[a-z0-9][a-z0-9_-]{0,99}$/.test(id) || ids.has(id))
|
|
49186
|
+
throw new Error("Invalid credit pack ID");
|
|
49187
|
+
if (id.startsWith("credits_") && id !== `credits_${credits}`)
|
|
49188
|
+
throw new Error("Inconsistent credit pack ID");
|
|
49189
|
+
ids.add(id);
|
|
49190
|
+
return { id, credits, ...row.expiresInDays === undefined ? {} : { expiresInDays: creditCount(row.expiresInDays) } };
|
|
49191
|
+
});
|
|
49192
|
+
}
|
|
49193
|
+
function parseRemoteBillingStatus(value) {
|
|
49194
|
+
const row = object(value);
|
|
49195
|
+
const counts = [row.creditBalance, row.balanceCents].filter((value2) => value2 !== undefined).map(creditCount);
|
|
49196
|
+
if (!counts.length || counts.some((count) => count !== counts[0]))
|
|
49197
|
+
throw new Error("Inconsistent credit balance");
|
|
49198
|
+
return {
|
|
49199
|
+
creditBalance: counts[0],
|
|
49200
|
+
formattedCreditBalance: `${counts[0]} credits`,
|
|
49201
|
+
...typeof row.plan === "string" ? { plan: row.plan } : {},
|
|
49202
|
+
...typeof row.hasPaymentMethod === "boolean" ? { hasPaymentMethod: row.hasPaymentMethod } : {}
|
|
49203
|
+
};
|
|
49204
|
+
}
|
|
49205
|
+
function parseRemoteCheckout(value) {
|
|
49206
|
+
const row = object(value);
|
|
49207
|
+
if (typeof row.url !== "string")
|
|
49208
|
+
throw new Error("Invalid checkout URL");
|
|
49209
|
+
const url = new URL(row.url);
|
|
49210
|
+
if (url.protocol !== "https:" || url.username || url.password)
|
|
49211
|
+
throw new Error("Invalid checkout URL");
|
|
49212
|
+
return { url: row.url };
|
|
49213
|
+
}
|
|
49214
|
+
function object(value) {
|
|
49215
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
49216
|
+
throw new Error("Invalid Skills server response");
|
|
49217
|
+
return value;
|
|
49218
|
+
}
|
|
49219
|
+
var RemoteCreditApprovalError;
|
|
49220
|
+
var init_remote_account = __esm(() => {
|
|
49221
|
+
RemoteCreditApprovalError = class RemoteCreditApprovalError extends Error {
|
|
49222
|
+
requiredCredits;
|
|
49223
|
+
maximumCredits;
|
|
49224
|
+
code = "CREDIT_APPROVAL_REQUIRED";
|
|
49225
|
+
constructor(requiredCredits, maximumCredits) {
|
|
49226
|
+
super(`This run requires ${requiredCredits} credits; the approved maximum is ${maximumCredits}. Quote the run and explicitly approve its cost.`);
|
|
49227
|
+
this.requiredCredits = requiredCredits;
|
|
49228
|
+
this.maximumCredits = maximumCredits;
|
|
49229
|
+
this.name = "RemoteCreditApprovalError";
|
|
49230
|
+
}
|
|
49231
|
+
};
|
|
49232
|
+
});
|
|
49233
|
+
|
|
49234
|
+
// src/lib/remote-files.ts
|
|
49235
|
+
var exports_remote_files = {};
|
|
49236
|
+
__export(exports_remote_files, {
|
|
49237
|
+
sha256: () => sha256,
|
|
49238
|
+
readBoundedResponse: () => readBoundedResponse,
|
|
49239
|
+
describeRemoteFiles: () => describeRemoteFiles,
|
|
49240
|
+
decodeRemoteFiles: () => decodeRemoteFiles,
|
|
49241
|
+
MAX_REMOTE_FILE_BYTES: () => MAX_REMOTE_FILE_BYTES
|
|
49242
|
+
});
|
|
49243
|
+
import { createHash as createHash2 } from "crypto";
|
|
49244
|
+
function describeRemoteFiles(files) {
|
|
49245
|
+
if (files.length > 10)
|
|
49246
|
+
throw new Error("At most 10 input files are supported");
|
|
49247
|
+
const names = new Set;
|
|
49248
|
+
let total = 0;
|
|
49249
|
+
return files.map((file) => {
|
|
49250
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(file.name) || file.name === "." || file.name === ".." || names.has(file.name))
|
|
49251
|
+
throw new Error("Input file names must be unique safe basenames");
|
|
49252
|
+
names.add(file.name);
|
|
49253
|
+
total += file.bytes.byteLength;
|
|
49254
|
+
if (file.bytes.byteLength > 20 * 1024 * 1024 || total > 50 * 1024 * 1024)
|
|
49255
|
+
throw new Error("Input files exceed the supported size limit");
|
|
49256
|
+
return { name: file.name, sizeBytes: file.bytes.byteLength, sha256: sha256(file.bytes), contentType: file.contentType ?? "application/octet-stream" };
|
|
49257
|
+
});
|
|
49258
|
+
}
|
|
49259
|
+
function sha256(bytes) {
|
|
49260
|
+
return createHash2("sha256").update(bytes).digest("hex");
|
|
49261
|
+
}
|
|
49262
|
+
async function readBoundedResponse(response, maximum) {
|
|
49263
|
+
if (!Number.isSafeInteger(maximum) || maximum < 0 || maximum > MAX_REMOTE_FILE_BYTES)
|
|
49264
|
+
throw new Error("Invalid artifact size limit");
|
|
49265
|
+
const length = response.headers.get("content-length");
|
|
49266
|
+
if (length && (!/^\d+$/.test(length) || Number(length) > maximum)) {
|
|
49267
|
+
await response.body?.cancel();
|
|
49268
|
+
throw new Error("Artifact exceeds its declared size limit");
|
|
49269
|
+
}
|
|
49270
|
+
const reader = response.body?.getReader();
|
|
49271
|
+
if (!reader)
|
|
49272
|
+
return new Uint8Array;
|
|
49273
|
+
const chunks = [];
|
|
49274
|
+
let size2 = 0;
|
|
49275
|
+
try {
|
|
49276
|
+
while (true) {
|
|
49277
|
+
const next = await reader.read();
|
|
49278
|
+
if (next.done)
|
|
49279
|
+
break;
|
|
49280
|
+
size2 += next.value.byteLength;
|
|
49281
|
+
if (size2 > maximum)
|
|
49282
|
+
throw new Error("Artifact exceeds its declared size limit");
|
|
49283
|
+
chunks.push(next.value);
|
|
49284
|
+
}
|
|
49285
|
+
} catch (error) {
|
|
49286
|
+
await reader.cancel().catch(() => {});
|
|
49287
|
+
throw error;
|
|
49288
|
+
} finally {
|
|
49289
|
+
reader.releaseLock();
|
|
49290
|
+
}
|
|
49291
|
+
const bytes = new Uint8Array(size2);
|
|
49292
|
+
let offset = 0;
|
|
49293
|
+
for (const chunk2 of chunks) {
|
|
49294
|
+
bytes.set(chunk2, offset);
|
|
49295
|
+
offset += chunk2.byteLength;
|
|
49296
|
+
}
|
|
49297
|
+
return bytes;
|
|
49298
|
+
}
|
|
49299
|
+
function decodeRemoteFiles(files) {
|
|
49300
|
+
let total = 0;
|
|
49301
|
+
const decoded = files.map((file) => {
|
|
49302
|
+
if (file.base64.length > 1398104 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(file.base64))
|
|
49303
|
+
throw new Error("Invalid inline input encoding");
|
|
49304
|
+
const bytes = Buffer.from(file.base64, "base64");
|
|
49305
|
+
total += bytes.byteLength;
|
|
49306
|
+
if (total > 1024 * 1024 || bytes.toString("base64") !== file.base64)
|
|
49307
|
+
throw new Error("Inline inputs must total at most 1 MiB");
|
|
49308
|
+
return { name: file.name, bytes, contentType: file.contentType };
|
|
49309
|
+
});
|
|
49310
|
+
describeRemoteFiles(decoded);
|
|
49311
|
+
return decoded;
|
|
49312
|
+
}
|
|
49313
|
+
var MAX_REMOTE_FILE_BYTES;
|
|
49314
|
+
var init_remote_files = __esm(() => {
|
|
49315
|
+
MAX_REMOTE_FILE_BYTES = 64 * 1024 * 1024;
|
|
49316
|
+
});
|
|
49317
|
+
|
|
49090
49318
|
// src/lib/remote-client.ts
|
|
49091
49319
|
var exports_remote_client = {};
|
|
49092
49320
|
__export(exports_remote_client, {
|
|
@@ -49100,13 +49328,16 @@ __export(exports_remote_client, {
|
|
|
49100
49328
|
class RemoteSkillsClient {
|
|
49101
49329
|
apiUrl;
|
|
49102
49330
|
apiKey;
|
|
49331
|
+
capabilities;
|
|
49103
49332
|
constructor(apiKey, apiUrl = getApiUrl()) {
|
|
49104
49333
|
this.apiKey = apiKey;
|
|
49105
|
-
this.apiUrl = apiUrl
|
|
49334
|
+
this.apiUrl = normalizeSkillsApiOrigin(apiUrl);
|
|
49106
49335
|
}
|
|
49107
49336
|
async request(path, options) {
|
|
49108
49337
|
return fetch(`${this.apiUrl}${path}`, {
|
|
49109
49338
|
...options,
|
|
49339
|
+
redirect: "error",
|
|
49340
|
+
signal: options?.signal ?? AbortSignal.timeout(15000),
|
|
49110
49341
|
headers: {
|
|
49111
49342
|
Authorization: `Bearer ${this.apiKey}`,
|
|
49112
49343
|
"Content-Type": "application/json",
|
|
@@ -49129,8 +49360,7 @@ class RemoteSkillsClient {
|
|
|
49129
49360
|
return response;
|
|
49130
49361
|
}
|
|
49131
49362
|
async listSkills() {
|
|
49132
|
-
|
|
49133
|
-
return res.json();
|
|
49363
|
+
return this.arrayResponse("/api/v1/skills");
|
|
49134
49364
|
}
|
|
49135
49365
|
async getSkillMd(slug) {
|
|
49136
49366
|
const res = await this.request(`/api/v1/skills/${slug}/skill.md`);
|
|
@@ -49152,39 +49382,217 @@ class RemoteSkillsClient {
|
|
|
49152
49382
|
} catch {}
|
|
49153
49383
|
return { status: res.status, body };
|
|
49154
49384
|
}
|
|
49155
|
-
async submitRun(slug, input, args) {
|
|
49156
|
-
|
|
49385
|
+
async submitRun(slug, input, args, approval = {}) {
|
|
49386
|
+
if (approval.idempotencyKey !== undefined && !/^[A-Za-z0-9._:-]{1,128}$/.test(approval.idempotencyKey))
|
|
49387
|
+
throw new Error("Idempotency key must be 1-128 URL-safe characters");
|
|
49388
|
+
if (approval.maxCostCents !== undefined)
|
|
49389
|
+
creditCount(approval.maxCostCents);
|
|
49390
|
+
if (approval.maxCredits !== undefined)
|
|
49391
|
+
creditCount(approval.maxCredits);
|
|
49392
|
+
if (approval.maxCredits !== undefined && approval.maxCostCents !== undefined && approval.maxCredits !== approval.maxCostCents)
|
|
49393
|
+
throw new Error("Credit approval fields disagree");
|
|
49394
|
+
const res = await this.request(`/api/v1/runs/${encodeURIComponent(slug)}`, {
|
|
49157
49395
|
method: "POST",
|
|
49158
|
-
body: JSON.stringify({
|
|
49396
|
+
body: JSON.stringify({
|
|
49397
|
+
input,
|
|
49398
|
+
args,
|
|
49399
|
+
...approval.maxCredits !== undefined ? { maxCredits: approval.maxCredits } : {},
|
|
49400
|
+
...approval.maxCostCents !== undefined ? { maxCostCents: approval.maxCostCents } : {},
|
|
49401
|
+
...approval.idempotencyKey !== undefined ? { idempotencyKey: approval.idempotencyKey } : {},
|
|
49402
|
+
...approval.inputFiles !== undefined ? { files: approval.inputFiles } : {}
|
|
49403
|
+
})
|
|
49159
49404
|
});
|
|
49160
49405
|
return normalizeRemoteSkillRunContract(await res.json(), slug);
|
|
49161
49406
|
}
|
|
49407
|
+
async quoteRun(slug, input = {}, args = []) {
|
|
49408
|
+
const response = await this.requestNewRoute(`/api/v1/skills/${encodeURIComponent(slug)}/quote`, {
|
|
49409
|
+
method: "POST",
|
|
49410
|
+
body: JSON.stringify({ input, args })
|
|
49411
|
+
});
|
|
49412
|
+
return parseRemoteRunQuote(await response.json());
|
|
49413
|
+
}
|
|
49414
|
+
getCapabilities() {
|
|
49415
|
+
if (!this.capabilities)
|
|
49416
|
+
this.capabilities = (async () => {
|
|
49417
|
+
const value = await (await this.requestNewRoute("/api/v1/capabilities")).json();
|
|
49418
|
+
if (value.contractVersion !== 1 || value.apiVersion !== 1 || !Array.isArray(value.capabilities) || value.capabilities.some((item) => typeof item !== "string"))
|
|
49419
|
+
throw new Error("Unsupported Skills server capability contract");
|
|
49420
|
+
const billing = value.billing;
|
|
49421
|
+
return { contractVersion: 1, apiVersion: 1, capabilities: value.capabilities, ...billing ? { billing } : {} };
|
|
49422
|
+
})();
|
|
49423
|
+
return this.capabilities;
|
|
49424
|
+
}
|
|
49425
|
+
async submitQuotedRun(slug, input = {}, args = [], approval = {}) {
|
|
49426
|
+
const maximum = creditCount(approval.maxCredits ?? approval.maxCostCents ?? 0);
|
|
49427
|
+
if (approval.maxCostCents !== undefined && approval.maxCostCents !== maximum)
|
|
49428
|
+
throw new Error("Credit approval fields disagree");
|
|
49429
|
+
const quote = await this.quoteRun(slug, input, args);
|
|
49430
|
+
if (quote.pricing.costCents > maximum)
|
|
49431
|
+
throw new RemoteCreditApprovalError(quote.pricing.costCents, maximum);
|
|
49432
|
+
const capabilities = await this.getCapabilities();
|
|
49433
|
+
if (!capabilities.capabilities.includes("runs.submit") || capabilities.billing?.boundedRunApproval !== true || capabilities.billing.unit !== "credits") {
|
|
49434
|
+
throw new Error("The configured server does not support bounded credit approval; refusing remote submission");
|
|
49435
|
+
}
|
|
49436
|
+
return this.submitRun(quote.skill, input, args, { ...approval, maxCredits: maximum, maxCostCents: maximum });
|
|
49437
|
+
}
|
|
49438
|
+
async getIdentity() {
|
|
49439
|
+
return (await this.requestNewRoute("/api/auth/whoami")).json();
|
|
49440
|
+
}
|
|
49441
|
+
async listApiKeys() {
|
|
49442
|
+
return this.arrayResponse("/api/auth/keys");
|
|
49443
|
+
}
|
|
49444
|
+
async createApiKey(name, scopes) {
|
|
49445
|
+
if (!name.trim() || name.length > 100)
|
|
49446
|
+
throw new Error("API key name must be 1-100 characters");
|
|
49447
|
+
const value = await (await this.requestNewRoute("/api/auth/keys", { method: "POST", body: JSON.stringify({ name, ...scopes ? { scopes } : {} }) })).json();
|
|
49448
|
+
if (!value || typeof value.key !== "string" || !value.key.trim())
|
|
49449
|
+
throw new Error("The server did not return a created API key");
|
|
49450
|
+
return value;
|
|
49451
|
+
}
|
|
49452
|
+
async revokeApiKey(keyId) {
|
|
49453
|
+
return (await this.requestNewRoute(`/api/auth/keys/${encodeURIComponent(keyId)}`, { method: "DELETE" })).json();
|
|
49454
|
+
}
|
|
49455
|
+
async getBillingStatus() {
|
|
49456
|
+
return parseRemoteBillingStatus(await (await this.requestNewRoute("/api/v1/billing/status")).json());
|
|
49457
|
+
}
|
|
49458
|
+
async listCreditPacks() {
|
|
49459
|
+
return parseRemoteCreditPacks(await (await this.requestNewRoute("/api/v1/billing/credits")).json());
|
|
49460
|
+
}
|
|
49461
|
+
async createCreditCheckout(packId) {
|
|
49462
|
+
const packs = await this.listCreditPacks();
|
|
49463
|
+
if (!packs.some((pack) => pack.id === packId))
|
|
49464
|
+
throw new Error("Choose a credit pack returned by skills credits packs");
|
|
49465
|
+
return parseRemoteCheckout(await (await this.requestNewRoute("/api/v1/billing/credits", {
|
|
49466
|
+
method: "POST",
|
|
49467
|
+
body: JSON.stringify({ packId })
|
|
49468
|
+
})).json());
|
|
49469
|
+
}
|
|
49470
|
+
async getUsage() {
|
|
49471
|
+
return this.arrayResponse("/api/v1/billing/usage");
|
|
49472
|
+
}
|
|
49473
|
+
async listInvoices() {
|
|
49474
|
+
return this.arrayResponse("/api/v1/billing/invoices");
|
|
49475
|
+
}
|
|
49476
|
+
async createBillingCheckout() {
|
|
49477
|
+
return this.checkoutResponse("/api/v1/billing/checkout");
|
|
49478
|
+
}
|
|
49479
|
+
async createBillingPortal() {
|
|
49480
|
+
return this.checkoutResponse("/api/v1/billing/portal");
|
|
49481
|
+
}
|
|
49482
|
+
async cancelRun(runId) {
|
|
49483
|
+
return this.controlRun(runId, "cancel");
|
|
49484
|
+
}
|
|
49485
|
+
async resumeRun(runId) {
|
|
49486
|
+
return this.controlRun(runId, "resume");
|
|
49487
|
+
}
|
|
49488
|
+
async controlRun(runId, action) {
|
|
49489
|
+
const response = await this.requestNewRoute(`/api/v1/runs/${encodeURIComponent(runId)}/${action}`, { method: "POST", body: "{}" });
|
|
49490
|
+
return normalizeRemoteSkillRunContract(await response.json());
|
|
49491
|
+
}
|
|
49492
|
+
async checkoutResponse(path) {
|
|
49493
|
+
return parseRemoteCheckout(await (await this.requestNewRoute(path, { method: "POST", body: "{}" })).json());
|
|
49494
|
+
}
|
|
49495
|
+
async arrayResponse(path) {
|
|
49496
|
+
const rows = await (await this.requestNewRoute(path)).json();
|
|
49497
|
+
if (!Array.isArray(rows) || rows.some((row) => !row || typeof row !== "object" || Array.isArray(row)))
|
|
49498
|
+
throw new Error("Invalid Skills server list response");
|
|
49499
|
+
return rows;
|
|
49500
|
+
}
|
|
49162
49501
|
async getRun(runId) {
|
|
49163
|
-
const
|
|
49164
|
-
|
|
49502
|
+
const path = `/api/v1/runs/${encodeURIComponent(runId)}`;
|
|
49503
|
+
const res = await this.request(path);
|
|
49504
|
+
if (res.status === 404)
|
|
49165
49505
|
return null;
|
|
49506
|
+
if (!res.ok)
|
|
49507
|
+
throw new RemoteRequestError(path, res.status, res.statusText);
|
|
49166
49508
|
return normalizeRemoteSkillRunContract(await res.json());
|
|
49167
49509
|
}
|
|
49168
49510
|
async getRunLogs(runId) {
|
|
49169
|
-
|
|
49170
|
-
if (!res.ok)
|
|
49171
|
-
return [];
|
|
49172
|
-
const payload = await res.json();
|
|
49173
|
-
return Array.isArray(payload) ? payload : [];
|
|
49511
|
+
return this.arrayResponse(`/api/v1/runs/${encodeURIComponent(runId)}/logs`);
|
|
49174
49512
|
}
|
|
49175
49513
|
async listRuns(limit = 20) {
|
|
49176
|
-
|
|
49177
|
-
|
|
49514
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
49515
|
+
throw new Error("Run limit must be an integer from 1 to 100");
|
|
49516
|
+
return this.arrayResponse(`/api/v1/runs?limit=${limit}`);
|
|
49178
49517
|
}
|
|
49179
49518
|
async getRunArtifacts(runId) {
|
|
49180
|
-
|
|
49181
|
-
return res.json();
|
|
49519
|
+
return this.arrayResponse(`/api/v1/runs/${encodeURIComponent(runId)}/artifacts`);
|
|
49182
49520
|
}
|
|
49183
49521
|
async downloadRunArtifact(runId, artifactId) {
|
|
49184
|
-
return this.request(`/api/v1/runs/${runId}/artifacts/${artifactId}/download`, {
|
|
49522
|
+
return this.request(`/api/v1/runs/${encodeURIComponent(runId)}/artifacts/${encodeURIComponent(artifactId)}/download`, {
|
|
49185
49523
|
method: "GET"
|
|
49186
49524
|
});
|
|
49187
49525
|
}
|
|
49526
|
+
async getVerifiedRunArtifact(runId, artifactId, maximumBytes = MAX_REMOTE_FILE_BYTES) {
|
|
49527
|
+
const artifacts = await this.getRunArtifacts(runId);
|
|
49528
|
+
const artifact = artifacts.find((row) => row.id === artifactId);
|
|
49529
|
+
if (!artifact)
|
|
49530
|
+
throw new Error("Run artifact not found");
|
|
49531
|
+
if (!Number.isSafeInteger(artifact.byteSize) || artifact.byteSize < 0 || artifact.byteSize > maximumBytes || typeof artifact.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(artifact.sha256))
|
|
49532
|
+
throw new Error("The server does not provide valid artifact integrity metadata");
|
|
49533
|
+
const response = await this.downloadRunArtifact(runId, artifactId);
|
|
49534
|
+
if (!response.ok)
|
|
49535
|
+
throw new RemoteRequestError("artifact download", response.status, response.statusText);
|
|
49536
|
+
const bytes = await readBoundedResponse(response, artifact.byteSize);
|
|
49537
|
+
if (bytes.byteLength !== artifact.byteSize || sha256(bytes) !== artifact.sha256)
|
|
49538
|
+
throw new Error("Artifact integrity verification failed");
|
|
49539
|
+
return { id: artifactId, fileName: String(artifact.fileName ?? artifactId), bytes, byteSize: bytes.byteLength, sha256: artifact.sha256 };
|
|
49540
|
+
}
|
|
49541
|
+
async submitQuotedRunWithFiles(slug, input, args, files, approval = {}) {
|
|
49542
|
+
const inputFiles = describeRemoteFiles(files);
|
|
49543
|
+
if (files.length && !(await this.getCapabilities()).capabilities.includes("runs.uploads"))
|
|
49544
|
+
throw new Error("The configured server does not support input uploads");
|
|
49545
|
+
const run = await this.submitQuotedRun(slug, input, args, { ...approval, inputFiles });
|
|
49546
|
+
if (run.error || !run.id || !files.length)
|
|
49547
|
+
return run;
|
|
49548
|
+
const pastUploads = (status) => typeof status === "string" && [
|
|
49549
|
+
"running",
|
|
49550
|
+
"completed",
|
|
49551
|
+
"failed",
|
|
49552
|
+
"cancelled",
|
|
49553
|
+
"expired",
|
|
49554
|
+
"pending_approval",
|
|
49555
|
+
"approved",
|
|
49556
|
+
"waiting"
|
|
49557
|
+
].includes(status);
|
|
49558
|
+
if (pastUploads(run.status))
|
|
49559
|
+
return run;
|
|
49560
|
+
try {
|
|
49561
|
+
await this.uploadRunFiles(run.id, files);
|
|
49562
|
+
} catch {
|
|
49563
|
+
try {
|
|
49564
|
+
const current = await this.getRun(run.id);
|
|
49565
|
+
if (current && pastUploads(current.status))
|
|
49566
|
+
return current;
|
|
49567
|
+
} catch {}
|
|
49568
|
+
let cancellationRequested = false;
|
|
49569
|
+
try {
|
|
49570
|
+
await this.cancelRun(run.id);
|
|
49571
|
+
cancellationRequested = true;
|
|
49572
|
+
} catch {}
|
|
49573
|
+
throw new Error(`Input upload failed for run ${run.id}; ${cancellationRequested ? "cancellation requested" : "check its status and cancel the run"}`);
|
|
49574
|
+
}
|
|
49575
|
+
return run;
|
|
49576
|
+
}
|
|
49577
|
+
async uploadRunFiles(runId, files) {
|
|
49578
|
+
const descriptors = describeRemoteFiles(files);
|
|
49579
|
+
const response = await this.requestNewRoute(`/api/v1/runs/${encodeURIComponent(runId)}/uploads`, { method: "POST", body: JSON.stringify({ files: descriptors }) });
|
|
49580
|
+
const payload = await response.json();
|
|
49581
|
+
if (!Array.isArray(payload.files) || payload.files.length !== files.length || new Set(payload.files.map((file) => file.name)).size !== files.length)
|
|
49582
|
+
throw new Error("Invalid input upload response");
|
|
49583
|
+
for (const file of files) {
|
|
49584
|
+
const upload = payload.files.find((row) => row.name === file.name);
|
|
49585
|
+
if (!upload)
|
|
49586
|
+
throw new Error("Missing input upload URL");
|
|
49587
|
+
const url = new URL(upload.uploadUrl);
|
|
49588
|
+
if (url.username || url.password || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)))
|
|
49589
|
+
throw new Error("Unsafe input upload URL");
|
|
49590
|
+
const uploaded = await fetch(url, { method: "PUT", body: file.bytes, headers: { "Content-Type": file.contentType ?? "application/octet-stream" }, redirect: "error", signal: AbortSignal.timeout(60000) });
|
|
49591
|
+
if (!uploaded.ok)
|
|
49592
|
+
throw new Error("Input upload failed");
|
|
49593
|
+
await uploaded.body?.cancel();
|
|
49594
|
+
}
|
|
49595
|
+
}
|
|
49188
49596
|
async publishSkill(manifest, bundle, ifMatch) {
|
|
49189
49597
|
const form = new FormData;
|
|
49190
49598
|
form.set("manifest", JSON.stringify(manifest));
|
|
@@ -49197,7 +49605,9 @@ class RemoteSkillsClient {
|
|
|
49197
49605
|
return fetch(`${this.apiUrl}/api/v1/skills`, {
|
|
49198
49606
|
method: "POST",
|
|
49199
49607
|
headers,
|
|
49200
|
-
body: form
|
|
49608
|
+
body: form,
|
|
49609
|
+
redirect: "error",
|
|
49610
|
+
signal: AbortSignal.timeout(15000)
|
|
49201
49611
|
});
|
|
49202
49612
|
}
|
|
49203
49613
|
async deleteSkill(slug) {
|
|
@@ -49253,12 +49663,13 @@ class RemoteSkillsClient {
|
|
|
49253
49663
|
if (!Array.isArray(payload)) {
|
|
49254
49664
|
throw new Error("Remote tags payload did not match the expected contract (expected an array of tag names)");
|
|
49255
49665
|
}
|
|
49256
|
-
|
|
49257
|
-
|
|
49258
|
-
|
|
49259
|
-
|
|
49666
|
+
const isName = (value) => typeof value === "string" && value.trim().length > 0;
|
|
49667
|
+
if (payload.every(isName))
|
|
49668
|
+
return payload;
|
|
49669
|
+
if (payload.every((tag) => tag !== null && typeof tag === "object" && !Array.isArray(tag) && isName(tag.name) && Number.isSafeInteger(tag.count) && tag.count >= 0)) {
|
|
49670
|
+
return payload.map((tag) => tag.name);
|
|
49260
49671
|
}
|
|
49261
|
-
|
|
49672
|
+
throw new Error("Remote tags payload did not match the expected contract (every element must be a non-empty tag name, or every element must be a counted tag record)");
|
|
49262
49673
|
}
|
|
49263
49674
|
async skillsByTag(tag) {
|
|
49264
49675
|
const path = `/api/v1/tags/${encodeURIComponent(tag)}/skills`;
|
|
@@ -49361,14 +49772,8 @@ function normalizeUpdatedSincePage(payload) {
|
|
|
49361
49772
|
return { skills, nextCursor };
|
|
49362
49773
|
}
|
|
49363
49774
|
async function createRemoteSkillsClient(env3 = process.env) {
|
|
49364
|
-
const
|
|
49365
|
-
|
|
49366
|
-
return null;
|
|
49367
|
-
const apiKey = await resolveSkillsApiKey(env3);
|
|
49368
|
-
if (!apiKey) {
|
|
49369
|
-
throw new Error("A Skills authority resolved but no API key did. Sign in with: skills auth login");
|
|
49370
|
-
}
|
|
49371
|
-
return new RemoteSkillsClient(apiKey, fleet.apiOrigin);
|
|
49775
|
+
const connection = await resolveSkillsConnection(env3);
|
|
49776
|
+
return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
|
|
49372
49777
|
}
|
|
49373
49778
|
function createRemoteSkillsClientReadOnly(env3 = process.env) {
|
|
49374
49779
|
return createRemoteSkillsClient(env3);
|
|
@@ -49377,6 +49782,8 @@ var RemoteRouteUnsupportedError, RemoteRequestError;
|
|
|
49377
49782
|
var init_remote_client = __esm(() => {
|
|
49378
49783
|
init_auth_store();
|
|
49379
49784
|
init_fleet_credentials();
|
|
49785
|
+
init_remote_account();
|
|
49786
|
+
init_remote_files();
|
|
49380
49787
|
RemoteRouteUnsupportedError = class RemoteRouteUnsupportedError extends Error {
|
|
49381
49788
|
path;
|
|
49382
49789
|
status;
|
|
@@ -49402,7 +49809,7 @@ var init_remote_client = __esm(() => {
|
|
|
49402
49809
|
});
|
|
49403
49810
|
|
|
49404
49811
|
// src/lib/revision.ts
|
|
49405
|
-
import { createHash as
|
|
49812
|
+
import { createHash as createHash3 } from "crypto";
|
|
49406
49813
|
function revisionIdOf(content) {
|
|
49407
49814
|
const canonical = JSON.stringify({
|
|
49408
49815
|
slug: content.slug,
|
|
@@ -49417,7 +49824,7 @@ function revisionIdOf(content) {
|
|
|
49417
49824
|
bundleSha256: content.bundleSha256 ?? null,
|
|
49418
49825
|
bundleByteSize: content.bundleByteSize ?? null
|
|
49419
49826
|
});
|
|
49420
|
-
return
|
|
49827
|
+
return createHash3("sha256").update(canonical).digest("hex");
|
|
49421
49828
|
}
|
|
49422
49829
|
var REVISION_ID_PATTERN;
|
|
49423
49830
|
var init_revision = __esm(() => {
|
|
@@ -49425,7 +49832,7 @@ var init_revision = __esm(() => {
|
|
|
49425
49832
|
});
|
|
49426
49833
|
|
|
49427
49834
|
// src/lib/skill-bundle.ts
|
|
49428
|
-
import { createHash as
|
|
49835
|
+
import { createHash as createHash4 } from "crypto";
|
|
49429
49836
|
import { readFileSync as readFileSync13, readdirSync as readdirSync9, statSync as statSync10 } from "fs";
|
|
49430
49837
|
import { join as join17, relative as relative2 } from "path";
|
|
49431
49838
|
function isDotenvFile(lower) {
|
|
@@ -49456,7 +49863,7 @@ function ownBytes(view) {
|
|
|
49456
49863
|
return out;
|
|
49457
49864
|
}
|
|
49458
49865
|
function sha256Hex(bytes) {
|
|
49459
|
-
return
|
|
49866
|
+
return createHash4("sha256").update(bytes).digest("hex");
|
|
49460
49867
|
}
|
|
49461
49868
|
function collectSkillBundleEntries(dir) {
|
|
49462
49869
|
const entries = [];
|
|
@@ -53188,7 +53595,7 @@ var init_runs = __esm(() => {
|
|
|
53188
53595
|
});
|
|
53189
53596
|
|
|
53190
53597
|
// src/lib/run-state.ts
|
|
53191
|
-
import { createHash as
|
|
53598
|
+
import { createHash as createHash5, randomBytes } from "crypto";
|
|
53192
53599
|
import { existsSync as existsSync23, mkdirSync as mkdirSync10, readFileSync as readFileSync21, readdirSync as readdirSync13, statSync as statSync14, writeFileSync as writeFileSync12 } from "fs";
|
|
53193
53600
|
import { extname, join as join25, relative as relative3 } from "path";
|
|
53194
53601
|
function createSkillRun(params, targetDir = process.cwd()) {
|
|
@@ -53212,6 +53619,7 @@ function createSkillRun(params, targetDir = process.cwd()) {
|
|
|
53212
53619
|
startedAt: now3.toISOString(),
|
|
53213
53620
|
remote: params.remote ?? false,
|
|
53214
53621
|
...params.remoteRunId ? { remoteRunId: params.remoteRunId } : {},
|
|
53622
|
+
...params.remoteApiOrigin ? { remoteApiOrigin: params.remoteApiOrigin } : {},
|
|
53215
53623
|
...params.costCents !== undefined ? { costCents: params.costCents } : {},
|
|
53216
53624
|
artifacts: [],
|
|
53217
53625
|
paths: {
|
|
@@ -53324,7 +53732,7 @@ function collectRunArtifacts(context) {
|
|
|
53324
53732
|
artifacts.push({
|
|
53325
53733
|
path: toProjectRelative(context.targetDir, path),
|
|
53326
53734
|
mime: mimeForPath(path),
|
|
53327
|
-
sha256:
|
|
53735
|
+
sha256: createHash5("sha256").update(bytes).digest("hex"),
|
|
53328
53736
|
sizeBytes: stat.size
|
|
53329
53737
|
});
|
|
53330
53738
|
}
|
|
@@ -53561,19 +53969,19 @@ function floatSafeRemainder2(val, step) {
|
|
|
53561
53969
|
const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", ""));
|
|
53562
53970
|
return valInt % stepInt / 10 ** decCount;
|
|
53563
53971
|
}
|
|
53564
|
-
function defineLazy(
|
|
53972
|
+
function defineLazy(object2, key, getter) {
|
|
53565
53973
|
const set2 = false;
|
|
53566
|
-
Object.defineProperty(
|
|
53974
|
+
Object.defineProperty(object2, key, {
|
|
53567
53975
|
get() {
|
|
53568
53976
|
if (!set2) {
|
|
53569
53977
|
const value = getter();
|
|
53570
|
-
|
|
53978
|
+
object2[key] = value;
|
|
53571
53979
|
return value;
|
|
53572
53980
|
}
|
|
53573
53981
|
throw new Error("cached value already set");
|
|
53574
53982
|
},
|
|
53575
53983
|
set(v) {
|
|
53576
|
-
Object.defineProperty(
|
|
53984
|
+
Object.defineProperty(object2, key, {
|
|
53577
53985
|
value: v
|
|
53578
53986
|
});
|
|
53579
53987
|
},
|
|
@@ -57357,7 +57765,7 @@ function never(params) {
|
|
|
57357
57765
|
function array(element, params) {
|
|
57358
57766
|
return _array(ZodArray2, element, params);
|
|
57359
57767
|
}
|
|
57360
|
-
function
|
|
57768
|
+
function object2(shape, params) {
|
|
57361
57769
|
const def = {
|
|
57362
57770
|
type: "object",
|
|
57363
57771
|
get shape() {
|
|
@@ -58000,30 +58408,30 @@ var init_types2 = __esm(() => {
|
|
|
58000
58408
|
ttl: number2().optional(),
|
|
58001
58409
|
pollInterval: number2().optional()
|
|
58002
58410
|
});
|
|
58003
|
-
TaskMetadataSchema =
|
|
58411
|
+
TaskMetadataSchema = object2({
|
|
58004
58412
|
ttl: number2().optional()
|
|
58005
58413
|
});
|
|
58006
|
-
RelatedTaskMetadataSchema =
|
|
58414
|
+
RelatedTaskMetadataSchema = object2({
|
|
58007
58415
|
taskId: string2()
|
|
58008
58416
|
});
|
|
58009
58417
|
RequestMetaSchema = looseObject({
|
|
58010
58418
|
progressToken: ProgressTokenSchema.optional(),
|
|
58011
58419
|
[RELATED_TASK_META_KEY]: RelatedTaskMetadataSchema.optional()
|
|
58012
58420
|
});
|
|
58013
|
-
BaseRequestParamsSchema =
|
|
58421
|
+
BaseRequestParamsSchema = object2({
|
|
58014
58422
|
_meta: RequestMetaSchema.optional()
|
|
58015
58423
|
});
|
|
58016
58424
|
TaskAugmentedRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
58017
58425
|
task: TaskMetadataSchema.optional()
|
|
58018
58426
|
});
|
|
58019
|
-
RequestSchema =
|
|
58427
|
+
RequestSchema = object2({
|
|
58020
58428
|
method: string2(),
|
|
58021
58429
|
params: BaseRequestParamsSchema.loose().optional()
|
|
58022
58430
|
});
|
|
58023
|
-
NotificationsParamsSchema =
|
|
58431
|
+
NotificationsParamsSchema = object2({
|
|
58024
58432
|
_meta: RequestMetaSchema.optional()
|
|
58025
58433
|
});
|
|
58026
|
-
NotificationSchema =
|
|
58434
|
+
NotificationSchema = object2({
|
|
58027
58435
|
method: string2(),
|
|
58028
58436
|
params: NotificationsParamsSchema.loose().optional()
|
|
58029
58437
|
});
|
|
@@ -58031,16 +58439,16 @@ var init_types2 = __esm(() => {
|
|
|
58031
58439
|
_meta: RequestMetaSchema.optional()
|
|
58032
58440
|
});
|
|
58033
58441
|
RequestIdSchema = union2([string2(), number2().int()]);
|
|
58034
|
-
JSONRPCRequestSchema =
|
|
58442
|
+
JSONRPCRequestSchema = object2({
|
|
58035
58443
|
jsonrpc: literal(JSONRPC_VERSION),
|
|
58036
58444
|
id: RequestIdSchema,
|
|
58037
58445
|
...RequestSchema.shape
|
|
58038
58446
|
}).strict();
|
|
58039
|
-
JSONRPCNotificationSchema =
|
|
58447
|
+
JSONRPCNotificationSchema = object2({
|
|
58040
58448
|
jsonrpc: literal(JSONRPC_VERSION),
|
|
58041
58449
|
...NotificationSchema.shape
|
|
58042
58450
|
}).strict();
|
|
58043
|
-
JSONRPCResultResponseSchema =
|
|
58451
|
+
JSONRPCResultResponseSchema = object2({
|
|
58044
58452
|
jsonrpc: literal(JSONRPC_VERSION),
|
|
58045
58453
|
id: RequestIdSchema,
|
|
58046
58454
|
result: ResultSchema
|
|
@@ -58055,10 +58463,10 @@ var init_types2 = __esm(() => {
|
|
|
58055
58463
|
ErrorCode2[ErrorCode2["InternalError"] = -32603] = "InternalError";
|
|
58056
58464
|
ErrorCode2[ErrorCode2["UrlElicitationRequired"] = -32042] = "UrlElicitationRequired";
|
|
58057
58465
|
})(ErrorCode || (ErrorCode = {}));
|
|
58058
|
-
JSONRPCErrorResponseSchema =
|
|
58466
|
+
JSONRPCErrorResponseSchema = object2({
|
|
58059
58467
|
jsonrpc: literal(JSONRPC_VERSION),
|
|
58060
58468
|
id: RequestIdSchema.optional(),
|
|
58061
|
-
error:
|
|
58469
|
+
error: object2({
|
|
58062
58470
|
code: number2().int(),
|
|
58063
58471
|
message: string2(),
|
|
58064
58472
|
data: unknown().optional()
|
|
@@ -58080,16 +58488,16 @@ var init_types2 = __esm(() => {
|
|
|
58080
58488
|
method: literal("notifications/cancelled"),
|
|
58081
58489
|
params: CancelledNotificationParamsSchema
|
|
58082
58490
|
});
|
|
58083
|
-
IconSchema =
|
|
58491
|
+
IconSchema = object2({
|
|
58084
58492
|
src: string2(),
|
|
58085
58493
|
mimeType: string2().optional(),
|
|
58086
58494
|
sizes: array(string2()).optional(),
|
|
58087
58495
|
theme: _enum(["light", "dark"]).optional()
|
|
58088
58496
|
});
|
|
58089
|
-
IconsSchema =
|
|
58497
|
+
IconsSchema = object2({
|
|
58090
58498
|
icons: array(IconSchema).optional()
|
|
58091
58499
|
});
|
|
58092
|
-
BaseMetadataSchema =
|
|
58500
|
+
BaseMetadataSchema = object2({
|
|
58093
58501
|
name: string2(),
|
|
58094
58502
|
title: string2().optional()
|
|
58095
58503
|
});
|
|
@@ -58100,7 +58508,7 @@ var init_types2 = __esm(() => {
|
|
|
58100
58508
|
websiteUrl: string2().optional(),
|
|
58101
58509
|
description: string2().optional()
|
|
58102
58510
|
});
|
|
58103
|
-
FormElicitationCapabilitySchema = intersection2(
|
|
58511
|
+
FormElicitationCapabilitySchema = intersection2(object2({
|
|
58104
58512
|
applyDefaults: boolean2().optional()
|
|
58105
58513
|
}), record(string2(), unknown()));
|
|
58106
58514
|
ElicitationCapabilitySchema = preprocess((value) => {
|
|
@@ -58110,7 +58518,7 @@ var init_types2 = __esm(() => {
|
|
|
58110
58518
|
}
|
|
58111
58519
|
}
|
|
58112
58520
|
return value;
|
|
58113
|
-
}, intersection2(
|
|
58521
|
+
}, intersection2(object2({
|
|
58114
58522
|
form: FormElicitationCapabilitySchema.optional(),
|
|
58115
58523
|
url: AssertObjectSchema.optional()
|
|
58116
58524
|
}), record(string2(), unknown()).optional()));
|
|
@@ -58135,14 +58543,14 @@ var init_types2 = __esm(() => {
|
|
|
58135
58543
|
}).optional()
|
|
58136
58544
|
}).optional()
|
|
58137
58545
|
});
|
|
58138
|
-
ClientCapabilitiesSchema =
|
|
58546
|
+
ClientCapabilitiesSchema = object2({
|
|
58139
58547
|
experimental: record(string2(), AssertObjectSchema).optional(),
|
|
58140
|
-
sampling:
|
|
58548
|
+
sampling: object2({
|
|
58141
58549
|
context: AssertObjectSchema.optional(),
|
|
58142
58550
|
tools: AssertObjectSchema.optional()
|
|
58143
58551
|
}).optional(),
|
|
58144
58552
|
elicitation: ElicitationCapabilitySchema.optional(),
|
|
58145
|
-
roots:
|
|
58553
|
+
roots: object2({
|
|
58146
58554
|
listChanged: boolean2().optional()
|
|
58147
58555
|
}).optional(),
|
|
58148
58556
|
tasks: ClientTasksCapabilitySchema.optional(),
|
|
@@ -58157,18 +58565,18 @@ var init_types2 = __esm(() => {
|
|
|
58157
58565
|
method: literal("initialize"),
|
|
58158
58566
|
params: InitializeRequestParamsSchema
|
|
58159
58567
|
});
|
|
58160
|
-
ServerCapabilitiesSchema =
|
|
58568
|
+
ServerCapabilitiesSchema = object2({
|
|
58161
58569
|
experimental: record(string2(), AssertObjectSchema).optional(),
|
|
58162
58570
|
logging: AssertObjectSchema.optional(),
|
|
58163
58571
|
completions: AssertObjectSchema.optional(),
|
|
58164
|
-
prompts:
|
|
58572
|
+
prompts: object2({
|
|
58165
58573
|
listChanged: boolean2().optional()
|
|
58166
58574
|
}).optional(),
|
|
58167
|
-
resources:
|
|
58575
|
+
resources: object2({
|
|
58168
58576
|
subscribe: boolean2().optional(),
|
|
58169
58577
|
listChanged: boolean2().optional()
|
|
58170
58578
|
}).optional(),
|
|
58171
|
-
tools:
|
|
58579
|
+
tools: object2({
|
|
58172
58580
|
listChanged: boolean2().optional()
|
|
58173
58581
|
}).optional(),
|
|
58174
58582
|
tasks: ServerTasksCapabilitySchema.optional(),
|
|
@@ -58188,12 +58596,12 @@ var init_types2 = __esm(() => {
|
|
|
58188
58596
|
method: literal("ping"),
|
|
58189
58597
|
params: BaseRequestParamsSchema.optional()
|
|
58190
58598
|
});
|
|
58191
|
-
ProgressSchema =
|
|
58599
|
+
ProgressSchema = object2({
|
|
58192
58600
|
progress: number2(),
|
|
58193
58601
|
total: optional(number2()),
|
|
58194
58602
|
message: optional(string2())
|
|
58195
58603
|
});
|
|
58196
|
-
ProgressNotificationParamsSchema =
|
|
58604
|
+
ProgressNotificationParamsSchema = object2({
|
|
58197
58605
|
...NotificationsParamsSchema.shape,
|
|
58198
58606
|
...ProgressSchema.shape,
|
|
58199
58607
|
progressToken: ProgressTokenSchema
|
|
@@ -58212,7 +58620,7 @@ var init_types2 = __esm(() => {
|
|
|
58212
58620
|
nextCursor: CursorSchema.optional()
|
|
58213
58621
|
});
|
|
58214
58622
|
TaskStatusSchema = _enum(["working", "input_required", "completed", "failed", "cancelled"]);
|
|
58215
|
-
TaskSchema =
|
|
58623
|
+
TaskSchema = object2({
|
|
58216
58624
|
taskId: string2(),
|
|
58217
58625
|
status: TaskStatusSchema,
|
|
58218
58626
|
ttl: union2([number2(), _null3()]),
|
|
@@ -58256,7 +58664,7 @@ var init_types2 = __esm(() => {
|
|
|
58256
58664
|
})
|
|
58257
58665
|
});
|
|
58258
58666
|
CancelTaskResultSchema = ResultSchema.merge(TaskSchema);
|
|
58259
|
-
ResourceContentsSchema =
|
|
58667
|
+
ResourceContentsSchema = object2({
|
|
58260
58668
|
uri: string2(),
|
|
58261
58669
|
mimeType: optional(string2()),
|
|
58262
58670
|
_meta: record(string2(), unknown()).optional()
|
|
@@ -58276,12 +58684,12 @@ var init_types2 = __esm(() => {
|
|
|
58276
58684
|
blob: Base64Schema
|
|
58277
58685
|
});
|
|
58278
58686
|
RoleSchema = _enum(["user", "assistant"]);
|
|
58279
|
-
AnnotationsSchema =
|
|
58687
|
+
AnnotationsSchema = object2({
|
|
58280
58688
|
audience: array(RoleSchema).optional(),
|
|
58281
58689
|
priority: number2().min(0).max(1).optional(),
|
|
58282
58690
|
lastModified: exports_iso.datetime({ offset: true }).optional()
|
|
58283
58691
|
});
|
|
58284
|
-
ResourceSchema =
|
|
58692
|
+
ResourceSchema = object2({
|
|
58285
58693
|
...BaseMetadataSchema.shape,
|
|
58286
58694
|
...IconsSchema.shape,
|
|
58287
58695
|
uri: string2(),
|
|
@@ -58291,7 +58699,7 @@ var init_types2 = __esm(() => {
|
|
|
58291
58699
|
annotations: AnnotationsSchema.optional(),
|
|
58292
58700
|
_meta: optional(looseObject({}))
|
|
58293
58701
|
});
|
|
58294
|
-
ResourceTemplateSchema =
|
|
58702
|
+
ResourceTemplateSchema = object2({
|
|
58295
58703
|
...BaseMetadataSchema.shape,
|
|
58296
58704
|
...IconsSchema.shape,
|
|
58297
58705
|
uriTemplate: string2(),
|
|
@@ -58344,12 +58752,12 @@ var init_types2 = __esm(() => {
|
|
|
58344
58752
|
method: literal("notifications/resources/updated"),
|
|
58345
58753
|
params: ResourceUpdatedNotificationParamsSchema
|
|
58346
58754
|
});
|
|
58347
|
-
PromptArgumentSchema =
|
|
58755
|
+
PromptArgumentSchema = object2({
|
|
58348
58756
|
name: string2(),
|
|
58349
58757
|
description: optional(string2()),
|
|
58350
58758
|
required: optional(boolean2())
|
|
58351
58759
|
});
|
|
58352
|
-
PromptSchema =
|
|
58760
|
+
PromptSchema = object2({
|
|
58353
58761
|
...BaseMetadataSchema.shape,
|
|
58354
58762
|
...IconsSchema.shape,
|
|
58355
58763
|
description: optional(string2()),
|
|
@@ -58370,34 +58778,34 @@ var init_types2 = __esm(() => {
|
|
|
58370
58778
|
method: literal("prompts/get"),
|
|
58371
58779
|
params: GetPromptRequestParamsSchema
|
|
58372
58780
|
});
|
|
58373
|
-
TextContentSchema =
|
|
58781
|
+
TextContentSchema = object2({
|
|
58374
58782
|
type: literal("text"),
|
|
58375
58783
|
text: string2(),
|
|
58376
58784
|
annotations: AnnotationsSchema.optional(),
|
|
58377
58785
|
_meta: record(string2(), unknown()).optional()
|
|
58378
58786
|
});
|
|
58379
|
-
ImageContentSchema =
|
|
58787
|
+
ImageContentSchema = object2({
|
|
58380
58788
|
type: literal("image"),
|
|
58381
58789
|
data: Base64Schema,
|
|
58382
58790
|
mimeType: string2(),
|
|
58383
58791
|
annotations: AnnotationsSchema.optional(),
|
|
58384
58792
|
_meta: record(string2(), unknown()).optional()
|
|
58385
58793
|
});
|
|
58386
|
-
AudioContentSchema =
|
|
58794
|
+
AudioContentSchema = object2({
|
|
58387
58795
|
type: literal("audio"),
|
|
58388
58796
|
data: Base64Schema,
|
|
58389
58797
|
mimeType: string2(),
|
|
58390
58798
|
annotations: AnnotationsSchema.optional(),
|
|
58391
58799
|
_meta: record(string2(), unknown()).optional()
|
|
58392
58800
|
});
|
|
58393
|
-
ToolUseContentSchema =
|
|
58801
|
+
ToolUseContentSchema = object2({
|
|
58394
58802
|
type: literal("tool_use"),
|
|
58395
58803
|
name: string2(),
|
|
58396
58804
|
id: string2(),
|
|
58397
58805
|
input: record(string2(), unknown()),
|
|
58398
58806
|
_meta: record(string2(), unknown()).optional()
|
|
58399
58807
|
});
|
|
58400
|
-
EmbeddedResourceSchema =
|
|
58808
|
+
EmbeddedResourceSchema = object2({
|
|
58401
58809
|
type: literal("resource"),
|
|
58402
58810
|
resource: union2([TextResourceContentsSchema, BlobResourceContentsSchema]),
|
|
58403
58811
|
annotations: AnnotationsSchema.optional(),
|
|
@@ -58413,7 +58821,7 @@ var init_types2 = __esm(() => {
|
|
|
58413
58821
|
ResourceLinkSchema,
|
|
58414
58822
|
EmbeddedResourceSchema
|
|
58415
58823
|
]);
|
|
58416
|
-
PromptMessageSchema =
|
|
58824
|
+
PromptMessageSchema = object2({
|
|
58417
58825
|
role: RoleSchema,
|
|
58418
58826
|
content: ContentBlockSchema
|
|
58419
58827
|
});
|
|
@@ -58425,26 +58833,26 @@ var init_types2 = __esm(() => {
|
|
|
58425
58833
|
method: literal("notifications/prompts/list_changed"),
|
|
58426
58834
|
params: NotificationsParamsSchema.optional()
|
|
58427
58835
|
});
|
|
58428
|
-
ToolAnnotationsSchema =
|
|
58836
|
+
ToolAnnotationsSchema = object2({
|
|
58429
58837
|
title: string2().optional(),
|
|
58430
58838
|
readOnlyHint: boolean2().optional(),
|
|
58431
58839
|
destructiveHint: boolean2().optional(),
|
|
58432
58840
|
idempotentHint: boolean2().optional(),
|
|
58433
58841
|
openWorldHint: boolean2().optional()
|
|
58434
58842
|
});
|
|
58435
|
-
ToolExecutionSchema =
|
|
58843
|
+
ToolExecutionSchema = object2({
|
|
58436
58844
|
taskSupport: _enum(["required", "optional", "forbidden"]).optional()
|
|
58437
58845
|
});
|
|
58438
|
-
ToolSchema =
|
|
58846
|
+
ToolSchema = object2({
|
|
58439
58847
|
...BaseMetadataSchema.shape,
|
|
58440
58848
|
...IconsSchema.shape,
|
|
58441
58849
|
description: string2().optional(),
|
|
58442
|
-
inputSchema:
|
|
58850
|
+
inputSchema: object2({
|
|
58443
58851
|
type: literal("object"),
|
|
58444
58852
|
properties: record(string2(), AssertObjectSchema).optional(),
|
|
58445
58853
|
required: array(string2()).optional()
|
|
58446
58854
|
}).catchall(unknown()),
|
|
58447
|
-
outputSchema:
|
|
58855
|
+
outputSchema: object2({
|
|
58448
58856
|
type: literal("object"),
|
|
58449
58857
|
properties: record(string2(), AssertObjectSchema).optional(),
|
|
58450
58858
|
required: array(string2()).optional()
|
|
@@ -58479,7 +58887,7 @@ var init_types2 = __esm(() => {
|
|
|
58479
58887
|
method: literal("notifications/tools/list_changed"),
|
|
58480
58888
|
params: NotificationsParamsSchema.optional()
|
|
58481
58889
|
});
|
|
58482
|
-
ListChangedOptionsBaseSchema =
|
|
58890
|
+
ListChangedOptionsBaseSchema = object2({
|
|
58483
58891
|
autoRefresh: boolean2().default(true),
|
|
58484
58892
|
debounceMs: number2().int().nonnegative().default(300)
|
|
58485
58893
|
});
|
|
@@ -58500,23 +58908,23 @@ var init_types2 = __esm(() => {
|
|
|
58500
58908
|
method: literal("notifications/message"),
|
|
58501
58909
|
params: LoggingMessageNotificationParamsSchema
|
|
58502
58910
|
});
|
|
58503
|
-
ModelHintSchema =
|
|
58911
|
+
ModelHintSchema = object2({
|
|
58504
58912
|
name: string2().optional()
|
|
58505
58913
|
});
|
|
58506
|
-
ModelPreferencesSchema =
|
|
58914
|
+
ModelPreferencesSchema = object2({
|
|
58507
58915
|
hints: array(ModelHintSchema).optional(),
|
|
58508
58916
|
costPriority: number2().min(0).max(1).optional(),
|
|
58509
58917
|
speedPriority: number2().min(0).max(1).optional(),
|
|
58510
58918
|
intelligencePriority: number2().min(0).max(1).optional()
|
|
58511
58919
|
});
|
|
58512
|
-
ToolChoiceSchema =
|
|
58920
|
+
ToolChoiceSchema = object2({
|
|
58513
58921
|
mode: _enum(["auto", "required", "none"]).optional()
|
|
58514
58922
|
});
|
|
58515
|
-
ToolResultContentSchema =
|
|
58923
|
+
ToolResultContentSchema = object2({
|
|
58516
58924
|
type: literal("tool_result"),
|
|
58517
58925
|
toolUseId: string2().describe("The unique identifier for the corresponding tool call."),
|
|
58518
58926
|
content: array(ContentBlockSchema).default([]),
|
|
58519
|
-
structuredContent:
|
|
58927
|
+
structuredContent: object2({}).loose().optional(),
|
|
58520
58928
|
isError: boolean2().optional(),
|
|
58521
58929
|
_meta: record(string2(), unknown()).optional()
|
|
58522
58930
|
});
|
|
@@ -58528,7 +58936,7 @@ var init_types2 = __esm(() => {
|
|
|
58528
58936
|
ToolUseContentSchema,
|
|
58529
58937
|
ToolResultContentSchema
|
|
58530
58938
|
]);
|
|
58531
|
-
SamplingMessageSchema =
|
|
58939
|
+
SamplingMessageSchema = object2({
|
|
58532
58940
|
role: RoleSchema,
|
|
58533
58941
|
content: union2([SamplingMessageContentBlockSchema, array(SamplingMessageContentBlockSchema)]),
|
|
58534
58942
|
_meta: record(string2(), unknown()).optional()
|
|
@@ -58561,13 +58969,13 @@ var init_types2 = __esm(() => {
|
|
|
58561
58969
|
role: RoleSchema,
|
|
58562
58970
|
content: union2([SamplingMessageContentBlockSchema, array(SamplingMessageContentBlockSchema)])
|
|
58563
58971
|
});
|
|
58564
|
-
BooleanSchemaSchema =
|
|
58972
|
+
BooleanSchemaSchema = object2({
|
|
58565
58973
|
type: literal("boolean"),
|
|
58566
58974
|
title: string2().optional(),
|
|
58567
58975
|
description: string2().optional(),
|
|
58568
58976
|
default: boolean2().optional()
|
|
58569
58977
|
});
|
|
58570
|
-
StringSchemaSchema =
|
|
58978
|
+
StringSchemaSchema = object2({
|
|
58571
58979
|
type: literal("string"),
|
|
58572
58980
|
title: string2().optional(),
|
|
58573
58981
|
description: string2().optional(),
|
|
@@ -58576,7 +58984,7 @@ var init_types2 = __esm(() => {
|
|
|
58576
58984
|
format: _enum(["email", "uri", "date", "date-time"]).optional(),
|
|
58577
58985
|
default: string2().optional()
|
|
58578
58986
|
});
|
|
58579
|
-
NumberSchemaSchema =
|
|
58987
|
+
NumberSchemaSchema = object2({
|
|
58580
58988
|
type: _enum(["number", "integer"]),
|
|
58581
58989
|
title: string2().optional(),
|
|
58582
58990
|
description: string2().optional(),
|
|
@@ -58584,24 +58992,24 @@ var init_types2 = __esm(() => {
|
|
|
58584
58992
|
maximum: number2().optional(),
|
|
58585
58993
|
default: number2().optional()
|
|
58586
58994
|
});
|
|
58587
|
-
UntitledSingleSelectEnumSchemaSchema =
|
|
58995
|
+
UntitledSingleSelectEnumSchemaSchema = object2({
|
|
58588
58996
|
type: literal("string"),
|
|
58589
58997
|
title: string2().optional(),
|
|
58590
58998
|
description: string2().optional(),
|
|
58591
58999
|
enum: array(string2()),
|
|
58592
59000
|
default: string2().optional()
|
|
58593
59001
|
});
|
|
58594
|
-
TitledSingleSelectEnumSchemaSchema =
|
|
59002
|
+
TitledSingleSelectEnumSchemaSchema = object2({
|
|
58595
59003
|
type: literal("string"),
|
|
58596
59004
|
title: string2().optional(),
|
|
58597
59005
|
description: string2().optional(),
|
|
58598
|
-
oneOf: array(
|
|
59006
|
+
oneOf: array(object2({
|
|
58599
59007
|
const: string2(),
|
|
58600
59008
|
title: string2()
|
|
58601
59009
|
})),
|
|
58602
59010
|
default: string2().optional()
|
|
58603
59011
|
});
|
|
58604
|
-
LegacyTitledEnumSchemaSchema =
|
|
59012
|
+
LegacyTitledEnumSchemaSchema = object2({
|
|
58605
59013
|
type: literal("string"),
|
|
58606
59014
|
title: string2().optional(),
|
|
58607
59015
|
description: string2().optional(),
|
|
@@ -58610,26 +59018,26 @@ var init_types2 = __esm(() => {
|
|
|
58610
59018
|
default: string2().optional()
|
|
58611
59019
|
});
|
|
58612
59020
|
SingleSelectEnumSchemaSchema = union2([UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema]);
|
|
58613
|
-
UntitledMultiSelectEnumSchemaSchema =
|
|
59021
|
+
UntitledMultiSelectEnumSchemaSchema = object2({
|
|
58614
59022
|
type: literal("array"),
|
|
58615
59023
|
title: string2().optional(),
|
|
58616
59024
|
description: string2().optional(),
|
|
58617
59025
|
minItems: number2().optional(),
|
|
58618
59026
|
maxItems: number2().optional(),
|
|
58619
|
-
items:
|
|
59027
|
+
items: object2({
|
|
58620
59028
|
type: literal("string"),
|
|
58621
59029
|
enum: array(string2())
|
|
58622
59030
|
}),
|
|
58623
59031
|
default: array(string2()).optional()
|
|
58624
59032
|
});
|
|
58625
|
-
TitledMultiSelectEnumSchemaSchema =
|
|
59033
|
+
TitledMultiSelectEnumSchemaSchema = object2({
|
|
58626
59034
|
type: literal("array"),
|
|
58627
59035
|
title: string2().optional(),
|
|
58628
59036
|
description: string2().optional(),
|
|
58629
59037
|
minItems: number2().optional(),
|
|
58630
59038
|
maxItems: number2().optional(),
|
|
58631
|
-
items:
|
|
58632
|
-
anyOf: array(
|
|
59039
|
+
items: object2({
|
|
59040
|
+
anyOf: array(object2({
|
|
58633
59041
|
const: string2(),
|
|
58634
59042
|
title: string2()
|
|
58635
59043
|
}))
|
|
@@ -58642,7 +59050,7 @@ var init_types2 = __esm(() => {
|
|
|
58642
59050
|
ElicitRequestFormParamsSchema = TaskAugmentedRequestParamsSchema.extend({
|
|
58643
59051
|
mode: literal("form").optional(),
|
|
58644
59052
|
message: string2(),
|
|
58645
|
-
requestedSchema:
|
|
59053
|
+
requestedSchema: object2({
|
|
58646
59054
|
type: literal("object"),
|
|
58647
59055
|
properties: record(string2(), PrimitiveSchemaDefinitionSchema),
|
|
58648
59056
|
required: array(string2()).optional()
|
|
@@ -58670,21 +59078,21 @@ var init_types2 = __esm(() => {
|
|
|
58670
59078
|
action: _enum(["accept", "decline", "cancel"]),
|
|
58671
59079
|
content: preprocess((val) => val === null ? undefined : val, record(string2(), union2([string2(), number2(), boolean2(), array(string2())])).optional())
|
|
58672
59080
|
});
|
|
58673
|
-
ResourceTemplateReferenceSchema =
|
|
59081
|
+
ResourceTemplateReferenceSchema = object2({
|
|
58674
59082
|
type: literal("ref/resource"),
|
|
58675
59083
|
uri: string2()
|
|
58676
59084
|
});
|
|
58677
|
-
PromptReferenceSchema =
|
|
59085
|
+
PromptReferenceSchema = object2({
|
|
58678
59086
|
type: literal("ref/prompt"),
|
|
58679
59087
|
name: string2()
|
|
58680
59088
|
});
|
|
58681
59089
|
CompleteRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
58682
59090
|
ref: union2([PromptReferenceSchema, ResourceTemplateReferenceSchema]),
|
|
58683
|
-
argument:
|
|
59091
|
+
argument: object2({
|
|
58684
59092
|
name: string2(),
|
|
58685
59093
|
value: string2()
|
|
58686
59094
|
}),
|
|
58687
|
-
context:
|
|
59095
|
+
context: object2({
|
|
58688
59096
|
arguments: record(string2(), string2()).optional()
|
|
58689
59097
|
}).optional()
|
|
58690
59098
|
});
|
|
@@ -58699,7 +59107,7 @@ var init_types2 = __esm(() => {
|
|
|
58699
59107
|
hasMore: optional(boolean2())
|
|
58700
59108
|
})
|
|
58701
59109
|
});
|
|
58702
|
-
RootSchema =
|
|
59110
|
+
RootSchema = object2({
|
|
58703
59111
|
uri: string2().startsWith("file://"),
|
|
58704
59112
|
name: string2().optional(),
|
|
58705
59113
|
_meta: record(string2(), unknown()).optional()
|
|
@@ -58938,7 +59346,7 @@ var init_parse3 = __esm(() => {
|
|
|
58938
59346
|
});
|
|
58939
59347
|
|
|
58940
59348
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v4/mini/schemas.js
|
|
58941
|
-
function
|
|
59349
|
+
function object3(shape, params) {
|
|
58942
59350
|
const def = {
|
|
58943
59351
|
type: "object",
|
|
58944
59352
|
get shape() {
|
|
@@ -59025,11 +59433,11 @@ function isZ4Schema(s) {
|
|
|
59025
59433
|
function objectFromShape(shape) {
|
|
59026
59434
|
const values2 = Object.values(shape);
|
|
59027
59435
|
if (values2.length === 0)
|
|
59028
|
-
return
|
|
59436
|
+
return object3({});
|
|
59029
59437
|
const allV4 = values2.every(isZ4Schema);
|
|
59030
59438
|
const allV3 = values2.every((s) => !isZ4Schema(s));
|
|
59031
59439
|
if (allV4)
|
|
59032
|
-
return
|
|
59440
|
+
return object3(shape);
|
|
59033
59441
|
if (allV3)
|
|
59034
59442
|
return objectType(shape);
|
|
59035
59443
|
throw new Error("Mixed Zod versions detected in object shape.");
|
|
@@ -59916,11 +60324,11 @@ var init_map = __esm(() => {
|
|
|
59916
60324
|
|
|
59917
60325
|
// ../../node_modules/.bun/zod-to-json-schema@3.25.2+27912429049419a2/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js
|
|
59918
60326
|
function parseNativeEnumDef(def) {
|
|
59919
|
-
const
|
|
60327
|
+
const object4 = def.values;
|
|
59920
60328
|
const actualKeys = Object.keys(def.values).filter((key) => {
|
|
59921
|
-
return typeof
|
|
60329
|
+
return typeof object4[object4[key]] !== "number";
|
|
59922
60330
|
});
|
|
59923
|
-
const actualValues = actualKeys.map((key) =>
|
|
60331
|
+
const actualValues = actualKeys.map((key) => object4[key]);
|
|
59924
60332
|
const parsedTypes = Array.from(new Set(actualValues.map((values2) => typeof values2)));
|
|
59925
60333
|
return {
|
|
59926
60334
|
type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"],
|
|
@@ -61856,11 +62264,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
61856
62264
|
const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
|
|
61857
62265
|
return `${varKind} ${this.name}${rhs};` + _n;
|
|
61858
62266
|
}
|
|
61859
|
-
optimizeNames(names,
|
|
62267
|
+
optimizeNames(names, constants3) {
|
|
61860
62268
|
if (!names[this.name.str])
|
|
61861
62269
|
return;
|
|
61862
62270
|
if (this.rhs)
|
|
61863
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
62271
|
+
this.rhs = optimizeExpr(this.rhs, names, constants3);
|
|
61864
62272
|
return this;
|
|
61865
62273
|
}
|
|
61866
62274
|
get names() {
|
|
@@ -61878,10 +62286,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
61878
62286
|
render({ _n }) {
|
|
61879
62287
|
return `${this.lhs} = ${this.rhs};` + _n;
|
|
61880
62288
|
}
|
|
61881
|
-
optimizeNames(names,
|
|
62289
|
+
optimizeNames(names, constants3) {
|
|
61882
62290
|
if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
|
|
61883
62291
|
return;
|
|
61884
|
-
this.rhs = optimizeExpr(this.rhs, names,
|
|
62292
|
+
this.rhs = optimizeExpr(this.rhs, names, constants3);
|
|
61885
62293
|
return this;
|
|
61886
62294
|
}
|
|
61887
62295
|
get names() {
|
|
@@ -61947,8 +62355,8 @@ var require_codegen = __commonJS((exports) => {
|
|
|
61947
62355
|
optimizeNodes() {
|
|
61948
62356
|
return `${this.code}` ? this : undefined;
|
|
61949
62357
|
}
|
|
61950
|
-
optimizeNames(names,
|
|
61951
|
-
this.code = optimizeExpr(this.code, names,
|
|
62358
|
+
optimizeNames(names, constants3) {
|
|
62359
|
+
this.code = optimizeExpr(this.code, names, constants3);
|
|
61952
62360
|
return this;
|
|
61953
62361
|
}
|
|
61954
62362
|
get names() {
|
|
@@ -61978,12 +62386,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
61978
62386
|
}
|
|
61979
62387
|
return nodes.length > 0 ? this : undefined;
|
|
61980
62388
|
}
|
|
61981
|
-
optimizeNames(names,
|
|
62389
|
+
optimizeNames(names, constants3) {
|
|
61982
62390
|
const { nodes } = this;
|
|
61983
62391
|
let i = nodes.length;
|
|
61984
62392
|
while (i--) {
|
|
61985
62393
|
const n = nodes[i];
|
|
61986
|
-
if (n.optimizeNames(names,
|
|
62394
|
+
if (n.optimizeNames(names, constants3))
|
|
61987
62395
|
continue;
|
|
61988
62396
|
subtractNames(names, n.names);
|
|
61989
62397
|
nodes.splice(i, 1);
|
|
@@ -62040,12 +62448,12 @@ var require_codegen = __commonJS((exports) => {
|
|
|
62040
62448
|
return;
|
|
62041
62449
|
return this;
|
|
62042
62450
|
}
|
|
62043
|
-
optimizeNames(names,
|
|
62451
|
+
optimizeNames(names, constants3) {
|
|
62044
62452
|
var _a;
|
|
62045
|
-
this.else = (_a = this.else) === null || _a === undefined ? undefined : _a.optimizeNames(names,
|
|
62046
|
-
if (!(super.optimizeNames(names,
|
|
62453
|
+
this.else = (_a = this.else) === null || _a === undefined ? undefined : _a.optimizeNames(names, constants3);
|
|
62454
|
+
if (!(super.optimizeNames(names, constants3) || this.else))
|
|
62047
62455
|
return;
|
|
62048
|
-
this.condition = optimizeExpr(this.condition, names,
|
|
62456
|
+
this.condition = optimizeExpr(this.condition, names, constants3);
|
|
62049
62457
|
return this;
|
|
62050
62458
|
}
|
|
62051
62459
|
get names() {
|
|
@@ -62070,10 +62478,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
62070
62478
|
render(opts) {
|
|
62071
62479
|
return `for(${this.iteration})` + super.render(opts);
|
|
62072
62480
|
}
|
|
62073
|
-
optimizeNames(names,
|
|
62074
|
-
if (!super.optimizeNames(names,
|
|
62481
|
+
optimizeNames(names, constants3) {
|
|
62482
|
+
if (!super.optimizeNames(names, constants3))
|
|
62075
62483
|
return;
|
|
62076
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
62484
|
+
this.iteration = optimizeExpr(this.iteration, names, constants3);
|
|
62077
62485
|
return this;
|
|
62078
62486
|
}
|
|
62079
62487
|
get names() {
|
|
@@ -62111,10 +62519,10 @@ var require_codegen = __commonJS((exports) => {
|
|
|
62111
62519
|
render(opts) {
|
|
62112
62520
|
return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
|
|
62113
62521
|
}
|
|
62114
|
-
optimizeNames(names,
|
|
62115
|
-
if (!super.optimizeNames(names,
|
|
62522
|
+
optimizeNames(names, constants3) {
|
|
62523
|
+
if (!super.optimizeNames(names, constants3))
|
|
62116
62524
|
return;
|
|
62117
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
62525
|
+
this.iterable = optimizeExpr(this.iterable, names, constants3);
|
|
62118
62526
|
return this;
|
|
62119
62527
|
}
|
|
62120
62528
|
get names() {
|
|
@@ -62159,11 +62567,11 @@ var require_codegen = __commonJS((exports) => {
|
|
|
62159
62567
|
(_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
|
|
62160
62568
|
return this;
|
|
62161
62569
|
}
|
|
62162
|
-
optimizeNames(names,
|
|
62570
|
+
optimizeNames(names, constants3) {
|
|
62163
62571
|
var _a, _b;
|
|
62164
|
-
super.optimizeNames(names,
|
|
62165
|
-
(_a = this.catch) === null || _a === undefined || _a.optimizeNames(names,
|
|
62166
|
-
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names,
|
|
62572
|
+
super.optimizeNames(names, constants3);
|
|
62573
|
+
(_a = this.catch) === null || _a === undefined || _a.optimizeNames(names, constants3);
|
|
62574
|
+
(_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants3);
|
|
62167
62575
|
return this;
|
|
62168
62576
|
}
|
|
62169
62577
|
get names() {
|
|
@@ -62437,7 +62845,7 @@ var require_codegen = __commonJS((exports) => {
|
|
|
62437
62845
|
function addExprNames(names, from) {
|
|
62438
62846
|
return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
|
|
62439
62847
|
}
|
|
62440
|
-
function optimizeExpr(expr, names,
|
|
62848
|
+
function optimizeExpr(expr, names, constants3) {
|
|
62441
62849
|
if (expr instanceof code_1.Name)
|
|
62442
62850
|
return replaceName(expr);
|
|
62443
62851
|
if (!canOptimize(expr))
|
|
@@ -62452,14 +62860,14 @@ var require_codegen = __commonJS((exports) => {
|
|
|
62452
62860
|
return items;
|
|
62453
62861
|
}, []));
|
|
62454
62862
|
function replaceName(n) {
|
|
62455
|
-
const c =
|
|
62863
|
+
const c = constants3[n.str];
|
|
62456
62864
|
if (c === undefined || names[n.str] !== 1)
|
|
62457
62865
|
return n;
|
|
62458
62866
|
delete names[n.str];
|
|
62459
62867
|
return c;
|
|
62460
62868
|
}
|
|
62461
62869
|
function canOptimize(e) {
|
|
62462
|
-
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 &&
|
|
62870
|
+
return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants3[c.str] !== undefined);
|
|
62463
62871
|
}
|
|
62464
62872
|
}
|
|
62465
62873
|
function subtractNames(names, from) {
|
|
@@ -69913,6 +70321,27 @@ var init_mcp = __esm(() => {
|
|
|
69913
70321
|
};
|
|
69914
70322
|
});
|
|
69915
70323
|
|
|
70324
|
+
// src/lib/remote-customer-operations.ts
|
|
70325
|
+
var REMOTE_CUSTOMER_OPERATIONS;
|
|
70326
|
+
var init_remote_customer_operations = __esm(() => {
|
|
70327
|
+
REMOTE_CUSTOMER_OPERATIONS = [
|
|
70328
|
+
{ name: "get_account", title: "Get Account Identity", parameter: null, mutates: false, invoke: (client) => client.getIdentity() },
|
|
70329
|
+
{ name: "get_server_capabilities", title: "Get Server Capabilities", parameter: null, mutates: false, invoke: (client) => client.getCapabilities() },
|
|
70330
|
+
{ name: "list_remote_skills", title: "List Remote Skills", parameter: null, mutates: false, invoke: (client) => client.listSkills() },
|
|
70331
|
+
{ name: "get_billing_status", title: "Get Billing Status", parameter: null, mutates: false, invoke: (client) => client.getBillingStatus() },
|
|
70332
|
+
{ name: "list_credit_packs", title: "List Credit Packs", parameter: null, mutates: false, invoke: (client) => client.listCreditPacks() },
|
|
70333
|
+
{ name: "create_credit_checkout", title: "Create Credit Checkout", parameter: "pack_id", mutates: true, invoke: (client, value) => client.createCreditCheckout(value) },
|
|
70334
|
+
{ name: "get_billing_usage", title: "Get Billing Usage", parameter: null, mutates: false, invoke: (client) => client.getUsage() },
|
|
70335
|
+
{ name: "list_invoices", title: "List Invoices", parameter: null, mutates: false, invoke: (client) => client.listInvoices() },
|
|
70336
|
+
{ name: "create_billing_checkout", title: "Create Billing Checkout", parameter: null, mutates: true, invoke: (client) => client.createBillingCheckout() },
|
|
70337
|
+
{ name: "create_billing_portal", title: "Create Billing Portal", parameter: null, mutates: true, invoke: (client) => client.createBillingPortal() },
|
|
70338
|
+
{ name: "get_run_logs", title: "Get Run Logs", parameter: "run_id", mutates: false, invoke: (client, value) => client.getRunLogs(value) },
|
|
70339
|
+
{ name: "cancel_run", title: "Cancel Run", parameter: "run_id", mutates: true, invoke: (client, value) => client.cancelRun(value) },
|
|
70340
|
+
{ name: "resume_run", title: "Resume Run", parameter: "run_id", mutates: true, invoke: (client, value) => client.resumeRun(value) },
|
|
70341
|
+
{ name: "list_run_artifacts", title: "List Run Artifacts", parameter: "run_id", mutates: false, invoke: (client, value) => client.getRunArtifacts(value) }
|
|
70342
|
+
];
|
|
70343
|
+
});
|
|
70344
|
+
|
|
69916
70345
|
// src/lib/mcp-contracts.ts
|
|
69917
70346
|
function listMcpToolContracts(query) {
|
|
69918
70347
|
const needle = query?.toLowerCase();
|
|
@@ -70054,8 +70483,9 @@ var MCP_CONTRACT_SCHEMA_VERSION = 1, stringSchema = (description) => ({
|
|
|
70054
70483
|
type: "array",
|
|
70055
70484
|
items,
|
|
70056
70485
|
...description ? { description } : {}
|
|
70057
|
-
}), skillNameInput, optionalAgentInput, scopeInput, runInputSchema, runArgsSchema, errorSchema, skillSummarySchema, toolPrimitiveSummarySchema, skillToolDependencySchema, validationMessageSchema, validationOutputSchema, installOutputSchema, runOutputSchema, toolContracts, contracts, resourceContracts;
|
|
70486
|
+
}), skillNameInput, optionalAgentInput, scopeInput, runInputSchema, runArgsSchema, errorSchema, skillSummarySchema, toolPrimitiveSummarySchema, skillToolDependencySchema, validationMessageSchema, validationOutputSchema, installOutputSchema, runOutputSchema, toolContracts, remoteCustomerContracts, contracts, resourceContracts;
|
|
70058
70487
|
var init_mcp_contracts = __esm(() => {
|
|
70488
|
+
init_remote_customer_operations();
|
|
70059
70489
|
skillNameInput = stringSchema("skill name or alias.");
|
|
70060
70490
|
optionalAgentInput = stringSchema("Optional target agent slug. Use MCP registration instead of direct skill-folder installs.");
|
|
70061
70491
|
scopeInput = {
|
|
@@ -70424,11 +70854,44 @@ var init_mcp_contracts = __esm(() => {
|
|
|
70424
70854
|
dependencies: objectSchema({}, [], "Package dependencies.", true)
|
|
70425
70855
|
})
|
|
70426
70856
|
},
|
|
70857
|
+
{
|
|
70858
|
+
name: "list_api_keys",
|
|
70859
|
+
title: "List API Keys",
|
|
70860
|
+
description: "List keys using fresh email OTP reauthentication.",
|
|
70861
|
+
params: ["email", "code"],
|
|
70862
|
+
category: "execution",
|
|
70863
|
+
sideEffects: "local-process-or-remote-run",
|
|
70864
|
+
stable: true,
|
|
70865
|
+
inputSchema: objectSchema({ email: { type: "string", format: "email" }, code: { type: "string", pattern: "^\\d{6}$" } }, ["email", "code"]),
|
|
70866
|
+
outputSchema: arraySchema(objectSchema({}, [], "API key metadata", true))
|
|
70867
|
+
},
|
|
70868
|
+
{
|
|
70869
|
+
name: "revoke_api_key",
|
|
70870
|
+
title: "Revoke API Key",
|
|
70871
|
+
description: "Revoke a key using fresh email OTP reauthentication.",
|
|
70872
|
+
params: ["key_id", "email", "code"],
|
|
70873
|
+
category: "execution",
|
|
70874
|
+
sideEffects: "local-process-or-remote-run",
|
|
70875
|
+
stable: true,
|
|
70876
|
+
inputSchema: objectSchema({ key_id: stringSchema("API key ID"), email: { type: "string", format: "email" }, code: { type: "string", pattern: "^\\d{6}$" } }, ["key_id", "email", "code"]),
|
|
70877
|
+
outputSchema: objectSchema({}, [], "Revocation result", true)
|
|
70878
|
+
},
|
|
70879
|
+
{
|
|
70880
|
+
name: "create_api_key",
|
|
70881
|
+
title: "Create API Key",
|
|
70882
|
+
description: "Create a key with fresh email OTP reauthentication; returns the secret once.",
|
|
70883
|
+
params: ["name", "email", "code", "scopes?"],
|
|
70884
|
+
category: "execution",
|
|
70885
|
+
sideEffects: "local-process-or-remote-run",
|
|
70886
|
+
stable: true,
|
|
70887
|
+
inputSchema: objectSchema({ name: stringSchema("Key name"), email: { type: "string", format: "email" }, code: { type: "string", pattern: "^\\d{6}$" }, scopes: arraySchema(stringSchema("Scope")) }, ["name", "email", "code"]),
|
|
70888
|
+
outputSchema: objectSchema({}, [], "Created key and one-time secret", true)
|
|
70889
|
+
},
|
|
70427
70890
|
{
|
|
70428
70891
|
name: "run_skill",
|
|
70429
70892
|
title: "Run Skill",
|
|
70430
70893
|
description: "Run a skill locally or through a configured remote runner. Returns compact stdout/stderr previews and run summaries by default; pass detail:true for full records.",
|
|
70431
|
-
params: ["name", "input?", "args?", "detail?"],
|
|
70894
|
+
params: ["name", "input?", "args?", "detail?", "remote?", "maxCredits?", "maxCostCents?", "idempotency_key?", "files?"],
|
|
70432
70895
|
category: "execution",
|
|
70433
70896
|
sideEffects: "local-process-or-remote-run",
|
|
70434
70897
|
stable: true,
|
|
@@ -70436,7 +70899,12 @@ var init_mcp_contracts = __esm(() => {
|
|
|
70436
70899
|
name: skillNameInput,
|
|
70437
70900
|
input: runInputSchema,
|
|
70438
70901
|
args: runArgsSchema,
|
|
70439
|
-
detail: { type: "boolean", default: false, description: "Return full stdout/stderr, remote run, and local run metadata." }
|
|
70902
|
+
detail: { type: "boolean", default: false, description: "Return full stdout/stderr, remote run, and local run metadata." },
|
|
70903
|
+
remote: { type: "boolean", description: "Use the configured server catalog." },
|
|
70904
|
+
maxCredits: { type: "integer", minimum: 0, description: "Maximum explicitly approved integer credits; omitted permits only free remote runs." },
|
|
70905
|
+
maxCostCents: { type: "integer", minimum: 0, description: "Legacy alias for maxCredits; both must agree." },
|
|
70906
|
+
idempotency_key: { type: "string", pattern: "^[A-Za-z0-9._:-]{1,128}$", description: "Stable retry key for the same remote submission." },
|
|
70907
|
+
files: { type: "array", maxItems: 10, items: objectSchema({ name: stringSchema("Safe basename"), base64: { type: "string", maxLength: 1398104 }, contentType: stringSchema("MIME type") }, ["name", "base64"]), description: "Inline remote inputs, at most 1 MiB combined." }
|
|
70440
70908
|
}, ["name"]),
|
|
70441
70909
|
outputSchema: runOutputSchema
|
|
70442
70910
|
},
|
|
@@ -70703,7 +71171,40 @@ var init_mcp_contracts = __esm(() => {
|
|
|
70703
71171
|
outputSchema: objectSchema({}, [], "Feedback save result.", true)
|
|
70704
71172
|
}
|
|
70705
71173
|
];
|
|
70706
|
-
|
|
71174
|
+
remoteCustomerContracts = REMOTE_CUSTOMER_OPERATIONS.map((operation) => ({
|
|
71175
|
+
name: operation.name,
|
|
71176
|
+
title: operation.title,
|
|
71177
|
+
description: `${operation.title} on the configured server; unavailable capabilities fail explicitly.`,
|
|
71178
|
+
params: operation.parameter ? [operation.parameter] : [],
|
|
71179
|
+
category: "execution",
|
|
71180
|
+
sideEffects: operation.mutates ? "local-process-or-remote-run" : "none",
|
|
71181
|
+
stable: true,
|
|
71182
|
+
inputSchema: objectSchema(operation.parameter ? { [operation.parameter]: stringSchema("Server resource identifier.") } : {}, operation.parameter ? [operation.parameter] : []),
|
|
71183
|
+
outputSchema: { oneOf: [objectSchema({}, [], "Server response.", true), { type: "array", items: objectSchema({}, [], "Server record.", true) }] }
|
|
71184
|
+
}));
|
|
71185
|
+
remoteCustomerContracts.push({
|
|
71186
|
+
name: "quote_skill",
|
|
71187
|
+
title: "Quote Remote Skill",
|
|
71188
|
+
description: "Get a server credit quote without submitting a run.",
|
|
71189
|
+
params: ["name", "input?", "args?"],
|
|
71190
|
+
category: "execution",
|
|
71191
|
+
sideEffects: "none",
|
|
71192
|
+
stable: true,
|
|
71193
|
+
inputSchema: objectSchema({ name: skillNameInput, input: runInputSchema, args: runArgsSchema }, ["name"]),
|
|
71194
|
+
outputSchema: objectSchema({ skill: stringSchema("Canonical server skill."), pricing: objectSchema({}, [], "Quoted integer credits.", true) }, ["skill", "pricing"], undefined, true)
|
|
71195
|
+
});
|
|
71196
|
+
remoteCustomerContracts.push({
|
|
71197
|
+
name: "download_run_artifact",
|
|
71198
|
+
title: "Download Verified Run Artifact",
|
|
71199
|
+
description: "Return verified artifact bytes as base64, bounded to 1 MiB.",
|
|
71200
|
+
params: ["run_id", "artifact_id"],
|
|
71201
|
+
category: "execution",
|
|
71202
|
+
sideEffects: "none",
|
|
71203
|
+
stable: true,
|
|
71204
|
+
inputSchema: objectSchema({ run_id: stringSchema("Run identifier."), artifact_id: stringSchema("Artifact identifier.") }, ["run_id", "artifact_id"]),
|
|
71205
|
+
outputSchema: objectSchema({ id: stringSchema("Artifact identifier."), fileName: stringSchema("Artifact file name."), base64: stringSchema("Verified bytes."), sha256: stringSchema("SHA256 digest."), byteSize: { type: "integer", minimum: 0 } }, ["id", "fileName", "base64", "sha256", "byteSize"])
|
|
71206
|
+
});
|
|
71207
|
+
contracts = [...toolContracts, ...remoteCustomerContracts].sort((a, b) => a.name.localeCompare(b.name));
|
|
70707
71208
|
resourceContracts = [
|
|
70708
71209
|
{
|
|
70709
71210
|
uri: "skills://mcp/contracts",
|
|
@@ -70985,14 +71486,12 @@ function resolveRunRouting(skill, apiKey, apiUrl) {
|
|
|
70985
71486
|
error: `${skill.name} is a server-owned skill. Run: skills auth login`
|
|
70986
71487
|
};
|
|
70987
71488
|
}
|
|
70988
|
-
return { route: "remote", apiKey };
|
|
71489
|
+
return { route: "remote", apiKey, apiOrigin: apiUrl };
|
|
70989
71490
|
}
|
|
70990
71491
|
async function resolveConfiguredRunRouting(skill, env3 = process.env) {
|
|
70991
|
-
let
|
|
70992
|
-
let apiKey;
|
|
71492
|
+
let connection;
|
|
70993
71493
|
try {
|
|
70994
|
-
|
|
70995
|
-
apiKey = fleet.mode === "hosted" ? await resolveSkillsApiKey(env3) : null;
|
|
71494
|
+
connection = await resolveSkillsConnection(env3);
|
|
70996
71495
|
} catch (error2) {
|
|
70997
71496
|
const isMissingCredential = (error2 instanceof SkillsFleetCredentialError || error2?.name === "SkillsFleetCredentialError") && error2.code === "MISSING_API_CREDENTIAL";
|
|
70998
71497
|
if (!isMissingCredential)
|
|
@@ -71003,7 +71502,7 @@ async function resolveConfiguredRunRouting(skill, env3 = process.env) {
|
|
|
71003
71502
|
error: `${skill.name} is a server-owned skill. ${error2.message}`
|
|
71004
71503
|
};
|
|
71005
71504
|
}
|
|
71006
|
-
return resolveRunRouting(skill, apiKey,
|
|
71505
|
+
return resolveRunRouting(skill, connection?.apiKey, connection?.apiOrigin);
|
|
71007
71506
|
}
|
|
71008
71507
|
var init_run_routing = __esm(() => {
|
|
71009
71508
|
init_fleet_credentials();
|
|
@@ -71212,10 +71711,15 @@ function registerOperationTools(server) {
|
|
|
71212
71711
|
name: exports_external.string(),
|
|
71213
71712
|
input: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
|
|
71214
71713
|
args: exports_external.array(exports_external.string()).optional(),
|
|
71215
|
-
detail: exports_external.boolean().optional()
|
|
71216
|
-
|
|
71217
|
-
|
|
71218
|
-
|
|
71714
|
+
detail: exports_external.boolean().optional(),
|
|
71715
|
+
maxCostCents: exports_external.number().int().min(0).max(2147483647).optional().describe("Maximum integer credits explicitly approved by the user for a remote run; omitted permits only free runs"),
|
|
71716
|
+
maxCredits: exports_external.number().int().min(0).max(2147483647).optional(),
|
|
71717
|
+
remote: exports_external.boolean().optional().describe("Use the configured server catalog, including skills not installed locally"),
|
|
71718
|
+
idempotency_key: exports_external.string().regex(/^[A-Za-z0-9._:-]{1,128}$/).optional().describe("Reuse for the same approved submission after an interrupted response"),
|
|
71719
|
+
files: exports_external.array(exports_external.object({ name: exports_external.string(), base64: exports_external.string().max(1398104), contentType: exports_external.string().optional() })).max(10).optional().describe("Inline remote inputs, at most 1 MiB combined; use CLI or SDK for larger files")
|
|
71720
|
+
}
|
|
71721
|
+
}, async ({ name, input, args, detail, maxCostCents, maxCredits, remote, idempotency_key, files }) => {
|
|
71722
|
+
const skill = remote ? { name, serverOwned: true } : getSkill(name);
|
|
71219
71723
|
if (!skill) {
|
|
71220
71724
|
return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
|
|
71221
71725
|
}
|
|
@@ -71226,17 +71730,26 @@ function registerOperationTools(server) {
|
|
|
71226
71730
|
const skillName = skill.name;
|
|
71227
71731
|
const runInput = input || {};
|
|
71228
71732
|
const runArgs = args || [];
|
|
71229
|
-
if (skillName === ARTICLE_GENERATION_SLUG2) {
|
|
71733
|
+
if (!remote && skillName === ARTICLE_GENERATION_SLUG2) {
|
|
71230
71734
|
const validation = validateBlogArticleRunOptions2(runInput, runArgs, { requireTopic: true });
|
|
71231
71735
|
if (!validation.ok) {
|
|
71232
71736
|
return mcpError("INVALID_BLOG_ARTICLE_OPTIONS", validation.errors.join(" "));
|
|
71233
71737
|
}
|
|
71234
71738
|
}
|
|
71235
71739
|
const routing = await resolveConfiguredRunRouting(skill);
|
|
71740
|
+
if (files?.length && routing.route !== "remote")
|
|
71741
|
+
return mcpError("REMOTE_REQUIRED", "Inline inputs require a remote run");
|
|
71742
|
+
let inputFiles;
|
|
71743
|
+
try {
|
|
71744
|
+
inputFiles = (await Promise.resolve().then(() => (init_remote_files(), exports_remote_files))).decodeRemoteFiles(files ?? []);
|
|
71745
|
+
} catch (error2) {
|
|
71746
|
+
return mcpError("INVALID_INPUT_FILES", error2.message);
|
|
71747
|
+
}
|
|
71236
71748
|
const runContext = createSkillRun({
|
|
71237
71749
|
skill: skillName,
|
|
71238
71750
|
args: runArgs,
|
|
71239
|
-
remote: routing.route === "remote"
|
|
71751
|
+
remote: routing.route === "remote",
|
|
71752
|
+
...routing.route === "remote" ? { remoteApiOrigin: routing.apiOrigin } : {}
|
|
71240
71753
|
});
|
|
71241
71754
|
if (routing.route === "error") {
|
|
71242
71755
|
const error2 = routing.error;
|
|
@@ -71249,8 +71762,8 @@ function registerOperationTools(server) {
|
|
|
71249
71762
|
if (routing.route === "remote") {
|
|
71250
71763
|
try {
|
|
71251
71764
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
71252
|
-
const client = new RemoteSkillsClient2(routing.apiKey);
|
|
71253
|
-
const run = await client.
|
|
71765
|
+
const client = new RemoteSkillsClient2(routing.apiKey, routing.apiOrigin);
|
|
71766
|
+
const run = await client.submitQuotedRunWithFiles(skillName, runInput, runArgs, inputFiles, { maxCredits, maxCostCents, idempotencyKey: idempotency_key ?? runContext.record.id });
|
|
71254
71767
|
if (run.error) {
|
|
71255
71768
|
writeRunLogs(runContext, "", String(run.error) + `
|
|
71256
71769
|
`);
|
|
@@ -71312,7 +71825,7 @@ function registerOperationTools(server) {
|
|
|
71312
71825
|
}
|
|
71313
71826
|
}, async ({ run_id, detail }) => {
|
|
71314
71827
|
const { skillsCredentialOrReason: skillsCredentialOrReason2 } = await Promise.resolve().then(() => (init_fleet_credentials(), exports_fleet_credentials));
|
|
71315
|
-
const { apiKey, reason } = await skillsCredentialOrReason2();
|
|
71828
|
+
const { apiKey, apiOrigin, reason } = await skillsCredentialOrReason2();
|
|
71316
71829
|
if (!apiKey) {
|
|
71317
71830
|
return mcpError("AUTH_REQUIRED", reason ?? "Remote run status requires API access. Run: skills auth login", ["skills auth login"]);
|
|
71318
71831
|
}
|
|
@@ -71323,7 +71836,9 @@ function registerOperationTools(server) {
|
|
|
71323
71836
|
}
|
|
71324
71837
|
try {
|
|
71325
71838
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
71326
|
-
|
|
71839
|
+
if (localRun?.remoteApiOrigin && localRun.remoteApiOrigin !== apiOrigin)
|
|
71840
|
+
return mcpError("INSTANCE_MISMATCH", "This run belongs to another Skills instance; select its credential profile");
|
|
71841
|
+
const client = new RemoteSkillsClient2(apiKey, apiOrigin);
|
|
71327
71842
|
const run = await client.getRun(remoteRunId);
|
|
71328
71843
|
if (!run)
|
|
71329
71844
|
return mcpError("RUN_NOT_FOUND", `Remote run '${remoteRunId}' not found`);
|
|
@@ -71985,7 +72500,7 @@ var init_schedule_tools = __esm(() => {
|
|
|
71985
72500
|
});
|
|
71986
72501
|
|
|
71987
72502
|
// src/lib/native-storage.ts
|
|
71988
|
-
import { createHash as
|
|
72503
|
+
import { createHash as createHash6, createHmac as createHmac3 } from "crypto";
|
|
71989
72504
|
import {
|
|
71990
72505
|
existsSync as existsSync27,
|
|
71991
72506
|
mkdirSync as mkdirSync13,
|
|
@@ -72062,7 +72577,7 @@ function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
|
|
|
72062
72577
|
files.push({
|
|
72063
72578
|
path: relativePath,
|
|
72064
72579
|
sizeBytes: bytes.byteLength,
|
|
72065
|
-
sha256:
|
|
72580
|
+
sha256: createHash6("sha256").update(bytes).digest("hex"),
|
|
72066
72581
|
...options.includeFileContents ? { contentBase64: Buffer.from(bytes).toString("base64") } : {}
|
|
72067
72582
|
});
|
|
72068
72583
|
}
|
|
@@ -72239,6 +72754,201 @@ var init_storage_tools = __esm(() => {
|
|
|
72239
72754
|
init_helpers();
|
|
72240
72755
|
});
|
|
72241
72756
|
|
|
72757
|
+
// src/lib/remote-auth.ts
|
|
72758
|
+
async function requestAuthApi(instance, path, options) {
|
|
72759
|
+
const url = normalizeSkillsApiOrigin(instance);
|
|
72760
|
+
const safeUrl = url;
|
|
72761
|
+
const endpoint = `${(options?.method || "GET").toUpperCase()} ${safeUrl}${path}`;
|
|
72762
|
+
let res;
|
|
72763
|
+
try {
|
|
72764
|
+
res = await fetch(`${url}${path}`, {
|
|
72765
|
+
...options,
|
|
72766
|
+
redirect: "error",
|
|
72767
|
+
signal: options?.signal ?? AbortSignal.timeout(15000),
|
|
72768
|
+
headers: { "Content-Type": "application/json", ...options?.headers }
|
|
72769
|
+
});
|
|
72770
|
+
} catch (err) {
|
|
72771
|
+
throw new HostedApiError(`Unable to reach the Skills API: ${err.message}`, {
|
|
72772
|
+
endpoint,
|
|
72773
|
+
apiUrl: safeUrl
|
|
72774
|
+
});
|
|
72775
|
+
}
|
|
72776
|
+
const text = await res.text();
|
|
72777
|
+
const body = text ? parseJsonBody(text) : {};
|
|
72778
|
+
if (!res.ok) {
|
|
72779
|
+
const record3 = isRecord4(body) ? body : {};
|
|
72780
|
+
const detail = typeof record3.detail === "string" ? record3.detail : undefined;
|
|
72781
|
+
const error2 = typeof record3.error === "string" ? record3.error : undefined;
|
|
72782
|
+
const code = typeof record3.code === "string" ? record3.code : undefined;
|
|
72783
|
+
throw new HostedApiError(detail || error2 || `${res.status} ${res.statusText}`, {
|
|
72784
|
+
status: res.status,
|
|
72785
|
+
code,
|
|
72786
|
+
detail,
|
|
72787
|
+
endpoint,
|
|
72788
|
+
apiUrl: safeUrl
|
|
72789
|
+
});
|
|
72790
|
+
}
|
|
72791
|
+
return body;
|
|
72792
|
+
}
|
|
72793
|
+
function parseJsonBody(text) {
|
|
72794
|
+
try {
|
|
72795
|
+
return JSON.parse(text);
|
|
72796
|
+
} catch {
|
|
72797
|
+
return { detail: condenseErrorBody(text) };
|
|
72798
|
+
}
|
|
72799
|
+
}
|
|
72800
|
+
function condenseErrorBody(text) {
|
|
72801
|
+
const stripped = /<[a-z!/]/i.test(text) ? text.replace(/<(script|style)[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]*>/g, " ") : text;
|
|
72802
|
+
const collapsed = stripped.replace(/\s+/g, " ").trim();
|
|
72803
|
+
if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
72804
|
+
return collapsed;
|
|
72805
|
+
return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
|
|
72806
|
+
}
|
|
72807
|
+
function isRecord4(value) {
|
|
72808
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
72809
|
+
}
|
|
72810
|
+
|
|
72811
|
+
class RemoteSkillsAuthClient {
|
|
72812
|
+
apiOrigin;
|
|
72813
|
+
constructor(apiUrl) {
|
|
72814
|
+
this.apiOrigin = normalizeSkillsApiOrigin(apiUrl);
|
|
72815
|
+
}
|
|
72816
|
+
requestCode(email2) {
|
|
72817
|
+
return this.request("/api/auth/login", { method: "POST", body: JSON.stringify({ email: email2 }) });
|
|
72818
|
+
}
|
|
72819
|
+
verifyCode(email2, code) {
|
|
72820
|
+
return this.request("/api/auth/verify", { method: "POST", body: JSON.stringify({ email: email2, code }) });
|
|
72821
|
+
}
|
|
72822
|
+
startDevice() {
|
|
72823
|
+
return this.request("/api/auth/device/start", { method: "POST", body: JSON.stringify({ client: "skills-sdk" }) });
|
|
72824
|
+
}
|
|
72825
|
+
pollDevice(deviceCode) {
|
|
72826
|
+
return this.request("/api/auth/device/token", { method: "POST", body: JSON.stringify({ deviceCode }) });
|
|
72827
|
+
}
|
|
72828
|
+
async sessionClient(email2, code) {
|
|
72829
|
+
if (!email2.includes("@") || !/^\d{6}$/.test(code))
|
|
72830
|
+
throw new Error("Fresh email and six-digit verification code are required to manage API keys");
|
|
72831
|
+
const login = await this.verifyCode(email2, code);
|
|
72832
|
+
if (!login || typeof login.token !== "string" || !login.token)
|
|
72833
|
+
throw new Error("The server did not return an authorized account session");
|
|
72834
|
+
return new RemoteSkillsClient(login.token, this.apiOrigin);
|
|
72835
|
+
}
|
|
72836
|
+
async createApiKey(email2, code, name, scopes) {
|
|
72837
|
+
return (await this.sessionClient(email2, code)).createApiKey(name, scopes);
|
|
72838
|
+
}
|
|
72839
|
+
async listApiKeys(email2, code) {
|
|
72840
|
+
return (await this.sessionClient(email2, code)).listApiKeys();
|
|
72841
|
+
}
|
|
72842
|
+
async revokeApiKey(email2, code, keyId) {
|
|
72843
|
+
return (await this.sessionClient(email2, code)).revokeApiKey(keyId);
|
|
72844
|
+
}
|
|
72845
|
+
request(path, options) {
|
|
72846
|
+
if (!["/api/auth/login", "/api/auth/verify", "/api/auth/device/start", "/api/auth/device/token", "/api/auth/keys", "/api/auth/whoami"].includes(path))
|
|
72847
|
+
throw new Error("Unsupported authentication operation");
|
|
72848
|
+
return requestAuthApi(this.apiOrigin, path, options);
|
|
72849
|
+
}
|
|
72850
|
+
}
|
|
72851
|
+
var MAX_ERROR_DETAIL_LENGTH = 200, HostedApiError;
|
|
72852
|
+
var init_remote_auth = __esm(() => {
|
|
72853
|
+
init_remote_client();
|
|
72854
|
+
init_fleet_credentials();
|
|
72855
|
+
HostedApiError = class HostedApiError extends Error {
|
|
72856
|
+
status;
|
|
72857
|
+
code;
|
|
72858
|
+
detail;
|
|
72859
|
+
endpoint;
|
|
72860
|
+
apiUrl;
|
|
72861
|
+
constructor(message, options = {}) {
|
|
72862
|
+
super(message);
|
|
72863
|
+
this.name = "HostedApiError";
|
|
72864
|
+
this.status = options.status;
|
|
72865
|
+
this.code = options.code;
|
|
72866
|
+
this.detail = options.detail;
|
|
72867
|
+
this.endpoint = options.endpoint;
|
|
72868
|
+
this.apiUrl = options.apiUrl;
|
|
72869
|
+
}
|
|
72870
|
+
};
|
|
72871
|
+
});
|
|
72872
|
+
|
|
72873
|
+
// src/mcp/remote-customer-tools.ts
|
|
72874
|
+
function registerRemoteCustomerTools(server) {
|
|
72875
|
+
for (const operation of REMOTE_CUSTOMER_OPERATIONS) {
|
|
72876
|
+
const inputSchema = {};
|
|
72877
|
+
if (operation.parameter)
|
|
72878
|
+
inputSchema[operation.parameter] = exports_external.string().min(1);
|
|
72879
|
+
server.registerTool(operation.name, {
|
|
72880
|
+
title: operation.title,
|
|
72881
|
+
description: `${operation.title} on the explicitly configured Skills server. Missing server capabilities return an error. Checkout links require external customer confirmation.`,
|
|
72882
|
+
inputSchema
|
|
72883
|
+
}, async (input) => callRemote((client) => operation.invoke(client, operation.parameter ? String(input[operation.parameter]) : "")));
|
|
72884
|
+
}
|
|
72885
|
+
server.registerTool("list_api_keys", {
|
|
72886
|
+
title: "List API Keys",
|
|
72887
|
+
description: "List account API keys using fresh email OTP reauthentication.",
|
|
72888
|
+
inputSchema: { email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
|
|
72889
|
+
}, async ({ email: email2, code }) => {
|
|
72890
|
+
try {
|
|
72891
|
+
return mcpJson(await new RemoteSkillsAuthClient(getApiUrl("List API keys")).listApiKeys(email2, code));
|
|
72892
|
+
} catch (error2) {
|
|
72893
|
+
return mcpError("KEY_LIST_FAILED", error2.message);
|
|
72894
|
+
}
|
|
72895
|
+
});
|
|
72896
|
+
server.registerTool("revoke_api_key", {
|
|
72897
|
+
title: "Revoke API Key",
|
|
72898
|
+
description: "Revoke an account API key using fresh email OTP reauthentication.",
|
|
72899
|
+
inputSchema: { key_id: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/) }
|
|
72900
|
+
}, async ({ key_id, email: email2, code }) => {
|
|
72901
|
+
try {
|
|
72902
|
+
return mcpJson(await new RemoteSkillsAuthClient(getApiUrl("Revoke API key")).revokeApiKey(email2, code, key_id));
|
|
72903
|
+
} catch (error2) {
|
|
72904
|
+
return mcpError("KEY_REVOKE_FAILED", error2.message);
|
|
72905
|
+
}
|
|
72906
|
+
});
|
|
72907
|
+
server.registerTool("create_api_key", {
|
|
72908
|
+
title: "Create API Key",
|
|
72909
|
+
description: "Create an API key using fresh email OTP reauthentication; returns its secret once. A stored API key cannot grant this authority.",
|
|
72910
|
+
inputSchema: { name: exports_external.string().min(1), email: exports_external.string().email(), code: exports_external.string().regex(/^\d{6}$/), scopes: exports_external.array(exports_external.string()).optional() }
|
|
72911
|
+
}, async ({ name, email: email2, code, scopes }) => {
|
|
72912
|
+
try {
|
|
72913
|
+
return mcpJson(await new RemoteSkillsAuthClient(getApiUrl("Create API key")).createApiKey(email2, code, name, scopes));
|
|
72914
|
+
} catch (error2) {
|
|
72915
|
+
return mcpError("KEY_CREATION_FAILED", error2.message);
|
|
72916
|
+
}
|
|
72917
|
+
});
|
|
72918
|
+
server.registerTool("quote_skill", {
|
|
72919
|
+
title: "Quote Remote Skill",
|
|
72920
|
+
description: "Get the configured server's credit quote without submitting a run.",
|
|
72921
|
+
inputSchema: { name: exports_external.string(), input: exports_external.record(exports_external.string(), exports_external.unknown()).optional(), args: exports_external.array(exports_external.string()).optional() }
|
|
72922
|
+
}, ({ name, input, args }) => callRemote((client) => client.quoteRun(name, input, args)));
|
|
72923
|
+
server.registerTool("download_run_artifact", {
|
|
72924
|
+
title: "Download Verified Run Artifact",
|
|
72925
|
+
description: "Return verified artifact bytes as base64 (at most 1 MiB); use the CLI for larger files.",
|
|
72926
|
+
inputSchema: { run_id: exports_external.string(), artifact_id: exports_external.string() }
|
|
72927
|
+
}, ({ run_id, artifact_id }) => callRemote(async (client) => {
|
|
72928
|
+
const artifact = await client.getVerifiedRunArtifact(run_id, artifact_id, 1024 * 1024);
|
|
72929
|
+
const { bytes, ...metadata } = artifact;
|
|
72930
|
+
return { ...metadata, base64: Buffer.from(bytes).toString("base64") };
|
|
72931
|
+
}));
|
|
72932
|
+
}
|
|
72933
|
+
async function callRemote(action) {
|
|
72934
|
+
try {
|
|
72935
|
+
const client = await createRemoteSkillsClient();
|
|
72936
|
+
if (!client)
|
|
72937
|
+
return mcpError("AUTH_REQUIRED", "Configure a Skills API and sign in with skills auth login");
|
|
72938
|
+
return mcpJson(await action(client));
|
|
72939
|
+
} catch (error2) {
|
|
72940
|
+
return mcpError("REMOTE_REQUEST_FAILED", error2 instanceof Error ? error2.message : "Skills server request failed");
|
|
72941
|
+
}
|
|
72942
|
+
}
|
|
72943
|
+
var init_remote_customer_tools = __esm(() => {
|
|
72944
|
+
init_zod();
|
|
72945
|
+
init_remote_auth();
|
|
72946
|
+
init_auth_store();
|
|
72947
|
+
init_remote_customer_operations();
|
|
72948
|
+
init_remote_client();
|
|
72949
|
+
init_helpers();
|
|
72950
|
+
});
|
|
72951
|
+
|
|
72242
72952
|
// src/mcp/server.ts
|
|
72243
72953
|
function buildServer() {
|
|
72244
72954
|
const server = new McpServer({
|
|
@@ -72250,6 +72960,7 @@ function buildServer() {
|
|
|
72250
72960
|
registerScheduleTools(server);
|
|
72251
72961
|
registerStorageTools(server);
|
|
72252
72962
|
registerResourceMetaTools(server);
|
|
72963
|
+
registerRemoteCustomerTools(server);
|
|
72253
72964
|
return server;
|
|
72254
72965
|
}
|
|
72255
72966
|
var server;
|
|
@@ -72261,6 +72972,7 @@ var init_server3 = __esm(() => {
|
|
|
72261
72972
|
init_resource_meta_tools();
|
|
72262
72973
|
init_schedule_tools();
|
|
72263
72974
|
init_storage_tools();
|
|
72975
|
+
init_remote_customer_tools();
|
|
72264
72976
|
server = buildServer();
|
|
72265
72977
|
});
|
|
72266
72978
|
|
|
@@ -72638,7 +73350,8 @@ MCP server for ${package_default.name}
|
|
|
72638
73350
|
Options:
|
|
72639
73351
|
-V, --version output the version number
|
|
72640
73352
|
-h, --help display help for command
|
|
72641
|
-
--
|
|
73353
|
+
--stdio run newline-delimited JSON-RPC for agent hosts
|
|
73354
|
+
--http run Streamable HTTP transport on 127.0.0.1 (default; port 8836)
|
|
72642
73355
|
--port <n> HTTP port (--http or MCP_HTTP=1)`);
|
|
72643
73356
|
}
|
|
72644
73357
|
async function startMcpStdio() {
|
|
@@ -72887,18 +73600,61 @@ var init_runtime_mcp = __esm(() => {
|
|
|
72887
73600
|
init_installer();
|
|
72888
73601
|
});
|
|
72889
73602
|
|
|
73603
|
+
// src/cli/commands/remote-account.ts
|
|
73604
|
+
var exports_remote_account = {};
|
|
73605
|
+
__export(exports_remote_account, {
|
|
73606
|
+
registerRemoteAccount: () => registerRemoteAccount,
|
|
73607
|
+
execute: () => execute
|
|
73608
|
+
});
|
|
73609
|
+
function registerRemoteAccount(parent) {
|
|
73610
|
+
parent.command("capabilities").option("--json", "Output as JSON", false).description("Inspect the selected server's supported API contract").action((options) => execute(options, (client) => client.getCapabilities()));
|
|
73611
|
+
parent.command("quote").argument("<skill>").argument("[args...]").allowUnknownOption(true).passThroughOptions(true).option("--json", "Output the server quote as JSON", false).description("Quote a skill on the configured server without submitting it").action((skill, args2, options) => execute(options, async (client) => client.quoteRun(skill, {}, args2)));
|
|
73612
|
+
const billing = parent.command("billing").description("Inspect the configured server's billing account");
|
|
73613
|
+
billing.command("status").option("--json", "Output as JSON", false).action((options) => execute(options, (client) => client.getBillingStatus()));
|
|
73614
|
+
billing.command("usage").option("--json", "Output as JSON", false).action((options) => execute(options, (client) => client.getUsage()));
|
|
73615
|
+
billing.command("invoices").option("--json", "Output as JSON", false).action((options) => execute(options, (client) => client.listInvoices()));
|
|
73616
|
+
billing.command("checkout").option("--json", "Output as JSON", false).description("Create an external subscription checkout link").action((options) => execute(options, (client) => client.createBillingCheckout()));
|
|
73617
|
+
billing.command("portal").option("--json", "Output as JSON", false).description("Create an external customer billing portal link").action((options) => execute(options, (client) => client.createBillingPortal()));
|
|
73618
|
+
const credits = parent.command("credits").description("Inspect and purchase credits from the configured server");
|
|
73619
|
+
credits.command("packs").option("--json", "Output as JSON", false).action((options) => execute(options, (client) => client.listCreditPacks()));
|
|
73620
|
+
credits.command("buy").argument("<pack-id>", "An ID returned by credits packs").option("--json", "Output as JSON", false).description("Create an external checkout link; payment is confirmed in the browser").action((packId, options) => execute(options, (client) => client.createCreditCheckout(packId)));
|
|
73621
|
+
}
|
|
73622
|
+
async function execute(options, action) {
|
|
73623
|
+
try {
|
|
73624
|
+
const client = await createRemoteSkillsClient();
|
|
73625
|
+
if (!client)
|
|
73626
|
+
throw new Error("Configure a Skills server with skills setup --api-url <url>, then skills auth login");
|
|
73627
|
+
const result2 = await action(client);
|
|
73628
|
+
console.log(JSON.stringify(result2, null, 2));
|
|
73629
|
+
} catch (error2) {
|
|
73630
|
+
const message = error2 instanceof Error ? error2.message : "The Skills server request failed";
|
|
73631
|
+
if (options.json)
|
|
73632
|
+
console.log(JSON.stringify({ error: message }));
|
|
73633
|
+
else
|
|
73634
|
+
console.error(message);
|
|
73635
|
+
process.exitCode = 1;
|
|
73636
|
+
}
|
|
73637
|
+
}
|
|
73638
|
+
var init_remote_account2 = __esm(() => {
|
|
73639
|
+
init_remote_client();
|
|
73640
|
+
});
|
|
73641
|
+
|
|
72890
73642
|
// src/cli/commands/runtime.ts
|
|
72891
73643
|
var exports_runtime = {};
|
|
72892
73644
|
__export(exports_runtime, {
|
|
72893
73645
|
registerRuntime: () => registerRuntime
|
|
72894
73646
|
});
|
|
72895
|
-
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync16 } from "fs";
|
|
72896
|
-
import {
|
|
73647
|
+
import { lstatSync as lstatSync4, mkdirSync as mkdirSync15, readFileSync as readFileSync25, writeFileSync as writeFileSync16 } from "fs";
|
|
73648
|
+
import { basename as basename5, join as join31 } from "path";
|
|
72897
73649
|
import { createInterface } from "readline";
|
|
72898
73650
|
function registerRuntime(parent) {
|
|
72899
|
-
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));
|
|
73651
|
+
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("--remote", "Run on the configured server, using its catalog and quote", false).option("--yes", "Approve the server's quoted credit cost for this run", false).option("--idempotency-key <key>", "Reuse this key when retrying the same remote submission").option("--file <path>", "Attach a local input file to a remote run (repeatable)", (value, prior) => [...prior, value], []).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));
|
|
72900
73652
|
const runs = parent.command("runs").description("Inspect local skill run records");
|
|
72901
|
-
runs.command("list").option("--json", "Output as JSON", false).option("--limit <n>", "Maximum number of runs", "20").option("--cursor <n>", "Numeric offset for human-output pagination", "0").description("List recent skill runs").action((options) => handleRunsList(options));
|
|
73653
|
+
runs.command("list").option("--remote", "List runs on the configured server", false).option("--json", "Output as JSON", false).option("--limit <n>", "Maximum number of runs", "20").option("--cursor <n>", "Numeric offset for human-output pagination", "0").description("List recent skill runs").action((options) => options.remote ? execute(options, (client) => client.listRuns(Number(options.limit))) : handleRunsList(options));
|
|
73654
|
+
runs.command("logs").argument("<run-id>").option("--json", "Output as JSON", false).action((id, options) => execute(options, (client) => client.getRunLogs(id)));
|
|
73655
|
+
runs.command("cancel").argument("<run-id>").option("--json", "Output as JSON", false).action((id, options) => execute(options, (client) => client.cancelRun(id)));
|
|
73656
|
+
runs.command("resume").argument("<run-id>").option("--json", "Output as JSON", false).action((id, options) => execute(options, (client) => client.resumeRun(id)));
|
|
73657
|
+
runs.command("artifacts").argument("<run-id>").option("--json", "Output as JSON", false).action((id, options) => execute(options, (client) => client.getRunArtifacts(id)));
|
|
72902
73658
|
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));
|
|
72903
73659
|
runs.command("status").argument("<run-id>", "Remote run id, or local run id linked to a remote run").option("--json", "Output as JSON", false).description("Fetch remote run status").action((runId, options) => handleRunsStatus(runId, options));
|
|
72904
73660
|
const exportsCommand = parent.command("exports").description("Inspect or open skill run exports");
|
|
@@ -72968,8 +73724,13 @@ async function handleSetup(options) {
|
|
|
72968
73724
|
return;
|
|
72969
73725
|
}
|
|
72970
73726
|
let requested = options.apiUrl?.trim();
|
|
72971
|
-
if (!requested && process.stdin.isTTY && process.stdout.isTTY) {
|
|
72972
|
-
|
|
73727
|
+
if (!requested && !options.json && process.stdin.isTTY && process.stdout.isTTY) {
|
|
73728
|
+
const answer = await promptLine("Skills API URL (blank to leave unchanged): ");
|
|
73729
|
+
if (answer === null) {
|
|
73730
|
+
process.exitCode = 130;
|
|
73731
|
+
return;
|
|
73732
|
+
}
|
|
73733
|
+
requested = answer.trim();
|
|
72973
73734
|
}
|
|
72974
73735
|
let saved = null;
|
|
72975
73736
|
let credentialsFile = null;
|
|
@@ -73000,8 +73761,14 @@ async function handleSetup(options) {
|
|
|
73000
73761
|
authenticated = true;
|
|
73001
73762
|
}
|
|
73002
73763
|
} catch (err) {
|
|
73003
|
-
|
|
73004
|
-
|
|
73764
|
+
if (err instanceof SkillsFleetCredentialError && err.code === "MISSING_API_CREDENTIAL") {
|
|
73765
|
+
const authority = resolveSkillsApiOrigin();
|
|
73766
|
+
configured = authority?.origin ?? saved;
|
|
73767
|
+
source = authority?.source ?? null;
|
|
73768
|
+
} else {
|
|
73769
|
+
error2 = err.message;
|
|
73770
|
+
configured = saved;
|
|
73771
|
+
}
|
|
73005
73772
|
}
|
|
73006
73773
|
const next = error2 ? ["skills auth login"] : configured ? ["skills auth login", "skills list --remote"] : ["skills list", "skills run <skill>"];
|
|
73007
73774
|
const payload = {
|
|
@@ -73058,14 +73825,23 @@ function requireHttpUrl(value) {
|
|
|
73058
73825
|
function promptLine(question) {
|
|
73059
73826
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
73060
73827
|
return new Promise((resolve2) => {
|
|
73061
|
-
|
|
73828
|
+
let settled = false;
|
|
73829
|
+
const finish = (answer) => {
|
|
73830
|
+
if (settled)
|
|
73831
|
+
return;
|
|
73832
|
+
settled = true;
|
|
73062
73833
|
rl.close();
|
|
73063
|
-
resolve2(answer
|
|
73834
|
+
resolve2(answer);
|
|
73835
|
+
};
|
|
73836
|
+
rl.once("SIGINT", () => finish(null));
|
|
73837
|
+
rl.once("close", () => finish(null));
|
|
73838
|
+
rl.question(source_default.bold(question), (answer) => {
|
|
73839
|
+
finish(answer.trim());
|
|
73064
73840
|
});
|
|
73065
73841
|
});
|
|
73066
73842
|
}
|
|
73067
73843
|
async function handleRun(name, args2, options) {
|
|
73068
|
-
const skill = getSkill(name);
|
|
73844
|
+
const skill = options.remote ? { name, serverOwned: true } : getSkill(name);
|
|
73069
73845
|
if (!skill) {
|
|
73070
73846
|
const similar = findSimilarSkills(name);
|
|
73071
73847
|
if (options.json) {
|
|
@@ -73079,7 +73855,7 @@ async function handleRun(name, args2, options) {
|
|
|
73079
73855
|
return;
|
|
73080
73856
|
}
|
|
73081
73857
|
const prompt = extractPrompt(args2);
|
|
73082
|
-
if (skill.name === ARTICLE_GENERATION_SLUG) {
|
|
73858
|
+
if (!options.remote && skill.name === ARTICLE_GENERATION_SLUG) {
|
|
73083
73859
|
const validation = validateBlogArticleRunOptions({}, args2, { requireTopic: true });
|
|
73084
73860
|
if (!validation.ok) {
|
|
73085
73861
|
writeBlogArticleValidationError(validation.errors, options.json);
|
|
@@ -73087,11 +73863,62 @@ async function handleRun(name, args2, options) {
|
|
|
73087
73863
|
}
|
|
73088
73864
|
}
|
|
73089
73865
|
const routing = await resolveConfiguredRunRouting(skill);
|
|
73866
|
+
if (routing.route !== "remote" && options.file?.length) {
|
|
73867
|
+
const error2 = "File uploads require an explicitly remote run";
|
|
73868
|
+
if (options.json)
|
|
73869
|
+
console.log(JSON.stringify({ error: error2 }));
|
|
73870
|
+
else
|
|
73871
|
+
console.error(error2);
|
|
73872
|
+
process.exitCode = 1;
|
|
73873
|
+
return;
|
|
73874
|
+
}
|
|
73875
|
+
let client;
|
|
73876
|
+
let approvedCredits = 0;
|
|
73877
|
+
let inputFiles = [];
|
|
73878
|
+
if (routing.route === "remote") {
|
|
73879
|
+
try {
|
|
73880
|
+
parsePollingOptions(options);
|
|
73881
|
+
inputFiles = (options.file ?? []).map((path) => {
|
|
73882
|
+
const info = lstatSync4(path);
|
|
73883
|
+
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
73884
|
+
throw new Error("Input must be a regular file no larger than 20 MiB");
|
|
73885
|
+
return { name: basename5(path), bytes: new Uint8Array(readFileSync25(path)) };
|
|
73886
|
+
});
|
|
73887
|
+
describeRemoteFiles(inputFiles);
|
|
73888
|
+
client = new RemoteSkillsClient(routing.apiKey, routing.apiOrigin);
|
|
73889
|
+
const quote = await client.quoteRun(skill.name, {}, args2);
|
|
73890
|
+
approvedCredits = quote.pricing.costCents;
|
|
73891
|
+
if (approvedCredits > 0 && !options.yes) {
|
|
73892
|
+
if (options.json || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
73893
|
+
throw new Error(`CREDIT_APPROVAL_REQUIRED: This run costs ${approvedCredits} credits. Review skills quote, then rerun with --yes before the skill name.`);
|
|
73894
|
+
}
|
|
73895
|
+
const answer = await promptLine(`Approve ${approvedCredits} credits for ${quote.skill}? (y/N) `);
|
|
73896
|
+
if (answer === null) {
|
|
73897
|
+
process.exitCode = 130;
|
|
73898
|
+
return;
|
|
73899
|
+
}
|
|
73900
|
+
if (!/^(y|yes)$/i.test(answer)) {
|
|
73901
|
+
process.exitCode = 1;
|
|
73902
|
+
return;
|
|
73903
|
+
}
|
|
73904
|
+
}
|
|
73905
|
+
skill.name = quote.skill;
|
|
73906
|
+
} catch (error2) {
|
|
73907
|
+
const message = error2 instanceof Error ? error2.message : "Remote quote failed";
|
|
73908
|
+
if (options.json)
|
|
73909
|
+
console.log(JSON.stringify({ skill: name, exitCode: 1, remote: true, error: message }));
|
|
73910
|
+
else
|
|
73911
|
+
console.error(message);
|
|
73912
|
+
process.exitCode = 1;
|
|
73913
|
+
return;
|
|
73914
|
+
}
|
|
73915
|
+
}
|
|
73090
73916
|
const runContext = createSkillRun({
|
|
73091
73917
|
skill: skill.name,
|
|
73092
73918
|
args: args2,
|
|
73093
73919
|
prompt,
|
|
73094
|
-
remote: routing.route === "remote"
|
|
73920
|
+
remote: routing.route === "remote",
|
|
73921
|
+
...routing.route === "remote" ? { remoteApiOrigin: routing.apiOrigin } : {}
|
|
73095
73922
|
});
|
|
73096
73923
|
if (routing.route === "error") {
|
|
73097
73924
|
const error2 = routing.error;
|
|
@@ -73107,9 +73934,10 @@ async function handleRun(name, args2, options) {
|
|
|
73107
73934
|
}
|
|
73108
73935
|
if (routing.route === "remote") {
|
|
73109
73936
|
try {
|
|
73110
|
-
const
|
|
73111
|
-
|
|
73112
|
-
|
|
73937
|
+
const run = await client.submitQuotedRunWithFiles(skill.name, {}, args2, inputFiles, {
|
|
73938
|
+
maxCredits: approvedCredits,
|
|
73939
|
+
idempotencyKey: options.idempotencyKey ?? runContext.record.id
|
|
73940
|
+
});
|
|
73113
73941
|
if (run.error) {
|
|
73114
73942
|
writeRunLogs(runContext, "", String(run.error) + `
|
|
73115
73943
|
`);
|
|
@@ -73283,7 +74111,7 @@ ${run.id}
|
|
|
73283
74111
|
}
|
|
73284
74112
|
async function handleRunsStatus(runId, options) {
|
|
73285
74113
|
const { skillsCredentialOrReason: skillsCredentialOrReason2 } = await Promise.resolve().then(() => (init_fleet_credentials(), exports_fleet_credentials));
|
|
73286
|
-
const { apiKey, reason } = await skillsCredentialOrReason2();
|
|
74114
|
+
const { apiKey, apiOrigin, reason } = await skillsCredentialOrReason2();
|
|
73287
74115
|
if (!apiKey) {
|
|
73288
74116
|
const error2 = reason ?? "Remote run status requires API access. Run: skills auth login";
|
|
73289
74117
|
if (options.json)
|
|
@@ -73306,7 +74134,9 @@ async function handleRunsStatus(runId, options) {
|
|
|
73306
74134
|
}
|
|
73307
74135
|
try {
|
|
73308
74136
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
73309
|
-
|
|
74137
|
+
if (localRun?.remoteApiOrigin && localRun.remoteApiOrigin !== apiOrigin)
|
|
74138
|
+
throw new Error("This run belongs to another Skills instance; select its credential profile");
|
|
74139
|
+
const client = new RemoteSkillsClient2(apiKey, apiOrigin);
|
|
73310
74140
|
const run = await client.getRun(remoteRunId);
|
|
73311
74141
|
if (!run) {
|
|
73312
74142
|
const error2 = `Remote run '${remoteRunId}' not found`;
|
|
@@ -73384,7 +74214,7 @@ async function handleExportsOpen(runId, options) {
|
|
|
73384
74214
|
}
|
|
73385
74215
|
async function handleExportsDownload(runId, options) {
|
|
73386
74216
|
const { skillsCredentialOrReason: skillsCredentialOrReason2 } = await Promise.resolve().then(() => (init_fleet_credentials(), exports_fleet_credentials));
|
|
73387
|
-
const { apiKey, reason } = await skillsCredentialOrReason2();
|
|
74217
|
+
const { apiKey, apiOrigin, reason } = await skillsCredentialOrReason2();
|
|
73388
74218
|
if (!apiKey) {
|
|
73389
74219
|
const error2 = reason ?? "Remote artifact downloads require API access. Run: skills auth login";
|
|
73390
74220
|
if (options.json)
|
|
@@ -73396,7 +74226,7 @@ async function handleExportsDownload(runId, options) {
|
|
|
73396
74226
|
}
|
|
73397
74227
|
try {
|
|
73398
74228
|
const { RemoteSkillsClient: RemoteSkillsClient2 } = await Promise.resolve().then(() => (init_remote_client(), exports_remote_client));
|
|
73399
|
-
const client = new RemoteSkillsClient2(apiKey);
|
|
74229
|
+
const client = new RemoteSkillsClient2(apiKey, apiOrigin);
|
|
73400
74230
|
const remoteRun = await client.getRun(runId);
|
|
73401
74231
|
if (!remoteRun) {
|
|
73402
74232
|
const error2 = `Remote run '${runId}' not found`;
|
|
@@ -73417,15 +74247,12 @@ async function handleExportsDownload(runId, options) {
|
|
|
73417
74247
|
const artifactId = String(artifact.id || "");
|
|
73418
74248
|
if (!artifactId)
|
|
73419
74249
|
continue;
|
|
73420
|
-
const
|
|
73421
|
-
if (!response.ok)
|
|
73422
|
-
throw new Error(`download failed for artifact ${artifactId}: ${response.status}`);
|
|
74250
|
+
const verified = await client.getVerifiedRunArtifact(runId, artifactId);
|
|
73423
74251
|
const relativePath = safeArtifactRelativePath(typeof artifact.relativePath === "string" ? artifact.relativePath : artifact.fileName, String(artifact.fileName || artifactId));
|
|
73424
74252
|
const outputPath = join31(exportDir, relativePath);
|
|
73425
|
-
|
|
73426
|
-
|
|
73427
|
-
|
|
73428
|
-
downloaded.push({ id: artifactId, path: outputPath, byteSize: bytes.byteLength });
|
|
74253
|
+
ensureSafeExportParent(exportDir, relativePath);
|
|
74254
|
+
writeFileSync16(outputPath, verified.bytes, { flag: "wx", mode: 384 });
|
|
74255
|
+
downloaded.push({ id: artifactId, path: outputPath, byteSize: verified.byteSize });
|
|
73429
74256
|
}
|
|
73430
74257
|
const payload = {
|
|
73431
74258
|
runId,
|
|
@@ -73452,11 +74279,26 @@ async function handleExportsDownload(runId, options) {
|
|
|
73452
74279
|
function safeArtifactRelativePath(value, fallback) {
|
|
73453
74280
|
const raw = typeof value === "string" && value.trim() ? value : fallback;
|
|
73454
74281
|
const parts = raw.split(/[\\/]+/).filter((part) => part && part !== ".");
|
|
73455
|
-
if (parts.length === 0 || parts.some((part) => part === ".."))
|
|
73456
|
-
|
|
73457
|
-
}
|
|
74282
|
+
if (raw.startsWith("/") || /^[A-Za-z]:/.test(raw) || parts.length === 0 || parts.some((part) => part === ".." || /[\x00-\x1f\x7f]/.test(part)))
|
|
74283
|
+
throw new Error("Unsafe artifact path");
|
|
73458
74284
|
return parts.join("/");
|
|
73459
74285
|
}
|
|
74286
|
+
function ensureSafeExportParent(root, relativePath) {
|
|
74287
|
+
const parts = relativePath.split("/").slice(0, -1);
|
|
74288
|
+
let parent = root;
|
|
74289
|
+
for (const part of ["", ...parts]) {
|
|
74290
|
+
if (part)
|
|
74291
|
+
parent = join31(parent, part);
|
|
74292
|
+
try {
|
|
74293
|
+
if (!lstatSync4(parent).isDirectory() || lstatSync4(parent).isSymbolicLink())
|
|
74294
|
+
throw new Error("Unsafe artifact directory");
|
|
74295
|
+
} catch (error2) {
|
|
74296
|
+
if (error2.code !== "ENOENT")
|
|
74297
|
+
throw error2;
|
|
74298
|
+
mkdirSync15(parent, { mode: 448 });
|
|
74299
|
+
}
|
|
74300
|
+
}
|
|
74301
|
+
}
|
|
73460
74302
|
function parsePollingOptions(options) {
|
|
73461
74303
|
return {
|
|
73462
74304
|
intervalMs: parsePositiveInt(options.pollIntervalMs, 1000),
|
|
@@ -73643,6 +74485,9 @@ var init_runtime = __esm(() => {
|
|
|
73643
74485
|
init_run_state();
|
|
73644
74486
|
init_runtime_mcp();
|
|
73645
74487
|
init_run_routing();
|
|
74488
|
+
init_remote_client();
|
|
74489
|
+
init_remote_account2();
|
|
74490
|
+
init_remote_files();
|
|
73646
74491
|
});
|
|
73647
74492
|
|
|
73648
74493
|
// src/cli/commands/completion.ts
|
|
@@ -73934,11 +74779,11 @@ var init_portable_snapshot_filter = __esm(() => {
|
|
|
73934
74779
|
});
|
|
73935
74780
|
|
|
73936
74781
|
// src/lib/station-snapshot.ts
|
|
73937
|
-
import { createHash as
|
|
74782
|
+
import { createHash as createHash7 } from "crypto";
|
|
73938
74783
|
import {
|
|
73939
74784
|
copyFileSync as copyFileSync2,
|
|
73940
74785
|
mkdirSync as mkdirSync16,
|
|
73941
|
-
readFileSync as
|
|
74786
|
+
readFileSync as readFileSync26,
|
|
73942
74787
|
statSync as statSync18,
|
|
73943
74788
|
writeFileSync as writeFileSync17
|
|
73944
74789
|
} from "fs";
|
|
@@ -73949,7 +74794,7 @@ function validateStationId(stationId) {
|
|
|
73949
74794
|
}
|
|
73950
74795
|
}
|
|
73951
74796
|
function sha256File(filePath) {
|
|
73952
|
-
return
|
|
74797
|
+
return createHash7("sha256").update(readFileSync26(filePath)).digest("hex");
|
|
73953
74798
|
}
|
|
73954
74799
|
function scanHome(definition, homesRoot) {
|
|
73955
74800
|
const homePath = homePathFor(definition, homesRoot);
|
|
@@ -74074,7 +74919,7 @@ function writeStationSnapshot(options) {
|
|
|
74074
74919
|
copyFileSync2(plan.source.fullPath, destination);
|
|
74075
74920
|
written += 1;
|
|
74076
74921
|
}
|
|
74077
|
-
const
|
|
74922
|
+
const unchanged2 = plans.length - untouched.length;
|
|
74078
74923
|
const manifest = {
|
|
74079
74924
|
schema: STATION_SYNC_MANIFEST_SCHEMA,
|
|
74080
74925
|
stationId: options.stationId,
|
|
@@ -74082,7 +74927,7 @@ function writeStationSnapshot(options) {
|
|
|
74082
74927
|
producer: STATION_SNAPSHOT_PRODUCER,
|
|
74083
74928
|
stats: {
|
|
74084
74929
|
written,
|
|
74085
|
-
unchanged,
|
|
74930
|
+
unchanged: unchanged2,
|
|
74086
74931
|
files: plans.length,
|
|
74087
74932
|
bytes: totalBytes
|
|
74088
74933
|
},
|
|
@@ -74095,7 +74940,7 @@ function writeStationSnapshot(options) {
|
|
|
74095
74940
|
return {
|
|
74096
74941
|
...base2,
|
|
74097
74942
|
mode: "populate",
|
|
74098
|
-
stats: { files: plans.length, bytes: totalBytes, written, unchanged },
|
|
74943
|
+
stats: { files: plans.length, bytes: totalBytes, written, unchanged: unchanged2 },
|
|
74099
74944
|
manifestPath
|
|
74100
74945
|
};
|
|
74101
74946
|
}
|
|
@@ -74121,7 +74966,7 @@ var exports_create_sync_config = {};
|
|
|
74121
74966
|
__export(exports_create_sync_config, {
|
|
74122
74967
|
registerCreateSync: () => registerCreateSync
|
|
74123
74968
|
});
|
|
74124
|
-
import { existsSync as existsSync29
|
|
74969
|
+
import { existsSync as existsSync29 } from "fs";
|
|
74125
74970
|
import { join as join33 } from "path";
|
|
74126
74971
|
function registerCreateSync(parent) {
|
|
74127
74972
|
const configCmd = parent.command("config").description("Manage skills configuration");
|
|
@@ -74214,54 +75059,27 @@ function registerCreateSync(parent) {
|
|
|
74214
75059
|
parent.command("sync").alias("render").argument("[names...]", "Skills to sync (default: every skill in this machine's corpus)").option("--for <agent>", `Target one agent (${SYNC_AGENTS.join(", ")}, or all)`, "all").option("--all", "Sync every corpus skill (the default)", false).option("--source <path>", "Canonical corpus source: a directory of skill folders, or a package root with skills/ (overrides $SKILLS_SOURCE)").option("--dry-run", "Show what would be written without touching any agent folder", false).option("--force", "Adopt an unmanaged skill that already has SKILL.md; other unmarked directories are never overwritten", false).option("--check", "Home drift census (missing-from-home / stray-in-home / diverged); exits non-zero on drift, writes nothing", false).option("--adopt", "Unmarked-home adoption mode: hash unmarked home skills against the corpus; exact matches are marked (dry-run by default)", false).option("--prune", "Prune mode: list (or with --apply, remove) marked home skill dirs that have no canonical corpus entry", false).option("--apply", "Write adoption markers / conflicts ledger, or perform prune removals", false).option("--json", "Output as JSON", false).option("--station <id>", "Per-station snapshot mode: snapshot the installed skill homes into resources/<station>/skills with a v3 sync-manifest (dry-run by default; --populate writes)").option("--populate", "Write the per-station snapshot (station mode; the default is dry-run)", false).option("--repo-root <path>", "Station snapshot destination repo root (default: cwd)").option("--homes-root <dir>", "Build the station snapshot from a staged mirror of the skill homes instead of this machine's $HOME").description("Write corpus skills into each coding agent's global skills folder, per-tool adapted; with --station, snapshot the homes into a reviewed snapshot repo instead").action((names, options) => handleSync(names, options));
|
|
74215
75060
|
}
|
|
74216
75061
|
function handleCreate(name, options) {
|
|
74217
|
-
|
|
74218
|
-
|
|
74219
|
-
|
|
74220
|
-
|
|
74221
|
-
|
|
74222
|
-
|
|
75062
|
+
try {
|
|
75063
|
+
const tags = options.tags?.split(",").map((tag) => tag.trim()).filter(Boolean);
|
|
75064
|
+
const result2 = scaffoldPortableSkill(name, {
|
|
75065
|
+
description: options.description,
|
|
75066
|
+
category: options.category,
|
|
75067
|
+
tags
|
|
75068
|
+
});
|
|
75069
|
+
clearRegistryCache();
|
|
75070
|
+
if (options.json)
|
|
75071
|
+
console.log(JSON.stringify({ created: result2.created, name: result2.name, path: result2.path, category: result2.manifest.category, tags: result2.manifest.tags }));
|
|
75072
|
+
else {
|
|
75073
|
+
console.log(source_default.green(`\u2713 Created custom skill '${result2.name}' at ${result2.path}`));
|
|
75074
|
+
console.log(source_default.dim(` Category: ${result2.manifest.category}`));
|
|
75075
|
+
console.log(source_default.dim(` Tags: ${result2.manifest.tags?.join(", ")}`));
|
|
75076
|
+
console.log(` ${source_default.cyan("Edit:")} ${join33(result2.path, "src", "index.ts")}`);
|
|
75077
|
+
console.log(` ${source_default.cyan("Run:")} skills run ${result2.name} --help`);
|
|
75078
|
+
}
|
|
75079
|
+
} catch (error2) {
|
|
75080
|
+
const message = error2.message;
|
|
75081
|
+
console.log(options.json ? JSON.stringify({ error: message }) : source_default.red(message));
|
|
74223
75082
|
process.exitCode = 1;
|
|
74224
|
-
return;
|
|
74225
|
-
}
|
|
74226
|
-
const description = options.description || `${bare} skill`;
|
|
74227
|
-
const tags = options.tags ? options.tags.split(",").map((t) => t.trim()).filter(Boolean) : [bare];
|
|
74228
|
-
const displayName2 = bare.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
74229
|
-
mkdirSync17(join33(skillDir, "src"), { recursive: true });
|
|
74230
|
-
writeFileSync18(join33(skillDir, "SKILL.md"), [
|
|
74231
|
-
"---",
|
|
74232
|
-
`name: ${bare}`,
|
|
74233
|
-
`description: ${description}`,
|
|
74234
|
-
`displayName: ${displayName2}`,
|
|
74235
|
-
`category: ${options.category}`,
|
|
74236
|
-
`tags: [${tags.join(", ")}]`,
|
|
74237
|
-
"",
|
|
74238
|
-
`# ${displayName2}`,
|
|
74239
|
-
"",
|
|
74240
|
-
description,
|
|
74241
|
-
"",
|
|
74242
|
-
"## Usage",
|
|
74243
|
-
"",
|
|
74244
|
-
"```bash",
|
|
74245
|
-
`${bare} --help`,
|
|
74246
|
-
"```",
|
|
74247
|
-
""
|
|
74248
|
-
].join(`
|
|
74249
|
-
`));
|
|
74250
|
-
writeFileSync18(join33(skillDir, "src", "index.ts"), [`#!/usr/bin/env bun`, `/**`, ` * ${displayName2} \u2014 ${description}`, ` */`, "", `console.log("${displayName2}");`, ""].join(`
|
|
74251
|
-
`));
|
|
74252
|
-
writeFileSync18(join33(skillDir, "package.json"), JSON.stringify({ name: bare, version: "0.1.0", description, bin: { [bare]: "./src/index.ts" }, scripts: { dev: `bun src/index.ts` }, dependencies: {} }, null, 2) + `
|
|
74253
|
-
`);
|
|
74254
|
-
writeFileSync18(join33(skillDir, "tsconfig.json"), JSON.stringify({ compilerOptions: { target: "ES2022", module: "ESNext", moduleResolution: "bundler", strict: true, outDir: "dist" }, include: ["src/**/*.ts"] }, null, 2) + `
|
|
74255
|
-
`);
|
|
74256
|
-
clearRegistryCache();
|
|
74257
|
-
if (options.json)
|
|
74258
|
-
console.log(JSON.stringify({ created: true, name: bare, path: skillDir, category: options.category, tags }));
|
|
74259
|
-
else {
|
|
74260
|
-
console.log(source_default.green(`\u2713 Created custom skill '${bare}' at ${skillDir}`));
|
|
74261
|
-
console.log(source_default.dim(` Category: ${options.category}`));
|
|
74262
|
-
console.log(source_default.dim(` Tags: ${tags.join(", ")}`));
|
|
74263
|
-
console.log(` ${source_default.cyan("Edit:")} ${join33(skillDir, "src", "index.ts")}`);
|
|
74264
|
-
console.log(` ${source_default.cyan("Run:")} bun ${join33(skillDir, "src", "index.ts")}`);
|
|
74265
75083
|
}
|
|
74266
75084
|
}
|
|
74267
75085
|
function handleSync(names, options) {
|
|
@@ -74507,14 +75325,14 @@ var init_create_sync_config = __esm(() => {
|
|
|
74507
75325
|
});
|
|
74508
75326
|
|
|
74509
75327
|
// src/lib/station-hydrate.ts
|
|
74510
|
-
import { createHash as
|
|
75328
|
+
import { createHash as createHash8 } from "crypto";
|
|
74511
75329
|
import {
|
|
74512
75330
|
copyFileSync as copyFileSync3,
|
|
74513
|
-
mkdirSync as
|
|
75331
|
+
mkdirSync as mkdirSync17,
|
|
74514
75332
|
readdirSync as readdirSync17,
|
|
74515
|
-
readFileSync as
|
|
75333
|
+
readFileSync as readFileSync27,
|
|
74516
75334
|
statSync as statSync19,
|
|
74517
|
-
writeFileSync as
|
|
75335
|
+
writeFileSync as writeFileSync18
|
|
74518
75336
|
} from "fs";
|
|
74519
75337
|
import { dirname as dirname13, join as join34, resolve as resolve3, sep as sep5 } from "path";
|
|
74520
75338
|
function fail2(code, message, detail = []) {
|
|
@@ -74528,7 +75346,7 @@ function readSnapshotManifest(repoRoot, stationId) {
|
|
|
74528
75346
|
const manifestPath = join34(snapshotRoot, "sync-manifest.json");
|
|
74529
75347
|
let manifest;
|
|
74530
75348
|
try {
|
|
74531
|
-
manifest = JSON.parse(
|
|
75349
|
+
manifest = JSON.parse(readFileSync27(manifestPath, "utf8"));
|
|
74532
75350
|
} catch (error2) {
|
|
74533
75351
|
fail2("MANIFEST_UNREADABLE", `cannot read snapshot manifest: ${manifestPath}: ${error2.message}`);
|
|
74534
75352
|
}
|
|
@@ -74664,7 +75482,7 @@ function planStationHydration(stationId, repoRoot) {
|
|
|
74664
75482
|
for (const copy of copies) {
|
|
74665
75483
|
let isStub = false;
|
|
74666
75484
|
try {
|
|
74667
|
-
isStub = isPointerSkillMd(
|
|
75485
|
+
isStub = isPointerSkillMd(readFileSync27(copy.fullPath, "utf8"));
|
|
74668
75486
|
} catch {
|
|
74669
75487
|
isStub = false;
|
|
74670
75488
|
}
|
|
@@ -74710,7 +75528,7 @@ function skillSha256(skill) {
|
|
|
74710
75528
|
return sha256File(skill.files[0].winner.fullPath);
|
|
74711
75529
|
}
|
|
74712
75530
|
const joined = skill.files.map((file) => sha256File(file.winner.fullPath));
|
|
74713
|
-
return
|
|
75531
|
+
return createHash8("sha256").update(joined.sort().join(`
|
|
74714
75532
|
`)).digest("hex");
|
|
74715
75533
|
}
|
|
74716
75534
|
function writeStationHydration(options) {
|
|
@@ -74769,11 +75587,11 @@ function writeStationHydration(options) {
|
|
|
74769
75587
|
}
|
|
74770
75588
|
let written = 0;
|
|
74771
75589
|
for (const entry of toWrite) {
|
|
74772
|
-
|
|
75590
|
+
mkdirSync17(dirname13(entry.destination), { recursive: true });
|
|
74773
75591
|
copyFileSync3(entry.fullPath, entry.destination);
|
|
74774
75592
|
written += 1;
|
|
74775
75593
|
}
|
|
74776
|
-
const
|
|
75594
|
+
const unchanged2 = plan.totalFiles - written;
|
|
74777
75595
|
const hydration = {
|
|
74778
75596
|
schema: STATION_HYDRATION_MANIFEST_SCHEMA,
|
|
74779
75597
|
stationId: options.stationId,
|
|
@@ -74784,20 +75602,20 @@ function writeStationHydration(options) {
|
|
|
74784
75602
|
stats: {
|
|
74785
75603
|
idents: plan.winners.length,
|
|
74786
75604
|
written,
|
|
74787
|
-
unchanged,
|
|
75605
|
+
unchanged: unchanged2,
|
|
74788
75606
|
files: plan.totalFiles,
|
|
74789
75607
|
bytes: plan.totalBytes
|
|
74790
75608
|
},
|
|
74791
75609
|
skills: resultSkills
|
|
74792
75610
|
};
|
|
74793
75611
|
const hydrationManifestPath = join34(dirname13(cacheRoot), `hydration-${options.stationId}.json`);
|
|
74794
|
-
|
|
74795
|
-
|
|
75612
|
+
mkdirSync17(dirname13(hydrationManifestPath), { recursive: true });
|
|
75613
|
+
writeFileSync18(hydrationManifestPath, `${JSON.stringify(hydration, null, 2)}
|
|
74796
75614
|
`);
|
|
74797
75615
|
return {
|
|
74798
75616
|
...base2,
|
|
74799
75617
|
mode: "apply",
|
|
74800
|
-
stats: { ...base2.stats, written, unchanged },
|
|
75618
|
+
stats: { ...base2.stats, written, unchanged: unchanged2 },
|
|
74801
75619
|
manifestPath: hydrationManifestPath
|
|
74802
75620
|
};
|
|
74803
75621
|
}
|
|
@@ -75194,7 +76012,7 @@ var init_schedule = __esm(() => {
|
|
|
75194
76012
|
});
|
|
75195
76013
|
|
|
75196
76014
|
// src/lib/registry-sync.ts
|
|
75197
|
-
import { mkdirSync as
|
|
76015
|
+
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync19 } from "fs";
|
|
75198
76016
|
import { dirname as dirname14, relative as relative6 } from "path";
|
|
75199
76017
|
function createRegistrySyncArtifact(options = {}) {
|
|
75200
76018
|
const profile = options.profile ?? "all";
|
|
@@ -75252,8 +76070,8 @@ function createRegistrySyncArtifact(options = {}) {
|
|
|
75252
76070
|
};
|
|
75253
76071
|
}
|
|
75254
76072
|
function writeRegistrySyncArtifact(path, artifact) {
|
|
75255
|
-
|
|
75256
|
-
|
|
76073
|
+
mkdirSync18(dirname14(path), { recursive: true });
|
|
76074
|
+
writeFileSync19(path, `${JSON.stringify(artifact, null, 2)}
|
|
75257
76075
|
`);
|
|
75258
76076
|
}
|
|
75259
76077
|
function buildDocs(name) {
|
|
@@ -75426,7 +76244,7 @@ __export(exports_publish, {
|
|
|
75426
76244
|
PushSkillError: () => PushSkillError
|
|
75427
76245
|
});
|
|
75428
76246
|
import { execFileSync } from "child_process";
|
|
75429
|
-
import { existsSync as existsSync30, readFileSync as
|
|
76247
|
+
import { existsSync as existsSync30, readFileSync as readFileSync28 } from "fs";
|
|
75430
76248
|
import { hostname as hostname2 } from "os";
|
|
75431
76249
|
import { join as join35 } from "path";
|
|
75432
76250
|
function registerPublish(parent) {
|
|
@@ -75476,7 +76294,7 @@ async function pushSkill(name, options = {}) {
|
|
|
75476
76294
|
const packed = packSkillBundle(skill.path, { maxUnpackedBytes: MAX_UNPACKED_BYTES });
|
|
75477
76295
|
const versionManifest = buildVersionManifest(skill.path, packed);
|
|
75478
76296
|
const skillMdPath = join35(skill.path, "SKILL.md");
|
|
75479
|
-
const skillMd = existsSync30(skillMdPath) ?
|
|
76297
|
+
const skillMd = existsSync30(skillMdPath) ? readFileSync28(skillMdPath, "utf-8") : undefined;
|
|
75480
76298
|
const base2 = {
|
|
75481
76299
|
slug: skill.name,
|
|
75482
76300
|
path: skill.path,
|
|
@@ -75680,72 +76498,35 @@ import { createInterface as createInterface2 } from "readline";
|
|
|
75680
76498
|
function prompt(question) {
|
|
75681
76499
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
75682
76500
|
return new Promise((resolve4) => {
|
|
75683
|
-
|
|
76501
|
+
let settled = false;
|
|
76502
|
+
const finish = (answer) => {
|
|
76503
|
+
if (settled)
|
|
76504
|
+
return;
|
|
76505
|
+
settled = true;
|
|
75684
76506
|
rl.close();
|
|
75685
|
-
|
|
75686
|
-
|
|
76507
|
+
if (answer === null)
|
|
76508
|
+
process.exitCode = 130;
|
|
76509
|
+
resolve4(answer);
|
|
76510
|
+
};
|
|
76511
|
+
rl.once("SIGINT", () => finish(null));
|
|
76512
|
+
rl.once("close", () => finish(null));
|
|
76513
|
+
rl.question(question, (answer) => finish(answer.trim()));
|
|
75687
76514
|
});
|
|
75688
76515
|
}
|
|
75689
|
-
function
|
|
75690
|
-
try {
|
|
75691
|
-
const parsed = new URL(url);
|
|
75692
|
-
if (!parsed.username && !parsed.password)
|
|
75693
|
-
return url;
|
|
75694
|
-
parsed.username = "";
|
|
75695
|
-
parsed.password = "";
|
|
75696
|
-
return parsed.toString().replace(/\/+$/, "");
|
|
75697
|
-
} catch {
|
|
75698
|
-
return url;
|
|
75699
|
-
}
|
|
75700
|
-
}
|
|
75701
|
-
async function apiRequest(path, options) {
|
|
75702
|
-
const url = getApiUrl(`${(options?.method || "GET").toUpperCase()} ${path}`);
|
|
75703
|
-
const safeUrl = redactUrl(url);
|
|
75704
|
-
const endpoint = `${(options?.method || "GET").toUpperCase()} ${safeUrl}${path}`;
|
|
75705
|
-
let res;
|
|
76516
|
+
function authForPrompt() {
|
|
75706
76517
|
try {
|
|
75707
|
-
|
|
75708
|
-
|
|
75709
|
-
|
|
75710
|
-
|
|
75711
|
-
|
|
75712
|
-
throw new HostedApiError(`Unable to reach the Skills API: ${err.message}`, {
|
|
75713
|
-
endpoint,
|
|
75714
|
-
apiUrl: safeUrl
|
|
75715
|
-
});
|
|
75716
|
-
}
|
|
75717
|
-
const text = await res.text();
|
|
75718
|
-
const body = text ? parseJsonBody(text) : {};
|
|
75719
|
-
if (!res.ok) {
|
|
75720
|
-
const record3 = isRecord4(body) ? body : {};
|
|
75721
|
-
const detail = typeof record3.detail === "string" ? record3.detail : undefined;
|
|
75722
|
-
const error2 = typeof record3.error === "string" ? record3.error : undefined;
|
|
75723
|
-
const code = typeof record3.code === "string" ? record3.code : undefined;
|
|
75724
|
-
throw new HostedApiError(detail || error2 || `${res.status} ${res.statusText}`, {
|
|
75725
|
-
status: res.status,
|
|
75726
|
-
code,
|
|
75727
|
-
detail,
|
|
75728
|
-
endpoint,
|
|
75729
|
-
apiUrl: safeUrl
|
|
75730
|
-
});
|
|
75731
|
-
}
|
|
75732
|
-
return body;
|
|
75733
|
-
}
|
|
75734
|
-
function parseJsonBody(text) {
|
|
75735
|
-
try {
|
|
75736
|
-
return JSON.parse(text);
|
|
75737
|
-
} catch {
|
|
75738
|
-
return { detail: condenseErrorBody(text) };
|
|
76518
|
+
return getAuthConfig();
|
|
76519
|
+
} catch (error2) {
|
|
76520
|
+
if (error2 instanceof SkillsFleetCredentialError && error2.code === "MISSING_API_CREDENTIAL")
|
|
76521
|
+
return null;
|
|
76522
|
+
throw error2;
|
|
75739
76523
|
}
|
|
75740
76524
|
}
|
|
75741
|
-
function
|
|
75742
|
-
const
|
|
75743
|
-
|
|
75744
|
-
if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
75745
|
-
return collapsed;
|
|
75746
|
-
return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
|
|
76525
|
+
async function apiRequest(path, options, instance) {
|
|
76526
|
+
const origin = instance ?? getApiUrl(`${(options?.method || "GET").toUpperCase()} ${path}`);
|
|
76527
|
+
return new RemoteSkillsAuthClient(origin).request(path, options);
|
|
75747
76528
|
}
|
|
75748
|
-
function
|
|
76529
|
+
function isRecord5(value) {
|
|
75749
76530
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
75750
76531
|
}
|
|
75751
76532
|
function commandErrorPayload(err, fallback) {
|
|
@@ -75759,7 +76540,7 @@ function commandErrorPayload(err, fallback) {
|
|
|
75759
76540
|
...err.apiUrl ? { apiUrl: err.apiUrl } : {}
|
|
75760
76541
|
};
|
|
75761
76542
|
}
|
|
75762
|
-
const code =
|
|
76543
|
+
const code = isRecord5(err) && typeof err.code === "string" ? err.code : undefined;
|
|
75763
76544
|
return {
|
|
75764
76545
|
error: err?.message || fallback,
|
|
75765
76546
|
...code ? { code } : {}
|
|
@@ -75783,19 +76564,11 @@ function writeCommandError(err, fallback, json) {
|
|
|
75783
76564
|
}
|
|
75784
76565
|
process.exitCode = 1;
|
|
75785
76566
|
}
|
|
75786
|
-
function credentialSource() {
|
|
75787
|
-
try {
|
|
75788
|
-
const fleet = resolveSkillsFleet();
|
|
75789
|
-
return fleet.mode === "hosted" ? fleet.apiKeySource : null;
|
|
75790
|
-
} catch {
|
|
75791
|
-
return null;
|
|
75792
|
-
}
|
|
75793
|
-
}
|
|
75794
76567
|
function stringField2(value) {
|
|
75795
76568
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
75796
76569
|
}
|
|
75797
76570
|
function recordField(value) {
|
|
75798
|
-
return
|
|
76571
|
+
return isRecord5(value) ? value : undefined;
|
|
75799
76572
|
}
|
|
75800
76573
|
function authIdentityPayload(authSource, live, cached2, offline = false) {
|
|
75801
76574
|
const root = recordField(live) ?? {};
|
|
@@ -75852,7 +76625,7 @@ function openBrowser(url) {
|
|
|
75852
76625
|
Bun.spawn(command, { stdout: "ignore", stderr: "ignore" });
|
|
75853
76626
|
} catch {}
|
|
75854
76627
|
}
|
|
75855
|
-
async function ensureApiKey(loginResult) {
|
|
76628
|
+
async function ensureApiKey(loginResult, origin) {
|
|
75856
76629
|
if (loginResult.apiKey)
|
|
75857
76630
|
return loginResult.apiKey;
|
|
75858
76631
|
if (!loginResult.token)
|
|
@@ -75861,11 +76634,11 @@ async function ensureApiKey(loginResult) {
|
|
|
75861
76634
|
method: "POST",
|
|
75862
76635
|
headers: { Authorization: `Bearer ${loginResult.token}` },
|
|
75863
76636
|
body: JSON.stringify({ name: "cli" })
|
|
75864
|
-
});
|
|
76637
|
+
}, origin);
|
|
75865
76638
|
return keyRes.key;
|
|
75866
76639
|
}
|
|
75867
|
-
async function persistLoginResult(loginResult) {
|
|
75868
|
-
const storedKey = await ensureApiKey(loginResult);
|
|
76640
|
+
async function persistLoginResult(loginResult, origin, env3) {
|
|
76641
|
+
const storedKey = await ensureApiKey(loginResult, origin);
|
|
75869
76642
|
if (!storedKey)
|
|
75870
76643
|
return;
|
|
75871
76644
|
saveAuthConfig({
|
|
@@ -75874,7 +76647,7 @@ async function persistLoginResult(loginResult) {
|
|
|
75874
76647
|
orgId: loginResult.organization.id,
|
|
75875
76648
|
orgSlug: loginResult.organization.slug,
|
|
75876
76649
|
userId: loginResult.user.id
|
|
75877
|
-
});
|
|
76650
|
+
}, env3, origin);
|
|
75878
76651
|
return storedKey;
|
|
75879
76652
|
}
|
|
75880
76653
|
function printLoginSuccess(loginResult, json) {
|
|
@@ -75895,6 +76668,14 @@ function printLoginSuccess(loginResult, json) {
|
|
|
75895
76668
|
}
|
|
75896
76669
|
}
|
|
75897
76670
|
async function doLogin(email2, code, json) {
|
|
76671
|
+
const env3 = { ...process.env };
|
|
76672
|
+
let origin;
|
|
76673
|
+
try {
|
|
76674
|
+
origin = getApiUrl("Sign in");
|
|
76675
|
+
} catch (error2) {
|
|
76676
|
+
writeCommandError(error2, "Configure a Skills API before signing in", json);
|
|
76677
|
+
return;
|
|
76678
|
+
}
|
|
75898
76679
|
if (!email2 || !email2.includes("@")) {
|
|
75899
76680
|
writeCommandError(new Error("Invalid email"), "Invalid email", json);
|
|
75900
76681
|
process.exitCode = 1;
|
|
@@ -75908,7 +76689,7 @@ async function doLogin(email2, code, json) {
|
|
|
75908
76689
|
sendRes = await apiRequest("/api/auth/login", {
|
|
75909
76690
|
method: "POST",
|
|
75910
76691
|
body: JSON.stringify({ email: email2 })
|
|
75911
|
-
});
|
|
76692
|
+
}, origin);
|
|
75912
76693
|
} catch (err) {
|
|
75913
76694
|
writeCommandError(err, "Failed to request login code", json);
|
|
75914
76695
|
return;
|
|
@@ -75923,14 +76704,17 @@ async function doLogin(email2, code, json) {
|
|
|
75923
76704
|
console.log(JSON.stringify({ status: "code_sent", email: email2, message: "Check email for 6-digit code, then run: skills auth login --email " + email2 + " --code <CODE>" }));
|
|
75924
76705
|
return;
|
|
75925
76706
|
}
|
|
75926
|
-
|
|
76707
|
+
const answer = await prompt(source_default.bold("Code: "));
|
|
76708
|
+
if (answer === null)
|
|
76709
|
+
return;
|
|
76710
|
+
code = answer;
|
|
75927
76711
|
}
|
|
75928
76712
|
let verifyRes;
|
|
75929
76713
|
try {
|
|
75930
76714
|
verifyRes = await apiRequest("/api/auth/verify", {
|
|
75931
76715
|
method: "POST",
|
|
75932
76716
|
body: JSON.stringify({ email: email2, code })
|
|
75933
|
-
});
|
|
76717
|
+
}, origin);
|
|
75934
76718
|
} catch (err) {
|
|
75935
76719
|
writeCommandError(err, "Failed to verify login code", json);
|
|
75936
76720
|
return;
|
|
@@ -75941,7 +76725,7 @@ async function doLogin(email2, code, json) {
|
|
|
75941
76725
|
}
|
|
75942
76726
|
let storedKey;
|
|
75943
76727
|
try {
|
|
75944
|
-
storedKey = await persistLoginResult(verifyRes);
|
|
76728
|
+
storedKey = await persistLoginResult(verifyRes, origin, env3);
|
|
75945
76729
|
} catch (err) {
|
|
75946
76730
|
writeCommandError(err, "Login succeeded but API key creation failed", json);
|
|
75947
76731
|
return;
|
|
@@ -75953,6 +76737,14 @@ async function doLogin(email2, code, json) {
|
|
|
75953
76737
|
printLoginSuccess(verifyRes, Boolean(json));
|
|
75954
76738
|
}
|
|
75955
76739
|
async function doApiKeyLogin(apiKey, json) {
|
|
76740
|
+
const env3 = { ...process.env };
|
|
76741
|
+
let origin;
|
|
76742
|
+
try {
|
|
76743
|
+
origin = getApiUrl("Verify API key");
|
|
76744
|
+
} catch (error2) {
|
|
76745
|
+
writeCommandError(error2, "Configure a Skills API before signing in", json);
|
|
76746
|
+
return;
|
|
76747
|
+
}
|
|
75956
76748
|
const trimmed = apiKey.trim();
|
|
75957
76749
|
if (!trimmed) {
|
|
75958
76750
|
writeCommandError(new Error("API key required"), "API key required", json);
|
|
@@ -75962,7 +76754,7 @@ async function doApiKeyLogin(apiKey, json) {
|
|
|
75962
76754
|
try {
|
|
75963
76755
|
whoami = await apiRequest("/api/auth/whoami", {
|
|
75964
76756
|
headers: { Authorization: `Bearer ${trimmed}` }
|
|
75965
|
-
});
|
|
76757
|
+
}, origin);
|
|
75966
76758
|
} catch (err) {
|
|
75967
76759
|
writeCommandError(err, "Failed to verify API key", json);
|
|
75968
76760
|
return;
|
|
@@ -75978,7 +76770,7 @@ async function doApiKeyLogin(apiKey, json) {
|
|
|
75978
76770
|
...orgId ? { orgId } : {},
|
|
75979
76771
|
...orgSlug ? { orgSlug } : {},
|
|
75980
76772
|
...userId ? { userId } : {}
|
|
75981
|
-
});
|
|
76773
|
+
}, env3, origin);
|
|
75982
76774
|
if (json || !isTTY) {
|
|
75983
76775
|
console.log(JSON.stringify({ ...identity2, status: "authenticated" }, null, 2));
|
|
75984
76776
|
return;
|
|
@@ -75986,12 +76778,25 @@ async function doApiKeyLogin(apiKey, json) {
|
|
|
75986
76778
|
printWhoami(identity2);
|
|
75987
76779
|
}
|
|
75988
76780
|
async function doDeviceLogin(options) {
|
|
76781
|
+
const timeoutMs = Number(options.pollTimeoutMs ?? DEFAULT_DEVICE_POLL_TIMEOUT_MS);
|
|
76782
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > DEFAULT_DEVICE_POLL_TIMEOUT_MS) {
|
|
76783
|
+
writeCommandError(new Error("Device polling timeout must be an integer from 1 to 600000 milliseconds"), "Invalid polling timeout", options.json);
|
|
76784
|
+
return;
|
|
76785
|
+
}
|
|
76786
|
+
const env3 = { ...process.env };
|
|
76787
|
+
let origin;
|
|
76788
|
+
try {
|
|
76789
|
+
origin = getApiUrl("Device sign in");
|
|
76790
|
+
} catch (error3) {
|
|
76791
|
+
writeCommandError(error3, "Configure a Skills API before signing in", options.json);
|
|
76792
|
+
return;
|
|
76793
|
+
}
|
|
75989
76794
|
let start;
|
|
75990
76795
|
try {
|
|
75991
76796
|
start = await apiRequest("/api/auth/device/start", {
|
|
75992
76797
|
method: "POST",
|
|
75993
76798
|
body: JSON.stringify({ client: "skills-cli" })
|
|
75994
|
-
});
|
|
76799
|
+
}, origin);
|
|
75995
76800
|
} catch (err) {
|
|
75996
76801
|
writeCommandError(err, "Failed to start device login", options.json);
|
|
75997
76802
|
return;
|
|
@@ -76035,8 +76840,8 @@ Sign in in your browser
|
|
|
76035
76840
|
console.log(source_default.dim(`
|
|
76036
76841
|
Waiting for authentication...`));
|
|
76037
76842
|
}
|
|
76038
|
-
const
|
|
76039
|
-
const
|
|
76843
|
+
const interval = Number(start.interval ?? 5);
|
|
76844
|
+
const intervalMs = Number.isFinite(interval) ? Math.min(30000, Math.max(1000, interval * 1000)) : 5000;
|
|
76040
76845
|
const deadline = Date.now() + timeoutMs;
|
|
76041
76846
|
while (Date.now() < deadline) {
|
|
76042
76847
|
let tokenRes;
|
|
@@ -76044,13 +76849,13 @@ Waiting for authentication...`));
|
|
|
76044
76849
|
tokenRes = await apiRequest("/api/auth/device/token", {
|
|
76045
76850
|
method: "POST",
|
|
76046
76851
|
body: JSON.stringify({ deviceCode: start.deviceCode })
|
|
76047
|
-
});
|
|
76852
|
+
}, origin);
|
|
76048
76853
|
} catch (err) {
|
|
76049
76854
|
writeCommandError(err, "Failed to poll device login", options.json);
|
|
76050
76855
|
return;
|
|
76051
76856
|
}
|
|
76052
76857
|
if (tokenRes.error === "authorization_pending" || tokenRes.status === "pending") {
|
|
76053
|
-
await sleep(intervalMs);
|
|
76858
|
+
await sleep(Math.min(intervalMs, Math.max(0, deadline - Date.now())));
|
|
76054
76859
|
continue;
|
|
76055
76860
|
}
|
|
76056
76861
|
if (tokenRes.error) {
|
|
@@ -76059,7 +76864,7 @@ Waiting for authentication...`));
|
|
|
76059
76864
|
}
|
|
76060
76865
|
let storedKey;
|
|
76061
76866
|
try {
|
|
76062
|
-
storedKey = await persistLoginResult(tokenRes);
|
|
76867
|
+
storedKey = await persistLoginResult(tokenRes, origin, env3);
|
|
76063
76868
|
} catch (err) {
|
|
76064
76869
|
writeCommandError(err, "Login succeeded but API key creation failed", options.json);
|
|
76065
76870
|
return;
|
|
@@ -76080,6 +76885,30 @@ Waiting for authentication...`));
|
|
|
76080
76885
|
}
|
|
76081
76886
|
function registerAuth(parent) {
|
|
76082
76887
|
const auth = parent.command("auth").description("Manage account authentication");
|
|
76888
|
+
const keys2 = auth.command("keys").description("Manage API keys on the configured instance");
|
|
76889
|
+
keys2.command("list").option("--json", "Output as JSON", false).requiredOption("--email <email>", "Account email for fresh reauthentication").requiredOption("--code <code>", "Fresh OTP requested through auth signup/login").action(async (options) => {
|
|
76890
|
+
try {
|
|
76891
|
+
console.log(JSON.stringify(await new RemoteSkillsAuthClient(getApiUrl("List API keys")).listApiKeys(options.email, options.code), null, 2));
|
|
76892
|
+
} catch (error2) {
|
|
76893
|
+
writeCommandError(error2, "Failed to list API keys", options.json);
|
|
76894
|
+
}
|
|
76895
|
+
});
|
|
76896
|
+
keys2.command("create").argument("<name>").option("--scope <scope>", "Limit key scope (repeatable)", (value, all) => [...all, value], []).option("--json", "Output the newly created key as JSON", false).requiredOption("--email <email>", "Account email for fresh reauthentication").requiredOption("--code <code>", "Fresh OTP requested through auth signup/login").description("Create a key; the returned secret is shown once and must be stored securely").action(async (name, options) => {
|
|
76897
|
+
try {
|
|
76898
|
+
const client = new RemoteSkillsAuthClient(getApiUrl("Create API key"));
|
|
76899
|
+
const created = await client.createApiKey(options.email, options.code, name, options.scope.length ? options.scope : undefined);
|
|
76900
|
+
console.log(JSON.stringify(created, null, 2));
|
|
76901
|
+
} catch (error2) {
|
|
76902
|
+
writeCommandError(error2, "Failed to create API key", options.json);
|
|
76903
|
+
}
|
|
76904
|
+
});
|
|
76905
|
+
keys2.command("revoke").argument("<key-id>").option("--json", "Output as JSON", false).requiredOption("--email <email>", "Account email for fresh reauthentication").requiredOption("--code <code>", "Fresh OTP requested through auth signup/login").action(async (id, options) => {
|
|
76906
|
+
try {
|
|
76907
|
+
console.log(JSON.stringify(await new RemoteSkillsAuthClient(getApiUrl("Revoke API key")).revokeApiKey(options.email, options.code, id), null, 2));
|
|
76908
|
+
} catch (error2) {
|
|
76909
|
+
writeCommandError(error2, "Failed to revoke API key", options.json);
|
|
76910
|
+
}
|
|
76911
|
+
});
|
|
76083
76912
|
auth.command("login").description("Sign in with browser/device code or email code").option("--email <email>", "Email address (non-interactive)").option("--code <code>", "Verification code (non-interactive)").option("--api-key <key>", "Verify and store an API key").option("--device", "Use browser/device-code login", false).option("--no-open", "Do not open a browser for device-code login").option("--poll", "Poll until browser authentication completes in non-interactive mode", false).option("--poll-timeout-ms <ms>", "Maximum time to wait for device-code login").option("--json", "Output result as JSON", false).action(async (options) => {
|
|
76084
76913
|
if (options.apiKey) {
|
|
76085
76914
|
await doApiKeyLogin(options.apiKey, options.json);
|
|
@@ -76090,63 +76919,67 @@ function registerAuth(parent) {
|
|
|
76090
76919
|
return;
|
|
76091
76920
|
}
|
|
76092
76921
|
let email2 = options.email;
|
|
76093
|
-
if (!email2 && isTTY) {
|
|
76094
|
-
const existing =
|
|
76922
|
+
if (!email2 && isTTY && !options.json) {
|
|
76923
|
+
const existing = authForPrompt();
|
|
76095
76924
|
if (existing) {
|
|
76096
76925
|
console.log(source_default.dim(`Already signed in as ${existing.email}`));
|
|
76097
76926
|
const again = await prompt("Sign in with a different account? (y/N) ");
|
|
76098
|
-
if (again.toLowerCase() !== "y")
|
|
76927
|
+
if (again === null || again.toLowerCase() !== "y")
|
|
76099
76928
|
return;
|
|
76100
76929
|
}
|
|
76101
|
-
|
|
76930
|
+
const answer = await prompt(source_default.bold("Email: "));
|
|
76931
|
+
if (answer === null)
|
|
76932
|
+
return;
|
|
76933
|
+
email2 = answer;
|
|
76102
76934
|
}
|
|
76103
76935
|
if (!email2) {
|
|
76104
|
-
|
|
76105
|
-
process.exitCode = 1;
|
|
76936
|
+
writeCommandError(new Error("Email required. Use: skills auth login --email you@example.com"), "Email required", options.json);
|
|
76106
76937
|
return;
|
|
76107
76938
|
}
|
|
76108
76939
|
await doLogin(email2, options.code, options.json);
|
|
76109
76940
|
});
|
|
76110
|
-
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) => {
|
|
76941
|
+
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)").option("--json", "Output result as JSON without prompting", false).action(async (options) => {
|
|
76111
76942
|
let email2 = options.email;
|
|
76112
|
-
if (!email2 && isTTY) {
|
|
76113
|
-
const existing =
|
|
76943
|
+
if (!email2 && isTTY && !options.json) {
|
|
76944
|
+
const existing = authForPrompt();
|
|
76114
76945
|
if (existing) {
|
|
76115
76946
|
console.log(source_default.dim(`Already signed in as ${existing.email}`));
|
|
76116
76947
|
const again = await prompt("Continue with a different account? (y/N) ");
|
|
76117
|
-
if (again.toLowerCase() !== "y")
|
|
76948
|
+
if (again === null || again.toLowerCase() !== "y")
|
|
76118
76949
|
return;
|
|
76119
76950
|
}
|
|
76120
|
-
|
|
76951
|
+
const answer = await prompt(source_default.bold("Email: "));
|
|
76952
|
+
if (answer === null)
|
|
76953
|
+
return;
|
|
76954
|
+
email2 = answer;
|
|
76121
76955
|
}
|
|
76122
76956
|
if (!email2) {
|
|
76123
|
-
|
|
76957
|
+
const error2 = "Email required. Use: skills auth signup --email you@example.com";
|
|
76958
|
+
if (options.json)
|
|
76959
|
+
console.log(JSON.stringify({ error: error2 }));
|
|
76960
|
+
else
|
|
76961
|
+
console.error(source_default.red(error2));
|
|
76124
76962
|
process.exitCode = 1;
|
|
76125
76963
|
return;
|
|
76126
76964
|
}
|
|
76127
|
-
await doLogin(email2, options.code);
|
|
76965
|
+
await doLogin(email2, options.code, options.json);
|
|
76128
76966
|
});
|
|
76129
|
-
auth.command("logout").description("
|
|
76130
|
-
const existing = getAuthConfig();
|
|
76131
|
-
if (!existing) {
|
|
76132
|
-
console.log(source_default.dim("Not signed in"));
|
|
76133
|
-
return;
|
|
76134
|
-
}
|
|
76967
|
+
auth.command("logout").description("Remove this profile's stored credentials; injected keys remain configured").option("--json", "Output as JSON", false).action((options) => {
|
|
76135
76968
|
const { stillResolves } = clearAuthConfig();
|
|
76136
|
-
|
|
76137
|
-
|
|
76138
|
-
|
|
76139
|
-
|
|
76969
|
+
if (options.json)
|
|
76970
|
+
console.log(JSON.stringify({ status: stillResolves ? "credential_still_configured" : "signed_out", stillResolves }));
|
|
76971
|
+
else
|
|
76972
|
+
console.log(stillResolves ? "Stored credential removed. A credential is still configured by the environment, profile selection, or Keychain; clear it there to finish signing out." : "Signed out; this profile has no stored credential.");
|
|
76140
76973
|
});
|
|
76141
76974
|
auth.command("whoami").description("Show current account info").option("--json", "Output as JSON", false).action(async (options) => {
|
|
76142
76975
|
let fleet;
|
|
76143
76976
|
try {
|
|
76144
|
-
fleet =
|
|
76977
|
+
fleet = await resolveSkillsConnection();
|
|
76145
76978
|
} catch (err) {
|
|
76146
76979
|
writeCommandError(err, "Failed to resolve the Skills credential", options.json);
|
|
76147
76980
|
return;
|
|
76148
76981
|
}
|
|
76149
|
-
if (fleet
|
|
76982
|
+
if (!fleet) {
|
|
76150
76983
|
const payload = {
|
|
76151
76984
|
status: "unauthenticated",
|
|
76152
76985
|
error: `Not signed in. Run: skills auth login, or set ${SKILLS_API_KEY_ENV}`
|
|
@@ -76157,12 +76990,12 @@ function registerAuth(parent) {
|
|
|
76157
76990
|
console.log(source_default.dim(payload.error));
|
|
76158
76991
|
return;
|
|
76159
76992
|
}
|
|
76160
|
-
const cached2 = fleet.apiKeyTier === "disk" ? getAuthIdentity() : null;
|
|
76993
|
+
const cached2 = fleet.apiKeyTier === "disk" || fleet.apiKeyTier === "profile" ? getAuthIdentity() : null;
|
|
76161
76994
|
const authSource = fleet.apiKeySource;
|
|
76162
76995
|
try {
|
|
76163
76996
|
const res = await apiRequest("/api/auth/whoami", {
|
|
76164
76997
|
headers: { Authorization: `Bearer ${fleet.apiKey}` }
|
|
76165
|
-
});
|
|
76998
|
+
}, fleet.apiOrigin);
|
|
76166
76999
|
const payload = authIdentityPayload(authSource, res, cached2);
|
|
76167
77000
|
if (options.json) {
|
|
76168
77001
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -76170,7 +77003,7 @@ function registerAuth(parent) {
|
|
|
76170
77003
|
printWhoami(payload);
|
|
76171
77004
|
}
|
|
76172
77005
|
} catch (err) {
|
|
76173
|
-
if (cached2 && Object.keys(cached2).length > 0) {
|
|
77006
|
+
if (cached2 && Object.keys(cached2).length > 0 && !(err instanceof HostedApiError && err.status !== undefined && err.status < 500)) {
|
|
76174
77007
|
const payload = authIdentityPayload(authSource, {}, cached2, true);
|
|
76175
77008
|
if (options.json)
|
|
76176
77009
|
console.log(JSON.stringify(payload, null, 2));
|
|
@@ -76182,30 +77015,15 @@ function registerAuth(parent) {
|
|
|
76182
77015
|
}
|
|
76183
77016
|
});
|
|
76184
77017
|
}
|
|
76185
|
-
var isTTY, DEFAULT_DEVICE_POLL_TIMEOUT_MS,
|
|
77018
|
+
var isTTY, DEFAULT_DEVICE_POLL_TIMEOUT_MS, CONFIG_HINT_STATUSES;
|
|
76186
77019
|
var init_auth = __esm(() => {
|
|
76187
77020
|
init_source();
|
|
76188
77021
|
init_auth_store();
|
|
76189
77022
|
init_fleet_credentials();
|
|
77023
|
+
init_remote_auth();
|
|
76190
77024
|
isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
76191
77025
|
DEFAULT_DEVICE_POLL_TIMEOUT_MS = 10 * 60 * 1000;
|
|
76192
77026
|
CONFIG_HINT_STATUSES = new Set([401, 403, 404, 405, 501]);
|
|
76193
|
-
HostedApiError = class HostedApiError extends Error {
|
|
76194
|
-
status;
|
|
76195
|
-
code;
|
|
76196
|
-
detail;
|
|
76197
|
-
endpoint;
|
|
76198
|
-
apiUrl;
|
|
76199
|
-
constructor(message, options = {}) {
|
|
76200
|
-
super(message);
|
|
76201
|
-
this.name = "HostedApiError";
|
|
76202
|
-
this.status = options.status;
|
|
76203
|
-
this.code = options.code;
|
|
76204
|
-
this.detail = options.detail;
|
|
76205
|
-
this.endpoint = options.endpoint;
|
|
76206
|
-
this.apiUrl = options.apiUrl;
|
|
76207
|
-
}
|
|
76208
|
-
};
|
|
76209
77027
|
});
|
|
76210
77028
|
|
|
76211
77029
|
// src/cli/commands/feedback.ts
|
|
@@ -76348,7 +77166,7 @@ var init_storage = __esm(() => {
|
|
|
76348
77166
|
});
|
|
76349
77167
|
|
|
76350
77168
|
// src/lib/registry-reconcile.ts
|
|
76351
|
-
import { existsSync as existsSync31, readFileSync as
|
|
77169
|
+
import { existsSync as existsSync31, readFileSync as readFileSync29, statSync as statSync20, writeFileSync as writeFileSync20 } from "fs";
|
|
76352
77170
|
import { join as join36 } from "path";
|
|
76353
77171
|
function isDirectory2(path) {
|
|
76354
77172
|
try {
|
|
@@ -76368,7 +77186,7 @@ function readBaseline(skillDir) {
|
|
|
76368
77186
|
if (!existsSync31(markerPath))
|
|
76369
77187
|
return;
|
|
76370
77188
|
try {
|
|
76371
|
-
const marker = JSON.parse(
|
|
77189
|
+
const marker = JSON.parse(readFileSync29(markerPath, "utf-8"));
|
|
76372
77190
|
return {
|
|
76373
77191
|
...typeof marker.contentHash === "string" && marker.contentHash ? { contentHash: marker.contentHash } : {},
|
|
76374
77192
|
...typeof marker.version === "string" && marker.version ? { version: marker.version } : {}
|
|
@@ -76382,7 +77200,7 @@ function readCursor(root) {
|
|
|
76382
77200
|
if (!existsSync31(path))
|
|
76383
77201
|
return { runCount: 0 };
|
|
76384
77202
|
try {
|
|
76385
|
-
const cursor = JSON.parse(
|
|
77203
|
+
const cursor = JSON.parse(readFileSync29(path, "utf-8"));
|
|
76386
77204
|
return { runCount: typeof cursor.runCount === "number" ? cursor.runCount : 0 };
|
|
76387
77205
|
} catch {
|
|
76388
77206
|
return { runCount: 0 };
|
|
@@ -76510,7 +77328,9 @@ async function reconcileRegistry(options = {}) {
|
|
|
76510
77328
|
locals.set(meta.name, { slug: meta.name, version: meta.version, sha256: "" });
|
|
76511
77329
|
}
|
|
76512
77330
|
}
|
|
76513
|
-
const remoteRowsPayload = await client.listSkills()
|
|
77331
|
+
const remoteRowsPayload = await client.listSkills().catch(() => {
|
|
77332
|
+
throw new Error("Registry listing failed: the server refused or could not return the catalog.");
|
|
77333
|
+
});
|
|
76514
77334
|
if (!Array.isArray(remoteRowsPayload)) {
|
|
76515
77335
|
const shape = remoteRowsPayload && typeof remoteRowsPayload === "object" ? `object with keys [${Object.keys(remoteRowsPayload).join(", ")}]` : typeof remoteRowsPayload;
|
|
76516
77336
|
throw new ReconcileRegistryError(`Registry listing failed: expected an array of skills, got ${shape}.`, ["Check HASNA_SKILLS_API_URL and the resolved credential; a failed listing must not be read as an empty registry."]);
|
|
@@ -76659,7 +77479,7 @@ async function reconcileRegistry(options = {}) {
|
|
|
76659
77479
|
runCount: readCursor(root).runCount + 1,
|
|
76660
77480
|
summary
|
|
76661
77481
|
};
|
|
76662
|
-
|
|
77482
|
+
writeFileSync20(join36(root, SYNC_CURSOR_FILE), `${JSON.stringify(cursor, null, 2)}
|
|
76663
77483
|
`);
|
|
76664
77484
|
return {
|
|
76665
77485
|
corpusRoot: root,
|
|
@@ -84089,7 +84909,12 @@ if (process.argv.includes("--no-color")) {
|
|
|
84089
84909
|
process.argv.splice(idx, 1);
|
|
84090
84910
|
}
|
|
84091
84911
|
var program2 = new Command;
|
|
84092
|
-
program2.name("skills").description("Discover and run AI agent skills through the Skills CLI/MCP").version(package_default.version).option("--verbose", "Enable verbose logging", false).option("--no-color", "Disable colored output (also respects NO_COLOR env var)").enablePositionalOptions();
|
|
84912
|
+
program2.name("skills").description("Discover and run AI agent skills through the Skills CLI/MCP").version(package_default.version).option("--verbose", "Enable verbose logging", false).option("--profile <name>", "Use an isolated Skills instance credential profile").option("--no-color", "Disable colored output (also respects NO_COLOR env var)").enablePositionalOptions();
|
|
84913
|
+
program2.hook("preAction", () => {
|
|
84914
|
+
const profile = program2.opts().profile;
|
|
84915
|
+
if (profile !== undefined)
|
|
84916
|
+
process.env.HASNA_PROFILE = profile;
|
|
84917
|
+
});
|
|
84093
84918
|
program2.command("interactive", { isDefault: true }).alias("i").allowExcessArguments(true).description("Interactive skill browser (TUI)").action((_options, command) => {
|
|
84094
84919
|
const stray = command.args[0];
|
|
84095
84920
|
if (stray !== undefined) {
|
|
@@ -84117,6 +84942,8 @@ var { registerDiagnostic: registerDiagnostic2 } = await Promise.resolve().then((
|
|
|
84117
84942
|
registerDiagnostic2(program2);
|
|
84118
84943
|
var { registerRuntime: registerRuntime2 } = await Promise.resolve().then(() => (init_runtime(), exports_runtime));
|
|
84119
84944
|
registerRuntime2(program2);
|
|
84945
|
+
var { registerRemoteAccount: registerRemoteAccount2 } = await Promise.resolve().then(() => (init_remote_account2(), exports_remote_account));
|
|
84946
|
+
registerRemoteAccount2(program2);
|
|
84120
84947
|
var { registerCompletion: registerCompletion2 } = await Promise.resolve().then(() => (init_completion(), exports_completion));
|
|
84121
84948
|
registerCompletion2(program2);
|
|
84122
84949
|
var { registerCreateSync: registerCreateSync2 } = await Promise.resolve().then(() => (init_create_sync_config(), exports_create_sync_config));
|