@hasna/skills 0.3.0 → 0.5.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.
Files changed (55) hide show
  1. package/README.md +269 -14
  2. package/bin/index.js +7835 -5440
  3. package/bin/mcp.js +2040 -589
  4. package/bin/migrate.js +148 -40
  5. package/bin/server.js +66 -87
  6. package/bin/worker.js +42 -75
  7. package/dist/admin-contract.d.ts +37 -19
  8. package/dist/admin-contract.js +1 -1
  9. package/dist/cli/cli.test-utils.d.ts +10 -8
  10. package/dist/cli/commands/customer-profile.d.ts +2 -0
  11. package/dist/cli/commands/customer-verification.d.ts +5 -0
  12. package/dist/cli/commands/remote-account.d.ts +7 -0
  13. package/dist/cli/commands/tool-primitives.d.ts +1 -1
  14. package/dist/cli/commands/workspace-member-mutations.d.ts +2 -0
  15. package/dist/cli/commands/workspace-members.d.ts +2 -0
  16. package/dist/cli/env-assignment.d.ts +9 -0
  17. package/dist/index.d.ts +7 -2
  18. package/dist/index.js +1369 -349
  19. package/dist/lib/agent-sync.d.ts +13 -8
  20. package/dist/lib/api-url.d.ts +4 -3
  21. package/dist/lib/app-home.d.ts +0 -1
  22. package/dist/lib/auth-store.d.ts +1 -1
  23. package/dist/lib/client-types.d.ts +75 -0
  24. package/dist/lib/credential-state.d.ts +12 -0
  25. package/dist/lib/fleet-credentials.d.ts +49 -17
  26. package/dist/lib/home-adoption.d.ts +2 -0
  27. package/dist/lib/home-census.d.ts +3 -1
  28. package/dist/lib/instance-credentials.d.ts +13 -0
  29. package/dist/lib/local-opt-in.d.ts +24 -0
  30. package/dist/lib/mcp-contracts.d.ts +4 -0
  31. package/dist/lib/portable-skills-files.d.ts +10 -2
  32. package/dist/lib/portable-skills-types.d.ts +2 -0
  33. package/dist/lib/read-access.d.ts +83 -0
  34. package/dist/lib/remote-account.d.ts +42 -0
  35. package/dist/lib/remote-auth.d.ts +46 -0
  36. package/dist/lib/remote-client.d.ts +90 -6
  37. package/dist/lib/remote-customer-operations.d.ts +106 -0
  38. package/dist/lib/remote-files.d.ts +21 -0
  39. package/dist/lib/remote-profile.d.ts +26 -0
  40. package/dist/lib/remote-registry.d.ts +7 -3
  41. package/dist/lib/remote-workspace.d.ts +76 -0
  42. package/dist/lib/run-routing.d.ts +1 -0
  43. package/dist/lib/run-state.d.ts +3 -0
  44. package/dist/lib/skillinfo.d.ts +1 -1
  45. package/dist/mcp/helpers.d.ts +22 -0
  46. package/dist/mcp/index.d.ts +16 -0
  47. package/dist/mcp/remote-customer-tools.d.ts +2 -0
  48. package/dist/sdk/governance-store.d.ts +1 -0
  49. package/dist/sdk/index.d.ts +8 -1
  50. package/dist/sdk/index.js +1994 -416
  51. package/dist/sdk/outputs.d.ts +0 -11
  52. package/dist/sdk/runs.d.ts +5 -5
  53. package/dist/storage.js +6 -40
  54. package/docs/skill-standard.md +30 -2
  55. package/package.json +7 -6
