@buzzni/saycode-cli 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -45,7 +45,7 @@ function _mergeNamespaces(n, m) {
45
45
  }
46
46
  return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
47
47
  }
48
- const version$2 = "0.7.0";
48
+ const version$2 = "0.7.1";
49
49
  const manifest = {
50
50
  version: version$2
51
51
  };
@@ -12696,7 +12696,7 @@ function normalizeConnectors(raw) {
12696
12696
  }
12697
12697
  return out;
12698
12698
  }
12699
- const PROVIDERS$1 = ["claude", "codex"];
12699
+ const PROVIDERS = ["claude", "codex"];
12700
12700
  const ROTATION_STATES = [
12701
12701
  "stopped",
12702
12702
  "starting",
@@ -12734,7 +12734,7 @@ function nullableNum(value2) {
12734
12734
  return typeof value2 === "number" && Number.isFinite(value2) ? value2 : null;
12735
12735
  }
12736
12736
  function provider(value2) {
12737
- return PROVIDERS$1.includes(str$1(value2)) ? str$1(value2) : null;
12737
+ return PROVIDERS.includes(str$1(value2)) ? str$1(value2) : null;
12738
12738
  }
12739
12739
  function parseBundle(value2) {
12740
12740
  const row2 = record$8(value2);
@@ -22621,9 +22621,9 @@ function resolvedProjectPreviewRelayUrl(input) {
22621
22621
  }
22622
22622
  return `${input.syncBaseUrl}/v1/preview/${encodeURIComponent(input.machineId)}/${input.port}/?ptoken=${encodeURIComponent(response.token)}`;
22623
22623
  }
22624
- const BASE64_PATTERN$2 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
22624
+ const BASE64_PATTERN$3 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
22625
22625
  function versionedAutomationBase64(value2, maxBytes, exactBytes) {
22626
- if (typeof value2 !== "string" || !value2 || value2.length > Math.ceil(maxBytes / 3) * 4 || !BASE64_PATTERN$2.test(value2)) {
22626
+ if (typeof value2 !== "string" || !value2 || value2.length > Math.ceil(maxBytes / 3) * 4 || !BASE64_PATTERN$3.test(value2)) {
22627
22627
  throw new Error("automation-response-invalid");
22628
22628
  }
22629
22629
  const decoded = Buffer$1.from(value2, "base64");
@@ -32951,9 +32951,9 @@ function channelText(text2) {
32951
32951
  }
32952
32952
  const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
32953
32953
  const RAW_ED25519_PUBLIC_KEY_BYTES = 32;
32954
- const BASE64_PATTERN$1 = /^[A-Za-z0-9+/]+={0,2}$/;
32954
+ const BASE64_PATTERN$2 = /^[A-Za-z0-9+/]+={0,2}$/;
32955
32955
  function createExtensionCatalogVerifier(publicKeyBase64) {
32956
- if (!publicKeyBase64 || !BASE64_PATTERN$1.test(publicKeyBase64) || publicKeyBase64.length % 4 !== 0) {
32956
+ if (!publicKeyBase64 || !BASE64_PATTERN$2.test(publicKeyBase64) || publicKeyBase64.length % 4 !== 0) {
32957
32957
  throw new Error("extension catalog public key must be base64");
32958
32958
  }
32959
32959
  const raw = Buffer.from(publicKeyBase64, "base64");
@@ -32976,14 +32976,14 @@ function createExtensionCatalogVerifier(publicKeyBase64) {
32976
32976
  const MAX_EXTENSION_CATALOG_PAYLOAD_BYTES = 256 * 1024;
32977
32977
  const EXTENSION_CATALOG_SCHEMA_VERSION = 2;
32978
32978
  const RELEASE_URL_PREFIX = "https://github.com/buzzni/saycode-extensions/releases/";
32979
- const ID_PATTERN$3 = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
32980
- const SEMVER_PATTERN$1 = /^\d+\.\d+\.\d+$/;
32981
- const SHA256_PATTERN = /^[a-f0-9]{64}$/;
32982
- const BASE64_PATTERN = /^[A-Za-z0-9+/]+={0,2}$/;
32979
+ const ID_PATTERN$4 = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
32980
+ const SEMVER_PATTERN$2 = /^\d+\.\d+\.\d+$/;
32981
+ const SHA256_PATTERN$1 = /^[a-f0-9]{64}$/;
32982
+ const BASE64_PATTERN$1 = /^[A-Za-z0-9+/]+={0,2}$/;
32983
32983
  const ISO_INSTANT_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
32984
32984
  const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
32985
32985
  function decodeBase64(value2, path) {
32986
- if (!BASE64_PATTERN.test(value2) || value2.length % 4 !== 0) fail$7(path, "expected base64");
32986
+ if (!BASE64_PATTERN$1.test(value2) || value2.length % 4 !== 0) fail$7(path, "expected base64");
32987
32987
  const padding = value2.endsWith("==") ? 2 : value2.endsWith("=") ? 1 : 0;
32988
32988
  const bytes = new Uint8Array(value2.length / 4 * 3 - padding);
32989
32989
  let offset = 0;
@@ -33022,16 +33022,16 @@ function releaseUrl(value2, path) {
33022
33022
  }
33023
33023
  return parsed2;
33024
33024
  }
33025
- function descriptor(value2, path) {
33025
+ function descriptor$1(value2, path) {
33026
33026
  const record2 = objectWithExactKeys(value2, ["id", "version", "releaseUrl", "archiveUrl", "sha256"], path);
33027
- const id2 = text$3(record2.id, `${path}.id`, ID_PATTERN$3);
33027
+ const id2 = text$3(record2.id, `${path}.id`, ID_PATTERN$4);
33028
33028
  if (id2.includes("..")) fail$7(`${path}.id`, "malformed value");
33029
33029
  return {
33030
33030
  id: id2,
33031
- version: text$3(record2.version, `${path}.version`, SEMVER_PATTERN$1),
33031
+ version: text$3(record2.version, `${path}.version`, SEMVER_PATTERN$2),
33032
33032
  releaseUrl: releaseUrl(record2.releaseUrl, `${path}.releaseUrl`),
33033
33033
  archiveUrl: releaseUrl(record2.archiveUrl, `${path}.archiveUrl`),
33034
- sha256: text$3(record2.sha256, `${path}.sha256`, SHA256_PATTERN)
33034
+ sha256: text$3(record2.sha256, `${path}.sha256`, SHA256_PATTERN$1)
33035
33035
  };
33036
33036
  }
33037
33037
  function revocation(value2, path) {
@@ -33039,13 +33039,13 @@ function revocation(value2, path) {
33039
33039
  const record2 = value2;
33040
33040
  const keys2 = Object.keys(record2).sort().join(",");
33041
33041
  if (keys2 !== "id,version" && keys2 !== "id,reason,version") fail$7(path, "unexpected fields");
33042
- const id2 = text$3(record2.id, `${path}.id`, ID_PATTERN$3);
33042
+ const id2 = text$3(record2.id, `${path}.id`, ID_PATTERN$4);
33043
33043
  if (id2.includes("..")) fail$7(`${path}.id`, "malformed value");
33044
33044
  return {
33045
33045
  id: id2,
33046
33046
  // Exact versions only: ADR-048 has no wildcard, so a mistaken entry costs one version,
33047
33047
  // not an entire extension.
33048
- version: text$3(record2.version, `${path}.version`, SEMVER_PATTERN$1),
33048
+ version: text$3(record2.version, `${path}.version`, SEMVER_PATTERN$2),
33049
33049
  ...record2.reason === void 0 ? {} : { reason: text$3(record2.reason, `${path}.reason`, /^.{1,200}$/s) }
33050
33050
  };
33051
33051
  }
@@ -33061,7 +33061,7 @@ function parsePayload(value2) {
33061
33061
  if (record2.schemaVersion !== EXTENSION_CATALOG_SCHEMA_VERSION) {
33062
33062
  fail$7("catalog.schemaVersion", `unsupported catalog schema ${String(record2.schemaVersion)}`);
33063
33063
  }
33064
- const extensions = array$2(record2.extensions, "catalog.extensions").map((entry, index) => descriptor(entry, `catalog.extensions[${index}]`));
33064
+ const extensions = array$2(record2.extensions, "catalog.extensions").map((entry, index) => descriptor$1(entry, `catalog.extensions[${index}]`));
33065
33065
  if (new Set(extensions.map((entry) => entry.id)).size !== extensions.length) {
33066
33066
  fail$7("catalog.extensions", "duplicate extension id");
33067
33067
  }
@@ -33707,9 +33707,9 @@ async function reconcileOne(spec, deps) {
33707
33707
  if (deps.isRevoked(spec.extensionId, spec.version)) return "revoked";
33708
33708
  let current = deps.registry.get(spec.extensionId);
33709
33709
  if (current?.installedVersion !== spec.version) {
33710
- const descriptor2 = deps.catalog.descriptorFor(spec.extensionId);
33711
- if (!descriptor2 || descriptor2.version !== spec.version) return "unavailable";
33712
- await deps.store.install(await deps.catalog.downloadArchive(descriptor2));
33710
+ if (await deps.official.versionOf(spec.extensionId) !== spec.version) return "unavailable";
33711
+ const installed = await deps.store.install(await deps.official.archive(spec.extensionId));
33712
+ if (installed.id !== spec.extensionId || installed.version !== spec.version) return "failed";
33713
33713
  current = await deps.registry.apply(spec.extensionId, current ? { type: "update-installed", version: spec.version } : { type: "installed", version: spec.version });
33714
33714
  }
33715
33715
  if (!current) return "failed";
@@ -33740,474 +33740,9 @@ async function reconcileHostExtensions(desired, deps) {
33740
33740
  }
33741
33741
  return result;
33742
33742
  }
33743
- function describe(secretKey) {
33744
- const { publicKey } = nacl.box.keyPair.fromSecretKey(secretKey);
33745
- const digest = createHash("sha256").update(publicKey).digest("hex").slice(0, 16).toUpperCase();
33746
- return {
33747
- publicKey,
33748
- secretKey,
33749
- publicKeyBase64: Buffer.from(publicKey).toString("base64"),
33750
- fingerprint: digest.match(/.{4}/g).join("-")
33751
- };
33752
- }
33753
- async function openChannelHostKey(input) {
33754
- if (!input.safeStorage.isEncryptionAvailable()) return null;
33755
- const path = join(input.dir, "host-key.v1.json");
33756
- let text2 = null;
33757
- try {
33758
- text2 = await readFile(path, "utf8");
33759
- } catch (error) {
33760
- if (error.code !== "ENOENT") throw error;
33761
- }
33762
- if (text2 !== null) {
33763
- const parsed2 = JSON.parse(text2);
33764
- if (parsed2.v !== 1 || typeof parsed2.sealed !== "string") throw new Error("channel host key file is unreadable");
33765
- const secret = Buffer.from(input.safeStorage.decryptString(Buffer.from(parsed2.sealed, "base64")), "base64");
33766
- if (secret.length !== nacl.box.secretKeyLength) throw new Error("channel host key file is unreadable");
33767
- return describe(new Uint8Array(secret));
33768
- }
33769
- const { secretKey } = nacl.box.keyPair();
33770
- await mkdir(input.dir, { recursive: true, mode: 448 });
33771
- const sealed2 = input.safeStorage.encryptString(Buffer.from(secretKey).toString("base64")).toString("base64");
33772
- const staging = `${path}.${process.pid}.tmp`;
33773
- await writeFile(staging, JSON.stringify({ v: 1, sealed: sealed2 }), { mode: 384 });
33774
- await rename(staging, path);
33775
- return describe(secretKey);
33776
- }
33777
- function defaultIsAlive(pid) {
33778
- try {
33779
- process.kill(pid, 0);
33780
- return true;
33781
- } catch (error) {
33782
- return error.code === "EPERM";
33783
- }
33784
- }
33785
- async function acquireChannelHostLock(input) {
33786
- const path = join(input.dir, "host.lock");
33787
- const isAlive = input.isAlive ?? defaultIsAlive;
33788
- for (let attempt2 = 0; attempt2 < 2; attempt2 += 1) {
33789
- try {
33790
- const handle = await open(path, "wx", 384);
33791
- await handle.writeFile(JSON.stringify({ pid: process.pid, startedAt: Date.now() }));
33792
- await handle.close();
33793
- return {
33794
- kind: "held",
33795
- release: async () => {
33796
- const current = await readFile(path, "utf8").then((text2) => JSON.parse(text2), () => null);
33797
- if (current?.pid === process.pid) await rm(path, { force: true });
33798
- }
33799
- };
33800
- } catch (error) {
33801
- if (error.code !== "EEXIST") throw error;
33802
- }
33803
- let holder = null;
33804
- try {
33805
- const parsed2 = JSON.parse(await readFile(path, "utf8"));
33806
- holder = typeof parsed2.pid === "number" && Number.isSafeInteger(parsed2.pid) ? parsed2.pid : null;
33807
- } catch {
33808
- holder = null;
33809
- }
33810
- if (holder === null || isAlive(holder)) return { kind: "refused" };
33811
- await rm(path, { force: true });
33812
- }
33813
- return { kind: "refused" };
33814
- }
33815
- function isBytes(a) {
33816
- return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
33817
- }
33818
- function abytes(value2, length, title2 = "") {
33819
- const bytes = isBytes(value2);
33820
- const len = value2?.length;
33821
- const needsLen = length !== void 0;
33822
- if (!bytes || needsLen) {
33823
- const prefix = title2 && `"${title2}" `;
33824
- const ofLen = "";
33825
- const got = bytes ? `length=${len}` : `type=${typeof value2}`;
33826
- const message = prefix + "expected Uint8Array" + ofLen + ", got " + got;
33827
- if (!bytes)
33828
- throw new TypeError(message);
33829
- throw new RangeError(message);
33830
- }
33831
- return value2;
33832
- }
33833
- function aexists(instance, checkFinished = true) {
33834
- if (instance.destroyed)
33835
- throw new Error("Hash instance has been destroyed");
33836
- if (checkFinished && instance.finished)
33837
- throw new Error("Hash#digest() has already been called");
33838
- }
33839
- function aoutput(out, instance) {
33840
- abytes(out, void 0, "digestInto() output");
33841
- const min = instance.outputLen;
33842
- if (out.length < min) {
33843
- throw new RangeError('"digestInto() output" expected to be of length >=' + min);
33844
- }
33845
- }
33846
- function clean(...arrays) {
33847
- for (let i = 0; i < arrays.length; i++) {
33848
- arrays[i].fill(0);
33849
- }
33850
- }
33851
- function createView(arr) {
33852
- return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
33853
- }
33854
- function rotr(word, shift) {
33855
- return word << 32 - shift | word >>> shift;
33856
- }
33857
- const hasHexBuiltin = /* @__PURE__ */ (() => (
33858
- // @ts-ignore
33859
- typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
33860
- ))();
33861
- const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
33862
- function bytesToHex(bytes) {
33863
- abytes(bytes);
33864
- if (hasHexBuiltin)
33865
- return bytes.toHex();
33866
- let hex = "";
33867
- for (let i = 0; i < bytes.length; i++) {
33868
- hex += hexes[bytes[i]];
33869
- }
33870
- return hex;
33871
- }
33872
- function createHasher(hashCons, info = {}) {
33873
- const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
33874
- const tmp = hashCons(void 0);
33875
- hashC.outputLen = tmp.outputLen;
33876
- hashC.blockLen = tmp.blockLen;
33877
- hashC.canXOF = tmp.canXOF;
33878
- hashC.create = (opts) => hashCons(opts);
33879
- Object.assign(hashC, info);
33880
- return Object.freeze(hashC);
33881
- }
33882
- const oidNist = (suffix) => ({
33883
- // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
33884
- // Larger suffix values would need base-128 OID encoding and a different length byte.
33885
- oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
33886
- });
33887
- function Chi(a, b, c) {
33888
- return a & b ^ ~a & c;
33889
- }
33890
- function Maj(a, b, c) {
33891
- return a & b ^ a & c ^ b & c;
33892
- }
33893
- class HashMD {
33894
- blockLen;
33895
- outputLen;
33896
- canXOF = false;
33897
- padOffset;
33898
- isLE;
33899
- // For partial updates less than block size
33900
- buffer;
33901
- view;
33902
- finished = false;
33903
- length = 0;
33904
- pos = 0;
33905
- destroyed = false;
33906
- constructor(blockLen, outputLen, padOffset, isLE) {
33907
- this.blockLen = blockLen;
33908
- this.outputLen = outputLen;
33909
- this.padOffset = padOffset;
33910
- this.isLE = isLE;
33911
- this.buffer = new Uint8Array(blockLen);
33912
- this.view = createView(this.buffer);
33913
- }
33914
- update(data) {
33915
- aexists(this);
33916
- abytes(data);
33917
- const { view, buffer, blockLen } = this;
33918
- const len = data.length;
33919
- for (let pos = 0; pos < len; ) {
33920
- const take = Math.min(blockLen - this.pos, len - pos);
33921
- if (take === blockLen) {
33922
- const dataView = createView(data);
33923
- for (; blockLen <= len - pos; pos += blockLen)
33924
- this.process(dataView, pos);
33925
- continue;
33926
- }
33927
- buffer.set(data.subarray(pos, pos + take), this.pos);
33928
- this.pos += take;
33929
- pos += take;
33930
- if (this.pos === blockLen) {
33931
- this.process(view, 0);
33932
- this.pos = 0;
33933
- }
33934
- }
33935
- this.length += data.length;
33936
- this.roundClean();
33937
- return this;
33938
- }
33939
- digestInto(out) {
33940
- aexists(this);
33941
- aoutput(out, this);
33942
- this.finished = true;
33943
- const { buffer, view, blockLen, isLE } = this;
33944
- let { pos } = this;
33945
- buffer[pos++] = 128;
33946
- clean(this.buffer.subarray(pos));
33947
- if (this.padOffset > blockLen - pos) {
33948
- this.process(view, 0);
33949
- pos = 0;
33950
- }
33951
- for (let i = pos; i < blockLen; i++)
33952
- buffer[i] = 0;
33953
- view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
33954
- this.process(view, 0);
33955
- const oview = createView(out);
33956
- const len = this.outputLen;
33957
- if (len % 4)
33958
- throw new Error("_sha2: outputLen must be aligned to 32bit");
33959
- const outLen = len / 4;
33960
- const state = this.get();
33961
- if (outLen > state.length)
33962
- throw new Error("_sha2: outputLen bigger than state");
33963
- for (let i = 0; i < outLen; i++)
33964
- oview.setUint32(4 * i, state[i], isLE);
33965
- }
33966
- digest() {
33967
- const { buffer, outputLen } = this;
33968
- this.digestInto(buffer);
33969
- const res = buffer.slice(0, outputLen);
33970
- this.destroy();
33971
- return res;
33972
- }
33973
- _cloneInto(to) {
33974
- to ||= new this.constructor();
33975
- to.set(...this.get());
33976
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
33977
- to.destroyed = destroyed;
33978
- to.finished = finished;
33979
- to.length = length;
33980
- to.pos = pos;
33981
- if (length % blockLen)
33982
- to.buffer.set(buffer);
33983
- return to;
33984
- }
33985
- clone() {
33986
- return this._cloneInto();
33987
- }
33988
- }
33989
- const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
33990
- 1779033703,
33991
- 3144134277,
33992
- 1013904242,
33993
- 2773480762,
33994
- 1359893119,
33995
- 2600822924,
33996
- 528734635,
33997
- 1541459225
33998
- ]);
33999
- const SHA256_K = /* @__PURE__ */ Uint32Array.from([
34000
- 1116352408,
34001
- 1899447441,
34002
- 3049323471,
34003
- 3921009573,
34004
- 961987163,
34005
- 1508970993,
34006
- 2453635748,
34007
- 2870763221,
34008
- 3624381080,
34009
- 310598401,
34010
- 607225278,
34011
- 1426881987,
34012
- 1925078388,
34013
- 2162078206,
34014
- 2614888103,
34015
- 3248222580,
34016
- 3835390401,
34017
- 4022224774,
34018
- 264347078,
34019
- 604807628,
34020
- 770255983,
34021
- 1249150122,
34022
- 1555081692,
34023
- 1996064986,
34024
- 2554220882,
34025
- 2821834349,
34026
- 2952996808,
34027
- 3210313671,
34028
- 3336571891,
34029
- 3584528711,
34030
- 113926993,
34031
- 338241895,
34032
- 666307205,
34033
- 773529912,
34034
- 1294757372,
34035
- 1396182291,
34036
- 1695183700,
34037
- 1986661051,
34038
- 2177026350,
34039
- 2456956037,
34040
- 2730485921,
34041
- 2820302411,
34042
- 3259730800,
34043
- 3345764771,
34044
- 3516065817,
34045
- 3600352804,
34046
- 4094571909,
34047
- 275423344,
34048
- 430227734,
34049
- 506948616,
34050
- 659060556,
34051
- 883997877,
34052
- 958139571,
34053
- 1322822218,
34054
- 1537002063,
34055
- 1747873779,
34056
- 1955562222,
34057
- 2024104815,
34058
- 2227730452,
34059
- 2361852424,
34060
- 2428436474,
34061
- 2756734187,
34062
- 3204031479,
34063
- 3329325298
34064
- ]);
34065
- const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
34066
- class SHA2_32B extends HashMD {
34067
- constructor(outputLen) {
34068
- super(64, outputLen, 8, false);
34069
- }
34070
- get() {
34071
- const { A, B, C, D, E, F, G, H } = this;
34072
- return [A, B, C, D, E, F, G, H];
34073
- }
34074
- // prettier-ignore
34075
- set(A, B, C, D, E, F, G, H) {
34076
- this.A = A | 0;
34077
- this.B = B | 0;
34078
- this.C = C | 0;
34079
- this.D = D | 0;
34080
- this.E = E | 0;
34081
- this.F = F | 0;
34082
- this.G = G | 0;
34083
- this.H = H | 0;
34084
- }
34085
- process(view, offset) {
34086
- for (let i = 0; i < 16; i++, offset += 4)
34087
- SHA256_W[i] = view.getUint32(offset, false);
34088
- for (let i = 16; i < 64; i++) {
34089
- const W15 = SHA256_W[i - 15];
34090
- const W2 = SHA256_W[i - 2];
34091
- const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
34092
- const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
34093
- SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
34094
- }
34095
- let { A, B, C, D, E, F, G, H } = this;
34096
- for (let i = 0; i < 64; i++) {
34097
- const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
34098
- const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
34099
- const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
34100
- const T2 = sigma0 + Maj(A, B, C) | 0;
34101
- H = G;
34102
- G = F;
34103
- F = E;
34104
- E = D + T1 | 0;
34105
- D = C;
34106
- C = B;
34107
- B = A;
34108
- A = T1 + T2 | 0;
34109
- }
34110
- A = A + this.A | 0;
34111
- B = B + this.B | 0;
34112
- C = C + this.C | 0;
34113
- D = D + this.D | 0;
34114
- E = E + this.E | 0;
34115
- F = F + this.F | 0;
34116
- G = G + this.G | 0;
34117
- H = H + this.H | 0;
34118
- this.set(A, B, C, D, E, F, G, H);
34119
- }
34120
- roundClean() {
34121
- clean(SHA256_W);
34122
- }
34123
- destroy() {
34124
- this.destroyed = true;
34125
- this.set(0, 0, 0, 0, 0, 0, 0, 0);
34126
- clean(this.buffer);
34127
- }
34128
- }
34129
- class _SHA256 extends SHA2_32B {
34130
- // We cannot use array here since array allows indexing by variable
34131
- // which means optimizer/compiler cannot use registers.
34132
- A = SHA256_IV[0] | 0;
34133
- B = SHA256_IV[1] | 0;
34134
- C = SHA256_IV[2] | 0;
34135
- D = SHA256_IV[3] | 0;
34136
- E = SHA256_IV[4] | 0;
34137
- F = SHA256_IV[5] | 0;
34138
- G = SHA256_IV[6] | 0;
34139
- H = SHA256_IV[7] | 0;
34140
- constructor() {
34141
- super(32);
34142
- }
34143
- }
34144
- const sha256 = /* @__PURE__ */ createHasher(
34145
- () => new _SHA256(),
34146
- /* @__PURE__ */ oidNist(1)
34147
- );
34148
- function channelLeaseSubject(input) {
34149
- const material = JSON.stringify([input.provider, input.installationId]);
34150
- return bytesToHex(sha256(new TextEncoder().encode(material)));
34151
- }
34152
- const LEASE_OUTCOMES = /* @__PURE__ */ new Set([
34153
- "claimed",
34154
- "taken-over",
34155
- "already-held",
34156
- "renewed",
34157
- "already-released",
34158
- "released"
34159
- ]);
34160
- const RELEASED_OUTCOMES = /* @__PURE__ */ new Set(["released", "already-released"]);
34161
- const HELD_OUTCOMES = /* @__PURE__ */ new Set([
34162
- "claimed",
34163
- "taken-over",
34164
- "renewed",
34165
- "already-held"
34166
- ]);
34167
- function nonNegativeInteger(value2) {
34168
- return typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0;
34169
- }
34170
- function isLeaseResponse(value2) {
34171
- if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return false;
34172
- const body = value2;
34173
- if (typeof body.held !== "boolean") return false;
34174
- if (typeof body.outcome !== "string" || !LEASE_OUTCOMES.has(body.outcome)) return false;
34175
- if (!nonNegativeInteger(body.ownerEpoch) || !nonNegativeInteger(body.version)) return false;
34176
- if (!nonNegativeInteger(body.serverNow) || !nonNegativeInteger(body.leaseUntil)) return false;
34177
- if (body.releasedAt !== null && !nonNegativeInteger(body.releasedAt)) return false;
34178
- if (body.held && body.releasedAt !== null) return false;
34179
- if (body.held && RELEASED_OUTCOMES.has(body.outcome)) return false;
34180
- if (!body.held && HELD_OUTCOMES.has(body.outcome)) return false;
34181
- return true;
34182
- }
34183
- function resolveChannelLease(input) {
34184
- if (!isLeaseResponse(input.body)) return { kind: "unknown" };
34185
- const body = input.body;
34186
- if (!body.held) {
34187
- return { kind: "lost", reason: body.releasedAt === null ? "conflict" : "released" };
34188
- }
34189
- const remaining = body.leaseUntil - body.serverNow;
34190
- if (!Number.isFinite(remaining) || remaining <= 0) return { kind: "unknown" };
34191
- return {
34192
- kind: "held",
34193
- hold: {
34194
- ownerId: input.ownerId,
34195
- ownerEpoch: body.ownerEpoch,
34196
- version: body.version,
34197
- deadlineMono: input.requestStartedMono + remaining
34198
- }
34199
- };
34200
- }
34201
- function channelLeaseStillHeld(hold, nowMono, options = {}) {
34202
- if (!hold || options.suspectedSuspend === true) return false;
34203
- return nowMono < hold.deadlineMono;
34204
- }
34205
- function channelLeaseAnswerIsCurrent(input) {
34206
- return !input.stopped && input.attempt === input.currentAttempt;
34207
- }
34208
33743
  const EXTENSION_ARTIFACT_ACTION_OPERATIONS = ["publishPublic"];
34209
33744
  const EXTENSION_ARTIFACT_SOURCE_TYPES = ["project-file", "personal-chat-file"];
34210
- const ID_PATTERN$2 = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
33745
+ const ID_PATTERN$3 = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
34211
33746
  const LOCALE_PATTERN$1 = /^[a-z]{2,3}(?:-[A-Z]{2})?$/;
34212
33747
  const EXTENSION_PATTERN = /^[a-z0-9]+$/;
34213
33748
  const MAX_ACTIONS = 32;
@@ -34283,7 +33818,7 @@ function parseExtensionArtifactActions(value2, path = "manifest.contributes.arti
34283
33818
  const action = record$3(raw, actionPath);
34284
33819
  exactKeys$2(action, ["id", "title", "operation", "when"], ["localizations"], actionPath);
34285
33820
  const parsedId = text$2(action.id, `${actionPath}.id`);
34286
- if (!ID_PATTERN$2.test(parsedId) || parsedId.includes("..")) fail$6(`${actionPath}.id`, "invalid stable identifier");
33821
+ if (!ID_PATTERN$3.test(parsedId) || parsedId.includes("..")) fail$6(`${actionPath}.id`, "invalid stable identifier");
34287
33822
  if (!EXTENSION_ARTIFACT_ACTION_OPERATIONS.includes(action.operation)) {
34288
33823
  fail$6(`${actionPath}.operation`, "unsupported operation");
34289
33824
  }
@@ -34618,7 +34153,7 @@ function parseOptions(value2, path, expected) {
34618
34153
  }));
34619
34154
  }
34620
34155
  const MAX_CHANNEL_CONTRIBUTIONS = CHANNEL_PROVIDERS.length;
34621
- const ID_PATTERN$1 = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
34156
+ const ID_PATTERN$2 = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
34622
34157
  const ENTRY_KEYS = /* @__PURE__ */ new Set(["id", "provider", "commands"]);
34623
34158
  function fail$3(path, detail) {
34624
34159
  throw new Error(`${path}: ${detail}`);
@@ -34636,7 +34171,7 @@ function parseExtensionChannelContributions(value2) {
34636
34171
  const extra = Object.keys(source2).find((key) => !ENTRY_KEYS.has(key));
34637
34172
  if (extra !== void 0) fail$3(path, `unknown field ${extra}`);
34638
34173
  const id2 = source2.id;
34639
- if (typeof id2 !== "string" || !ID_PATTERN$1.test(id2) || id2.includes("..")) {
34174
+ if (typeof id2 !== "string" || !ID_PATTERN$2.test(id2) || id2.includes("..")) {
34640
34175
  fail$3(`${path}.id`, "invalid identifier");
34641
34176
  }
34642
34177
  const provider2 = source2.provider;
@@ -34702,8 +34237,8 @@ class UnsupportedExtensionApiVersionError extends Error {
34702
34237
  }
34703
34238
  name = "UnsupportedExtensionApiVersionError";
34704
34239
  }
34705
- const ID_PATTERN = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
34706
- const SEMVER_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
34240
+ const ID_PATTERN$1 = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
34241
+ const SEMVER_PATTERN$1 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
34707
34242
  const ENGINE_RANGE_PATTERN = /^(?:\^|~|>=|<=|>|<)?\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
34708
34243
  const ENTRYPOINT_PATTERN = /\.(?:cjs|mjs|js)$/;
34709
34244
  const LOCALE_PATTERN = /^[a-z]{2,3}(?:-[A-Z]{2})?$/;
@@ -34792,7 +34327,7 @@ function string(value2, path) {
34792
34327
  }
34793
34328
  function id$1(value2, path) {
34794
34329
  const parsed2 = string(value2, path);
34795
- if (!ID_PATTERN.test(parsed2) || parsed2.includes("..")) fail$2(path, "invalid stable identifier");
34330
+ if (!ID_PATTERN$1.test(parsed2) || parsed2.includes("..")) fail$2(path, "invalid stable identifier");
34796
34331
  return parsed2;
34797
34332
  }
34798
34333
  function relativePath(value2, path, requireScript = false) {
@@ -34968,7 +34503,7 @@ function parseExtensionManifest(value2, options) {
34968
34503
  assertOnlyKeys(manifest2, TOP_LEVEL_KEYS, "manifest");
34969
34504
  const parsedId = id$1(manifest2.id, "manifest.id");
34970
34505
  const version2 = string(manifest2.version, "manifest.version");
34971
- if (!SEMVER_PATTERN.test(version2)) fail$2("manifest.version", "expected semantic version");
34506
+ if (!SEMVER_PATTERN$1.test(version2)) fail$2("manifest.version", "expected semantic version");
34972
34507
  const apiVersion = parseApiVersion(manifest2.apiVersion, options);
34973
34508
  const channelApiVersion = parseChannelApiVersion(manifest2.channelApiVersion, apiVersion);
34974
34509
  const engines = record$2(manifest2.engines, "manifest.engines");
@@ -35066,6 +34601,645 @@ function parseExtensionManifest(value2, options) {
35066
34601
  contributes
35067
34602
  };
35068
34603
  }
34604
+ const ID_PATTERN = /^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/;
34605
+ const SEMVER_PATTERN = /^\d+\.\d+\.\d+$/;
34606
+ const SHA256_PATTERN = /^[a-f0-9]{64}$/;
34607
+ const BASE64_PATTERN = /^[A-Za-z0-9+/]*={0,2}$/;
34608
+ function isNewerVersion(candidate, installed) {
34609
+ if (!SEMVER_PATTERN.test(installed)) return false;
34610
+ const left = candidate.split(".").map(Number);
34611
+ const right = installed.split(".").map(Number);
34612
+ for (let index = 0; index < left.length; index += 1) {
34613
+ if (left[index] !== right[index]) return left[index] > right[index];
34614
+ }
34615
+ return false;
34616
+ }
34617
+ function descriptor(value2) {
34618
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw new Error("official extension descriptor is invalid");
34619
+ const item = value2;
34620
+ if (Object.keys(item).sort().join(",") !== "archive,id,releaseUrl,sha256,version" || typeof item.id !== "string" || !ID_PATTERN.test(item.id) || item.id.includes("..") || typeof item.version !== "string" || !SEMVER_PATTERN.test(item.version) || typeof item.releaseUrl !== "string" || !item.releaseUrl.startsWith("https://github.com/buzzni/saycode-extensions/releases/tag/") || typeof item.archive !== "string" || basename(item.archive) !== item.archive || typeof item.sha256 !== "string" || !SHA256_PATTERN.test(item.sha256)) throw new Error("official extension descriptor is invalid");
34621
+ return item;
34622
+ }
34623
+ function catalog(value2) {
34624
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) throw new Error("official extension catalog is invalid");
34625
+ const record2 = value2;
34626
+ if (Object.keys(record2).sort().join(",") !== "extensions,schemaVersion" || record2.schemaVersion !== 1 || !Array.isArray(record2.extensions)) throw new Error("official extension catalog is invalid");
34627
+ const extensions = record2.extensions.map(descriptor);
34628
+ if (new Set(extensions.map((item) => item.id)).size !== extensions.length) {
34629
+ throw new Error("official extension catalog contains duplicate ids");
34630
+ }
34631
+ return { schemaVersion: 1, extensions };
34632
+ }
34633
+ class OfficialExtensionInstaller {
34634
+ constructor(options) {
34635
+ this.options = options;
34636
+ }
34637
+ /**
34638
+ * What the user could install right now (specs/desktop-official-extension-install-list R1).
34639
+ *
34640
+ * `install(id)` has always taken any catalog id; nothing could ask which ids exist, so the only
34641
+ * way to offer one was a button written by hand per extension. This is that missing half.
34642
+ *
34643
+ * Already-installed ids are left out: the list is an offer, not an inventory — the installed
34644
+ * ones are the rest of the panel.
34645
+ */
34646
+ async installable() {
34647
+ let bundled = [];
34648
+ try {
34649
+ bundled = (await this.readCatalog()).extensions;
34650
+ } catch {
34651
+ bundled = [];
34652
+ }
34653
+ const versions = /* @__PURE__ */ new Map();
34654
+ for (const entry of bundled) versions.set(entry.id, entry.version);
34655
+ for (const entry of this.options.remote?.descriptors() ?? []) versions.set(entry.id, entry.version);
34656
+ return [...versions].filter(([id2, version2]) => !this.options.registry.get(id2) && !this.options.revocations?.isRevoked(id2, version2)).map(([id2, version2]) => ({ id: id2, version: version2 }));
34657
+ }
34658
+ async install(id2) {
34659
+ if (this.options.registry.get(id2)) throw new Error(`extension is already installed: ${id2}`);
34660
+ const source2 = await this.resolveArtifact(id2);
34661
+ const installed = await this.options.store.install(source2.archive);
34662
+ if (installed.id !== source2.metadata.id || installed.version !== source2.metadata.version) {
34663
+ await this.options.store.removeVersion(installed.id, installed.version);
34664
+ throw new Error("official extension artifact does not match its provenance");
34665
+ }
34666
+ try {
34667
+ await this.options.registry.apply(installed.id, { type: "installed", version: installed.version });
34668
+ } catch (error) {
34669
+ await this.options.store.removeVersion(installed.id, installed.version);
34670
+ throw error;
34671
+ }
34672
+ return { id: installed.id, version: installed.version, releaseUrl: source2.metadata.releaseUrl };
34673
+ }
34674
+ async reconcileBundledCompatibility() {
34675
+ const installedEntries = this.options.registry.entries();
34676
+ if (installedEntries.length === 0) return;
34677
+ const bundled = (await this.readCatalog()).extensions;
34678
+ let firstError = null;
34679
+ for (const { id: id2, state } of installedEntries) {
34680
+ try {
34681
+ const metadata = bundled.find((item) => item.id === id2);
34682
+ if (!metadata || !isNewerVersion(metadata.version, state.installedVersion)) continue;
34683
+ try {
34684
+ await this.options.store.readInstalledManifest(id2, state.installedVersion);
34685
+ continue;
34686
+ } catch (error) {
34687
+ if (!(error instanceof UnsupportedExtensionApiVersionError) || typeof error.apiVersion !== "number" || error.apiVersion >= error.minimumSupportedApiVersion) throw error;
34688
+ }
34689
+ const archive = await this.readArchive(metadata);
34690
+ await this.options.store.removeVersion(id2, metadata.version);
34691
+ const migrated = await this.options.store.install(archive);
34692
+ if (migrated.id !== id2 || migrated.version !== metadata.version) {
34693
+ await this.options.store.removeVersion(migrated.id, migrated.version);
34694
+ throw new Error("bundled compatibility artifact does not match its provenance");
34695
+ }
34696
+ try {
34697
+ await this.options.registry.apply(id2, {
34698
+ type: "compatibility-update-installed",
34699
+ version: migrated.version
34700
+ });
34701
+ } catch (error) {
34702
+ await this.options.store.removeVersion(migrated.id, migrated.version);
34703
+ throw error;
34704
+ }
34705
+ await this.options.store.removeVersion(id2, state.installedVersion);
34706
+ } catch (error) {
34707
+ firstError ??= error;
34708
+ }
34709
+ }
34710
+ if (firstError) throw firstError;
34711
+ }
34712
+ /** Ids the official channel owns — bundled or signed-remote. A development build must never
34713
+ * be able to stand in for one (ADR-050). */
34714
+ async isOfficialId(id2) {
34715
+ if (this.options.remote?.descriptorFor(id2)) return true;
34716
+ try {
34717
+ return (await this.readCatalog()).extensions.some((item) => item.id === id2);
34718
+ } catch {
34719
+ return true;
34720
+ }
34721
+ }
34722
+ async resolveArtifact(id2) {
34723
+ const remote = this.options.remote?.descriptorFor(id2) ?? null;
34724
+ if (remote) {
34725
+ return { archive: await this.options.remote.downloadArchive(remote), metadata: remote };
34726
+ }
34727
+ const metadata = (await this.readCatalog()).extensions.find((item) => item.id === id2);
34728
+ if (!metadata) throw new Error(`official extension is unavailable: ${id2}`);
34729
+ return { archive: await this.readArchive(metadata), metadata };
34730
+ }
34731
+ async readCatalog() {
34732
+ try {
34733
+ return catalog(JSON.parse(await readFile(join(this.options.resourceRoot, "catalog.v1.json"), "utf8")));
34734
+ } catch (error) {
34735
+ throw new Error(`official extension catalog could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
34736
+ }
34737
+ }
34738
+ async readArchive(metadata) {
34739
+ const encoded = (await readFile(join(this.options.resourceRoot, metadata.archive), "utf8")).trim();
34740
+ if (!BASE64_PATTERN.test(encoded) || encoded.length % 4 !== 0) {
34741
+ throw new Error("official extension archive encoding is invalid");
34742
+ }
34743
+ const archive = Buffer.from(encoded, "base64");
34744
+ const checksum2 = createHash("sha256").update(archive).digest("hex");
34745
+ if (checksum2 !== metadata.sha256) throw new Error("official extension checksum mismatch");
34746
+ return archive;
34747
+ }
34748
+ }
34749
+ const CHANNEL_ADAPTER_IDS = {
34750
+ telegram: "buzzni.telegram",
34751
+ slack: "buzzni.slack",
34752
+ discord: "buzzni.discord"
34753
+ };
34754
+ const ADAPTER_IDS = new Set(Object.values(CHANNEL_ADAPTER_IDS));
34755
+ function createHostOfficialAdapterSource(input) {
34756
+ const installer = new OfficialExtensionInstaller({
34757
+ resourceRoot: input.resourceRoot,
34758
+ store: null,
34759
+ registry: null,
34760
+ ...input.remote ? { remote: input.remote } : {}
34761
+ });
34762
+ const resolve2 = (id2) => {
34763
+ if (!ADAPTER_IDS.has(id2)) return Promise.reject(new Error(`not a messenger adapter: ${id2}`));
34764
+ return installer.resolveArtifact(id2);
34765
+ };
34766
+ return {
34767
+ versionOf: (id2) => resolve2(id2).then((artifact) => artifact.metadata.version, () => null),
34768
+ archive: async (id2) => (await resolve2(id2)).archive
34769
+ };
34770
+ }
34771
+ async function offeredChannelProviders(source2) {
34772
+ const offered = [];
34773
+ for (const [provider2, id2] of Object.entries(CHANNEL_ADAPTER_IDS)) {
34774
+ if (await source2.versionOf(id2)) offered.push(provider2);
34775
+ }
34776
+ return offered;
34777
+ }
34778
+ function describe(secretKey) {
34779
+ const { publicKey } = nacl.box.keyPair.fromSecretKey(secretKey);
34780
+ const digest = createHash("sha256").update(publicKey).digest("hex").slice(0, 16).toUpperCase();
34781
+ return {
34782
+ publicKey,
34783
+ secretKey,
34784
+ publicKeyBase64: Buffer.from(publicKey).toString("base64"),
34785
+ fingerprint: digest.match(/.{4}/g).join("-")
34786
+ };
34787
+ }
34788
+ async function openChannelHostKey(input) {
34789
+ if (!input.safeStorage.isEncryptionAvailable()) return null;
34790
+ const path = join(input.dir, "host-key.v1.json");
34791
+ let text2 = null;
34792
+ try {
34793
+ text2 = await readFile(path, "utf8");
34794
+ } catch (error) {
34795
+ if (error.code !== "ENOENT") throw error;
34796
+ }
34797
+ if (text2 !== null) {
34798
+ const parsed2 = JSON.parse(text2);
34799
+ if (parsed2.v !== 1 || typeof parsed2.sealed !== "string") throw new Error("channel host key file is unreadable");
34800
+ const secret = Buffer.from(input.safeStorage.decryptString(Buffer.from(parsed2.sealed, "base64")), "base64");
34801
+ if (secret.length !== nacl.box.secretKeyLength) throw new Error("channel host key file is unreadable");
34802
+ return describe(new Uint8Array(secret));
34803
+ }
34804
+ const { secretKey } = nacl.box.keyPair();
34805
+ await mkdir(input.dir, { recursive: true, mode: 448 });
34806
+ const sealed2 = input.safeStorage.encryptString(Buffer.from(secretKey).toString("base64")).toString("base64");
34807
+ const staging = `${path}.${process.pid}.tmp`;
34808
+ await writeFile(staging, JSON.stringify({ v: 1, sealed: sealed2 }), { mode: 384 });
34809
+ await rename(staging, path);
34810
+ return describe(secretKey);
34811
+ }
34812
+ function defaultIsAlive(pid) {
34813
+ try {
34814
+ process.kill(pid, 0);
34815
+ return true;
34816
+ } catch (error) {
34817
+ return error.code === "EPERM";
34818
+ }
34819
+ }
34820
+ async function acquireChannelHostLock(input) {
34821
+ const path = join(input.dir, "host.lock");
34822
+ const isAlive = input.isAlive ?? defaultIsAlive;
34823
+ for (let attempt2 = 0; attempt2 < 2; attempt2 += 1) {
34824
+ try {
34825
+ const handle = await open(path, "wx", 384);
34826
+ await handle.writeFile(JSON.stringify({ pid: process.pid, startedAt: Date.now() }));
34827
+ await handle.close();
34828
+ return {
34829
+ kind: "held",
34830
+ release: async () => {
34831
+ const current = await readFile(path, "utf8").then((text2) => JSON.parse(text2), () => null);
34832
+ if (current?.pid === process.pid) await rm(path, { force: true });
34833
+ }
34834
+ };
34835
+ } catch (error) {
34836
+ if (error.code !== "EEXIST") throw error;
34837
+ }
34838
+ let holder = null;
34839
+ try {
34840
+ const parsed2 = JSON.parse(await readFile(path, "utf8"));
34841
+ holder = typeof parsed2.pid === "number" && Number.isSafeInteger(parsed2.pid) ? parsed2.pid : null;
34842
+ } catch {
34843
+ holder = null;
34844
+ }
34845
+ if (holder === null || isAlive(holder)) return { kind: "refused" };
34846
+ await rm(path, { force: true });
34847
+ }
34848
+ return { kind: "refused" };
34849
+ }
34850
+ function isBytes(a) {
34851
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
34852
+ }
34853
+ function abytes(value2, length, title2 = "") {
34854
+ const bytes = isBytes(value2);
34855
+ const len = value2?.length;
34856
+ const needsLen = length !== void 0;
34857
+ if (!bytes || needsLen) {
34858
+ const prefix = title2 && `"${title2}" `;
34859
+ const ofLen = "";
34860
+ const got = bytes ? `length=${len}` : `type=${typeof value2}`;
34861
+ const message = prefix + "expected Uint8Array" + ofLen + ", got " + got;
34862
+ if (!bytes)
34863
+ throw new TypeError(message);
34864
+ throw new RangeError(message);
34865
+ }
34866
+ return value2;
34867
+ }
34868
+ function aexists(instance, checkFinished = true) {
34869
+ if (instance.destroyed)
34870
+ throw new Error("Hash instance has been destroyed");
34871
+ if (checkFinished && instance.finished)
34872
+ throw new Error("Hash#digest() has already been called");
34873
+ }
34874
+ function aoutput(out, instance) {
34875
+ abytes(out, void 0, "digestInto() output");
34876
+ const min = instance.outputLen;
34877
+ if (out.length < min) {
34878
+ throw new RangeError('"digestInto() output" expected to be of length >=' + min);
34879
+ }
34880
+ }
34881
+ function clean(...arrays) {
34882
+ for (let i = 0; i < arrays.length; i++) {
34883
+ arrays[i].fill(0);
34884
+ }
34885
+ }
34886
+ function createView(arr) {
34887
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
34888
+ }
34889
+ function rotr(word, shift) {
34890
+ return word << 32 - shift | word >>> shift;
34891
+ }
34892
+ const hasHexBuiltin = /* @__PURE__ */ (() => (
34893
+ // @ts-ignore
34894
+ typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
34895
+ ))();
34896
+ const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
34897
+ function bytesToHex(bytes) {
34898
+ abytes(bytes);
34899
+ if (hasHexBuiltin)
34900
+ return bytes.toHex();
34901
+ let hex = "";
34902
+ for (let i = 0; i < bytes.length; i++) {
34903
+ hex += hexes[bytes[i]];
34904
+ }
34905
+ return hex;
34906
+ }
34907
+ function createHasher(hashCons, info = {}) {
34908
+ const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
34909
+ const tmp = hashCons(void 0);
34910
+ hashC.outputLen = tmp.outputLen;
34911
+ hashC.blockLen = tmp.blockLen;
34912
+ hashC.canXOF = tmp.canXOF;
34913
+ hashC.create = (opts) => hashCons(opts);
34914
+ Object.assign(hashC, info);
34915
+ return Object.freeze(hashC);
34916
+ }
34917
+ const oidNist = (suffix) => ({
34918
+ // Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
34919
+ // Larger suffix values would need base-128 OID encoding and a different length byte.
34920
+ oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
34921
+ });
34922
+ function Chi(a, b, c) {
34923
+ return a & b ^ ~a & c;
34924
+ }
34925
+ function Maj(a, b, c) {
34926
+ return a & b ^ a & c ^ b & c;
34927
+ }
34928
+ class HashMD {
34929
+ blockLen;
34930
+ outputLen;
34931
+ canXOF = false;
34932
+ padOffset;
34933
+ isLE;
34934
+ // For partial updates less than block size
34935
+ buffer;
34936
+ view;
34937
+ finished = false;
34938
+ length = 0;
34939
+ pos = 0;
34940
+ destroyed = false;
34941
+ constructor(blockLen, outputLen, padOffset, isLE) {
34942
+ this.blockLen = blockLen;
34943
+ this.outputLen = outputLen;
34944
+ this.padOffset = padOffset;
34945
+ this.isLE = isLE;
34946
+ this.buffer = new Uint8Array(blockLen);
34947
+ this.view = createView(this.buffer);
34948
+ }
34949
+ update(data) {
34950
+ aexists(this);
34951
+ abytes(data);
34952
+ const { view, buffer, blockLen } = this;
34953
+ const len = data.length;
34954
+ for (let pos = 0; pos < len; ) {
34955
+ const take = Math.min(blockLen - this.pos, len - pos);
34956
+ if (take === blockLen) {
34957
+ const dataView = createView(data);
34958
+ for (; blockLen <= len - pos; pos += blockLen)
34959
+ this.process(dataView, pos);
34960
+ continue;
34961
+ }
34962
+ buffer.set(data.subarray(pos, pos + take), this.pos);
34963
+ this.pos += take;
34964
+ pos += take;
34965
+ if (this.pos === blockLen) {
34966
+ this.process(view, 0);
34967
+ this.pos = 0;
34968
+ }
34969
+ }
34970
+ this.length += data.length;
34971
+ this.roundClean();
34972
+ return this;
34973
+ }
34974
+ digestInto(out) {
34975
+ aexists(this);
34976
+ aoutput(out, this);
34977
+ this.finished = true;
34978
+ const { buffer, view, blockLen, isLE } = this;
34979
+ let { pos } = this;
34980
+ buffer[pos++] = 128;
34981
+ clean(this.buffer.subarray(pos));
34982
+ if (this.padOffset > blockLen - pos) {
34983
+ this.process(view, 0);
34984
+ pos = 0;
34985
+ }
34986
+ for (let i = pos; i < blockLen; i++)
34987
+ buffer[i] = 0;
34988
+ view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
34989
+ this.process(view, 0);
34990
+ const oview = createView(out);
34991
+ const len = this.outputLen;
34992
+ if (len % 4)
34993
+ throw new Error("_sha2: outputLen must be aligned to 32bit");
34994
+ const outLen = len / 4;
34995
+ const state = this.get();
34996
+ if (outLen > state.length)
34997
+ throw new Error("_sha2: outputLen bigger than state");
34998
+ for (let i = 0; i < outLen; i++)
34999
+ oview.setUint32(4 * i, state[i], isLE);
35000
+ }
35001
+ digest() {
35002
+ const { buffer, outputLen } = this;
35003
+ this.digestInto(buffer);
35004
+ const res = buffer.slice(0, outputLen);
35005
+ this.destroy();
35006
+ return res;
35007
+ }
35008
+ _cloneInto(to) {
35009
+ to ||= new this.constructor();
35010
+ to.set(...this.get());
35011
+ const { blockLen, buffer, length, finished, destroyed, pos } = this;
35012
+ to.destroyed = destroyed;
35013
+ to.finished = finished;
35014
+ to.length = length;
35015
+ to.pos = pos;
35016
+ if (length % blockLen)
35017
+ to.buffer.set(buffer);
35018
+ return to;
35019
+ }
35020
+ clone() {
35021
+ return this._cloneInto();
35022
+ }
35023
+ }
35024
+ const SHA256_IV = /* @__PURE__ */ Uint32Array.from([
35025
+ 1779033703,
35026
+ 3144134277,
35027
+ 1013904242,
35028
+ 2773480762,
35029
+ 1359893119,
35030
+ 2600822924,
35031
+ 528734635,
35032
+ 1541459225
35033
+ ]);
35034
+ const SHA256_K = /* @__PURE__ */ Uint32Array.from([
35035
+ 1116352408,
35036
+ 1899447441,
35037
+ 3049323471,
35038
+ 3921009573,
35039
+ 961987163,
35040
+ 1508970993,
35041
+ 2453635748,
35042
+ 2870763221,
35043
+ 3624381080,
35044
+ 310598401,
35045
+ 607225278,
35046
+ 1426881987,
35047
+ 1925078388,
35048
+ 2162078206,
35049
+ 2614888103,
35050
+ 3248222580,
35051
+ 3835390401,
35052
+ 4022224774,
35053
+ 264347078,
35054
+ 604807628,
35055
+ 770255983,
35056
+ 1249150122,
35057
+ 1555081692,
35058
+ 1996064986,
35059
+ 2554220882,
35060
+ 2821834349,
35061
+ 2952996808,
35062
+ 3210313671,
35063
+ 3336571891,
35064
+ 3584528711,
35065
+ 113926993,
35066
+ 338241895,
35067
+ 666307205,
35068
+ 773529912,
35069
+ 1294757372,
35070
+ 1396182291,
35071
+ 1695183700,
35072
+ 1986661051,
35073
+ 2177026350,
35074
+ 2456956037,
35075
+ 2730485921,
35076
+ 2820302411,
35077
+ 3259730800,
35078
+ 3345764771,
35079
+ 3516065817,
35080
+ 3600352804,
35081
+ 4094571909,
35082
+ 275423344,
35083
+ 430227734,
35084
+ 506948616,
35085
+ 659060556,
35086
+ 883997877,
35087
+ 958139571,
35088
+ 1322822218,
35089
+ 1537002063,
35090
+ 1747873779,
35091
+ 1955562222,
35092
+ 2024104815,
35093
+ 2227730452,
35094
+ 2361852424,
35095
+ 2428436474,
35096
+ 2756734187,
35097
+ 3204031479,
35098
+ 3329325298
35099
+ ]);
35100
+ const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
35101
+ class SHA2_32B extends HashMD {
35102
+ constructor(outputLen) {
35103
+ super(64, outputLen, 8, false);
35104
+ }
35105
+ get() {
35106
+ const { A, B, C, D, E, F, G, H } = this;
35107
+ return [A, B, C, D, E, F, G, H];
35108
+ }
35109
+ // prettier-ignore
35110
+ set(A, B, C, D, E, F, G, H) {
35111
+ this.A = A | 0;
35112
+ this.B = B | 0;
35113
+ this.C = C | 0;
35114
+ this.D = D | 0;
35115
+ this.E = E | 0;
35116
+ this.F = F | 0;
35117
+ this.G = G | 0;
35118
+ this.H = H | 0;
35119
+ }
35120
+ process(view, offset) {
35121
+ for (let i = 0; i < 16; i++, offset += 4)
35122
+ SHA256_W[i] = view.getUint32(offset, false);
35123
+ for (let i = 16; i < 64; i++) {
35124
+ const W15 = SHA256_W[i - 15];
35125
+ const W2 = SHA256_W[i - 2];
35126
+ const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
35127
+ const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
35128
+ SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
35129
+ }
35130
+ let { A, B, C, D, E, F, G, H } = this;
35131
+ for (let i = 0; i < 64; i++) {
35132
+ const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
35133
+ const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
35134
+ const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
35135
+ const T2 = sigma0 + Maj(A, B, C) | 0;
35136
+ H = G;
35137
+ G = F;
35138
+ F = E;
35139
+ E = D + T1 | 0;
35140
+ D = C;
35141
+ C = B;
35142
+ B = A;
35143
+ A = T1 + T2 | 0;
35144
+ }
35145
+ A = A + this.A | 0;
35146
+ B = B + this.B | 0;
35147
+ C = C + this.C | 0;
35148
+ D = D + this.D | 0;
35149
+ E = E + this.E | 0;
35150
+ F = F + this.F | 0;
35151
+ G = G + this.G | 0;
35152
+ H = H + this.H | 0;
35153
+ this.set(A, B, C, D, E, F, G, H);
35154
+ }
35155
+ roundClean() {
35156
+ clean(SHA256_W);
35157
+ }
35158
+ destroy() {
35159
+ this.destroyed = true;
35160
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
35161
+ clean(this.buffer);
35162
+ }
35163
+ }
35164
+ class _SHA256 extends SHA2_32B {
35165
+ // We cannot use array here since array allows indexing by variable
35166
+ // which means optimizer/compiler cannot use registers.
35167
+ A = SHA256_IV[0] | 0;
35168
+ B = SHA256_IV[1] | 0;
35169
+ C = SHA256_IV[2] | 0;
35170
+ D = SHA256_IV[3] | 0;
35171
+ E = SHA256_IV[4] | 0;
35172
+ F = SHA256_IV[5] | 0;
35173
+ G = SHA256_IV[6] | 0;
35174
+ H = SHA256_IV[7] | 0;
35175
+ constructor() {
35176
+ super(32);
35177
+ }
35178
+ }
35179
+ const sha256 = /* @__PURE__ */ createHasher(
35180
+ () => new _SHA256(),
35181
+ /* @__PURE__ */ oidNist(1)
35182
+ );
35183
+ function channelLeaseSubject(input) {
35184
+ const material = JSON.stringify([input.provider, input.installationId]);
35185
+ return bytesToHex(sha256(new TextEncoder().encode(material)));
35186
+ }
35187
+ const LEASE_OUTCOMES = /* @__PURE__ */ new Set([
35188
+ "claimed",
35189
+ "taken-over",
35190
+ "already-held",
35191
+ "renewed",
35192
+ "already-released",
35193
+ "released"
35194
+ ]);
35195
+ const RELEASED_OUTCOMES = /* @__PURE__ */ new Set(["released", "already-released"]);
35196
+ const HELD_OUTCOMES = /* @__PURE__ */ new Set([
35197
+ "claimed",
35198
+ "taken-over",
35199
+ "renewed",
35200
+ "already-held"
35201
+ ]);
35202
+ function nonNegativeInteger(value2) {
35203
+ return typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0;
35204
+ }
35205
+ function isLeaseResponse(value2) {
35206
+ if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) return false;
35207
+ const body = value2;
35208
+ if (typeof body.held !== "boolean") return false;
35209
+ if (typeof body.outcome !== "string" || !LEASE_OUTCOMES.has(body.outcome)) return false;
35210
+ if (!nonNegativeInteger(body.ownerEpoch) || !nonNegativeInteger(body.version)) return false;
35211
+ if (!nonNegativeInteger(body.serverNow) || !nonNegativeInteger(body.leaseUntil)) return false;
35212
+ if (body.releasedAt !== null && !nonNegativeInteger(body.releasedAt)) return false;
35213
+ if (body.held && body.releasedAt !== null) return false;
35214
+ if (body.held && RELEASED_OUTCOMES.has(body.outcome)) return false;
35215
+ if (!body.held && HELD_OUTCOMES.has(body.outcome)) return false;
35216
+ return true;
35217
+ }
35218
+ function resolveChannelLease(input) {
35219
+ if (!isLeaseResponse(input.body)) return { kind: "unknown" };
35220
+ const body = input.body;
35221
+ if (!body.held) {
35222
+ return { kind: "lost", reason: body.releasedAt === null ? "conflict" : "released" };
35223
+ }
35224
+ const remaining = body.leaseUntil - body.serverNow;
35225
+ if (!Number.isFinite(remaining) || remaining <= 0) return { kind: "unknown" };
35226
+ return {
35227
+ kind: "held",
35228
+ hold: {
35229
+ ownerId: input.ownerId,
35230
+ ownerEpoch: body.ownerEpoch,
35231
+ version: body.version,
35232
+ deadlineMono: input.requestStartedMono + remaining
35233
+ }
35234
+ };
35235
+ }
35236
+ function channelLeaseStillHeld(hold, nowMono, options = {}) {
35237
+ if (!hold || options.suspectedSuspend === true) return false;
35238
+ return nowMono < hold.deadlineMono;
35239
+ }
35240
+ function channelLeaseAnswerIsCurrent(input) {
35241
+ return !input.stopped && input.attempt === input.currentAttempt;
35242
+ }
35069
35243
  function syncSocketTokens(auth) {
35070
35244
  const primary = auth.syncToken || auth.token;
35071
35245
  if (!primary) return [];
@@ -46893,12 +47067,12 @@ class ChannelSettingsService {
46893
47067
  const { principalKey } = this.requirePrincipal();
46894
47068
  const epoch = this.options.accountEpoch();
46895
47069
  const record2 = await this.records(principalKey);
46896
- const catalog = await this.readCatalog(record2);
47070
+ const catalog2 = await this.readCatalog(record2);
46897
47071
  const after = this.requirePrincipal();
46898
47072
  if (after.principalKey !== principalKey || this.options.accountEpoch() !== epoch) {
46899
47073
  throw new ChannelSettingsError("STALE_SNAPSHOT", "the signed-in account changed");
46900
47074
  }
46901
- return this.buildSnapshot(record2, catalog);
47075
+ return this.buildSnapshot(record2, catalog2);
46902
47076
  }
46903
47077
  async get(provider2) {
46904
47078
  const snapshot = await this.snapshot();
@@ -47083,22 +47257,22 @@ class ChannelSettingsService {
47083
47257
  });
47084
47258
  await this.options.persistence.save(principalKey, next);
47085
47259
  this.cache.set(principalKey, next);
47086
- const catalog = await this.readCatalog(next);
47087
- const snapshot = this.buildSnapshot(next, catalog);
47260
+ const catalog2 = await this.readCatalog(next);
47261
+ const snapshot = this.buildSnapshot(next, catalog2);
47088
47262
  this.options.onChanged(snapshot);
47089
47263
  await this.options.onCommitted?.(next).catch(() => void 0);
47090
- const settled = this.buildSnapshot(next, catalog);
47264
+ const settled = this.buildSnapshot(next, catalog2);
47091
47265
  const before = snapshot.connections[connection.provider];
47092
47266
  const after = settled.connections[connection.provider];
47093
47267
  const botFields = ["botCheck", "botUsername", "botName", "botAppRef", "botScopeRef", "status"];
47094
47268
  if (botFields.some((field) => after[field] !== before[field])) this.options.onChanged(settled);
47095
47269
  return after;
47096
47270
  }
47097
- buildSnapshot(record2, catalog) {
47271
+ buildSnapshot(record2, catalog2) {
47098
47272
  const { principalKey } = this.requirePrincipal();
47099
47273
  return buildChannelSettingsSnapshot({
47100
47274
  record: record2,
47101
- catalog,
47275
+ catalog: catalog2,
47102
47276
  accountScopeKey: principalKey,
47103
47277
  epoch: this.options.accountEpoch(),
47104
47278
  installed: this.options.installedAdapters(),
@@ -59934,7 +60108,6 @@ const runKeychainCommand = (command, args, stdin) => new Promise((resolve2, reje
59934
60108
  }, reject2);
59935
60109
  });
59936
60110
  const TICK_MS = 3e4;
59937
- const PROVIDERS = ["telegram", "slack", "discord"];
59938
60111
  function report(code) {
59939
60112
  process.stderr.write(`[channel-host] ${code}
59940
60113
  `);
@@ -59988,8 +60161,9 @@ async function runChannelHost() {
59988
60161
  if (!layout) report("CHANNEL_HOST_EXTENSIONS_DIR_DENIED");
59989
60162
  const sandbox = layout ? await loadAdapterSandbox({ resolveFrom: import.meta.url, deniedReads: layout.deniedReads }) : null;
59990
60163
  const bootstrapPath = join(dirname(fileURLToPath(import.meta.url)), "channel-extension-host.mjs");
60164
+ const officialRoot = join(dirname(fileURLToPath(import.meta.url)), "official-extensions");
59991
60165
  let opened = null;
59992
- let catalog = null;
60166
+ let catalog2 = null;
59993
60167
  const store = createHostStateStore({ dir: init.dataDir, safeStorage });
59994
60168
  const controller = createHostController({
59995
60169
  machineId: init.machine.id,
@@ -59999,7 +60173,7 @@ async function runChannelHost() {
59999
60173
  serverFor: (binding, token) => createHostServerClient({ apiBaseUrl: binding.apiBaseUrl, token }),
60000
60174
  openRuntime: async ({ binding, token, isPaused }) => {
60001
60175
  opened = await openHostRuntime({ init, binding, token, isPaused, safeStorage, bridge, sandbox, extensionRoot: layout?.extensionRoot ?? init.extensionsDir, bootstrapPath, report });
60002
- catalog = createRemoteExtensionCatalog({
60176
+ catalog2 = createRemoteExtensionCatalog({
60003
60177
  cachePath: join(init.dataDir, "extension-catalog.v1.json"),
60004
60178
  revocations: opened.extensions.revocations,
60005
60179
  fetch: (url2) => fetch(url2, { signal: AbortSignal.timeout(3e4) }),
@@ -60008,14 +60182,16 @@ async function runChannelHost() {
60008
60182
  return opened;
60009
60183
  },
60010
60184
  reconcileAdapters: async (specs) => {
60011
- if (!opened || !catalog) throw Object.assign(new Error("NOT_READY"), { code: "CHANNEL_HOST_CATALOG_UNAVAILABLE" });
60012
- await catalog.load();
60013
- await catalog.refresh();
60185
+ if (!opened) throw Object.assign(new Error("NOT_READY"), { code: "CHANNEL_HOST_NOT_READY" });
60186
+ if (catalog2) {
60187
+ await catalog2.load();
60188
+ await catalog2.refresh().catch(() => report("CHANNEL_HOST_CATALOG_REFRESH_FAILED"));
60189
+ }
60014
60190
  const { registry: registry2, store: extensionStore, revocations } = opened.extensions;
60015
60191
  return reconcileHostExtensions(specs, {
60016
60192
  registry: registry2,
60017
60193
  store: extensionStore,
60018
- catalog,
60194
+ official: createHostOfficialAdapterSource({ resourceRoot: officialRoot, remote: catalog2 }),
60019
60195
  isRevoked: (id2, version2) => revocations.isRevoked(id2, version2)
60020
60196
  });
60021
60197
  },
@@ -60027,22 +60203,15 @@ async function runChannelHost() {
60027
60203
  void controller.handleSettings(wire).then((answer) => bridge.send({ t: "settings-result", id: id2, wire: answer })).catch(() => bridge.send({ t: "settings-result", id: id2, wire: { sealed: "", error: "HOST_CALL_FAILED" } }));
60028
60204
  });
60029
60205
  await controller.start().catch(() => report("CHANNEL_HOST_RESUME_FAILED"));
60030
- const catalogConfigured = createRemoteExtensionCatalog({
60031
- cachePath: join(init.dataDir, "extension-catalog.probe.json"),
60032
- revocations: { record: async () => void 0 },
60033
- fetch: async () => {
60034
- throw new Error("probe");
60035
- },
60036
- onDiagnostic: () => void 0
60037
- }) !== null;
60206
+ const offered = await offeredChannelProviders(createHostOfficialAdapterSource({ resourceRoot: officialRoot, remote: null }));
60038
60207
  bridge.send({
60039
60208
  t: "ready",
60040
60209
  hostKey: key.publicKeyBase64,
60041
60210
  fingerprint: key.fingerprint,
60042
60211
  custody: "available",
60043
60212
  isolation: sandbox ? "available" : "unavailable",
60044
- // Without isolation or a signed catalog no adapter can run here, so nothing is offered.
60045
- providers: sandbox && catalogConfigured ? PROVIDERS : []
60213
+ // Without isolation no adapter may run here, so nothing is offered.
60214
+ providers: sandbox ? offered : []
60046
60215
  });
60047
60216
  const tick = setInterval(() => {
60048
60217
  void controller.tick().catch(() => report("CHANNEL_HOST_TICK_FAILED"));