@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/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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
3931
|
+
resolve7();
|
|
3917
3932
|
} else {
|
|
3918
3933
|
reject(err);
|
|
3919
3934
|
}
|
|
3920
3935
|
} else {
|
|
3921
|
-
|
|
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((
|
|
4036
|
+
await new Promise((resolve7) => {
|
|
4022
4037
|
const shutdown = () => {
|
|
4023
4038
|
handle.close().then(() => {
|
|
4024
|
-
registry.close().finally(
|
|
4025
|
-
}).catch(
|
|
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
|
|
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
|
|
4260
|
+
var hasHexBuiltin2 = /* @__PURE__ */ (() => (
|
|
4246
4261
|
// @ts-ignore
|
|
4247
4262
|
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
4248
4263
|
))();
|
|
4249
|
-
var
|
|
4250
|
-
function
|
|
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 (
|
|
4267
|
+
if (hasHexBuiltin2)
|
|
4253
4268
|
return bytes.toHex();
|
|
4254
4269
|
let hex = "";
|
|
4255
4270
|
for (let i = 0; i < bytes.length; i++) {
|
|
4256
|
-
hex +=
|
|
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((
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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:
|
|
6930
|
+
const { join: join25 } = await import("path");
|
|
6916
6931
|
const shard = cacheKey.slice(0, 3);
|
|
6917
|
-
const filePath =
|
|
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
|
-
//
|
|
8870
|
-
|
|
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
|
|
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 (!
|
|
9286
|
+
if (!existsSync5(markerPath)) return null;
|
|
8879
9287
|
try {
|
|
8880
|
-
return JSON.parse(
|
|
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 ??
|
|
8906
|
-
const markerPath =
|
|
9313
|
+
const aiderDir = overrideAiderDir ?? join14(homedir2(), ".aider");
|
|
9314
|
+
const markerPath = join14(aiderDir, AIDER_HOOK_MARKER_FILENAME);
|
|
8907
9315
|
try {
|
|
8908
|
-
|
|
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-
|
|
8955
|
-
import { existsSync as
|
|
8956
|
-
import {
|
|
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
|
|
9536
|
+
var HOOK_COMMAND4 = "yakcc hook-intercept";
|
|
8961
9537
|
function readCursorSettings(settingsPath) {
|
|
8962
|
-
if (!
|
|
9538
|
+
if (!existsSync8(settingsPath)) return {};
|
|
8963
9539
|
try {
|
|
8964
|
-
return JSON.parse(
|
|
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
|
-
|
|
9546
|
+
writeFileSync7(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
8971
9547
|
`, "utf-8");
|
|
8972
9548
|
}
|
|
8973
|
-
function
|
|
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 (
|
|
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:
|
|
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 (!
|
|
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 } =
|
|
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 =
|
|
9021
|
-
const settingsPath =
|
|
9022
|
-
const markerPath =
|
|
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
|
-
|
|
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
|
-
|
|
9628
|
+
writeFileSync7(
|
|
9053
9629
|
markerPath,
|
|
9054
9630
|
`${JSON.stringify(
|
|
9055
9631
|
{
|
|
9056
|
-
command:
|
|
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: ${
|
|
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
|
|
9086
|
-
import { join as
|
|
9087
|
-
import { parseArgs as
|
|
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
|
|
9666
|
+
var HOOK_COMMAND5 = "yakcc hook-intercept";
|
|
9091
9667
|
var YAKCC_MARKER = "yakcc-hook-v1";
|
|
9092
9668
|
function readSettings(settingsPath) {
|
|
9093
|
-
if (!
|
|
9669
|
+
if (!existsSync9(settingsPath)) return {};
|
|
9094
9670
|
try {
|
|
9095
|
-
return JSON.parse(
|
|
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
|
-
|
|
9677
|
+
writeFileSync8(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
9102
9678
|
`, "utf-8");
|
|
9103
9679
|
}
|
|
9104
9680
|
function buildYakccHookObject() {
|
|
9105
|
-
return { type: "command", command:
|
|
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 } =
|
|
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 =
|
|
9155
|
-
const settingsPath =
|
|
9156
|
-
const claudeMdPath =
|
|
9730
|
+
const claudeDir = join18(targetDir, ".claude");
|
|
9731
|
+
const settingsPath = join18(claudeDir, "settings.json");
|
|
9732
|
+
const claudeMdPath = join18(claudeDir, "CLAUDE.md");
|
|
9157
9733
|
try {
|
|
9158
|
-
|
|
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 (
|
|
9761
|
+
if (existsSync9(claudeMdPath)) {
|
|
9186
9762
|
try {
|
|
9187
|
-
|
|
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 ${
|
|
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
|
|
9203
|
-
import { join as
|
|
9204
|
-
import { parseArgs as
|
|
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
|
|
9783
|
+
var HOOK_COMMAND6 = "yakcc hook-intercept";
|
|
9208
9784
|
function readWindsurfSettings(settingsPath) {
|
|
9209
|
-
if (!
|
|
9785
|
+
if (!existsSync10(settingsPath)) return {};
|
|
9210
9786
|
try {
|
|
9211
|
-
return JSON.parse(
|
|
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
|
-
|
|
9793
|
+
writeFileSync9(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
9218
9794
|
`, "utf-8");
|
|
9219
9795
|
}
|
|
9220
|
-
function
|
|
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 (
|
|
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:
|
|
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 (!
|
|
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 } =
|
|
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 =
|
|
9268
|
-
const settingsPath =
|
|
9269
|
-
const markerPath =
|
|
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
|
-
|
|
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
|
-
|
|
9875
|
+
writeFileSync9(
|
|
9300
9876
|
markerPath,
|
|
9301
9877
|
`${JSON.stringify(
|
|
9302
9878
|
{
|
|
9303
|
-
command:
|
|
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: ${
|
|
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
|
|
9336
|
-
import { join as
|
|
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
|
|
9341
|
-
import { homedir as
|
|
9342
|
-
import { join as
|
|
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 [
|
|
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 [
|
|
9928
|
+
return [join20(appdata, "Cursor")];
|
|
9353
9929
|
}
|
|
9354
|
-
return [
|
|
9930
|
+
return [join20(home, "AppData", "Roaming", "Cursor")];
|
|
9355
9931
|
}
|
|
9356
|
-
return [
|
|
9932
|
+
return [join20(home, ".config", "Cursor")];
|
|
9357
9933
|
})();
|
|
9358
9934
|
const clineCandidates = [
|
|
9359
|
-
|
|
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
|
-
|
|
9938
|
+
join20(home, ".vscode", "extensions", "saoudrizwan.claude-dev")
|
|
9363
9939
|
];
|
|
9364
9940
|
const continueCandidates = [
|
|
9365
|
-
|
|
9366
|
-
|
|
9941
|
+
join20(home, ".continue"),
|
|
9942
|
+
join20(home, ".vscode", "extensions", "continue.continue")
|
|
9367
9943
|
];
|
|
9368
|
-
const windsurfCandidates = [
|
|
9369
|
-
const aiderCandidates = [
|
|
9944
|
+
const windsurfCandidates = [join20(home, ".windsurf")];
|
|
9945
|
+
const aiderCandidates = [join20(home, ".aider")];
|
|
9370
9946
|
return {
|
|
9371
|
-
"claude-code": [
|
|
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 ??
|
|
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 (
|
|
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
|
|
9573
|
-
import { dirname as
|
|
9574
|
-
import { fileURLToPath as
|
|
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 =
|
|
9984
|
+
let dir = dirname7(fileURLToPath3(import.meta.url));
|
|
9577
9985
|
for (let i = 0; i < 30; i++) {
|
|
9578
|
-
const candidate =
|
|
9579
|
-
if (
|
|
9580
|
-
const parent =
|
|
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 =
|
|
9670
|
-
if (!
|
|
10077
|
+
const rcPath = join22(targetDir, RC_FILENAME);
|
|
10078
|
+
if (!existsSync13(rcPath)) return null;
|
|
9671
10079
|
try {
|
|
9672
|
-
return JSON.parse(
|
|
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(
|
|
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:
|
|
9704
|
-
const home = overrideHome ??
|
|
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:
|
|
9718
|
-
const clineDir =
|
|
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:
|
|
9725
|
-
const continueDir =
|
|
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:
|
|
9737
|
-
const aiderDir =
|
|
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 =
|
|
9800
|
-
const yakccDirExists =
|
|
10207
|
+
const yakccDir = join22(targetDir, YAKCC_DIR);
|
|
10208
|
+
const yakccDirExists = existsSync13(yakccDir);
|
|
9801
10209
|
try {
|
|
9802
|
-
|
|
10210
|
+
mkdirSync13(yakccDir, { recursive: true });
|
|
9803
10211
|
for (const sub of YAKCC_SUBDIRS) {
|
|
9804
|
-
|
|
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 =
|
|
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 ${
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
10503
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync14 } from "fs";
|
|
10096
10504
|
import { createRequire as createRequire2 } from "module";
|
|
10097
|
-
import { dirname as
|
|
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 =
|
|
10116
|
-
const outputPath =
|
|
10117
|
-
if (!
|
|
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
|
-
|
|
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
|
|
10163
|
-
import { dirname as
|
|
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 =
|
|
10176
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
10477
|
-
import { homedir as
|
|
10478
|
-
import { join as
|
|
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 =
|
|
10484
|
-
if (!
|
|
10891
|
+
const rcPath = join23(targetDir, RC_FILENAME2);
|
|
10892
|
+
if (!existsSync15(rcPath)) return null;
|
|
10485
10893
|
try {
|
|
10486
|
-
return JSON.parse(
|
|
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 ??
|
|
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,
|
|
10917
|
+
return hooksClineInstall(["--uninstall"], logger, join23(home, ".config", "cline"));
|
|
10510
10918
|
case "continue":
|
|
10511
|
-
return hooksContinueInstall(["--uninstall"], logger,
|
|
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,
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 =
|
|
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 ${
|
|
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
|
|
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
|
|
10816
|
-
import { homedir as
|
|
10817
|
-
import { basename as basename2, join as
|
|
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 =
|
|
11261
|
+
const content = readFileSync18(snapshotPath);
|
|
10823
11262
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
10824
|
-
const cacheBase = process.env.PKG_NATIVE_CACHE_PATH ??
|
|
10825
|
-
const cacheDir =
|
|
10826
|
-
|
|
10827
|
-
const dest =
|
|
10828
|
-
if (
|
|
10829
|
-
const existing =
|
|
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(
|
|
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) {
|