@yakcc/cli 0.5.0-alpha.0 → 0.5.0-alpha.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/dist/bin.js CHANGED
@@ -77,6 +77,16 @@ function byteSwap32(arr) {
77
77
  }
78
78
  return arr;
79
79
  }
80
+ function bytesToHex(bytes) {
81
+ abytes(bytes);
82
+ if (hasHexBuiltin)
83
+ return bytes.toHex();
84
+ let hex = "";
85
+ for (let i = 0; i < bytes.length; i++) {
86
+ hex += hexes[bytes[i]];
87
+ }
88
+ return hex;
89
+ }
80
90
  function createHasher(hashCons, info = {}) {
81
91
  const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
82
92
  const tmp = hashCons(void 0);
@@ -87,13 +97,18 @@ function createHasher(hashCons, info = {}) {
87
97
  Object.assign(hashC, info);
88
98
  return Object.freeze(hashC);
89
99
  }
90
- var isLE, swap8IfBE, swap32IfBE;
100
+ var isLE, swap8IfBE, swap32IfBE, hasHexBuiltin, hexes;
91
101
  var init_utils = __esm({
92
102
  "../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/utils.js"() {
93
103
  "use strict";
94
104
  isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
95
105
  swap8IfBE = isLE ? (n) => n : (n) => byteSwap(n) >>> 0;
96
106
  swap32IfBE = isLE ? (u) => u : byteSwap32;
107
+ hasHexBuiltin = /* @__PURE__ */ (() => (
108
+ // @ts-ignore
109
+ typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
110
+ ))();
111
+ hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
97
112
  }
98
113
  });
99
114
 
@@ -682,7 +697,7 @@ __export(contract_id_exports, {
682
697
  });
683
698
  function contractIdFromBytes(canonical) {
684
699
  const digest = blake3(canonical);
685
- return bytesToHex(digest);
700
+ return bytesToHex2(digest);
686
701
  }
687
702
  function contractId(spec) {
688
703
  return contractIdFromBytes(canonicalize(spec));
@@ -690,7 +705,7 @@ function contractId(spec) {
690
705
  function isValidContractId(s) {
691
706
  return /^[0-9a-f]{64}$/.test(s);
692
707
  }
693
- function bytesToHex(bytes) {
708
+ function bytesToHex2(bytes) {
694
709
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
695
710
  }
696
711
  var init_contract_id = __esm({
@@ -929,13 +944,13 @@ function concatBytes(...arrays) {
929
944
  }
930
945
  return out;
931
946
  }
932
- function bytesToHex2(bytes) {
947
+ function bytesToHex3(bytes) {
933
948
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
934
949
  }
935
950
  function specHash(spec) {
936
951
  const bytes = canonicalize(spec);
937
952
  const digest = blake3(bytes);
938
- return bytesToHex2(digest);
953
+ return bytesToHex3(digest);
939
954
  }
940
955
  function blockMerkleRoot(triplet) {
941
956
  if (triplet.kind === "foreign") {
@@ -961,7 +976,7 @@ function blockMerkleRootLocal(triplet) {
961
976
  const proofRootBytes = blake3(proofInput);
962
977
  const rootInput = concatBytes(specHashBytes, implHashBytes, proofRootBytes);
963
978
  const rootBytes = blake3(rootInput);
964
- return bytesToHex2(rootBytes);
979
+ return bytesToHex3(rootBytes);
965
980
  }
966
981
  function blockMerkleRootForeign(triplet) {
967
982
  const identityObj = {
@@ -973,7 +988,7 @@ function blockMerkleRootForeign(triplet) {
973
988
  };
974
989
  const identityBytes = canonicalize(identityObj);
975
990
  const rootBytes = blake3(identityBytes);
976
- return bytesToHex2(rootBytes);
991
+ return bytesToHex3(rootBytes);
977
992
  }
978
993
  function isLocalTriplet(t) {
979
994
  return t.kind !== "foreign";
@@ -993,7 +1008,7 @@ var init_merkle = __esm({
993
1008
 
994
1009
  // ../contracts/dist/canonical-ast.js
995
1010
  import { Project, ScriptKind, SyntaxKind, ts } from "ts-morph";
996
- function bytesToHex3(bytes) {
1011
+ function bytesToHex4(bytes) {
997
1012
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
998
1013
  }
999
1014
  function findEnclosingNode(file, range) {
@@ -1134,7 +1149,7 @@ function canonicalAstHash(source, sourceRange) {
1134
1149
  const renames = collectLocalRenames(root);
1135
1150
  const canonical = emitCanonical(root, renames);
1136
1151
  const digest = blake3(TEXT_ENCODER3.encode(canonical));
1137
- return bytesToHex3(digest);
1152
+ return bytesToHex4(digest);
1138
1153
  }
1139
1154
  var CanonicalAstParseError, TEXT_ENCODER3;
1140
1155
  var init_canonical_ast = __esm({
@@ -2227,7 +2242,7 @@ function isStricterThan(aRoot, bRoot, edgeSet, allRoots) {
2227
2242
  }
2228
2243
  return false;
2229
2244
  }
2230
- function bytesToHex4(bytes) {
2245
+ function bytesToHex5(bytes) {
2231
2246
  let hex = "";
2232
2247
  for (let i = 0; i < bytes.length; i++) {
2233
2248
  hex += bytes[i]?.toString(16).padStart(2, "0");
@@ -2859,7 +2874,7 @@ var init_storage = __esm({
2859
2874
  ORDER BY b.block_merkle_root ASC`).all();
2860
2875
  if (blockRows.length === 0)
2861
2876
  return [];
2862
- const EMPTY_SENTINEL = bytesToHex4(blake3(new Uint8Array(0)));
2877
+ const EMPTY_SENTINEL = bytesToHex5(blake3(new Uint8Array(0)));
2863
2878
  const allRoots = blockRows.map((r) => r.block_merkle_root);
2864
2879
  const placeholders = allRoots.map(() => "?").join(", ");
2865
2880
  const artifactRows = this.db.prepare(`SELECT block_merkle_root, path, bytes
@@ -2873,7 +2888,7 @@ var init_storage = __esm({
2873
2888
  entry = { implSourceHash: EMPTY_SENTINEL, manifestJsonHash: EMPTY_SENTINEL };
2874
2889
  hashMap.set(row.block_merkle_root, entry);
2875
2890
  }
2876
- const digest = bytesToHex4(blake3(new Uint8Array(row.bytes)));
2891
+ const digest = bytesToHex5(blake3(new Uint8Array(row.bytes)));
2877
2892
  if (row.path === "impl.ts") {
2878
2893
  entry.implSourceHash = digest;
2879
2894
  } else if (row.path === "proof/manifest.json") {
@@ -2912,7 +2927,7 @@ var init_storage = __esm({
2912
2927
  if (entry.workspacePath.startsWith("/") || entry.workspacePath.includes("..")) {
2913
2928
  throw new Error(`storeWorkspacePlumbing: workspacePath must be workspace-relative and must not contain '..': ${entry.workspacePath}`);
2914
2929
  }
2915
- const actualHash = bytesToHex4(blake3(entry.contentBytes));
2930
+ const actualHash = bytesToHex5(blake3(entry.contentBytes));
2916
2931
  if (actualHash !== entry.contentHash) {
2917
2932
  throw new Error(`storeWorkspacePlumbing: contentHash mismatch for ${entry.workspacePath}: stored=${entry.contentHash}, computed=${actualHash}`);
2918
2933
  }
@@ -2963,7 +2978,7 @@ var init_storage = __esm({
2963
2978
  if (entry.sourceFile.startsWith("/") || entry.sourceFile.includes("..")) {
2964
2979
  throw new Error(`storeSourceFileGlue: sourceFile must be workspace-relative and must not contain '..': ${entry.sourceFile}`);
2965
2980
  }
2966
- const actualHash = bytesToHex4(blake3(entry.contentBlob));
2981
+ const actualHash = bytesToHex5(blake3(entry.contentBlob));
2967
2982
  if (actualHash !== entry.contentHash) {
2968
2983
  throw new Error(`storeSourceFileGlue: contentHash mismatch for ${entry.sourceFile}: stored=${entry.contentHash}, computed=${actualHash}`);
2969
2984
  }
@@ -3888,11 +3903,11 @@ async function serveRegistry(registry, options) {
3888
3903
  console.error("[serveRegistry] Unhandled request error:", err);
3889
3904
  });
3890
3905
  });
3891
- await new Promise((resolve6, reject) => {
3906
+ await new Promise((resolve7, reject) => {
3892
3907
  server.once("error", reject);
3893
3908
  server.listen(port, host, () => {
3894
3909
  server.removeListener("error", reject);
3895
- resolve6();
3910
+ resolve7();
3896
3911
  });
3897
3912
  });
3898
3913
  const address = server.address();
@@ -3909,16 +3924,16 @@ async function serveRegistry(registry, options) {
3909
3924
  if (closed)
3910
3925
  return Promise.resolve();
3911
3926
  closed = true;
3912
- return new Promise((resolve6, reject) => {
3927
+ return new Promise((resolve7, reject) => {
3913
3928
  server.close((err) => {
3914
3929
  if (err !== void 0) {
3915
3930
  if (err.code === "ERR_SERVER_NOT_RUNNING") {
3916
- resolve6();
3931
+ resolve7();
3917
3932
  } else {
3918
3933
  reject(err);
3919
3934
  }
3920
3935
  } else {
3921
- resolve6();
3936
+ resolve7();
3922
3937
  }
3923
3938
  });
3924
3939
  });
@@ -4018,11 +4033,11 @@ async function runFederationServe(argv, logger, opts) {
4018
4033
  if (opts?.noBlock === true) {
4019
4034
  return { code: 0, handle };
4020
4035
  }
4021
- await new Promise((resolve6) => {
4036
+ await new Promise((resolve7) => {
4022
4037
  const shutdown = () => {
4023
4038
  handle.close().then(() => {
4024
- registry.close().finally(resolve6);
4025
- }).catch(resolve6);
4039
+ registry.close().finally(resolve7);
4040
+ }).catch(resolve7);
4026
4041
  };
4027
4042
  process.once("SIGINT", shutdown);
4028
4043
  process.once("SIGTERM", shutdown);
@@ -4177,7 +4192,7 @@ var init_federation = __esm({
4177
4192
  // src/bin.ts
4178
4193
  import { realpathSync } from "fs";
4179
4194
  import { createRequire as createRequire3 } from "module";
4180
- import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
4195
+ import { fileURLToPath as fileURLToPath4, pathToFileURL } from "url";
4181
4196
 
4182
4197
  // src/commands/bootstrap.ts
4183
4198
  init_dist();
@@ -4242,18 +4257,18 @@ function byteSwap322(arr) {
4242
4257
  return arr;
4243
4258
  }
4244
4259
  var swap32IfBE2 = isLE2 ? (u) => u : byteSwap322;
4245
- var hasHexBuiltin = /* @__PURE__ */ (() => (
4260
+ var hasHexBuiltin2 = /* @__PURE__ */ (() => (
4246
4261
  // @ts-ignore
4247
4262
  typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
4248
4263
  ))();
4249
- var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
4250
- function bytesToHex5(bytes) {
4264
+ var hexes2 = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
4265
+ function bytesToHex6(bytes) {
4251
4266
  abytes2(bytes);
4252
- if (hasHexBuiltin)
4267
+ if (hasHexBuiltin2)
4253
4268
  return bytes.toHex();
4254
4269
  let hex = "";
4255
4270
  for (let i = 0; i < bytes.length; i++) {
4256
- hex += hexes[bytes[i]];
4271
+ hex += hexes2[bytes[i]];
4257
4272
  }
4258
4273
  return hex;
4259
4274
  }
@@ -4651,7 +4666,7 @@ async function renameWithRetry(src, dst) {
4651
4666
  }
4652
4667
  if (attempt < MAX_ATTEMPTS - 1) {
4653
4668
  const delay = BACKOFF_MS[attempt] ?? BACKOFF_MS[BACKOFF_MS.length - 1] ?? 160;
4654
- await new Promise((resolve6) => setTimeout(resolve6, delay));
4669
+ await new Promise((resolve7) => setTimeout(resolve7, delay));
4655
4670
  }
4656
4671
  }
4657
4672
  }
@@ -4712,12 +4727,12 @@ function normalizeSource(s) {
4712
4727
  var encoder = new TextEncoder();
4713
4728
  function sourceHash(unitSource) {
4714
4729
  const normalized = normalizeSource(unitSource);
4715
- return bytesToHex5(blake32(encoder.encode(normalized)));
4730
+ return bytesToHex6(blake32(encoder.encode(normalized)));
4716
4731
  }
4717
4732
  function keyFromIntentInputs(inputs) {
4718
4733
  const { sourceHash: sh, modelTag, promptVersion, schemaVersion } = inputs;
4719
4734
  const raw = `${sh}\0${modelTag}\0${promptVersion}\0${schemaVersion}`;
4720
- return bytesToHex5(blake32(encoder.encode(raw)));
4735
+ return bytesToHex6(blake32(encoder.encode(raw)));
4721
4736
  }
4722
4737
 
4723
4738
  // ../shave/dist/corpus/ai-derived.js
@@ -4757,7 +4772,7 @@ async function extractFromAiDerivedCached(intentCard, source, cacheDir, model, p
4757
4772
  if (cached === void 0)
4758
4773
  return void 0;
4759
4774
  const bytes = encoder2.encode(cached.content);
4760
- const contentHash = bytesToHex5(blake32(bytes));
4775
+ const contentHash = bytesToHex6(blake32(bytes));
4761
4776
  void intentCard;
4762
4777
  return {
4763
4778
  source: "ai-derived",
@@ -4789,7 +4804,7 @@ async function extractFromPropsFile(propsFilePath, _intentCard, source) {
4789
4804
  return void 0;
4790
4805
  }
4791
4806
  const bytes = encoder3.encode(fileContent);
4792
- const contentHash = bytesToHex5(blake32(bytes));
4807
+ const contentHash = bytesToHex6(blake32(bytes));
4793
4808
  return {
4794
4809
  source: "props-file",
4795
4810
  bytes,
@@ -4914,7 +4929,7 @@ function extractFromDocumentedUsage(intentCard, source) {
4914
4929
  `);
4915
4930
  }
4916
4931
  const bytes = encoder4.encode(content);
4917
- const contentHash = bytesToHex5(blake32(bytes));
4932
+ const contentHash = bytesToHex6(blake32(bytes));
4918
4933
  return {
4919
4934
  source: "documented-usage",
4920
4935
  bytes,
@@ -4991,7 +5006,7 @@ var UPSTREAM_TEST_PATH = "property-tests.fast-check.ts";
4991
5006
  function extractFromUpstreamTest(intentCard, source) {
4992
5007
  const content = buildUpstreamTestContent(intentCard, source);
4993
5008
  const bytes = encoder5.encode(content);
4994
- const contentHash = bytesToHex5(blake32(bytes));
5009
+ const contentHash = bytesToHex6(blake32(bytes));
4995
5010
  return {
4996
5011
  source: "upstream-test",
4997
5012
  bytes,
@@ -5511,7 +5526,7 @@ function safeCanonicalAstHash(node, nodeSource, fullSource, start, end) {
5511
5526
  return canonicalAstHash(fullSource, { start, end });
5512
5527
  } catch {
5513
5528
  const TEXT_ENC = new TextEncoder();
5514
- return bytesToHex5(blake32(TEXT_ENC.encode(nodeSource)));
5529
+ return bytesToHex6(blake32(TEXT_ENC.encode(nodeSource)));
5515
5530
  }
5516
5531
  }
5517
5532
  }
@@ -6912,9 +6927,9 @@ async function extractIntent(unitSource, ctx) {
6912
6927
  } catch (err) {
6913
6928
  console.warn(`[shave extractIntent] Corrupt cache entry for key ${cacheKey} (${err instanceof Error ? err.message : String(err)}); treating as miss.`);
6914
6929
  const { unlink: unlink2 } = await import("fs/promises");
6915
- const { join: join21 } = await import("path");
6930
+ const { join: join25 } = await import("path");
6916
6931
  const shard = cacheKey.slice(0, 3);
6917
- const filePath = join21(ctx.cacheDir, shard, `${cacheKey}.json`);
6932
+ const filePath = join25(ctx.cacheDir, shard, `${cacheKey}.json`);
6918
6933
  await unlink2(filePath).catch(() => {
6919
6934
  });
6920
6935
  }
@@ -8866,18 +8881,411 @@ async function compile(argv, logger, opts) {
8866
8881
  // src/index.ts
8867
8882
  init_federation();
8868
8883
 
8869
- // src/commands/hooks-aider-install.ts
8870
- import { existsSync as existsSync3, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync4 } from "fs";
8884
+ // ../hooks-base/dist/telemetry.js
8885
+ init_blake3();
8886
+ init_utils();
8887
+ import { appendFileSync as appendFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync6 } from "fs";
8871
8888
  import { homedir } from "os";
8872
- import { join as join10 } from "path";
8889
+ import { join as join13 } from "path";
8890
+
8891
+ // ../hooks-base/dist/telemetry-sink.js
8892
+ import { appendFileSync, mkdirSync as mkdirSync5 } from "fs";
8893
+ import { join as join11 } from "path";
8894
+
8895
+ // ../hooks-base/dist/telemetry-config.js
8896
+ var DEFAULT_TELEMETRY_ENDPOINT = "https://metrics.yakcc.com";
8897
+ function resolveTelemetryConfig(env = process.env) {
8898
+ const fullIntent = env.YAKCC_TELEMETRY_FULL_INTENT === "1";
8899
+ if (env.YAKCC_TELEMETRY_DISABLED === "1") {
8900
+ return { disabled: true, endpoint: DEFAULT_TELEMETRY_ENDPOINT, fullIntent };
8901
+ }
8902
+ const rawEndpoint = env.YAKCC_TELEMETRY_ENDPOINT;
8903
+ if (rawEndpoint === "off") {
8904
+ return { disabled: true, endpoint: DEFAULT_TELEMETRY_ENDPOINT, fullIntent };
8905
+ }
8906
+ const endpoint = rawEndpoint !== void 0 && rawEndpoint !== "" ? rawEndpoint : DEFAULT_TELEMETRY_ENDPOINT;
8907
+ return { disabled: false, endpoint, fullIntent };
8908
+ }
8909
+
8910
+ // ../hooks-base/dist/telemetry-wire.js
8911
+ import { readFileSync as readFileSync5 } from "fs";
8912
+ import { dirname as dirname6, join as join10, resolve as resolve3 } from "path";
8913
+ import { fileURLToPath as fileURLToPath2 } from "url";
8914
+ var SCHEMA_VERSION2 = 1;
8915
+ var _cachedSource = null;
8916
+ function buildSource() {
8917
+ if (_cachedSource !== null)
8918
+ return _cachedSource;
8919
+ let cliVersion = "unknown";
8920
+ try {
8921
+ const __filename = fileURLToPath2(import.meta.url);
8922
+ const pkgPath = resolve3(join10(dirname6(__filename), "../package.json"));
8923
+ const pkgJson = JSON.parse(readFileSync5(pkgPath, "utf-8"));
8924
+ cliVersion = typeof pkgJson.version === "string" ? pkgJson.version : "unknown";
8925
+ } catch {
8926
+ }
8927
+ _cachedSource = {
8928
+ cliVersion,
8929
+ platform: process.platform,
8930
+ nodeVersion: process.version
8931
+ };
8932
+ return _cachedSource;
8933
+ }
8934
+ function buildEnvelope(events, sessionId, now = Date.now()) {
8935
+ return {
8936
+ schemaVersion: SCHEMA_VERSION2,
8937
+ sessionId,
8938
+ events,
8939
+ emittedAt: now,
8940
+ source: buildSource()
8941
+ };
8942
+ }
8943
+
8944
+ // ../hooks-base/dist/telemetry-sink.js
8945
+ var _SINK_FALLBACK_SESSION_ID = (() => {
8946
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
8947
+ return crypto.randomUUID();
8948
+ }
8949
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
8950
+ const r = Math.floor(Math.random() * 16);
8951
+ const v = c === "x" ? r : r & 3 | 8;
8952
+ return v.toString(16);
8953
+ });
8954
+ })();
8955
+ function _resolveSinkSessionId() {
8956
+ return process.env.CLAUDE_SESSION_ID ?? _SINK_FALLBACK_SESSION_ID;
8957
+ }
8958
+ var NoOpSink = class {
8959
+ send(_event) {
8960
+ }
8961
+ };
8962
+ var FileSink = class {
8963
+ dir;
8964
+ sessionId;
8965
+ initialized = false;
8966
+ // at-most-once warn set (DEC-TELEMETRY-EXPORT-FAIL-SILENT-005)
8967
+ warnedClasses = /* @__PURE__ */ new Set();
8968
+ constructor(dir, sessionId) {
8969
+ this.dir = dir;
8970
+ this.sessionId = sessionId ?? _resolveSinkSessionId();
8971
+ }
8972
+ send(event) {
8973
+ try {
8974
+ if (!this.initialized) {
8975
+ mkdirSync5(this.dir, { recursive: true });
8976
+ this.initialized = true;
8977
+ }
8978
+ const filePath = join11(this.dir, `${this.sessionId}.jsonl`);
8979
+ appendFileSync(filePath, `${JSON.stringify(event)}
8980
+ `, "utf-8");
8981
+ } catch (err) {
8982
+ this._warnOnce(err);
8983
+ }
8984
+ }
8985
+ _warnOnce(err) {
8986
+ const cls = err instanceof Error ? err.constructor.name : "UnknownError";
8987
+ if (!this.warnedClasses.has(cls)) {
8988
+ this.warnedClasses.add(cls);
8989
+ console.warn(`[yakcc telemetry] FileSink error (${cls}):`, err);
8990
+ }
8991
+ }
8992
+ };
8993
+ var BATCH_FLUSH_INTERVAL_MS = 5e3;
8994
+ var BATCH_FLUSH_SIZE = 50;
8995
+ var FETCH_TIMEOUT_MS = 1e4;
8996
+ var HttpsBatcherSink = class {
8997
+ endpoint;
8998
+ sessionId;
8999
+ buffer = [];
9000
+ timer = null;
9001
+ flushing = false;
9002
+ // at-most-once warn set (DEC-TELEMETRY-EXPORT-FAIL-SILENT-005)
9003
+ warnedClasses = /* @__PURE__ */ new Set();
9004
+ _beforeExitHandler;
9005
+ _registered = false;
9006
+ constructor(endpoint, sessionId) {
9007
+ this.endpoint = endpoint;
9008
+ this.sessionId = sessionId ?? _resolveSinkSessionId();
9009
+ this._beforeExitHandler = () => {
9010
+ this._flushSync();
9011
+ };
9012
+ }
9013
+ send(event) {
9014
+ this.buffer.push(event);
9015
+ this._ensureTimer();
9016
+ if (this.buffer.length >= BATCH_FLUSH_SIZE) {
9017
+ this._scheduleFlush();
9018
+ }
9019
+ }
9020
+ /** Start the interval timer and register the beforeExit handler (lazy, once). */
9021
+ _ensureTimer() {
9022
+ if (this._registered)
9023
+ return;
9024
+ this._registered = true;
9025
+ this.timer = setInterval(() => {
9026
+ this._scheduleFlush();
9027
+ }, BATCH_FLUSH_INTERVAL_MS);
9028
+ if (this.timer && typeof this.timer.unref === "function") {
9029
+ this.timer.unref();
9030
+ }
9031
+ process.on("beforeExit", this._beforeExitHandler);
9032
+ }
9033
+ /** Schedule a flush on the next microtask tick (non-blocking). */
9034
+ _scheduleFlush() {
9035
+ if (this.buffer.length === 0)
9036
+ return;
9037
+ const batch = this.buffer.splice(0, this.buffer.length);
9038
+ void this._flush(batch);
9039
+ }
9040
+ /** Async flush — fire-and-forget. DEC-TELEMETRY-EXPORT-FAIL-SILENT-005. */
9041
+ async _flush(batch) {
9042
+ if (batch.length === 0)
9043
+ return;
9044
+ const envelope = buildEnvelope(batch, this.sessionId);
9045
+ const controller = new AbortController();
9046
+ const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
9047
+ try {
9048
+ const response = await fetch(this.endpoint, {
9049
+ method: "POST",
9050
+ headers: {
9051
+ "Content-Type": "application/json",
9052
+ "User-Agent": `yakcc-hooks-base/${envelope.source.cliVersion} (${envelope.source.platform}; node-${envelope.source.nodeVersion})`
9053
+ },
9054
+ body: JSON.stringify(envelope),
9055
+ signal: controller.signal
9056
+ });
9057
+ if (!response.ok) {
9058
+ this._warnOnce(new Error(`HTTP ${response.status}`), "HttpError");
9059
+ }
9060
+ } catch (err) {
9061
+ this._warnOnce(err);
9062
+ } finally {
9063
+ clearTimeout(timeoutId);
9064
+ }
9065
+ }
9066
+ /**
9067
+ * Best-effort exit-flush called from `beforeExit`.
9068
+ *
9069
+ * @decision DEC-TELEMETRY-EXPORT-BATCHING-004
9070
+ * `beforeExit` fires when the Node event loop becomes empty (not via process.exit()).
9071
+ * We start the async flush here. Because `beforeExit` fires when the loop is empty,
9072
+ * the pending fetch promise keeps the loop alive long enough for the flush to complete
9073
+ * under normal conditions (no explicit process.exit()). If `process.exit()` is called
9074
+ * by the host, inflight events are dropped — this is the documented NG5 behavior
9075
+ * (no retry queue, at-most-once delivery).
9076
+ *
9077
+ * Previous implementation used `Atomics.wait` as a bounded sleep, but
9078
+ * `Atomics.wait` on the main thread throws `TypeError` in Node ≥ 16 when
9079
+ * `--experimental-vm-modules` or other thread guards are active (Node 22 always
9080
+ * rejects it on the main thread). The async-only approach is correct here because
9081
+ * `beforeExit` itself is an async boundary: the outstanding fetch promise will
9082
+ * re-trigger the loop, and if the process exits without the loop draining further,
9083
+ * the events are already acknowledged as best-effort (DEC-TELEMETRY-EXPORT-BATCHING-004).
9084
+ */
9085
+ _flushSync() {
9086
+ if (this.buffer.length === 0)
9087
+ return;
9088
+ if (this.flushing)
9089
+ return;
9090
+ this.flushing = true;
9091
+ const batch = this.buffer.splice(0, this.buffer.length);
9092
+ void this._flush(batch);
9093
+ }
9094
+ /**
9095
+ * Deregister timer and handlers (for tests and clean shutdown).
9096
+ * Drains the buffer without flushing — events in-buffer at dispose time are
9097
+ * dropped (NG5: at-most-once delivery). This is intentional for test isolation:
9098
+ * after dispose(), no further async fetch calls will originate from this sink.
9099
+ */
9100
+ dispose() {
9101
+ if (this.timer !== null) {
9102
+ clearInterval(this.timer);
9103
+ this.timer = null;
9104
+ }
9105
+ process.removeListener("beforeExit", this._beforeExitHandler);
9106
+ this._registered = false;
9107
+ this.buffer.length = 0;
9108
+ }
9109
+ _warnOnce(err, classOverride) {
9110
+ const cls = classOverride ?? (err instanceof Error ? err.constructor.name : "UnknownError");
9111
+ if (!this.warnedClasses.has(cls)) {
9112
+ this.warnedClasses.add(cls);
9113
+ console.warn(`[yakcc telemetry] HttpsBatcherSink error (${cls}):`, err);
9114
+ }
9115
+ }
9116
+ };
9117
+ var CompositeSink = class {
9118
+ sinks;
9119
+ constructor(sinks) {
9120
+ this.sinks = sinks;
9121
+ }
9122
+ send(event) {
9123
+ for (const sink of this.sinks) {
9124
+ try {
9125
+ sink.send(event);
9126
+ } catch {
9127
+ }
9128
+ }
9129
+ }
9130
+ /**
9131
+ * Propagate dispose() to inner sinks that support it.
9132
+ * Safe to call multiple times (inner sinks are idempotent on dispose).
9133
+ * @internal — for test isolation and clean process shutdown.
9134
+ */
9135
+ dispose() {
9136
+ for (const sink of this.sinks) {
9137
+ if (sink instanceof HttpsBatcherSink) {
9138
+ sink.dispose();
9139
+ }
9140
+ }
9141
+ }
9142
+ };
9143
+ var _sinkSingleton = null;
9144
+ function selectSink(env = process.env, config) {
9145
+ if (_sinkSingleton !== null)
9146
+ return _sinkSingleton;
9147
+ _sinkSingleton = _buildSink(config ?? resolveTelemetryConfig(env));
9148
+ return _sinkSingleton;
9149
+ }
9150
+ function _buildSink(config, sessionId) {
9151
+ if (config.disabled) {
9152
+ return new NoOpSink();
9153
+ }
9154
+ const endpoint = config.endpoint;
9155
+ if (endpoint.startsWith("file://")) {
9156
+ const dir = endpoint.slice("file://".length);
9157
+ return new FileSink(dir, sessionId);
9158
+ }
9159
+ if (endpoint.startsWith("https://")) {
9160
+ return new CompositeSink([new HttpsBatcherSink(endpoint, sessionId)]);
9161
+ }
9162
+ console.warn(`[yakcc telemetry] Unknown endpoint scheme: ${endpoint} \u2014 using NoOpSink`);
9163
+ return new NoOpSink();
9164
+ }
9165
+
9166
+ // ../hooks-base/dist/enforcement-config.js
9167
+ import { existsSync as existsSync3, readFileSync as readFileSync6 } from "fs";
9168
+ import { join as join12 } from "path";
9169
+
9170
+ // ../hooks-base/dist/telemetry.js
9171
+ var FALLBACK_SESSION_ID = (() => {
9172
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
9173
+ return crypto.randomUUID();
9174
+ }
9175
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
9176
+ const r = Math.floor(Math.random() * 16);
9177
+ const v = c === "x" ? r : r & 3 | 8;
9178
+ return v.toString(16);
9179
+ });
9180
+ })();
9181
+ function resolveSessionId() {
9182
+ return process.env.CLAUDE_SESSION_ID ?? FALLBACK_SESSION_ID;
9183
+ }
9184
+ function resolveTelemetryDir() {
9185
+ return process.env.YAKCC_TELEMETRY_DIR ?? join13(homedir(), ".yakcc", "telemetry");
9186
+ }
9187
+ function hashIntent(intentText) {
9188
+ const encoded = new TextEncoder().encode(intentText);
9189
+ const digest = blake3(encoded);
9190
+ return bytesToHex(digest);
9191
+ }
9192
+ function appendTelemetryEvent(event, sessionId, dir) {
9193
+ if (!existsSync4(dir)) {
9194
+ mkdirSync6(dir, { recursive: true });
9195
+ }
9196
+ const filePath = join13(dir, `${sessionId}.jsonl`);
9197
+ appendFileSync2(filePath, `${JSON.stringify(event)}
9198
+ `, "utf-8");
9199
+ try {
9200
+ selectSink().send(event);
9201
+ } catch {
9202
+ }
9203
+ }
9204
+
9205
+ // src/commands/hook-intercept.ts
9206
+ var WINDOWS_ILLEGAL_FILENAME_RE = /[<>:"/\\|?*\x00-\x1f]/;
9207
+ function sanitizeSessionId(raw) {
9208
+ if (WINDOWS_ILLEGAL_FILENAME_RE.test(raw)) return null;
9209
+ return raw;
9210
+ }
9211
+ var ALLOWED_TOOL_NAMES = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit"]);
9212
+ async function hookIntercept(argv, logger, options) {
9213
+ void argv;
9214
+ void logger;
9215
+ const stdinStream = options?.stdin ?? process.stdin;
9216
+ const telemetryDir = options?.telemetryDir ?? resolveTelemetryDir();
9217
+ const appendEvent = options?.appendEvent ?? appendTelemetryEvent;
9218
+ const now = options?.now ?? Date.now;
9219
+ const start = now();
9220
+ try {
9221
+ const chunks = [];
9222
+ for await (const chunk of stdinStream) {
9223
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
9224
+ }
9225
+ const stdinText = Buffer.concat(chunks).toString("utf-8").trim();
9226
+ if (!stdinText) {
9227
+ return 0;
9228
+ }
9229
+ let parsed;
9230
+ try {
9231
+ parsed = JSON.parse(stdinText);
9232
+ } catch {
9233
+ return 0;
9234
+ }
9235
+ if (typeof parsed !== "object" || parsed === null) {
9236
+ return 0;
9237
+ }
9238
+ const payload = parsed;
9239
+ const toolName = payload.tool_name;
9240
+ if (typeof toolName !== "string" || !ALLOWED_TOOL_NAMES.has(toolName)) {
9241
+ return 0;
9242
+ }
9243
+ const validToolName = toolName;
9244
+ let sessionId;
9245
+ const payloadSessionId = payload.session_id;
9246
+ if (typeof payloadSessionId === "string" && payloadSessionId.length > 0) {
9247
+ const sanitized = sanitizeSessionId(payloadSessionId);
9248
+ sessionId = sanitized ?? resolveSessionId();
9249
+ } else {
9250
+ sessionId = resolveSessionId();
9251
+ }
9252
+ const toolInput = typeof payload.tool_input === "object" && payload.tool_input !== null ? payload.tool_input : {};
9253
+ const intentText = typeof toolInput.new_string === "string" ? toolInput.new_string : typeof toolInput.content === "string" ? toolInput.content : "";
9254
+ const end = now();
9255
+ const event = {
9256
+ t: end,
9257
+ intentHash: hashIntent(intentText),
9258
+ toolName: validToolName,
9259
+ candidateCount: 0,
9260
+ // Phase 1: no registry query
9261
+ topScore: null,
9262
+ // Phase 1: no registry query
9263
+ substituted: false,
9264
+ // Phase 1: never substitutes
9265
+ substitutedAtomHash: null,
9266
+ // Phase 1: never substitutes
9267
+ latencyMs: end - start,
9268
+ outcome: "passthrough"
9269
+ // D-HOOK-5 canonical value per plan section 3
9270
+ };
9271
+ appendEvent(event, sessionId, telemetryDir);
9272
+ } catch {
9273
+ }
9274
+ return 0;
9275
+ }
9276
+
9277
+ // src/commands/hooks-aider-install.ts
9278
+ import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync7, rmSync, writeFileSync as writeFileSync4 } from "fs";
9279
+ import { homedir as homedir2 } from "os";
9280
+ import { join as join14 } from "path";
8873
9281
  import { parseArgs as parseArgs6 } from "util";
8874
9282
  var AIDER_HOOK_MARKER_FILENAME = "yakcc-aider-hook.json";
8875
9283
  var YAKCC_AIDER_MARKER = "yakcc-hook-v1-aider";
8876
9284
  var HOOK_COMMAND = "yakcc hook-intercept";
8877
9285
  function readMarker(markerPath) {
8878
- if (!existsSync3(markerPath)) return null;
9286
+ if (!existsSync5(markerPath)) return null;
8879
9287
  try {
8880
- return JSON.parse(readFileSync5(markerPath, "utf-8"));
9288
+ return JSON.parse(readFileSync7(markerPath, "utf-8"));
8881
9289
  } catch {
8882
9290
  return null;
8883
9291
  }
@@ -8902,10 +9310,10 @@ async function hooksAiderInstall(argv, logger, overrideAiderDir) {
8902
9310
  logger.error(`error: ${err.message}`);
8903
9311
  return 1;
8904
9312
  }
8905
- const aiderDir = overrideAiderDir ?? join10(homedir(), ".aider");
8906
- const markerPath = join10(aiderDir, AIDER_HOOK_MARKER_FILENAME);
9313
+ const aiderDir = overrideAiderDir ?? join14(homedir2(), ".aider");
9314
+ const markerPath = join14(aiderDir, AIDER_HOOK_MARKER_FILENAME);
8907
9315
  try {
8908
- mkdirSync5(aiderDir, { recursive: true });
9316
+ mkdirSync7(aiderDir, { recursive: true });
8909
9317
  } catch (err) {
8910
9318
  logger.error(`error: cannot create ${aiderDir}: ${String(err)}`);
8911
9319
  return 1;
@@ -8951,26 +9359,194 @@ async function hooksAiderInstall(argv, logger, overrideAiderDir) {
8951
9359
  return 0;
8952
9360
  }
8953
9361
 
8954
- // src/commands/hooks-cursor-install.ts
8955
- import { existsSync as existsSync4, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
8956
- import { join as join11 } from "path";
9362
+ // src/commands/hooks-cline-install.ts
9363
+ import { existsSync as existsSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync8, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
9364
+ import { homedir as homedir3 } from "os";
9365
+ import { join as join15 } from "path";
8957
9366
  import { parseArgs as parseArgs7 } from "util";
9367
+ var CLINE_HOOK_MARKER_FILENAME = "yakcc-cline-hook.json";
9368
+ var YAKCC_CLINE_MARKER = "yakcc-hook-v1-cline";
9369
+ var HOOK_COMMAND2 = "yakcc hook-intercept";
9370
+ function readMarker2(markerPath) {
9371
+ if (!existsSync6(markerPath)) return null;
9372
+ try {
9373
+ return JSON.parse(readFileSync8(markerPath, "utf-8"));
9374
+ } catch {
9375
+ return null;
9376
+ }
9377
+ }
9378
+ function isYakccInstalled2(markerPath) {
9379
+ const marker = readMarker2(markerPath);
9380
+ return marker !== null && marker._yakcc === YAKCC_CLINE_MARKER;
9381
+ }
9382
+ async function hooksClineInstall(argv, logger, overrideClineDir) {
9383
+ let parsed;
9384
+ try {
9385
+ parsed = parseArgs7({
9386
+ args: [...argv],
9387
+ options: {
9388
+ target: { type: "string", short: "t" },
9389
+ uninstall: { type: "boolean" }
9390
+ },
9391
+ allowPositionals: false,
9392
+ strict: true
9393
+ });
9394
+ } catch (err) {
9395
+ logger.error(`error: ${err.message}`);
9396
+ return 1;
9397
+ }
9398
+ const clineDir = overrideClineDir ?? join15(homedir3(), ".config", "cline");
9399
+ const markerPath = join15(clineDir, CLINE_HOOK_MARKER_FILENAME);
9400
+ try {
9401
+ mkdirSync8(clineDir, { recursive: true });
9402
+ } catch (err) {
9403
+ logger.error(`error: cannot create ${clineDir}: ${String(err)}`);
9404
+ return 1;
9405
+ }
9406
+ if (parsed.values.uninstall) {
9407
+ if (!isYakccInstalled2(markerPath)) {
9408
+ logger.log("yakcc cline hook not installed \u2014 nothing to uninstall.");
9409
+ return 0;
9410
+ }
9411
+ try {
9412
+ rmSync2(markerPath);
9413
+ } catch (err) {
9414
+ logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
9415
+ return 1;
9416
+ }
9417
+ logger.log(`yakcc cline hook marker removed: ${markerPath}`);
9418
+ return 0;
9419
+ }
9420
+ if (isYakccInstalled2(markerPath)) {
9421
+ logger.log(`yakcc cline hook already installed at ${markerPath} (idempotent).`);
9422
+ return 0;
9423
+ }
9424
+ const marker = {
9425
+ command: HOOK_COMMAND2,
9426
+ description: "yakcc tool-call interception hook for Cline",
9427
+ sessionEnvVar: "CLINE_SESSION_ID",
9428
+ telemetryPrefix: "cline",
9429
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
9430
+ _yakcc: YAKCC_CLINE_MARKER,
9431
+ note: "Cline (saoudrizwan.claude-dev) does not yet expose synchronous tool-call interception via a stable Node.js API. This marker documents the intended wiring (DEC-CLI-HOOKS-CLINE-INSTALL-001). When the Cline extension API stabilises, hook activation requires no reinstall."
9432
+ };
9433
+ try {
9434
+ writeFileSync5(markerPath, `${JSON.stringify(marker, null, 2)}
9435
+ `, "utf-8");
9436
+ } catch (err) {
9437
+ logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
9438
+ return 1;
9439
+ }
9440
+ logger.log(`yakcc cline hook marker installed: ${markerPath}`);
9441
+ logger.log("note: Cline tool-call interception API not yet stable \u2014 see marker for details.");
9442
+ return 0;
9443
+ }
9444
+
9445
+ // src/commands/hooks-continue-install.ts
9446
+ import { existsSync as existsSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync9, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
9447
+ import { homedir as homedir4 } from "os";
9448
+ import { join as join16 } from "path";
9449
+ import { parseArgs as parseArgs8 } from "util";
9450
+ var CONTINUE_HOOK_MARKER_FILENAME = "yakcc-continue-hook.json";
9451
+ var YAKCC_CONTINUE_MARKER = "yakcc-hook-v1-continue";
9452
+ var HOOK_COMMAND3 = "yakcc hook-intercept";
9453
+ function readMarker3(markerPath) {
9454
+ if (!existsSync7(markerPath)) return null;
9455
+ try {
9456
+ return JSON.parse(readFileSync9(markerPath, "utf-8"));
9457
+ } catch {
9458
+ return null;
9459
+ }
9460
+ }
9461
+ function isYakccInstalled3(markerPath) {
9462
+ const marker = readMarker3(markerPath);
9463
+ return marker !== null && marker._yakcc === YAKCC_CONTINUE_MARKER;
9464
+ }
9465
+ async function hooksContinueInstall(argv, logger, overrideContinueDir) {
9466
+ let parsed;
9467
+ try {
9468
+ parsed = parseArgs8({
9469
+ args: [...argv],
9470
+ options: {
9471
+ target: { type: "string", short: "t" },
9472
+ uninstall: { type: "boolean" }
9473
+ },
9474
+ allowPositionals: false,
9475
+ strict: true
9476
+ });
9477
+ } catch (err) {
9478
+ logger.error(`error: ${err.message}`);
9479
+ return 1;
9480
+ }
9481
+ const continueDir = overrideContinueDir ?? join16(homedir4(), ".continue");
9482
+ const markerPath = join16(continueDir, CONTINUE_HOOK_MARKER_FILENAME);
9483
+ try {
9484
+ mkdirSync9(continueDir, { recursive: true });
9485
+ } catch (err) {
9486
+ logger.error(`error: cannot create ${continueDir}: ${String(err)}`);
9487
+ return 1;
9488
+ }
9489
+ if (parsed.values.uninstall) {
9490
+ if (!isYakccInstalled3(markerPath)) {
9491
+ logger.log("yakcc continue hook not installed \u2014 nothing to uninstall.");
9492
+ return 0;
9493
+ }
9494
+ try {
9495
+ rmSync3(markerPath);
9496
+ } catch (err) {
9497
+ logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
9498
+ return 1;
9499
+ }
9500
+ logger.log(`yakcc continue hook marker removed: ${markerPath}`);
9501
+ return 0;
9502
+ }
9503
+ if (isYakccInstalled3(markerPath)) {
9504
+ logger.log(`yakcc continue hook already installed at ${markerPath} (idempotent).`);
9505
+ return 0;
9506
+ }
9507
+ const marker = {
9508
+ command: HOOK_COMMAND3,
9509
+ description: "yakcc tool-call interception hook for Continue.dev",
9510
+ sessionEnvVar: "CONTINUE_SESSION_ID",
9511
+ telemetryPrefix: "continue",
9512
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
9513
+ _yakcc: YAKCC_CONTINUE_MARKER,
9514
+ note: "Continue.dev (continue.continue) does not yet expose synchronous tool-call interception via a stable Node.js API. This marker documents the intended wiring (DEC-CLI-HOOKS-CONTINUE-INSTALL-001). When the Continue.dev API stabilises, hook activation requires no reinstall."
9515
+ };
9516
+ try {
9517
+ writeFileSync6(markerPath, `${JSON.stringify(marker, null, 2)}
9518
+ `, "utf-8");
9519
+ } catch (err) {
9520
+ logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
9521
+ return 1;
9522
+ }
9523
+ logger.log(`yakcc continue hook marker installed: ${markerPath}`);
9524
+ logger.log(
9525
+ "note: Continue.dev tool-call interception API not yet stable \u2014 see marker for details."
9526
+ );
9527
+ return 0;
9528
+ }
9529
+
9530
+ // src/commands/hooks-cursor-install.ts
9531
+ import { existsSync as existsSync8, mkdirSync as mkdirSync10, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
9532
+ import { join as join17 } from "path";
9533
+ import { parseArgs as parseArgs9 } from "util";
8958
9534
  var CURSOR_HOOK_MARKER_FILENAME = "yakcc-cursor-hook.json";
8959
9535
  var YAKCC_CURSOR_MARKER = "yakcc-hook-v1-cursor";
8960
- var HOOK_COMMAND2 = "yakcc hook-intercept";
9536
+ var HOOK_COMMAND4 = "yakcc hook-intercept";
8961
9537
  function readCursorSettings(settingsPath) {
8962
- if (!existsSync4(settingsPath)) return {};
9538
+ if (!existsSync8(settingsPath)) return {};
8963
9539
  try {
8964
- return JSON.parse(readFileSync6(settingsPath, "utf-8"));
9540
+ return JSON.parse(readFileSync10(settingsPath, "utf-8"));
8965
9541
  } catch {
8966
9542
  return {};
8967
9543
  }
8968
9544
  }
8969
9545
  function writeCursorSettings(settingsPath, settings) {
8970
- writeFileSync5(settingsPath, `${JSON.stringify(settings, null, 2)}
9546
+ writeFileSync7(settingsPath, `${JSON.stringify(settings, null, 2)}
8971
9547
  `, "utf-8");
8972
9548
  }
8973
- function isYakccInstalled2(settings) {
9549
+ function isYakccInstalled4(settings) {
8974
9550
  const hooks = settings.hooks;
8975
9551
  if (hooks == null || typeof hooks !== "object") return false;
8976
9552
  const yakccEntry = hooks.yakcc;
@@ -8978,7 +9554,7 @@ function isYakccInstalled2(settings) {
8978
9554
  return yakccEntry._yakcc === YAKCC_CURSOR_MARKER;
8979
9555
  }
8980
9556
  function applyInstall(settings) {
8981
- if (isYakccInstalled2(settings)) {
9557
+ if (isYakccInstalled4(settings)) {
8982
9558
  return { settings, alreadyInstalled: true };
8983
9559
  }
8984
9560
  return {
@@ -8987,7 +9563,7 @@ function applyInstall(settings) {
8987
9563
  hooks: {
8988
9564
  ...settings.hooks ?? {},
8989
9565
  yakcc: {
8990
- command: HOOK_COMMAND2,
9566
+ command: HOOK_COMMAND4,
8991
9567
  description: "yakcc tool-call interception hook for Cursor",
8992
9568
  sessionEnvVar: "CURSOR_SESSION_ID",
8993
9569
  _yakcc: YAKCC_CURSOR_MARKER
@@ -8998,7 +9574,7 @@ function applyInstall(settings) {
8998
9574
  };
8999
9575
  }
9000
9576
  function applyUninstall(settings) {
9001
- if (!isYakccInstalled2(settings)) {
9577
+ if (!isYakccInstalled4(settings)) {
9002
9578
  return { settings, wasInstalled: false };
9003
9579
  }
9004
9580
  const { yakcc: _removed, ...remainingHooks } = settings.hooks ?? {};
@@ -9007,7 +9583,7 @@ function applyUninstall(settings) {
9007
9583
  return { settings: newSettings, wasInstalled: true };
9008
9584
  }
9009
9585
  async function hooksCursorInstall(argv, logger) {
9010
- const { values } = parseArgs7({
9586
+ const { values } = parseArgs9({
9011
9587
  args: [...argv],
9012
9588
  options: {
9013
9589
  target: { type: "string", short: "t" },
@@ -9017,11 +9593,11 @@ async function hooksCursorInstall(argv, logger) {
9017
9593
  strict: true
9018
9594
  });
9019
9595
  const targetDir = values.target ?? ".";
9020
- const cursorDir = join11(targetDir, ".cursor");
9021
- const settingsPath = join11(cursorDir, "settings.json");
9022
- const markerPath = join11(cursorDir, CURSOR_HOOK_MARKER_FILENAME);
9596
+ const cursorDir = join17(targetDir, ".cursor");
9597
+ const settingsPath = join17(cursorDir, "settings.json");
9598
+ const markerPath = join17(cursorDir, CURSOR_HOOK_MARKER_FILENAME);
9023
9599
  try {
9024
- mkdirSync6(cursorDir, { recursive: true });
9600
+ mkdirSync10(cursorDir, { recursive: true });
9025
9601
  } catch (err) {
9026
9602
  logger.error(`error: cannot create ${cursorDir}: ${String(err)}`);
9027
9603
  return 1;
@@ -9049,11 +9625,11 @@ async function hooksCursorInstall(argv, logger) {
9049
9625
  return 1;
9050
9626
  }
9051
9627
  try {
9052
- writeFileSync5(
9628
+ writeFileSync7(
9053
9629
  markerPath,
9054
9630
  `${JSON.stringify(
9055
9631
  {
9056
- command: HOOK_COMMAND2,
9632
+ command: HOOK_COMMAND4,
9057
9633
  description: "yakcc tool-call interception hook for Cursor",
9058
9634
  sessionEnvVar: "CURSOR_SESSION_ID",
9059
9635
  telemetryPrefix: "cursor",
@@ -9073,7 +9649,7 @@ async function hooksCursorInstall(argv, logger) {
9073
9649
  logger.log(`yakcc cursor hook already installed at ${settingsPath} (idempotent).`);
9074
9650
  } else {
9075
9651
  logger.log(`yakcc cursor hook installed at ${settingsPath}`);
9076
- logger.log(`hook command: ${HOOK_COMMAND2}`);
9652
+ logger.log(`hook command: ${HOOK_COMMAND4}`);
9077
9653
  logger.log("session env var: CURSOR_SESSION_ID");
9078
9654
  logger.log(`marker: ${markerPath}`);
9079
9655
  logger.log("note: Cursor tool-call interception API not yet stable \u2014 see marker for details.");
@@ -9082,27 +9658,27 @@ async function hooksCursorInstall(argv, logger) {
9082
9658
  }
9083
9659
 
9084
9660
  // src/commands/hooks-install.ts
9085
- import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "fs";
9086
- import { join as join12 } from "path";
9087
- import { parseArgs as parseArgs8 } from "util";
9661
+ import { existsSync as existsSync9, mkdirSync as mkdirSync11, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
9662
+ import { join as join18 } from "path";
9663
+ import { parseArgs as parseArgs10 } from "util";
9088
9664
  var HOOK_EVENT = "PreToolUse";
9089
9665
  var HOOK_MATCHER = "Edit|Write|MultiEdit";
9090
- var HOOK_COMMAND3 = "yakcc hook-intercept";
9666
+ var HOOK_COMMAND5 = "yakcc hook-intercept";
9091
9667
  var YAKCC_MARKER = "yakcc-hook-v1";
9092
9668
  function readSettings(settingsPath) {
9093
- if (!existsSync5(settingsPath)) return {};
9669
+ if (!existsSync9(settingsPath)) return {};
9094
9670
  try {
9095
- return JSON.parse(readFileSync7(settingsPath, "utf-8"));
9671
+ return JSON.parse(readFileSync11(settingsPath, "utf-8"));
9096
9672
  } catch {
9097
9673
  return {};
9098
9674
  }
9099
9675
  }
9100
9676
  function writeSettings(settingsPath, settings) {
9101
- writeFileSync6(settingsPath, `${JSON.stringify(settings, null, 2)}
9677
+ writeFileSync8(settingsPath, `${JSON.stringify(settings, null, 2)}
9102
9678
  `, "utf-8");
9103
9679
  }
9104
9680
  function buildYakccHookObject() {
9105
- return { type: "command", command: HOOK_COMMAND3, _yakcc: YAKCC_MARKER };
9681
+ return { type: "command", command: HOOK_COMMAND5, _yakcc: YAKCC_MARKER };
9106
9682
  }
9107
9683
  function isYakccEntry(entry) {
9108
9684
  return entry.hooks.some((h) => h._yakcc === YAKCC_MARKER);
@@ -9141,7 +9717,7 @@ function applyUninstall2(settings) {
9141
9717
  return { settings: newSettings, wasInstalled: true };
9142
9718
  }
9143
9719
  async function hooksClaudeCodeInstall(argv, logger) {
9144
- const { values } = parseArgs8({
9720
+ const { values } = parseArgs10({
9145
9721
  args: [...argv],
9146
9722
  options: {
9147
9723
  target: { type: "string", short: "t" },
@@ -9151,11 +9727,11 @@ async function hooksClaudeCodeInstall(argv, logger) {
9151
9727
  strict: true
9152
9728
  });
9153
9729
  const targetDir = values.target ?? ".";
9154
- const claudeDir = join12(targetDir, ".claude");
9155
- const settingsPath = join12(claudeDir, "settings.json");
9156
- const claudeMdPath = join12(claudeDir, "CLAUDE.md");
9730
+ const claudeDir = join18(targetDir, ".claude");
9731
+ const settingsPath = join18(claudeDir, "settings.json");
9732
+ const claudeMdPath = join18(claudeDir, "CLAUDE.md");
9157
9733
  try {
9158
- mkdirSync7(claudeDir, { recursive: true });
9734
+ mkdirSync11(claudeDir, { recursive: true });
9159
9735
  } catch (err) {
9160
9736
  logger.error(`error: cannot create ${claudeDir}: ${String(err)}`);
9161
9737
  return 1;
@@ -9182,9 +9758,9 @@ async function hooksClaudeCodeInstall(argv, logger) {
9182
9758
  logger.error(`error: cannot write ${settingsPath}: ${String(err)}`);
9183
9759
  return 1;
9184
9760
  }
9185
- if (existsSync5(claudeMdPath)) {
9761
+ if (existsSync9(claudeMdPath)) {
9186
9762
  try {
9187
- rmSync2(claudeMdPath);
9763
+ rmSync4(claudeMdPath);
9188
9764
  } catch (err) {
9189
9765
  logger.error(`warning: cannot remove v0 stub ${claudeMdPath}: ${String(err)}`);
9190
9766
  }
@@ -9193,31 +9769,31 @@ async function hooksClaudeCodeInstall(argv, logger) {
9193
9769
  logger.log(`yakcc hook already installed at ${settingsPath} (idempotent).`);
9194
9770
  } else {
9195
9771
  logger.log(`yakcc hook installed at ${settingsPath}`);
9196
- logger.log(`tool-call interception: ${HOOK_MATCHER} \u2192 ${HOOK_COMMAND3}`);
9772
+ logger.log(`tool-call interception: ${HOOK_MATCHER} \u2192 ${HOOK_COMMAND5}`);
9197
9773
  }
9198
9774
  return 0;
9199
9775
  }
9200
9776
 
9201
9777
  // src/commands/hooks-windsurf-install.ts
9202
- import { existsSync as existsSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
9203
- import { join as join13 } from "path";
9204
- import { parseArgs as parseArgs9 } from "util";
9778
+ import { existsSync as existsSync10, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
9779
+ import { join as join19 } from "path";
9780
+ import { parseArgs as parseArgs11 } from "util";
9205
9781
  var WINDSURF_HOOK_MARKER_FILENAME = "yakcc-windsurf-hook.json";
9206
9782
  var YAKCC_WINDSURF_MARKER = "yakcc-hook-v1-windsurf";
9207
- var HOOK_COMMAND4 = "yakcc hook-intercept";
9783
+ var HOOK_COMMAND6 = "yakcc hook-intercept";
9208
9784
  function readWindsurfSettings(settingsPath) {
9209
- if (!existsSync6(settingsPath)) return {};
9785
+ if (!existsSync10(settingsPath)) return {};
9210
9786
  try {
9211
- return JSON.parse(readFileSync8(settingsPath, "utf-8"));
9787
+ return JSON.parse(readFileSync12(settingsPath, "utf-8"));
9212
9788
  } catch {
9213
9789
  return {};
9214
9790
  }
9215
9791
  }
9216
9792
  function writeWindsurfSettings(settingsPath, settings) {
9217
- writeFileSync7(settingsPath, `${JSON.stringify(settings, null, 2)}
9793
+ writeFileSync9(settingsPath, `${JSON.stringify(settings, null, 2)}
9218
9794
  `, "utf-8");
9219
9795
  }
9220
- function isYakccInstalled3(settings) {
9796
+ function isYakccInstalled5(settings) {
9221
9797
  const hooks = settings.hooks;
9222
9798
  if (hooks == null || typeof hooks !== "object") return false;
9223
9799
  const yakccEntry = hooks.yakcc;
@@ -9225,7 +9801,7 @@ function isYakccInstalled3(settings) {
9225
9801
  return yakccEntry._yakcc === YAKCC_WINDSURF_MARKER;
9226
9802
  }
9227
9803
  function applyInstall3(settings) {
9228
- if (isYakccInstalled3(settings)) {
9804
+ if (isYakccInstalled5(settings)) {
9229
9805
  return { settings, alreadyInstalled: true };
9230
9806
  }
9231
9807
  return {
@@ -9234,7 +9810,7 @@ function applyInstall3(settings) {
9234
9810
  hooks: {
9235
9811
  ...settings.hooks ?? {},
9236
9812
  yakcc: {
9237
- command: HOOK_COMMAND4,
9813
+ command: HOOK_COMMAND6,
9238
9814
  description: "yakcc tool-call interception hook for Windsurf",
9239
9815
  sessionEnvVar: "WINDSURF_SESSION_ID",
9240
9816
  _yakcc: YAKCC_WINDSURF_MARKER
@@ -9245,7 +9821,7 @@ function applyInstall3(settings) {
9245
9821
  };
9246
9822
  }
9247
9823
  function applyUninstall3(settings) {
9248
- if (!isYakccInstalled3(settings)) {
9824
+ if (!isYakccInstalled5(settings)) {
9249
9825
  return { settings, wasInstalled: false };
9250
9826
  }
9251
9827
  const { yakcc: _removed, ...remainingHooks } = settings.hooks ?? {};
@@ -9254,7 +9830,7 @@ function applyUninstall3(settings) {
9254
9830
  return { settings: newSettings, wasInstalled: true };
9255
9831
  }
9256
9832
  async function hooksWindsurfInstall(argv, logger) {
9257
- const { values } = parseArgs9({
9833
+ const { values } = parseArgs11({
9258
9834
  args: [...argv],
9259
9835
  options: {
9260
9836
  target: { type: "string", short: "t" },
@@ -9264,11 +9840,11 @@ async function hooksWindsurfInstall(argv, logger) {
9264
9840
  strict: true
9265
9841
  });
9266
9842
  const targetDir = values.target ?? ".";
9267
- const windsurfDir = join13(targetDir, ".windsurf");
9268
- const settingsPath = join13(windsurfDir, "settings.json");
9269
- const markerPath = join13(windsurfDir, WINDSURF_HOOK_MARKER_FILENAME);
9843
+ const windsurfDir = join19(targetDir, ".windsurf");
9844
+ const settingsPath = join19(windsurfDir, "settings.json");
9845
+ const markerPath = join19(windsurfDir, WINDSURF_HOOK_MARKER_FILENAME);
9270
9846
  try {
9271
- mkdirSync8(windsurfDir, { recursive: true });
9847
+ mkdirSync12(windsurfDir, { recursive: true });
9272
9848
  } catch (err) {
9273
9849
  logger.error(`error: cannot create ${windsurfDir}: ${String(err)}`);
9274
9850
  return 1;
@@ -9296,11 +9872,11 @@ async function hooksWindsurfInstall(argv, logger) {
9296
9872
  return 1;
9297
9873
  }
9298
9874
  try {
9299
- writeFileSync7(
9875
+ writeFileSync9(
9300
9876
  markerPath,
9301
9877
  `${JSON.stringify(
9302
9878
  {
9303
- command: HOOK_COMMAND4,
9879
+ command: HOOK_COMMAND6,
9304
9880
  description: "yakcc tool-call interception hook for Windsurf",
9305
9881
  sessionEnvVar: "WINDSURF_SESSION_ID",
9306
9882
  telemetryPrefix: "windsurf",
@@ -9320,7 +9896,7 @@ async function hooksWindsurfInstall(argv, logger) {
9320
9896
  logger.log(`yakcc windsurf hook already installed at ${settingsPath} (idempotent).`);
9321
9897
  } else {
9322
9898
  logger.log(`yakcc windsurf hook installed at ${settingsPath}`);
9323
- logger.log(`hook command: ${HOOK_COMMAND4}`);
9899
+ logger.log(`hook command: ${HOOK_COMMAND6}`);
9324
9900
  logger.log("session env var: WINDSURF_SESSION_ID");
9325
9901
  logger.log(`marker: ${markerPath}`);
9326
9902
  logger.log(
@@ -9332,43 +9908,43 @@ async function hooksWindsurfInstall(argv, logger) {
9332
9908
 
9333
9909
  // src/commands/init.ts
9334
9910
  init_dist2();
9335
- import { existsSync as existsSync11, mkdirSync as mkdirSync11, readFileSync as readFileSync11, writeFileSync as writeFileSync10 } from "fs";
9336
- import { join as join18 } from "path";
9911
+ import { existsSync as existsSync13, mkdirSync as mkdirSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
9912
+ import { join as join22 } from "path";
9337
9913
  import { parseArgs as parseArgs12 } from "util";
9338
9914
 
9339
9915
  // src/lib/ide-detect.ts
9340
- import { existsSync as existsSync7 } from "fs";
9341
- import { homedir as homedir2 } from "os";
9342
- import { join as join14 } from "path";
9916
+ import { existsSync as existsSync11 } from "fs";
9917
+ import { homedir as homedir5 } from "os";
9918
+ import { join as join20 } from "path";
9343
9919
  function buildCandidatePaths(home) {
9344
9920
  const platform = process.platform;
9345
9921
  const cursorCandidates = (() => {
9346
9922
  if (platform === "darwin") {
9347
- return [join14(home, "Library", "Application Support", "Cursor")];
9923
+ return [join20(home, "Library", "Application Support", "Cursor")];
9348
9924
  }
9349
9925
  if (platform === "win32") {
9350
9926
  const appdata = process.env.APPDATA;
9351
9927
  if (appdata !== void 0) {
9352
- return [join14(appdata, "Cursor")];
9928
+ return [join20(appdata, "Cursor")];
9353
9929
  }
9354
- return [join14(home, "AppData", "Roaming", "Cursor")];
9930
+ return [join20(home, "AppData", "Roaming", "Cursor")];
9355
9931
  }
9356
- return [join14(home, ".config", "Cursor")];
9932
+ return [join20(home, ".config", "Cursor")];
9357
9933
  })();
9358
9934
  const clineCandidates = [
9359
- join14(home, ".config", "cline"),
9935
+ join20(home, ".config", "cline"),
9360
9936
  // VS Code extension dir marker — check the containing directory prefix since
9361
9937
  // the actual extension dir includes a version suffix.
9362
- join14(home, ".vscode", "extensions", "saoudrizwan.claude-dev")
9938
+ join20(home, ".vscode", "extensions", "saoudrizwan.claude-dev")
9363
9939
  ];
9364
9940
  const continueCandidates = [
9365
- join14(home, ".continue"),
9366
- join14(home, ".vscode", "extensions", "continue.continue")
9941
+ join20(home, ".continue"),
9942
+ join20(home, ".vscode", "extensions", "continue.continue")
9367
9943
  ];
9368
- const windsurfCandidates = [join14(home, ".windsurf")];
9369
- const aiderCandidates = [join14(home, ".aider")];
9944
+ const windsurfCandidates = [join20(home, ".windsurf")];
9945
+ const aiderCandidates = [join20(home, ".aider")];
9370
9946
  return {
9371
- "claude-code": [join14(home, ".claude")],
9947
+ "claude-code": [join20(home, ".claude")],
9372
9948
  cursor: cursorCandidates,
9373
9949
  cline: clineCandidates,
9374
9950
  continue: continueCandidates,
@@ -9377,12 +9953,12 @@ function buildCandidatePaths(home) {
9377
9953
  };
9378
9954
  }
9379
9955
  function detectInstalledIdes(overrideHome) {
9380
- const home = overrideHome ?? homedir2();
9956
+ const home = overrideHome ?? homedir5();
9381
9957
  const candidates = buildCandidatePaths(home);
9382
9958
  const detected = [];
9383
9959
  for (const [name, paths] of Object.entries(candidates)) {
9384
9960
  for (const configDir of paths) {
9385
- if (existsSync7(configDir)) {
9961
+ if (existsSync11(configDir)) {
9386
9962
  detected.push({ name, configDir, installed: true });
9387
9963
  break;
9388
9964
  }
@@ -9399,185 +9975,17 @@ var KNOWN_IDE_NAMES = [
9399
9975
  "aider"
9400
9976
  ];
9401
9977
 
9402
- // src/commands/hooks-cline-install.ts
9403
- import { existsSync as existsSync8, mkdirSync as mkdirSync9, readFileSync as readFileSync9, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "fs";
9404
- import { homedir as homedir3 } from "os";
9405
- import { join as join15 } from "path";
9406
- import { parseArgs as parseArgs10 } from "util";
9407
- var CLINE_HOOK_MARKER_FILENAME = "yakcc-cline-hook.json";
9408
- var YAKCC_CLINE_MARKER = "yakcc-hook-v1-cline";
9409
- var HOOK_COMMAND5 = "yakcc hook-intercept";
9410
- function readMarker2(markerPath) {
9411
- if (!existsSync8(markerPath)) return null;
9412
- try {
9413
- return JSON.parse(readFileSync9(markerPath, "utf-8"));
9414
- } catch {
9415
- return null;
9416
- }
9417
- }
9418
- function isYakccInstalled4(markerPath) {
9419
- const marker = readMarker2(markerPath);
9420
- return marker !== null && marker._yakcc === YAKCC_CLINE_MARKER;
9421
- }
9422
- async function hooksClineInstall(argv, logger, overrideClineDir) {
9423
- let parsed;
9424
- try {
9425
- parsed = parseArgs10({
9426
- args: [...argv],
9427
- options: {
9428
- target: { type: "string", short: "t" },
9429
- uninstall: { type: "boolean" }
9430
- },
9431
- allowPositionals: false,
9432
- strict: true
9433
- });
9434
- } catch (err) {
9435
- logger.error(`error: ${err.message}`);
9436
- return 1;
9437
- }
9438
- const clineDir = overrideClineDir ?? join15(homedir3(), ".config", "cline");
9439
- const markerPath = join15(clineDir, CLINE_HOOK_MARKER_FILENAME);
9440
- try {
9441
- mkdirSync9(clineDir, { recursive: true });
9442
- } catch (err) {
9443
- logger.error(`error: cannot create ${clineDir}: ${String(err)}`);
9444
- return 1;
9445
- }
9446
- if (parsed.values.uninstall) {
9447
- if (!isYakccInstalled4(markerPath)) {
9448
- logger.log("yakcc cline hook not installed \u2014 nothing to uninstall.");
9449
- return 0;
9450
- }
9451
- try {
9452
- rmSync3(markerPath);
9453
- } catch (err) {
9454
- logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
9455
- return 1;
9456
- }
9457
- logger.log(`yakcc cline hook marker removed: ${markerPath}`);
9458
- return 0;
9459
- }
9460
- if (isYakccInstalled4(markerPath)) {
9461
- logger.log(`yakcc cline hook already installed at ${markerPath} (idempotent).`);
9462
- return 0;
9463
- }
9464
- const marker = {
9465
- command: HOOK_COMMAND5,
9466
- description: "yakcc tool-call interception hook for Cline",
9467
- sessionEnvVar: "CLINE_SESSION_ID",
9468
- telemetryPrefix: "cline",
9469
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
9470
- _yakcc: YAKCC_CLINE_MARKER,
9471
- note: "Cline (saoudrizwan.claude-dev) does not yet expose synchronous tool-call interception via a stable Node.js API. This marker documents the intended wiring (DEC-CLI-HOOKS-CLINE-INSTALL-001). When the Cline extension API stabilises, hook activation requires no reinstall."
9472
- };
9473
- try {
9474
- writeFileSync8(markerPath, `${JSON.stringify(marker, null, 2)}
9475
- `, "utf-8");
9476
- } catch (err) {
9477
- logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
9478
- return 1;
9479
- }
9480
- logger.log(`yakcc cline hook marker installed: ${markerPath}`);
9481
- logger.log("note: Cline tool-call interception API not yet stable \u2014 see marker for details.");
9482
- return 0;
9483
- }
9484
-
9485
- // src/commands/hooks-continue-install.ts
9486
- import { existsSync as existsSync9, mkdirSync as mkdirSync10, readFileSync as readFileSync10, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "fs";
9487
- import { homedir as homedir4 } from "os";
9488
- import { join as join16 } from "path";
9489
- import { parseArgs as parseArgs11 } from "util";
9490
- var CONTINUE_HOOK_MARKER_FILENAME = "yakcc-continue-hook.json";
9491
- var YAKCC_CONTINUE_MARKER = "yakcc-hook-v1-continue";
9492
- var HOOK_COMMAND6 = "yakcc hook-intercept";
9493
- function readMarker3(markerPath) {
9494
- if (!existsSync9(markerPath)) return null;
9495
- try {
9496
- return JSON.parse(readFileSync10(markerPath, "utf-8"));
9497
- } catch {
9498
- return null;
9499
- }
9500
- }
9501
- function isYakccInstalled5(markerPath) {
9502
- const marker = readMarker3(markerPath);
9503
- return marker !== null && marker._yakcc === YAKCC_CONTINUE_MARKER;
9504
- }
9505
- async function hooksContinueInstall(argv, logger, overrideContinueDir) {
9506
- let parsed;
9507
- try {
9508
- parsed = parseArgs11({
9509
- args: [...argv],
9510
- options: {
9511
- target: { type: "string", short: "t" },
9512
- uninstall: { type: "boolean" }
9513
- },
9514
- allowPositionals: false,
9515
- strict: true
9516
- });
9517
- } catch (err) {
9518
- logger.error(`error: ${err.message}`);
9519
- return 1;
9520
- }
9521
- const continueDir = overrideContinueDir ?? join16(homedir4(), ".continue");
9522
- const markerPath = join16(continueDir, CONTINUE_HOOK_MARKER_FILENAME);
9523
- try {
9524
- mkdirSync10(continueDir, { recursive: true });
9525
- } catch (err) {
9526
- logger.error(`error: cannot create ${continueDir}: ${String(err)}`);
9527
- return 1;
9528
- }
9529
- if (parsed.values.uninstall) {
9530
- if (!isYakccInstalled5(markerPath)) {
9531
- logger.log("yakcc continue hook not installed \u2014 nothing to uninstall.");
9532
- return 0;
9533
- }
9534
- try {
9535
- rmSync4(markerPath);
9536
- } catch (err) {
9537
- logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
9538
- return 1;
9539
- }
9540
- logger.log(`yakcc continue hook marker removed: ${markerPath}`);
9541
- return 0;
9542
- }
9543
- if (isYakccInstalled5(markerPath)) {
9544
- logger.log(`yakcc continue hook already installed at ${markerPath} (idempotent).`);
9545
- return 0;
9546
- }
9547
- const marker = {
9548
- command: HOOK_COMMAND6,
9549
- description: "yakcc tool-call interception hook for Continue.dev",
9550
- sessionEnvVar: "CONTINUE_SESSION_ID",
9551
- telemetryPrefix: "continue",
9552
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
9553
- _yakcc: YAKCC_CONTINUE_MARKER,
9554
- note: "Continue.dev (continue.continue) does not yet expose synchronous tool-call interception via a stable Node.js API. This marker documents the intended wiring (DEC-CLI-HOOKS-CONTINUE-INSTALL-001). When the Continue.dev API stabilises, hook activation requires no reinstall."
9555
- };
9556
- try {
9557
- writeFileSync9(markerPath, `${JSON.stringify(marker, null, 2)}
9558
- `, "utf-8");
9559
- } catch (err) {
9560
- logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
9561
- return 1;
9562
- }
9563
- logger.log(`yakcc continue hook marker installed: ${markerPath}`);
9564
- logger.log(
9565
- "note: Continue.dev tool-call interception API not yet stable \u2014 see marker for details."
9566
- );
9567
- return 0;
9568
- }
9569
-
9570
9978
  // src/commands/seed-yakcc.ts
9571
9979
  init_dist2();
9572
- import { existsSync as existsSync10 } from "fs";
9573
- import { dirname as dirname6, join as join17 } from "path";
9574
- import { fileURLToPath as fileURLToPath2 } from "url";
9980
+ import { existsSync as existsSync12 } from "fs";
9981
+ import { dirname as dirname7, join as join21 } from "path";
9982
+ import { fileURLToPath as fileURLToPath3 } from "url";
9575
9983
  function findBootstrapSqlite() {
9576
- let dir = dirname6(fileURLToPath2(import.meta.url));
9984
+ let dir = dirname7(fileURLToPath3(import.meta.url));
9577
9985
  for (let i = 0; i < 30; i++) {
9578
- const candidate = join17(dir, "bootstrap", "yakcc.registry.sqlite");
9579
- if (existsSync10(candidate)) return candidate;
9580
- const parent = dirname6(dir);
9986
+ const candidate = join21(dir, "bootstrap", "yakcc.registry.sqlite");
9987
+ if (existsSync12(candidate)) return candidate;
9988
+ const parent = dirname7(dir);
9581
9989
  if (parent === dir) break;
9582
9990
  dir = parent;
9583
9991
  }
@@ -9666,16 +10074,16 @@ var YAKCC_SUBDIRS = ["registry", "telemetry", "config"];
9666
10074
  var DEFAULT_REGISTRY_SUBPATH = ".yakcc/registry.sqlite";
9667
10075
  var RC_FILENAME = ".yakccrc.json";
9668
10076
  function readRc(targetDir) {
9669
- const rcPath = join18(targetDir, RC_FILENAME);
9670
- if (!existsSync11(rcPath)) return null;
10077
+ const rcPath = join22(targetDir, RC_FILENAME);
10078
+ if (!existsSync13(rcPath)) return null;
9671
10079
  try {
9672
- return JSON.parse(readFileSync11(rcPath, "utf-8"));
10080
+ return JSON.parse(readFileSync13(rcPath, "utf-8"));
9673
10081
  } catch {
9674
10082
  return null;
9675
10083
  }
9676
10084
  }
9677
10085
  function writeRc(targetDir, rc) {
9678
- writeFileSync10(join18(targetDir, RC_FILENAME), `${JSON.stringify(rc, null, 2)}
10086
+ writeFileSync10(join22(targetDir, RC_FILENAME), `${JSON.stringify(rc, null, 2)}
9679
10087
  `, "utf-8");
9680
10088
  }
9681
10089
  function validatePeerUrl(url) {
@@ -9700,8 +10108,8 @@ function parseIdeList(raw) {
9700
10108
  return { ok: parts };
9701
10109
  }
9702
10110
  async function installHookForIde(ide, targetDir, logger, overrideHome) {
9703
- const { homedir: homedir7 } = await import("os");
9704
- const home = overrideHome ?? homedir7();
10111
+ const { homedir: homedir8 } = await import("os");
10112
+ const home = overrideHome ?? homedir8();
9705
10113
  switch (ide) {
9706
10114
  case "claude-code": {
9707
10115
  const code = await hooksClaudeCodeInstall(["--target", targetDir], logger);
@@ -9714,15 +10122,15 @@ async function installHookForIde(ide, targetDir, logger, overrideHome) {
9714
10122
  break;
9715
10123
  }
9716
10124
  case "cline": {
9717
- const { join: join21 } = await import("path");
9718
- const clineDir = join21(home, ".config", "cline");
10125
+ const { join: join25 } = await import("path");
10126
+ const clineDir = join25(home, ".config", "cline");
9719
10127
  const code = await hooksClineInstall([], logger, clineDir);
9720
10128
  if (code !== 0) throw new Error(`cline hook install failed (exit ${code})`);
9721
10129
  break;
9722
10130
  }
9723
10131
  case "continue": {
9724
- const { join: join21 } = await import("path");
9725
- const continueDir = join21(home, ".continue");
10132
+ const { join: join25 } = await import("path");
10133
+ const continueDir = join25(home, ".continue");
9726
10134
  const code = await hooksContinueInstall([], logger, continueDir);
9727
10135
  if (code !== 0) throw new Error(`continue hook install failed (exit ${code})`);
9728
10136
  break;
@@ -9733,8 +10141,8 @@ async function installHookForIde(ide, targetDir, logger, overrideHome) {
9733
10141
  break;
9734
10142
  }
9735
10143
  case "aider": {
9736
- const { join: join21 } = await import("path");
9737
- const aiderDir = join21(home, ".aider");
10144
+ const { join: join25 } = await import("path");
10145
+ const aiderDir = join25(home, ".aider");
9738
10146
  const code = await hooksAiderInstall([], logger, aiderDir);
9739
10147
  if (code !== 0) throw new Error(`aider hook install failed (exit ${code})`);
9740
10148
  break;
@@ -9796,12 +10204,12 @@ async function init(argv, logger, opts) {
9796
10204
  }
9797
10205
  explicitIdes = parseResult.ok;
9798
10206
  }
9799
- const yakccDir = join18(targetDir, YAKCC_DIR);
9800
- const yakccDirExists = existsSync11(yakccDir);
10207
+ const yakccDir = join22(targetDir, YAKCC_DIR);
10208
+ const yakccDirExists = existsSync13(yakccDir);
9801
10209
  try {
9802
- mkdirSync11(yakccDir, { recursive: true });
10210
+ mkdirSync13(yakccDir, { recursive: true });
9803
10211
  for (const sub of YAKCC_SUBDIRS) {
9804
- mkdirSync11(join18(yakccDir, sub), { recursive: true });
10212
+ mkdirSync13(join22(yakccDir, sub), { recursive: true });
9805
10213
  }
9806
10214
  } catch (err) {
9807
10215
  logger.error(`error: cannot create ${yakccDir}: ${String(err)}`);
@@ -9812,7 +10220,7 @@ async function init(argv, logger, opts) {
9812
10220
  } else {
9813
10221
  logger.log(" .yakcc/ created");
9814
10222
  }
9815
- const registryPath = join18(targetDir, DEFAULT_REGISTRY_SUBPATH);
10223
+ const registryPath = join22(targetDir, DEFAULT_REGISTRY_SUBPATH);
9816
10224
  const registryCode = await registryInit(["--path", registryPath], logger);
9817
10225
  if (registryCode !== 0) {
9818
10226
  return registryCode;
@@ -9897,7 +10305,7 @@ async function init(argv, logger, opts) {
9897
10305
  try {
9898
10306
  writeRc(targetDir, rc);
9899
10307
  } catch (err) {
9900
- logger.error(`error: cannot write ${join18(targetDir, RC_FILENAME)}: ${String(err)}`);
10308
+ logger.error(`error: cannot write ${join22(targetDir, RC_FILENAME)}: ${String(err)}`);
9901
10309
  return 1;
9902
10310
  }
9903
10311
  logger.log(` ${RC_FILENAME} written`);
@@ -9916,7 +10324,7 @@ async function init(argv, logger, opts) {
9916
10324
  // src/commands/propose.ts
9917
10325
  init_dist();
9918
10326
  init_dist2();
9919
- import { readFileSync as readFileSync12 } from "fs";
10327
+ import { readFileSync as readFileSync14 } from "fs";
9920
10328
  import { parseArgs as parseArgs13 } from "util";
9921
10329
  async function propose(argv, logger) {
9922
10330
  const { values, positionals } = parseArgs13({
@@ -9943,7 +10351,7 @@ async function propose(argv, logger) {
9943
10351
  const registryPath = values.registry ?? DEFAULT_REGISTRY_PATH3;
9944
10352
  let specJson;
9945
10353
  try {
9946
- specJson = readFileSync12(specFilePath, "utf-8");
10354
+ specJson = readFileSync14(specFilePath, "utf-8");
9947
10355
  } catch (err) {
9948
10356
  logger.error(`error: cannot read spec file ${specFilePath}: ${String(err)}`);
9949
10357
  return 1;
@@ -9984,7 +10392,7 @@ async function propose(argv, logger) {
9984
10392
 
9985
10393
  // src/commands/query.ts
9986
10394
  init_dist2();
9987
- import { readFileSync as readFileSync13 } from "fs";
10395
+ import { readFileSync as readFileSync15 } from "fs";
9988
10396
  import { parseArgs as parseArgs14 } from "util";
9989
10397
  function truncate(s, max) {
9990
10398
  return s.length <= max ? s : `${s.slice(0, max - 3)}...`;
@@ -10014,7 +10422,7 @@ async function query(argv, logger, opts) {
10014
10422
  if (cardFilePath !== void 0) {
10015
10423
  let cardJson;
10016
10424
  try {
10017
- cardJson = readFileSync13(cardFilePath, "utf-8");
10425
+ cardJson = readFileSync15(cardFilePath, "utf-8");
10018
10426
  } catch (err) {
10019
10427
  logger.error(`error: cannot read card file ${cardFilePath}: ${String(err)}`);
10020
10428
  return 1;
@@ -10092,9 +10500,9 @@ async function query(argv, logger, opts) {
10092
10500
  }
10093
10501
 
10094
10502
  // src/commands/registry-export.ts
10095
- import { existsSync as existsSync12, mkdirSync as mkdirSync12 } from "fs";
10503
+ import { existsSync as existsSync14, mkdirSync as mkdirSync14 } from "fs";
10096
10504
  import { createRequire as createRequire2 } from "module";
10097
- import { dirname as dirname7, resolve as resolve3 } from "path";
10505
+ import { dirname as dirname8, resolve as resolve4 } from "path";
10098
10506
  import { parseArgs as parseArgs15 } from "util";
10099
10507
  var _registryModuleUrl = new URL("../../../registry/src/index.ts", import.meta.url).href;
10100
10508
  var _req = createRequire2(_registryModuleUrl);
@@ -10112,13 +10520,13 @@ async function registryExport(argv, logger) {
10112
10520
  logger.error("error: --to <path> is required for 'registry export'");
10113
10521
  return 1;
10114
10522
  }
10115
- const sourcePath = resolve3(values.from);
10116
- const outputPath = resolve3(values.to);
10117
- if (!existsSync12(sourcePath)) {
10523
+ const sourcePath = resolve4(values.from);
10524
+ const outputPath = resolve4(values.to);
10525
+ if (!existsSync14(sourcePath)) {
10118
10526
  logger.error(`error: source registry not found at ${sourcePath}`);
10119
10527
  return 1;
10120
10528
  }
10121
- mkdirSync12(dirname7(outputPath), { recursive: true });
10529
+ mkdirSync14(dirname8(outputPath), { recursive: true });
10122
10530
  const escapedOutputPath = outputPath.replace(/'/g, "''");
10123
10531
  let Database2;
10124
10532
  try {
@@ -10159,8 +10567,8 @@ async function registryExport(argv, logger) {
10159
10567
 
10160
10568
  // src/commands/registry-rebuild.ts
10161
10569
  init_dist2();
10162
- import { mkdirSync as mkdirSync13 } from "fs";
10163
- import { dirname as dirname8 } from "path";
10570
+ import { mkdirSync as mkdirSync15 } from "fs";
10571
+ import { dirname as dirname9 } from "path";
10164
10572
  import { parseArgs as parseArgs16 } from "util";
10165
10573
  async function registryRebuild(argv, logger, opts) {
10166
10574
  const { values } = parseArgs16({
@@ -10172,8 +10580,8 @@ async function registryRebuild(argv, logger, opts) {
10172
10580
  strict: true
10173
10581
  });
10174
10582
  const registryPath = values.path ?? DEFAULT_REGISTRY_PATH3;
10175
- const parent = dirname8(registryPath);
10176
- mkdirSync13(parent, { recursive: true });
10583
+ const parent = dirname9(registryPath);
10584
+ mkdirSync15(parent, { recursive: true });
10177
10585
  let embeddingProvider = opts?.embeddings;
10178
10586
  if (embeddingProvider === void 0) {
10179
10587
  const { createLocalEmbeddingProvider: createLocalEmbeddingProvider2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
@@ -10213,7 +10621,7 @@ async function registryRebuild(argv, logger, opts) {
10213
10621
  // src/commands/search.ts
10214
10622
  init_dist();
10215
10623
  init_dist2();
10216
- import { readFileSync as readFileSync14 } from "fs";
10624
+ import { readFileSync as readFileSync16 } from "fs";
10217
10625
  import { parseArgs as parseArgs17 } from "util";
10218
10626
  var FREE_TEXT_SPEC_DEFAULTS = {
10219
10627
  inputs: [],
@@ -10265,7 +10673,7 @@ async function search(argv, logger, opts) {
10265
10673
  if (looksLikePath) {
10266
10674
  let specJson;
10267
10675
  try {
10268
- specJson = readFileSync14(query2, "utf-8");
10676
+ specJson = readFileSync16(query2, "utf-8");
10269
10677
  } catch (err) {
10270
10678
  logger.error(`error: cannot read spec file ${query2}: ${String(err)}`);
10271
10679
  return 1;
@@ -10374,7 +10782,7 @@ async function seed(argv, logger, opts) {
10374
10782
 
10375
10783
  // src/commands/shave.ts
10376
10784
  init_dist2();
10377
- import { resolve as resolve4 } from "path";
10785
+ import { resolve as resolve5 } from "path";
10378
10786
  import { parseArgs as parseArgs19 } from "util";
10379
10787
  var VALID_FOREIGN_POLICIES = ["allow", "reject", "tag"];
10380
10788
  var SHAVE_PARSE_OPTIONS = {
@@ -10425,7 +10833,7 @@ async function shave2(argv, logger) {
10425
10833
  const offline = parsed.values.offline === true;
10426
10834
  let registry;
10427
10835
  try {
10428
- registry = await openRegistry(resolve4(registryPath));
10836
+ registry = await openRegistry(resolve5(registryPath));
10429
10837
  } catch (err) {
10430
10838
  logger.error(`error: failed to open registry at ${registryPath}: ${err.message}`);
10431
10839
  return 1;
@@ -10439,7 +10847,7 @@ async function shave2(argv, logger) {
10439
10847
  findByCanonicalAstHash: registry.findByCanonicalAstHash?.bind(registry)
10440
10848
  };
10441
10849
  try {
10442
- const result = await shave(resolve4(sourcePath), shaveRegistry, { offline, foreignPolicy });
10850
+ const result = await shave(resolve5(sourcePath), shaveRegistry, { offline, foreignPolicy });
10443
10851
  logger.log(`Shaved ${result.sourcePath}:`);
10444
10852
  logger.log(` atoms: ${result.atoms.length}`);
10445
10853
  logger.log(` intentCards: ${result.intentCards.length}`);
@@ -10473,17 +10881,17 @@ async function shave2(argv, logger) {
10473
10881
  }
10474
10882
 
10475
10883
  // src/commands/uninstall.ts
10476
- import { existsSync as existsSync13, readFileSync as readFileSync15, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
10477
- import { homedir as homedir5 } from "os";
10478
- import { join as join19, resolve as resolve5 } from "path";
10884
+ import { existsSync as existsSync15, readFileSync as readFileSync17, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
10885
+ import { homedir as homedir6 } from "os";
10886
+ import { join as join23, resolve as resolve6 } from "path";
10479
10887
  import { parseArgs as parseArgs20 } from "util";
10480
10888
  var YAKCC_DIR2 = ".yakcc";
10481
10889
  var RC_FILENAME2 = ".yakccrc.json";
10482
10890
  function readRc2(targetDir) {
10483
- const rcPath = join19(targetDir, RC_FILENAME2);
10484
- if (!existsSync13(rcPath)) return null;
10891
+ const rcPath = join23(targetDir, RC_FILENAME2);
10892
+ if (!existsSync15(rcPath)) return null;
10485
10893
  try {
10486
- return JSON.parse(readFileSync15(rcPath, "utf-8"));
10894
+ return JSON.parse(readFileSync17(rcPath, "utf-8"));
10487
10895
  } catch {
10488
10896
  return null;
10489
10897
  }
@@ -10499,20 +10907,20 @@ function parseIdeList2(raw) {
10499
10907
  return { ok: parts };
10500
10908
  }
10501
10909
  async function uninstallHookForIde(ide, targetDir, logger, overrideHome) {
10502
- const home = overrideHome ?? homedir5();
10910
+ const home = overrideHome ?? homedir6();
10503
10911
  switch (ide) {
10504
10912
  case "claude-code":
10505
10913
  return hooksClaudeCodeInstall(["--target", targetDir, "--uninstall"], logger);
10506
10914
  case "cursor":
10507
10915
  return hooksCursorInstall(["--target", targetDir, "--uninstall"], logger);
10508
10916
  case "cline":
10509
- return hooksClineInstall(["--uninstall"], logger, join19(home, ".config", "cline"));
10917
+ return hooksClineInstall(["--uninstall"], logger, join23(home, ".config", "cline"));
10510
10918
  case "continue":
10511
- return hooksContinueInstall(["--uninstall"], logger, join19(home, ".continue"));
10919
+ return hooksContinueInstall(["--uninstall"], logger, join23(home, ".continue"));
10512
10920
  case "windsurf":
10513
10921
  return hooksWindsurfInstall(["--target", targetDir, "--uninstall"], logger);
10514
10922
  case "aider":
10515
- return hooksAiderInstall(["--uninstall"], logger, join19(home, ".aider"));
10923
+ return hooksAiderInstall(["--uninstall"], logger, join23(home, ".aider"));
10516
10924
  }
10517
10925
  }
10518
10926
  async function uninstall(argv, logger, opts) {
@@ -10588,7 +10996,7 @@ async function uninstall(argv, logger, opts) {
10588
10996
  const updated = { ...rc, installedHooks: updatedHooks };
10589
10997
  try {
10590
10998
  writeFileSync11(
10591
- join19(targetDir, RC_FILENAME2),
10999
+ join23(targetDir, RC_FILENAME2),
10592
11000
  `${JSON.stringify(updated, null, 2)}
10593
11001
  `,
10594
11002
  "utf-8"
@@ -10600,22 +11008,22 @@ async function uninstall(argv, logger, opts) {
10600
11008
  }
10601
11009
  if (doPurge) {
10602
11010
  try {
10603
- rmSync5(join19(targetDir, YAKCC_DIR2), { recursive: true, force: true });
11011
+ rmSync5(join23(targetDir, YAKCC_DIR2), { recursive: true, force: true });
10604
11012
  } catch (err) {
10605
11013
  logger.error(`warning: cannot remove ${YAKCC_DIR2}: ${String(err)}`);
10606
11014
  }
10607
11015
  try {
10608
- rmSync5(join19(targetDir, RC_FILENAME2), { force: true });
11016
+ rmSync5(join23(targetDir, RC_FILENAME2), { force: true });
10609
11017
  } catch (err) {
10610
11018
  logger.error(`warning: cannot remove ${RC_FILENAME2}: ${String(err)}`);
10611
11019
  }
10612
11020
  }
10613
- const absTargetDir = resolve5(targetDir);
11021
+ const absTargetDir = resolve6(targetDir);
10614
11022
  const removedLine = removedIdes.length > 0 ? `Removed from: ${removedIdes.join(", ")}.` : "No hooks removed (nothing was installed).";
10615
11023
  if (doPurge) {
10616
11024
  logger.log(`${removedLine} Purged .yakcc/ and ${RC_FILENAME2} at ${absTargetDir}.`);
10617
11025
  } else {
10618
- logger.log(`${removedLine} Registry preserved at ${join19(absTargetDir, YAKCC_DIR2)}.`);
11026
+ logger.log(`${removedLine} Registry preserved at ${join23(absTargetDir, YAKCC_DIR2)}.`);
10619
11027
  }
10620
11028
  return 0;
10621
11029
  }
@@ -10673,6 +11081,13 @@ COMMANDS
10673
11081
  hooks cursor install Wire yakcc tool-call interception for Cursor
10674
11082
  [--target <dir>] Target project directory (default: .)
10675
11083
  [--uninstall] Remove the yakcc cursor hook entry
11084
+ hooks cline install Wire yakcc tool-call interception for Cline
11085
+ [--target <dir>] Target project directory (default: .)
11086
+ [--uninstall] Remove the yakcc cline hook entry
11087
+ hooks continue install Wire yakcc tool-call interception for Continue.dev
11088
+ [--target <dir>] Target project directory (default: .)
11089
+ [--uninstall] Remove the yakcc continue hook entry
11090
+ hook-intercept (internal -- invoked by IDE hook configs via PreToolUse)
10676
11091
  federation serve --registry <p> Start a read-only HTTP registry server
10677
11092
  [--port <n>] [--host <h>]
10678
11093
  federation mirror --remote <url> Mirror all blocks from a remote registry peer
@@ -10791,11 +11206,35 @@ async function runCli(argv, logger = CONSOLE_LOGGER, opts) {
10791
11206
  );
10792
11207
  return 1;
10793
11208
  }
11209
+ if (subcommand === "cline") {
11210
+ const [hooksSub, ...hooksRest] = rest;
11211
+ if (hooksSub === "install") {
11212
+ return hooksClineInstall(hooksRest, logger);
11213
+ }
11214
+ logger.error(
11215
+ `error: unknown hooks cline subcommand: ${hooksSub ?? "(none)"}. Did you mean 'hooks cline install'?`
11216
+ );
11217
+ return 1;
11218
+ }
11219
+ if (subcommand === "continue") {
11220
+ const [hooksSub, ...hooksRest] = rest;
11221
+ if (hooksSub === "install") {
11222
+ return hooksContinueInstall(hooksRest, logger);
11223
+ }
11224
+ logger.error(
11225
+ `error: unknown hooks continue subcommand: ${hooksSub ?? "(none)"}. Did you mean 'hooks continue install'?`
11226
+ );
11227
+ return 1;
11228
+ }
10794
11229
  logger.error(
10795
- `error: unknown hooks subcommand: ${subcommand ?? "(none)"}. Did you mean 'hooks claude-code install', 'hooks cursor install', 'hooks windsurf install', or 'hooks aider install'?`
11230
+ `error: unknown hooks subcommand: ${subcommand ?? "(none)"}. Did you mean 'hooks claude-code install', 'hooks cursor install', 'hooks windsurf install', 'hooks aider install', 'hooks cline install', or 'hooks continue install'?`
10796
11231
  );
10797
11232
  return 1;
10798
11233
  }
11234
+ case "hook-intercept": {
11235
+ const hookInterceptArgv = subcommand !== void 0 ? [subcommand, ...rest] : rest;
11236
+ return hookIntercept(hookInterceptArgv, logger);
11237
+ }
10799
11238
  case void 0:
10800
11239
  case "--help":
10801
11240
  case "-h": {
@@ -10812,21 +11251,21 @@ async function runCli(argv, logger = CONSOLE_LOGGER, opts) {
10812
11251
 
10813
11252
  // src/pkg-native-compat.ts
10814
11253
  import { createHash } from "crypto";
10815
- import { existsSync as existsSync14, mkdirSync as mkdirSync14, readFileSync as readFileSync16, writeFileSync as writeFileSync12 } from "fs";
10816
- import { homedir as homedir6 } from "os";
10817
- import { basename as basename2, join as join20 } from "path";
11254
+ import { existsSync as existsSync16, mkdirSync as mkdirSync16, readFileSync as readFileSync18, writeFileSync as writeFileSync12 } from "fs";
11255
+ import { homedir as homedir7 } from "os";
11256
+ import { basename as basename2, join as join24 } from "path";
10818
11257
  function insideSnapshot(p) {
10819
11258
  return p.startsWith("/snapshot/") || p.startsWith("/snapshot");
10820
11259
  }
10821
11260
  function extractFromSnapshot(snapshotPath) {
10822
- const content = readFileSync16(snapshotPath);
11261
+ const content = readFileSync18(snapshotPath);
10823
11262
  const hash = createHash("sha256").update(content).digest("hex");
10824
- const cacheBase = process.env.PKG_NATIVE_CACHE_PATH ?? join20(homedir6(), ".cache");
10825
- const cacheDir = join20(cacheBase, "pkg", hash);
10826
- mkdirSync14(cacheDir, { recursive: true });
10827
- const dest = join20(cacheDir, basename2(snapshotPath));
10828
- if (existsSync14(dest)) {
10829
- const existing = readFileSync16(dest);
11263
+ const cacheBase = process.env.PKG_NATIVE_CACHE_PATH ?? join24(homedir7(), ".cache");
11264
+ const cacheDir = join24(cacheBase, "pkg", hash);
11265
+ mkdirSync16(cacheDir, { recursive: true });
11266
+ const dest = join24(cacheDir, basename2(snapshotPath));
11267
+ if (existsSync16(dest)) {
11268
+ const existing = readFileSync18(dest);
10830
11269
  if (createHash("sha256").update(existing).digest("hex") === hash) {
10831
11270
  return dest;
10832
11271
  }
@@ -10863,7 +11302,7 @@ function patchSqliteDatabase(Database2) {
10863
11302
  }
10864
11303
  function isMainModule() {
10865
11304
  try {
10866
- const thisFile = realpathSync(fileURLToPath3(import.meta.url));
11305
+ const thisFile = realpathSync(fileURLToPath4(import.meta.url));
10867
11306
  const entryFile = process.argv[1] ? realpathSync(process.argv[1]) : "";
10868
11307
  return thisFile === entryFile;
10869
11308
  } catch (err) {