package/dist/sdk/index.js CHANGED
@@ -2370,11 +2370,11 @@ var require_config = __commonJS((exports) => {
2370
2370
  };
2371
2371
  function getSelectorName(functionString) {
2372
2372
  try {
2373
- const constants = new Set(Array.from(functionString.match(/([A-Z_]){3,}/g) ?? []));
2374
- constants.delete("CONFIG");
2375
- constants.delete("CONFIG_PREFIX_SEPARATOR");
2376
- constants.delete("ENV");
2377
- return [...constants].join(", ");
2373
+ const constants2 = new Set(Array.from(functionString.match(/([A-Z_]){3,}/g) ?? []));
2374
+ constants2.delete("CONFIG");
2375
+ constants2.delete("CONFIG_PREFIX_SEPARATOR");
2376
+ constants2.delete("ENV");
2377
+ return [...constants2].join(", ");
2378
2378
  } catch (ignored) {
2379
2379
  return functionString;
2380
2380
  }
@@ -3573,7 +3573,7 @@ var require_serde = __commonJS((exports) => {
3573
3573
  var { createHmac: createHmac2, createHash: createHash2, getRandomValues } = __require("crypto");
3574
3574
  var { hasOwn: hasOwn2, HttpResponse } = require_transport();
3575
3575
  exports.hasOwn = hasOwn2;
3576
- var { ReadStream, lstatSync, fstatSync: fstatSync2 } = __require("fs");
3576
+ var { ReadStream, lstatSync: lstatSync2, fstatSync: fstatSync3 } = __require("fs");
3577
3577
  var { toEndpointV1 } = require_endpoints();
3578
3578
  var { Readable, Writable, PassThrough } = __require("stream");
3579
3579
  var isArrayBuffer = (arg) => typeof ArrayBuffer === "function" && arg instanceof ArrayBuffer || Object.prototype.toString.call(arg) === "[object ArrayBuffer]";
@@ -4339,9 +4339,9 @@ var require_serde = __commonJS((exports) => {
4339
4339
  return body.end + 1 - body.start;
4340
4340
  } else if (body instanceof ReadStream) {
4341
4341
  if (body.path != null) {
4342
- return lstatSync(body.path).size;
4342
+ return lstatSync2(body.path).size;
4343
4343
  } else if (typeof body.fd === "number") {
4344
- return fstatSync2(body.fd).size;
4344
+ return fstatSync3(body.fd).size;
4345
4345
  }
4346
4346
  }
4347
4347
  throw new Error(`Body Length computation failed for ${body}`);
@@ -17645,7 +17645,7 @@ var require_httpAuthSchemes = __commonJS((exports) => {
17645
17645
  });
17646
17646
 
17647
17647
  // ../../node_modules/.bun/@aws-sdk+credential-provider-env@3.972.70/node_modules/@aws-sdk/credential-provider-env/dist-es/fromEnv.js
17648
- var import_client6, import_config, ENV_KEY = "AWS_ACCESS_KEY_ID", ENV_SECRET = "AWS_SECRET_ACCESS_KEY", ENV_SESSION = "AWS_SESSION_TOKEN", ENV_EXPIRATION = "AWS_CREDENTIAL_EXPIRATION", ENV_CREDENTIAL_SCOPE = "AWS_CREDENTIAL_SCOPE", ENV_ACCOUNT_ID = "AWS_ACCOUNT_ID", fromEnv = (init) => async () => {
17648
+ var import_client8, import_config, ENV_KEY = "AWS_ACCESS_KEY_ID", ENV_SECRET = "AWS_SECRET_ACCESS_KEY", ENV_SESSION = "AWS_SESSION_TOKEN", ENV_EXPIRATION = "AWS_CREDENTIAL_EXPIRATION", ENV_CREDENTIAL_SCOPE = "AWS_CREDENTIAL_SCOPE", ENV_ACCOUNT_ID = "AWS_ACCOUNT_ID", fromEnv = (init) => async () => {
17649
17649
  init?.logger?.debug("@aws-sdk/credential-provider-env - fromEnv");
17650
17650
  const accessKeyId = process.env[ENV_KEY];
17651
17651
  const secretAccessKey = process.env[ENV_SECRET];
@@ -17662,13 +17662,13 @@ var import_client6, import_config, ENV_KEY = "AWS_ACCESS_KEY_ID", ENV_SECRET = "
17662
17662
  ...credentialScope && { credentialScope },
17663
17663
  ...accountId && { accountId }
17664
17664
  };
17665
- import_client6.setCredentialFeature(credentials, "CREDENTIALS_ENV_VARS", "g");
17665
+ import_client8.setCredentialFeature(credentials, "CREDENTIALS_ENV_VARS", "g");
17666
17666
  return credentials;
17667
17667
  }
17668
17668
  throw new import_config.CredentialsProviderError("Unable to find environment variable credentials.", { logger: init?.logger });
17669
17669
  };
17670
17670
  var init_fromEnv = __esm(() => {
17671
- import_client6 = __toESM(require_client2(), 1);
17671
+ import_client8 = __toESM(require_client2(), 1);
17672
17672
  import_config = __toESM(require_config(), 1);
17673
17673
  });
17674
17674
 
@@ -18738,7 +18738,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18738
18738
  return this.connectOptions === undefined ? http2.connect(url) : http2.connect(url, this.connectOptions);
18739
18739
  }
18740
18740
  }
18741
- var { constants } = http2;
18741
+ var { constants: constants2 } = http2;
18742
18742
 
18743
18743
  class NodeHttp2Handler {
18744
18744
  config;
@@ -18829,8 +18829,8 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
18829
18829
  }
18830
18830
  const clientHttp2Stream = session.request({
18831
18831
  ...request.headers,
18832
- [constants.HTTP2_HEADER_PATH]: path,
18833
- [constants.HTTP2_HEADER_METHOD]: method
18832
+ [constants2.HTTP2_HEADER_PATH]: path,
18833
+ [constants2.HTTP2_HEADER_METHOD]: method
18834
18834
  });
18835
18835
  if (effectiveRequestTimeout) {
18836
18836
  clientHttp2Stream.setTimeout(effectiveRequestTimeout, () => {
@@ -19010,7 +19010,7 @@ var retryWrapper = (toRetry, maxRetries, delayMs) => {
19010
19010
 
19011
19011
  // ../../node_modules/.bun/@aws-sdk+credential-provider-http@3.972.72/node_modules/@aws-sdk/credential-provider-http/dist-es/fromHttp/fromHttp.js
19012
19012
  import fs from "fs/promises";
19013
- var import_client7, import_config9, import_node_http_handler, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", DEFAULT_LINK_LOCAL_HOST = "http://169.254.170.2", AWS_CONTAINER_CREDENTIALS_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI", AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE", AWS_CONTAINER_AUTHORIZATION_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN", fromHttp = (options = {}) => {
19013
+ var import_client9, import_config9, import_node_http_handler, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", DEFAULT_LINK_LOCAL_HOST = "http://169.254.170.2", AWS_CONTAINER_CREDENTIALS_FULL_URI = "AWS_CONTAINER_CREDENTIALS_FULL_URI", AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE", AWS_CONTAINER_AUTHORIZATION_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN", fromHttp = (options = {}) => {
19014
19014
  options.logger?.debug("@aws-sdk/credential-provider-http - fromHttp");
19015
19015
  let host;
19016
19016
  const relative2 = options.awsContainerCredentialsRelativeUri ?? process.env[AWS_CONTAINER_CREDENTIALS_RELATIVE_URI];
@@ -19047,7 +19047,7 @@ Set AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
19047
19047
  }
19048
19048
  try {
19049
19049
  const result = await requestHandler.handle(request, { requestTimeout });
19050
- return getCredentials(result.response).then((creds) => import_client7.setCredentialFeature(creds, "CREDENTIALS_HTTP", "z"));
19050
+ return getCredentials(result.response).then((creds) => import_client9.setCredentialFeature(creds, "CREDENTIALS_HTTP", "z"));
19051
19051
  } catch (e2) {
19052
19052
  throw new import_config9.CredentialsProviderError(String(e2), { logger: options.logger });
19053
19053
  }
@@ -19069,7 +19069,7 @@ Set AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
19069
19069
  var init_fromHttp = __esm(() => {
19070
19070
  init_checkUrl();
19071
19071
  init_requestHelpers();
19072
- import_client7 = __toESM(require_client2(), 1);
19072
+ import_client9 = __toESM(require_client2(), 1);
19073
19073
  import_config9 = __toESM(require_config(), 1);
19074
19074
  import_node_http_handler = __toESM(require_dist_cjs6(), 1);
19075
19075
  });
@@ -20453,7 +20453,7 @@ var init_loadSso = __esm(() => {
20453
20453
  });
20454
20454
 
20455
20455
  // ../../node_modules/.bun/@aws-sdk+credential-provider-sso@3.973.14/node_modules/@aws-sdk/credential-provider-sso/dist-es/resolveSSOCredentials.js
20456
- var import_client8, import_config15, SHOULD_FAIL_CREDENTIAL_CHAIN = false, resolveSSOCredentials = async ({ ssoStartUrl, ssoSession, ssoAccountId, ssoRegion, ssoRoleName, ssoClient, clientConfig, parentClientConfig, callerClientConfig, profile, filepath, configFilepath, ignoreCache, logger }) => {
20456
+ var import_client10, import_config15, SHOULD_FAIL_CREDENTIAL_CHAIN = false, resolveSSOCredentials = async ({ ssoStartUrl, ssoSession, ssoAccountId, ssoRegion, ssoRoleName, ssoClient, clientConfig, parentClientConfig, callerClientConfig, profile, filepath, configFilepath, ignoreCache, logger }) => {
20457
20457
  let token;
20458
20458
  const refreshMessage = `To refresh this SSO session run aws sso login with the corresponding profile.`;
20459
20459
  if (ssoSession) {
@@ -20529,15 +20529,15 @@ var import_client8, import_config15, SHOULD_FAIL_CREDENTIAL_CHAIN = false, resol
20529
20529
  ...accountId && { accountId }
20530
20530
  };
20531
20531
  if (ssoSession) {
20532
- import_client8.setCredentialFeature(credentials, "CREDENTIALS_SSO", "s");
20532
+ import_client10.setCredentialFeature(credentials, "CREDENTIALS_SSO", "s");
20533
20533
  } else {
20534
- import_client8.setCredentialFeature(credentials, "CREDENTIALS_SSO_LEGACY", "u");
20534
+ import_client10.setCredentialFeature(credentials, "CREDENTIALS_SSO_LEGACY", "u");
20535
20535
  }
20536
20536
  return credentials;
20537
20537
  };
20538
20538
  var init_resolveSSOCredentials = __esm(() => {
20539
20539
  init_dist_es4();
20540
- import_client8 = __toESM(require_client2(), 1);
20540
+ import_client10 = __toESM(require_client2(), 1);
20541
20541
  import_config15 = __toESM(require_config(), 1);
20542
20542
  });
20543
20543
 
@@ -20649,7 +20649,7 @@ var init_dist_es5 = __esm(() => {
20649
20649
  });
20650
20650
 
20651
20651
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveCredentialSource.js
20652
- var import_client9, import_config18, resolveCredentialSource = (credentialSource, profileName, logger) => {
20652
+ var import_client11, import_config18, resolveCredentialSource = (credentialSource, profileName, logger) => {
20653
20653
  const sourceProvidersMap = {
20654
20654
  EcsContainer: async (options) => {
20655
20655
  const { fromHttp: fromHttp2 } = await Promise.resolve().then(() => (init_dist_es3(), exports_dist_es3));
@@ -20673,9 +20673,9 @@ var import_client9, import_config18, resolveCredentialSource = (credentialSource
20673
20673
  } else {
20674
20674
  throw new import_config18.CredentialsProviderError(`Unsupported credential source in profile ${profileName}. Got ${credentialSource}, expected EcsContainer or Ec2InstanceMetadata or Environment.`, { logger });
20675
20675
  }
20676
- }, setNamedProvider = (creds) => import_client9.setCredentialFeature(creds, "CREDENTIALS_PROFILE_NAMED_PROVIDER", "p");
20676
+ }, setNamedProvider = (creds) => import_client11.setCredentialFeature(creds, "CREDENTIALS_PROFILE_NAMED_PROVIDER", "p");
20677
20677
  var init_resolveCredentialSource = __esm(() => {
20678
- import_client9 = __toESM(require_client2(), 1);
20678
+ import_client11 = __toESM(require_client2(), 1);
20679
20679
  import_config18 = __toESM(require_config(), 1);
20680
20680
  });
20681
20681
 
@@ -21702,7 +21702,7 @@ var require_sts = __commonJS((exports) => {
21702
21702
  });
21703
21703
 
21704
21704
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveAssumeRoleCredentials.js
21705
- var import_client10, import_config19, isAssumeRoleProfile = (arg, { profile = "default", logger } = {}) => {
21705
+ var import_client12, import_config19, isAssumeRoleProfile = (arg, { profile = "default", logger } = {}) => {
21706
21706
  return Boolean(arg) && typeof arg === "object" && typeof arg.role_arn === "string" && ["undefined", "string"].indexOf(typeof arg.role_session_name) > -1 && ["undefined", "string"].indexOf(typeof arg.external_id) > -1 && ["undefined", "string"].indexOf(typeof arg.mfa_serial) > -1 && (isAssumeRoleWithSourceProfile(arg, { profile, logger }) || isCredentialSourceProfile(arg, { profile, logger }));
21707
21707
  }, isAssumeRoleWithSourceProfile = (arg, { profile, logger }) => {
21708
21708
  const withSourceProfile = typeof arg.source_profile === "string" && typeof arg.credential_source === "undefined";
@@ -21741,7 +21741,7 @@ var import_client10, import_config19, isAssumeRoleProfile = (arg, { profile = "d
21741
21741
  [source_profile]: true
21742
21742
  }, isCredentialSourceWithoutRoleArn(profiles[source_profile] ?? {})) : (await resolveCredentialSource(profileData.credential_source, profileName, options.logger)(options))();
21743
21743
  if (isCredentialSourceWithoutRoleArn(profileData)) {
21744
- return sourceCredsProvider.then((creds) => import_client10.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
21744
+ return sourceCredsProvider.then((creds) => import_client12.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
21745
21745
  } else {
21746
21746
  const params = {
21747
21747
  RoleArn: profileData.role_arn,
@@ -21758,14 +21758,14 @@ var import_client10, import_config19, isAssumeRoleProfile = (arg, { profile = "d
21758
21758
  params.TokenCode = await options.mfaCodeProvider(mfa_serial);
21759
21759
  }
21760
21760
  const sourceCreds = await sourceCredsProvider;
21761
- return options.roleAssumer(sourceCreds, params).then((creds) => import_client10.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
21761
+ return options.roleAssumer(sourceCreds, params).then((creds) => import_client12.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
21762
21762
  }
21763
21763
  }, isCredentialSourceWithoutRoleArn = (section) => {
21764
21764
  return !section.role_arn && !!section.credential_source;
21765
21765
  };
21766
21766
  var init_resolveAssumeRoleCredentials = __esm(() => {
21767
21767
  init_resolveCredentialSource();
21768
- import_client10 = __toESM(require_client2(), 1);
21768
+ import_client12 = __toESM(require_client2(), 1);
21769
21769
  import_config19 = __toESM(require_config(), 1);
21770
21770
  });
21771
21771
 
@@ -22766,7 +22766,7 @@ var init_LoginCredentialsFetcher = __esm(() => {
22766
22766
  });
22767
22767
 
22768
22768
  // ../../node_modules/.bun/@aws-sdk+credential-provider-login@3.972.77/node_modules/@aws-sdk/credential-provider-login/dist-es/fromLoginCredentials.js
22769
- var import_client11, import_config21, fromLoginCredentials = (init) => async ({ callerClientConfig } = {}) => {
22769
+ var import_client13, import_config21, fromLoginCredentials = (init) => async ({ callerClientConfig } = {}) => {
22770
22770
  init?.logger?.debug?.("@aws-sdk/credential-providers - fromLoginCredentials");
22771
22771
  const profiles = await import_config21.parseKnownFiles(init || {});
22772
22772
  const profileName = import_config21.getProfileName({
@@ -22781,11 +22781,11 @@ var import_client11, import_config21, fromLoginCredentials = (init) => async ({
22781
22781
  }
22782
22782
  const fetcher = new LoginCredentialsFetcher(profile, init, callerClientConfig);
22783
22783
  const credentials = await fetcher.loadCredentials();
22784
- return import_client11.setCredentialFeature(credentials, "CREDENTIALS_LOGIN", "AD");
22784
+ return import_client13.setCredentialFeature(credentials, "CREDENTIALS_LOGIN", "AD");
22785
22785
  };
22786
22786
  var init_fromLoginCredentials = __esm(() => {
22787
22787
  init_LoginCredentialsFetcher();
22788
- import_client11 = __toESM(require_client2(), 1);
22788
+ import_client13 = __toESM(require_client2(), 1);
22789
22789
  import_config21 = __toESM(require_config(), 1);
22790
22790
  });
22791
22791
 
@@ -22799,7 +22799,7 @@ var init_dist_es6 = __esm(() => {
22799
22799
  });
22800
22800
 
22801
22801
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveLoginCredentials.js
22802
- var import_client12, isLoginProfile = (data) => {
22802
+ var import_client14, isLoginProfile = (data) => {
22803
22803
  return Boolean(data && data.login_session);
22804
22804
  }, resolveLoginCredentials = async (profileName, options, callerClientConfig) => {
22805
22805
  const { fromLoginCredentials: fromLoginCredentials2 } = await Promise.resolve().then(() => (init_dist_es6(), exports_dist_es5));
@@ -22807,14 +22807,14 @@ var import_client12, isLoginProfile = (data) => {
22807
22807
  ...options,
22808
22808
  profile: profileName
22809
22809
  })({ callerClientConfig });
22810
- return import_client12.setCredentialFeature(credentials, "CREDENTIALS_PROFILE_LOGIN", "AC");
22810
+ return import_client14.setCredentialFeature(credentials, "CREDENTIALS_PROFILE_LOGIN", "AC");
22811
22811
  };
22812
22812
  var init_resolveLoginCredentials = __esm(() => {
22813
- import_client12 = __toESM(require_client2(), 1);
22813
+ import_client14 = __toESM(require_client2(), 1);
22814
22814
  });
22815
22815
 
22816
22816
  // ../../node_modules/.bun/@aws-sdk+credential-provider-process@3.972.70/node_modules/@aws-sdk/credential-provider-process/dist-es/getValidatedProcessCredentials.js
22817
- var import_client13, getValidatedProcessCredentials = (profileName, data, profiles) => {
22817
+ var import_client15, getValidatedProcessCredentials = (profileName, data, profiles) => {
22818
22818
  if (data.Version !== 1) {
22819
22819
  throw Error(`Profile ${profileName} credential_process did not return Version 1.`);
22820
22820
  }
@@ -22840,11 +22840,11 @@ var import_client13, getValidatedProcessCredentials = (profileName, data, profil
22840
22840
  ...data.CredentialScope && { credentialScope: data.CredentialScope },
22841
22841
  ...accountId && { accountId }
22842
22842
  };
22843
- import_client13.setCredentialFeature(credentials, "CREDENTIALS_PROCESS", "w");
22843
+ import_client15.setCredentialFeature(credentials, "CREDENTIALS_PROCESS", "w");
22844
22844
  return credentials;
22845
22845
  };
22846
22846
  var init_getValidatedProcessCredentials = __esm(() => {
22847
- import_client13 = __toESM(require_client2(), 1);
22847
+ import_client15 = __toESM(require_client2(), 1);
22848
22848
  });
22849
22849
 
22850
22850
  // ../../node_modules/.bun/@aws-sdk+credential-provider-process@3.972.70/node_modules/@aws-sdk/credential-provider-process/dist-es/resolveProcessCredentials.js
@@ -22905,20 +22905,20 @@ var init_dist_es7 = __esm(() => {
22905
22905
  });
22906
22906
 
22907
22907
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveProcessCredentials.js
22908
- var import_client14, isProcessProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.credential_process === "string", resolveProcessCredentials2 = async (options, profile) => {
22908
+ var import_client16, isProcessProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.credential_process === "string", resolveProcessCredentials2 = async (options, profile) => {
22909
22909
  const { fromProcess: fromProcess2 } = await Promise.resolve().then(() => (init_dist_es7(), exports_dist_es6));
22910
22910
  const credentials = await fromProcess2({
22911
22911
  ...options,
22912
22912
  profile
22913
22913
  })();
22914
- return import_client14.setCredentialFeature(credentials, "CREDENTIALS_PROFILE_PROCESS", "v");
22914
+ return import_client16.setCredentialFeature(credentials, "CREDENTIALS_PROFILE_PROCESS", "v");
22915
22915
  };
22916
22916
  var init_resolveProcessCredentials2 = __esm(() => {
22917
- import_client14 = __toESM(require_client2(), 1);
22917
+ import_client16 = __toESM(require_client2(), 1);
22918
22918
  });
22919
22919
 
22920
22920
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveSsoCredentials.js
22921
- var import_client15, resolveSsoCredentials = async (profile, profileData, options = {}, callerClientConfig) => {
22921
+ var import_client17, resolveSsoCredentials = async (profile, profileData, options = {}, callerClientConfig) => {
22922
22922
  const { fromSSO: fromSSO2 } = await Promise.resolve().then(() => (init_dist_es5(), exports_dist_es4));
22923
22923
  return fromSSO2({
22924
22924
  profile,
@@ -22929,18 +22929,18 @@ var import_client15, resolveSsoCredentials = async (profile, profileData, option
22929
22929
  callerClientConfig
22930
22930
  }).then((creds) => {
22931
22931
  if (profileData.sso_session) {
22932
- return import_client15.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO", "r");
22932
+ return import_client17.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO", "r");
22933
22933
  } else {
22934
- return import_client15.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO_LEGACY", "t");
22934
+ return import_client17.setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO_LEGACY", "t");
22935
22935
  }
22936
22936
  });
22937
22937
  }, isSsoProfile2 = (arg) => arg && (typeof arg.sso_start_url === "string" || typeof arg.sso_account_id === "string" || typeof arg.sso_session === "string" || typeof arg.sso_region === "string" || typeof arg.sso_role_name === "string");
22938
22938
  var init_resolveSsoCredentials = __esm(() => {
22939
- import_client15 = __toESM(require_client2(), 1);
22939
+ import_client17 = __toESM(require_client2(), 1);
22940
22940
  });
22941
22941
 
22942
22942
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveStaticCredentials.js
22943
- var import_client16, isStaticCredsProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.aws_access_key_id === "string" && typeof arg.aws_secret_access_key === "string" && ["undefined", "string"].indexOf(typeof arg.aws_session_token) > -1 && ["undefined", "string"].indexOf(typeof arg.aws_account_id) > -1, resolveStaticCredentials = async (profile, options) => {
22943
+ var import_client18, isStaticCredsProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.aws_access_key_id === "string" && typeof arg.aws_secret_access_key === "string" && ["undefined", "string"].indexOf(typeof arg.aws_session_token) > -1 && ["undefined", "string"].indexOf(typeof arg.aws_account_id) > -1, resolveStaticCredentials = async (profile, options) => {
22944
22944
  options?.logger?.debug("@aws-sdk/credential-provider-ini - resolveStaticCredentials");
22945
22945
  const credentials = {
22946
22946
  accessKeyId: profile.aws_access_key_id,
@@ -22949,10 +22949,10 @@ var import_client16, isStaticCredsProfile = (arg) => Boolean(arg) && typeof arg
22949
22949
  ...profile.aws_credential_scope && { credentialScope: profile.aws_credential_scope },
22950
22950
  ...profile.aws_account_id && { accountId: profile.aws_account_id }
22951
22951
  };
22952
- return import_client16.setCredentialFeature(credentials, "CREDENTIALS_PROFILE", "n");
22952
+ return import_client18.setCredentialFeature(credentials, "CREDENTIALS_PROFILE", "n");
22953
22953
  };
22954
22954
  var init_resolveStaticCredentials = __esm(() => {
22955
- import_client16 = __toESM(require_client2(), 1);
22955
+ import_client18 = __toESM(require_client2(), 1);
22956
22956
  });
22957
22957
 
22958
22958
  // ../../node_modules/.bun/@aws-sdk+credential-provider-web-identity@3.972.76/node_modules/@aws-sdk/credential-provider-web-identity/dist-es/fromWebToken.js
@@ -22984,7 +22984,7 @@ var fromWebToken = (init) => async (awsIdentityProperties) => {
22984
22984
 
22985
22985
  // ../../node_modules/.bun/@aws-sdk+credential-provider-web-identity@3.972.76/node_modules/@aws-sdk/credential-provider-web-identity/dist-es/fromTokenFile.js
22986
22986
  import { readFileSync as readFileSync3 } from "fs";
22987
- var import_client17, import_config24, ENV_TOKEN_FILE = "AWS_WEB_IDENTITY_TOKEN_FILE", ENV_ROLE_ARN = "AWS_ROLE_ARN", ENV_ROLE_SESSION_NAME = "AWS_ROLE_SESSION_NAME", fromTokenFile = (init = {}) => async (awsIdentityProperties) => {
22987
+ var import_client19, import_config24, ENV_TOKEN_FILE = "AWS_WEB_IDENTITY_TOKEN_FILE", ENV_ROLE_ARN = "AWS_ROLE_ARN", ENV_ROLE_SESSION_NAME = "AWS_ROLE_SESSION_NAME", fromTokenFile = (init = {}) => async (awsIdentityProperties) => {
22988
22988
  init.logger?.debug("@aws-sdk/credential-provider-web-identity - fromTokenFile");
22989
22989
  const webIdentityTokenFile = init?.webIdentityTokenFile ?? process.env[ENV_TOKEN_FILE];
22990
22990
  const roleArn = init?.roleArn ?? process.env[ENV_ROLE_ARN];
@@ -23001,12 +23001,12 @@ var import_client17, import_config24, ENV_TOKEN_FILE = "AWS_WEB_IDENTITY_TOKEN_F
23001
23001
  roleSessionName
23002
23002
  })(awsIdentityProperties);
23003
23003
  if (webIdentityTokenFile === process.env[ENV_TOKEN_FILE]) {
23004
- import_client17.setCredentialFeature(credentials, "CREDENTIALS_ENV_VARS_STS_WEB_ID_TOKEN", "h");
23004
+ import_client19.setCredentialFeature(credentials, "CREDENTIALS_ENV_VARS_STS_WEB_ID_TOKEN", "h");
23005
23005
  }
23006
23006
  return credentials;
23007
23007
  };
23008
23008
  var init_fromTokenFile = __esm(() => {
23009
- import_client17 = __toESM(require_client2(), 1);
23009
+ import_client19 = __toESM(require_client2(), 1);
23010
23010
  import_config24 = __toESM(require_config(), 1);
23011
23011
  });
23012
23012
 
@@ -23021,7 +23021,7 @@ var init_dist_es8 = __esm(() => {
23021
23021
  });
23022
23022
 
23023
23023
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveWebIdentityCredentials.js
23024
- var import_client18, isWebIdentityProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.web_identity_token_file === "string" && typeof arg.role_arn === "string" && ["undefined", "string"].indexOf(typeof arg.role_session_name) > -1, resolveWebIdentityCredentials = async (profile, options, callerClientConfig) => {
23024
+ var import_client20, isWebIdentityProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.web_identity_token_file === "string" && typeof arg.role_arn === "string" && ["undefined", "string"].indexOf(typeof arg.role_session_name) > -1, resolveWebIdentityCredentials = async (profile, options, callerClientConfig) => {
23025
23025
  const { fromTokenFile: fromTokenFile2 } = await Promise.resolve().then(() => (init_dist_es8(), exports_dist_es7));
23026
23026
  const credentials = await fromTokenFile2({
23027
23027
  webIdentityTokenFile: profile.web_identity_token_file,
@@ -23033,10 +23033,10 @@ var import_client18, isWebIdentityProfile = (arg) => Boolean(arg) && typeof arg
23033
23033
  })({
23034
23034
  callerClientConfig
23035
23035
  });
23036
- return import_client18.setCredentialFeature(credentials, "CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN", "q");
23036
+ return import_client20.setCredentialFeature(credentials, "CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN", "q");
23037
23037
  };
23038
23038
  var init_resolveWebIdentityCredentials = __esm(() => {
23039
- import_client18 = __toESM(require_client2(), 1);
23039
+ import_client20 = __toESM(require_client2(), 1);
23040
23040
  });
23041
23041
 
23042
23042
  // ../../node_modules/.bun/@aws-sdk+credential-provider-ini@3.973.15/node_modules/@aws-sdk/credential-provider-ini/dist-es/resolveProfileData.js
@@ -23097,15 +23097,23 @@ var init_dist_es9 = __esm(() => {
23097
23097
  init_fromIni();
23098
23098
  });
23099
23099
 
23100
- // ../../node_modules/.bun/@hasna+events@0.1.16/node_modules/@hasna/events/dist/index.js
23100
+ // ../events/dist/index.js
23101
23101
  import { chmod, mkdir, readFile, rename, writeFile as writeFile2 } from "fs/promises";
23102
23102
  import { Buffer as Buffer2 } from "buffer";
23103
+ import { existsSync as existsSync22 } from "fs";
23104
+ import { join as join22 } from "path";
23103
23105
  import { existsSync as existsSync16 } from "fs";
23104
23106
  import { homedir as homedir5 } from "os";
23105
- import { join as join20 } from "path";
23107
+ import { join as join20, resolve as resolve3 } from "path";
23108
+ import { homedir as pathsResolverHomedir2 } from "os";
23109
+ import { join as pathsResolverJoin2 } from "path";
23106
23110
  import { createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
23111
+ import { lookup as dnsLookup } from "dns/promises";
23112
+ import { isIP as isIP2 } from "net";
23107
23113
  import { randomUUID as randomUUID5 } from "crypto";
23108
23114
  import { spawn } from "child_process";
23115
+ import { request as nodeHttpRequest } from "http";
23116
+ import { request as nodeHttpsRequest } from "https";
23109
23117
  import { randomUUID as randomUUID22 } from "crypto";
23110
23118
  function getPathValue(input, path) {
23111
23119
  return path.split(".").reduce((value, part) => {
@@ -23202,8 +23210,90 @@ function channelMatchesEvent(channel, event) {
23202
23210
  return true;
23203
23211
  return channel.filters.some((filter) => eventMatchesFilter(event, filter));
23204
23212
  }
23213
+ function pathsResolverAssertApp2(app) {
23214
+ if (typeof app !== "string" || app.length === 0) {
23215
+ throw new TypeError("paths: app must be a non-empty string");
23216
+ }
23217
+ if (!PATHS_RESOLVER_APP_SLUG_RE2.test(app)) {
23218
+ throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
23219
+ }
23220
+ }
23221
+ function pathsResolverAssertKind(kind) {
23222
+ if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
23223
+ throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
23224
+ }
23225
+ }
23226
+ function pathsResolverBaseDir(kind, options) {
23227
+ pathsResolverAssertKind(kind);
23228
+ const env = options.env ?? process.env;
23229
+ const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
23230
+ if (typeof override === "string" && override.length > 0)
23231
+ return override;
23232
+ const home = options.home ?? pathsResolverHomedir2();
23233
+ const platform = options.platform ?? process.platform;
23234
+ if (platform === "darwin") {
23235
+ switch (kind) {
23236
+ case "config":
23237
+ case "data":
23238
+ return pathsResolverJoin2(home, "Library", "Application Support", "Hasna");
23239
+ case "cache":
23240
+ return pathsResolverJoin2(home, "Library", "Caches", "Hasna");
23241
+ case "state":
23242
+ return pathsResolverJoin2(home, "Library", "Logs", "Hasna");
23243
+ }
23244
+ }
23245
+ switch (kind) {
23246
+ case "config":
23247
+ return pathsResolverJoin2(home, ".config", "hasna");
23248
+ case "data":
23249
+ return pathsResolverJoin2(home, ".local", "share", "hasna");
23250
+ case "state":
23251
+ return pathsResolverJoin2(home, ".local", "state", "hasna");
23252
+ case "cache":
23253
+ return pathsResolverJoin2(home, ".cache", "hasna");
23254
+ }
23255
+ }
23256
+ function pathsResolverResolve(kind, options) {
23257
+ pathsResolverAssertApp2(options.app);
23258
+ const appSegment = options.internal === true ? pathsResolverJoin2("internal", options.app) : options.app;
23259
+ return pathsResolverJoin2(pathsResolverBaseDir(kind, options), appSegment);
23260
+ }
23261
+ function dataDir2(options) {
23262
+ return pathsResolverResolve("data", options);
23263
+ }
23264
+ function effectiveHome2() {
23265
+ return process.env["HOME"] || process.env["USERPROFILE"] || homedir5();
23266
+ }
23267
+ function legacyHomeDir() {
23268
+ return join20(effectiveHome2(), ".hasna", "events");
23269
+ }
23270
+ function resolverHome() {
23271
+ return dataDir2({ app: "events", home: effectiveHome2() || undefined });
23272
+ }
23273
+ function adoptResolverHome(resolved, env = process.env) {
23274
+ const dataOverride = env.HASNA_DATA_HOME;
23275
+ if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
23276
+ return true;
23277
+ return existsSync16(join20(resolved, EVENTS_STORE_SENTINEL_FILE));
23278
+ }
23279
+ function exactEventsHome() {
23280
+ const dir = process.env[HASNA_EVENTS_DIR_ENV];
23281
+ if (dir && dir.trim())
23282
+ return dir.trim();
23283
+ const home = process.env[HASNA_EVENTS_HOME_ENV];
23284
+ if (home && home.trim())
23285
+ return home.trim();
23286
+ return;
23287
+ }
23288
+ function getEventsHome() {
23289
+ const exact = exactEventsHome();
23290
+ if (exact)
23291
+ return resolve3(exact);
23292
+ const resolved = resolverHome();
23293
+ return adoptResolverHome(resolved) ? resolve3(resolved) : resolve3(legacyHomeDir());
23294
+ }
23205
23295
  function getEventsDataDir(override) {
23206
- return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join20(homedir5(), ".hasna", "events");
23296
+ return override || getEventsHome();
23207
23297
  }
23208
23298
 
23209
23299
  class JsonEventsStore {
@@ -23212,12 +23302,12 @@ class JsonEventsStore {
23212
23302
  channelsPath;
23213
23303
  eventsPath;
23214
23304
  deliveriesPath;
23215
- constructor(dataDir2 = getEventsDataDir()) {
23216
- this.dataDir = dataDir2;
23217
- this.runtime = localJsonRuntime(dataDir2);
23218
- this.channelsPath = join20(dataDir2, "channels.json");
23219
- this.eventsPath = join20(dataDir2, "events.json");
23220
- this.deliveriesPath = join20(dataDir2, "deliveries.json");
23305
+ constructor(dataDir22 = getEventsDataDir()) {
23306
+ this.dataDir = dataDir22;
23307
+ this.runtime = localJsonRuntime(dataDir22);
23308
+ this.channelsPath = join22(dataDir22, "channels.json");
23309
+ this.eventsPath = join22(dataDir22, "events.json");
23310
+ this.deliveriesPath = join22(dataDir22, "deliveries.json");
23221
23311
  }
23222
23312
  async init() {
23223
23313
  await mkdir(this.dataDir, { recursive: true, mode: 448 });
@@ -23334,7 +23424,7 @@ class JsonEventsStore {
23334
23424
  };
23335
23425
  }
23336
23426
  async ensureArrayFile(path) {
23337
- if (!existsSync16(path)) {
23427
+ if (!existsSync22(path)) {
23338
23428
  await writeFile2(path, `[]
23339
23429
  `, { encoding: "utf-8", mode: 384 });
23340
23430
  }
@@ -23364,7 +23454,7 @@ class JsonEventsStore {
23364
23454
  });
23365
23455
  }
23366
23456
  }
23367
- function localJsonRuntime(dataDir2 = getEventsDataDir()) {
23457
+ function localJsonRuntime(dataDir22 = getEventsDataDir()) {
23368
23458
  return {
23369
23459
  mode: "local-files",
23370
23460
  name: "json-events-store",
@@ -23377,7 +23467,7 @@ function localJsonRuntime(dataDir2 = getEventsDataDir()) {
23377
23467
  durable: true,
23378
23468
  idempotency: "best-effort-local",
23379
23469
  replayCursors: true,
23380
- description: `Local JSON files in ${dataDir2}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
23470
+ description: `Local JSON files in ${dataDir22}; no SQLite, Postgres, S3, or AWS runtime is configured by this store.`
23381
23471
  };
23382
23472
  }
23383
23473
  function encodeLocalJsonEventCursor(offset, options = {}) {
@@ -23448,6 +23538,177 @@ function signPayload(secret, timestamp, body) {
23448
23538
  const digest2 = createHmac3("sha256", secret).update(buildSignatureBase(timestamp, body)).digest("hex");
23449
23539
  return `sha256=${digest2}`;
23450
23540
  }
23541
+ function isPrivateAddress(address) {
23542
+ const normalized = stripZoneId(address);
23543
+ const version2 = isIP2(normalized);
23544
+ if (version2 === 4) {
23545
+ const integer = ipv4ToInt(normalized);
23546
+ if (integer === undefined)
23547
+ return true;
23548
+ return IPV4_PRIVATE_RANGES.some(([low, high]) => integer >= low && integer <= high);
23549
+ }
23550
+ if (version2 === 6) {
23551
+ const groups = ipv6Groups(normalized);
23552
+ if (!groups)
23553
+ return true;
23554
+ for (const prefix of IPV6_SPECIAL_PREFIXES) {
23555
+ if (!ipv6MatchesPrefix(groups, prefix.groups, prefix.bits))
23556
+ continue;
23557
+ if (prefix.bits === 96 && groups[5] === 65535) {
23558
+ return isPrivateAddress(ipv4IntToString(groups[6] << 16 | groups[7]));
23559
+ }
23560
+ if (prefix.bits === 16 && groups[0] === 8194) {
23561
+ return isPrivateAddress(ipv4IntToString(groups[1] << 16 | groups[2]));
23562
+ }
23563
+ return true;
23564
+ }
23565
+ return false;
23566
+ }
23567
+ return true;
23568
+ }
23569
+ async function resolveWebhookTarget(url, policy = {}) {
23570
+ const hostname = normalizeHostname(url.hostname);
23571
+ const allowlist = (policy.allowPrivateHosts ?? []).map((entry) => normalizeHostname(entry.toLowerCase()));
23572
+ if (allowlist.includes(hostname)) {
23573
+ const version22 = isIP2(hostname);
23574
+ if (version22 === 4 || version22 === 6) {
23575
+ return { hostname, addresses: [hostname] };
23576
+ }
23577
+ const lookup2 = policy.lookup ?? defaultTargetLookup;
23578
+ let resolved2;
23579
+ try {
23580
+ resolved2 = await lookup2(hostname);
23581
+ } catch {
23582
+ throw new Error(`Webhook target ${hostname} could not be resolved`);
23583
+ }
23584
+ if (!Array.isArray(resolved2) || resolved2.length === 0) {
23585
+ throw new Error(`Webhook target ${hostname} resolved to no addresses`);
23586
+ }
23587
+ const addresses = resolved2.map((entry) => normalizeHostname(entry.address));
23588
+ return { hostname, addresses };
23589
+ }
23590
+ const version2 = isIP2(hostname);
23591
+ if (version2 === 4 || version2 === 6) {
23592
+ if (isPrivateAddress(hostname)) {
23593
+ throw new Error(`Webhook target ${hostname} is a private or special-use address`);
23594
+ }
23595
+ return { hostname, addresses: [hostname] };
23596
+ }
23597
+ const lookup = policy.lookup ?? defaultTargetLookup;
23598
+ let resolved;
23599
+ try {
23600
+ resolved = await lookup(hostname);
23601
+ } catch {
23602
+ throw new Error(`Webhook target ${hostname} could not be resolved`);
23603
+ }
23604
+ if (!Array.isArray(resolved) || resolved.length === 0) {
23605
+ throw new Error(`Webhook target ${hostname} resolved to no addresses`);
23606
+ }
23607
+ const allowed = [];
23608
+ for (const entry of resolved) {
23609
+ const address = normalizeHostname(entry.address);
23610
+ if (isPrivateAddress(address)) {
23611
+ if (allowlist.includes(address)) {
23612
+ allowed.push(address);
23613
+ continue;
23614
+ }
23615
+ throw new Error(`Webhook target ${hostname} resolves to private or special-use address ${address}`);
23616
+ }
23617
+ allowed.push(address);
23618
+ }
23619
+ if (allowed.length === 0) {
23620
+ throw new Error(`Webhook target ${hostname} resolved to no public addresses`);
23621
+ }
23622
+ return { hostname, addresses: allowed };
23623
+ }
23624
+ function normalizeMaxRedirects(value) {
23625
+ if (value === undefined)
23626
+ return DEFAULT_MAX_REDIRECTS;
23627
+ if (!Number.isInteger(value) || value < 0)
23628
+ throw new Error("webhookTargetPolicy.maxRedirects must be a non-negative integer");
23629
+ return value;
23630
+ }
23631
+ function normalizeHostname(hostname) {
23632
+ const lower = hostname.toLowerCase();
23633
+ if (lower.startsWith("[") && lower.endsWith("]"))
23634
+ return lower.slice(1, -1);
23635
+ return lower;
23636
+ }
23637
+ function stripZoneId(address) {
23638
+ const percent = address.indexOf("%");
23639
+ return percent === -1 ? address : address.slice(0, percent);
23640
+ }
23641
+ function ipv4ToInt(address) {
23642
+ const parts = address.split(".");
23643
+ if (parts.length !== 4)
23644
+ return;
23645
+ let value = 0;
23646
+ for (const part of parts) {
23647
+ if (!/^\d{1,3}$/.test(part))
23648
+ return;
23649
+ const octet = Number(part);
23650
+ if (octet > 255)
23651
+ return;
23652
+ value = value << 8 | octet;
23653
+ }
23654
+ return value >>> 0;
23655
+ }
23656
+ function ipv4IntToString(integer) {
23657
+ return [
23658
+ integer >>> 24 & 255,
23659
+ integer >>> 16 & 255,
23660
+ integer >>> 8 & 255,
23661
+ integer & 255
23662
+ ].join(".");
23663
+ }
23664
+ function ipv6Groups(address) {
23665
+ const raw = stripZoneId(address);
23666
+ const doubleColon = raw.indexOf("::");
23667
+ const headText = doubleColon === -1 ? raw : raw.slice(0, doubleColon);
23668
+ const tailText = doubleColon === -1 ? "" : raw.slice(doubleColon + 2);
23669
+ const parseGroups = (text) => {
23670
+ if (text === "")
23671
+ return [];
23672
+ const out = [];
23673
+ for (const part of text.split(":")) {
23674
+ if (part.includes(".")) {
23675
+ const v4 = ipv4ToInt(part);
23676
+ if (v4 === undefined)
23677
+ return;
23678
+ out.push(v4 >>> 16 & 65535, v4 & 65535);
23679
+ } else {
23680
+ if (!/^[0-9a-fA-F]{1,4}$/.test(part))
23681
+ return;
23682
+ out.push(parseInt(part, 16));
23683
+ }
23684
+ }
23685
+ return out;
23686
+ };
23687
+ const head = parseGroups(headText);
23688
+ if (!head)
23689
+ return;
23690
+ const tail = parseGroups(tailText);
23691
+ if (!tail)
23692
+ return;
23693
+ const total = head.length + tail.length;
23694
+ if (doubleColon === -1) {
23695
+ return total === 8 ? head : undefined;
23696
+ }
23697
+ if (total >= 8)
23698
+ return;
23699
+ return [...head, ...new Array(8 - total).fill(0), ...tail];
23700
+ }
23701
+ function ipv6MatchesPrefix(groups, prefixGroups, prefixBits) {
23702
+ let remaining = prefixBits;
23703
+ for (let index = 0;index < prefixGroups.length && remaining > 0; index += 1) {
23704
+ const take = Math.min(16, remaining);
23705
+ const mask = 65535 << 16 - take & 65535;
23706
+ if ((groups[index] & mask) !== (prefixGroups[index] & mask))
23707
+ return false;
23708
+ remaining -= take;
23709
+ }
23710
+ return true;
23711
+ }
23451
23712
  function now() {
23452
23713
  return new Date().toISOString();
23453
23714
  }
@@ -23478,9 +23739,18 @@ function buildWebhookRequest(event, channel, options = {}) {
23478
23739
  }
23479
23740
  return { body, headers };
23480
23741
  }
23742
+ function normalizeWebhookUrl(raw) {
23743
+ const url = new URL(raw);
23744
+ if (url.username !== "" || url.password !== "") {
23745
+ url.username = "";
23746
+ url.password = "";
23747
+ }
23748
+ return url.toString();
23749
+ }
23481
23750
  async function dispatchWebhook(event, channel, options = {}) {
23482
23751
  if (!channel.webhook)
23483
23752
  throw new Error(`Channel ${channel.id} has no webhook config`);
23753
+ const webhookUrl = normalizeWebhookUrl(channel.webhook.url);
23484
23754
  const startedAt = now();
23485
23755
  let secret = channel.webhook.secret;
23486
23756
  if (channel.webhook.secretRef) {
@@ -23497,10 +23767,14 @@ async function dispatchWebhook(event, channel, options = {}) {
23497
23767
  }
23498
23768
  const timestamp = (options.now?.() ?? new Date).toISOString();
23499
23769
  const { body, headers } = buildWebhookRequest(event, channel, { secret, timestamp });
23770
+ const validateTargets = options.webhookTargetPolicy !== undefined || options.fetchImpl === undefined;
23771
+ if (validateTargets) {
23772
+ return dispatchValidatedWebhook(event, channel, { body, headers, startedAt, options });
23773
+ }
23500
23774
  const controller = new AbortController;
23501
23775
  const timeout = setTimeout(() => controller.abort(), channel.webhook.timeoutMs ?? 15000);
23502
23776
  try {
23503
- const response = await (options.fetchImpl ?? fetch)(channel.webhook.url, {
23777
+ const response = await (options.fetchImpl ?? fetch)(webhookUrl, {
23504
23778
  method: "POST",
23505
23779
  headers,
23506
23780
  body,
@@ -23528,6 +23802,130 @@ async function dispatchWebhook(event, channel, options = {}) {
23528
23802
  clearTimeout(timeout);
23529
23803
  }
23530
23804
  }
23805
+ function isRedirectStatus(status) {
23806
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
23807
+ }
23808
+ function redirectKeepsBody(status) {
23809
+ return status === 307 || status === 308;
23810
+ }
23811
+ async function pinnedNativeRequest(target, addresses, method, headers, body, signal, tls) {
23812
+ const isHttps = target.protocol === "https:";
23813
+ if (!isHttps && target.protocol !== "http:") {
23814
+ throw new Error(`Webhook target uses unsupported protocol ${target.protocol}`);
23815
+ }
23816
+ const defaultPort = isHttps ? 443 : 80;
23817
+ const port = target.port ? Number(target.port) : defaultPort;
23818
+ const requestOptions = {
23819
+ hostname: target.hostname,
23820
+ port,
23821
+ path: `${target.pathname}${target.search}`,
23822
+ method,
23823
+ headers,
23824
+ ...tls?.ca ? { ca: tls.ca } : {},
23825
+ lookup: (hostname, _options, callback) => {
23826
+ const entries = addresses.map((address) => ({
23827
+ address,
23828
+ family: address.includes(":") ? 6 : 4
23829
+ }));
23830
+ callback(null, entries);
23831
+ }
23832
+ };
23833
+ return new Promise((resolve22, reject) => {
23834
+ const request = isHttps ? nodeHttpsRequest(requestOptions, onResponse) : nodeHttpRequest(requestOptions, onResponse);
23835
+ const onAbort = () => {
23836
+ const error = new Error("The operation was aborted.");
23837
+ error.name = "AbortError";
23838
+ request.destroy(error);
23839
+ };
23840
+ if (signal.aborted)
23841
+ onAbort();
23842
+ else
23843
+ signal.addEventListener("abort", onAbort, { once: true });
23844
+ request.on("error", reject);
23845
+ if (body !== undefined)
23846
+ request.write(body);
23847
+ request.end();
23848
+ function onResponse(response) {
23849
+ const chunks = [];
23850
+ response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
23851
+ response.on("error", reject);
23852
+ response.on("end", () => {
23853
+ const headersRecord = {};
23854
+ for (const [name, value] of Object.entries(response.headers)) {
23855
+ if (typeof value === "string")
23856
+ headersRecord[name] = value;
23857
+ else if (Array.isArray(value))
23858
+ headersRecord[name] = value.join(", ");
23859
+ }
23860
+ resolve22(new Response(Buffer.concat(chunks), { status: response.statusCode ?? 200, headers: headersRecord }));
23861
+ });
23862
+ }
23863
+ });
23864
+ }
23865
+ async function dispatchValidatedWebhook(event, channel, input) {
23866
+ const { body, headers, startedAt, options } = input;
23867
+ const webhook = channel.webhook;
23868
+ if (!webhook)
23869
+ throw new Error(`Channel ${channel.id} has no webhook config`);
23870
+ const policy = options.webhookTargetPolicy ?? {};
23871
+ const maxRedirects = normalizeMaxRedirects(policy.maxRedirects);
23872
+ const controller = new AbortController;
23873
+ const timeout = setTimeout(() => controller.abort(), webhook.timeoutMs ?? 15000);
23874
+ try {
23875
+ let target = new URL(normalizeWebhookUrl(webhook.url));
23876
+ let requestHeaders = headers;
23877
+ let method = "POST";
23878
+ let requestBody = body;
23879
+ let redirectsFollowed = 0;
23880
+ for (;; ) {
23881
+ const resolved = await resolveWebhookTarget(target, policy).catch((error) => {
23882
+ throw new Error(`Webhook target rejected by SSRF guard: ${error.message}`);
23883
+ });
23884
+ const response = options.fetchImpl ? await options.fetchImpl(target, {
23885
+ method,
23886
+ headers: requestHeaders,
23887
+ body: requestBody,
23888
+ signal: controller.signal,
23889
+ redirect: "manual"
23890
+ }) : await pinnedNativeRequest(target, resolved.addresses, method, requestHeaders, requestBody, controller.signal, options.tls);
23891
+ const location = response.headers.get("location");
23892
+ if (isRedirectStatus(response.status) && location) {
23893
+ if (redirectsFollowed >= maxRedirects) {
23894
+ return failedAttempt(startedAt, `Webhook target exceeded ${maxRedirects} redirects`);
23895
+ }
23896
+ redirectsFollowed += 1;
23897
+ const next = new URL(location, target);
23898
+ target = next;
23899
+ if (!redirectKeepsBody(response.status)) {
23900
+ method = "GET";
23901
+ requestBody = undefined;
23902
+ requestHeaders = Object.fromEntries(Object.entries(requestHeaders).filter(([name]) => name.toLowerCase() !== "content-type" && name.toLowerCase() !== "content-length"));
23903
+ }
23904
+ continue;
23905
+ }
23906
+ const responseBody = truncate(await response.text());
23907
+ return {
23908
+ attempt: 1,
23909
+ status: response.ok ? "success" : "failed",
23910
+ startedAt,
23911
+ completedAt: now(),
23912
+ responseStatus: response.status,
23913
+ responseBody,
23914
+ error: response.ok ? undefined : `Webhook returned HTTP ${response.status}`
23915
+ };
23916
+ }
23917
+ } catch (error) {
23918
+ return {
23919
+ attempt: 1,
23920
+ status: "failed",
23921
+ startedAt,
23922
+ completedAt: now(),
23923
+ error: error instanceof Error ? error.message : String(error)
23924
+ };
23925
+ } finally {
23926
+ clearTimeout(timeout);
23927
+ }
23928
+ }
23531
23929
  function failedAttempt(startedAt, error) {
23532
23930
  return {
23533
23931
  attempt: 1,
@@ -23556,7 +23954,7 @@ async function dispatchCommand(event, channel) {
23556
23954
  HASNA_EVENT_SCHEMA_VERSION: event.schemaVersion,
23557
23955
  HASNA_EVENT_JSON: eventJson
23558
23956
  };
23559
- return new Promise((resolve3) => {
23957
+ return new Promise((resolve22) => {
23560
23958
  const child = spawn(channel.command.command, channel.command.args ?? [], {
23561
23959
  cwd: channel.command.cwd,
23562
23960
  env,
@@ -23574,7 +23972,7 @@ async function dispatchCommand(event, channel) {
23574
23972
  });
23575
23973
  child.on("error", (error) => {
23576
23974
  clearTimeout(timeout);
23577
- resolve3({
23975
+ resolve22({
23578
23976
  attempt: 1,
23579
23977
  status: "failed",
23580
23978
  startedAt,
@@ -23587,7 +23985,7 @@ async function dispatchCommand(event, channel) {
23587
23985
  child.on("close", (code, signal) => {
23588
23986
  clearTimeout(timeout);
23589
23987
  const success = code === 0;
23590
- resolve3({
23988
+ resolve22({
23591
23989
  attempt: 1,
23592
23990
  status: success ? "success" : "failed",
23593
23991
  startedAt,
@@ -23723,7 +24121,9 @@ class EventsClient {
23723
24121
  this.transportOptions = {
23724
24122
  fetchImpl: options.fetchImpl,
23725
24123
  secretResolver: options.secretResolver,
23726
- now: options.now
24124
+ now: options.now,
24125
+ tls: options.tls,
24126
+ webhookTargetPolicy: options.webhookTargetPolicy
23727
24127
  };
23728
24128
  this.catalog = options.catalog ?? defaultEventTypeCatalog;
23729
24129
  this.validateCatalogTypes = options.validateCatalogTypes ?? false;
@@ -23928,9 +24328,51 @@ function normalizeRetryPolicy(policy) {
23928
24328
  multiplier: Math.max(1, policy?.multiplier ?? 2)
23929
24329
  };
23930
24330
  }
23931
- var HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR", HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME", LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:", DEFAULT_EVENT_PAGE_LIMIT = 100, MAX_EVENT_PAGE_LIMIT = 1000, DEFAULT_SIGNATURE_TOLERANCE_MS, EventValidationError, defaultEventTypeCatalog, APP_EVENT_V1_MAX_DATA_BYTES;
24331
+ var PATHS_RESOLVER_KIND_ENV, PATHS_RESOLVER_APP_SLUG_RE2, HASNA_EVENTS_DIR_ENV = "HASNA_EVENTS_DIR", HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME", EVENTS_STORE_SENTINEL_FILE = "events.json", LOCAL_JSON_EVENT_CURSOR_PREFIX = "local-json-v1:", DEFAULT_EVENT_PAGE_LIMIT = 100, MAX_EVENT_PAGE_LIMIT = 1000, DEFAULT_SIGNATURE_TOLERANCE_MS, DEFAULT_MAX_REDIRECTS = 5, IPV4_PRIVATE_RANGES, IPV6_SPECIAL_PREFIXES, defaultTargetLookup = async (hostname) => {
24332
+ return dnsLookup(hostname, { all: true, verbatim: false });
24333
+ }, EventValidationError, defaultEventTypeCatalog, APP_EVENT_V1_MAX_DATA_BYTES;
23932
24334
  var init_dist = __esm(() => {
24335
+ PATHS_RESOLVER_KIND_ENV = {
24336
+ config: "HASNA_CONFIG_HOME",
24337
+ data: "HASNA_DATA_HOME",
24338
+ state: "HASNA_STATE_HOME",
24339
+ cache: "HASNA_CACHE_HOME"
24340
+ };
24341
+ PATHS_RESOLVER_APP_SLUG_RE2 = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
23933
24342
  DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
24343
+ IPV4_PRIVATE_RANGES = [
24344
+ [0, 16777215],
24345
+ [167772160, 184549375],
24346
+ [1681915904, 1686110207],
24347
+ [2130706432, 2147483647],
24348
+ [2851995648, 2852061183],
24349
+ [2886729728, 2887778303],
24350
+ [3221225472, 3221225727],
24351
+ [3221225984, 3221226239],
24352
+ [3227017984, 3227018239],
24353
+ [3232235520, 3232301055],
24354
+ [3323068416, 3323199487],
24355
+ [3325256704, 3325256959],
24356
+ [3405803776, 3405804031],
24357
+ [3758096384, 4294967295]
24358
+ ];
24359
+ IPV6_SPECIAL_PREFIXES = [
24360
+ { groups: [0, 0, 0, 0, 0, 0, 0, 0], bits: 128 },
24361
+ { groups: [0, 0, 0, 0, 0, 0, 0, 1], bits: 128 },
24362
+ { groups: [0, 0, 0, 0, 0, 65535, 0, 0], bits: 96 },
24363
+ { groups: [100, 65435, 0, 0, 0, 0, 0, 0], bits: 96 },
24364
+ { groups: [256, 0, 0, 0, 0, 0, 0, 0], bits: 64 },
24365
+ { groups: [8193, 0, 0, 0, 0, 0, 0, 0], bits: 32 },
24366
+ { groups: [8193, 2, 0, 0, 0, 0, 0, 0], bits: 48 },
24367
+ { groups: [8193, 16, 0, 0, 0, 0, 0, 0], bits: 28 },
24368
+ { groups: [8193, 3512, 0, 0, 0, 0, 0, 0], bits: 32 },
24369
+ { groups: [8194, 0, 0, 0, 0, 0, 0, 0], bits: 16 },
24370
+ { groups: [16383, 0, 0, 0, 0, 0, 0, 0], bits: 20 },
24371
+ { groups: [64512, 0, 0, 0, 0, 0, 0, 0], bits: 7 },
24372
+ { groups: [65152, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
24373
+ { groups: [65216, 0, 0, 0, 0, 0, 0, 0], bits: 10 },
24374
+ { groups: [65280, 0, 0, 0, 0, 0, 0, 0], bits: 8 }
24375
+ ];
23934
24376
  EventValidationError = class EventValidationError extends Error {
23935
24377
  eventType;
23936
24378
  issues;
@@ -24525,7 +24967,6 @@ async function completePointerCredential(name, pointerResolution, env = process.
24525
24967
  });
24526
24968
  }
24527
24969
  var DEFAULT_FLEET_GATEWAY_ORIGIN = "https://api.hasna.com";
24528
- var DEFAULT_AUTHORITY_SOURCE = "default";
24529
24970
  function defaultFleetGatewayBaseUrl(name) {
24530
24971
  return `${DEFAULT_FLEET_GATEWAY_ORIGIN}/${validateAppSlug(name)}`;
24531
24972
  }
@@ -24644,110 +25085,124 @@ function toV1BaseUrl(apiUrl) {
24644
25085
  url.pathname = `${path}/v1`;
24645
25086
  return url.toString().replace(/\/+$/, "");
24646
25087
  }
24647
- class ClientTransportConfigurationError extends Error {
24648
- appName;
24649
- sources;
24650
- constructor(appName, message, sources = []) {
24651
- super(message);
24652
- this.name = "ClientTransportConfigurationError";
24653
- this.appName = appName;
24654
- this.sources = Object.freeze([...sources]);
24655
- }
25088
+ var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
25089
+ var AUTHORITY_OVERRIDE_HEADERS = new Set([
25090
+ "host",
25091
+ ":authority",
25092
+ "forwarded",
25093
+ "x-forwarded-host",
25094
+ "x-original-host"
25095
+ ]);
25096
+
25097
+ // src/lib/instance-credentials.ts
25098
+ import { closeSync as closeSync2, constants, fstatSync as fstatSync2, lstatSync, openSync as openSync2, readSync } from "fs";
25099
+ var SKILLS_BOUND_API_URL = "HASNA_SKILLS_BOUND_API_URL";
25100
+ function selectedSkillsProfile(env, explicit) {
25101
+ const selected = explicit ?? env.HASNA_PROFILE;
25102
+ if (selected === undefined)
25103
+ return null;
25104
+ const profile = selected.trim();
25105
+ if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(profile))
25106
+ throw new Error("Invalid Skills credential profile");
25107
+ return profile;
24656
25108
  }
24657
- function resolveClientTransportSnapshot(name, env = process.env, options = {}) {
24658
- env = snapshotClientEnvironment(name, env);
24659
- const keys = clientTransportEnvKeys(name);
24660
- const definedUrlEntries = keys.apiUrlKeys.filter((key) => Object.prototype.hasOwnProperty.call(env, key) && env[key] !== undefined).map((key) => ({ key, raw: String(env[key]) }));
24661
- const blankUrl = definedUrlEntries.find((entry) => entry.raw.trim().length === 0);
24662
- if (blankUrl) {
24663
- 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]);
24664
- }
24665
- const controlledUrl = definedUrlEntries.find((entry) => ASCII_CONTROL_PATTERN.test(entry.raw));
24666
- if (controlledUrl) {
24667
- throw new ClientTransportConfigurationError(name, `${controlledUrl.key} contains ASCII control characters.`, [controlledUrl.key]);
24668
- }
24669
- const usableUrlEntries = definedUrlEntries.map((entry) => ({ key: entry.key, value: entry.raw.trim() }));
24670
- if (usableUrlEntries.length > 1 && new Set(usableUrlEntries.map((entry) => entry.value)).size > 1) {
24671
- 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));
24672
- }
24673
- const envUrlHit = usableUrlEntries[0] ?? null;
24674
- const keychainUrlHit = keychainConfigValue(name, env, options.credentials?.keychain);
24675
- const diskConfigUrlHit = appConfigDiskValue(name, env, keys.apiUrlKeys);
24676
- if (diskConfigUrlHit?.unusable) {
24677
- 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]);
24678
- }
24679
- const urlCandidates = [
24680
- ...envUrlHit ? [envUrlHit] : [],
24681
- ...keychainUrlHit ? [{ key: keychainUrlHit.source, value: keychainUrlHit.value }] : [],
24682
- ...diskConfigUrlHit ? [{ key: diskConfigUrlHit.path, value: diskConfigUrlHit.value.trim() }] : []
24683
- ];
24684
- const configuredUrl = urlCandidates[0] ?? null;
24685
- const divergentUrls = urlCandidates.filter((candidate) => candidate.value !== configuredUrl?.value);
24686
- if (configuredUrl && divergentUrls.length > 0) {
24687
- 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));
24688
- }
24689
- const warnings = [];
24690
- if (configuredUrl && !envUrlHit) {
24691
- warnings.push(`No ${keys.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.`);
25109
+ function skillsProfileCredentialFiles(env, explicit) {
25110
+ return credentialDiskSourceList("skills", env, selectedSkillsProfile(env, explicit)).map((source) => source.path);
25111
+ }
25112
+ function fileIdentity(file) {
25113
+ try {
25114
+ return lstatSync(file);
25115
+ } catch (error) {
25116
+ if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
25117
+ return null;
25118
+ throw new Error("Cannot inspect Skills instance configuration");
24692
25119
  }
24693
- const credential = resolveCredential(name, env, options.credentials);
24694
- if (!credential) {
24695
- const diskHint = credentialDiskSourcesForMessage(name, env);
24696
- const lead = configuredUrl ? `${configuredUrl.key} selects the HTTP server for '${name}', but no API key could be resolved` : `${keys.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`;
24697
- 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 ${keys.apiKeyKeys[0]} in the environment.`);
24698
- throw new ClientTransportConfigurationError(name, warnings.join(" "), [configuredUrl?.key ?? keys.apiUrlKeys[0]]);
24699
- }
24700
- if (credential.warning)
24701
- warnings.push(credential.warning);
24702
- let urlHit;
24703
- if (configuredUrl) {
24704
- urlHit = configuredUrl;
24705
- } else {
24706
- try {
24707
- urlHit = { key: DEFAULT_AUTHORITY_SOURCE, value: defaultFleetGatewayBaseUrl(name) };
24708
- } catch (error) {
24709
- const message = error instanceof Error ? error.message : String(error);
24710
- throw new ClientTransportConfigurationError(name, `No ${keys.apiUrlKeys[0]} is configured and the default fleet gateway authority cannot be composed for '${name}': ${message}`, [keys.apiUrlKeys[0]]);
25120
+ }
25121
+ function unchanged(before, after) {
25122
+ return before === null || after === null ? before === after : ["dev", "ino", "size", "mtimeMs", "ctimeMs", "mode", "uid"].every((key) => before[key] === after[key]);
25123
+ }
25124
+ function captureSkillsCredentialFiles(files) {
25125
+ const identities = files.map((file) => [file, fileIdentity(file)]);
25126
+ return () => {
25127
+ if (identities.some(([file, before]) => !unchanged(before, fileIdentity(file)))) {
25128
+ throw new Error("Skills instance configuration changed while resolving credentials; retry without sending a credential");
24711
25129
  }
24712
- }
24713
- const apiUrlSource = urlHit.key;
24714
- let baseUrl;
25130
+ };
25131
+ }
25132
+ function readMetadataText(file) {
25133
+ let fd;
24715
25134
  try {
24716
- baseUrl = toV1BaseUrl(urlHit.value);
25135
+ fd = openSync2(file, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
24717
25136
  } catch (error) {
24718
- const message = error instanceof Error ? error.message : String(error);
24719
- throw new ClientTransportConfigurationError(name, `Invalid API URL from ${apiUrlSource}: ${message}`, [apiUrlSource]);
25137
+ if (["ENOENT", "ENOTDIR"].includes(error.code ?? ""))
25138
+ return null;
25139
+ throw new Error("Cannot safely read Skills instance configuration");
25140
+ }
25141
+ try {
25142
+ const before = fstatSync2(fd);
25143
+ const uid = process.getuid?.() ?? process.geteuid?.();
25144
+ if (!before.isFile() || ![256, 384].includes(before.mode & 4095) || uid !== undefined && before.uid !== uid || before.size > 64 * 1024) {
25145
+ throw new Error("Unsafe Skills instance configuration; expected a bounded owner-only regular file");
25146
+ }
25147
+ const bytes = Buffer.alloc(64 * 1024 + 1);
25148
+ let length = 0;
25149
+ while (length < bytes.length) {
25150
+ const count = readSync(fd, bytes, length, bytes.length - length, null);
25151
+ if (!count)
25152
+ break;
25153
+ length += count;
25154
+ }
25155
+ if (length > 64 * 1024 || !unchanged(before, fstatSync2(fd)) || !unchanged(before, fileIdentity(file))) {
25156
+ throw new Error("Skills instance configuration changed while reading");
25157
+ }
25158
+ return bytes.subarray(0, length).toString("utf8");
25159
+ } finally {
25160
+ closeSync2(fd);
24720
25161
  }
24721
- return {
24722
- resolution: {
24723
- transport: "http",
24724
- transportSource: urlHit.key,
24725
- baseUrl,
24726
- apiUrlSource,
24727
- apiKeyPresent: true,
24728
- apiKeySource: credential.source,
24729
- apiKeyTier: credential.tier,
24730
- misconfigured: false,
24731
- warning: warnings.length > 0 ? warnings.join(" ") : null
24732
- },
24733
- credential
24734
- };
24735
25162
  }
24736
- function resolveClientTransport(name, env = process.env, options = {}) {
24737
- return resolveClientTransportSnapshot(name, env, options).resolution;
25163
+ function readSkillsInstanceMetadata(file) {
25164
+ const text = readMetadataText(file);
25165
+ if (text === null)
25166
+ return {};
25167
+ const values = new Map;
25168
+ for (const line of text.split(/\r?\n/)) {
25169
+ const match = /^\s*(?:export\s+)?(HASNA_SKILLS_API_URL|SKILLS_API_URL|HASNA_SKILLS_BOUND_API_URL)\s*=\s*(.*)$/.exec(line);
25170
+ if (!match)
25171
+ continue;
25172
+ let value = match[2].trim();
25173
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))
25174
+ value = value.slice(1, -1);
25175
+ if (!value || /[\x00-\x20\x7f]/.test(value) || values.has(match[1]))
25176
+ throw new Error("Invalid Skills instance configuration");
25177
+ values.set(match[1], value);
25178
+ }
25179
+ const urls = [values.get("HASNA_SKILLS_API_URL"), values.get("SKILLS_API_URL")].filter(Boolean);
25180
+ if (new Set(urls).size > 1)
25181
+ throw new Error("Skills API URL aliases disagree");
25182
+ return { apiUrl: urls[0], binding: values.get(SKILLS_BOUND_API_URL) };
24738
25183
  }
24739
- function credentialDiskSourcesForMessage(name, env) {
24740
- const paths = credentialDiskSources(name, env);
24741
- return paths.length > 0 ? paths.join(" or ") : "<no HOME or HASNA_HOME set in this environment, so no credential file was consulted>";
25184
+
25185
+ // src/lib/local-opt-in.ts
25186
+ var SKILLS_LOCAL_OPT_IN_ENV_KEYS = ["HASNA_SKILLS_LOCAL", "SKILLS_LOCAL"];
25187
+ function isSkillsLocalOptIn(env = process.env) {
25188
+ return SKILLS_LOCAL_OPT_IN_ENV_KEYS.some((key) => (env[key] ?? "").trim() !== "");
25189
+ }
25190
+ function skillsAuthorityEnvKeys() {
25191
+ const keys = clientTransportEnvKeys("skills");
25192
+ return [
25193
+ ...keys.apiUrlKeys,
25194
+ ...keys.apiKeyKeys,
25195
+ credentialOverrideEnvKey("skills"),
25196
+ credentialPointerEnvKey("skills"),
25197
+ CREDENTIAL_PROFILE_ENV_KEY
25198
+ ];
25199
+ }
25200
+ function hasSkillsEnvAuthorityIntent(env = process.env) {
25201
+ return skillsAuthorityEnvKeys().some((key) => (env[key] ?? "").trim() !== "");
25202
+ }
25203
+ function selectsSkillsLocalMode(env = process.env) {
25204
+ return !hasSkillsEnvAuthorityIntent(env) && isSkillsLocalOptIn(env);
24742
25205
  }
24743
- var IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
24744
- var AUTHORITY_OVERRIDE_HEADERS = new Set([
24745
- "host",
24746
- ":authority",
24747
- "forwarded",
24748
- "x-forwarded-host",
24749
- "x-original-host"
24750
- ]);
24751
25206
 
24752
25207
  // src/lib/fleet-credentials.ts
24753
25208
  var SKILLS_APP = "skills";
@@ -24765,12 +25220,12 @@ class SkillsFleetCredentialError extends Error {
24765
25220
  this.code = code;
24766
25221
  }
24767
25222
  }
24768
- function isClientTransportConfigurationError(error) {
24769
- return error instanceof ClientTransportConfigurationError || typeof error === "object" && error !== null && error.name === "ClientTransportConfigurationError";
24770
- }
24771
25223
  function isCredentialResolutionError(error) {
24772
25224
  return error instanceof CredentialResolutionError || typeof error === "object" && error !== null && error.name === "CredentialResolutionError";
24773
25225
  }
25226
+ function isSkillsFleetCredentialError(error) {
25227
+ return error instanceof SkillsFleetCredentialError || typeof error === "object" && error !== null && error.name === "SkillsFleetCredentialError";
25228
+ }
24774
25229
  function asSkillsFleetCredentialError(error) {
24775
25230
  if (!isCredentialResolutionError(error))
24776
25231
  return null;
@@ -24778,6 +25233,9 @@ function asSkillsFleetCredentialError(error) {
24778
25233
  }
24779
25234
  function normalizeSkillsApiOrigin(apiUrl) {
24780
25235
  const url = new URL(apiUrl);
25236
+ if (url.username || url.password || url.search || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname))) {
25237
+ throw new SkillsFleetCredentialError("A Skills API URL must use HTTPS (or loopback HTTP), without credentials, query or fragment", "INVALID_API_URL");
25238
+ }
24781
25239
  const pathname = url.pathname.replace(/\/+$/, "");
24782
25240
  if (pathname === "/api" || pathname === "/api/v1") {
24783
25241
  url.pathname = "/";
@@ -24788,11 +25246,24 @@ function normalizeSkillsApiOrigin(apiUrl) {
24788
25246
  }
24789
25247
  return url.toString().replace(/\/+$/, "");
24790
25248
  }
24791
- function configuredSkillsApiUrl(env = process.env, keychain) {
24792
- for (const key of SKILLS_API_URL_ENV_KEYS) {
24793
- const value = env[key]?.trim();
24794
- if (value)
24795
- return { value, source: key };
25249
+ function configuredSkillsApiUrl(env = process.env, keychain, profile) {
25250
+ const declared = SKILLS_API_URL_ENV_KEYS.filter((key) => env[key] !== undefined).map((key) => ({ key, value: env[key] }));
25251
+ for (const entry of declared) {
25252
+ if (!entry.value.trim() || /[\x00-\x1f\x7f]/.test(entry.value))
25253
+ throw new SkillsFleetCredentialError(`${entry.key} is blank or contains control characters`, "INVALID_API_URL");
25254
+ }
25255
+ const normalized = declared.map((entry) => ({ value: normalizeSkillsApiOrigin(entry.value), source: entry.key }));
25256
+ if (new Set(normalized.map((entry) => entry.value)).size > 1)
25257
+ throw new SkillsFleetCredentialError("Skills API URL aliases disagree", "INVALID_API_URL");
25258
+ if (normalized[0])
25259
+ return normalized[0];
25260
+ if (selectedSkillsProfile(env, profile)) {
25261
+ for (const file of skillsProfileCredentialFiles(env, profile)) {
25262
+ const metadata = readSkillsInstanceMetadata(file);
25263
+ if (metadata.apiUrl || metadata.binding)
25264
+ return { value: metadata.apiUrl ?? metadata.binding, source: file };
25265
+ }
25266
+ return { value: defaultFleetGatewayBaseUrl(SKILLS_APP), source: "default" };
24796
25267
  }
24797
25268
  const fromKeychain = keychainConfigValue(SKILLS_APP, env, keychain);
24798
25269
  if (fromKeychain)
@@ -24806,7 +25277,7 @@ function configuredSkillsApiUrl(env = process.env, keychain) {
24806
25277
  return null;
24807
25278
  }
24808
25279
  function skillsCredentialFiles(env = process.env) {
24809
- return credentialDiskSources(SKILLS_APP, env);
25280
+ return skillsProfileCredentialFiles(env);
24810
25281
  }
24811
25282
  function skillsCredentialFilePath(env = process.env) {
24812
25283
  const paths = skillsCredentialFiles(env);
@@ -24821,11 +25292,15 @@ function noticeLocalSkillsMode(write = (line) => console.error(line)) {
24821
25292
  if (localNoticePrinted)
24822
25293
  return;
24823
25294
  localNoticePrinted = true;
24824
- write(`skills: local mode \u2014 no ${SKILLS_API_KEY_ENV} and no ${SKILLS_API_URL_ENV} resolved, ` + `so this runs on this machine against the bundled corpus. ` + `Sign in with: skills auth login`);
25295
+ write(`skills: local mode (${SKILLS_LOCAL_OPT_IN_ENV_KEYS[0]}=1) \u2014 running on this machine against the bundled corpus.`);
24825
25296
  }
24826
25297
  function resolveSkillsFleet(env = process.env, options = {}) {
24827
25298
  try {
24828
- return resolveSkillsFleetOrThrow(env, options);
25299
+ const snapshot = snapshotSkillsEnvironment(env);
25300
+ const resolved = resolveSkillsFleetOrThrow(snapshot, snapshotSkillsOptions(env, options));
25301
+ if (resolved.mode === "local" && env === process.env)
25302
+ noticeLocalSkillsMode();
25303
+ return resolved;
24829
25304
  } catch (error) {
24830
25305
  const translated = asSkillsFleetCredentialError(error);
24831
25306
  if (translated)
@@ -24833,38 +25308,49 @@ function resolveSkillsFleet(env = process.env, options = {}) {
24833
25308
  throw error;
24834
25309
  }
24835
25310
  }
24836
- function resolveSkillsFleetOrThrow(env, options) {
24837
- let resolution;
24838
- try {
24839
- resolution = resolveClientTransport(SKILLS_APP, env, { credentials: options.credentials });
24840
- } catch (error) {
24841
- if (!isClientTransportConfigurationError(error))
24842
- throw error;
24843
- const configured2 = configuredSkillsApiUrl(env, options.credentials?.keychain);
24844
- const credential2 = resolveCredential(SKILLS_APP, env, options.credentials);
24845
- if (!configured2 && !credential2) {
24846
- if (env === process.env)
24847
- noticeLocalSkillsMode();
24848
- return { mode: "local", apiOrigin: null, apiKey: null };
24849
- }
24850
- if (configured2 && !credential2) {
24851
- 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(env).join(" or ") || "no credentials file (no HOME)"}, ` + `then ${SKILLS_API_KEY_ENV}. Sign in with: skills auth login`);
25311
+ function snapshotSkillsEnvironment(env) {
25312
+ const snapshot = {};
25313
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(env))) {
25314
+ if (!("value" in descriptor)) {
25315
+ if (/^(?:HASNA_|SKILLS_|HOME$|USER$)/.test(key))
25316
+ throw new SkillsFleetCredentialError("Accessor-backed Skills configuration is unsupported");
25317
+ continue;
24852
25318
  }
24853
- throw error;
25319
+ snapshot[key] = descriptor.value;
24854
25320
  }
24855
- const configured = configuredSkillsApiUrl(env, options.credentials?.keychain);
24856
- const apiOrigin = configured ? normalizeSkillsApiOrigin(configured.value) : stripV1(resolution.baseUrl);
25321
+ return Object.freeze(snapshot);
25322
+ }
25323
+ function snapshotSkillsOptions(env, options) {
25324
+ if (env !== process.env)
25325
+ return options;
25326
+ return { ...options, credentials: { ...options.credentials, keychain: {
25327
+ ...options.credentials?.keychain,
25328
+ enabled: options.credentials?.keychain?.enabled ?? true
25329
+ } } };
25330
+ }
25331
+ function resolveSkillsFleetOrThrow(env, options) {
25332
+ if (selectsSkillsLocalMode(env))
25333
+ return { mode: "local", apiOrigin: null, apiKey: null };
25334
+ const assertFilesUnchanged = captureSkillsCredentialFiles(skillsProfileCredentialFiles(env, options.credentials?.profile));
25335
+ const configured = configuredSkillsApiUrl(env, options.credentials?.keychain, options.credentials?.profile);
24857
25336
  const credential = resolveCredential(SKILLS_APP, env, options.credentials);
24858
25337
  if (!credential) {
24859
- throw new SkillsFleetCredentialError(`A Skills authority resolved but no API key did. Sign in with: skills auth login`);
25338
+ if (!configured) {
25339
+ throw new SkillsFleetCredentialError(`No API key resolved and no Skills API URL is configured \u2014 failing closed ` + `(local mode is opt-in only: set ${SKILLS_LOCAL_OPT_IN_ENV_KEYS[0]}=1 to run on this machine). ` + `Looked in ${credentialLocations(env)}. Sign in with: skills auth login`);
25340
+ }
25341
+ 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 ${credentialLocations(env)}. Sign in with: skills auth login`);
24860
25342
  }
25343
+ const apiOrigin = normalizeSkillsApiOrigin(configured?.value ?? defaultFleetGatewayBaseUrl(SKILLS_APP));
25344
+ toV1BaseUrl(apiOrigin);
25345
+ assertCredentialInstance(credential, apiOrigin, env, options);
25346
+ assertFilesUnchanged();
24861
25347
  const base = {
24862
25348
  mode: "hosted",
24863
25349
  apiOrigin,
24864
- apiUrlSource: resolution.apiUrlSource ?? (configured?.source ?? "default"),
24865
- apiKeySource: resolution.apiKeySource ?? credential.source,
24866
- apiKeyTier: resolution.apiKeyTier,
24867
- warning: resolution.warning
25350
+ apiUrlSource: configured?.source ?? "default",
25351
+ apiKeySource: credential.source,
25352
+ apiKeyTier: credential.tier,
25353
+ warning: credential.warning
24868
25354
  };
24869
25355
  if (credential.tier === "pointer") {
24870
25356
  return { ...base, apiKey: null, apiKeyPointer: credential };
@@ -24874,19 +25360,41 @@ function resolveSkillsFleetOrThrow(env, options) {
24874
25360
  }
24875
25361
  return { ...base, apiKey: credential.apiKey, apiKeyPointer: null };
24876
25362
  }
25363
+ function credentialLocations(env) {
25364
+ const files = skillsCredentialFiles(env).join(" or ") || "no credentials file (HOME is unset)";
25365
+ return `hasna.credentials.${SKILLS_APP}.api-key (macOS Keychain, account HASNA_STATION or the host name), ${files}, and ${SKILLS_API_KEY_ENV}`;
25366
+ }
25367
+ function assertCredentialInstance(credential, apiOrigin, env, options) {
25368
+ let bound;
25369
+ if (credential.tier === "disk" || credential.tier === "profile") {
25370
+ const metadata = readSkillsInstanceMetadata(credential.source);
25371
+ bound = metadata.binding ?? metadata.apiUrl ?? defaultFleetGatewayBaseUrl(SKILLS_APP);
25372
+ } else if (credential.tier === "keychain") {
25373
+ bound = keychainConfigValue(SKILLS_APP, env, options.credentials?.keychain)?.value ?? defaultFleetGatewayBaseUrl(SKILLS_APP);
25374
+ }
25375
+ if (bound && normalizeSkillsApiOrigin(bound) !== apiOrigin) {
25376
+ 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");
25377
+ }
25378
+ }
24877
25379
  async function resolveSkillsApiKey(env = process.env, options = {}) {
24878
- const fleet = resolveSkillsFleet(env, options);
25380
+ return (await resolveSkillsConnection(env, options))?.apiKey ?? null;
25381
+ }
25382
+ async function resolveSkillsConnection(env = process.env, options = {}) {
25383
+ const snapshotEnv = snapshotSkillsEnvironment(env);
25384
+ const fleet = resolveSkillsFleet(snapshotEnv, snapshotSkillsOptions(env, options));
25385
+ if (fleet.mode === "local" && env === process.env)
25386
+ noticeLocalSkillsMode();
24879
25387
  if (fleet.mode !== "hosted")
24880
25388
  return null;
24881
25389
  if (fleet.apiKey)
24882
- return fleet.apiKey;
25390
+ return { ...fleet, apiKey: fleet.apiKey };
24883
25391
  const pointer = fleet.apiKeyPointer;
24884
25392
  if (!pointer) {
24885
25393
  throw new SkillsFleetCredentialError(`A Skills authority resolved but no API key did. Sign in with: skills auth login`);
24886
25394
  }
24887
25395
  let completed;
24888
25396
  try {
24889
- completed = await completePointerCredential(SKILLS_APP, pointer, env);
25397
+ completed = await completePointerCredential(SKILLS_APP, pointer, snapshotEnv);
24890
25398
  } catch (error) {
24891
25399
  const translated = asSkillsFleetCredentialError(error);
24892
25400
  if (translated)
@@ -24896,7 +25404,7 @@ async function resolveSkillsApiKey(env = process.env, options = {}) {
24896
25404
  if (!completed.apiKey?.trim()) {
24897
25405
  throw new SkillsFleetCredentialError(`${credentialPointerEnvKey(SKILLS_APP)} names a vault item that produced an empty Skills API key \u2014 ` + `refusing to send an unauthenticated request.`);
24898
25406
  }
24899
- return completed.apiKey;
25407
+ return { ...fleet, apiKey: completed.apiKey, apiKeyPointer: null };
24900
25408
  }
24901
25409
  async function requireSkillsApiKey(action = "This command", env = process.env, options = {}) {
24902
25410
  const apiKey = await resolveSkillsApiKey(env, options);
@@ -24904,27 +25412,31 @@ async function requireSkillsApiKey(action = "This command", env = process.env, o
24904
25412
  throw new MissingSkillsFleetError(action);
24905
25413
  return apiKey;
24906
25414
  }
24907
- function stripV1(baseUrl) {
24908
- return baseUrl.replace(/\/v1$/, "").replace(/\/+$/, "");
24909
- }
24910
25415
  async function skillsCredentialOrReason(env = process.env, options = {}) {
24911
25416
  try {
24912
- const apiKey = await resolveSkillsApiKey(env, options);
24913
- return apiKey ? { apiKey, reason: null } : { apiKey: null, reason: null };
25417
+ const connection = await resolveSkillsConnection(env, options);
25418
+ return connection ? { apiKey: connection.apiKey, apiOrigin: connection.apiOrigin, reason: null } : { apiKey: null, apiOrigin: null, reason: null };
24914
25419
  } catch (error) {
24915
- if (error instanceof SkillsFleetCredentialError || error?.name === "SkillsFleetCredentialError") {
24916
- return { apiKey: null, reason: error.message };
25420
+ if (isSkillsFleetCredentialError(error)) {
25421
+ return { apiKey: null, apiOrigin: null, reason: error.message };
24917
25422
  }
24918
25423
  throw error;
24919
25424
  }
24920
25425
  }
24921
25426
  function resolveSkillsApiOrigin(env = process.env, options = {}) {
24922
- const configured = configuredSkillsApiUrl(env, options.credentials?.keychain);
25427
+ const configured = configuredSkillsApiUrl(env, options.credentials?.keychain, options.credentials?.profile);
24923
25428
  if (configured) {
24924
25429
  toV1BaseUrl(configured.value);
24925
25430
  return { origin: normalizeSkillsApiOrigin(configured.value), source: configured.source };
24926
25431
  }
24927
- const fleet = resolveSkillsFleet(env, options);
25432
+ let fleet;
25433
+ try {
25434
+ fleet = resolveSkillsFleet(env, options);
25435
+ } catch (error) {
25436
+ if (isSkillsFleetCredentialError(error))
25437
+ return null;
25438
+ throw error;
25439
+ }
24928
25440
  return fleet.mode === "hosted" ? { origin: fleet.apiOrigin, source: fleet.apiUrlSource } : null;
24929
25441
  }
24930
25442
  function requireSkillsApiOrigin(action = "This command", env = process.env, options = {}) {
@@ -24950,7 +25462,7 @@ class MissingSkillsFleetError extends Error {
24950
25462
  // package.json
24951
25463
  var package_default = {
24952
25464
  name: "@hasna/skills",
24953
- version: "0.3.0",
25465
+ version: "0.5.0",
24954
25466
  description: "Skills library for AI coding agents",
24955
25467
  type: "module",
24956
25468
  bin: {
@@ -24982,6 +25494,7 @@ var package_default = {
24982
25494
  files: [
24983
25495
  "dist/",
24984
25496
  "!dist/**/*.test.d.ts",
25497
+ "!dist/**/*.fixture.d.ts",
24985
25498
  "!dist/test-preload.d.ts",
24986
25499
  "!dist/platform",
24987
25500
  "bin/",
@@ -25007,10 +25520,10 @@ var package_default = {
25007
25520
  migrate: "bun run ./src/server/migrate.ts",
25008
25521
  typecheck: "tsc --noEmit",
25009
25522
  "verify:release": "bun run scripts/release-guard.ts",
25523
+ "verify:consumer-types": "bun run scripts/consumer-types.ts",
25010
25524
  prepare: "bun run build:js",
25011
- prepack: "bun run build && bun run verify:release",
25012
- prepublishOnly: "bun run typecheck && bun run test",
25013
- postinstall: "mkdir -p $HOME/.hasna/skills/custom 2>/dev/null || true"
25525
+ prepack: "bun run build && bun run verify:release && bun run verify:consumer-types",
25526
+ prepublishOnly: "bun run typecheck && bun run test"
25014
25527
  },
25015
25528
  keywords: [
25016
25529
  "skills",
@@ -25031,6 +25544,7 @@ var package_default = {
25031
25544
  author: "Hasna",
25032
25545
  license: "Apache-2.0",
25033
25546
  devDependencies: {
25547
+ "@hasna/contracts": "1.0.2",
25034
25548
  "@types/bun": "1.3.14",
25035
25549
  "@types/node": "25.2.3",
25036
25550
  "@types/react": "^18.2.0",
@@ -25042,8 +25556,7 @@ var package_default = {
25042
25556
  dependencies: {
25043
25557
  "@aws-sdk/client-ecs": "^3.1079.0",
25044
25558
  "@aws-sdk/client-s3": "^3.1079.0",
25045
- "@hasna/contracts": "1.0.1",
25046
- "@hasna/events": "0.1.16",
25559
+ "@hasna/events": "0.1.18",
25047
25560
  "@modelcontextprotocol/sdk": "^1.26.0",
25048
25561
  chalk: "^5.3.0",
25049
25562
  commander: "^12.1.0",
@@ -25859,8 +26372,8 @@ var $NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS = NODE_RESPONSE_CHECKSUM_V
25859
26372
  var $getFlexibleChecksumsPlugin = getFlexibleChecksumsPlugin;
25860
26373
  var $resolveFlexibleChecksumsConfig = resolveFlexibleChecksumsConfig;
25861
26374
 
25862
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/S3Client.js
25863
- var import_client24 = __toESM(require_client2(), 1);
26375
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/S3Client.js
26376
+ var import_client26 = __toESM(require_client2(), 1);
25864
26377
 
25865
26378
  // ../../node_modules/.bun/@aws-sdk+middleware-sdk-s3@3.972.75/node_modules/@aws-sdk/middleware-sdk-s3/dist-cjs/submodules/s3/index.js
25866
26379
  var { NoOpLogger, getSmithyContext } = require_client();
@@ -26467,9 +26980,9 @@ var $getThrow200ExceptionsPlugin = getThrow200ExceptionsPlugin;
26467
26980
  var $getValidateBucketNamePlugin = getValidateBucketNamePlugin;
26468
26981
  var $resolveS3Config = resolveS3Config;
26469
26982
 
26470
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/S3Client.js
26983
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/S3Client.js
26471
26984
  var import_core = __toESM(require_dist_cjs2(), 1);
26472
- var import_client25 = __toESM(require_client(), 1);
26985
+ var import_client27 = __toESM(require_client(), 1);
26473
26986
  var import_config29 = __toESM(require_config(), 1);
26474
26987
  var import_endpoints5 = __toESM(require_endpoints(), 1);
26475
26988
  var import_event_streams2 = __toESM(require_event_streams(), 1);
@@ -26477,17 +26990,17 @@ var import_protocols6 = __toESM(require_protocols(), 1);
26477
26990
  var import_retry4 = __toESM(require_retry(), 1);
26478
26991
  var import_schema2 = __toESM(require_schema(), 1);
26479
26992
 
26480
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/auth/httpAuthSchemeProvider.js
26993
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/auth/httpAuthSchemeProvider.js
26481
26994
  var import_httpAuthSchemes = __toESM(require_httpAuthSchemes(), 1);
26482
26995
  var import_signature_v4_multi_region = __toESM(require_dist_cjs4(), 1);
26483
- var import_client3 = __toESM(require_client(), 1);
26996
+ var import_client5 = __toESM(require_client(), 1);
26484
26997
  var import_endpoints3 = __toESM(require_endpoints(), 1);
26485
26998
 
26486
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/endpointResolver.js
26487
- var import_client2 = __toESM(require_client2(), 1);
26999
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/endpointResolver.js
27000
+ var import_client4 = __toESM(require_client2(), 1);
26488
27001
  var import_endpoints2 = __toESM(require_endpoints(), 1);
26489
27002
 
26490
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/bdd.js
27003
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/bdd.js
26491
27004
  var import_endpoints = __toESM(require_endpoints(), 1);
26492
27005
  var aw = "ref";
26493
27006
  var ax = "argv";
@@ -28431,7 +28944,7 @@ var nodes = new Int32Array([
28431
28944
  ]);
28432
28945
  var bdd = import_endpoints.BinaryDecisionDiagram.from(nodes, root, _data.conditions, _data.results);
28433
28946
 
28434
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/endpointResolver.js
28947
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/endpointResolver.js
28435
28948
  var cache = new import_endpoints2.EndpointCache({
28436
28949
  size: 50,
28437
28950
  params: [
@@ -28457,15 +28970,15 @@ var defaultEndpointResolver = (endpointParams, context = {}) => {
28457
28970
  logger: context.logger
28458
28971
  }));
28459
28972
  };
28460
- import_endpoints2.customEndpointFunctions.aws = import_client2.awsEndpointFunctions;
28973
+ import_endpoints2.customEndpointFunctions.aws = import_client4.awsEndpointFunctions;
28461
28974
 
28462
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/auth/httpAuthSchemeProvider.js
28975
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/auth/httpAuthSchemeProvider.js
28463
28976
  var createEndpointRuleSetHttpAuthSchemeParametersProvider = (defaultHttpAuthSchemeParametersProvider) => async (config, context, input) => {
28464
28977
  if (!input) {
28465
28978
  throw new Error("Could not find `input` for `defaultEndpointRuleSetHttpAuthSchemeParametersProvider`");
28466
28979
  }
28467
28980
  const defaultParameters = await defaultHttpAuthSchemeParametersProvider(config, context, input);
28468
- const instructionsFn = import_client3.getSmithyContext(context)?.commandInstance?.constructor?.getEndpointParameterInstructions;
28981
+ const instructionsFn = import_client5.getSmithyContext(context)?.commandInstance?.constructor?.getEndpointParameterInstructions;
28469
28982
  if (!instructionsFn) {
28470
28983
  throw new Error(`getEndpointParameterInstructions() is not defined on '${context.commandName}'`);
28471
28984
  }
@@ -28474,8 +28987,8 @@ var createEndpointRuleSetHttpAuthSchemeParametersProvider = (defaultHttpAuthSche
28474
28987
  };
28475
28988
  var _defaultS3HttpAuthSchemeParametersProvider = async (config, context, input) => {
28476
28989
  return {
28477
- operation: import_client3.getSmithyContext(context).operation,
28478
- region: await import_client3.normalizeProvider(config.region)() || (() => {
28990
+ operation: import_client5.getSmithyContext(context).operation,
28991
+ region: await import_client5.normalizeProvider(config.region)() || (() => {
28479
28992
  throw new Error("expected `region` to be configured for `aws.auth#sigv4`");
28480
28993
  })()
28481
28994
  };
@@ -28571,15 +29084,15 @@ var resolveHttpAuthSchemeConfig = (config) => {
28571
29084
  const config_0 = import_httpAuthSchemes.resolveAwsSdkSigV4Config(config);
28572
29085
  const config_1 = import_httpAuthSchemes.resolveAwsSdkSigV4AConfig(config_0);
28573
29086
  return Object.assign(config_1, {
28574
- authSchemePreference: import_client3.normalizeProvider(config.authSchemePreference ?? [])
29087
+ authSchemePreference: import_client5.normalizeProvider(config.authSchemePreference ?? [])
28575
29088
  });
28576
29089
  };
28577
29090
 
28578
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/commandBuilder.js
28579
- var import_client4 = __toESM(require_client(), 1);
29091
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/commandBuilder.js
29092
+ var import_client6 = __toESM(require_client(), 1);
28580
29093
  var import_endpoints4 = __toESM(require_endpoints(), 1);
28581
29094
 
28582
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/EndpointParameters.js
29095
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/endpoint/EndpointParameters.js
28583
29096
  var resolveClientEndpointParameters = (options) => {
28584
29097
  return Object.assign(options, {
28585
29098
  useFipsEndpoint: options.useFipsEndpoint ?? false,
@@ -28605,8 +29118,8 @@ var commonParams = {
28605
29118
  UseDualStack: { type: "builtInParams", name: "useDualstackEndpoint" }
28606
29119
  };
28607
29120
 
28608
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/commandBuilder.js
28609
- var command = import_client4.makeBuilder(commonParams, "AmazonS3", "S3Client", import_endpoints4.getEndpointPlugin);
29121
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/commandBuilder.js
29122
+ var command = import_client6.makeBuilder(commonParams, "AmazonS3", "S3Client", import_endpoints4.getEndpointPlugin);
28610
29123
  var _ep0 = {
28611
29124
  Bucket: { type: "contextParams", name: "Bucket" },
28612
29125
  Key: { type: "contextParams", name: "Key" }
@@ -28637,19 +29150,19 @@ var _mw11 = (Command, cs, config, o2) => [
28637
29150
  $getSsecPlugin(config)
28638
29151
  ];
28639
29152
 
28640
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/schemas/schemas_0.js
29153
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/schemas/schemas_0.js
28641
29154
  var import_schema = __toESM(require_schema(), 1);
28642
29155
 
28643
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/models/S3ServiceException.js
28644
- var import_client5 = __toESM(require_client(), 1);
28645
- class S3ServiceException extends import_client5.ServiceException {
29156
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/models/S3ServiceException.js
29157
+ var import_client7 = __toESM(require_client(), 1);
29158
+ class S3ServiceException extends import_client7.ServiceException {
28646
29159
  constructor(options) {
28647
29160
  super(options);
28648
29161
  Object.setPrototypeOf(this, S3ServiceException.prototype);
28649
29162
  }
28650
29163
  }
28651
29164
 
28652
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/models/errors.js
29165
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/models/errors.js
28653
29166
  class NoSuchUpload extends S3ServiceException {
28654
29167
  name = "NoSuchUpload";
28655
29168
  $fault = "client";
@@ -28927,7 +29440,7 @@ class ObjectAlreadyInActiveTierError extends S3ServiceException {
28927
29440
  }
28928
29441
  }
28929
29442
 
28930
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/schemas/schemas_0.js
29443
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/schemas/schemas_0.js
28931
29444
  var _A = "Account";
28932
29445
  var _AAO = "AnalyticsAndOperator";
28933
29446
  var _AC = "AccelerateConfiguration";
@@ -34379,13 +34892,13 @@ var WriteGetObjectResponse$ = [
34379
34892
  () => __Unit
34380
34893
  ];
34381
34894
 
34382
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/commands/CreateSessionCommand.js
34895
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/commands/CreateSessionCommand.js
34383
34896
  class CreateSessionCommand extends command(_ep4, _mw0, "CreateSession", CreateSession$) {
34384
34897
  }
34385
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/package.json
34898
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/package.json
34386
34899
  var package_default2 = {
34387
34900
  name: "@aws-sdk/client-s3",
34388
- version: "3.1126.0",
34901
+ version: "3.1127.0",
34389
34902
  description: "AWS SDK for JavaScript S3 Client for Node.js, Browser and React Native",
34390
34903
  homepage: "https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-s3",
34391
34904
  license: "Apache-2.0",
@@ -34452,7 +34965,7 @@ var package_default2 = {
34452
34965
  tslib: "^2.6.2"
34453
34966
  },
34454
34967
  devDependencies: {
34455
- "@aws-sdk/signature-v4-crt": "3.1126.0",
34968
+ "@aws-sdk/signature-v4-crt": "3.1127.0",
34456
34969
  "@smithy/snapshot-testing": "^2.3.2",
34457
34970
  "@tsconfig/node20": "20.1.8",
34458
34971
  "@types/node": "^20.14.8",
@@ -34467,8 +34980,8 @@ var package_default2 = {
34467
34980
  }
34468
34981
  };
34469
34982
 
34470
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.js
34471
- var import_client20 = __toESM(require_client2(), 1);
34983
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.js
34984
+ var import_client22 = __toESM(require_client2(), 1);
34472
34985
  var import_httpAuthSchemes3 = __toESM(require_httpAuthSchemes(), 1);
34473
34986
 
34474
34987
  // ../../node_modules/.bun/@aws-sdk+credential-provider-node@3.972.82/node_modules/@aws-sdk/credential-provider-node/dist-es/defaultProvider.js
@@ -34624,9 +35137,9 @@ var defaultProvider = (init = {}) => memoizeChain([
34624
35137
  }
34625
35138
  ], credentialsTreatedAsExpired);
34626
35139
  var credentialsTreatedAsExpired = (credentials) => credentials?.expiration !== undefined && credentials.expiration.getTime() - Date.now() < 300000;
34627
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.js
35140
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.js
34628
35141
  var import_checksum2 = __toESM(require_checksum(), 1);
34629
- var import_client21 = __toESM(require_client(), 1);
35142
+ var import_client23 = __toESM(require_client(), 1);
34630
35143
  var import_config28 = __toESM(require_config(), 1);
34631
35144
  var import_event_streams = __toESM(require_event_streams(), 1);
34632
35145
  var import_retry3 = __toESM(require_retry(), 1);
@@ -34862,11 +35375,11 @@ var subtle = typeof digest === "function" && typeof sign2 === "function" && type
34862
35375
  var MAX_PENDING_BYTES = 8 * 1024 * 1024;
34863
35376
  var $Sha1 = Sha1Node;
34864
35377
 
34865
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.shared.js
35378
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.shared.js
34866
35379
  var import_httpAuthSchemes2 = __toESM(require_httpAuthSchemes(), 1);
34867
35380
  var import_signature_v4_multi_region2 = __toESM(require_dist_cjs4(), 1);
34868
35381
  var import_checksum = __toESM(require_checksum(), 1);
34869
- var import_client19 = __toESM(require_client(), 1);
35382
+ var import_client21 = __toESM(require_client(), 1);
34870
35383
  var import_protocols4 = __toESM(require_protocols(), 1);
34871
35384
  var import_serde3 = __toESM(require_serde(), 1);
34872
35385
  var getRuntimeConfig2 = (config) => {
@@ -34891,7 +35404,7 @@ var getRuntimeConfig2 = (config) => {
34891
35404
  signer: new import_httpAuthSchemes2.AwsSdkSigV4ASigner
34892
35405
  }
34893
35406
  ],
34894
- logger: config?.logger ?? new import_client19.NoOpLogger,
35407
+ logger: config?.logger ?? new import_client21.NoOpLogger,
34895
35408
  md5: config?.md5 ?? import_checksum.Md5,
34896
35409
  protocol: config?.protocol ?? $S3RestXmlProtocol,
34897
35410
  protocolSettings: config?.protocolSettings ?? {
@@ -34914,13 +35427,13 @@ var getRuntimeConfig2 = (config) => {
34914
35427
  };
34915
35428
  };
34916
35429
 
34917
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.js
35430
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeConfig.js
34918
35431
  var getRuntimeConfig3 = (config) => {
34919
- import_client21.emitWarningIfUnsupportedVersion(process.version);
35432
+ import_client23.emitWarningIfUnsupportedVersion(process.version);
34920
35433
  const defaultsMode = import_config28.resolveDefaultsModeConfig(config);
34921
- const defaultConfigProvider = () => defaultsMode().then(import_client21.loadConfigsForDefaultMode);
35434
+ const defaultConfigProvider = () => defaultsMode().then(import_client23.loadConfigsForDefaultMode);
34922
35435
  const clientSharedValues = getRuntimeConfig2(config);
34923
- import_client20.emitWarningIfUnsupportedVersion(process.version);
35436
+ import_client22.emitWarningIfUnsupportedVersion(process.version);
34924
35437
  const loaderConfig = {
34925
35438
  profile: config?.profile,
34926
35439
  logger: clientSharedValues.logger
@@ -34933,7 +35446,7 @@ var getRuntimeConfig3 = (config) => {
34933
35446
  authSchemePreference: config?.authSchemePreference ?? import_config28.loadConfig(import_httpAuthSchemes3.NODE_AUTH_SCHEME_PREFERENCE_OPTIONS, loaderConfig),
34934
35447
  bodyLengthChecker: config?.bodyLengthChecker ?? import_serde4.calculateBodyLength,
34935
35448
  credentialDefaultProvider: config?.credentialDefaultProvider ?? defaultProvider,
34936
- defaultUserAgentProvider: config?.defaultUserAgentProvider ?? import_client20.createDefaultUserAgentProvider({ serviceId: clientSharedValues.serviceId, clientVersion: package_default2.version }),
35449
+ defaultUserAgentProvider: config?.defaultUserAgentProvider ?? import_client22.createDefaultUserAgentProvider({ serviceId: clientSharedValues.serviceId, clientVersion: package_default2.version }),
34937
35450
  disableS3ExpressSessionAuth: config?.disableS3ExpressSessionAuth ?? import_config28.loadConfig($NODE_DISABLE_S3_EXPRESS_SESSION_AUTH_OPTIONS, loaderConfig),
34938
35451
  eventStreamSerdeProvider: config?.eventStreamSerdeProvider ?? import_event_streams.eventStreamSerdeProvider,
34939
35452
  maxAttempts: config?.maxAttempts ?? import_config28.loadConfig(import_retry3.NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config),
@@ -34951,16 +35464,16 @@ var getRuntimeConfig3 = (config) => {
34951
35464
  useArnRegion: config?.useArnRegion ?? import_config28.loadConfig($NODE_USE_ARN_REGION_CONFIG_OPTIONS, loaderConfig),
34952
35465
  useDualstackEndpoint: config?.useDualstackEndpoint ?? import_config28.loadConfig(import_config28.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
34953
35466
  useFipsEndpoint: config?.useFipsEndpoint ?? import_config28.loadConfig(import_config28.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
34954
- userAgentAppId: config?.userAgentAppId ?? import_config28.loadConfig(import_client20.NODE_APP_ID_CONFIG_OPTIONS, loaderConfig)
35467
+ userAgentAppId: config?.userAgentAppId ?? import_config28.loadConfig(import_client22.NODE_APP_ID_CONFIG_OPTIONS, loaderConfig)
34955
35468
  };
34956
35469
  };
34957
35470
 
34958
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeExtensions.js
34959
- var import_client22 = __toESM(require_client2(), 1);
34960
- var import_client23 = __toESM(require_client(), 1);
35471
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeExtensions.js
35472
+ var import_client24 = __toESM(require_client2(), 1);
35473
+ var import_client25 = __toESM(require_client(), 1);
34961
35474
  var import_protocols5 = __toESM(require_protocols(), 1);
34962
35475
 
34963
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/auth/httpAuthExtensionConfiguration.js
35476
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/auth/httpAuthExtensionConfiguration.js
34964
35477
  var getHttpAuthExtensionConfiguration2 = (runtimeConfig) => {
34965
35478
  const _httpAuthSchemes = runtimeConfig.httpAuthSchemes;
34966
35479
  let _httpAuthSchemeProvider = runtimeConfig.httpAuthSchemeProvider;
@@ -34999,26 +35512,26 @@ var resolveHttpAuthRuntimeConfig2 = (config) => {
34999
35512
  };
35000
35513
  };
35001
35514
 
35002
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeExtensions.js
35515
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/runtimeExtensions.js
35003
35516
  var resolveRuntimeExtensions2 = (runtimeConfig, extensions) => {
35004
- const extensionConfiguration = Object.assign(import_client22.getAwsRegionExtensionConfiguration(runtimeConfig), import_client23.getDefaultExtensionConfiguration(runtimeConfig), import_protocols5.getHttpHandlerExtensionConfiguration(runtimeConfig), getHttpAuthExtensionConfiguration2(runtimeConfig));
35517
+ const extensionConfiguration = Object.assign(import_client24.getAwsRegionExtensionConfiguration(runtimeConfig), import_client25.getDefaultExtensionConfiguration(runtimeConfig), import_protocols5.getHttpHandlerExtensionConfiguration(runtimeConfig), getHttpAuthExtensionConfiguration2(runtimeConfig));
35005
35518
  extensions.forEach((extension) => extension.configure(extensionConfiguration));
35006
- return Object.assign(runtimeConfig, import_client22.resolveAwsRegionExtensionConfiguration(extensionConfiguration), import_client23.resolveDefaultRuntimeConfig(extensionConfiguration), import_protocols5.resolveHttpHandlerRuntimeConfig(extensionConfiguration), resolveHttpAuthRuntimeConfig2(extensionConfiguration));
35519
+ return Object.assign(runtimeConfig, import_client24.resolveAwsRegionExtensionConfiguration(extensionConfiguration), import_client25.resolveDefaultRuntimeConfig(extensionConfiguration), import_protocols5.resolveHttpHandlerRuntimeConfig(extensionConfiguration), resolveHttpAuthRuntimeConfig2(extensionConfiguration));
35007
35520
  };
35008
35521
 
35009
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/S3Client.js
35010
- class S3Client extends import_client25.Client {
35522
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/S3Client.js
35523
+ class S3Client extends import_client27.Client {
35011
35524
  config;
35012
35525
  constructor(...[configuration]) {
35013
35526
  const _config_0 = getRuntimeConfig3(configuration || {});
35014
35527
  super(_config_0);
35015
35528
  this.initConfig = _config_0;
35016
35529
  const _config_1 = resolveClientEndpointParameters(_config_0);
35017
- const _config_2 = import_client24.resolveUserAgentConfig(_config_1);
35530
+ const _config_2 = import_client26.resolveUserAgentConfig(_config_1);
35018
35531
  const _config_3 = $resolveFlexibleChecksumsConfig(_config_2);
35019
35532
  const _config_4 = import_retry4.resolveRetryConfig(_config_3);
35020
35533
  const _config_5 = import_config29.resolveRegionConfig(_config_4);
35021
- const _config_6 = import_client24.resolveHostHeaderConfig(_config_5);
35534
+ const _config_6 = import_client26.resolveHostHeaderConfig(_config_5);
35022
35535
  const _config_7 = import_endpoints5.resolveEndpointConfig(_config_6);
35023
35536
  const _config_8 = import_event_streams2.resolveEventStreamSerdeConfig(_config_7);
35024
35537
  const _config_9 = resolveHttpAuthSchemeConfig(_config_8);
@@ -35026,12 +35539,12 @@ class S3Client extends import_client25.Client {
35026
35539
  const _config_11 = resolveRuntimeExtensions2(_config_10, configuration?.extensions || []);
35027
35540
  this.config = _config_11;
35028
35541
  this.middlewareStack.use(import_schema2.getSchemaSerdePlugin(this.config));
35029
- this.middlewareStack.use(import_client24.getUserAgentPlugin(this.config));
35542
+ this.middlewareStack.use(import_client26.getUserAgentPlugin(this.config));
35030
35543
  this.middlewareStack.use(import_retry4.getRetryPlugin(this.config));
35031
35544
  this.middlewareStack.use(import_protocols6.getContentLengthPlugin(this.config));
35032
- this.middlewareStack.use(import_client24.getHostHeaderPlugin(this.config));
35033
- this.middlewareStack.use(import_client24.getLoggerPlugin(this.config));
35034
- this.middlewareStack.use(import_client24.getRecursionDetectionPlugin(this.config));
35545
+ this.middlewareStack.use(import_client26.getHostHeaderPlugin(this.config));
35546
+ this.middlewareStack.use(import_client26.getLoggerPlugin(this.config));
35547
+ this.middlewareStack.use(import_client26.getRecursionDetectionPlugin(this.config));
35035
35548
  this.middlewareStack.use(import_core.getHttpAuthSchemeEndpointRuleSetPlugin(this.config, {
35036
35549
  httpAuthSchemeParametersProvider: defaultS3HttpAuthSchemeParametersProvider,
35037
35550
  identityProviderConfigProvider: async (config) => new import_core.DefaultIdentityProviderConfig({
@@ -35051,15 +35564,15 @@ class S3Client extends import_client25.Client {
35051
35564
  }
35052
35565
  }
35053
35566
 
35054
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/commands/DeleteObjectCommand.js
35567
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/commands/DeleteObjectCommand.js
35055
35568
  class DeleteObjectCommand extends command(_ep0, _mw0, "DeleteObject", DeleteObject$) {
35056
35569
  }
35057
35570
 
35058
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/commands/GetObjectCommand.js
35571
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/commands/GetObjectCommand.js
35059
35572
  class GetObjectCommand extends command(_ep0, _mw7, "GetObject", GetObject$) {
35060
35573
  }
35061
35574
 
35062
- // ../../node_modules/.bun/@aws-sdk+client-s3@3.1126.0/node_modules/@aws-sdk/client-s3/dist-es/commands/PutObjectCommand.js
35575
+ // ../../node_modules/.bun/@aws-sdk+client-s3@3.1127.0/node_modules/@aws-sdk/client-s3/dist-es/commands/PutObjectCommand.js
35063
35576
  class PutObjectCommand extends command(_ep0, _mw11, "PutObject", PutObject$) {
35064
35577
  }
35065
35578
 
@@ -35465,12 +35978,7 @@ import { homedir as homedir2 } from "os";
35465
35978
  import { join as join4, resolve } from "path";
35466
35979
  import { homedir as pathsResolverHomedir } from "os";
35467
35980
  import { join as pathsResolverJoin } from "path";
35468
- var PATHS_RESOLVER_KIND_ENV = {
35469
- config: "HASNA_CONFIG_HOME",
35470
- data: "HASNA_DATA_HOME",
35471
- state: "HASNA_STATE_HOME",
35472
- cache: "HASNA_CACHE_HOME"
35473
- };
35981
+ var PATHS_RESOLVER_DATA_ENV = "HASNA_DATA_HOME";
35474
35982
  var PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
35475
35983
  function pathsResolverAssertApp(app) {
35476
35984
  if (typeof app !== "string" || app.length === 0) {
@@ -35480,48 +35988,19 @@ function pathsResolverAssertApp(app) {
35480
35988
  throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
35481
35989
  }
35482
35990
  }
35483
- function pathsResolverAssertKind(kind) {
35484
- if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
35485
- throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
35486
- }
35487
- }
35488
- function pathsResolverBaseDir(kind, options) {
35489
- pathsResolverAssertKind(kind);
35991
+ function pathsResolverDataBaseDir(options) {
35490
35992
  const env = options.env ?? process.env;
35491
- const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
35993
+ const override = env[PATHS_RESOLVER_DATA_ENV];
35492
35994
  if (typeof override === "string" && override.length > 0)
35493
35995
  return override;
35494
35996
  const home = options.home ?? pathsResolverHomedir();
35495
35997
  const platform = options.platform ?? process.platform;
35496
- if (platform === "darwin") {
35497
- switch (kind) {
35498
- case "config":
35499
- case "data":
35500
- return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
35501
- case "cache":
35502
- return pathsResolverJoin(home, "Library", "Caches", "Hasna");
35503
- case "state":
35504
- return pathsResolverJoin(home, "Library", "Logs", "Hasna");
35505
- }
35506
- }
35507
- switch (kind) {
35508
- case "config":
35509
- return pathsResolverJoin(home, ".config", "hasna");
35510
- case "data":
35511
- return pathsResolverJoin(home, ".local", "share", "hasna");
35512
- case "state":
35513
- return pathsResolverJoin(home, ".local", "state", "hasna");
35514
- case "cache":
35515
- return pathsResolverJoin(home, ".cache", "hasna");
35516
- }
35998
+ return platform === "darwin" ? pathsResolverJoin(home, "Library", "Application Support", "Hasna") : pathsResolverJoin(home, ".local", "share", "hasna");
35517
35999
  }
35518
- function pathsResolverResolve(kind, options) {
36000
+ function dataDir(options) {
35519
36001
  pathsResolverAssertApp(options.app);
35520
36002
  const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
35521
- return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
35522
- }
35523
- function dataDir(options) {
35524
- return pathsResolverResolve("data", options);
36003
+ return pathsResolverJoin(pathsResolverDataBaseDir(options), appSegment);
35525
36004
  }
35526
36005
  var DATA_DIR_ENV = "HASNA_SKILLS_DIR";
35527
36006
  var HASNA_SKILLS_HOME_ENV = "HASNA_SKILLS_HOME";
@@ -36852,13 +37331,12 @@ class SqliteGovernanceStore {
36852
37331
  return rows.map((row) => this.reservationFrom(row));
36853
37332
  }
36854
37333
  async reconcileReservation(reservationId2, actualCents, status) {
36855
- const row = this.db.query("SELECT * FROM skills_credit_reservations WHERE id = ? LIMIT 1").get(reservationId2);
36856
- if (!row || String(row.status) !== "reserved")
36857
- return row ? this.reservationFrom(row) : null;
36858
- const reconciledAt = nowIso();
36859
- this.db.run("UPDATE skills_credit_reservations SET actual_cents = ?, status = ?, reconciled_at = ? WHERE id = ?", [actualCents, status, reconciledAt, reservationId2]);
36860
- const updated = this.db.query("SELECT * FROM skills_credit_reservations WHERE id = ? LIMIT 1").get(reservationId2);
36861
- return this.reservationFrom(updated);
37334
+ const updated = this.db.query(`UPDATE skills_credit_reservations SET actual_cents = ?, status = ?, reconciled_at = ?
37335
+ WHERE id = ? AND status = 'reserved' RETURNING *`).get(actualCents, status, nowIso(), reservationId2);
37336
+ if (updated)
37337
+ return this.reservationFrom(updated);
37338
+ const existing = this.db.query("SELECT * FROM skills_credit_reservations WHERE id = ? LIMIT 1").get(reservationId2);
37339
+ return existing ? this.reservationFrom(existing) : null;
36862
37340
  }
36863
37341
  async monthlySpendCents(orgId, monthPrefix) {
36864
37342
  const from = `${monthPrefix}-01T00:00:00.000Z`;
@@ -37046,6 +37524,7 @@ import { fileURLToPath as fileURLToPath2 } from "url";
37046
37524
  import {
37047
37525
  cpSync as cpSync3,
37048
37526
  existsSync as existsSync9,
37527
+ lstatSync as lstatSync4,
37049
37528
  mkdirSync as mkdirSync6,
37050
37529
  mkdtempSync as mkdtempSync2,
37051
37530
  readFileSync as readFileSync10,
@@ -37821,7 +38300,7 @@ var BRACE_SOURCE_EXCLUSION = new RegExp(`^!skills/\\{(${SLUG}(?:,${SLUG})+)\\}/s
37821
38300
  var SINGLE_SOURCE_EXCLUSION = new RegExp(`^!skills/(${SLUG})/src$`);
37822
38301
 
37823
38302
  // src/lib/skill-validation.ts
37824
- import { existsSync as existsSync5, lstatSync, readFileSync as readFileSync7, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
38303
+ import { existsSync as existsSync5, lstatSync as lstatSync2, readFileSync as readFileSync7, readdirSync as readdirSync5, statSync as statSync4 } from "fs";
37825
38304
  import { isAbsolute as isAbsolute3, join as join10, normalize } from "path";
37826
38305
  var VALID_SKILL_KINDS = ["executable", "instruction"];
37827
38306
  var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
@@ -37902,6 +38381,16 @@ function isHostedMetadataSkill(skillName, frontmatter, registryMeta, packageDecl
37902
38381
  return true;
37903
38382
  return false;
37904
38383
  }
38384
+ function frontmatterString(raw) {
38385
+ if (raw.startsWith('"') && raw.endsWith('"')) {
38386
+ try {
38387
+ const decoded = JSON.parse(raw);
38388
+ if (typeof decoded === "string")
38389
+ return decoded;
38390
+ } catch {}
38391
+ }
38392
+ return raw.replace(/^["']|["']$/g, "");
38393
+ }
37905
38394
  function parseSkillFrontmatter(content) {
37906
38395
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
37907
38396
  if (!match)
@@ -37921,12 +38410,12 @@ function parseSkillFrontmatter(content) {
37921
38410
  const tags = [];
37922
38411
  while (i3 + 1 < lines.length && /^\s+-\s+/.test(lines[i3 + 1])) {
37923
38412
  i3++;
37924
- tags.push(lines[i3].replace(/^\s+-\s+/, "").trim());
38413
+ tags.push(frontmatterString(lines[i3].replace(/^\s+-\s+/, "").trim()));
37925
38414
  }
37926
38415
  result.tags = tags;
37927
38416
  continue;
37928
38417
  }
37929
- const value = rawValue.replace(/^["']|["']$/g, "");
38418
+ const value = frontmatterString(rawValue);
37930
38419
  if (!value)
37931
38420
  continue;
37932
38421
  if (key === "name")
@@ -37979,7 +38468,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
37979
38468
  if (RESERVED_SKILL_ENTRIES.has(entry)) {
37980
38469
  add(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
37981
38470
  }
37982
- if (lstatSync(entryPath).isSymbolicLink()) {
38471
+ if (lstatSync2(entryPath).isSymbolicLink()) {
37983
38472
  add(issues, "skill.symlink_forbidden", `Symlink '${entry}' is not allowed in skill packages`);
37984
38473
  }
37985
38474
  if (!KNOWN_TOP_LEVEL_ENTRIES.has(entry)) {
@@ -38461,7 +38950,7 @@ function validateRuntimeContract(manifest, issues, strict) {
38461
38950
  import {
38462
38951
  cpSync,
38463
38952
  existsSync as existsSync7,
38464
- lstatSync as lstatSync2,
38953
+ lstatSync as lstatSync3,
38465
38954
  mkdirSync as mkdirSync4,
38466
38955
  readFileSync as readFileSync9,
38467
38956
  realpathSync,
@@ -38509,14 +38998,27 @@ function normalizePortableSkillName(name) {
38509
38998
  }
38510
38999
  return normalized;
38511
39000
  }
39001
+ function normalizeNewPortableSkillName(name) {
39002
+ normalizePortableSkillName(name);
39003
+ const normalized = name.trim().replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
39004
+ if (!normalized)
39005
+ throw new Error(`Invalid skill name '${name}'. Include letters or numbers.`);
39006
+ return normalized;
39007
+ }
38512
39008
  function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)) {
39009
+ return readManifest(skillPath, fallbackName, normalizePortableSkillName);
39010
+ }
39011
+ function readPortableSkillManifestForImport(skillPath) {
39012
+ return readManifest(skillPath, basename(skillPath), normalizeNewPortableSkillName);
39013
+ }
39014
+ function readManifest(skillPath, fallbackName, normalizeName) {
38513
39015
  const skillJsonPath = join12(skillPath, "skill.json");
38514
39016
  const skillMdPath = join12(skillPath, "SKILL.md");
38515
39017
  const pkgPath = join12(skillPath, "package.json");
38516
39018
  const jsonManifest = existsSync7(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
38517
39019
  const frontmatter = existsSync7(skillMdPath) ? parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8")) ?? undefined : undefined;
38518
39020
  const pkg = existsSync7(pkgPath) ? readJsonObject(pkgPath) : undefined;
38519
- const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
39021
+ const name = normalizeName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
38520
39022
  const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
38521
39023
  const version2 = readDeclaredSkillVersion(skillPath) ?? PORTABLE_SKILL_DEFAULT_VERSION;
38522
39024
  const kind = parseSkillKind(stringField(jsonManifest, "kind") ?? frontmatter?.kind);
@@ -38559,8 +39061,8 @@ function createInstructionManifest(name, options) {
38559
39061
  description: options.description,
38560
39062
  version: PORTABLE_SKILL_DEFAULT_VERSION,
38561
39063
  displayName: displayName(name),
38562
- category: "Development Tools",
38563
- tags: ["custom", name],
39064
+ category: options.category ?? "Development Tools",
39065
+ tags: options.tags ?? ["custom", name],
38564
39066
  kind: "instruction",
38565
39067
  inputs: [],
38566
39068
  commands: [],
@@ -38575,16 +39077,16 @@ function writeInstructionSkillTemplate(skillPath, manifest) {
38575
39077
  }
38576
39078
  function renderInstructionSkillMd(manifest) {
38577
39079
  const tags = manifest.tags?.length ? `tags:
38578
- ${manifest.tags.map((tag) => ` - ${tag}`).join(`
39080
+ ${manifest.tags.map((tag) => ` - ${yamlString(tag)}`).join(`
38579
39081
  `)}
38580
39082
  ` : "";
38581
39083
  return `---
38582
39084
  name: ${manifest.name}
38583
- description: ${manifest.description}
39085
+ description: ${yamlString(manifest.description)}
38584
39086
  kind: instruction
38585
39087
  version: ${manifest.version}
38586
39088
  source: custom
38587
- category: ${manifest.category ?? "Development Tools"}
39089
+ category: ${yamlString(manifest.category ?? "Development Tools")}
38588
39090
  ${tags}---
38589
39091
 
38590
39092
  # ${manifest.displayName ?? displayName(manifest.name)}
@@ -38605,8 +39107,8 @@ function createPortableManifest(name, options) {
38605
39107
  description: options.description,
38606
39108
  version: PORTABLE_SKILL_DEFAULT_VERSION,
38607
39109
  displayName: displayName(name),
38608
- category: "Development Tools",
38609
- tags: ["custom", name],
39110
+ category: options.category ?? "Development Tools",
39111
+ tags: options.tags ?? ["custom", name],
38610
39112
  inputs: DEFAULT_INPUTS,
38611
39113
  commands: [{
38612
39114
  name,
@@ -38764,12 +39266,47 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
38764
39266
  };
38765
39267
  if (!existsSync7(join12(skillPath, "SKILL.md"))) {
38766
39268
  writeFileSync2(join12(skillPath, "SKILL.md"), renderSkillMd(next));
39269
+ } else {
39270
+ const path = join12(skillPath, "SKILL.md");
39271
+ const content = readFileSync9(path, "utf8");
39272
+ const declaredName = parseSkillFrontmatter(content)?.name;
39273
+ if (declaredName && declaredName !== next.name) {
39274
+ writeFileSync2(path, renameInstructionFrontmatter(content, next.name));
39275
+ }
39276
+ }
39277
+ const packagePath = join12(skillPath, "package.json");
39278
+ if (existsSync7(packagePath)) {
39279
+ const pkg = readJsonObject(packagePath);
39280
+ if (typeof pkg.name === "string" && pkg.name !== next.name) {
39281
+ writeFileSync2(packagePath, `${JSON.stringify({ ...pkg, name: next.name }, null, 2)}
39282
+ `);
39283
+ }
38767
39284
  }
38768
39285
  writeSkillJsonWithHash(skillPath, next);
38769
39286
  return readPortableSkillManifest(skillPath, next.name);
38770
39287
  }
39288
+ function renameInstructionFrontmatter(content, name) {
39289
+ const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?=\r?\n|$)/);
39290
+ const names = frontmatter?.[1]?.match(/^[ \t]*name[ \t]*:[^\r\n]*/gm) ?? [];
39291
+ const declaration = names.length === 1 ? names[0].match(/^(name[ \t]*:[ \t]*)(.*?)([ \t]*)$/) : null;
39292
+ const scalar = declaration?.[2] ?? "";
39293
+ let simple = /^[a-zA-Z0-9_.@/ -]+$/.test(scalar);
39294
+ if (scalar.startsWith('"')) {
39295
+ try {
39296
+ simple = typeof JSON.parse(scalar) === "string";
39297
+ } catch {
39298
+ simple = false;
39299
+ }
39300
+ } else if (scalar.startsWith("'"))
39301
+ simple = /^'[^'\r\n]*'$/.test(scalar);
39302
+ if (!frontmatter || !declaration || !simple) {
39303
+ throw new Error("Cannot rename instruction SKILL.md: use one unambiguous top-level name scalar in frontmatter.");
39304
+ }
39305
+ const renamed = frontmatter[0].replace(/^name[ \t]*:[^\r\n]*/m, () => `${declaration[1]}${name}${declaration[3]}`);
39306
+ return renamed + content.slice(frontmatter[0].length);
39307
+ }
38771
39308
  function copySkillDirectory(source, destination) {
38772
- const resolvedSource = lstatSync2(source).isSymbolicLink() ? realpathSync(source) : source;
39309
+ const resolvedSource = lstatSync3(source).isSymbolicLink() ? realpathSync(source) : source;
38773
39310
  mkdirSync4(destination, { recursive: true });
38774
39311
  cpSync(resolvedSource, destination, {
38775
39312
  recursive: true,
@@ -38782,7 +39319,7 @@ function copySkillDirectory(source, destination) {
38782
39319
  if (isExcludedCopyEntry(segments[i3], i3 === 0))
38783
39320
  return false;
38784
39321
  }
38785
- if (lstatSync2(src).isSymbolicLink())
39322
+ if (lstatSync3(src).isSymbolicLink())
38786
39323
  return false;
38787
39324
  return true;
38788
39325
  }
@@ -38797,10 +39334,13 @@ function isExcludedCopyEntry(name, isFirstSegment) {
38797
39334
  return true;
38798
39335
  return false;
38799
39336
  }
39337
+ function yamlString(value) {
39338
+ return JSON.stringify(value);
39339
+ }
38800
39340
  function renderSkillMd(manifest) {
38801
39341
  return `---
38802
39342
  name: ${manifest.name}
38803
- description: ${manifest.description}
39343
+ description: ${yamlString(manifest.description)}
38804
39344
  ---
38805
39345
 
38806
39346
  # ${manifest.displayName ?? displayName(manifest.name)}
@@ -39172,7 +39712,7 @@ function isOfficialSkillName(name) {
39172
39712
  return OFFICIAL_SKILL_NAMES.has(name);
39173
39713
  }
39174
39714
  function scaffoldPortableSkill(name, options = {}) {
39175
- const skillName = normalizePortableSkillName(name);
39715
+ const skillName = normalizeNewPortableSkillName(name);
39176
39716
  const root3 = getPortableSkillsRoot(options);
39177
39717
  const skillPath = join13(root3, skillName);
39178
39718
  if (existsSync8(skillPath)) {
@@ -39183,11 +39723,11 @@ function scaffoldPortableSkill(name, options = {}) {
39183
39723
  const kind = options.kind ?? "executable";
39184
39724
  const description = options.description ?? `${displayName(skillName)} skill`;
39185
39725
  if (kind === "instruction") {
39186
- const manifest2 = createInstructionManifest(skillName, { description });
39726
+ const manifest2 = createInstructionManifest(skillName, { description, category: options.category, tags: options.tags });
39187
39727
  writeInstructionSkillTemplate(skillPath, manifest2);
39188
39728
  return { name: skillName, path: skillPath, manifest: manifest2, created: true };
39189
39729
  }
39190
- const manifest = createPortableManifest(skillName, { description });
39730
+ const manifest = createPortableManifest(skillName, { description, category: options.category, tags: options.tags });
39191
39731
  writePortableSkillTemplate(skillPath, manifest);
39192
39732
  return { name: skillName, path: skillPath, manifest, created: true };
39193
39733
  }
@@ -39242,9 +39782,9 @@ function portPortableSkill(sourcePath, options = {}) {
39242
39782
  if (!existsSync8(absoluteSource) || !statSync7(absoluteSource).isDirectory()) {
39243
39783
  throw new Error(`Skill source directory not found: ${sourcePath}`);
39244
39784
  }
39245
- const inferred = readPortableSkillManifest(absoluteSource, basename2(absoluteSource));
39785
+ const inferred = readPortableSkillManifestForImport(absoluteSource);
39246
39786
  const explicitName = options.name != null;
39247
- const skillName = normalizePortableSkillName(options.name ?? inferred.name);
39787
+ const skillName = normalizeNewPortableSkillName(options.name ?? inferred.name);
39248
39788
  if (isOfficialSkillName(skillName) && !options.allowShadow) {
39249
39789
  const sourceSlug = safeNormalizeName(basename2(absoluteSource));
39250
39790
  const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename2(absoluteSource)}')` : ""} matches a bundled official skill.`;
@@ -39518,6 +40058,20 @@ var SYNC_AGENTS = ["claude", "codewith", "codex", "opencode", "cursor"];
39518
40058
  var SKILLS_SOURCE_ENV = "SKILLS_SOURCE";
39519
40059
  var SYNC_MARKER_FILE = ".hasna-skills.json";
39520
40060
  var SYNC_MARKER_MANAGED_BY = "@hasna/skills";
40061
+ function isSkillsOwnershipMarker(marker) {
40062
+ return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
40063
+ }
40064
+ function hasSkillsOwnershipMarker(dir) {
40065
+ const path = join14(dir, SYNC_MARKER_FILE);
40066
+ try {
40067
+ if (!lstatSync4(path).isFile())
40068
+ return false;
40069
+ const marker = JSON.parse(readFileSync10(path, "utf8"));
40070
+ return isSkillsOwnershipMarker(marker);
40071
+ } catch {
40072
+ return false;
40073
+ }
40074
+ }
39521
40075
  function isSyncAgent(value) {
39522
40076
  return SYNC_AGENTS.includes(value);
39523
40077
  }
@@ -39701,7 +40255,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
39701
40255
  const skillMdPath = join14(dir, "SKILL.md");
39702
40256
  const markerPath = join14(dir, SYNC_MARKER_FILE);
39703
40257
  const dirExists = existsSync9(dir);
39704
- const managed = existsSync9(markerPath);
40258
+ const managed = hasSkillsOwnershipMarker(dir);
39705
40259
  const hasSkillMd = existsSync9(skillMdPath);
39706
40260
  if (dirExists && !managed && !hasSkillMd) {
39707
40261
  return {
@@ -39714,7 +40268,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
39714
40268
  return {
39715
40269
  action: "skip",
39716
40270
  path: skillMdPath,
39717
- reason: "an unmanaged SKILL.md already exists here (hand-authored); pass --force to overwrite"
40271
+ reason: existsSync9(markerPath) ? "an unmanaged SKILL.md already exists here (invalid or foreign ownership marker); pass --force to overwrite" : "an unmanaged SKILL.md already exists here (hand-authored); pass --force to overwrite"
39718
40272
  };
39719
40273
  }
39720
40274
  if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
@@ -39791,7 +40345,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
39791
40345
  }
39792
40346
  function removeManagedAgentSkill(skill, agent, homeDir2 = homedir3()) {
39793
40347
  const dir = join14(agentGlobalSkillsDir(agent, homeDir2), skill);
39794
- if (!existsSync9(join14(dir, SYNC_MARKER_FILE)))
40348
+ if (!hasSkillsOwnershipMarker(dir))
39795
40349
  return false;
39796
40350
  rmSync2(dir, { recursive: true, force: true });
39797
40351
  return true;
@@ -40512,7 +41066,7 @@ function removeSkillForAgent(name, options) {
40512
41066
  const canonicalName = getCanonicalSkillName(name);
40513
41067
  const scope = options.scope ?? "global";
40514
41068
  const dir = getAgentSkillPath(canonicalName, options.agent, scope, options.projectDir);
40515
- if (!existsSync12(join17(dir, SYNC_MARKER_FILE)))
41069
+ if (!hasSkillsOwnershipMarker(dir))
40516
41070
  return false;
40517
41071
  rmSync3(dir, { recursive: true, force: true });
40518
41072
  return true;
@@ -40756,7 +41310,7 @@ async function runSkill(name, args, options = {}) {
40756
41310
  }
40757
41311
  const proc = Bun.spawn(["bun", "run", entryPath, ...args], {
40758
41312
  cwd: skillPath,
40759
- stdout: options.stdio === "pipe" ? "pipe" : "inherit",
41313
+ stdout: options.stdio === "pipe" ? "pipe" : options.stdio === "stderr" ? 2 : "inherit",
40760
41314
  stderr: options.stdio === "pipe" ? "pipe" : "inherit",
40761
41315
  stdin: "inherit",
40762
41316
  env: { ...process.env, ...options.env }
@@ -41126,7 +41680,7 @@ async function getMergedSkill(store, artifactStorage, principal, slug) {
41126
41680
  if (resolved.kind === "published")
41127
41681
  return publishedPayload(resolved.record);
41128
41682
  const bundled = getServerSkill(slug);
41129
- return bundled ? bundled : null;
41683
+ return bundled ? { ...bundled, publicationState: "catalogue-only", revisionId: null } : null;
41130
41684
  }
41131
41685
  async function getMergedSkillMd(store, artifactStorage, principal, slug) {
41132
41686
  const resolved = await resolvePublishedSkill(store, artifactStorage, principal, slug);
@@ -47090,7 +47644,7 @@ function sortKeys(value) {
47090
47644
  return value.map(sortKeys);
47091
47645
  if (value !== null && typeof value === "object") {
47092
47646
  const record = value;
47093
- const sorted = {};
47647
+ const sorted = Object.create(null);
47094
47648
  for (const key of Object.keys(record).sort()) {
47095
47649
  sorted[key] = sortKeys(record[key]);
47096
47650
  }
@@ -47843,23 +48397,23 @@ function createReceiptService(store) {
47843
48397
  // src/sdk/execution/dispatchers/ecs.ts
47844
48398
  import { createHash as createHash11 } from "crypto";
47845
48399
 
47846
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/ECSClient.js
47847
- var import_client34 = __toESM(require_client2(), 1);
48400
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/ECSClient.js
48401
+ var import_client36 = __toESM(require_client2(), 1);
47848
48402
  var import_core2 = __toESM(require_dist_cjs2(), 1);
47849
- var import_client35 = __toESM(require_client(), 1);
48403
+ var import_client37 = __toESM(require_client(), 1);
47850
48404
  var import_config39 = __toESM(require_config(), 1);
47851
48405
  var import_endpoints8 = __toESM(require_endpoints(), 1);
47852
48406
  var import_protocols10 = __toESM(require_protocols(), 1);
47853
48407
  var import_retry6 = __toESM(require_retry(), 1);
47854
48408
  var import_schema4 = __toESM(require_schema(), 1);
47855
48409
 
47856
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/auth/httpAuthSchemeProvider.js
48410
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/auth/httpAuthSchemeProvider.js
47857
48411
  var import_httpAuthSchemes4 = __toESM(require_httpAuthSchemes(), 1);
47858
- var import_client26 = __toESM(require_client(), 1);
48412
+ var import_client28 = __toESM(require_client(), 1);
47859
48413
  var defaultECSHttpAuthSchemeParametersProvider = async (config, context, input) => {
47860
48414
  return {
47861
- operation: import_client26.getSmithyContext(context).operation,
47862
- region: await import_client26.normalizeProvider(config.region)() || (() => {
48415
+ operation: import_client28.getSmithyContext(context).operation,
48416
+ region: await import_client28.normalizeProvider(config.region)() || (() => {
47863
48417
  throw new Error("expected `region` to be configured for `aws.auth#sigv4`");
47864
48418
  })()
47865
48419
  };
@@ -47891,11 +48445,11 @@ var defaultECSHttpAuthSchemeProvider = (authParameters) => {
47891
48445
  var resolveHttpAuthSchemeConfig3 = (config) => {
47892
48446
  const config_0 = import_httpAuthSchemes4.resolveAwsSdkSigV4Config(config);
47893
48447
  return Object.assign(config_0, {
47894
- authSchemePreference: import_client26.normalizeProvider(config.authSchemePreference ?? [])
48448
+ authSchemePreference: import_client28.normalizeProvider(config.authSchemePreference ?? [])
47895
48449
  });
47896
48450
  };
47897
48451
 
47898
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/EndpointParameters.js
48452
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/EndpointParameters.js
47899
48453
  var resolveClientEndpointParameters3 = (options) => {
47900
48454
  return Object.assign(options, {
47901
48455
  useDualstackEndpoint: options.useDualstackEndpoint ?? false,
@@ -47909,10 +48463,10 @@ var commonParams3 = {
47909
48463
  Region: { type: "builtInParams", name: "region" },
47910
48464
  UseDualStack: { type: "builtInParams", name: "useDualstackEndpoint" }
47911
48465
  };
47912
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/package.json
48466
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/package.json
47913
48467
  var package_default3 = {
47914
48468
  name: "@aws-sdk/client-ecs",
47915
- version: "3.1126.0",
48469
+ version: "3.1127.0",
47916
48470
  description: "AWS SDK for JavaScript Ecs Client for Node.js, Browser and React Native",
47917
48471
  homepage: "https://github.com/aws/aws-sdk-js-v3/tree/main/clients/client-ecs",
47918
48472
  license: "Apache-2.0",
@@ -47982,28 +48536,28 @@ var package_default3 = {
47982
48536
  }
47983
48537
  };
47984
48538
 
47985
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.js
47986
- var import_client30 = __toESM(require_client2(), 1);
48539
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.js
48540
+ var import_client32 = __toESM(require_client2(), 1);
47987
48541
  var import_httpAuthSchemes6 = __toESM(require_httpAuthSchemes(), 1);
47988
- var import_client31 = __toESM(require_client(), 1);
48542
+ var import_client33 = __toESM(require_client(), 1);
47989
48543
  var import_config38 = __toESM(require_config(), 1);
47990
48544
  var import_retry5 = __toESM(require_retry(), 1);
47991
48545
  var import_serde6 = __toESM(require_serde(), 1);
47992
48546
  var import_node_http_handler3 = __toESM(require_dist_cjs6(), 1);
47993
48547
 
47994
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.shared.js
48548
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.shared.js
47995
48549
  var import_httpAuthSchemes5 = __toESM(require_httpAuthSchemes(), 1);
47996
48550
  var import_protocols7 = __toESM(require_protocols2(), 1);
47997
48551
  var import_checksum3 = __toESM(require_checksum(), 1);
47998
- var import_client29 = __toESM(require_client(), 1);
48552
+ var import_client31 = __toESM(require_client(), 1);
47999
48553
  var import_protocols8 = __toESM(require_protocols(), 1);
48000
48554
  var import_serde5 = __toESM(require_serde(), 1);
48001
48555
 
48002
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/endpointResolver.js
48003
- var import_client27 = __toESM(require_client2(), 1);
48556
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/endpointResolver.js
48557
+ var import_client29 = __toESM(require_client2(), 1);
48004
48558
  var import_endpoints7 = __toESM(require_endpoints(), 1);
48005
48559
 
48006
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/bdd.js
48560
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/bdd.js
48007
48561
  var import_endpoints6 = __toESM(require_endpoints(), 1);
48008
48562
  var k3 = "ref";
48009
48563
  var a3 = -1;
@@ -48086,7 +48640,7 @@ var nodes3 = new Int32Array([
48086
48640
  ]);
48087
48641
  var bdd3 = import_endpoints6.BinaryDecisionDiagram.from(nodes3, root3, _data3.conditions, _data3.results);
48088
48642
 
48089
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/endpointResolver.js
48643
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/endpoint/endpointResolver.js
48090
48644
  var cache3 = new import_endpoints7.EndpointCache({
48091
48645
  size: 50,
48092
48646
  params: ["Endpoint", "Region", "UseDualStack", "UseFIPS"]
@@ -48097,21 +48651,21 @@ var defaultEndpointResolver3 = (endpointParams, context = {}) => {
48097
48651
  logger: context.logger
48098
48652
  }));
48099
48653
  };
48100
- import_endpoints7.customEndpointFunctions.aws = import_client27.awsEndpointFunctions;
48654
+ import_endpoints7.customEndpointFunctions.aws = import_client29.awsEndpointFunctions;
48101
48655
 
48102
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/schemas/schemas_0.js
48656
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/schemas/schemas_0.js
48103
48657
  var import_schema3 = __toESM(require_schema(), 1);
48104
48658
 
48105
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/models/ECSServiceException.js
48106
- var import_client28 = __toESM(require_client(), 1);
48107
- class ECSServiceException extends import_client28.ServiceException {
48659
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/models/ECSServiceException.js
48660
+ var import_client30 = __toESM(require_client(), 1);
48661
+ class ECSServiceException extends import_client30.ServiceException {
48108
48662
  constructor(options) {
48109
48663
  super(options);
48110
48664
  Object.setPrototypeOf(this, ECSServiceException.prototype);
48111
48665
  }
48112
48666
  }
48113
48667
 
48114
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/models/errors.js
48668
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/models/errors.js
48115
48669
  class AccessDeniedException extends ECSServiceException {
48116
48670
  name = "AccessDeniedException";
48117
48671
  $fault = "client";
@@ -48504,7 +49058,7 @@ class BlockedException extends ECSServiceException {
48504
49058
  }
48505
49059
  }
48506
49060
 
48507
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/schemas/schemas_0.js
49061
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/schemas/schemas_0.js
48508
49062
  var _A2 = "Attachment";
48509
49063
  var _ACR = "AcceleratorCountRequest";
48510
49064
  var _AD2 = "AttachmentDetails";
@@ -50891,7 +51445,7 @@ var StopTask$ = [
50891
51445
  () => StopTaskResponse$
50892
51446
  ];
50893
51447
 
50894
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.shared.js
51448
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.shared.js
50895
51449
  var getRuntimeConfig4 = (config) => {
50896
51450
  return {
50897
51451
  apiVersion: "2014-11-13",
@@ -50908,7 +51462,7 @@ var getRuntimeConfig4 = (config) => {
50908
51462
  signer: new import_httpAuthSchemes5.AwsSdkSigV4Signer
50909
51463
  }
50910
51464
  ],
50911
- logger: config?.logger ?? new import_client29.NoOpLogger,
51465
+ logger: config?.logger ?? new import_client31.NoOpLogger,
50912
51466
  protocol: config?.protocol ?? import_protocols7.AwsJson1_1Protocol,
50913
51467
  protocolSettings: config?.protocolSettings ?? {
50914
51468
  defaultNamespace: "com.amazonaws.ecs",
@@ -50925,13 +51479,13 @@ var getRuntimeConfig4 = (config) => {
50925
51479
  };
50926
51480
  };
50927
51481
 
50928
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.js
51482
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeConfig.js
50929
51483
  var getRuntimeConfig5 = (config) => {
50930
- import_client31.emitWarningIfUnsupportedVersion(process.version);
51484
+ import_client33.emitWarningIfUnsupportedVersion(process.version);
50931
51485
  const defaultsMode = import_config38.resolveDefaultsModeConfig(config);
50932
- const defaultConfigProvider = () => defaultsMode().then(import_client31.loadConfigsForDefaultMode);
51486
+ const defaultConfigProvider = () => defaultsMode().then(import_client33.loadConfigsForDefaultMode);
50933
51487
  const clientSharedValues = getRuntimeConfig4(config);
50934
- import_client30.emitWarningIfUnsupportedVersion(process.version);
51488
+ import_client32.emitWarningIfUnsupportedVersion(process.version);
50935
51489
  const loaderConfig = {
50936
51490
  profile: config?.profile,
50937
51491
  logger: clientSharedValues.logger
@@ -50944,7 +51498,7 @@ var getRuntimeConfig5 = (config) => {
50944
51498
  authSchemePreference: config?.authSchemePreference ?? import_config38.loadConfig(import_httpAuthSchemes6.NODE_AUTH_SCHEME_PREFERENCE_OPTIONS, loaderConfig),
50945
51499
  bodyLengthChecker: config?.bodyLengthChecker ?? import_serde6.calculateBodyLength,
50946
51500
  credentialDefaultProvider: config?.credentialDefaultProvider ?? defaultProvider,
50947
- defaultUserAgentProvider: config?.defaultUserAgentProvider ?? import_client30.createDefaultUserAgentProvider({ serviceId: clientSharedValues.serviceId, clientVersion: package_default3.version }),
51501
+ defaultUserAgentProvider: config?.defaultUserAgentProvider ?? import_client32.createDefaultUserAgentProvider({ serviceId: clientSharedValues.serviceId, clientVersion: package_default3.version }),
50948
51502
  maxAttempts: config?.maxAttempts ?? import_config38.loadConfig(import_retry5.NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config),
50949
51503
  region: config?.region ?? import_config38.loadConfig(import_config38.NODE_REGION_CONFIG_OPTIONS, { ...import_config38.NODE_REGION_CONFIG_FILE_OPTIONS, ...loaderConfig }),
50950
51504
  requestHandler: import_node_http_handler3.NodeHttpHandler.create(config?.requestHandler ?? defaultConfigProvider),
@@ -50955,16 +51509,16 @@ var getRuntimeConfig5 = (config) => {
50955
51509
  streamCollector: config?.streamCollector ?? import_node_http_handler3.streamCollector,
50956
51510
  useDualstackEndpoint: config?.useDualstackEndpoint ?? import_config38.loadConfig(import_config38.NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
50957
51511
  useFipsEndpoint: config?.useFipsEndpoint ?? import_config38.loadConfig(import_config38.NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, loaderConfig),
50958
- userAgentAppId: config?.userAgentAppId ?? import_config38.loadConfig(import_client30.NODE_APP_ID_CONFIG_OPTIONS, loaderConfig)
51512
+ userAgentAppId: config?.userAgentAppId ?? import_config38.loadConfig(import_client32.NODE_APP_ID_CONFIG_OPTIONS, loaderConfig)
50959
51513
  };
50960
51514
  };
50961
51515
 
50962
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeExtensions.js
50963
- var import_client32 = __toESM(require_client2(), 1);
50964
- var import_client33 = __toESM(require_client(), 1);
51516
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeExtensions.js
51517
+ var import_client34 = __toESM(require_client2(), 1);
51518
+ var import_client35 = __toESM(require_client(), 1);
50965
51519
  var import_protocols9 = __toESM(require_protocols(), 1);
50966
51520
 
50967
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/auth/httpAuthExtensionConfiguration.js
51521
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/auth/httpAuthExtensionConfiguration.js
50968
51522
  var getHttpAuthExtensionConfiguration3 = (runtimeConfig) => {
50969
51523
  const _httpAuthSchemes = runtimeConfig.httpAuthSchemes;
50970
51524
  let _httpAuthSchemeProvider = runtimeConfig.httpAuthSchemeProvider;
@@ -51003,36 +51557,36 @@ var resolveHttpAuthRuntimeConfig3 = (config) => {
51003
51557
  };
51004
51558
  };
51005
51559
 
51006
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeExtensions.js
51560
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/runtimeExtensions.js
51007
51561
  var resolveRuntimeExtensions3 = (runtimeConfig, extensions) => {
51008
- const extensionConfiguration = Object.assign(import_client32.getAwsRegionExtensionConfiguration(runtimeConfig), import_client33.getDefaultExtensionConfiguration(runtimeConfig), import_protocols9.getHttpHandlerExtensionConfiguration(runtimeConfig), getHttpAuthExtensionConfiguration3(runtimeConfig));
51562
+ const extensionConfiguration = Object.assign(import_client34.getAwsRegionExtensionConfiguration(runtimeConfig), import_client35.getDefaultExtensionConfiguration(runtimeConfig), import_protocols9.getHttpHandlerExtensionConfiguration(runtimeConfig), getHttpAuthExtensionConfiguration3(runtimeConfig));
51009
51563
  extensions.forEach((extension) => extension.configure(extensionConfiguration));
51010
- return Object.assign(runtimeConfig, import_client32.resolveAwsRegionExtensionConfiguration(extensionConfiguration), import_client33.resolveDefaultRuntimeConfig(extensionConfiguration), import_protocols9.resolveHttpHandlerRuntimeConfig(extensionConfiguration), resolveHttpAuthRuntimeConfig3(extensionConfiguration));
51564
+ return Object.assign(runtimeConfig, import_client34.resolveAwsRegionExtensionConfiguration(extensionConfiguration), import_client35.resolveDefaultRuntimeConfig(extensionConfiguration), import_protocols9.resolveHttpHandlerRuntimeConfig(extensionConfiguration), resolveHttpAuthRuntimeConfig3(extensionConfiguration));
51011
51565
  };
51012
51566
 
51013
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/ECSClient.js
51014
- class ECSClient extends import_client35.Client {
51567
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/ECSClient.js
51568
+ class ECSClient extends import_client37.Client {
51015
51569
  config;
51016
51570
  constructor(...[configuration]) {
51017
51571
  const _config_0 = getRuntimeConfig5(configuration || {});
51018
51572
  super(_config_0);
51019
51573
  this.initConfig = _config_0;
51020
51574
  const _config_1 = resolveClientEndpointParameters3(_config_0);
51021
- const _config_2 = import_client34.resolveUserAgentConfig(_config_1);
51575
+ const _config_2 = import_client36.resolveUserAgentConfig(_config_1);
51022
51576
  const _config_3 = import_retry6.resolveRetryConfig(_config_2);
51023
51577
  const _config_4 = import_config39.resolveRegionConfig(_config_3);
51024
- const _config_5 = import_client34.resolveHostHeaderConfig(_config_4);
51578
+ const _config_5 = import_client36.resolveHostHeaderConfig(_config_4);
51025
51579
  const _config_6 = import_endpoints8.resolveEndpointConfig(_config_5);
51026
51580
  const _config_7 = resolveHttpAuthSchemeConfig3(_config_6);
51027
51581
  const _config_8 = resolveRuntimeExtensions3(_config_7, configuration?.extensions || []);
51028
51582
  this.config = _config_8;
51029
51583
  this.middlewareStack.use(import_schema4.getSchemaSerdePlugin(this.config));
51030
- this.middlewareStack.use(import_client34.getUserAgentPlugin(this.config));
51584
+ this.middlewareStack.use(import_client36.getUserAgentPlugin(this.config));
51031
51585
  this.middlewareStack.use(import_retry6.getRetryPlugin(this.config));
51032
51586
  this.middlewareStack.use(import_protocols10.getContentLengthPlugin(this.config));
51033
- this.middlewareStack.use(import_client34.getHostHeaderPlugin(this.config));
51034
- this.middlewareStack.use(import_client34.getLoggerPlugin(this.config));
51035
- this.middlewareStack.use(import_client34.getRecursionDetectionPlugin(this.config));
51587
+ this.middlewareStack.use(import_client36.getHostHeaderPlugin(this.config));
51588
+ this.middlewareStack.use(import_client36.getLoggerPlugin(this.config));
51589
+ this.middlewareStack.use(import_client36.getRecursionDetectionPlugin(this.config));
51036
51590
  this.middlewareStack.use(import_core2.getHttpAuthSchemeEndpointRuleSetPlugin(this.config, {
51037
51591
  httpAuthSchemeParametersProvider: defaultECSHttpAuthSchemeParametersProvider,
51038
51592
  identityProviderConfigProvider: async (config) => new import_core2.DefaultIdentityProviderConfig({
@@ -51046,26 +51600,26 @@ class ECSClient extends import_client35.Client {
51046
51600
  }
51047
51601
  }
51048
51602
 
51049
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/commandBuilder.js
51050
- var import_client36 = __toESM(require_client(), 1);
51603
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/commandBuilder.js
51604
+ var import_client38 = __toESM(require_client(), 1);
51051
51605
  var import_endpoints9 = __toESM(require_endpoints(), 1);
51052
- var command3 = import_client36.makeBuilder(commonParams3, "AmazonEC2ContainerServiceV20141113", "ECSClient", import_endpoints9.getEndpointPlugin);
51606
+ var command3 = import_client38.makeBuilder(commonParams3, "AmazonEC2ContainerServiceV20141113", "ECSClient", import_endpoints9.getEndpointPlugin);
51053
51607
  var _ep03 = {};
51054
51608
  var _mw03 = (Command, cs, config, o2) => [];
51055
51609
 
51056
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/DescribeTasksCommand.js
51610
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/DescribeTasksCommand.js
51057
51611
  class DescribeTasksCommand extends command3(_ep03, _mw03, "DescribeTasks", DescribeTasks$) {
51058
51612
  }
51059
51613
 
51060
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/ListTasksCommand.js
51614
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/ListTasksCommand.js
51061
51615
  class ListTasksCommand extends command3(_ep03, _mw03, "ListTasks", ListTasks$) {
51062
51616
  }
51063
51617
 
51064
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/RunTaskCommand.js
51618
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/RunTaskCommand.js
51065
51619
  class RunTaskCommand extends command3(_ep03, _mw03, "RunTask", RunTask$) {
51066
51620
  }
51067
51621
 
51068
- // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1126.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/StopTaskCommand.js
51622
+ // ../../node_modules/.bun/@aws-sdk+client-ecs@3.1127.0/node_modules/@aws-sdk/client-ecs/dist-es/commands/StopTaskCommand.js
51069
51623
  class StopTaskCommand extends command3(_ep03, _mw03, "StopTask", StopTask$) {
51070
51624
  }
51071
51625
 
@@ -51391,6 +51945,7 @@ var localRunExecutor = {
51391
51945
  // src/sdk/storage.ts
51392
51946
  var artifactStorageSeam = ArtifactStorage;
51393
51947
  // src/sdk/outputs.ts
51948
+ import { createHash as createHash12 } from "crypto";
51394
51949
  class DatabaseOnlyObjectStore {
51395
51950
  usesS3 = false;
51396
51951
  async materialize(run, artifact, body) {
@@ -51418,9 +51973,13 @@ function createGovernedArtifactWriter(options) {
51418
51973
  const storage2 = options.storage ?? new DatabaseOnlyObjectStore;
51419
51974
  return {
51420
51975
  async write(run, meta, body) {
51976
+ if (typeof body?.bodyText !== "string") {
51977
+ throw new TypeError("Governed artifacts require a text body before persistence");
51978
+ }
51421
51979
  const redacted = redactRunOutput(body.bodyText, config.redactPatterns);
51422
51980
  const redactedBody = { ...body, bodyText: redacted };
51423
- const outputBytes = new TextEncoder().encode(redacted).byteLength;
51981
+ const persistedBytes = new TextEncoder().encode(redacted);
51982
+ const outputBytes = persistedBytes.byteLength;
51424
51983
  if (outputBytes > config.perOutputBytes) {
51425
51984
  throw new GovernanceError(GOVERNANCE_ERROR_CODES.ARTIFACT_LIMIT_EXCEEDED, `output ${meta.relativePath} for run ${run.id} is ${outputBytes} bytes; the per-output limit is ${config.perOutputBytes}`, { gate: "perOutputBytes" });
51426
51985
  }
@@ -51432,6 +51991,8 @@ function createGovernedArtifactWriter(options) {
51432
51991
  const createdAt = new Date().toISOString();
51433
51992
  const stamped = {
51434
51993
  ...meta,
51994
+ byteSize: outputBytes,
51995
+ sha256: createHash12("sha256").update(persistedBytes).digest("hex"),
51435
51996
  visibility: options.visibility ?? config.defaultVisibility,
51436
51997
  ...config.artifactTtlSeconds !== undefined ? { expiresAt: expiresAtFor(createdAt, config.artifactTtlSeconds) } : {}
51437
51998
  };
@@ -51603,6 +52164,1011 @@ function createOfflineGate(options) {
51603
52164
  }
51604
52165
  };
51605
52166
  }
52167
+ // src/lib/remote-workspace.ts
52168
+ var record = (value) => !!value && typeof value === "object" && !Array.isArray(value);
52169
+ var cursor = (value) => typeof value === "string" && /^[A-Za-z0-9_-]{1,512}$/.test(value);
52170
+ var uuid = (value) => typeof value === "string" && /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i.test(value);
52171
+ function workspaceMembersQuery(options = {}) {
52172
+ if (!record(options) || Object.keys(options).some((key) => key !== "limit" && key !== "cursor") || options.limit !== undefined && (!Number.isInteger(options.limit) || options.limit < 1 || options.limit > 100) || options.cursor !== undefined && !cursor(options.cursor))
52173
+ throw new Error("Use a roster limit from 1 to 100 and an unchanged continuation cursor.");
52174
+ const query = new URLSearchParams;
52175
+ if (options.limit !== undefined)
52176
+ query.set("limit", String(options.limit));
52177
+ if (options.cursor !== undefined)
52178
+ query.set("cursor", options.cursor);
52179
+ return query.size ? `?${query}` : "";
52180
+ }
52181
+ function timestamp(value) {
52182
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z$/.test(value))
52183
+ return false;
52184
+ const time = Date.parse(value);
52185
+ return Number.isFinite(time) && new Date(time).toISOString().slice(0, 23) === value.slice(0, 23);
52186
+ }
52187
+ function parseMember(row, fail) {
52188
+ if (!record(row) || !uuid(row.membershipId) || !uuid(row.userId) || typeof row.email !== "string" || !row.email || !(row.displayName === null || typeof row.displayName === "string") || !isRole(row.role) || !timestamp(row.createdAt))
52189
+ return fail();
52190
+ return {
52191
+ membershipId: row.membershipId,
52192
+ userId: row.userId,
52193
+ email: row.email,
52194
+ displayName: row.displayName,
52195
+ role: row.role,
52196
+ createdAt: row.createdAt
52197
+ };
52198
+ }
52199
+ var isRole = (value) => typeof value === "string" && ["owner", "admin", "member", "viewer"].includes(value);
52200
+
52201
+ class WorkspaceMemberInputError extends Error {
52202
+ constructor() {
52203
+ super("Use an unchanged lowercase membership ID and the exact role and expected-role parameters from the roster.");
52204
+ this.name = "WorkspaceMemberInputError";
52205
+ }
52206
+ }
52207
+ function mutationInput(membershipId, input, roleChange) {
52208
+ if (typeof membershipId !== "string" || !uuid(membershipId) || membershipId !== membershipId.toLowerCase() || !record(input) || Object.keys(input).sort().join(",") !== (roleChange ? "expectedRole,role" : "expectedRole"))
52209
+ throw new WorkspaceMemberInputError;
52210
+ const expectedRole = input.expectedRole, role = roleChange ? input.role : undefined;
52211
+ if (!isRole(expectedRole) || roleChange && !isRole(role))
52212
+ throw new WorkspaceMemberInputError;
52213
+ return { membershipId, role, expectedRole };
52214
+ }
52215
+ function workspaceMemberRoleInput(membershipId, input) {
52216
+ const value = mutationInput(membershipId, input, true);
52217
+ return { membershipId: value.membershipId, body: { role: value.role, expectedRole: value.expectedRole } };
52218
+ }
52219
+ function workspaceMemberRemovalInput(membershipId, input) {
52220
+ const value = mutationInput(membershipId, input, false);
52221
+ return { membershipId: value.membershipId, body: { expectedRole: value.expectedRole } };
52222
+ }
52223
+ var invalidMemberResult = "The server returned an invalid workspace member result. Refresh the roster before another action.";
52224
+ function parseWorkspaceMemberRoleResult(value, membershipId, role) {
52225
+ const fail = () => {
52226
+ throw new Error(invalidMemberResult);
52227
+ };
52228
+ if (!record(value) || !uuid(value.organizationId) || typeof value.changed !== "boolean")
52229
+ return fail();
52230
+ const member = parseMember(value.member, fail);
52231
+ if (member.membershipId !== membershipId || member.role !== role)
52232
+ return fail();
52233
+ return { organizationId: value.organizationId, member, changed: value.changed };
52234
+ }
52235
+ function parseWorkspaceMemberRemovalResult(value, membershipId) {
52236
+ if (!record(value) || !uuid(value.organizationId) || value.membershipId !== membershipId || value.removed !== true || typeof value.alreadyRemoved !== "boolean")
52237
+ throw new Error(invalidMemberResult);
52238
+ return { organizationId: value.organizationId, membershipId, removed: true, alreadyRemoved: value.alreadyRemoved };
52239
+ }
52240
+ var workspaceMemberFailures = {
52241
+ INVALID_REQUEST: [400, "Provide the exact membership role parameters."],
52242
+ ACCOUNT_UNAVAILABLE: [403, "Account is unavailable."],
52243
+ INTERACTIVE_SESSION_REQUIRED: [403, "Fresh interactive sign-in is required."],
52244
+ WORKSPACE_ADMIN_REQUIRED: [403, "A current workspace owner or admin is required."],
52245
+ MEMBERSHIP_ACTION_FORBIDDEN: [403, "Your current workspace role cannot perform this membership action."],
52246
+ MEMBERSHIP_NOT_FOUND: [404, "Membership was not found in the current workspace."],
52247
+ SELF_REMOVAL_UNAVAILABLE: [409, "Leaving your own workspace is not available through member removal."],
52248
+ MEMBERSHIP_ROLE_CHANGED: [409, "The member role changed. Refresh the roster before another action."],
52249
+ LAST_OWNER_REQUIRED: [409, "The workspace must retain at least one active owner."],
52250
+ MEMBERSHIP_BUSY: [503, "Membership is busy. Refresh the roster before another action."]
52251
+ };
52252
+ function workspaceMemberFailure(value, status) {
52253
+ if (!record(value) || typeof value.code !== "string" || !Object.hasOwn(workspaceMemberFailures, value.code))
52254
+ return null;
52255
+ const code = value.code;
52256
+ return workspaceMemberFailures[code][0] === status ? code : null;
52257
+ }
52258
+ function parseWorkspaceMembersPage(value) {
52259
+ const fail = () => {
52260
+ throw new Error("The server returned an invalid workspace roster.");
52261
+ };
52262
+ if (!record(value) || !uuid(value.organizationId) || !Array.isArray(value.members) || value.members.length > 100 || !(value.nextCursor === null || cursor(value.nextCursor)) || !value.members.length && value.nextCursor !== null)
52263
+ return fail();
52264
+ const members = value.members.map((row) => parseMember(row, fail));
52265
+ if (new Set(members.map((row) => row.membershipId)).size !== members.length)
52266
+ return fail();
52267
+ return { organizationId: value.organizationId, members, nextCursor: value.nextCursor };
52268
+ }
52269
+ // src/lib/auth-store.ts
52270
+ function getApiUrl(action, env = process.env, options = {}) {
52271
+ return requireSkillsApiOrigin(action, env, options);
52272
+ }
52273
+
52274
+ // src/lib/remote-account.ts
52275
+ class RemoteCreditApprovalError extends Error {
52276
+ requiredCredits;
52277
+ maximumCredits;
52278
+ code = "CREDIT_APPROVAL_REQUIRED";
52279
+ constructor(requiredCredits, maximumCredits) {
52280
+ super(`This run requires ${requiredCredits} credits; the approved maximum is ${maximumCredits}. Quote the run and explicitly approve its cost.`);
52281
+ this.requiredCredits = requiredCredits;
52282
+ this.maximumCredits = maximumCredits;
52283
+ this.name = "RemoteCreditApprovalError";
52284
+ }
52285
+ }
52286
+ function creditCount(value) {
52287
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0 || value > 2147483647) {
52288
+ throw new Error("The Skills server returned an invalid credit count");
52289
+ }
52290
+ return value;
52291
+ }
52292
+ function parseRemoteRunQuote(value) {
52293
+ const quote = object(value);
52294
+ const pricing = object(quote.pricing);
52295
+ if (typeof quote.skill !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(quote.skill))
52296
+ throw new Error("Invalid quoted skill");
52297
+ const costCents = creditCount(pricing.costCredits ?? pricing.costCents);
52298
+ if (pricing.costCredits !== undefined && pricing.costCents !== undefined && pricing.costCents !== costCents)
52299
+ throw new Error("Inconsistent quoted credit count");
52300
+ if (quote.availability && object(quote.availability).status !== "available")
52301
+ throw new Error("This skill is unavailable for remote execution");
52302
+ return { ...quote, skill: quote.skill, pricing: { ...pricing, costCredits: costCents, costCents, formattedCost: `${costCents} credits` } };
52303
+ }
52304
+ function parseRemoteCreditPacks(value) {
52305
+ if (!Array.isArray(value))
52306
+ throw new Error("Invalid credit pack response");
52307
+ const ids = new Set;
52308
+ return value.map((value2) => {
52309
+ const row = object(value2);
52310
+ const counts = [row.credits, row.creditsCents, row.amountCents].filter((value3) => value3 !== undefined).map(creditCount);
52311
+ if (!counts.length || counts[0] === 0 || counts.some((count) => count !== counts[0]))
52312
+ throw new Error("Inconsistent credit pack counts");
52313
+ const credits = counts[0];
52314
+ const id = row.id ?? `credits_${credits}`;
52315
+ if (typeof id !== "string" || !/^[a-z0-9][a-z0-9_-]{0,99}$/.test(id) || ids.has(id))
52316
+ throw new Error("Invalid credit pack ID");
52317
+ if (id.startsWith("credits_") && id !== `credits_${credits}`)
52318
+ throw new Error("Inconsistent credit pack ID");
52319
+ ids.add(id);
52320
+ return { id, credits, ...row.expiresInDays === undefined ? {} : { expiresInDays: creditCount(row.expiresInDays) } };
52321
+ });
52322
+ }
52323
+ function parseRemoteBillingStatus(value) {
52324
+ const row = object(value);
52325
+ const counts = [row.creditBalance, row.balanceCents].filter((value2) => value2 !== undefined).map(creditCount);
52326
+ if (!counts.length || counts.some((count) => count !== counts[0]))
52327
+ throw new Error("Inconsistent credit balance");
52328
+ return {
52329
+ creditBalance: counts[0],
52330
+ formattedCreditBalance: `${counts[0]} credits`,
52331
+ ...typeof row.plan === "string" ? { plan: row.plan } : {},
52332
+ ...typeof row.hasPaymentMethod === "boolean" ? { hasPaymentMethod: row.hasPaymentMethod } : {}
52333
+ };
52334
+ }
52335
+ function parseRemoteCheckout(value) {
52336
+ const row = object(value);
52337
+ if (typeof row.url !== "string")
52338
+ throw new Error("Invalid checkout URL");
52339
+ const url = new URL(row.url);
52340
+ if (url.protocol !== "https:" || url.username || url.password)
52341
+ throw new Error("Invalid checkout URL");
52342
+ return { url: row.url };
52343
+ }
52344
+ function object(value) {
52345
+ if (!value || typeof value !== "object" || Array.isArray(value))
52346
+ throw new Error("Invalid Skills server response");
52347
+ return value;
52348
+ }
52349
+
52350
+ // src/lib/remote-files.ts
52351
+ import { createHash as createHash13 } from "crypto";
52352
+ var MAX_REMOTE_FILE_BYTES = 64 * 1024 * 1024;
52353
+ function describeRemoteFiles(files) {
52354
+ if (files.length > 10)
52355
+ throw new Error("At most 10 input files are supported");
52356
+ const names = new Set;
52357
+ let total = 0;
52358
+ return files.map((file) => {
52359
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/.test(file.name) || file.name === "." || file.name === ".." || names.has(file.name))
52360
+ throw new Error("Input file names must be unique safe basenames");
52361
+ names.add(file.name);
52362
+ total += file.bytes.byteLength;
52363
+ if (file.bytes.byteLength > 20 * 1024 * 1024 || total > 50 * 1024 * 1024)
52364
+ throw new Error("Input files exceed the supported size limit");
52365
+ return { name: file.name, sizeBytes: file.bytes.byteLength, sha256: sha256(file.bytes), contentType: file.contentType ?? "application/octet-stream" };
52366
+ });
52367
+ }
52368
+ function sha256(bytes) {
52369
+ return createHash13("sha256").update(bytes).digest("hex");
52370
+ }
52371
+ async function readBoundedResponse(response, maximum) {
52372
+ if (!Number.isSafeInteger(maximum) || maximum < 0 || maximum > MAX_REMOTE_FILE_BYTES)
52373
+ throw new Error("Invalid artifact size limit");
52374
+ const length = response.headers.get("content-length");
52375
+ if (length && (!/^\d+$/.test(length) || Number(length) > maximum)) {
52376
+ await response.body?.cancel();
52377
+ throw new Error("Artifact exceeds its declared size limit");
52378
+ }
52379
+ const reader = response.body?.getReader();
52380
+ if (!reader)
52381
+ return new Uint8Array;
52382
+ const chunks = [];
52383
+ let size = 0;
52384
+ try {
52385
+ while (true) {
52386
+ const next = await reader.read();
52387
+ if (next.done)
52388
+ break;
52389
+ size += next.value.byteLength;
52390
+ if (size > maximum)
52391
+ throw new Error("Artifact exceeds its declared size limit");
52392
+ chunks.push(next.value);
52393
+ }
52394
+ } catch (error) {
52395
+ await reader.cancel().catch(() => {});
52396
+ throw error;
52397
+ } finally {
52398
+ reader.releaseLock();
52399
+ }
52400
+ const bytes = new Uint8Array(size);
52401
+ let offset = 0;
52402
+ for (const chunk of chunks) {
52403
+ bytes.set(chunk, offset);
52404
+ offset += chunk.byteLength;
52405
+ }
52406
+ return bytes;
52407
+ }
52408
+
52409
+ // src/lib/remote-profile.ts
52410
+ function customerNamePatch(input, field) {
52411
+ if (!isRecord5(input) || Object.keys(input).length !== 1 || !Object.hasOwn(input, field))
52412
+ throw new Error("Provide only the requested name field.");
52413
+ const value = input[field];
52414
+ if (typeof value !== "string" || /[\p{Cc}\p{Cs}\u2028\u2029]/u.test(value) || !value.trim() || [...value.trim()].length > 100) {
52415
+ throw new Error("Use a name of 1\u2013100 characters without control characters or newlines.");
52416
+ }
52417
+ return { [field]: value.trim() };
52418
+ }
52419
+ function isRecord5(value) {
52420
+ return !!value && typeof value === "object" && !Array.isArray(value);
52421
+ }
52422
+ function string(value) {
52423
+ return typeof value === "string" && value.length > 0;
52424
+ }
52425
+ function parseUpdatedProfile(value) {
52426
+ const user = isRecord5(value) && value.user;
52427
+ if (!isRecord5(user) || !string(user.id) || !string(user.email) || !(user.displayName === null || typeof user.displayName === "string") || typeof user.role !== "string" || !["owner", "admin", "member", "viewer"].includes(user.role)) {
52428
+ throw new Error("The server returned an invalid account profile.");
52429
+ }
52430
+ return { user: { id: user.id, email: user.email, displayName: user.displayName, role: user.role } };
52431
+ }
52432
+ function parseUpdatedWorkspace(value) {
52433
+ const organization = isRecord5(value) && value.organization;
52434
+ if (!isRecord5(organization) || !string(organization.id) || !string(organization.slug) || !string(organization.name)) {
52435
+ throw new Error("The server returned an invalid workspace.");
52436
+ }
52437
+ return { organization: { id: organization.id, slug: organization.slug, name: organization.name } };
52438
+ }
52439
+
52440
+ // src/lib/remote-client.ts
52441
+ class RemoteRouteUnsupportedError extends Error {
52442
+ path;
52443
+ status;
52444
+ instance;
52445
+ constructor(path, status, instance) {
52446
+ super(`The configured Skills instance does not support ${path} (HTTP ${status}). ` + `The instance at ${instance} predates this client feature \u2014 upgrade the server, or ` + `use a client version that matches it.`);
52447
+ this.path = path;
52448
+ this.status = status;
52449
+ this.instance = instance;
52450
+ this.name = "RemoteRouteUnsupportedError";
52451
+ }
52452
+ }
52453
+
52454
+ class RemoteRequestError extends Error {
52455
+ path;
52456
+ status;
52457
+ constructor(path, status, _statusText) {
52458
+ super(`Remote request to ${path} failed: HTTP ${status}`);
52459
+ this.path = path;
52460
+ this.status = status;
52461
+ this.name = "RemoteRequestError";
52462
+ }
52463
+ }
52464
+
52465
+ class RemoteWorkspaceMemberError extends RemoteRequestError {
52466
+ code;
52467
+ constructor(path, code) {
52468
+ super(path, workspaceMemberFailures[code][0]);
52469
+ this.code = code;
52470
+ this.name = "RemoteWorkspaceMemberError";
52471
+ this.message = workspaceMemberFailures[code][1];
52472
+ }
52473
+ }
52474
+
52475
+ class RemoteCapabilityUnavailableError extends RemoteRequestError {
52476
+ code = "SUBSCRIPTION_CHECKOUT_UNAVAILABLE";
52477
+ constructor() {
52478
+ super("/api/v1/billing/checkout", 503);
52479
+ this.name = "RemoteCapabilityUnavailableError";
52480
+ this.message = "Subscription checkout is unavailable on the configured Skills server. " + "Use skills credits packs to view credit packs, or skills billing portal to manage an existing subscription.";
52481
+ }
52482
+ }
52483
+
52484
+ class RemoteSkillsClient {
52485
+ apiUrl;
52486
+ apiKey;
52487
+ capabilities;
52488
+ constructor(apiKey, apiUrl = getApiUrl()) {
52489
+ this.apiKey = apiKey;
52490
+ this.apiUrl = normalizeSkillsApiOrigin(apiUrl);
52491
+ }
52492
+ async request(path, options) {
52493
+ return fetch(`${this.apiUrl}${path}`, {
52494
+ ...options,
52495
+ redirect: "error",
52496
+ signal: options?.signal ?? AbortSignal.timeout(15000),
52497
+ headers: {
52498
+ Authorization: `Bearer ${this.apiKey}`,
52499
+ "Content-Type": "application/json",
52500
+ ...options?.headers
52501
+ }
52502
+ });
52503
+ }
52504
+ async requestNewRoute(path, options, opts = {}) {
52505
+ const response = await this.request(path, options);
52506
+ const routePath = path.split("?")[0];
52507
+ if (response.status === 404 || response.status === 405) {
52508
+ if (response.status === 404 && opts.domainNotFoundCodes?.length && await responseBodyCarriesCode(response, opts.domainNotFoundCodes)) {
52509
+ return response;
52510
+ }
52511
+ response.body?.cancel().catch(() => {});
52512
+ throw new RemoteRouteUnsupportedError(routePath, response.status, this.apiUrl);
52513
+ }
52514
+ if (!response.ok) {
52515
+ if (path === "/api/v1/billing/checkout" && options?.method === "POST" && response.status === 503 && await responseBodyCarriesCode(response, ["SUBSCRIPTION_CHECKOUT_UNAVAILABLE"])) {
52516
+ throw new RemoteCapabilityUnavailableError;
52517
+ }
52518
+ response.body?.cancel().catch(() => {});
52519
+ throw new RemoteRequestError(routePath, response.status, response.statusText);
52520
+ }
52521
+ return response;
52522
+ }
52523
+ async listSkills() {
52524
+ return this.arrayResponse("/api/v1/skills");
52525
+ }
52526
+ async getSkillMd(slug) {
52527
+ const res = await this.request(`/api/v1/skills/${slug}/skill.md`);
52528
+ if (!res.ok)
52529
+ return null;
52530
+ return res.text();
52531
+ }
52532
+ async getSkill(slug) {
52533
+ const res = await this.request(`/api/v1/skills/${slug}`);
52534
+ if (!res.ok)
52535
+ return null;
52536
+ return res.json();
52537
+ }
52538
+ async getSkillStatus(slug) {
52539
+ const res = await this.request(`/api/v1/skills/${encodeURIComponent(slug)}`, { method: "GET" });
52540
+ let body = null;
52541
+ try {
52542
+ body = await res.json();
52543
+ } catch {}
52544
+ return { status: res.status, body };
52545
+ }
52546
+ async submitRun(slug, input, args, approval = {}) {
52547
+ if (approval.idempotencyKey !== undefined && !/^[A-Za-z0-9._:-]{1,128}$/.test(approval.idempotencyKey))
52548
+ throw new Error("Idempotency key must be 1-128 URL-safe characters");
52549
+ if (approval.maxCostCents !== undefined)
52550
+ creditCount(approval.maxCostCents);
52551
+ if (approval.maxCredits !== undefined)
52552
+ creditCount(approval.maxCredits);
52553
+ if (approval.maxCredits !== undefined && approval.maxCostCents !== undefined && approval.maxCredits !== approval.maxCostCents)
52554
+ throw new Error("Credit approval fields disagree");
52555
+ const res = await this.request(`/api/v1/runs/${encodeURIComponent(slug)}`, {
52556
+ method: "POST",
52557
+ body: JSON.stringify({
52558
+ input,
52559
+ args,
52560
+ ...approval.maxCredits !== undefined ? { maxCredits: approval.maxCredits } : {},
52561
+ ...approval.maxCostCents !== undefined ? { maxCostCents: approval.maxCostCents } : {},
52562
+ ...approval.idempotencyKey !== undefined ? { idempotencyKey: approval.idempotencyKey } : {},
52563
+ ...approval.inputFiles !== undefined ? { files: approval.inputFiles } : {}
52564
+ })
52565
+ });
52566
+ return normalizeRemoteSkillRunContract(await res.json(), slug);
52567
+ }
52568
+ async quoteRun(slug, input = {}, args = []) {
52569
+ const response = await this.requestNewRoute(`/api/v1/skills/${encodeURIComponent(slug)}/quote`, {
52570
+ method: "POST",
52571
+ body: JSON.stringify({ input, args })
52572
+ });
52573
+ return parseRemoteRunQuote(await response.json());
52574
+ }
52575
+ getCapabilities() {
52576
+ if (!this.capabilities)
52577
+ this.capabilities = (async () => {
52578
+ const value = await (await this.requestNewRoute("/api/v1/capabilities")).json();
52579
+ if (value.contractVersion !== 1 || value.apiVersion !== 1 || !Array.isArray(value.capabilities) || value.capabilities.some((item) => typeof item !== "string"))
52580
+ throw new Error("Unsupported Skills server capability contract");
52581
+ const billing = value.billing;
52582
+ return { contractVersion: 1, apiVersion: 1, capabilities: value.capabilities, ...billing ? { billing } : {} };
52583
+ })();
52584
+ return this.capabilities;
52585
+ }
52586
+ async submitQuotedRun(slug, input = {}, args = [], approval = {}) {
52587
+ const maximum = creditCount(approval.maxCredits ?? approval.maxCostCents ?? 0);
52588
+ if (approval.maxCostCents !== undefined && approval.maxCostCents !== maximum)
52589
+ throw new Error("Credit approval fields disagree");
52590
+ const quote = await this.quoteRun(slug, input, args);
52591
+ if (quote.pricing.costCents > maximum)
52592
+ throw new RemoteCreditApprovalError(quote.pricing.costCents, maximum);
52593
+ const capabilities = await this.getCapabilities();
52594
+ if (!capabilities.capabilities.includes("runs.submit") || capabilities.billing?.boundedRunApproval !== true || capabilities.billing.unit !== "credits") {
52595
+ throw new Error("The configured server does not support bounded credit approval; refusing remote submission");
52596
+ }
52597
+ return this.submitRun(quote.skill, input, args, { ...approval, maxCredits: maximum, maxCostCents: maximum });
52598
+ }
52599
+ async getIdentity() {
52600
+ return (await this.requestNewRoute("/api/auth/whoami")).json();
52601
+ }
52602
+ async updateProfile(input) {
52603
+ const body = customerNamePatch(input, "displayName");
52604
+ return parseUpdatedProfile(await (await this.requestNewRoute("/api/v1/account/profile", { method: "PATCH", body: JSON.stringify(body) })).json());
52605
+ }
52606
+ async updateCurrentWorkspace(input) {
52607
+ const body = customerNamePatch(input, "name");
52608
+ return parseUpdatedWorkspace(await (await this.requestNewRoute("/api/v1/workspaces/current", { method: "PATCH", body: JSON.stringify(body) })).json());
52609
+ }
52610
+ async listWorkspaceMembers(options = {}) {
52611
+ const query = workspaceMembersQuery(options);
52612
+ const requestedCursor = options.cursor;
52613
+ const response = await this.requestNewRoute(`/api/v1/workspace/members${query}`);
52614
+ let value;
52615
+ try {
52616
+ value = await response.json();
52617
+ } catch {
52618
+ throw new Error("The server returned an invalid workspace roster.");
52619
+ }
52620
+ const page = parseWorkspaceMembersPage(value);
52621
+ if (requestedCursor !== undefined && page.nextCursor === requestedCursor)
52622
+ throw new Error("The server returned an invalid workspace roster.");
52623
+ return page;
52624
+ }
52625
+ async setWorkspaceMemberRole(membershipId, input) {
52626
+ const captured = workspaceMemberRoleInput(membershipId, input);
52627
+ const value = await this.requestWorkspaceMember(captured.membershipId, "PATCH", captured.body);
52628
+ return parseWorkspaceMemberRoleResult(value, captured.membershipId, captured.body.role);
52629
+ }
52630
+ async removeWorkspaceMember(membershipId, input) {
52631
+ const captured = workspaceMemberRemovalInput(membershipId, input);
52632
+ return parseWorkspaceMemberRemovalResult(await this.requestWorkspaceMember(captured.membershipId, "DELETE", captured.body), captured.membershipId);
52633
+ }
52634
+ async requestWorkspaceMember(membershipId, method, body) {
52635
+ const path = `/api/v1/workspace/members/${membershipId}`;
52636
+ const response = await this.request(path, { method, body: JSON.stringify(body) });
52637
+ let value;
52638
+ try {
52639
+ value = JSON.parse(new TextDecoder().decode(await readBoundedResponse(response, response.ok ? 64 * 1024 : 4096)));
52640
+ } catch {
52641
+ if (response.ok)
52642
+ throw new Error(invalidMemberResult);
52643
+ }
52644
+ if (!response.ok) {
52645
+ const code = workspaceMemberFailure(value, response.status);
52646
+ if (code)
52647
+ throw new RemoteWorkspaceMemberError(path, code);
52648
+ if (response.status === 404 || response.status === 405)
52649
+ throw new RemoteRouteUnsupportedError(path, response.status, this.apiUrl);
52650
+ throw new RemoteRequestError(path, response.status);
52651
+ }
52652
+ return value;
52653
+ }
52654
+ async listApiKeys() {
52655
+ return this.arrayResponse("/api/auth/keys");
52656
+ }
52657
+ async createApiKey(name, scopes) {
52658
+ if (!name.trim() || name.length > 100)
52659
+ throw new Error("API key name must be 1-100 characters");
52660
+ const value = await (await this.requestNewRoute("/api/auth/keys", { method: "POST", body: JSON.stringify({ name, ...scopes ? { scopes } : {} }) })).json();
52661
+ if (!value || typeof value.key !== "string" || !value.key.trim())
52662
+ throw new Error("The server did not return a created API key");
52663
+ return value;
52664
+ }
52665
+ async revokeApiKey(keyId) {
52666
+ return (await this.requestNewRoute(`/api/auth/keys/${encodeURIComponent(keyId)}`, { method: "DELETE" })).json();
52667
+ }
52668
+ async getBillingStatus() {
52669
+ return parseRemoteBillingStatus(await (await this.requestNewRoute("/api/v1/billing/status")).json());
52670
+ }
52671
+ async listCreditPacks() {
52672
+ return parseRemoteCreditPacks(await (await this.requestNewRoute("/api/v1/billing/credits")).json());
52673
+ }
52674
+ async createCreditCheckout(packId) {
52675
+ const packs = await this.listCreditPacks();
52676
+ if (!packs.some((pack) => pack.id === packId))
52677
+ throw new Error("Choose a credit pack returned by skills credits packs");
52678
+ return parseRemoteCheckout(await (await this.requestNewRoute("/api/v1/billing/credits", {
52679
+ method: "POST",
52680
+ body: JSON.stringify({ packId })
52681
+ })).json());
52682
+ }
52683
+ async getUsage() {
52684
+ return this.arrayResponse("/api/v1/billing/usage");
52685
+ }
52686
+ async listInvoices() {
52687
+ return this.arrayResponse("/api/v1/billing/invoices");
52688
+ }
52689
+ async createBillingCheckout() {
52690
+ return this.checkoutResponse("/api/v1/billing/checkout");
52691
+ }
52692
+ async createBillingPortal() {
52693
+ return this.checkoutResponse("/api/v1/billing/portal");
52694
+ }
52695
+ async cancelRun(runId2) {
52696
+ return this.controlRun(runId2, "cancel");
52697
+ }
52698
+ async resumeRun(runId2) {
52699
+ return this.controlRun(runId2, "resume");
52700
+ }
52701
+ async controlRun(runId2, action) {
52702
+ const response = await this.requestNewRoute(`/api/v1/runs/${encodeURIComponent(runId2)}/${action}`, { method: "POST", body: "{}" });
52703
+ return normalizeRemoteSkillRunContract(await response.json());
52704
+ }
52705
+ async checkoutResponse(path) {
52706
+ return parseRemoteCheckout(await (await this.requestNewRoute(path, { method: "POST", body: "{}" })).json());
52707
+ }
52708
+ async arrayResponse(path) {
52709
+ const rows = await (await this.requestNewRoute(path)).json();
52710
+ if (!Array.isArray(rows) || rows.some((row) => !row || typeof row !== "object" || Array.isArray(row)))
52711
+ throw new Error("Invalid Skills server list response");
52712
+ return rows;
52713
+ }
52714
+ async getRun(runId2) {
52715
+ const path = `/api/v1/runs/${encodeURIComponent(runId2)}`;
52716
+ const res = await this.request(path);
52717
+ if (res.status === 404)
52718
+ return null;
52719
+ if (!res.ok)
52720
+ throw new RemoteRequestError(path, res.status, res.statusText);
52721
+ return normalizeRemoteSkillRunContract(await res.json());
52722
+ }
52723
+ async getRunLogs(runId2) {
52724
+ return this.arrayResponse(`/api/v1/runs/${encodeURIComponent(runId2)}/logs`);
52725
+ }
52726
+ async listRuns(limit = 20) {
52727
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100)
52728
+ throw new Error("Run limit must be an integer from 1 to 100");
52729
+ return this.arrayResponse(`/api/v1/runs?limit=${limit}`);
52730
+ }
52731
+ async getRunArtifacts(runId2) {
52732
+ return this.arrayResponse(`/api/v1/runs/${encodeURIComponent(runId2)}/artifacts`);
52733
+ }
52734
+ async downloadRunArtifact(runId2, artifactId2) {
52735
+ return this.request(`/api/v1/runs/${encodeURIComponent(runId2)}/artifacts/${encodeURIComponent(artifactId2)}/download`, {
52736
+ method: "GET"
52737
+ });
52738
+ }
52739
+ async getVerifiedRunArtifact(runId2, artifactId2, maximumBytes = MAX_REMOTE_FILE_BYTES) {
52740
+ const artifacts = await this.getRunArtifacts(runId2);
52741
+ const artifact = artifacts.find((row) => row.id === artifactId2);
52742
+ if (!artifact)
52743
+ throw new Error("Run artifact not found");
52744
+ if (!Number.isSafeInteger(artifact.byteSize) || artifact.byteSize < 0 || artifact.byteSize > maximumBytes || typeof artifact.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(artifact.sha256))
52745
+ throw new Error("The server does not provide valid artifact integrity metadata");
52746
+ const response = await this.downloadRunArtifact(runId2, artifactId2);
52747
+ if (!response.ok)
52748
+ throw new RemoteRequestError("artifact download", response.status, response.statusText);
52749
+ const bytes = await readBoundedResponse(response, artifact.byteSize);
52750
+ if (bytes.byteLength !== artifact.byteSize || sha256(bytes) !== artifact.sha256)
52751
+ throw new Error("Artifact integrity verification failed");
52752
+ return { id: artifactId2, fileName: String(artifact.fileName ?? artifactId2), bytes, byteSize: bytes.byteLength, sha256: artifact.sha256 };
52753
+ }
52754
+ async submitQuotedRunWithFiles(slug, input, args, files, approval = {}) {
52755
+ const inputFiles = describeRemoteFiles(files);
52756
+ if (files.length && !(await this.getCapabilities()).capabilities.includes("runs.uploads"))
52757
+ throw new Error("The configured server does not support input uploads");
52758
+ const run = await this.submitQuotedRun(slug, input, args, { ...approval, inputFiles });
52759
+ if (run.error || !run.id || !files.length)
52760
+ return run;
52761
+ const pastUploads = (status) => typeof status === "string" && [
52762
+ "running",
52763
+ "completed",
52764
+ "failed",
52765
+ "cancelled",
52766
+ "expired",
52767
+ "pending_approval",
52768
+ "approved",
52769
+ "waiting"
52770
+ ].includes(status);
52771
+ if (pastUploads(run.status))
52772
+ return run;
52773
+ try {
52774
+ await this.uploadRunFiles(run.id, files);
52775
+ } catch {
52776
+ try {
52777
+ const current = await this.getRun(run.id);
52778
+ if (current && pastUploads(current.status))
52779
+ return current;
52780
+ } catch {}
52781
+ let cancellationRequested = false;
52782
+ try {
52783
+ await this.cancelRun(run.id);
52784
+ cancellationRequested = true;
52785
+ } catch {}
52786
+ throw new Error(`Input upload failed for run ${run.id}; ${cancellationRequested ? "cancellation requested" : "check its status and cancel the run"}`);
52787
+ }
52788
+ return run;
52789
+ }
52790
+ async uploadRunFiles(runId2, files) {
52791
+ const descriptors = describeRemoteFiles(files);
52792
+ const response = await this.requestNewRoute(`/api/v1/runs/${encodeURIComponent(runId2)}/uploads`, { method: "POST", body: JSON.stringify({ files: descriptors }) });
52793
+ const payload = await response.json();
52794
+ if (!Array.isArray(payload.files) || payload.files.length !== files.length || new Set(payload.files.map((file) => file.name)).size !== files.length)
52795
+ throw new Error("Invalid input upload response");
52796
+ for (const file of files) {
52797
+ const upload = payload.files.find((row) => row.name === file.name);
52798
+ if (!upload)
52799
+ throw new Error("Missing input upload URL");
52800
+ const url = new URL(upload.uploadUrl);
52801
+ if (url.username || url.password || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)))
52802
+ throw new Error("Unsafe input upload URL");
52803
+ const uploaded = await fetch(url, { method: "PUT", body: file.bytes, headers: { "Content-Type": file.contentType ?? "application/octet-stream" }, redirect: "error", signal: AbortSignal.timeout(60000) });
52804
+ if (!uploaded.ok)
52805
+ throw new Error("Input upload failed");
52806
+ await uploaded.body?.cancel();
52807
+ }
52808
+ }
52809
+ async publishSkill(manifest, bundle, ifMatch) {
52810
+ const form = new FormData;
52811
+ form.set("manifest", JSON.stringify(manifest));
52812
+ if (bundle) {
52813
+ form.set("bundle", new Blob([bundle], { type: "application/gzip" }), `${String(manifest.slug ?? "skill")}.tar.gz`);
52814
+ }
52815
+ const headers = { Authorization: `Bearer ${this.apiKey}` };
52816
+ if (ifMatch)
52817
+ headers["If-Match"] = ifMatch;
52818
+ return fetch(`${this.apiUrl}/api/v1/skills`, {
52819
+ method: "POST",
52820
+ headers,
52821
+ body: form,
52822
+ redirect: "error",
52823
+ signal: AbortSignal.timeout(15000)
52824
+ });
52825
+ }
52826
+ async deleteSkill(slug) {
52827
+ return this.request(`/api/v1/skills/${encodeURIComponent(slug)}`, { method: "DELETE" });
52828
+ }
52829
+ async downloadSkillBundle(slug) {
52830
+ return this.request(`/api/v1/skills/${encodeURIComponent(slug)}/bundle`, { method: "GET" });
52831
+ }
52832
+ async getBundle(slug, version2) {
52833
+ const path = version2 ? `/api/v1/skills/${encodeURIComponent(slug)}/versions/${encodeURIComponent(version2)}/bundle` : `/api/v1/skills/${encodeURIComponent(slug)}/bundle`;
52834
+ const response = await this.request(path, { method: "GET" });
52835
+ if (response.status === 404)
52836
+ return null;
52837
+ return response;
52838
+ }
52839
+ async listSkillVersions(slug) {
52840
+ const response = await this.requestNewRoute(`/api/v1/skills/${encodeURIComponent(slug)}/versions`, undefined, { domainNotFoundCodes: ["SKILL_NOT_FOUND"] });
52841
+ if (response.status === 404)
52842
+ return [];
52843
+ if (!response.ok)
52844
+ throw new Error(`versions request failed: ${response.status}`);
52845
+ const body = await readSkillVersionPayload(response);
52846
+ if (!isVersionRecord(body) || !Array.isArray(body.versions) || body.slug !== undefined && body.slug !== slug)
52847
+ throw new Error(INVALID_SKILL_VERSION_RESPONSE);
52848
+ return body.versions.map((entry) => normalizeSkillVersion(entry, slug));
52849
+ }
52850
+ async getSkillVersion(slug, version2) {
52851
+ const response = await this.requestNewRoute(`/api/v1/skills/${encodeURIComponent(slug)}/versions/${encodeURIComponent(version2)}`, undefined, { domainNotFoundCodes: ["SKILL_NOT_FOUND", "SKILL_VERSION_NOT_FOUND"] });
52852
+ if (response.status === 404)
52853
+ return null;
52854
+ if (!response.ok)
52855
+ throw new Error(`version request failed: ${response.status}`);
52856
+ return normalizeSkillVersion(await readSkillVersionPayload(response), slug, version2);
52857
+ }
52858
+ async listPins() {
52859
+ const response = await this.requestNewRoute("/api/v1/pins");
52860
+ return normalizePinList(await response.json());
52861
+ }
52862
+ async pin(slug, metadata) {
52863
+ const path = `/api/v1/pins/${encodeURIComponent(slug)}`;
52864
+ const response = await this.requestNewRoute(path, {
52865
+ method: "PUT",
52866
+ body: JSON.stringify({ ...metadata ? { metadata } : {} })
52867
+ });
52868
+ return normalizePin(await response.json());
52869
+ }
52870
+ async unpin(slug) {
52871
+ const path = `/api/v1/pins/${encodeURIComponent(slug)}`;
52872
+ const response = await this.requestNewRoute(path, { method: "DELETE" }, { domainNotFoundCodes: ["PIN_NOT_FOUND"] });
52873
+ return response.status !== 404;
52874
+ }
52875
+ async listTags() {
52876
+ const response = await this.requestNewRoute("/api/v1/tags");
52877
+ const payload = await response.json();
52878
+ if (!Array.isArray(payload)) {
52879
+ throw new Error("Remote tags payload did not match the expected contract (expected an array of tag names)");
52880
+ }
52881
+ const isName = (value) => typeof value === "string" && value.trim().length > 0;
52882
+ if (payload.every(isName))
52883
+ return payload;
52884
+ if (payload.every((tag) => tag !== null && typeof tag === "object" && !Array.isArray(tag) && isName(tag.name) && Number.isSafeInteger(tag.count) && tag.count >= 0)) {
52885
+ return payload.map((tag) => tag.name);
52886
+ }
52887
+ 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)");
52888
+ }
52889
+ async skillsByTag(tag) {
52890
+ const path = `/api/v1/tags/${encodeURIComponent(tag)}/skills`;
52891
+ const response = await this.requestNewRoute(path);
52892
+ return normalizeSkillSummaryList(await response.json());
52893
+ }
52894
+ async listUpdatedSince(since, options = {}) {
52895
+ const params = new URLSearchParams({ since });
52896
+ if (options.cursor)
52897
+ params.set("cursor", options.cursor);
52898
+ if (options.limit !== undefined)
52899
+ params.set("limit", String(options.limit));
52900
+ const response = await this.requestNewRoute(`/api/v1/skills/updated?${params.toString()}`);
52901
+ return normalizeUpdatedSincePage(await response.json());
52902
+ }
52903
+ }
52904
+ function requireOptionalString(record2, field) {
52905
+ if (record2[field] === undefined)
52906
+ return;
52907
+ if (typeof record2[field] !== "string") {
52908
+ throw new Error(`Remote payload did not match the expected contract (${field} must be a string when present)`);
52909
+ }
52910
+ return record2[field];
52911
+ }
52912
+ var INVALID_SKILL_VERSION_RESPONSE = "Remote skill version payload did not match the expected contract.";
52913
+ function isVersionRecord(value) {
52914
+ return value !== null && typeof value === "object" && !Array.isArray(value);
52915
+ }
52916
+ async function readSkillVersionPayload(response) {
52917
+ try {
52918
+ return await response.json();
52919
+ } catch {
52920
+ throw new Error(INVALID_SKILL_VERSION_RESPONSE);
52921
+ }
52922
+ }
52923
+ function normalizeSkillVersion(entry, slug, version2) {
52924
+ if (!isVersionRecord(entry) || typeof entry.slug !== "string" || !entry.slug.trim() || entry.slug !== slug || typeof entry.version !== "string" || !entry.version.trim() || version2 !== undefined && entry.version !== version2 || typeof entry.bundleSha256 !== "string" || !/^[a-f0-9]{64}$/i.test(entry.bundleSha256) || typeof entry.bundleByteSize !== "number" || !Number.isSafeInteger(entry.bundleByteSize) || entry.bundleByteSize < 0 || typeof entry.createdAt !== "string" || !entry.createdAt.trim() || entry.current !== undefined && typeof entry.current !== "boolean" || entry.storageKind !== undefined && typeof entry.storageKind !== "string" || entry.manifest !== undefined && !isVersionRecord(entry.manifest)) {
52925
+ throw new Error(INVALID_SKILL_VERSION_RESPONSE);
52926
+ }
52927
+ return entry;
52928
+ }
52929
+ function normalizePin(entry) {
52930
+ if (!entry || typeof entry !== "object") {
52931
+ throw new Error("Remote pin payload did not match the expected contract (expected an object)");
52932
+ }
52933
+ const record2 = entry;
52934
+ const slug = typeof record2.slug === "string" && record2.slug.trim() ? record2.slug.trim() : undefined;
52935
+ if (!slug) {
52936
+ throw new Error("Remote pin payload did not match the expected contract (missing slug)");
52937
+ }
52938
+ let metadata;
52939
+ if (record2.metadata !== undefined) {
52940
+ if (!record2.metadata || typeof record2.metadata !== "object" || Array.isArray(record2.metadata)) {
52941
+ throw new Error("Remote pin payload did not match the expected contract (metadata must be a JSON object when present)");
52942
+ }
52943
+ metadata = record2.metadata;
52944
+ }
52945
+ const pinnedAt = requireOptionalString(record2, "pinnedAt");
52946
+ return {
52947
+ slug,
52948
+ ...pinnedAt !== undefined ? { pinnedAt } : {},
52949
+ ...metadata ? { metadata } : {}
52950
+ };
52951
+ }
52952
+ function normalizePinList(payload) {
52953
+ if (!Array.isArray(payload)) {
52954
+ throw new Error("Remote pins payload did not match the expected contract (expected an array of pins)");
52955
+ }
52956
+ return payload.map(normalizePin);
52957
+ }
52958
+ function normalizeSkillSummary(entry) {
52959
+ if (!entry || typeof entry !== "object") {
52960
+ throw new Error("Remote skill payload did not match the expected contract (expected an object)");
52961
+ }
52962
+ const record2 = entry;
52963
+ const slug = typeof record2.slug === "string" && record2.slug.trim() ? record2.slug.trim() : undefined;
52964
+ if (!slug) {
52965
+ throw new Error("Remote skill payload did not match the expected contract (missing slug)");
52966
+ }
52967
+ return {
52968
+ slug,
52969
+ ...requireOptionalString(record2, "name") !== undefined ? { name: requireOptionalString(record2, "name") } : {},
52970
+ ...requireOptionalString(record2, "version") !== undefined ? { version: requireOptionalString(record2, "version") } : {},
52971
+ ...requireOptionalString(record2, "updatedAt") !== undefined ? { updatedAt: requireOptionalString(record2, "updatedAt") } : {}
52972
+ };
52973
+ }
52974
+ function normalizeSkillSummaryList(payload) {
52975
+ if (!Array.isArray(payload)) {
52976
+ throw new Error("Remote skills payload did not match the expected contract (expected an array of skills)");
52977
+ }
52978
+ return payload.map(normalizeSkillSummary);
52979
+ }
52980
+ async function responseBodyCarriesCode(response, codes) {
52981
+ const reader = response.body?.getReader();
52982
+ if (!reader)
52983
+ return false;
52984
+ const maximum = 8 * 1024;
52985
+ let deadline;
52986
+ const expired = new Promise((_, reject) => {
52987
+ deadline = setTimeout(() => reject(new Error("Error response read deadline exceeded")), 1000);
52988
+ });
52989
+ try {
52990
+ const chunks = [];
52991
+ let size = 0;
52992
+ while (true) {
52993
+ const next = await Promise.race([reader.read(), expired]);
52994
+ if (next.done)
52995
+ break;
52996
+ size += next.value.byteLength;
52997
+ if (size > maximum)
52998
+ return false;
52999
+ chunks.push(next.value);
53000
+ }
53001
+ const bytes = new Uint8Array(size);
53002
+ let offset = 0;
53003
+ for (const chunk of chunks) {
53004
+ bytes.set(chunk, offset);
53005
+ offset += chunk.byteLength;
53006
+ }
53007
+ const payload = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
53008
+ if (!payload || typeof payload !== "object" || Array.isArray(payload) || !Object.hasOwn(payload, "code"))
53009
+ return false;
53010
+ const code = payload.code;
53011
+ return typeof code === "string" && codes.includes(code);
53012
+ } catch {
53013
+ return false;
53014
+ } finally {
53015
+ clearTimeout(deadline);
53016
+ reader.cancel().catch(() => {});
53017
+ reader.releaseLock();
53018
+ }
53019
+ }
53020
+ function normalizeUpdatedSincePage(payload) {
53021
+ if (!payload || typeof payload !== "object") {
53022
+ throw new Error("Updated-since payload did not match the expected contract (expected an object)");
53023
+ }
53024
+ const record2 = payload;
53025
+ if (!Array.isArray(record2.skills)) {
53026
+ throw new Error("Updated-since payload did not match the expected contract (missing skills array)");
53027
+ }
53028
+ const skills = record2.skills.map(normalizeSkillSummary);
53029
+ const nextCursor = record2.nextCursor === undefined || record2.nextCursor === null ? null : record2.nextCursor;
53030
+ if (nextCursor !== null && typeof nextCursor !== "string") {
53031
+ throw new Error("Updated-since payload did not match the expected contract (nextCursor must be a string or absent)");
53032
+ }
53033
+ return { skills, nextCursor };
53034
+ }
53035
+ async function createRemoteSkillsClient(env = process.env) {
53036
+ const connection = await resolveSkillsConnection(env);
53037
+ return connection ? new RemoteSkillsClient(connection.apiKey, connection.apiOrigin) : null;
53038
+ }
53039
+ // src/lib/remote-auth.ts
53040
+ var MAX_ERROR_DETAIL_LENGTH = 200;
53041
+
53042
+ class HostedApiError extends Error {
53043
+ status;
53044
+ code;
53045
+ detail;
53046
+ endpoint;
53047
+ apiUrl;
53048
+ constructor(message, options = {}) {
53049
+ super(message);
53050
+ this.name = "HostedApiError";
53051
+ this.status = options.status;
53052
+ this.code = options.code;
53053
+ this.detail = options.detail;
53054
+ this.endpoint = options.endpoint;
53055
+ this.apiUrl = options.apiUrl;
53056
+ }
53057
+ }
53058
+ async function requestAuthApi(instance, path, options) {
53059
+ const url = normalizeSkillsApiOrigin(instance);
53060
+ const safeUrl = url;
53061
+ const endpoint = `${(options?.method || "GET").toUpperCase()} ${safeUrl}${path}`;
53062
+ let res;
53063
+ try {
53064
+ res = await fetch(`${url}${path}`, {
53065
+ ...options,
53066
+ redirect: "error",
53067
+ signal: options?.signal ?? AbortSignal.timeout(15000),
53068
+ headers: { "Content-Type": "application/json", ...options?.headers }
53069
+ });
53070
+ } catch (err) {
53071
+ throw new HostedApiError(`Unable to reach the Skills API: ${err.message}`, {
53072
+ endpoint,
53073
+ apiUrl: safeUrl
53074
+ });
53075
+ }
53076
+ const text = await res.text();
53077
+ const body = text ? parseJsonBody(text) : {};
53078
+ if (!res.ok) {
53079
+ const record2 = isRecord6(body) ? body : {};
53080
+ const detail = typeof record2.detail === "string" ? record2.detail : undefined;
53081
+ const error = typeof record2.error === "string" ? record2.error : undefined;
53082
+ const code = typeof record2.code === "string" ? record2.code : undefined;
53083
+ throw new HostedApiError(detail || error || `${res.status} ${res.statusText}`, {
53084
+ status: res.status,
53085
+ code,
53086
+ detail,
53087
+ endpoint,
53088
+ apiUrl: safeUrl
53089
+ });
53090
+ }
53091
+ return body;
53092
+ }
53093
+ function parseJsonBody(text) {
53094
+ try {
53095
+ return JSON.parse(text);
53096
+ } catch {
53097
+ return { detail: condenseErrorBody(text) };
53098
+ }
53099
+ }
53100
+ function condenseErrorBody(text) {
53101
+ const stripped = /<[a-z!/]/i.test(text) ? text.replace(/<(script|style)[\s\S]*?<\/\1>/gi, " ").replace(/<[^>]*>/g, " ") : text;
53102
+ const collapsed = stripped.replace(/\s+/g, " ").trim();
53103
+ if (collapsed.length <= MAX_ERROR_DETAIL_LENGTH)
53104
+ return collapsed;
53105
+ return `${collapsed.slice(0, MAX_ERROR_DETAIL_LENGTH - 1).trimEnd()}\u2026`;
53106
+ }
53107
+ function isRecord6(value) {
53108
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
53109
+ }
53110
+
53111
+ class RemoteSkillsAuthClient {
53112
+ apiOrigin;
53113
+ constructor(apiUrl) {
53114
+ this.apiOrigin = normalizeSkillsApiOrigin(apiUrl);
53115
+ }
53116
+ requestCode(email) {
53117
+ return this.request("/api/auth/login", { method: "POST", body: JSON.stringify({ email }) });
53118
+ }
53119
+ verifyCode(email, code) {
53120
+ return this.request("/api/auth/verify", { method: "POST", body: JSON.stringify({ email, code }) });
53121
+ }
53122
+ startDevice() {
53123
+ return this.request("/api/auth/device/start", { method: "POST", body: JSON.stringify({ client: "skills-sdk" }) });
53124
+ }
53125
+ pollDevice(deviceCode) {
53126
+ return this.request("/api/auth/device/token", { method: "POST", body: JSON.stringify({ deviceCode }) });
53127
+ }
53128
+ async sessionClient(email, code) {
53129
+ const apiOrigin = this.apiOrigin;
53130
+ if (!email.includes("@") || !/^\d{6}$/.test(code))
53131
+ throw new Error("Fresh email and six-digit verification code are required to manage this account");
53132
+ const login = await this.verifyCode(email, code);
53133
+ if (!login || typeof login.token !== "string" || !login.token)
53134
+ throw new Error("The server did not return an authorized account session");
53135
+ return new RemoteSkillsClient(login.token, apiOrigin);
53136
+ }
53137
+ async createApiKey(email, code, name, scopes) {
53138
+ return (await this.sessionClient(email, code)).createApiKey(name, scopes);
53139
+ }
53140
+ async listApiKeys(email, code) {
53141
+ return (await this.sessionClient(email, code)).listApiKeys();
53142
+ }
53143
+ async revokeApiKey(email, code, keyId) {
53144
+ return (await this.sessionClient(email, code)).revokeApiKey(keyId);
53145
+ }
53146
+ async updateProfile(email, code, input) {
53147
+ customerNamePatch(input, "displayName");
53148
+ return (await this.sessionClient(email, code)).updateProfile(input);
53149
+ }
53150
+ async updateCurrentWorkspace(email, code, input) {
53151
+ customerNamePatch(input, "name");
53152
+ return (await this.sessionClient(email, code)).updateCurrentWorkspace(input);
53153
+ }
53154
+ async listWorkspaceMembers(email, code, options = {}) {
53155
+ workspaceMembersQuery(options);
53156
+ return (await this.sessionClient(email, code)).listWorkspaceMembers(options);
53157
+ }
53158
+ async setWorkspaceMemberRole(email, code, membershipId, input) {
53159
+ const captured = workspaceMemberRoleInput(membershipId, input);
53160
+ return (await this.sessionClient(email, code)).setWorkspaceMemberRole(captured.membershipId, captured.body);
53161
+ }
53162
+ async removeWorkspaceMember(email, code, membershipId, input) {
53163
+ const captured = workspaceMemberRemovalInput(membershipId, input);
53164
+ return (await this.sessionClient(email, code)).removeWorkspaceMember(captured.membershipId, captured.body);
53165
+ }
53166
+ request(path, options) {
53167
+ if (!["/api/auth/login", "/api/auth/verify", "/api/auth/device/start", "/api/auth/device/token", "/api/auth/keys", "/api/auth/whoami"].includes(path))
53168
+ throw new Error("Unsupported authentication operation");
53169
+ return requestAuthApi(this.apiOrigin, path, options);
53170
+ }
53171
+ }
51606
53172
  export {
51607
53173
  validateRunLifecycleEvent,
51608
53174
  startedByFor,
@@ -51612,6 +53178,7 @@ export {
51612
53178
  skillsCredentialFiles,
51613
53179
  skillsCredentialFilePath,
51614
53180
  settleRun,
53181
+ selectsSkillsLocalMode,
51615
53182
  runTerminalSchema,
51616
53183
  runProtocolSchema,
51617
53184
  runPointersOf,
@@ -51639,6 +53206,7 @@ export {
51639
53206
  leaseGenerationOf,
51640
53207
  isValidSkillSlug,
51641
53208
  isTerminalStatus,
53209
+ isSkillsLocalOptIn,
51642
53210
  isActiveStatus,
51643
53211
  getServerSkillMd,
51644
53212
  getServerSkill,
@@ -51656,6 +53224,7 @@ export {
51656
53224
  createRunStateMachine,
51657
53225
  createRunService,
51658
53226
  createRunEventEmitter,
53227
+ createRemoteSkillsClient,
51659
53228
  createReceiptService,
51660
53229
  createOfflineGate,
51661
53230
  createImageProfileRegistry,
@@ -51677,9 +53246,17 @@ export {
51677
53246
  SqliteRunExecutionStore,
51678
53247
  SqliteGovernanceStore,
51679
53248
  SkillsFleetCredentialError,
53249
+ SKILLS_LOCAL_OPT_IN_ENV_KEYS,
51680
53250
  SKILLS_APP,
51681
53251
  SKILLS_API_URL_ENV,
51682
53252
  SKILLS_API_KEY_ENV,
53253
+ RemoteWorkspaceMemberError,
53254
+ RemoteSkillsClient,
53255
+ RemoteSkillsAuthClient,
53256
+ RemoteRouteUnsupportedError,
53257
+ RemoteRequestError,
53258
+ RemoteCreditApprovalError,
53259
+ RemoteCapabilityUnavailableError,
51683
53260
  RUN_PROTOCOL_VERSION,
51684
53261
  RUN_PROTOCOL_STATES,
51685
53262
  RUN_LIFECYCLE_EVENT_TYPES,
@@ -51693,6 +53270,7 @@ export {
51693
53270
  MemoryGovernanceStore,
51694
53271
  LEGAL_TRANSITIONS,
51695
53272
  ImageProfileResolutionError,
53273
+ HostedApiError,
51696
53274
  GovernanceError,
51697
53275
  GOVERNANCE_ERROR_CODES,
51698
53276
  EcsDispatcher,