@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 +796 -357
- package/dist/bin.js.map +1 -1
- package/dist/bootstrap/yakcc.registry.sqlite +0 -0
- package/dist/index.js +784 -345
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -76,6 +76,16 @@ function byteSwap32(arr) {
|
|
|
76
76
|
}
|
|
77
77
|
return arr;
|
|
78
78
|
}
|
|
79
|
+
function bytesToHex(bytes) {
|
|
80
|
+
abytes(bytes);
|
|
81
|
+
if (hasHexBuiltin)
|
|
82
|
+
return bytes.toHex();
|
|
83
|
+
let hex = "";
|
|
84
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
85
|
+
hex += hexes[bytes[i]];
|
|
86
|
+
}
|
|
87
|
+
return hex;
|
|
88
|
+
}
|
|
79
89
|
function createHasher(hashCons, info = {}) {
|
|
80
90
|
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
81
91
|
const tmp = hashCons(void 0);
|
|
@@ -86,13 +96,18 @@ function createHasher(hashCons, info = {}) {
|
|
|
86
96
|
Object.assign(hashC, info);
|
|
87
97
|
return Object.freeze(hashC);
|
|
88
98
|
}
|
|
89
|
-
var isLE, swap8IfBE, swap32IfBE;
|
|
99
|
+
var isLE, swap8IfBE, swap32IfBE, hasHexBuiltin, hexes;
|
|
90
100
|
var init_utils = __esm({
|
|
91
101
|
"../../node_modules/.pnpm/@noble+hashes@2.2.0/node_modules/@noble/hashes/utils.js"() {
|
|
92
102
|
"use strict";
|
|
93
103
|
isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
|
|
94
104
|
swap8IfBE = isLE ? (n) => n : (n) => byteSwap(n) >>> 0;
|
|
95
105
|
swap32IfBE = isLE ? (u) => u : byteSwap32;
|
|
106
|
+
hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
107
|
+
// @ts-ignore
|
|
108
|
+
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
109
|
+
))();
|
|
110
|
+
hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
96
111
|
}
|
|
97
112
|
});
|
|
98
113
|
|
|
@@ -681,7 +696,7 @@ __export(contract_id_exports, {
|
|
|
681
696
|
});
|
|
682
697
|
function contractIdFromBytes(canonical) {
|
|
683
698
|
const digest = blake3(canonical);
|
|
684
|
-
return
|
|
699
|
+
return bytesToHex2(digest);
|
|
685
700
|
}
|
|
686
701
|
function contractId(spec) {
|
|
687
702
|
return contractIdFromBytes(canonicalize(spec));
|
|
@@ -689,7 +704,7 @@ function contractId(spec) {
|
|
|
689
704
|
function isValidContractId(s) {
|
|
690
705
|
return /^[0-9a-f]{64}$/.test(s);
|
|
691
706
|
}
|
|
692
|
-
function
|
|
707
|
+
function bytesToHex2(bytes) {
|
|
693
708
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
694
709
|
}
|
|
695
710
|
var init_contract_id = __esm({
|
|
@@ -928,13 +943,13 @@ function concatBytes(...arrays) {
|
|
|
928
943
|
}
|
|
929
944
|
return out;
|
|
930
945
|
}
|
|
931
|
-
function
|
|
946
|
+
function bytesToHex3(bytes) {
|
|
932
947
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
933
948
|
}
|
|
934
949
|
function specHash(spec) {
|
|
935
950
|
const bytes = canonicalize(spec);
|
|
936
951
|
const digest = blake3(bytes);
|
|
937
|
-
return
|
|
952
|
+
return bytesToHex3(digest);
|
|
938
953
|
}
|
|
939
954
|
function blockMerkleRoot(triplet) {
|
|
940
955
|
if (triplet.kind === "foreign") {
|
|
@@ -960,7 +975,7 @@ function blockMerkleRootLocal(triplet) {
|
|
|
960
975
|
const proofRootBytes = blake3(proofInput);
|
|
961
976
|
const rootInput = concatBytes(specHashBytes, implHashBytes, proofRootBytes);
|
|
962
977
|
const rootBytes = blake3(rootInput);
|
|
963
|
-
return
|
|
978
|
+
return bytesToHex3(rootBytes);
|
|
964
979
|
}
|
|
965
980
|
function blockMerkleRootForeign(triplet) {
|
|
966
981
|
const identityObj = {
|
|
@@ -972,7 +987,7 @@ function blockMerkleRootForeign(triplet) {
|
|
|
972
987
|
};
|
|
973
988
|
const identityBytes = canonicalize(identityObj);
|
|
974
989
|
const rootBytes = blake3(identityBytes);
|
|
975
|
-
return
|
|
990
|
+
return bytesToHex3(rootBytes);
|
|
976
991
|
}
|
|
977
992
|
function isLocalTriplet(t) {
|
|
978
993
|
return t.kind !== "foreign";
|
|
@@ -992,7 +1007,7 @@ var init_merkle = __esm({
|
|
|
992
1007
|
|
|
993
1008
|
// ../contracts/dist/canonical-ast.js
|
|
994
1009
|
import { Project, ScriptKind, SyntaxKind, ts } from "ts-morph";
|
|
995
|
-
function
|
|
1010
|
+
function bytesToHex4(bytes) {
|
|
996
1011
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
997
1012
|
}
|
|
998
1013
|
function findEnclosingNode(file, range) {
|
|
@@ -1133,7 +1148,7 @@ function canonicalAstHash(source, sourceRange) {
|
|
|
1133
1148
|
const renames = collectLocalRenames(root);
|
|
1134
1149
|
const canonical = emitCanonical(root, renames);
|
|
1135
1150
|
const digest = blake3(TEXT_ENCODER3.encode(canonical));
|
|
1136
|
-
return
|
|
1151
|
+
return bytesToHex4(digest);
|
|
1137
1152
|
}
|
|
1138
1153
|
var CanonicalAstParseError, TEXT_ENCODER3;
|
|
1139
1154
|
var init_canonical_ast = __esm({
|
|
@@ -2226,7 +2241,7 @@ function isStricterThan(aRoot, bRoot, edgeSet, allRoots) {
|
|
|
2226
2241
|
}
|
|
2227
2242
|
return false;
|
|
2228
2243
|
}
|
|
2229
|
-
function
|
|
2244
|
+
function bytesToHex5(bytes) {
|
|
2230
2245
|
let hex = "";
|
|
2231
2246
|
for (let i = 0; i < bytes.length; i++) {
|
|
2232
2247
|
hex += bytes[i]?.toString(16).padStart(2, "0");
|
|
@@ -2858,7 +2873,7 @@ var init_storage = __esm({
|
|
|
2858
2873
|
ORDER BY b.block_merkle_root ASC`).all();
|
|
2859
2874
|
if (blockRows.length === 0)
|
|
2860
2875
|
return [];
|
|
2861
|
-
const EMPTY_SENTINEL =
|
|
2876
|
+
const EMPTY_SENTINEL = bytesToHex5(blake3(new Uint8Array(0)));
|
|
2862
2877
|
const allRoots = blockRows.map((r) => r.block_merkle_root);
|
|
2863
2878
|
const placeholders = allRoots.map(() => "?").join(", ");
|
|
2864
2879
|
const artifactRows = this.db.prepare(`SELECT block_merkle_root, path, bytes
|
|
@@ -2872,7 +2887,7 @@ var init_storage = __esm({
|
|
|
2872
2887
|
entry = { implSourceHash: EMPTY_SENTINEL, manifestJsonHash: EMPTY_SENTINEL };
|
|
2873
2888
|
hashMap.set(row.block_merkle_root, entry);
|
|
2874
2889
|
}
|
|
2875
|
-
const digest =
|
|
2890
|
+
const digest = bytesToHex5(blake3(new Uint8Array(row.bytes)));
|
|
2876
2891
|
if (row.path === "impl.ts") {
|
|
2877
2892
|
entry.implSourceHash = digest;
|
|
2878
2893
|
} else if (row.path === "proof/manifest.json") {
|
|
@@ -2911,7 +2926,7 @@ var init_storage = __esm({
|
|
|
2911
2926
|
if (entry.workspacePath.startsWith("/") || entry.workspacePath.includes("..")) {
|
|
2912
2927
|
throw new Error(`storeWorkspacePlumbing: workspacePath must be workspace-relative and must not contain '..': ${entry.workspacePath}`);
|
|
2913
2928
|
}
|
|
2914
|
-
const actualHash =
|
|
2929
|
+
const actualHash = bytesToHex5(blake3(entry.contentBytes));
|
|
2915
2930
|
if (actualHash !== entry.contentHash) {
|
|
2916
2931
|
throw new Error(`storeWorkspacePlumbing: contentHash mismatch for ${entry.workspacePath}: stored=${entry.contentHash}, computed=${actualHash}`);
|
|
2917
2932
|
}
|
|
@@ -2962,7 +2977,7 @@ var init_storage = __esm({
|
|
|
2962
2977
|
if (entry.sourceFile.startsWith("/") || entry.sourceFile.includes("..")) {
|
|
2963
2978
|
throw new Error(`storeSourceFileGlue: sourceFile must be workspace-relative and must not contain '..': ${entry.sourceFile}`);
|
|
2964
2979
|
}
|
|
2965
|
-
const actualHash =
|
|
2980
|
+
const actualHash = bytesToHex5(blake3(entry.contentBlob));
|
|
2966
2981
|
if (actualHash !== entry.contentHash) {
|
|
2967
2982
|
throw new Error(`storeSourceFileGlue: contentHash mismatch for ${entry.sourceFile}: stored=${entry.contentHash}, computed=${actualHash}`);
|
|
2968
2983
|
}
|
|
@@ -3887,11 +3902,11 @@ async function serveRegistry(registry, options) {
|
|
|
3887
3902
|
console.error("[serveRegistry] Unhandled request error:", err);
|
|
3888
3903
|
});
|
|
3889
3904
|
});
|
|
3890
|
-
await new Promise((
|
|
3905
|
+
await new Promise((resolve7, reject) => {
|
|
3891
3906
|
server.once("error", reject);
|
|
3892
3907
|
server.listen(port, host, () => {
|
|
3893
3908
|
server.removeListener("error", reject);
|
|
3894
|
-
|
|
3909
|
+
resolve7();
|
|
3895
3910
|
});
|
|
3896
3911
|
});
|
|
3897
3912
|
const address = server.address();
|
|
@@ -3908,16 +3923,16 @@ async function serveRegistry(registry, options) {
|
|
|
3908
3923
|
if (closed)
|
|
3909
3924
|
return Promise.resolve();
|
|
3910
3925
|
closed = true;
|
|
3911
|
-
return new Promise((
|
|
3926
|
+
return new Promise((resolve7, reject) => {
|
|
3912
3927
|
server.close((err) => {
|
|
3913
3928
|
if (err !== void 0) {
|
|
3914
3929
|
if (err.code === "ERR_SERVER_NOT_RUNNING") {
|
|
3915
|
-
|
|
3930
|
+
resolve7();
|
|
3916
3931
|
} else {
|
|
3917
3932
|
reject(err);
|
|
3918
3933
|
}
|
|
3919
3934
|
} else {
|
|
3920
|
-
|
|
3935
|
+
resolve7();
|
|
3921
3936
|
}
|
|
3922
3937
|
});
|
|
3923
3938
|
});
|
|
@@ -4017,11 +4032,11 @@ async function runFederationServe(argv, logger, opts) {
|
|
|
4017
4032
|
if (opts?.noBlock === true) {
|
|
4018
4033
|
return { code: 0, handle };
|
|
4019
4034
|
}
|
|
4020
|
-
await new Promise((
|
|
4035
|
+
await new Promise((resolve7) => {
|
|
4021
4036
|
const shutdown = () => {
|
|
4022
4037
|
handle.close().then(() => {
|
|
4023
|
-
registry.close().finally(
|
|
4024
|
-
}).catch(
|
|
4038
|
+
registry.close().finally(resolve7);
|
|
4039
|
+
}).catch(resolve7);
|
|
4025
4040
|
};
|
|
4026
4041
|
process.once("SIGINT", shutdown);
|
|
4027
4042
|
process.once("SIGTERM", shutdown);
|
|
@@ -4236,18 +4251,18 @@ function byteSwap322(arr) {
|
|
|
4236
4251
|
return arr;
|
|
4237
4252
|
}
|
|
4238
4253
|
var swap32IfBE2 = isLE2 ? (u) => u : byteSwap322;
|
|
4239
|
-
var
|
|
4254
|
+
var hasHexBuiltin2 = /* @__PURE__ */ (() => (
|
|
4240
4255
|
// @ts-ignore
|
|
4241
4256
|
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
4242
4257
|
))();
|
|
4243
|
-
var
|
|
4244
|
-
function
|
|
4258
|
+
var hexes2 = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
4259
|
+
function bytesToHex6(bytes) {
|
|
4245
4260
|
abytes2(bytes);
|
|
4246
|
-
if (
|
|
4261
|
+
if (hasHexBuiltin2)
|
|
4247
4262
|
return bytes.toHex();
|
|
4248
4263
|
let hex = "";
|
|
4249
4264
|
for (let i = 0; i < bytes.length; i++) {
|
|
4250
|
-
hex +=
|
|
4265
|
+
hex += hexes2[bytes[i]];
|
|
4251
4266
|
}
|
|
4252
4267
|
return hex;
|
|
4253
4268
|
}
|
|
@@ -4645,7 +4660,7 @@ async function renameWithRetry(src, dst) {
|
|
|
4645
4660
|
}
|
|
4646
4661
|
if (attempt < MAX_ATTEMPTS - 1) {
|
|
4647
4662
|
const delay = BACKOFF_MS[attempt] ?? BACKOFF_MS[BACKOFF_MS.length - 1] ?? 160;
|
|
4648
|
-
await new Promise((
|
|
4663
|
+
await new Promise((resolve7) => setTimeout(resolve7, delay));
|
|
4649
4664
|
}
|
|
4650
4665
|
}
|
|
4651
4666
|
}
|
|
@@ -4706,12 +4721,12 @@ function normalizeSource(s) {
|
|
|
4706
4721
|
var encoder = new TextEncoder();
|
|
4707
4722
|
function sourceHash(unitSource) {
|
|
4708
4723
|
const normalized = normalizeSource(unitSource);
|
|
4709
|
-
return
|
|
4724
|
+
return bytesToHex6(blake32(encoder.encode(normalized)));
|
|
4710
4725
|
}
|
|
4711
4726
|
function keyFromIntentInputs(inputs) {
|
|
4712
4727
|
const { sourceHash: sh, modelTag, promptVersion, schemaVersion } = inputs;
|
|
4713
4728
|
const raw = `${sh}\0${modelTag}\0${promptVersion}\0${schemaVersion}`;
|
|
4714
|
-
return
|
|
4729
|
+
return bytesToHex6(blake32(encoder.encode(raw)));
|
|
4715
4730
|
}
|
|
4716
4731
|
|
|
4717
4732
|
// ../shave/dist/corpus/ai-derived.js
|
|
@@ -4751,7 +4766,7 @@ async function extractFromAiDerivedCached(intentCard, source, cacheDir, model, p
|
|
|
4751
4766
|
if (cached === void 0)
|
|
4752
4767
|
return void 0;
|
|
4753
4768
|
const bytes = encoder2.encode(cached.content);
|
|
4754
|
-
const contentHash =
|
|
4769
|
+
const contentHash = bytesToHex6(blake32(bytes));
|
|
4755
4770
|
void intentCard;
|
|
4756
4771
|
return {
|
|
4757
4772
|
source: "ai-derived",
|
|
@@ -4783,7 +4798,7 @@ async function extractFromPropsFile(propsFilePath, _intentCard, source) {
|
|
|
4783
4798
|
return void 0;
|
|
4784
4799
|
}
|
|
4785
4800
|
const bytes = encoder3.encode(fileContent);
|
|
4786
|
-
const contentHash =
|
|
4801
|
+
const contentHash = bytesToHex6(blake32(bytes));
|
|
4787
4802
|
return {
|
|
4788
4803
|
source: "props-file",
|
|
4789
4804
|
bytes,
|
|
@@ -4908,7 +4923,7 @@ function extractFromDocumentedUsage(intentCard, source) {
|
|
|
4908
4923
|
`);
|
|
4909
4924
|
}
|
|
4910
4925
|
const bytes = encoder4.encode(content);
|
|
4911
|
-
const contentHash =
|
|
4926
|
+
const contentHash = bytesToHex6(blake32(bytes));
|
|
4912
4927
|
return {
|
|
4913
4928
|
source: "documented-usage",
|
|
4914
4929
|
bytes,
|
|
@@ -4985,7 +5000,7 @@ var UPSTREAM_TEST_PATH = "property-tests.fast-check.ts";
|
|
|
4985
5000
|
function extractFromUpstreamTest(intentCard, source) {
|
|
4986
5001
|
const content = buildUpstreamTestContent(intentCard, source);
|
|
4987
5002
|
const bytes = encoder5.encode(content);
|
|
4988
|
-
const contentHash =
|
|
5003
|
+
const contentHash = bytesToHex6(blake32(bytes));
|
|
4989
5004
|
return {
|
|
4990
5005
|
source: "upstream-test",
|
|
4991
5006
|
bytes,
|
|
@@ -5505,7 +5520,7 @@ function safeCanonicalAstHash(node, nodeSource, fullSource, start, end) {
|
|
|
5505
5520
|
return canonicalAstHash(fullSource, { start, end });
|
|
5506
5521
|
} catch {
|
|
5507
5522
|
const TEXT_ENC = new TextEncoder();
|
|
5508
|
-
return
|
|
5523
|
+
return bytesToHex6(blake32(TEXT_ENC.encode(nodeSource)));
|
|
5509
5524
|
}
|
|
5510
5525
|
}
|
|
5511
5526
|
}
|
|
@@ -6906,9 +6921,9 @@ async function extractIntent(unitSource, ctx) {
|
|
|
6906
6921
|
} catch (err) {
|
|
6907
6922
|
console.warn(`[shave extractIntent] Corrupt cache entry for key ${cacheKey} (${err instanceof Error ? err.message : String(err)}); treating as miss.`);
|
|
6908
6923
|
const { unlink: unlink2 } = await import("fs/promises");
|
|
6909
|
-
const { join:
|
|
6924
|
+
const { join: join24 } = await import("path");
|
|
6910
6925
|
const shard = cacheKey.slice(0, 3);
|
|
6911
|
-
const filePath =
|
|
6926
|
+
const filePath = join24(ctx.cacheDir, shard, `${cacheKey}.json`);
|
|
6912
6927
|
await unlink2(filePath).catch(() => {
|
|
6913
6928
|
});
|
|
6914
6929
|
}
|
|
@@ -8860,18 +8875,411 @@ async function compile(argv, logger, opts) {
|
|
|
8860
8875
|
// src/index.ts
|
|
8861
8876
|
init_federation();
|
|
8862
8877
|
|
|
8863
|
-
//
|
|
8864
|
-
|
|
8878
|
+
// ../hooks-base/dist/telemetry.js
|
|
8879
|
+
init_blake3();
|
|
8880
|
+
init_utils();
|
|
8881
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync6 } from "fs";
|
|
8865
8882
|
import { homedir } from "os";
|
|
8866
|
-
import { join as
|
|
8883
|
+
import { join as join13 } from "path";
|
|
8884
|
+
|
|
8885
|
+
// ../hooks-base/dist/telemetry-sink.js
|
|
8886
|
+
import { appendFileSync, mkdirSync as mkdirSync5 } from "fs";
|
|
8887
|
+
import { join as join11 } from "path";
|
|
8888
|
+
|
|
8889
|
+
// ../hooks-base/dist/telemetry-config.js
|
|
8890
|
+
var DEFAULT_TELEMETRY_ENDPOINT = "https://metrics.yakcc.com";
|
|
8891
|
+
function resolveTelemetryConfig(env = process.env) {
|
|
8892
|
+
const fullIntent = env.YAKCC_TELEMETRY_FULL_INTENT === "1";
|
|
8893
|
+
if (env.YAKCC_TELEMETRY_DISABLED === "1") {
|
|
8894
|
+
return { disabled: true, endpoint: DEFAULT_TELEMETRY_ENDPOINT, fullIntent };
|
|
8895
|
+
}
|
|
8896
|
+
const rawEndpoint = env.YAKCC_TELEMETRY_ENDPOINT;
|
|
8897
|
+
if (rawEndpoint === "off") {
|
|
8898
|
+
return { disabled: true, endpoint: DEFAULT_TELEMETRY_ENDPOINT, fullIntent };
|
|
8899
|
+
}
|
|
8900
|
+
const endpoint = rawEndpoint !== void 0 && rawEndpoint !== "" ? rawEndpoint : DEFAULT_TELEMETRY_ENDPOINT;
|
|
8901
|
+
return { disabled: false, endpoint, fullIntent };
|
|
8902
|
+
}
|
|
8903
|
+
|
|
8904
|
+
// ../hooks-base/dist/telemetry-wire.js
|
|
8905
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
8906
|
+
import { dirname as dirname6, join as join10, resolve as resolve3 } from "path";
|
|
8907
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8908
|
+
var SCHEMA_VERSION2 = 1;
|
|
8909
|
+
var _cachedSource = null;
|
|
8910
|
+
function buildSource() {
|
|
8911
|
+
if (_cachedSource !== null)
|
|
8912
|
+
return _cachedSource;
|
|
8913
|
+
let cliVersion = "unknown";
|
|
8914
|
+
try {
|
|
8915
|
+
const __filename = fileURLToPath2(import.meta.url);
|
|
8916
|
+
const pkgPath = resolve3(join10(dirname6(__filename), "../package.json"));
|
|
8917
|
+
const pkgJson = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
8918
|
+
cliVersion = typeof pkgJson.version === "string" ? pkgJson.version : "unknown";
|
|
8919
|
+
} catch {
|
|
8920
|
+
}
|
|
8921
|
+
_cachedSource = {
|
|
8922
|
+
cliVersion,
|
|
8923
|
+
platform: process.platform,
|
|
8924
|
+
nodeVersion: process.version
|
|
8925
|
+
};
|
|
8926
|
+
return _cachedSource;
|
|
8927
|
+
}
|
|
8928
|
+
function buildEnvelope(events, sessionId, now = Date.now()) {
|
|
8929
|
+
return {
|
|
8930
|
+
schemaVersion: SCHEMA_VERSION2,
|
|
8931
|
+
sessionId,
|
|
8932
|
+
events,
|
|
8933
|
+
emittedAt: now,
|
|
8934
|
+
source: buildSource()
|
|
8935
|
+
};
|
|
8936
|
+
}
|
|
8937
|
+
|
|
8938
|
+
// ../hooks-base/dist/telemetry-sink.js
|
|
8939
|
+
var _SINK_FALLBACK_SESSION_ID = (() => {
|
|
8940
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
8941
|
+
return crypto.randomUUID();
|
|
8942
|
+
}
|
|
8943
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
8944
|
+
const r = Math.floor(Math.random() * 16);
|
|
8945
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
8946
|
+
return v.toString(16);
|
|
8947
|
+
});
|
|
8948
|
+
})();
|
|
8949
|
+
function _resolveSinkSessionId() {
|
|
8950
|
+
return process.env.CLAUDE_SESSION_ID ?? _SINK_FALLBACK_SESSION_ID;
|
|
8951
|
+
}
|
|
8952
|
+
var NoOpSink = class {
|
|
8953
|
+
send(_event) {
|
|
8954
|
+
}
|
|
8955
|
+
};
|
|
8956
|
+
var FileSink = class {
|
|
8957
|
+
dir;
|
|
8958
|
+
sessionId;
|
|
8959
|
+
initialized = false;
|
|
8960
|
+
// at-most-once warn set (DEC-TELEMETRY-EXPORT-FAIL-SILENT-005)
|
|
8961
|
+
warnedClasses = /* @__PURE__ */ new Set();
|
|
8962
|
+
constructor(dir, sessionId) {
|
|
8963
|
+
this.dir = dir;
|
|
8964
|
+
this.sessionId = sessionId ?? _resolveSinkSessionId();
|
|
8965
|
+
}
|
|
8966
|
+
send(event) {
|
|
8967
|
+
try {
|
|
8968
|
+
if (!this.initialized) {
|
|
8969
|
+
mkdirSync5(this.dir, { recursive: true });
|
|
8970
|
+
this.initialized = true;
|
|
8971
|
+
}
|
|
8972
|
+
const filePath = join11(this.dir, `${this.sessionId}.jsonl`);
|
|
8973
|
+
appendFileSync(filePath, `${JSON.stringify(event)}
|
|
8974
|
+
`, "utf-8");
|
|
8975
|
+
} catch (err) {
|
|
8976
|
+
this._warnOnce(err);
|
|
8977
|
+
}
|
|
8978
|
+
}
|
|
8979
|
+
_warnOnce(err) {
|
|
8980
|
+
const cls = err instanceof Error ? err.constructor.name : "UnknownError";
|
|
8981
|
+
if (!this.warnedClasses.has(cls)) {
|
|
8982
|
+
this.warnedClasses.add(cls);
|
|
8983
|
+
console.warn(`[yakcc telemetry] FileSink error (${cls}):`, err);
|
|
8984
|
+
}
|
|
8985
|
+
}
|
|
8986
|
+
};
|
|
8987
|
+
var BATCH_FLUSH_INTERVAL_MS = 5e3;
|
|
8988
|
+
var BATCH_FLUSH_SIZE = 50;
|
|
8989
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
8990
|
+
var HttpsBatcherSink = class {
|
|
8991
|
+
endpoint;
|
|
8992
|
+
sessionId;
|
|
8993
|
+
buffer = [];
|
|
8994
|
+
timer = null;
|
|
8995
|
+
flushing = false;
|
|
8996
|
+
// at-most-once warn set (DEC-TELEMETRY-EXPORT-FAIL-SILENT-005)
|
|
8997
|
+
warnedClasses = /* @__PURE__ */ new Set();
|
|
8998
|
+
_beforeExitHandler;
|
|
8999
|
+
_registered = false;
|
|
9000
|
+
constructor(endpoint, sessionId) {
|
|
9001
|
+
this.endpoint = endpoint;
|
|
9002
|
+
this.sessionId = sessionId ?? _resolveSinkSessionId();
|
|
9003
|
+
this._beforeExitHandler = () => {
|
|
9004
|
+
this._flushSync();
|
|
9005
|
+
};
|
|
9006
|
+
}
|
|
9007
|
+
send(event) {
|
|
9008
|
+
this.buffer.push(event);
|
|
9009
|
+
this._ensureTimer();
|
|
9010
|
+
if (this.buffer.length >= BATCH_FLUSH_SIZE) {
|
|
9011
|
+
this._scheduleFlush();
|
|
9012
|
+
}
|
|
9013
|
+
}
|
|
9014
|
+
/** Start the interval timer and register the beforeExit handler (lazy, once). */
|
|
9015
|
+
_ensureTimer() {
|
|
9016
|
+
if (this._registered)
|
|
9017
|
+
return;
|
|
9018
|
+
this._registered = true;
|
|
9019
|
+
this.timer = setInterval(() => {
|
|
9020
|
+
this._scheduleFlush();
|
|
9021
|
+
}, BATCH_FLUSH_INTERVAL_MS);
|
|
9022
|
+
if (this.timer && typeof this.timer.unref === "function") {
|
|
9023
|
+
this.timer.unref();
|
|
9024
|
+
}
|
|
9025
|
+
process.on("beforeExit", this._beforeExitHandler);
|
|
9026
|
+
}
|
|
9027
|
+
/** Schedule a flush on the next microtask tick (non-blocking). */
|
|
9028
|
+
_scheduleFlush() {
|
|
9029
|
+
if (this.buffer.length === 0)
|
|
9030
|
+
return;
|
|
9031
|
+
const batch = this.buffer.splice(0, this.buffer.length);
|
|
9032
|
+
void this._flush(batch);
|
|
9033
|
+
}
|
|
9034
|
+
/** Async flush — fire-and-forget. DEC-TELEMETRY-EXPORT-FAIL-SILENT-005. */
|
|
9035
|
+
async _flush(batch) {
|
|
9036
|
+
if (batch.length === 0)
|
|
9037
|
+
return;
|
|
9038
|
+
const envelope = buildEnvelope(batch, this.sessionId);
|
|
9039
|
+
const controller = new AbortController();
|
|
9040
|
+
const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
9041
|
+
try {
|
|
9042
|
+
const response = await fetch(this.endpoint, {
|
|
9043
|
+
method: "POST",
|
|
9044
|
+
headers: {
|
|
9045
|
+
"Content-Type": "application/json",
|
|
9046
|
+
"User-Agent": `yakcc-hooks-base/${envelope.source.cliVersion} (${envelope.source.platform}; node-${envelope.source.nodeVersion})`
|
|
9047
|
+
},
|
|
9048
|
+
body: JSON.stringify(envelope),
|
|
9049
|
+
signal: controller.signal
|
|
9050
|
+
});
|
|
9051
|
+
if (!response.ok) {
|
|
9052
|
+
this._warnOnce(new Error(`HTTP ${response.status}`), "HttpError");
|
|
9053
|
+
}
|
|
9054
|
+
} catch (err) {
|
|
9055
|
+
this._warnOnce(err);
|
|
9056
|
+
} finally {
|
|
9057
|
+
clearTimeout(timeoutId);
|
|
9058
|
+
}
|
|
9059
|
+
}
|
|
9060
|
+
/**
|
|
9061
|
+
* Best-effort exit-flush called from `beforeExit`.
|
|
9062
|
+
*
|
|
9063
|
+
* @decision DEC-TELEMETRY-EXPORT-BATCHING-004
|
|
9064
|
+
* `beforeExit` fires when the Node event loop becomes empty (not via process.exit()).
|
|
9065
|
+
* We start the async flush here. Because `beforeExit` fires when the loop is empty,
|
|
9066
|
+
* the pending fetch promise keeps the loop alive long enough for the flush to complete
|
|
9067
|
+
* under normal conditions (no explicit process.exit()). If `process.exit()` is called
|
|
9068
|
+
* by the host, inflight events are dropped — this is the documented NG5 behavior
|
|
9069
|
+
* (no retry queue, at-most-once delivery).
|
|
9070
|
+
*
|
|
9071
|
+
* Previous implementation used `Atomics.wait` as a bounded sleep, but
|
|
9072
|
+
* `Atomics.wait` on the main thread throws `TypeError` in Node ≥ 16 when
|
|
9073
|
+
* `--experimental-vm-modules` or other thread guards are active (Node 22 always
|
|
9074
|
+
* rejects it on the main thread). The async-only approach is correct here because
|
|
9075
|
+
* `beforeExit` itself is an async boundary: the outstanding fetch promise will
|
|
9076
|
+
* re-trigger the loop, and if the process exits without the loop draining further,
|
|
9077
|
+
* the events are already acknowledged as best-effort (DEC-TELEMETRY-EXPORT-BATCHING-004).
|
|
9078
|
+
*/
|
|
9079
|
+
_flushSync() {
|
|
9080
|
+
if (this.buffer.length === 0)
|
|
9081
|
+
return;
|
|
9082
|
+
if (this.flushing)
|
|
9083
|
+
return;
|
|
9084
|
+
this.flushing = true;
|
|
9085
|
+
const batch = this.buffer.splice(0, this.buffer.length);
|
|
9086
|
+
void this._flush(batch);
|
|
9087
|
+
}
|
|
9088
|
+
/**
|
|
9089
|
+
* Deregister timer and handlers (for tests and clean shutdown).
|
|
9090
|
+
* Drains the buffer without flushing — events in-buffer at dispose time are
|
|
9091
|
+
* dropped (NG5: at-most-once delivery). This is intentional for test isolation:
|
|
9092
|
+
* after dispose(), no further async fetch calls will originate from this sink.
|
|
9093
|
+
*/
|
|
9094
|
+
dispose() {
|
|
9095
|
+
if (this.timer !== null) {
|
|
9096
|
+
clearInterval(this.timer);
|
|
9097
|
+
this.timer = null;
|
|
9098
|
+
}
|
|
9099
|
+
process.removeListener("beforeExit", this._beforeExitHandler);
|
|
9100
|
+
this._registered = false;
|
|
9101
|
+
this.buffer.length = 0;
|
|
9102
|
+
}
|
|
9103
|
+
_warnOnce(err, classOverride) {
|
|
9104
|
+
const cls = classOverride ?? (err instanceof Error ? err.constructor.name : "UnknownError");
|
|
9105
|
+
if (!this.warnedClasses.has(cls)) {
|
|
9106
|
+
this.warnedClasses.add(cls);
|
|
9107
|
+
console.warn(`[yakcc telemetry] HttpsBatcherSink error (${cls}):`, err);
|
|
9108
|
+
}
|
|
9109
|
+
}
|
|
9110
|
+
};
|
|
9111
|
+
var CompositeSink = class {
|
|
9112
|
+
sinks;
|
|
9113
|
+
constructor(sinks) {
|
|
9114
|
+
this.sinks = sinks;
|
|
9115
|
+
}
|
|
9116
|
+
send(event) {
|
|
9117
|
+
for (const sink of this.sinks) {
|
|
9118
|
+
try {
|
|
9119
|
+
sink.send(event);
|
|
9120
|
+
} catch {
|
|
9121
|
+
}
|
|
9122
|
+
}
|
|
9123
|
+
}
|
|
9124
|
+
/**
|
|
9125
|
+
* Propagate dispose() to inner sinks that support it.
|
|
9126
|
+
* Safe to call multiple times (inner sinks are idempotent on dispose).
|
|
9127
|
+
* @internal — for test isolation and clean process shutdown.
|
|
9128
|
+
*/
|
|
9129
|
+
dispose() {
|
|
9130
|
+
for (const sink of this.sinks) {
|
|
9131
|
+
if (sink instanceof HttpsBatcherSink) {
|
|
9132
|
+
sink.dispose();
|
|
9133
|
+
}
|
|
9134
|
+
}
|
|
9135
|
+
}
|
|
9136
|
+
};
|
|
9137
|
+
var _sinkSingleton = null;
|
|
9138
|
+
function selectSink(env = process.env, config) {
|
|
9139
|
+
if (_sinkSingleton !== null)
|
|
9140
|
+
return _sinkSingleton;
|
|
9141
|
+
_sinkSingleton = _buildSink(config ?? resolveTelemetryConfig(env));
|
|
9142
|
+
return _sinkSingleton;
|
|
9143
|
+
}
|
|
9144
|
+
function _buildSink(config, sessionId) {
|
|
9145
|
+
if (config.disabled) {
|
|
9146
|
+
return new NoOpSink();
|
|
9147
|
+
}
|
|
9148
|
+
const endpoint = config.endpoint;
|
|
9149
|
+
if (endpoint.startsWith("file://")) {
|
|
9150
|
+
const dir = endpoint.slice("file://".length);
|
|
9151
|
+
return new FileSink(dir, sessionId);
|
|
9152
|
+
}
|
|
9153
|
+
if (endpoint.startsWith("https://")) {
|
|
9154
|
+
return new CompositeSink([new HttpsBatcherSink(endpoint, sessionId)]);
|
|
9155
|
+
}
|
|
9156
|
+
console.warn(`[yakcc telemetry] Unknown endpoint scheme: ${endpoint} \u2014 using NoOpSink`);
|
|
9157
|
+
return new NoOpSink();
|
|
9158
|
+
}
|
|
9159
|
+
|
|
9160
|
+
// ../hooks-base/dist/enforcement-config.js
|
|
9161
|
+
import { existsSync as existsSync3, readFileSync as readFileSync6 } from "fs";
|
|
9162
|
+
import { join as join12 } from "path";
|
|
9163
|
+
|
|
9164
|
+
// ../hooks-base/dist/telemetry.js
|
|
9165
|
+
var FALLBACK_SESSION_ID = (() => {
|
|
9166
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
9167
|
+
return crypto.randomUUID();
|
|
9168
|
+
}
|
|
9169
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
9170
|
+
const r = Math.floor(Math.random() * 16);
|
|
9171
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
9172
|
+
return v.toString(16);
|
|
9173
|
+
});
|
|
9174
|
+
})();
|
|
9175
|
+
function resolveSessionId() {
|
|
9176
|
+
return process.env.CLAUDE_SESSION_ID ?? FALLBACK_SESSION_ID;
|
|
9177
|
+
}
|
|
9178
|
+
function resolveTelemetryDir() {
|
|
9179
|
+
return process.env.YAKCC_TELEMETRY_DIR ?? join13(homedir(), ".yakcc", "telemetry");
|
|
9180
|
+
}
|
|
9181
|
+
function hashIntent(intentText) {
|
|
9182
|
+
const encoded = new TextEncoder().encode(intentText);
|
|
9183
|
+
const digest = blake3(encoded);
|
|
9184
|
+
return bytesToHex(digest);
|
|
9185
|
+
}
|
|
9186
|
+
function appendTelemetryEvent(event, sessionId, dir) {
|
|
9187
|
+
if (!existsSync4(dir)) {
|
|
9188
|
+
mkdirSync6(dir, { recursive: true });
|
|
9189
|
+
}
|
|
9190
|
+
const filePath = join13(dir, `${sessionId}.jsonl`);
|
|
9191
|
+
appendFileSync2(filePath, `${JSON.stringify(event)}
|
|
9192
|
+
`, "utf-8");
|
|
9193
|
+
try {
|
|
9194
|
+
selectSink().send(event);
|
|
9195
|
+
} catch {
|
|
9196
|
+
}
|
|
9197
|
+
}
|
|
9198
|
+
|
|
9199
|
+
// src/commands/hook-intercept.ts
|
|
9200
|
+
var WINDOWS_ILLEGAL_FILENAME_RE = /[<>:"/\\|?*\x00-\x1f]/;
|
|
9201
|
+
function sanitizeSessionId(raw) {
|
|
9202
|
+
if (WINDOWS_ILLEGAL_FILENAME_RE.test(raw)) return null;
|
|
9203
|
+
return raw;
|
|
9204
|
+
}
|
|
9205
|
+
var ALLOWED_TOOL_NAMES = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit"]);
|
|
9206
|
+
async function hookIntercept(argv, logger, options) {
|
|
9207
|
+
void argv;
|
|
9208
|
+
void logger;
|
|
9209
|
+
const stdinStream = options?.stdin ?? process.stdin;
|
|
9210
|
+
const telemetryDir = options?.telemetryDir ?? resolveTelemetryDir();
|
|
9211
|
+
const appendEvent = options?.appendEvent ?? appendTelemetryEvent;
|
|
9212
|
+
const now = options?.now ?? Date.now;
|
|
9213
|
+
const start = now();
|
|
9214
|
+
try {
|
|
9215
|
+
const chunks = [];
|
|
9216
|
+
for await (const chunk of stdinStream) {
|
|
9217
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
9218
|
+
}
|
|
9219
|
+
const stdinText = Buffer.concat(chunks).toString("utf-8").trim();
|
|
9220
|
+
if (!stdinText) {
|
|
9221
|
+
return 0;
|
|
9222
|
+
}
|
|
9223
|
+
let parsed;
|
|
9224
|
+
try {
|
|
9225
|
+
parsed = JSON.parse(stdinText);
|
|
9226
|
+
} catch {
|
|
9227
|
+
return 0;
|
|
9228
|
+
}
|
|
9229
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
9230
|
+
return 0;
|
|
9231
|
+
}
|
|
9232
|
+
const payload = parsed;
|
|
9233
|
+
const toolName = payload.tool_name;
|
|
9234
|
+
if (typeof toolName !== "string" || !ALLOWED_TOOL_NAMES.has(toolName)) {
|
|
9235
|
+
return 0;
|
|
9236
|
+
}
|
|
9237
|
+
const validToolName = toolName;
|
|
9238
|
+
let sessionId;
|
|
9239
|
+
const payloadSessionId = payload.session_id;
|
|
9240
|
+
if (typeof payloadSessionId === "string" && payloadSessionId.length > 0) {
|
|
9241
|
+
const sanitized = sanitizeSessionId(payloadSessionId);
|
|
9242
|
+
sessionId = sanitized ?? resolveSessionId();
|
|
9243
|
+
} else {
|
|
9244
|
+
sessionId = resolveSessionId();
|
|
9245
|
+
}
|
|
9246
|
+
const toolInput = typeof payload.tool_input === "object" && payload.tool_input !== null ? payload.tool_input : {};
|
|
9247
|
+
const intentText = typeof toolInput.new_string === "string" ? toolInput.new_string : typeof toolInput.content === "string" ? toolInput.content : "";
|
|
9248
|
+
const end = now();
|
|
9249
|
+
const event = {
|
|
9250
|
+
t: end,
|
|
9251
|
+
intentHash: hashIntent(intentText),
|
|
9252
|
+
toolName: validToolName,
|
|
9253
|
+
candidateCount: 0,
|
|
9254
|
+
// Phase 1: no registry query
|
|
9255
|
+
topScore: null,
|
|
9256
|
+
// Phase 1: no registry query
|
|
9257
|
+
substituted: false,
|
|
9258
|
+
// Phase 1: never substitutes
|
|
9259
|
+
substitutedAtomHash: null,
|
|
9260
|
+
// Phase 1: never substitutes
|
|
9261
|
+
latencyMs: end - start,
|
|
9262
|
+
outcome: "passthrough"
|
|
9263
|
+
// D-HOOK-5 canonical value per plan section 3
|
|
9264
|
+
};
|
|
9265
|
+
appendEvent(event, sessionId, telemetryDir);
|
|
9266
|
+
} catch {
|
|
9267
|
+
}
|
|
9268
|
+
return 0;
|
|
9269
|
+
}
|
|
9270
|
+
|
|
9271
|
+
// src/commands/hooks-aider-install.ts
|
|
9272
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync7, readFileSync as readFileSync7, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
9273
|
+
import { homedir as homedir2 } from "os";
|
|
9274
|
+
import { join as join14 } from "path";
|
|
8867
9275
|
import { parseArgs as parseArgs6 } from "util";
|
|
8868
9276
|
var AIDER_HOOK_MARKER_FILENAME = "yakcc-aider-hook.json";
|
|
8869
9277
|
var YAKCC_AIDER_MARKER = "yakcc-hook-v1-aider";
|
|
8870
9278
|
var HOOK_COMMAND = "yakcc hook-intercept";
|
|
8871
9279
|
function readMarker(markerPath) {
|
|
8872
|
-
if (!
|
|
9280
|
+
if (!existsSync5(markerPath)) return null;
|
|
8873
9281
|
try {
|
|
8874
|
-
return JSON.parse(
|
|
9282
|
+
return JSON.parse(readFileSync7(markerPath, "utf-8"));
|
|
8875
9283
|
} catch {
|
|
8876
9284
|
return null;
|
|
8877
9285
|
}
|
|
@@ -8896,10 +9304,10 @@ async function hooksAiderInstall(argv, logger, overrideAiderDir) {
|
|
|
8896
9304
|
logger.error(`error: ${err.message}`);
|
|
8897
9305
|
return 1;
|
|
8898
9306
|
}
|
|
8899
|
-
const aiderDir = overrideAiderDir ??
|
|
8900
|
-
const markerPath =
|
|
9307
|
+
const aiderDir = overrideAiderDir ?? join14(homedir2(), ".aider");
|
|
9308
|
+
const markerPath = join14(aiderDir, AIDER_HOOK_MARKER_FILENAME);
|
|
8901
9309
|
try {
|
|
8902
|
-
|
|
9310
|
+
mkdirSync7(aiderDir, { recursive: true });
|
|
8903
9311
|
} catch (err) {
|
|
8904
9312
|
logger.error(`error: cannot create ${aiderDir}: ${String(err)}`);
|
|
8905
9313
|
return 1;
|
|
@@ -8945,26 +9353,194 @@ async function hooksAiderInstall(argv, logger, overrideAiderDir) {
|
|
|
8945
9353
|
return 0;
|
|
8946
9354
|
}
|
|
8947
9355
|
|
|
8948
|
-
// src/commands/hooks-
|
|
8949
|
-
import { existsSync as
|
|
8950
|
-
import {
|
|
9356
|
+
// src/commands/hooks-cline-install.ts
|
|
9357
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync8, readFileSync as readFileSync8, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
9358
|
+
import { homedir as homedir3 } from "os";
|
|
9359
|
+
import { join as join15 } from "path";
|
|
8951
9360
|
import { parseArgs as parseArgs7 } from "util";
|
|
9361
|
+
var CLINE_HOOK_MARKER_FILENAME = "yakcc-cline-hook.json";
|
|
9362
|
+
var YAKCC_CLINE_MARKER = "yakcc-hook-v1-cline";
|
|
9363
|
+
var HOOK_COMMAND2 = "yakcc hook-intercept";
|
|
9364
|
+
function readMarker2(markerPath) {
|
|
9365
|
+
if (!existsSync6(markerPath)) return null;
|
|
9366
|
+
try {
|
|
9367
|
+
return JSON.parse(readFileSync8(markerPath, "utf-8"));
|
|
9368
|
+
} catch {
|
|
9369
|
+
return null;
|
|
9370
|
+
}
|
|
9371
|
+
}
|
|
9372
|
+
function isYakccInstalled2(markerPath) {
|
|
9373
|
+
const marker = readMarker2(markerPath);
|
|
9374
|
+
return marker !== null && marker._yakcc === YAKCC_CLINE_MARKER;
|
|
9375
|
+
}
|
|
9376
|
+
async function hooksClineInstall(argv, logger, overrideClineDir) {
|
|
9377
|
+
let parsed;
|
|
9378
|
+
try {
|
|
9379
|
+
parsed = parseArgs7({
|
|
9380
|
+
args: [...argv],
|
|
9381
|
+
options: {
|
|
9382
|
+
target: { type: "string", short: "t" },
|
|
9383
|
+
uninstall: { type: "boolean" }
|
|
9384
|
+
},
|
|
9385
|
+
allowPositionals: false,
|
|
9386
|
+
strict: true
|
|
9387
|
+
});
|
|
9388
|
+
} catch (err) {
|
|
9389
|
+
logger.error(`error: ${err.message}`);
|
|
9390
|
+
return 1;
|
|
9391
|
+
}
|
|
9392
|
+
const clineDir = overrideClineDir ?? join15(homedir3(), ".config", "cline");
|
|
9393
|
+
const markerPath = join15(clineDir, CLINE_HOOK_MARKER_FILENAME);
|
|
9394
|
+
try {
|
|
9395
|
+
mkdirSync8(clineDir, { recursive: true });
|
|
9396
|
+
} catch (err) {
|
|
9397
|
+
logger.error(`error: cannot create ${clineDir}: ${String(err)}`);
|
|
9398
|
+
return 1;
|
|
9399
|
+
}
|
|
9400
|
+
if (parsed.values.uninstall) {
|
|
9401
|
+
if (!isYakccInstalled2(markerPath)) {
|
|
9402
|
+
logger.log("yakcc cline hook not installed \u2014 nothing to uninstall.");
|
|
9403
|
+
return 0;
|
|
9404
|
+
}
|
|
9405
|
+
try {
|
|
9406
|
+
rmSync2(markerPath);
|
|
9407
|
+
} catch (err) {
|
|
9408
|
+
logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
|
|
9409
|
+
return 1;
|
|
9410
|
+
}
|
|
9411
|
+
logger.log(`yakcc cline hook marker removed: ${markerPath}`);
|
|
9412
|
+
return 0;
|
|
9413
|
+
}
|
|
9414
|
+
if (isYakccInstalled2(markerPath)) {
|
|
9415
|
+
logger.log(`yakcc cline hook already installed at ${markerPath} (idempotent).`);
|
|
9416
|
+
return 0;
|
|
9417
|
+
}
|
|
9418
|
+
const marker = {
|
|
9419
|
+
command: HOOK_COMMAND2,
|
|
9420
|
+
description: "yakcc tool-call interception hook for Cline",
|
|
9421
|
+
sessionEnvVar: "CLINE_SESSION_ID",
|
|
9422
|
+
telemetryPrefix: "cline",
|
|
9423
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9424
|
+
_yakcc: YAKCC_CLINE_MARKER,
|
|
9425
|
+
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."
|
|
9426
|
+
};
|
|
9427
|
+
try {
|
|
9428
|
+
writeFileSync5(markerPath, `${JSON.stringify(marker, null, 2)}
|
|
9429
|
+
`, "utf-8");
|
|
9430
|
+
} catch (err) {
|
|
9431
|
+
logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
|
|
9432
|
+
return 1;
|
|
9433
|
+
}
|
|
9434
|
+
logger.log(`yakcc cline hook marker installed: ${markerPath}`);
|
|
9435
|
+
logger.log("note: Cline tool-call interception API not yet stable \u2014 see marker for details.");
|
|
9436
|
+
return 0;
|
|
9437
|
+
}
|
|
9438
|
+
|
|
9439
|
+
// src/commands/hooks-continue-install.ts
|
|
9440
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync9, readFileSync as readFileSync9, rmSync as rmSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
9441
|
+
import { homedir as homedir4 } from "os";
|
|
9442
|
+
import { join as join16 } from "path";
|
|
9443
|
+
import { parseArgs as parseArgs8 } from "util";
|
|
9444
|
+
var CONTINUE_HOOK_MARKER_FILENAME = "yakcc-continue-hook.json";
|
|
9445
|
+
var YAKCC_CONTINUE_MARKER = "yakcc-hook-v1-continue";
|
|
9446
|
+
var HOOK_COMMAND3 = "yakcc hook-intercept";
|
|
9447
|
+
function readMarker3(markerPath) {
|
|
9448
|
+
if (!existsSync7(markerPath)) return null;
|
|
9449
|
+
try {
|
|
9450
|
+
return JSON.parse(readFileSync9(markerPath, "utf-8"));
|
|
9451
|
+
} catch {
|
|
9452
|
+
return null;
|
|
9453
|
+
}
|
|
9454
|
+
}
|
|
9455
|
+
function isYakccInstalled3(markerPath) {
|
|
9456
|
+
const marker = readMarker3(markerPath);
|
|
9457
|
+
return marker !== null && marker._yakcc === YAKCC_CONTINUE_MARKER;
|
|
9458
|
+
}
|
|
9459
|
+
async function hooksContinueInstall(argv, logger, overrideContinueDir) {
|
|
9460
|
+
let parsed;
|
|
9461
|
+
try {
|
|
9462
|
+
parsed = parseArgs8({
|
|
9463
|
+
args: [...argv],
|
|
9464
|
+
options: {
|
|
9465
|
+
target: { type: "string", short: "t" },
|
|
9466
|
+
uninstall: { type: "boolean" }
|
|
9467
|
+
},
|
|
9468
|
+
allowPositionals: false,
|
|
9469
|
+
strict: true
|
|
9470
|
+
});
|
|
9471
|
+
} catch (err) {
|
|
9472
|
+
logger.error(`error: ${err.message}`);
|
|
9473
|
+
return 1;
|
|
9474
|
+
}
|
|
9475
|
+
const continueDir = overrideContinueDir ?? join16(homedir4(), ".continue");
|
|
9476
|
+
const markerPath = join16(continueDir, CONTINUE_HOOK_MARKER_FILENAME);
|
|
9477
|
+
try {
|
|
9478
|
+
mkdirSync9(continueDir, { recursive: true });
|
|
9479
|
+
} catch (err) {
|
|
9480
|
+
logger.error(`error: cannot create ${continueDir}: ${String(err)}`);
|
|
9481
|
+
return 1;
|
|
9482
|
+
}
|
|
9483
|
+
if (parsed.values.uninstall) {
|
|
9484
|
+
if (!isYakccInstalled3(markerPath)) {
|
|
9485
|
+
logger.log("yakcc continue hook not installed \u2014 nothing to uninstall.");
|
|
9486
|
+
return 0;
|
|
9487
|
+
}
|
|
9488
|
+
try {
|
|
9489
|
+
rmSync3(markerPath);
|
|
9490
|
+
} catch (err) {
|
|
9491
|
+
logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
|
|
9492
|
+
return 1;
|
|
9493
|
+
}
|
|
9494
|
+
logger.log(`yakcc continue hook marker removed: ${markerPath}`);
|
|
9495
|
+
return 0;
|
|
9496
|
+
}
|
|
9497
|
+
if (isYakccInstalled3(markerPath)) {
|
|
9498
|
+
logger.log(`yakcc continue hook already installed at ${markerPath} (idempotent).`);
|
|
9499
|
+
return 0;
|
|
9500
|
+
}
|
|
9501
|
+
const marker = {
|
|
9502
|
+
command: HOOK_COMMAND3,
|
|
9503
|
+
description: "yakcc tool-call interception hook for Continue.dev",
|
|
9504
|
+
sessionEnvVar: "CONTINUE_SESSION_ID",
|
|
9505
|
+
telemetryPrefix: "continue",
|
|
9506
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9507
|
+
_yakcc: YAKCC_CONTINUE_MARKER,
|
|
9508
|
+
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."
|
|
9509
|
+
};
|
|
9510
|
+
try {
|
|
9511
|
+
writeFileSync6(markerPath, `${JSON.stringify(marker, null, 2)}
|
|
9512
|
+
`, "utf-8");
|
|
9513
|
+
} catch (err) {
|
|
9514
|
+
logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
|
|
9515
|
+
return 1;
|
|
9516
|
+
}
|
|
9517
|
+
logger.log(`yakcc continue hook marker installed: ${markerPath}`);
|
|
9518
|
+
logger.log(
|
|
9519
|
+
"note: Continue.dev tool-call interception API not yet stable \u2014 see marker for details."
|
|
9520
|
+
);
|
|
9521
|
+
return 0;
|
|
9522
|
+
}
|
|
9523
|
+
|
|
9524
|
+
// src/commands/hooks-cursor-install.ts
|
|
9525
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync10, readFileSync as readFileSync10, writeFileSync as writeFileSync7 } from "fs";
|
|
9526
|
+
import { join as join17 } from "path";
|
|
9527
|
+
import { parseArgs as parseArgs9 } from "util";
|
|
8952
9528
|
var CURSOR_HOOK_MARKER_FILENAME = "yakcc-cursor-hook.json";
|
|
8953
9529
|
var YAKCC_CURSOR_MARKER = "yakcc-hook-v1-cursor";
|
|
8954
|
-
var
|
|
9530
|
+
var HOOK_COMMAND4 = "yakcc hook-intercept";
|
|
8955
9531
|
function readCursorSettings(settingsPath) {
|
|
8956
|
-
if (!
|
|
9532
|
+
if (!existsSync8(settingsPath)) return {};
|
|
8957
9533
|
try {
|
|
8958
|
-
return JSON.parse(
|
|
9534
|
+
return JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
8959
9535
|
} catch {
|
|
8960
9536
|
return {};
|
|
8961
9537
|
}
|
|
8962
9538
|
}
|
|
8963
9539
|
function writeCursorSettings(settingsPath, settings) {
|
|
8964
|
-
|
|
9540
|
+
writeFileSync7(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
8965
9541
|
`, "utf-8");
|
|
8966
9542
|
}
|
|
8967
|
-
function
|
|
9543
|
+
function isYakccInstalled4(settings) {
|
|
8968
9544
|
const hooks = settings.hooks;
|
|
8969
9545
|
if (hooks == null || typeof hooks !== "object") return false;
|
|
8970
9546
|
const yakccEntry = hooks.yakcc;
|
|
@@ -8972,7 +9548,7 @@ function isYakccInstalled2(settings) {
|
|
|
8972
9548
|
return yakccEntry._yakcc === YAKCC_CURSOR_MARKER;
|
|
8973
9549
|
}
|
|
8974
9550
|
function applyInstall(settings) {
|
|
8975
|
-
if (
|
|
9551
|
+
if (isYakccInstalled4(settings)) {
|
|
8976
9552
|
return { settings, alreadyInstalled: true };
|
|
8977
9553
|
}
|
|
8978
9554
|
return {
|
|
@@ -8981,7 +9557,7 @@ function applyInstall(settings) {
|
|
|
8981
9557
|
hooks: {
|
|
8982
9558
|
...settings.hooks ?? {},
|
|
8983
9559
|
yakcc: {
|
|
8984
|
-
command:
|
|
9560
|
+
command: HOOK_COMMAND4,
|
|
8985
9561
|
description: "yakcc tool-call interception hook for Cursor",
|
|
8986
9562
|
sessionEnvVar: "CURSOR_SESSION_ID",
|
|
8987
9563
|
_yakcc: YAKCC_CURSOR_MARKER
|
|
@@ -8992,7 +9568,7 @@ function applyInstall(settings) {
|
|
|
8992
9568
|
};
|
|
8993
9569
|
}
|
|
8994
9570
|
function applyUninstall(settings) {
|
|
8995
|
-
if (!
|
|
9571
|
+
if (!isYakccInstalled4(settings)) {
|
|
8996
9572
|
return { settings, wasInstalled: false };
|
|
8997
9573
|
}
|
|
8998
9574
|
const { yakcc: _removed, ...remainingHooks } = settings.hooks ?? {};
|
|
@@ -9001,7 +9577,7 @@ function applyUninstall(settings) {
|
|
|
9001
9577
|
return { settings: newSettings, wasInstalled: true };
|
|
9002
9578
|
}
|
|
9003
9579
|
async function hooksCursorInstall(argv, logger) {
|
|
9004
|
-
const { values } =
|
|
9580
|
+
const { values } = parseArgs9({
|
|
9005
9581
|
args: [...argv],
|
|
9006
9582
|
options: {
|
|
9007
9583
|
target: { type: "string", short: "t" },
|
|
@@ -9011,11 +9587,11 @@ async function hooksCursorInstall(argv, logger) {
|
|
|
9011
9587
|
strict: true
|
|
9012
9588
|
});
|
|
9013
9589
|
const targetDir = values.target ?? ".";
|
|
9014
|
-
const cursorDir =
|
|
9015
|
-
const settingsPath =
|
|
9016
|
-
const markerPath =
|
|
9590
|
+
const cursorDir = join17(targetDir, ".cursor");
|
|
9591
|
+
const settingsPath = join17(cursorDir, "settings.json");
|
|
9592
|
+
const markerPath = join17(cursorDir, CURSOR_HOOK_MARKER_FILENAME);
|
|
9017
9593
|
try {
|
|
9018
|
-
|
|
9594
|
+
mkdirSync10(cursorDir, { recursive: true });
|
|
9019
9595
|
} catch (err) {
|
|
9020
9596
|
logger.error(`error: cannot create ${cursorDir}: ${String(err)}`);
|
|
9021
9597
|
return 1;
|
|
@@ -9043,11 +9619,11 @@ async function hooksCursorInstall(argv, logger) {
|
|
|
9043
9619
|
return 1;
|
|
9044
9620
|
}
|
|
9045
9621
|
try {
|
|
9046
|
-
|
|
9622
|
+
writeFileSync7(
|
|
9047
9623
|
markerPath,
|
|
9048
9624
|
`${JSON.stringify(
|
|
9049
9625
|
{
|
|
9050
|
-
command:
|
|
9626
|
+
command: HOOK_COMMAND4,
|
|
9051
9627
|
description: "yakcc tool-call interception hook for Cursor",
|
|
9052
9628
|
sessionEnvVar: "CURSOR_SESSION_ID",
|
|
9053
9629
|
telemetryPrefix: "cursor",
|
|
@@ -9067,7 +9643,7 @@ async function hooksCursorInstall(argv, logger) {
|
|
|
9067
9643
|
logger.log(`yakcc cursor hook already installed at ${settingsPath} (idempotent).`);
|
|
9068
9644
|
} else {
|
|
9069
9645
|
logger.log(`yakcc cursor hook installed at ${settingsPath}`);
|
|
9070
|
-
logger.log(`hook command: ${
|
|
9646
|
+
logger.log(`hook command: ${HOOK_COMMAND4}`);
|
|
9071
9647
|
logger.log("session env var: CURSOR_SESSION_ID");
|
|
9072
9648
|
logger.log(`marker: ${markerPath}`);
|
|
9073
9649
|
logger.log("note: Cursor tool-call interception API not yet stable \u2014 see marker for details.");
|
|
@@ -9076,27 +9652,27 @@ async function hooksCursorInstall(argv, logger) {
|
|
|
9076
9652
|
}
|
|
9077
9653
|
|
|
9078
9654
|
// src/commands/hooks-install.ts
|
|
9079
|
-
import { existsSync as
|
|
9080
|
-
import { join as
|
|
9081
|
-
import { parseArgs as
|
|
9655
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync11, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync8 } from "fs";
|
|
9656
|
+
import { join as join18 } from "path";
|
|
9657
|
+
import { parseArgs as parseArgs10 } from "util";
|
|
9082
9658
|
var HOOK_EVENT = "PreToolUse";
|
|
9083
9659
|
var HOOK_MATCHER = "Edit|Write|MultiEdit";
|
|
9084
|
-
var
|
|
9660
|
+
var HOOK_COMMAND5 = "yakcc hook-intercept";
|
|
9085
9661
|
var YAKCC_MARKER = "yakcc-hook-v1";
|
|
9086
9662
|
function readSettings(settingsPath) {
|
|
9087
|
-
if (!
|
|
9663
|
+
if (!existsSync9(settingsPath)) return {};
|
|
9088
9664
|
try {
|
|
9089
|
-
return JSON.parse(
|
|
9665
|
+
return JSON.parse(readFileSync11(settingsPath, "utf-8"));
|
|
9090
9666
|
} catch {
|
|
9091
9667
|
return {};
|
|
9092
9668
|
}
|
|
9093
9669
|
}
|
|
9094
9670
|
function writeSettings(settingsPath, settings) {
|
|
9095
|
-
|
|
9671
|
+
writeFileSync8(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
9096
9672
|
`, "utf-8");
|
|
9097
9673
|
}
|
|
9098
9674
|
function buildYakccHookObject() {
|
|
9099
|
-
return { type: "command", command:
|
|
9675
|
+
return { type: "command", command: HOOK_COMMAND5, _yakcc: YAKCC_MARKER };
|
|
9100
9676
|
}
|
|
9101
9677
|
function isYakccEntry(entry) {
|
|
9102
9678
|
return entry.hooks.some((h) => h._yakcc === YAKCC_MARKER);
|
|
@@ -9135,7 +9711,7 @@ function applyUninstall2(settings) {
|
|
|
9135
9711
|
return { settings: newSettings, wasInstalled: true };
|
|
9136
9712
|
}
|
|
9137
9713
|
async function hooksClaudeCodeInstall(argv, logger) {
|
|
9138
|
-
const { values } =
|
|
9714
|
+
const { values } = parseArgs10({
|
|
9139
9715
|
args: [...argv],
|
|
9140
9716
|
options: {
|
|
9141
9717
|
target: { type: "string", short: "t" },
|
|
@@ -9145,11 +9721,11 @@ async function hooksClaudeCodeInstall(argv, logger) {
|
|
|
9145
9721
|
strict: true
|
|
9146
9722
|
});
|
|
9147
9723
|
const targetDir = values.target ?? ".";
|
|
9148
|
-
const claudeDir =
|
|
9149
|
-
const settingsPath =
|
|
9150
|
-
const claudeMdPath =
|
|
9724
|
+
const claudeDir = join18(targetDir, ".claude");
|
|
9725
|
+
const settingsPath = join18(claudeDir, "settings.json");
|
|
9726
|
+
const claudeMdPath = join18(claudeDir, "CLAUDE.md");
|
|
9151
9727
|
try {
|
|
9152
|
-
|
|
9728
|
+
mkdirSync11(claudeDir, { recursive: true });
|
|
9153
9729
|
} catch (err) {
|
|
9154
9730
|
logger.error(`error: cannot create ${claudeDir}: ${String(err)}`);
|
|
9155
9731
|
return 1;
|
|
@@ -9176,9 +9752,9 @@ async function hooksClaudeCodeInstall(argv, logger) {
|
|
|
9176
9752
|
logger.error(`error: cannot write ${settingsPath}: ${String(err)}`);
|
|
9177
9753
|
return 1;
|
|
9178
9754
|
}
|
|
9179
|
-
if (
|
|
9755
|
+
if (existsSync9(claudeMdPath)) {
|
|
9180
9756
|
try {
|
|
9181
|
-
|
|
9757
|
+
rmSync4(claudeMdPath);
|
|
9182
9758
|
} catch (err) {
|
|
9183
9759
|
logger.error(`warning: cannot remove v0 stub ${claudeMdPath}: ${String(err)}`);
|
|
9184
9760
|
}
|
|
@@ -9187,31 +9763,31 @@ async function hooksClaudeCodeInstall(argv, logger) {
|
|
|
9187
9763
|
logger.log(`yakcc hook already installed at ${settingsPath} (idempotent).`);
|
|
9188
9764
|
} else {
|
|
9189
9765
|
logger.log(`yakcc hook installed at ${settingsPath}`);
|
|
9190
|
-
logger.log(`tool-call interception: ${HOOK_MATCHER} \u2192 ${
|
|
9766
|
+
logger.log(`tool-call interception: ${HOOK_MATCHER} \u2192 ${HOOK_COMMAND5}`);
|
|
9191
9767
|
}
|
|
9192
9768
|
return 0;
|
|
9193
9769
|
}
|
|
9194
9770
|
|
|
9195
9771
|
// src/commands/hooks-windsurf-install.ts
|
|
9196
|
-
import { existsSync as
|
|
9197
|
-
import { join as
|
|
9198
|
-
import { parseArgs as
|
|
9772
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
|
|
9773
|
+
import { join as join19 } from "path";
|
|
9774
|
+
import { parseArgs as parseArgs11 } from "util";
|
|
9199
9775
|
var WINDSURF_HOOK_MARKER_FILENAME = "yakcc-windsurf-hook.json";
|
|
9200
9776
|
var YAKCC_WINDSURF_MARKER = "yakcc-hook-v1-windsurf";
|
|
9201
|
-
var
|
|
9777
|
+
var HOOK_COMMAND6 = "yakcc hook-intercept";
|
|
9202
9778
|
function readWindsurfSettings(settingsPath) {
|
|
9203
|
-
if (!
|
|
9779
|
+
if (!existsSync10(settingsPath)) return {};
|
|
9204
9780
|
try {
|
|
9205
|
-
return JSON.parse(
|
|
9781
|
+
return JSON.parse(readFileSync12(settingsPath, "utf-8"));
|
|
9206
9782
|
} catch {
|
|
9207
9783
|
return {};
|
|
9208
9784
|
}
|
|
9209
9785
|
}
|
|
9210
9786
|
function writeWindsurfSettings(settingsPath, settings) {
|
|
9211
|
-
|
|
9787
|
+
writeFileSync9(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
9212
9788
|
`, "utf-8");
|
|
9213
9789
|
}
|
|
9214
|
-
function
|
|
9790
|
+
function isYakccInstalled5(settings) {
|
|
9215
9791
|
const hooks = settings.hooks;
|
|
9216
9792
|
if (hooks == null || typeof hooks !== "object") return false;
|
|
9217
9793
|
const yakccEntry = hooks.yakcc;
|
|
@@ -9219,7 +9795,7 @@ function isYakccInstalled3(settings) {
|
|
|
9219
9795
|
return yakccEntry._yakcc === YAKCC_WINDSURF_MARKER;
|
|
9220
9796
|
}
|
|
9221
9797
|
function applyInstall3(settings) {
|
|
9222
|
-
if (
|
|
9798
|
+
if (isYakccInstalled5(settings)) {
|
|
9223
9799
|
return { settings, alreadyInstalled: true };
|
|
9224
9800
|
}
|
|
9225
9801
|
return {
|
|
@@ -9228,7 +9804,7 @@ function applyInstall3(settings) {
|
|
|
9228
9804
|
hooks: {
|
|
9229
9805
|
...settings.hooks ?? {},
|
|
9230
9806
|
yakcc: {
|
|
9231
|
-
command:
|
|
9807
|
+
command: HOOK_COMMAND6,
|
|
9232
9808
|
description: "yakcc tool-call interception hook for Windsurf",
|
|
9233
9809
|
sessionEnvVar: "WINDSURF_SESSION_ID",
|
|
9234
9810
|
_yakcc: YAKCC_WINDSURF_MARKER
|
|
@@ -9239,7 +9815,7 @@ function applyInstall3(settings) {
|
|
|
9239
9815
|
};
|
|
9240
9816
|
}
|
|
9241
9817
|
function applyUninstall3(settings) {
|
|
9242
|
-
if (!
|
|
9818
|
+
if (!isYakccInstalled5(settings)) {
|
|
9243
9819
|
return { settings, wasInstalled: false };
|
|
9244
9820
|
}
|
|
9245
9821
|
const { yakcc: _removed, ...remainingHooks } = settings.hooks ?? {};
|
|
@@ -9248,7 +9824,7 @@ function applyUninstall3(settings) {
|
|
|
9248
9824
|
return { settings: newSettings, wasInstalled: true };
|
|
9249
9825
|
}
|
|
9250
9826
|
async function hooksWindsurfInstall(argv, logger) {
|
|
9251
|
-
const { values } =
|
|
9827
|
+
const { values } = parseArgs11({
|
|
9252
9828
|
args: [...argv],
|
|
9253
9829
|
options: {
|
|
9254
9830
|
target: { type: "string", short: "t" },
|
|
@@ -9258,11 +9834,11 @@ async function hooksWindsurfInstall(argv, logger) {
|
|
|
9258
9834
|
strict: true
|
|
9259
9835
|
});
|
|
9260
9836
|
const targetDir = values.target ?? ".";
|
|
9261
|
-
const windsurfDir =
|
|
9262
|
-
const settingsPath =
|
|
9263
|
-
const markerPath =
|
|
9837
|
+
const windsurfDir = join19(targetDir, ".windsurf");
|
|
9838
|
+
const settingsPath = join19(windsurfDir, "settings.json");
|
|
9839
|
+
const markerPath = join19(windsurfDir, WINDSURF_HOOK_MARKER_FILENAME);
|
|
9264
9840
|
try {
|
|
9265
|
-
|
|
9841
|
+
mkdirSync12(windsurfDir, { recursive: true });
|
|
9266
9842
|
} catch (err) {
|
|
9267
9843
|
logger.error(`error: cannot create ${windsurfDir}: ${String(err)}`);
|
|
9268
9844
|
return 1;
|
|
@@ -9290,11 +9866,11 @@ async function hooksWindsurfInstall(argv, logger) {
|
|
|
9290
9866
|
return 1;
|
|
9291
9867
|
}
|
|
9292
9868
|
try {
|
|
9293
|
-
|
|
9869
|
+
writeFileSync9(
|
|
9294
9870
|
markerPath,
|
|
9295
9871
|
`${JSON.stringify(
|
|
9296
9872
|
{
|
|
9297
|
-
command:
|
|
9873
|
+
command: HOOK_COMMAND6,
|
|
9298
9874
|
description: "yakcc tool-call interception hook for Windsurf",
|
|
9299
9875
|
sessionEnvVar: "WINDSURF_SESSION_ID",
|
|
9300
9876
|
telemetryPrefix: "windsurf",
|
|
@@ -9314,7 +9890,7 @@ async function hooksWindsurfInstall(argv, logger) {
|
|
|
9314
9890
|
logger.log(`yakcc windsurf hook already installed at ${settingsPath} (idempotent).`);
|
|
9315
9891
|
} else {
|
|
9316
9892
|
logger.log(`yakcc windsurf hook installed at ${settingsPath}`);
|
|
9317
|
-
logger.log(`hook command: ${
|
|
9893
|
+
logger.log(`hook command: ${HOOK_COMMAND6}`);
|
|
9318
9894
|
logger.log("session env var: WINDSURF_SESSION_ID");
|
|
9319
9895
|
logger.log(`marker: ${markerPath}`);
|
|
9320
9896
|
logger.log(
|
|
@@ -9326,43 +9902,43 @@ async function hooksWindsurfInstall(argv, logger) {
|
|
|
9326
9902
|
|
|
9327
9903
|
// src/commands/init.ts
|
|
9328
9904
|
init_dist2();
|
|
9329
|
-
import { existsSync as
|
|
9330
|
-
import { join as
|
|
9905
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync13, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
|
|
9906
|
+
import { join as join22 } from "path";
|
|
9331
9907
|
import { parseArgs as parseArgs12 } from "util";
|
|
9332
9908
|
|
|
9333
9909
|
// src/lib/ide-detect.ts
|
|
9334
|
-
import { existsSync as
|
|
9335
|
-
import { homedir as
|
|
9336
|
-
import { join as
|
|
9910
|
+
import { existsSync as existsSync11 } from "fs";
|
|
9911
|
+
import { homedir as homedir5 } from "os";
|
|
9912
|
+
import { join as join20 } from "path";
|
|
9337
9913
|
function buildCandidatePaths(home) {
|
|
9338
9914
|
const platform = process.platform;
|
|
9339
9915
|
const cursorCandidates = (() => {
|
|
9340
9916
|
if (platform === "darwin") {
|
|
9341
|
-
return [
|
|
9917
|
+
return [join20(home, "Library", "Application Support", "Cursor")];
|
|
9342
9918
|
}
|
|
9343
9919
|
if (platform === "win32") {
|
|
9344
9920
|
const appdata = process.env.APPDATA;
|
|
9345
9921
|
if (appdata !== void 0) {
|
|
9346
|
-
return [
|
|
9922
|
+
return [join20(appdata, "Cursor")];
|
|
9347
9923
|
}
|
|
9348
|
-
return [
|
|
9924
|
+
return [join20(home, "AppData", "Roaming", "Cursor")];
|
|
9349
9925
|
}
|
|
9350
|
-
return [
|
|
9926
|
+
return [join20(home, ".config", "Cursor")];
|
|
9351
9927
|
})();
|
|
9352
9928
|
const clineCandidates = [
|
|
9353
|
-
|
|
9929
|
+
join20(home, ".config", "cline"),
|
|
9354
9930
|
// VS Code extension dir marker — check the containing directory prefix since
|
|
9355
9931
|
// the actual extension dir includes a version suffix.
|
|
9356
|
-
|
|
9932
|
+
join20(home, ".vscode", "extensions", "saoudrizwan.claude-dev")
|
|
9357
9933
|
];
|
|
9358
9934
|
const continueCandidates = [
|
|
9359
|
-
|
|
9360
|
-
|
|
9935
|
+
join20(home, ".continue"),
|
|
9936
|
+
join20(home, ".vscode", "extensions", "continue.continue")
|
|
9361
9937
|
];
|
|
9362
|
-
const windsurfCandidates = [
|
|
9363
|
-
const aiderCandidates = [
|
|
9938
|
+
const windsurfCandidates = [join20(home, ".windsurf")];
|
|
9939
|
+
const aiderCandidates = [join20(home, ".aider")];
|
|
9364
9940
|
return {
|
|
9365
|
-
"claude-code": [
|
|
9941
|
+
"claude-code": [join20(home, ".claude")],
|
|
9366
9942
|
cursor: cursorCandidates,
|
|
9367
9943
|
cline: clineCandidates,
|
|
9368
9944
|
continue: continueCandidates,
|
|
@@ -9371,12 +9947,12 @@ function buildCandidatePaths(home) {
|
|
|
9371
9947
|
};
|
|
9372
9948
|
}
|
|
9373
9949
|
function detectInstalledIdes(overrideHome) {
|
|
9374
|
-
const home = overrideHome ??
|
|
9950
|
+
const home = overrideHome ?? homedir5();
|
|
9375
9951
|
const candidates = buildCandidatePaths(home);
|
|
9376
9952
|
const detected = [];
|
|
9377
9953
|
for (const [name, paths] of Object.entries(candidates)) {
|
|
9378
9954
|
for (const configDir of paths) {
|
|
9379
|
-
if (
|
|
9955
|
+
if (existsSync11(configDir)) {
|
|
9380
9956
|
detected.push({ name, configDir, installed: true });
|
|
9381
9957
|
break;
|
|
9382
9958
|
}
|
|
@@ -9393,185 +9969,17 @@ var KNOWN_IDE_NAMES = [
|
|
|
9393
9969
|
"aider"
|
|
9394
9970
|
];
|
|
9395
9971
|
|
|
9396
|
-
// src/commands/hooks-cline-install.ts
|
|
9397
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync9, readFileSync as readFileSync9, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
9398
|
-
import { homedir as homedir3 } from "os";
|
|
9399
|
-
import { join as join15 } from "path";
|
|
9400
|
-
import { parseArgs as parseArgs10 } from "util";
|
|
9401
|
-
var CLINE_HOOK_MARKER_FILENAME = "yakcc-cline-hook.json";
|
|
9402
|
-
var YAKCC_CLINE_MARKER = "yakcc-hook-v1-cline";
|
|
9403
|
-
var HOOK_COMMAND5 = "yakcc hook-intercept";
|
|
9404
|
-
function readMarker2(markerPath) {
|
|
9405
|
-
if (!existsSync8(markerPath)) return null;
|
|
9406
|
-
try {
|
|
9407
|
-
return JSON.parse(readFileSync9(markerPath, "utf-8"));
|
|
9408
|
-
} catch {
|
|
9409
|
-
return null;
|
|
9410
|
-
}
|
|
9411
|
-
}
|
|
9412
|
-
function isYakccInstalled4(markerPath) {
|
|
9413
|
-
const marker = readMarker2(markerPath);
|
|
9414
|
-
return marker !== null && marker._yakcc === YAKCC_CLINE_MARKER;
|
|
9415
|
-
}
|
|
9416
|
-
async function hooksClineInstall(argv, logger, overrideClineDir) {
|
|
9417
|
-
let parsed;
|
|
9418
|
-
try {
|
|
9419
|
-
parsed = parseArgs10({
|
|
9420
|
-
args: [...argv],
|
|
9421
|
-
options: {
|
|
9422
|
-
target: { type: "string", short: "t" },
|
|
9423
|
-
uninstall: { type: "boolean" }
|
|
9424
|
-
},
|
|
9425
|
-
allowPositionals: false,
|
|
9426
|
-
strict: true
|
|
9427
|
-
});
|
|
9428
|
-
} catch (err) {
|
|
9429
|
-
logger.error(`error: ${err.message}`);
|
|
9430
|
-
return 1;
|
|
9431
|
-
}
|
|
9432
|
-
const clineDir = overrideClineDir ?? join15(homedir3(), ".config", "cline");
|
|
9433
|
-
const markerPath = join15(clineDir, CLINE_HOOK_MARKER_FILENAME);
|
|
9434
|
-
try {
|
|
9435
|
-
mkdirSync9(clineDir, { recursive: true });
|
|
9436
|
-
} catch (err) {
|
|
9437
|
-
logger.error(`error: cannot create ${clineDir}: ${String(err)}`);
|
|
9438
|
-
return 1;
|
|
9439
|
-
}
|
|
9440
|
-
if (parsed.values.uninstall) {
|
|
9441
|
-
if (!isYakccInstalled4(markerPath)) {
|
|
9442
|
-
logger.log("yakcc cline hook not installed \u2014 nothing to uninstall.");
|
|
9443
|
-
return 0;
|
|
9444
|
-
}
|
|
9445
|
-
try {
|
|
9446
|
-
rmSync3(markerPath);
|
|
9447
|
-
} catch (err) {
|
|
9448
|
-
logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
|
|
9449
|
-
return 1;
|
|
9450
|
-
}
|
|
9451
|
-
logger.log(`yakcc cline hook marker removed: ${markerPath}`);
|
|
9452
|
-
return 0;
|
|
9453
|
-
}
|
|
9454
|
-
if (isYakccInstalled4(markerPath)) {
|
|
9455
|
-
logger.log(`yakcc cline hook already installed at ${markerPath} (idempotent).`);
|
|
9456
|
-
return 0;
|
|
9457
|
-
}
|
|
9458
|
-
const marker = {
|
|
9459
|
-
command: HOOK_COMMAND5,
|
|
9460
|
-
description: "yakcc tool-call interception hook for Cline",
|
|
9461
|
-
sessionEnvVar: "CLINE_SESSION_ID",
|
|
9462
|
-
telemetryPrefix: "cline",
|
|
9463
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9464
|
-
_yakcc: YAKCC_CLINE_MARKER,
|
|
9465
|
-
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."
|
|
9466
|
-
};
|
|
9467
|
-
try {
|
|
9468
|
-
writeFileSync8(markerPath, `${JSON.stringify(marker, null, 2)}
|
|
9469
|
-
`, "utf-8");
|
|
9470
|
-
} catch (err) {
|
|
9471
|
-
logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
|
|
9472
|
-
return 1;
|
|
9473
|
-
}
|
|
9474
|
-
logger.log(`yakcc cline hook marker installed: ${markerPath}`);
|
|
9475
|
-
logger.log("note: Cline tool-call interception API not yet stable \u2014 see marker for details.");
|
|
9476
|
-
return 0;
|
|
9477
|
-
}
|
|
9478
|
-
|
|
9479
|
-
// src/commands/hooks-continue-install.ts
|
|
9480
|
-
import { existsSync as existsSync9, mkdirSync as mkdirSync10, readFileSync as readFileSync10, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
9481
|
-
import { homedir as homedir4 } from "os";
|
|
9482
|
-
import { join as join16 } from "path";
|
|
9483
|
-
import { parseArgs as parseArgs11 } from "util";
|
|
9484
|
-
var CONTINUE_HOOK_MARKER_FILENAME = "yakcc-continue-hook.json";
|
|
9485
|
-
var YAKCC_CONTINUE_MARKER = "yakcc-hook-v1-continue";
|
|
9486
|
-
var HOOK_COMMAND6 = "yakcc hook-intercept";
|
|
9487
|
-
function readMarker3(markerPath) {
|
|
9488
|
-
if (!existsSync9(markerPath)) return null;
|
|
9489
|
-
try {
|
|
9490
|
-
return JSON.parse(readFileSync10(markerPath, "utf-8"));
|
|
9491
|
-
} catch {
|
|
9492
|
-
return null;
|
|
9493
|
-
}
|
|
9494
|
-
}
|
|
9495
|
-
function isYakccInstalled5(markerPath) {
|
|
9496
|
-
const marker = readMarker3(markerPath);
|
|
9497
|
-
return marker !== null && marker._yakcc === YAKCC_CONTINUE_MARKER;
|
|
9498
|
-
}
|
|
9499
|
-
async function hooksContinueInstall(argv, logger, overrideContinueDir) {
|
|
9500
|
-
let parsed;
|
|
9501
|
-
try {
|
|
9502
|
-
parsed = parseArgs11({
|
|
9503
|
-
args: [...argv],
|
|
9504
|
-
options: {
|
|
9505
|
-
target: { type: "string", short: "t" },
|
|
9506
|
-
uninstall: { type: "boolean" }
|
|
9507
|
-
},
|
|
9508
|
-
allowPositionals: false,
|
|
9509
|
-
strict: true
|
|
9510
|
-
});
|
|
9511
|
-
} catch (err) {
|
|
9512
|
-
logger.error(`error: ${err.message}`);
|
|
9513
|
-
return 1;
|
|
9514
|
-
}
|
|
9515
|
-
const continueDir = overrideContinueDir ?? join16(homedir4(), ".continue");
|
|
9516
|
-
const markerPath = join16(continueDir, CONTINUE_HOOK_MARKER_FILENAME);
|
|
9517
|
-
try {
|
|
9518
|
-
mkdirSync10(continueDir, { recursive: true });
|
|
9519
|
-
} catch (err) {
|
|
9520
|
-
logger.error(`error: cannot create ${continueDir}: ${String(err)}`);
|
|
9521
|
-
return 1;
|
|
9522
|
-
}
|
|
9523
|
-
if (parsed.values.uninstall) {
|
|
9524
|
-
if (!isYakccInstalled5(markerPath)) {
|
|
9525
|
-
logger.log("yakcc continue hook not installed \u2014 nothing to uninstall.");
|
|
9526
|
-
return 0;
|
|
9527
|
-
}
|
|
9528
|
-
try {
|
|
9529
|
-
rmSync4(markerPath);
|
|
9530
|
-
} catch (err) {
|
|
9531
|
-
logger.error(`error: cannot remove ${markerPath}: ${String(err)}`);
|
|
9532
|
-
return 1;
|
|
9533
|
-
}
|
|
9534
|
-
logger.log(`yakcc continue hook marker removed: ${markerPath}`);
|
|
9535
|
-
return 0;
|
|
9536
|
-
}
|
|
9537
|
-
if (isYakccInstalled5(markerPath)) {
|
|
9538
|
-
logger.log(`yakcc continue hook already installed at ${markerPath} (idempotent).`);
|
|
9539
|
-
return 0;
|
|
9540
|
-
}
|
|
9541
|
-
const marker = {
|
|
9542
|
-
command: HOOK_COMMAND6,
|
|
9543
|
-
description: "yakcc tool-call interception hook for Continue.dev",
|
|
9544
|
-
sessionEnvVar: "CONTINUE_SESSION_ID",
|
|
9545
|
-
telemetryPrefix: "continue",
|
|
9546
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9547
|
-
_yakcc: YAKCC_CONTINUE_MARKER,
|
|
9548
|
-
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."
|
|
9549
|
-
};
|
|
9550
|
-
try {
|
|
9551
|
-
writeFileSync9(markerPath, `${JSON.stringify(marker, null, 2)}
|
|
9552
|
-
`, "utf-8");
|
|
9553
|
-
} catch (err) {
|
|
9554
|
-
logger.error(`error: cannot write marker ${markerPath}: ${String(err)}`);
|
|
9555
|
-
return 1;
|
|
9556
|
-
}
|
|
9557
|
-
logger.log(`yakcc continue hook marker installed: ${markerPath}`);
|
|
9558
|
-
logger.log(
|
|
9559
|
-
"note: Continue.dev tool-call interception API not yet stable \u2014 see marker for details."
|
|
9560
|
-
);
|
|
9561
|
-
return 0;
|
|
9562
|
-
}
|
|
9563
|
-
|
|
9564
9972
|
// src/commands/seed-yakcc.ts
|
|
9565
9973
|
init_dist2();
|
|
9566
|
-
import { existsSync as
|
|
9567
|
-
import { dirname as
|
|
9568
|
-
import { fileURLToPath as
|
|
9974
|
+
import { existsSync as existsSync12 } from "fs";
|
|
9975
|
+
import { dirname as dirname7, join as join21 } from "path";
|
|
9976
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9569
9977
|
function findBootstrapSqlite() {
|
|
9570
|
-
let dir =
|
|
9978
|
+
let dir = dirname7(fileURLToPath3(import.meta.url));
|
|
9571
9979
|
for (let i = 0; i < 30; i++) {
|
|
9572
|
-
const candidate =
|
|
9573
|
-
if (
|
|
9574
|
-
const parent =
|
|
9980
|
+
const candidate = join21(dir, "bootstrap", "yakcc.registry.sqlite");
|
|
9981
|
+
if (existsSync12(candidate)) return candidate;
|
|
9982
|
+
const parent = dirname7(dir);
|
|
9575
9983
|
if (parent === dir) break;
|
|
9576
9984
|
dir = parent;
|
|
9577
9985
|
}
|
|
@@ -9660,16 +10068,16 @@ var YAKCC_SUBDIRS = ["registry", "telemetry", "config"];
|
|
|
9660
10068
|
var DEFAULT_REGISTRY_SUBPATH = ".yakcc/registry.sqlite";
|
|
9661
10069
|
var RC_FILENAME = ".yakccrc.json";
|
|
9662
10070
|
function readRc(targetDir) {
|
|
9663
|
-
const rcPath =
|
|
9664
|
-
if (!
|
|
10071
|
+
const rcPath = join22(targetDir, RC_FILENAME);
|
|
10072
|
+
if (!existsSync13(rcPath)) return null;
|
|
9665
10073
|
try {
|
|
9666
|
-
return JSON.parse(
|
|
10074
|
+
return JSON.parse(readFileSync13(rcPath, "utf-8"));
|
|
9667
10075
|
} catch {
|
|
9668
10076
|
return null;
|
|
9669
10077
|
}
|
|
9670
10078
|
}
|
|
9671
10079
|
function writeRc(targetDir, rc) {
|
|
9672
|
-
writeFileSync10(
|
|
10080
|
+
writeFileSync10(join22(targetDir, RC_FILENAME), `${JSON.stringify(rc, null, 2)}
|
|
9673
10081
|
`, "utf-8");
|
|
9674
10082
|
}
|
|
9675
10083
|
function validatePeerUrl(url) {
|
|
@@ -9694,8 +10102,8 @@ function parseIdeList(raw) {
|
|
|
9694
10102
|
return { ok: parts };
|
|
9695
10103
|
}
|
|
9696
10104
|
async function installHookForIde(ide, targetDir, logger, overrideHome) {
|
|
9697
|
-
const { homedir:
|
|
9698
|
-
const home = overrideHome ??
|
|
10105
|
+
const { homedir: homedir7 } = await import("os");
|
|
10106
|
+
const home = overrideHome ?? homedir7();
|
|
9699
10107
|
switch (ide) {
|
|
9700
10108
|
case "claude-code": {
|
|
9701
10109
|
const code = await hooksClaudeCodeInstall(["--target", targetDir], logger);
|
|
@@ -9708,15 +10116,15 @@ async function installHookForIde(ide, targetDir, logger, overrideHome) {
|
|
|
9708
10116
|
break;
|
|
9709
10117
|
}
|
|
9710
10118
|
case "cline": {
|
|
9711
|
-
const { join:
|
|
9712
|
-
const clineDir =
|
|
10119
|
+
const { join: join24 } = await import("path");
|
|
10120
|
+
const clineDir = join24(home, ".config", "cline");
|
|
9713
10121
|
const code = await hooksClineInstall([], logger, clineDir);
|
|
9714
10122
|
if (code !== 0) throw new Error(`cline hook install failed (exit ${code})`);
|
|
9715
10123
|
break;
|
|
9716
10124
|
}
|
|
9717
10125
|
case "continue": {
|
|
9718
|
-
const { join:
|
|
9719
|
-
const continueDir =
|
|
10126
|
+
const { join: join24 } = await import("path");
|
|
10127
|
+
const continueDir = join24(home, ".continue");
|
|
9720
10128
|
const code = await hooksContinueInstall([], logger, continueDir);
|
|
9721
10129
|
if (code !== 0) throw new Error(`continue hook install failed (exit ${code})`);
|
|
9722
10130
|
break;
|
|
@@ -9727,8 +10135,8 @@ async function installHookForIde(ide, targetDir, logger, overrideHome) {
|
|
|
9727
10135
|
break;
|
|
9728
10136
|
}
|
|
9729
10137
|
case "aider": {
|
|
9730
|
-
const { join:
|
|
9731
|
-
const aiderDir =
|
|
10138
|
+
const { join: join24 } = await import("path");
|
|
10139
|
+
const aiderDir = join24(home, ".aider");
|
|
9732
10140
|
const code = await hooksAiderInstall([], logger, aiderDir);
|
|
9733
10141
|
if (code !== 0) throw new Error(`aider hook install failed (exit ${code})`);
|
|
9734
10142
|
break;
|
|
@@ -9790,12 +10198,12 @@ async function init(argv, logger, opts) {
|
|
|
9790
10198
|
}
|
|
9791
10199
|
explicitIdes = parseResult.ok;
|
|
9792
10200
|
}
|
|
9793
|
-
const yakccDir =
|
|
9794
|
-
const yakccDirExists =
|
|
10201
|
+
const yakccDir = join22(targetDir, YAKCC_DIR);
|
|
10202
|
+
const yakccDirExists = existsSync13(yakccDir);
|
|
9795
10203
|
try {
|
|
9796
|
-
|
|
10204
|
+
mkdirSync13(yakccDir, { recursive: true });
|
|
9797
10205
|
for (const sub of YAKCC_SUBDIRS) {
|
|
9798
|
-
|
|
10206
|
+
mkdirSync13(join22(yakccDir, sub), { recursive: true });
|
|
9799
10207
|
}
|
|
9800
10208
|
} catch (err) {
|
|
9801
10209
|
logger.error(`error: cannot create ${yakccDir}: ${String(err)}`);
|
|
@@ -9806,7 +10214,7 @@ async function init(argv, logger, opts) {
|
|
|
9806
10214
|
} else {
|
|
9807
10215
|
logger.log(" .yakcc/ created");
|
|
9808
10216
|
}
|
|
9809
|
-
const registryPath =
|
|
10217
|
+
const registryPath = join22(targetDir, DEFAULT_REGISTRY_SUBPATH);
|
|
9810
10218
|
const registryCode = await registryInit(["--path", registryPath], logger);
|
|
9811
10219
|
if (registryCode !== 0) {
|
|
9812
10220
|
return registryCode;
|
|
@@ -9891,7 +10299,7 @@ async function init(argv, logger, opts) {
|
|
|
9891
10299
|
try {
|
|
9892
10300
|
writeRc(targetDir, rc);
|
|
9893
10301
|
} catch (err) {
|
|
9894
|
-
logger.error(`error: cannot write ${
|
|
10302
|
+
logger.error(`error: cannot write ${join22(targetDir, RC_FILENAME)}: ${String(err)}`);
|
|
9895
10303
|
return 1;
|
|
9896
10304
|
}
|
|
9897
10305
|
logger.log(` ${RC_FILENAME} written`);
|
|
@@ -9910,7 +10318,7 @@ async function init(argv, logger, opts) {
|
|
|
9910
10318
|
// src/commands/propose.ts
|
|
9911
10319
|
init_dist();
|
|
9912
10320
|
init_dist2();
|
|
9913
|
-
import { readFileSync as
|
|
10321
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
9914
10322
|
import { parseArgs as parseArgs13 } from "util";
|
|
9915
10323
|
async function propose(argv, logger) {
|
|
9916
10324
|
const { values, positionals } = parseArgs13({
|
|
@@ -9937,7 +10345,7 @@ async function propose(argv, logger) {
|
|
|
9937
10345
|
const registryPath = values.registry ?? DEFAULT_REGISTRY_PATH3;
|
|
9938
10346
|
let specJson;
|
|
9939
10347
|
try {
|
|
9940
|
-
specJson =
|
|
10348
|
+
specJson = readFileSync14(specFilePath, "utf-8");
|
|
9941
10349
|
} catch (err) {
|
|
9942
10350
|
logger.error(`error: cannot read spec file ${specFilePath}: ${String(err)}`);
|
|
9943
10351
|
return 1;
|
|
@@ -9978,7 +10386,7 @@ async function propose(argv, logger) {
|
|
|
9978
10386
|
|
|
9979
10387
|
// src/commands/query.ts
|
|
9980
10388
|
init_dist2();
|
|
9981
|
-
import { readFileSync as
|
|
10389
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
9982
10390
|
import { parseArgs as parseArgs14 } from "util";
|
|
9983
10391
|
function truncate(s, max) {
|
|
9984
10392
|
return s.length <= max ? s : `${s.slice(0, max - 3)}...`;
|
|
@@ -10008,7 +10416,7 @@ async function query(argv, logger, opts) {
|
|
|
10008
10416
|
if (cardFilePath !== void 0) {
|
|
10009
10417
|
let cardJson;
|
|
10010
10418
|
try {
|
|
10011
|
-
cardJson =
|
|
10419
|
+
cardJson = readFileSync15(cardFilePath, "utf-8");
|
|
10012
10420
|
} catch (err) {
|
|
10013
10421
|
logger.error(`error: cannot read card file ${cardFilePath}: ${String(err)}`);
|
|
10014
10422
|
return 1;
|
|
@@ -10086,9 +10494,9 @@ async function query(argv, logger, opts) {
|
|
|
10086
10494
|
}
|
|
10087
10495
|
|
|
10088
10496
|
// src/commands/registry-export.ts
|
|
10089
|
-
import { existsSync as
|
|
10497
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync14 } from "fs";
|
|
10090
10498
|
import { createRequire as createRequire2 } from "module";
|
|
10091
|
-
import { dirname as
|
|
10499
|
+
import { dirname as dirname8, resolve as resolve4 } from "path";
|
|
10092
10500
|
import { parseArgs as parseArgs15 } from "util";
|
|
10093
10501
|
var _registryModuleUrl = new URL("../../../registry/src/index.ts", import.meta.url).href;
|
|
10094
10502
|
var _req = createRequire2(_registryModuleUrl);
|
|
@@ -10106,13 +10514,13 @@ async function registryExport(argv, logger) {
|
|
|
10106
10514
|
logger.error("error: --to <path> is required for 'registry export'");
|
|
10107
10515
|
return 1;
|
|
10108
10516
|
}
|
|
10109
|
-
const sourcePath =
|
|
10110
|
-
const outputPath =
|
|
10111
|
-
if (!
|
|
10517
|
+
const sourcePath = resolve4(values.from);
|
|
10518
|
+
const outputPath = resolve4(values.to);
|
|
10519
|
+
if (!existsSync14(sourcePath)) {
|
|
10112
10520
|
logger.error(`error: source registry not found at ${sourcePath}`);
|
|
10113
10521
|
return 1;
|
|
10114
10522
|
}
|
|
10115
|
-
|
|
10523
|
+
mkdirSync14(dirname8(outputPath), { recursive: true });
|
|
10116
10524
|
const escapedOutputPath = outputPath.replace(/'/g, "''");
|
|
10117
10525
|
let Database2;
|
|
10118
10526
|
try {
|
|
@@ -10153,8 +10561,8 @@ async function registryExport(argv, logger) {
|
|
|
10153
10561
|
|
|
10154
10562
|
// src/commands/registry-rebuild.ts
|
|
10155
10563
|
init_dist2();
|
|
10156
|
-
import { mkdirSync as
|
|
10157
|
-
import { dirname as
|
|
10564
|
+
import { mkdirSync as mkdirSync15 } from "fs";
|
|
10565
|
+
import { dirname as dirname9 } from "path";
|
|
10158
10566
|
import { parseArgs as parseArgs16 } from "util";
|
|
10159
10567
|
async function registryRebuild(argv, logger, opts) {
|
|
10160
10568
|
const { values } = parseArgs16({
|
|
@@ -10166,8 +10574,8 @@ async function registryRebuild(argv, logger, opts) {
|
|
|
10166
10574
|
strict: true
|
|
10167
10575
|
});
|
|
10168
10576
|
const registryPath = values.path ?? DEFAULT_REGISTRY_PATH3;
|
|
10169
|
-
const parent =
|
|
10170
|
-
|
|
10577
|
+
const parent = dirname9(registryPath);
|
|
10578
|
+
mkdirSync15(parent, { recursive: true });
|
|
10171
10579
|
let embeddingProvider = opts?.embeddings;
|
|
10172
10580
|
if (embeddingProvider === void 0) {
|
|
10173
10581
|
const { createLocalEmbeddingProvider: createLocalEmbeddingProvider2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
@@ -10207,7 +10615,7 @@ async function registryRebuild(argv, logger, opts) {
|
|
|
10207
10615
|
// src/commands/search.ts
|
|
10208
10616
|
init_dist();
|
|
10209
10617
|
init_dist2();
|
|
10210
|
-
import { readFileSync as
|
|
10618
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
10211
10619
|
import { parseArgs as parseArgs17 } from "util";
|
|
10212
10620
|
var FREE_TEXT_SPEC_DEFAULTS = {
|
|
10213
10621
|
inputs: [],
|
|
@@ -10259,7 +10667,7 @@ async function search(argv, logger, opts) {
|
|
|
10259
10667
|
if (looksLikePath) {
|
|
10260
10668
|
let specJson;
|
|
10261
10669
|
try {
|
|
10262
|
-
specJson =
|
|
10670
|
+
specJson = readFileSync16(query2, "utf-8");
|
|
10263
10671
|
} catch (err) {
|
|
10264
10672
|
logger.error(`error: cannot read spec file ${query2}: ${String(err)}`);
|
|
10265
10673
|
return 1;
|
|
@@ -10368,7 +10776,7 @@ async function seed(argv, logger, opts) {
|
|
|
10368
10776
|
|
|
10369
10777
|
// src/commands/shave.ts
|
|
10370
10778
|
init_dist2();
|
|
10371
|
-
import { resolve as
|
|
10779
|
+
import { resolve as resolve5 } from "path";
|
|
10372
10780
|
import { parseArgs as parseArgs19 } from "util";
|
|
10373
10781
|
var VALID_FOREIGN_POLICIES = ["allow", "reject", "tag"];
|
|
10374
10782
|
var SHAVE_PARSE_OPTIONS = {
|
|
@@ -10419,7 +10827,7 @@ async function shave2(argv, logger) {
|
|
|
10419
10827
|
const offline = parsed.values.offline === true;
|
|
10420
10828
|
let registry;
|
|
10421
10829
|
try {
|
|
10422
|
-
registry = await openRegistry(
|
|
10830
|
+
registry = await openRegistry(resolve5(registryPath));
|
|
10423
10831
|
} catch (err) {
|
|
10424
10832
|
logger.error(`error: failed to open registry at ${registryPath}: ${err.message}`);
|
|
10425
10833
|
return 1;
|
|
@@ -10433,7 +10841,7 @@ async function shave2(argv, logger) {
|
|
|
10433
10841
|
findByCanonicalAstHash: registry.findByCanonicalAstHash?.bind(registry)
|
|
10434
10842
|
};
|
|
10435
10843
|
try {
|
|
10436
|
-
const result = await shave(
|
|
10844
|
+
const result = await shave(resolve5(sourcePath), shaveRegistry, { offline, foreignPolicy });
|
|
10437
10845
|
logger.log(`Shaved ${result.sourcePath}:`);
|
|
10438
10846
|
logger.log(` atoms: ${result.atoms.length}`);
|
|
10439
10847
|
logger.log(` intentCards: ${result.intentCards.length}`);
|
|
@@ -10467,17 +10875,17 @@ async function shave2(argv, logger) {
|
|
|
10467
10875
|
}
|
|
10468
10876
|
|
|
10469
10877
|
// src/commands/uninstall.ts
|
|
10470
|
-
import { existsSync as
|
|
10471
|
-
import { homedir as
|
|
10472
|
-
import { join as
|
|
10878
|
+
import { existsSync as existsSync15, readFileSync as readFileSync17, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
|
|
10879
|
+
import { homedir as homedir6 } from "os";
|
|
10880
|
+
import { join as join23, resolve as resolve6 } from "path";
|
|
10473
10881
|
import { parseArgs as parseArgs20 } from "util";
|
|
10474
10882
|
var YAKCC_DIR2 = ".yakcc";
|
|
10475
10883
|
var RC_FILENAME2 = ".yakccrc.json";
|
|
10476
10884
|
function readRc2(targetDir) {
|
|
10477
|
-
const rcPath =
|
|
10478
|
-
if (!
|
|
10885
|
+
const rcPath = join23(targetDir, RC_FILENAME2);
|
|
10886
|
+
if (!existsSync15(rcPath)) return null;
|
|
10479
10887
|
try {
|
|
10480
|
-
return JSON.parse(
|
|
10888
|
+
return JSON.parse(readFileSync17(rcPath, "utf-8"));
|
|
10481
10889
|
} catch {
|
|
10482
10890
|
return null;
|
|
10483
10891
|
}
|
|
@@ -10493,20 +10901,20 @@ function parseIdeList2(raw) {
|
|
|
10493
10901
|
return { ok: parts };
|
|
10494
10902
|
}
|
|
10495
10903
|
async function uninstallHookForIde(ide, targetDir, logger, overrideHome) {
|
|
10496
|
-
const home = overrideHome ??
|
|
10904
|
+
const home = overrideHome ?? homedir6();
|
|
10497
10905
|
switch (ide) {
|
|
10498
10906
|
case "claude-code":
|
|
10499
10907
|
return hooksClaudeCodeInstall(["--target", targetDir, "--uninstall"], logger);
|
|
10500
10908
|
case "cursor":
|
|
10501
10909
|
return hooksCursorInstall(["--target", targetDir, "--uninstall"], logger);
|
|
10502
10910
|
case "cline":
|
|
10503
|
-
return hooksClineInstall(["--uninstall"], logger,
|
|
10911
|
+
return hooksClineInstall(["--uninstall"], logger, join23(home, ".config", "cline"));
|
|
10504
10912
|
case "continue":
|
|
10505
|
-
return hooksContinueInstall(["--uninstall"], logger,
|
|
10913
|
+
return hooksContinueInstall(["--uninstall"], logger, join23(home, ".continue"));
|
|
10506
10914
|
case "windsurf":
|
|
10507
10915
|
return hooksWindsurfInstall(["--target", targetDir, "--uninstall"], logger);
|
|
10508
10916
|
case "aider":
|
|
10509
|
-
return hooksAiderInstall(["--uninstall"], logger,
|
|
10917
|
+
return hooksAiderInstall(["--uninstall"], logger, join23(home, ".aider"));
|
|
10510
10918
|
}
|
|
10511
10919
|
}
|
|
10512
10920
|
async function uninstall(argv, logger, opts) {
|
|
@@ -10582,7 +10990,7 @@ async function uninstall(argv, logger, opts) {
|
|
|
10582
10990
|
const updated = { ...rc, installedHooks: updatedHooks };
|
|
10583
10991
|
try {
|
|
10584
10992
|
writeFileSync11(
|
|
10585
|
-
|
|
10993
|
+
join23(targetDir, RC_FILENAME2),
|
|
10586
10994
|
`${JSON.stringify(updated, null, 2)}
|
|
10587
10995
|
`,
|
|
10588
10996
|
"utf-8"
|
|
@@ -10594,22 +11002,22 @@ async function uninstall(argv, logger, opts) {
|
|
|
10594
11002
|
}
|
|
10595
11003
|
if (doPurge) {
|
|
10596
11004
|
try {
|
|
10597
|
-
rmSync5(
|
|
11005
|
+
rmSync5(join23(targetDir, YAKCC_DIR2), { recursive: true, force: true });
|
|
10598
11006
|
} catch (err) {
|
|
10599
11007
|
logger.error(`warning: cannot remove ${YAKCC_DIR2}: ${String(err)}`);
|
|
10600
11008
|
}
|
|
10601
11009
|
try {
|
|
10602
|
-
rmSync5(
|
|
11010
|
+
rmSync5(join23(targetDir, RC_FILENAME2), { force: true });
|
|
10603
11011
|
} catch (err) {
|
|
10604
11012
|
logger.error(`warning: cannot remove ${RC_FILENAME2}: ${String(err)}`);
|
|
10605
11013
|
}
|
|
10606
11014
|
}
|
|
10607
|
-
const absTargetDir =
|
|
11015
|
+
const absTargetDir = resolve6(targetDir);
|
|
10608
11016
|
const removedLine = removedIdes.length > 0 ? `Removed from: ${removedIdes.join(", ")}.` : "No hooks removed (nothing was installed).";
|
|
10609
11017
|
if (doPurge) {
|
|
10610
11018
|
logger.log(`${removedLine} Purged .yakcc/ and ${RC_FILENAME2} at ${absTargetDir}.`);
|
|
10611
11019
|
} else {
|
|
10612
|
-
logger.log(`${removedLine} Registry preserved at ${
|
|
11020
|
+
logger.log(`${removedLine} Registry preserved at ${join23(absTargetDir, YAKCC_DIR2)}.`);
|
|
10613
11021
|
}
|
|
10614
11022
|
return 0;
|
|
10615
11023
|
}
|
|
@@ -10677,6 +11085,13 @@ COMMANDS
|
|
|
10677
11085
|
hooks cursor install Wire yakcc tool-call interception for Cursor
|
|
10678
11086
|
[--target <dir>] Target project directory (default: .)
|
|
10679
11087
|
[--uninstall] Remove the yakcc cursor hook entry
|
|
11088
|
+
hooks cline install Wire yakcc tool-call interception for Cline
|
|
11089
|
+
[--target <dir>] Target project directory (default: .)
|
|
11090
|
+
[--uninstall] Remove the yakcc cline hook entry
|
|
11091
|
+
hooks continue install Wire yakcc tool-call interception for Continue.dev
|
|
11092
|
+
[--target <dir>] Target project directory (default: .)
|
|
11093
|
+
[--uninstall] Remove the yakcc continue hook entry
|
|
11094
|
+
hook-intercept (internal -- invoked by IDE hook configs via PreToolUse)
|
|
10680
11095
|
federation serve --registry <p> Start a read-only HTTP registry server
|
|
10681
11096
|
[--port <n>] [--host <h>]
|
|
10682
11097
|
federation mirror --remote <url> Mirror all blocks from a remote registry peer
|
|
@@ -10795,11 +11210,35 @@ async function runCli(argv, logger = CONSOLE_LOGGER, opts) {
|
|
|
10795
11210
|
);
|
|
10796
11211
|
return 1;
|
|
10797
11212
|
}
|
|
11213
|
+
if (subcommand === "cline") {
|
|
11214
|
+
const [hooksSub, ...hooksRest] = rest;
|
|
11215
|
+
if (hooksSub === "install") {
|
|
11216
|
+
return hooksClineInstall(hooksRest, logger);
|
|
11217
|
+
}
|
|
11218
|
+
logger.error(
|
|
11219
|
+
`error: unknown hooks cline subcommand: ${hooksSub ?? "(none)"}. Did you mean 'hooks cline install'?`
|
|
11220
|
+
);
|
|
11221
|
+
return 1;
|
|
11222
|
+
}
|
|
11223
|
+
if (subcommand === "continue") {
|
|
11224
|
+
const [hooksSub, ...hooksRest] = rest;
|
|
11225
|
+
if (hooksSub === "install") {
|
|
11226
|
+
return hooksContinueInstall(hooksRest, logger);
|
|
11227
|
+
}
|
|
11228
|
+
logger.error(
|
|
11229
|
+
`error: unknown hooks continue subcommand: ${hooksSub ?? "(none)"}. Did you mean 'hooks continue install'?`
|
|
11230
|
+
);
|
|
11231
|
+
return 1;
|
|
11232
|
+
}
|
|
10798
11233
|
logger.error(
|
|
10799
|
-
`error: unknown hooks subcommand: ${subcommand ?? "(none)"}. Did you mean 'hooks claude-code install', 'hooks cursor install', 'hooks windsurf install', or 'hooks
|
|
11234
|
+
`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'?`
|
|
10800
11235
|
);
|
|
10801
11236
|
return 1;
|
|
10802
11237
|
}
|
|
11238
|
+
case "hook-intercept": {
|
|
11239
|
+
const hookInterceptArgv = subcommand !== void 0 ? [subcommand, ...rest] : rest;
|
|
11240
|
+
return hookIntercept(hookInterceptArgv, logger);
|
|
11241
|
+
}
|
|
10803
11242
|
case void 0:
|
|
10804
11243
|
case "--help":
|
|
10805
11244
|
case "-h": {
|