qodewk 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -12
- package/dist/index.cjs +1758 -606
- package/package.json +3 -4
package/dist/index.cjs
CHANGED
|
@@ -1153,8 +1153,8 @@ var require_command = __commonJS({
|
|
|
1153
1153
|
"use strict";
|
|
1154
1154
|
var EventEmitter2 = require("events").EventEmitter;
|
|
1155
1155
|
var childProcess = require("child_process");
|
|
1156
|
-
var
|
|
1157
|
-
var
|
|
1156
|
+
var path11 = require("path");
|
|
1157
|
+
var fs11 = require("fs");
|
|
1158
1158
|
var process2 = require("process");
|
|
1159
1159
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
1160
1160
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -2135,7 +2135,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2135
2135
|
* @param {string} subcommandName
|
|
2136
2136
|
*/
|
|
2137
2137
|
_checkForMissingExecutable(executableFile, executableDir, subcommandName) {
|
|
2138
|
-
if (
|
|
2138
|
+
if (fs11.existsSync(executableFile)) return;
|
|
2139
2139
|
const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
|
|
2140
2140
|
const executableMissing = `'${executableFile}' does not exist
|
|
2141
2141
|
- if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
|
|
@@ -2153,11 +2153,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2153
2153
|
let launchWithNode = false;
|
|
2154
2154
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
2155
2155
|
function findFile(baseDir, baseName) {
|
|
2156
|
-
const localBin =
|
|
2157
|
-
if (
|
|
2158
|
-
if (sourceExt.includes(
|
|
2156
|
+
const localBin = path11.resolve(baseDir, baseName);
|
|
2157
|
+
if (fs11.existsSync(localBin)) return localBin;
|
|
2158
|
+
if (sourceExt.includes(path11.extname(baseName))) return void 0;
|
|
2159
2159
|
const foundExt = sourceExt.find(
|
|
2160
|
-
(ext) =>
|
|
2160
|
+
(ext) => fs11.existsSync(`${localBin}${ext}`)
|
|
2161
2161
|
);
|
|
2162
2162
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
2163
2163
|
return void 0;
|
|
@@ -2169,21 +2169,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2169
2169
|
if (this._scriptPath) {
|
|
2170
2170
|
let resolvedScriptPath;
|
|
2171
2171
|
try {
|
|
2172
|
-
resolvedScriptPath =
|
|
2172
|
+
resolvedScriptPath = fs11.realpathSync(this._scriptPath);
|
|
2173
2173
|
} catch {
|
|
2174
2174
|
resolvedScriptPath = this._scriptPath;
|
|
2175
2175
|
}
|
|
2176
|
-
executableDir =
|
|
2177
|
-
|
|
2176
|
+
executableDir = path11.resolve(
|
|
2177
|
+
path11.dirname(resolvedScriptPath),
|
|
2178
2178
|
executableDir
|
|
2179
2179
|
);
|
|
2180
2180
|
}
|
|
2181
2181
|
if (executableDir) {
|
|
2182
2182
|
let localFile = findFile(executableDir, executableFile);
|
|
2183
2183
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
2184
|
-
const legacyName =
|
|
2184
|
+
const legacyName = path11.basename(
|
|
2185
2185
|
this._scriptPath,
|
|
2186
|
-
|
|
2186
|
+
path11.extname(this._scriptPath)
|
|
2187
2187
|
);
|
|
2188
2188
|
if (legacyName !== this._name) {
|
|
2189
2189
|
localFile = findFile(
|
|
@@ -2194,7 +2194,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2194
2194
|
}
|
|
2195
2195
|
executableFile = localFile || executableFile;
|
|
2196
2196
|
}
|
|
2197
|
-
launchWithNode = sourceExt.includes(
|
|
2197
|
+
launchWithNode = sourceExt.includes(path11.extname(executableFile));
|
|
2198
2198
|
let proc;
|
|
2199
2199
|
if (process2.platform !== "win32") {
|
|
2200
2200
|
if (launchWithNode) {
|
|
@@ -3041,7 +3041,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3041
3041
|
* @return {Command}
|
|
3042
3042
|
*/
|
|
3043
3043
|
nameFromFilename(filename) {
|
|
3044
|
-
this._name =
|
|
3044
|
+
this._name = path11.basename(filename, path11.extname(filename));
|
|
3045
3045
|
return this;
|
|
3046
3046
|
}
|
|
3047
3047
|
/**
|
|
@@ -3055,9 +3055,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
3055
3055
|
* @param {string} [path]
|
|
3056
3056
|
* @return {(string|null|Command)}
|
|
3057
3057
|
*/
|
|
3058
|
-
executableDir(
|
|
3059
|
-
if (
|
|
3060
|
-
this._executableDir =
|
|
3058
|
+
executableDir(path12) {
|
|
3059
|
+
if (path12 === void 0) return this._executableDir;
|
|
3060
|
+
this._executableDir = path12;
|
|
3061
3061
|
return this;
|
|
3062
3062
|
}
|
|
3063
3063
|
/**
|
|
@@ -4067,10 +4067,10 @@ var require_src2 = __commonJS({
|
|
|
4067
4067
|
var fs_1 = require("fs");
|
|
4068
4068
|
var debug_1 = __importDefault(require_src());
|
|
4069
4069
|
var log = debug_1.default("@kwsites/file-exists");
|
|
4070
|
-
function check(
|
|
4071
|
-
log(`checking %s`,
|
|
4070
|
+
function check(path11, isFile, isDirectory) {
|
|
4071
|
+
log(`checking %s`, path11);
|
|
4072
4072
|
try {
|
|
4073
|
-
const stat = fs_1.statSync(
|
|
4073
|
+
const stat = fs_1.statSync(path11);
|
|
4074
4074
|
if (stat.isFile() && isFile) {
|
|
4075
4075
|
log(`[OK] path represents a file`);
|
|
4076
4076
|
return true;
|
|
@@ -4090,8 +4090,8 @@ var require_src2 = __commonJS({
|
|
|
4090
4090
|
throw e;
|
|
4091
4091
|
}
|
|
4092
4092
|
}
|
|
4093
|
-
function exists2(
|
|
4094
|
-
return check(
|
|
4093
|
+
function exists2(path11, type = exports2.READABLE) {
|
|
4094
|
+
return check(path11, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
|
|
4095
4095
|
}
|
|
4096
4096
|
exports2.exists = exists2;
|
|
4097
4097
|
exports2.FILE = 1;
|
|
@@ -4155,8 +4155,8 @@ var require_dist2 = __commonJS({
|
|
|
4155
4155
|
});
|
|
4156
4156
|
|
|
4157
4157
|
// src/index.ts
|
|
4158
|
-
var
|
|
4159
|
-
var
|
|
4158
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
4159
|
+
var path10 = __toESM(require("path"), 1);
|
|
4160
4160
|
|
|
4161
4161
|
// ../../node_modules/.pnpm/commander@13.1.0/node_modules/commander/esm.mjs
|
|
4162
4162
|
var import_index = __toESM(require_commander(), 1);
|
|
@@ -4176,204 +4176,7 @@ var {
|
|
|
4176
4176
|
} = import_index.default;
|
|
4177
4177
|
|
|
4178
4178
|
// src/index.ts
|
|
4179
|
-
var
|
|
4180
|
-
|
|
4181
|
-
// src/barcode.ts
|
|
4182
|
-
var CODE128_PATTERNS = [
|
|
4183
|
-
"11011001100",
|
|
4184
|
-
"11001101100",
|
|
4185
|
-
"11001100110",
|
|
4186
|
-
"10010011000",
|
|
4187
|
-
"10010001100",
|
|
4188
|
-
"10001001100",
|
|
4189
|
-
"10011001000",
|
|
4190
|
-
"10011000100",
|
|
4191
|
-
"10001100100",
|
|
4192
|
-
"11001001000",
|
|
4193
|
-
"11001000100",
|
|
4194
|
-
"11000100100",
|
|
4195
|
-
"10110011100",
|
|
4196
|
-
"10011011100",
|
|
4197
|
-
"10011001110",
|
|
4198
|
-
"10111001100",
|
|
4199
|
-
"10011101100",
|
|
4200
|
-
"10011100110",
|
|
4201
|
-
"11001110010",
|
|
4202
|
-
"11001011100",
|
|
4203
|
-
"11001001110",
|
|
4204
|
-
"11011100100",
|
|
4205
|
-
"11001110100",
|
|
4206
|
-
"11101101110",
|
|
4207
|
-
"11101001100",
|
|
4208
|
-
"11100101100",
|
|
4209
|
-
"11100100110",
|
|
4210
|
-
"11101100100",
|
|
4211
|
-
"11100110100",
|
|
4212
|
-
"11100110010",
|
|
4213
|
-
"11011011000",
|
|
4214
|
-
"11011000110",
|
|
4215
|
-
"11000110110",
|
|
4216
|
-
"10100011000",
|
|
4217
|
-
"10001011000",
|
|
4218
|
-
"10001000110",
|
|
4219
|
-
"10110001000",
|
|
4220
|
-
"10001101000",
|
|
4221
|
-
"10001100010",
|
|
4222
|
-
"11010001000",
|
|
4223
|
-
"11000101000",
|
|
4224
|
-
"11000100010",
|
|
4225
|
-
"10110111000",
|
|
4226
|
-
"10110001110",
|
|
4227
|
-
"10001101110",
|
|
4228
|
-
"10111011000",
|
|
4229
|
-
"10111000110",
|
|
4230
|
-
"10001110110",
|
|
4231
|
-
"11101110110",
|
|
4232
|
-
"11010001110",
|
|
4233
|
-
"11000101110",
|
|
4234
|
-
"11011101000",
|
|
4235
|
-
"11011100010",
|
|
4236
|
-
"11011101110",
|
|
4237
|
-
"11101011000",
|
|
4238
|
-
"11101000110",
|
|
4239
|
-
"11100010110",
|
|
4240
|
-
"11101101000",
|
|
4241
|
-
"11101100010",
|
|
4242
|
-
"11100011010",
|
|
4243
|
-
"11101111010",
|
|
4244
|
-
"11001000010",
|
|
4245
|
-
"11110001010",
|
|
4246
|
-
"10100110000",
|
|
4247
|
-
"10100001100",
|
|
4248
|
-
"10010110000",
|
|
4249
|
-
"10010000110",
|
|
4250
|
-
"10000101100",
|
|
4251
|
-
"10000100110",
|
|
4252
|
-
"10110010000",
|
|
4253
|
-
"10110000100",
|
|
4254
|
-
"10011010000",
|
|
4255
|
-
"10011000010",
|
|
4256
|
-
"10000110100",
|
|
4257
|
-
"10000110010",
|
|
4258
|
-
"11000010010",
|
|
4259
|
-
"11001010000",
|
|
4260
|
-
"11110111010",
|
|
4261
|
-
"11000010100",
|
|
4262
|
-
"10001111010",
|
|
4263
|
-
"10100111100",
|
|
4264
|
-
"10010111100",
|
|
4265
|
-
"10010011110",
|
|
4266
|
-
"10111100100",
|
|
4267
|
-
"10011110100",
|
|
4268
|
-
"10011110010",
|
|
4269
|
-
"11110100100",
|
|
4270
|
-
"11110010100",
|
|
4271
|
-
"11110010010",
|
|
4272
|
-
"11011011110",
|
|
4273
|
-
"11011110110",
|
|
4274
|
-
"11110110110",
|
|
4275
|
-
"10101111000",
|
|
4276
|
-
"10100011110",
|
|
4277
|
-
"10001011110",
|
|
4278
|
-
"10111101000",
|
|
4279
|
-
"10111100010",
|
|
4280
|
-
"11110101000",
|
|
4281
|
-
"11110100010",
|
|
4282
|
-
"10111011110",
|
|
4283
|
-
"10111101110",
|
|
4284
|
-
"11101011110",
|
|
4285
|
-
"11110101110",
|
|
4286
|
-
"11010000100",
|
|
4287
|
-
"11010010000",
|
|
4288
|
-
"11010011100",
|
|
4289
|
-
"1100011101011"
|
|
4290
|
-
];
|
|
4291
|
-
var START_B = 104;
|
|
4292
|
-
var STOP = 106;
|
|
4293
|
-
function encodeCode128B(text) {
|
|
4294
|
-
const codes = [START_B];
|
|
4295
|
-
for (const ch of text) {
|
|
4296
|
-
const code = ch.charCodeAt(0) - 32;
|
|
4297
|
-
if (code < 0 || code > 95) {
|
|
4298
|
-
throw new Error(`Code 128-B cannot encode character: ${JSON.stringify(ch)}`);
|
|
4299
|
-
}
|
|
4300
|
-
codes.push(code);
|
|
4301
|
-
}
|
|
4302
|
-
let checksum = START_B;
|
|
4303
|
-
for (let i2 = 1; i2 < codes.length; i2++) {
|
|
4304
|
-
checksum += codes[i2] * i2;
|
|
4305
|
-
}
|
|
4306
|
-
codes.push(checksum % 103);
|
|
4307
|
-
codes.push(STOP);
|
|
4308
|
-
return codes;
|
|
4309
|
-
}
|
|
4310
|
-
function code128Modules(text) {
|
|
4311
|
-
const codes = encodeCode128B(text);
|
|
4312
|
-
let modules = "";
|
|
4313
|
-
for (const code of codes) {
|
|
4314
|
-
modules += CODE128_PATTERNS[code] ?? "";
|
|
4315
|
-
}
|
|
4316
|
-
return modules;
|
|
4317
|
-
}
|
|
4318
|
-
function renderTerminalBarcode(text, options = {}) {
|
|
4319
|
-
const maxWidth = Math.max(16, options.maxWidth ?? 52);
|
|
4320
|
-
const height = Math.max(2, options.height ?? 3);
|
|
4321
|
-
const quietZone = Math.max(0, options.quietZone ?? 10);
|
|
4322
|
-
let payload = text;
|
|
4323
|
-
payload = [...payload].filter((ch) => {
|
|
4324
|
-
const c3 = ch.charCodeAt(0);
|
|
4325
|
-
return c3 >= 32 && c3 <= 126;
|
|
4326
|
-
}).join("");
|
|
4327
|
-
if (!payload) payload = "QODEWK";
|
|
4328
|
-
let modules;
|
|
4329
|
-
try {
|
|
4330
|
-
modules = code128Modules(payload);
|
|
4331
|
-
} catch {
|
|
4332
|
-
modules = code128Modules("QODEWK");
|
|
4333
|
-
}
|
|
4334
|
-
const withQuiet = "0".repeat(quietZone) + modules + "0".repeat(quietZone);
|
|
4335
|
-
const scaled = downsampleModules(withQuiet, maxWidth);
|
|
4336
|
-
const row = modulesToBlocks(scaled);
|
|
4337
|
-
return Array.from({ length: height }, () => row);
|
|
4338
|
-
}
|
|
4339
|
-
function downsampleModules(modules, maxWidth) {
|
|
4340
|
-
if (modules.length <= maxWidth) return modules;
|
|
4341
|
-
const out = [];
|
|
4342
|
-
const ratio = modules.length / maxWidth;
|
|
4343
|
-
for (let i2 = 0; i2 < maxWidth; i2++) {
|
|
4344
|
-
const start = Math.floor(i2 * ratio);
|
|
4345
|
-
const end = Math.max(start + 1, Math.floor((i2 + 1) * ratio));
|
|
4346
|
-
let bars = 0;
|
|
4347
|
-
for (let j2 = start; j2 < end && j2 < modules.length; j2++) {
|
|
4348
|
-
if (modules[j2] === "1") bars++;
|
|
4349
|
-
}
|
|
4350
|
-
out.push(bars * 2 >= end - start ? "1" : "0");
|
|
4351
|
-
}
|
|
4352
|
-
return out.join("");
|
|
4353
|
-
}
|
|
4354
|
-
function modulesToBlocks(modules) {
|
|
4355
|
-
let out = "";
|
|
4356
|
-
for (const bit of modules) {
|
|
4357
|
-
out += bit === "1" ? "\u2588" : " ";
|
|
4358
|
-
}
|
|
4359
|
-
return out;
|
|
4360
|
-
}
|
|
4361
|
-
function pickBarcodePayload(input) {
|
|
4362
|
-
const maxChars = input.maxChars ?? 24;
|
|
4363
|
-
const candidates = [];
|
|
4364
|
-
if (input.publicUrl) candidates.push(input.publicUrl);
|
|
4365
|
-
if (input.displayHost && input.receiptId) {
|
|
4366
|
-
candidates.push(`${input.displayHost}/r/${input.receiptId}`);
|
|
4367
|
-
}
|
|
4368
|
-
candidates.push(input.receiptId);
|
|
4369
|
-
if (input.receiptId.length > 12) {
|
|
4370
|
-
candidates.push(input.receiptId.replace(/^rec_/, "").slice(0, 12));
|
|
4371
|
-
}
|
|
4372
|
-
for (const c3 of candidates) {
|
|
4373
|
-
if (c3.length <= maxChars) return c3;
|
|
4374
|
-
}
|
|
4375
|
-
return candidates[candidates.length - 1].slice(0, maxChars);
|
|
4376
|
-
}
|
|
4179
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
4377
4180
|
|
|
4378
4181
|
// ../core/dist/index.js
|
|
4379
4182
|
var crypto2 = __toESM(require("crypto"), 1);
|
|
@@ -4856,8 +4659,8 @@ function getErrorMap() {
|
|
|
4856
4659
|
|
|
4857
4660
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
4858
4661
|
var makeIssue = (params) => {
|
|
4859
|
-
const { data, path:
|
|
4860
|
-
const fullPath = [...
|
|
4662
|
+
const { data, path: path11, errorMaps, issueData } = params;
|
|
4663
|
+
const fullPath = [...path11, ...issueData.path || []];
|
|
4861
4664
|
const fullIssue = {
|
|
4862
4665
|
...issueData,
|
|
4863
4666
|
path: fullPath
|
|
@@ -4973,11 +4776,11 @@ var errorUtil;
|
|
|
4973
4776
|
|
|
4974
4777
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
4975
4778
|
var ParseInputLazyPath = class {
|
|
4976
|
-
constructor(parent, value,
|
|
4779
|
+
constructor(parent, value, path11, key) {
|
|
4977
4780
|
this._cachedPath = [];
|
|
4978
4781
|
this.parent = parent;
|
|
4979
4782
|
this.data = value;
|
|
4980
|
-
this._path =
|
|
4783
|
+
this._path = path11;
|
|
4981
4784
|
this._key = key;
|
|
4982
4785
|
}
|
|
4983
4786
|
get path() {
|
|
@@ -9089,8 +8892,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
9089
8892
|
function forEachLineWithContent(input, callback) {
|
|
9090
8893
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
9091
8894
|
}
|
|
9092
|
-
function folderExists(
|
|
9093
|
-
return (0, import_file_exists.exists)(
|
|
8895
|
+
function folderExists(path11) {
|
|
8896
|
+
return (0, import_file_exists.exists)(path11, import_file_exists.FOLDER);
|
|
9094
8897
|
}
|
|
9095
8898
|
function append(target, item) {
|
|
9096
8899
|
if (Array.isArray(target)) {
|
|
@@ -9492,8 +9295,8 @@ function checkIsRepoRootTask() {
|
|
|
9492
9295
|
commands,
|
|
9493
9296
|
format: "utf-8",
|
|
9494
9297
|
onError,
|
|
9495
|
-
parser(
|
|
9496
|
-
return /^\.(git)?$/.test(
|
|
9298
|
+
parser(path11) {
|
|
9299
|
+
return /^\.(git)?$/.test(path11.trim());
|
|
9497
9300
|
}
|
|
9498
9301
|
};
|
|
9499
9302
|
}
|
|
@@ -9927,11 +9730,11 @@ function parseGrep(grep) {
|
|
|
9927
9730
|
const paths = /* @__PURE__ */ new Set();
|
|
9928
9731
|
const results = {};
|
|
9929
9732
|
forEachLineWithContent(grep, (input) => {
|
|
9930
|
-
const [
|
|
9931
|
-
paths.add(
|
|
9932
|
-
(results[
|
|
9733
|
+
const [path11, line, preview] = input.split(NULL);
|
|
9734
|
+
paths.add(path11);
|
|
9735
|
+
(results[path11] = results[path11] || []).push({
|
|
9933
9736
|
line: asNumber(line),
|
|
9934
|
-
path:
|
|
9737
|
+
path: path11,
|
|
9935
9738
|
preview
|
|
9936
9739
|
});
|
|
9937
9740
|
});
|
|
@@ -10695,14 +10498,14 @@ var init_hash_object = __esm({
|
|
|
10695
10498
|
init_task();
|
|
10696
10499
|
}
|
|
10697
10500
|
});
|
|
10698
|
-
function parseInit(bare,
|
|
10501
|
+
function parseInit(bare, path11, text) {
|
|
10699
10502
|
const response = String(text).trim();
|
|
10700
10503
|
let result;
|
|
10701
10504
|
if (result = initResponseRegex.exec(response)) {
|
|
10702
|
-
return new InitSummary(bare,
|
|
10505
|
+
return new InitSummary(bare, path11, false, result[1]);
|
|
10703
10506
|
}
|
|
10704
10507
|
if (result = reInitResponseRegex.exec(response)) {
|
|
10705
|
-
return new InitSummary(bare,
|
|
10508
|
+
return new InitSummary(bare, path11, true, result[1]);
|
|
10706
10509
|
}
|
|
10707
10510
|
let gitDir = "";
|
|
10708
10511
|
const tokens = response.split(" ");
|
|
@@ -10713,7 +10516,7 @@ function parseInit(bare, path8, text) {
|
|
|
10713
10516
|
break;
|
|
10714
10517
|
}
|
|
10715
10518
|
}
|
|
10716
|
-
return new InitSummary(bare,
|
|
10519
|
+
return new InitSummary(bare, path11, /^re/i.test(response), gitDir);
|
|
10717
10520
|
}
|
|
10718
10521
|
var InitSummary;
|
|
10719
10522
|
var initResponseRegex;
|
|
@@ -10722,9 +10525,9 @@ var init_InitSummary = __esm({
|
|
|
10722
10525
|
"src/lib/responses/InitSummary.ts"() {
|
|
10723
10526
|
"use strict";
|
|
10724
10527
|
InitSummary = class {
|
|
10725
|
-
constructor(bare,
|
|
10528
|
+
constructor(bare, path11, existing, gitDir) {
|
|
10726
10529
|
this.bare = bare;
|
|
10727
|
-
this.path =
|
|
10530
|
+
this.path = path11;
|
|
10728
10531
|
this.existing = existing;
|
|
10729
10532
|
this.gitDir = gitDir;
|
|
10730
10533
|
}
|
|
@@ -10736,7 +10539,7 @@ var init_InitSummary = __esm({
|
|
|
10736
10539
|
function hasBareCommand(command) {
|
|
10737
10540
|
return command.includes(bareCommand);
|
|
10738
10541
|
}
|
|
10739
|
-
function initTask(bare = false,
|
|
10542
|
+
function initTask(bare = false, path11, customArgs) {
|
|
10740
10543
|
const commands = ["init", ...customArgs];
|
|
10741
10544
|
if (bare && !hasBareCommand(commands)) {
|
|
10742
10545
|
commands.splice(1, 0, bareCommand);
|
|
@@ -10745,7 +10548,7 @@ function initTask(bare = false, path8, customArgs) {
|
|
|
10745
10548
|
commands,
|
|
10746
10549
|
format: "utf-8",
|
|
10747
10550
|
parser(text) {
|
|
10748
|
-
return parseInit(commands.includes("--bare"),
|
|
10551
|
+
return parseInit(commands.includes("--bare"), path11, text);
|
|
10749
10552
|
}
|
|
10750
10553
|
};
|
|
10751
10554
|
}
|
|
@@ -11560,12 +11363,12 @@ var init_FileStatusSummary = __esm({
|
|
|
11560
11363
|
"use strict";
|
|
11561
11364
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
11562
11365
|
FileStatusSummary = class {
|
|
11563
|
-
constructor(
|
|
11564
|
-
this.path =
|
|
11366
|
+
constructor(path11, index, working_dir) {
|
|
11367
|
+
this.path = path11;
|
|
11565
11368
|
this.index = index;
|
|
11566
11369
|
this.working_dir = working_dir;
|
|
11567
11370
|
if (index === "R" || working_dir === "R") {
|
|
11568
|
-
const detail = fromPathRegex.exec(
|
|
11371
|
+
const detail = fromPathRegex.exec(path11) || [null, path11, path11];
|
|
11569
11372
|
this.from = detail[2] || "";
|
|
11570
11373
|
this.path = detail[1] || "";
|
|
11571
11374
|
}
|
|
@@ -11596,14 +11399,14 @@ function splitLine(result, lineStr) {
|
|
|
11596
11399
|
default:
|
|
11597
11400
|
return;
|
|
11598
11401
|
}
|
|
11599
|
-
function data(index, workingDir,
|
|
11402
|
+
function data(index, workingDir, path11) {
|
|
11600
11403
|
const raw = `${index}${workingDir}`;
|
|
11601
11404
|
const handler = parsers6.get(raw);
|
|
11602
11405
|
if (handler) {
|
|
11603
|
-
handler(result,
|
|
11406
|
+
handler(result, path11);
|
|
11604
11407
|
}
|
|
11605
11408
|
if (raw !== "##" && raw !== "!!") {
|
|
11606
|
-
result.files.push(new FileStatusSummary(
|
|
11409
|
+
result.files.push(new FileStatusSummary(path11, index, workingDir));
|
|
11607
11410
|
}
|
|
11608
11411
|
}
|
|
11609
11412
|
}
|
|
@@ -11954,9 +11757,9 @@ var init_simple_git_api = __esm({
|
|
|
11954
11757
|
next
|
|
11955
11758
|
);
|
|
11956
11759
|
}
|
|
11957
|
-
hashObject(
|
|
11760
|
+
hashObject(path11, write) {
|
|
11958
11761
|
return this._runTask(
|
|
11959
|
-
hashObjectTask(
|
|
11762
|
+
hashObjectTask(path11, write === true),
|
|
11960
11763
|
trailingFunctionArgument(arguments)
|
|
11961
11764
|
);
|
|
11962
11765
|
}
|
|
@@ -12310,8 +12113,8 @@ var init_branch = __esm({
|
|
|
12310
12113
|
}
|
|
12311
12114
|
});
|
|
12312
12115
|
function toPath(input) {
|
|
12313
|
-
const
|
|
12314
|
-
return
|
|
12116
|
+
const path11 = input.trim().replace(/^["']|["']$/g, "");
|
|
12117
|
+
return path11 && (0, import_node_path.normalize)(path11);
|
|
12315
12118
|
}
|
|
12316
12119
|
var parseCheckIgnore;
|
|
12317
12120
|
var init_CheckIgnore = __esm({
|
|
@@ -12596,8 +12399,8 @@ __export2(sub_module_exports, {
|
|
|
12596
12399
|
subModuleTask: () => subModuleTask,
|
|
12597
12400
|
updateSubModuleTask: () => updateSubModuleTask
|
|
12598
12401
|
});
|
|
12599
|
-
function addSubModuleTask(repo,
|
|
12600
|
-
return subModuleTask(["add", repo,
|
|
12402
|
+
function addSubModuleTask(repo, path11) {
|
|
12403
|
+
return subModuleTask(["add", repo, path11]);
|
|
12601
12404
|
}
|
|
12602
12405
|
function initSubModuleTask(customArgs) {
|
|
12603
12406
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -12911,8 +12714,8 @@ var require_git = __commonJS2({
|
|
|
12911
12714
|
}
|
|
12912
12715
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
12913
12716
|
};
|
|
12914
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
12915
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
12717
|
+
Git2.prototype.submoduleAdd = function(repo, path11, then) {
|
|
12718
|
+
return this._runTask(addSubModuleTask2(repo, path11), trailingFunctionArgument2(arguments));
|
|
12916
12719
|
};
|
|
12917
12720
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
12918
12721
|
return this._runTask(
|
|
@@ -13493,6 +13296,58 @@ function parseSinceOption(since) {
|
|
|
13493
13296
|
}
|
|
13494
13297
|
return void 0;
|
|
13495
13298
|
}
|
|
13299
|
+
async function resolveGitSha(git, ref) {
|
|
13300
|
+
const trimmed2 = ref.trim();
|
|
13301
|
+
if (!trimmed2) {
|
|
13302
|
+
throw new Error("Git reference cannot be empty.");
|
|
13303
|
+
}
|
|
13304
|
+
try {
|
|
13305
|
+
const full = (await git.raw(["rev-parse", "--verify", trimmed2])).trim();
|
|
13306
|
+
if (/^[0-9a-f]{40}$/i.test(full)) {
|
|
13307
|
+
return full.toLowerCase();
|
|
13308
|
+
}
|
|
13309
|
+
} catch {
|
|
13310
|
+
}
|
|
13311
|
+
try {
|
|
13312
|
+
const full = (await git.raw(["rev-parse", trimmed2])).trim();
|
|
13313
|
+
if (/^[0-9a-f]{40}$/i.test(full)) {
|
|
13314
|
+
return full.toLowerCase();
|
|
13315
|
+
}
|
|
13316
|
+
} catch {
|
|
13317
|
+
}
|
|
13318
|
+
try {
|
|
13319
|
+
const fullOrigin = (await git.raw(["rev-parse", `origin/${trimmed2}`])).trim();
|
|
13320
|
+
if (/^[0-9a-f]{40}$/i.test(fullOrigin)) {
|
|
13321
|
+
return fullOrigin.toLowerCase();
|
|
13322
|
+
}
|
|
13323
|
+
} catch {
|
|
13324
|
+
}
|
|
13325
|
+
try {
|
|
13326
|
+
const fullRef = (await git.raw(["rev-parse", `refs/heads/${trimmed2}`])).trim();
|
|
13327
|
+
if (/^[0-9a-f]{40}$/i.test(fullRef)) {
|
|
13328
|
+
return fullRef.toLowerCase();
|
|
13329
|
+
}
|
|
13330
|
+
} catch {
|
|
13331
|
+
}
|
|
13332
|
+
if (/^[0-9a-f]{40}$/i.test(trimmed2)) {
|
|
13333
|
+
return trimmed2.toLowerCase();
|
|
13334
|
+
}
|
|
13335
|
+
throw new Error(`Unable to resolve git reference '${ref}' to a valid commit SHA.`);
|
|
13336
|
+
}
|
|
13337
|
+
async function detectDefaultBaseBranch(repoPathOrGit = process.cwd()) {
|
|
13338
|
+
const git = typeof repoPathOrGit === "string" ? simpleGit(repoPathOrGit) : repoPathOrGit;
|
|
13339
|
+
const candidates = ["origin/main", "main", "origin/master", "master"];
|
|
13340
|
+
for (const c3 of candidates) {
|
|
13341
|
+
try {
|
|
13342
|
+
const sha = (await git.raw(["rev-parse", "--verify", c3])).trim();
|
|
13343
|
+
if (/^[0-9a-f]{40}$/i.test(sha)) {
|
|
13344
|
+
return c3;
|
|
13345
|
+
}
|
|
13346
|
+
} catch {
|
|
13347
|
+
}
|
|
13348
|
+
}
|
|
13349
|
+
return "main";
|
|
13350
|
+
}
|
|
13496
13351
|
async function extractGitMetrics(optionsOrPath = process.cwd()) {
|
|
13497
13352
|
const options = typeof optionsOrPath === "string" ? { repoPath: optionsOrPath } : optionsOrPath;
|
|
13498
13353
|
const repoPath = options.repoPath || process.cwd();
|
|
@@ -13503,8 +13358,20 @@ async function extractGitMetrics(optionsOrPath = process.cwd()) {
|
|
|
13503
13358
|
}
|
|
13504
13359
|
const branchSummary = await git.branch();
|
|
13505
13360
|
const branch = branchSummary.current || "HEAD";
|
|
13506
|
-
let headSha
|
|
13507
|
-
|
|
13361
|
+
let headSha;
|
|
13362
|
+
if (options.headSha) {
|
|
13363
|
+
headSha = await resolveGitSha(git, options.headSha);
|
|
13364
|
+
} else {
|
|
13365
|
+
try {
|
|
13366
|
+
headSha = (await git.raw(["rev-parse", "HEAD"])).trim().toLowerCase();
|
|
13367
|
+
} catch {
|
|
13368
|
+
headSha = "0000000000000000000000000000000000000000";
|
|
13369
|
+
}
|
|
13370
|
+
}
|
|
13371
|
+
let baseSha = void 0;
|
|
13372
|
+
if (options.baseSha) {
|
|
13373
|
+
baseSha = await resolveGitSha(git, options.baseSha);
|
|
13374
|
+
}
|
|
13508
13375
|
let commitMessage = void 0;
|
|
13509
13376
|
let commitDate = void 0;
|
|
13510
13377
|
let commitsCount = 1;
|
|
@@ -13546,6 +13413,27 @@ async function extractGitMetrics(optionsOrPath = process.cwd()) {
|
|
|
13546
13413
|
} catch {
|
|
13547
13414
|
}
|
|
13548
13415
|
}
|
|
13416
|
+
if (!commitMessage && headSha && headSha !== "0000000000000000000000000000000000000000") {
|
|
13417
|
+
try {
|
|
13418
|
+
const headLog = await git.show(["-s", "--format=%B%x00%aI", headSha]);
|
|
13419
|
+
const parts = headLog.split("\0");
|
|
13420
|
+
if (parts[0])
|
|
13421
|
+
commitMessage = parts[0].trim();
|
|
13422
|
+
if (parts[1])
|
|
13423
|
+
commitDate = parts[1].trim();
|
|
13424
|
+
} catch {
|
|
13425
|
+
}
|
|
13426
|
+
}
|
|
13427
|
+
if (baseSha && headSha && baseSha !== headSha) {
|
|
13428
|
+
try {
|
|
13429
|
+
const countRaw = await git.raw(["rev-list", "--count", `${baseSha}..${headSha}`]);
|
|
13430
|
+
const count = parseInt(countRaw.trim(), 10);
|
|
13431
|
+
if (!isNaN(count) && count > 0) {
|
|
13432
|
+
commitsCount = count;
|
|
13433
|
+
}
|
|
13434
|
+
} catch {
|
|
13435
|
+
}
|
|
13436
|
+
}
|
|
13549
13437
|
let repoIdentifier = path.basename(path.resolve(repoPath));
|
|
13550
13438
|
try {
|
|
13551
13439
|
const remotes = await git.getRemotes(true);
|
|
@@ -13681,63 +13569,62 @@ function mapExtensionToLanguage(ext) {
|
|
|
13681
13569
|
};
|
|
13682
13570
|
return map[ext] || (ext ? ext.toUpperCase() : null);
|
|
13683
13571
|
}
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
if (msg.includes("claude") || msg.includes("anthropic")) {
|
|
13694
|
-
return {
|
|
13695
|
-
provider: "anthropic",
|
|
13696
|
-
model: "claude-3-7-sonnet",
|
|
13697
|
-
confidence: 0.85,
|
|
13698
|
-
mode: "observed"
|
|
13699
|
-
};
|
|
13700
|
-
}
|
|
13701
|
-
if (msg.includes("antigravity")) {
|
|
13702
|
-
return {
|
|
13703
|
-
provider: "antigravity",
|
|
13704
|
-
model: "claude-sonnet-4-6-thinking",
|
|
13705
|
-
confidence: 0.85,
|
|
13706
|
-
mode: "observed"
|
|
13707
|
-
};
|
|
13708
|
-
}
|
|
13709
|
-
if (msg.includes("gemini")) {
|
|
13710
|
-
return {
|
|
13711
|
-
provider: "google",
|
|
13712
|
-
model: "gemini-3-8-flash",
|
|
13713
|
-
confidence: 0.85,
|
|
13714
|
-
mode: "observed"
|
|
13715
|
-
};
|
|
13572
|
+
var QODEWK_GIT_NOTES_REF = "refs/notes/qodewk";
|
|
13573
|
+
async function writeGitReceiptNote(commitSha, receipt, options = {}) {
|
|
13574
|
+
const repoPath = options.repoPath || process.cwd();
|
|
13575
|
+
const git = simpleGit(repoPath);
|
|
13576
|
+
const cleanSha = commitSha.trim();
|
|
13577
|
+
const notePayload = JSON.stringify(receipt, null, 2);
|
|
13578
|
+
const args = ["notes", `--ref=${QODEWK_GIT_NOTES_REF}`, "add"];
|
|
13579
|
+
if (options.force !== false) {
|
|
13580
|
+
args.push("-f");
|
|
13716
13581
|
}
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13582
|
+
args.push("-m", notePayload, cleanSha);
|
|
13583
|
+
await git.raw(args);
|
|
13584
|
+
}
|
|
13585
|
+
async function readGitReceiptNote(commitSha, options = {}) {
|
|
13586
|
+
const repoPath = options.repoPath || process.cwd();
|
|
13587
|
+
const git = simpleGit(repoPath);
|
|
13588
|
+
const cleanSha = commitSha.trim();
|
|
13589
|
+
try {
|
|
13590
|
+
const rawNote = await git.raw(["notes", `--ref=${QODEWK_GIT_NOTES_REF}`, "show", cleanSha]);
|
|
13591
|
+
if (!rawNote || !rawNote.trim())
|
|
13592
|
+
return null;
|
|
13593
|
+
const parsed = JSON.parse(rawNote.trim());
|
|
13594
|
+
const valid = ReceiptV1Schema.safeParse(parsed);
|
|
13595
|
+
if (valid.success) {
|
|
13596
|
+
return valid.data;
|
|
13597
|
+
}
|
|
13598
|
+
return null;
|
|
13599
|
+
} catch {
|
|
13600
|
+
return null;
|
|
13724
13601
|
}
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13602
|
+
}
|
|
13603
|
+
async function listGitReceiptNotes(options = {}) {
|
|
13604
|
+
const repoPath = options.repoPath || process.cwd();
|
|
13605
|
+
const git = simpleGit(repoPath);
|
|
13606
|
+
try {
|
|
13607
|
+
const output = await git.raw(["notes", `--ref=${QODEWK_GIT_NOTES_REF}`, "list"]);
|
|
13608
|
+
if (!output || !output.trim())
|
|
13609
|
+
return [];
|
|
13610
|
+
const lines = output.trim().split("\n");
|
|
13611
|
+
const commitShas = [];
|
|
13612
|
+
for (const line of lines) {
|
|
13613
|
+
const parts = line.trim().split(/\s+/);
|
|
13614
|
+
if (parts.length >= 2 && parts[1]) {
|
|
13615
|
+
commitShas.push(parts[1]);
|
|
13616
|
+
}
|
|
13617
|
+
}
|
|
13618
|
+
return commitShas;
|
|
13619
|
+
} catch {
|
|
13620
|
+
return [];
|
|
13732
13621
|
}
|
|
13733
|
-
return null;
|
|
13734
13622
|
}
|
|
13735
13623
|
|
|
13736
|
-
// ../core/dist/
|
|
13737
|
-
var
|
|
13738
|
-
var
|
|
13739
|
-
var
|
|
13740
|
-
var import_node_module = require("module");
|
|
13624
|
+
// ../core/dist/discovery.js
|
|
13625
|
+
var fs = __toESM(require("fs"), 1);
|
|
13626
|
+
var path2 = __toESM(require("path"), 1);
|
|
13627
|
+
var os = __toESM(require("os"), 1);
|
|
13741
13628
|
|
|
13742
13629
|
// ../pricing/dist/index.js
|
|
13743
13630
|
var RATE_CARDS = {
|
|
@@ -13772,6 +13659,16 @@ var RATE_CARDS = {
|
|
|
13772
13659
|
cacheWritePerMTok: 3.75,
|
|
13773
13660
|
contextWindow: 2e5
|
|
13774
13661
|
},
|
|
13662
|
+
"claude-sonnet-4": {
|
|
13663
|
+
id: "claude-sonnet-4",
|
|
13664
|
+
provider: "anthropic",
|
|
13665
|
+
name: "Claude Sonnet 4",
|
|
13666
|
+
inputPerMTok: 3,
|
|
13667
|
+
outputPerMTok: 15,
|
|
13668
|
+
cacheReadPerMTok: 0.3,
|
|
13669
|
+
cacheWritePerMTok: 3.75,
|
|
13670
|
+
contextWindow: 2e5
|
|
13671
|
+
},
|
|
13775
13672
|
"claude-3-7-sonnet": {
|
|
13776
13673
|
id: "claude-3-7-sonnet",
|
|
13777
13674
|
provider: "anthropic",
|
|
@@ -13813,6 +13710,26 @@ var RATE_CARDS = {
|
|
|
13813
13710
|
cacheWritePerMTok: 2.5,
|
|
13814
13711
|
contextWindow: 128e3
|
|
13815
13712
|
},
|
|
13713
|
+
"gpt-4o-mini": {
|
|
13714
|
+
id: "gpt-4o-mini",
|
|
13715
|
+
provider: "openai",
|
|
13716
|
+
name: "GPT-4o Mini",
|
|
13717
|
+
inputPerMTok: 0.15,
|
|
13718
|
+
outputPerMTok: 0.6,
|
|
13719
|
+
cacheReadPerMTok: 0.075,
|
|
13720
|
+
cacheWritePerMTok: 0.15,
|
|
13721
|
+
contextWindow: 128e3
|
|
13722
|
+
},
|
|
13723
|
+
"o1": {
|
|
13724
|
+
id: "o1",
|
|
13725
|
+
provider: "openai",
|
|
13726
|
+
name: "o1",
|
|
13727
|
+
inputPerMTok: 15,
|
|
13728
|
+
outputPerMTok: 60,
|
|
13729
|
+
cacheReadPerMTok: 7.5,
|
|
13730
|
+
cacheWritePerMTok: 15,
|
|
13731
|
+
contextWindow: 2e5
|
|
13732
|
+
},
|
|
13816
13733
|
"o3-mini": {
|
|
13817
13734
|
id: "o3-mini",
|
|
13818
13735
|
provider: "openai",
|
|
@@ -13897,40 +13814,244 @@ var RATE_CARDS = {
|
|
|
13897
13814
|
contextWindow: 128e3
|
|
13898
13815
|
}
|
|
13899
13816
|
};
|
|
13817
|
+
var MODEL_ALIASES = {
|
|
13818
|
+
// Anthropic aliases
|
|
13819
|
+
"claude-3-7-sonnet-latest": "claude-3-7-sonnet",
|
|
13820
|
+
"claude-3-7-sonnet-20250219": "claude-3-7-sonnet",
|
|
13821
|
+
"claude-3-5-sonnet-latest": "claude-3-5-sonnet",
|
|
13822
|
+
"claude-3-5-sonnet-20241022": "claude-3-5-sonnet",
|
|
13823
|
+
"claude-3-5-sonnet-20240620": "claude-3-5-sonnet",
|
|
13824
|
+
"claude-3-5-haiku-latest": "claude-3-5-haiku",
|
|
13825
|
+
"claude-3-5-haiku-20241022": "claude-3-5-haiku",
|
|
13826
|
+
"claude-3-opus-20240229": "claude-opus-4",
|
|
13827
|
+
"claude-code": "claude-3-7-sonnet",
|
|
13828
|
+
"cursor-fast": "claude-3-5-sonnet",
|
|
13829
|
+
"cursor-small": "claude-3-5-haiku",
|
|
13830
|
+
// OpenAI aliases
|
|
13831
|
+
"chatgpt-4o-latest": "gpt-4o",
|
|
13832
|
+
"gpt-4o-2024-08-06": "gpt-4o",
|
|
13833
|
+
"gpt-4o-2024-11-20": "gpt-4o",
|
|
13834
|
+
"gpt-4o-mini-2024-07-18": "gpt-4o-mini",
|
|
13835
|
+
"o1-preview": "o1",
|
|
13836
|
+
"o1-2024-12-17": "o1",
|
|
13837
|
+
"o3": "o3-mini",
|
|
13838
|
+
// Google aliases
|
|
13839
|
+
"gemini-3": "gemini-3-8-flash",
|
|
13840
|
+
"gemini-flash": "gemini-3-8-flash",
|
|
13841
|
+
"gemini-pro": "gemini-2-5-pro",
|
|
13842
|
+
"gemini-2.0-flash": "gemini-2-0-flash",
|
|
13843
|
+
"gemini-1.5-pro": "gemini-1-5-pro",
|
|
13844
|
+
"gemini-1.5-flash": "gemini-2-0-flash",
|
|
13845
|
+
// DeepSeek aliases
|
|
13846
|
+
"deepseek-chat": "deepseek-v3",
|
|
13847
|
+
"deepseek-coder": "deepseek-v3",
|
|
13848
|
+
"deepseek/deepseek-chat": "deepseek-v3",
|
|
13849
|
+
"deepseek-reasoner": "deepseek-r1",
|
|
13850
|
+
"deepseek/deepseek-r1": "deepseek-r1"
|
|
13851
|
+
};
|
|
13900
13852
|
function getRateCard(modelId) {
|
|
13901
13853
|
if (!modelId)
|
|
13902
13854
|
return RATE_CARDS["default"];
|
|
13903
|
-
|
|
13855
|
+
let key = modelId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
13856
|
+
if (MODEL_ALIASES[modelId.toLowerCase()]) {
|
|
13857
|
+
key = MODEL_ALIASES[modelId.toLowerCase()];
|
|
13858
|
+
} else if (MODEL_ALIASES[key]) {
|
|
13859
|
+
key = MODEL_ALIASES[key];
|
|
13860
|
+
}
|
|
13904
13861
|
if (RATE_CARDS[key])
|
|
13905
13862
|
return RATE_CARDS[key];
|
|
13906
13863
|
if (key.includes("opus")) {
|
|
13907
|
-
return RATE_CARDS["claude-opus-4-6-thinking"]
|
|
13864
|
+
return RATE_CARDS["claude-opus-4-6-thinking"] ?? RATE_CARDS["claude-opus-4"];
|
|
13908
13865
|
}
|
|
13909
|
-
if (key.includes("sonnet")
|
|
13910
|
-
|
|
13866
|
+
if (key.includes("sonnet")) {
|
|
13867
|
+
if (key.includes("4-6") || key.includes("thinking")) {
|
|
13868
|
+
return RATE_CARDS["claude-sonnet-4-6-thinking"];
|
|
13869
|
+
}
|
|
13870
|
+
if (key.includes("3-7") || key.includes("sonnet-3-7")) {
|
|
13871
|
+
return RATE_CARDS["claude-3-7-sonnet"];
|
|
13872
|
+
}
|
|
13873
|
+
if (key.includes("3-5") || key.includes("sonnet-3-5")) {
|
|
13874
|
+
return RATE_CARDS["claude-3-5-sonnet"];
|
|
13875
|
+
}
|
|
13876
|
+
if (key.includes("sonnet-4") || key.includes("claude-4") || key.includes("sonnet-v4")) {
|
|
13877
|
+
return RATE_CARDS["claude-sonnet-4"] ?? RATE_CARDS["claude-sonnet-4-6-thinking"];
|
|
13878
|
+
}
|
|
13911
13879
|
}
|
|
13912
|
-
if (key.includes("
|
|
13913
|
-
return RATE_CARDS["
|
|
13880
|
+
if (key.includes("o1-mini") || key.includes("o3-mini")) {
|
|
13881
|
+
return RATE_CARDS["o3-mini"];
|
|
13914
13882
|
}
|
|
13915
|
-
if (key.includes("
|
|
13916
|
-
return RATE_CARDS["
|
|
13883
|
+
if (key.includes("o1")) {
|
|
13884
|
+
return RATE_CARDS["o1"];
|
|
13885
|
+
}
|
|
13886
|
+
if (key.includes("4o-mini")) {
|
|
13887
|
+
return RATE_CARDS["gpt-4o-mini"];
|
|
13888
|
+
}
|
|
13889
|
+
if (key.includes("4o")) {
|
|
13890
|
+
return RATE_CARDS["gpt-4o"];
|
|
13917
13891
|
}
|
|
13918
13892
|
if (key.includes("gemini") && key.includes("flash")) {
|
|
13919
|
-
return RATE_CARDS["gemini-3-8-flash"]
|
|
13893
|
+
return RATE_CARDS["gemini-3-8-flash"] ?? RATE_CARDS["gemini-2-0-flash"];
|
|
13920
13894
|
}
|
|
13921
13895
|
if (key.includes("gemini") && (key.includes("pro") || key.includes("2-5"))) {
|
|
13922
|
-
return RATE_CARDS["gemini-2-5-pro"]
|
|
13896
|
+
return RATE_CARDS["gemini-2-5-pro"] ?? RATE_CARDS["gemini-1-5-pro"];
|
|
13923
13897
|
}
|
|
13924
13898
|
return RATE_CARDS["default"];
|
|
13925
13899
|
}
|
|
13926
|
-
function computeCost(inputTokens, outputTokens, cachedTokens, card) {
|
|
13900
|
+
function computeCost(inputTokens, outputTokens, cachedTokens, card, cacheWriteTokens = 0) {
|
|
13927
13901
|
const freshInput = Math.max(0, inputTokens - cachedTokens);
|
|
13928
13902
|
const freshCost = freshInput / 1e6 * card.inputPerMTok;
|
|
13929
|
-
const
|
|
13903
|
+
const cacheReadCost = cachedTokens / 1e6 * card.cacheReadPerMTok;
|
|
13904
|
+
const cacheWriteCost = cacheWriteTokens / 1e6 * card.cacheWritePerMTok;
|
|
13930
13905
|
const outCost = outputTokens / 1e6 * card.outputPerMTok;
|
|
13931
|
-
return Number((freshCost +
|
|
13906
|
+
return Number((freshCost + cacheReadCost + cacheWriteCost + outCost).toFixed(4));
|
|
13907
|
+
}
|
|
13908
|
+
|
|
13909
|
+
// ../core/dist/discovery.js
|
|
13910
|
+
function parseGitTrailers(commitMessage) {
|
|
13911
|
+
if (!commitMessage)
|
|
13912
|
+
return [];
|
|
13913
|
+
const trailers = [];
|
|
13914
|
+
const lines = commitMessage.split("\n");
|
|
13915
|
+
for (const line of lines) {
|
|
13916
|
+
const trimmed2 = line.trim();
|
|
13917
|
+
const match = trimmed2.match(/^([A-Za-z\-]+):\s*(.+)$/i);
|
|
13918
|
+
if (!match || !match[1] || !match[2])
|
|
13919
|
+
continue;
|
|
13920
|
+
const token = match[1].toLowerCase();
|
|
13921
|
+
const value = match[2];
|
|
13922
|
+
const valLower = value.toLowerCase();
|
|
13923
|
+
if (token === "co-authored-by" || token === "generated-by" || token === "assisted-by" || token === "signed-off-by") {
|
|
13924
|
+
if (valLower.includes("copilot") || valLower.includes("github-actions")) {
|
|
13925
|
+
trailers.push({ token, value, provider: "copilot", model: "gpt-4o" });
|
|
13926
|
+
} else if (valLower.includes("claude") || valLower.includes("anthropic")) {
|
|
13927
|
+
trailers.push({ token, value, provider: "claude", model: "claude-3-7-sonnet" });
|
|
13928
|
+
} else if (valLower.includes("cursor") || valLower.includes("anysphere")) {
|
|
13929
|
+
trailers.push({ token, value, provider: "cursor", model: "claude-3-5-sonnet" });
|
|
13930
|
+
} else if (valLower.includes("aider")) {
|
|
13931
|
+
trailers.push({ token, value, provider: "aider", model: "claude-3-5-sonnet" });
|
|
13932
|
+
} else if (valLower.includes("windsurf") || valLower.includes("codeium")) {
|
|
13933
|
+
trailers.push({ token, value, provider: "windsurf", model: "claude-3-5-sonnet" });
|
|
13934
|
+
} else if (valLower.includes("antigravity") || valLower.includes("gemini")) {
|
|
13935
|
+
trailers.push({ token, value, provider: "antigravity", model: "claude-sonnet-4-6-thinking" });
|
|
13936
|
+
}
|
|
13937
|
+
}
|
|
13938
|
+
}
|
|
13939
|
+
return trailers;
|
|
13940
|
+
}
|
|
13941
|
+
function detectProviderFromCommit(commitMessage) {
|
|
13942
|
+
if (!commitMessage)
|
|
13943
|
+
return null;
|
|
13944
|
+
const trailers = parseGitTrailers(commitMessage);
|
|
13945
|
+
if (trailers.length > 0) {
|
|
13946
|
+
const primary = trailers[0];
|
|
13947
|
+
return {
|
|
13948
|
+
provider: primary.provider === "claude" ? "anthropic" : primary.provider,
|
|
13949
|
+
model: primary.model,
|
|
13950
|
+
confidence: 0.9,
|
|
13951
|
+
mode: "observed"
|
|
13952
|
+
};
|
|
13953
|
+
}
|
|
13954
|
+
const msg = commitMessage.toLowerCase();
|
|
13955
|
+
if (msg.includes("claude") || msg.includes("anthropic")) {
|
|
13956
|
+
return {
|
|
13957
|
+
provider: "anthropic",
|
|
13958
|
+
model: "claude-3-7-sonnet",
|
|
13959
|
+
confidence: 0.8,
|
|
13960
|
+
mode: "observed"
|
|
13961
|
+
};
|
|
13962
|
+
}
|
|
13963
|
+
if (msg.includes("antigravity")) {
|
|
13964
|
+
return {
|
|
13965
|
+
provider: "antigravity",
|
|
13966
|
+
model: "claude-sonnet-4-6-thinking",
|
|
13967
|
+
confidence: 0.8,
|
|
13968
|
+
mode: "observed"
|
|
13969
|
+
};
|
|
13970
|
+
}
|
|
13971
|
+
if (msg.includes("gemini")) {
|
|
13972
|
+
return {
|
|
13973
|
+
provider: "google",
|
|
13974
|
+
model: "gemini-3-8-flash",
|
|
13975
|
+
confidence: 0.8,
|
|
13976
|
+
mode: "observed"
|
|
13977
|
+
};
|
|
13978
|
+
}
|
|
13979
|
+
if (msg.includes("cursor")) {
|
|
13980
|
+
return {
|
|
13981
|
+
provider: "cursor",
|
|
13982
|
+
model: "claude-3-5-sonnet",
|
|
13983
|
+
confidence: 0.8,
|
|
13984
|
+
mode: "observed"
|
|
13985
|
+
};
|
|
13986
|
+
}
|
|
13987
|
+
if (msg.includes("aider")) {
|
|
13988
|
+
return {
|
|
13989
|
+
provider: "aider",
|
|
13990
|
+
model: "claude-3-5-sonnet",
|
|
13991
|
+
confidence: 0.8,
|
|
13992
|
+
mode: "observed"
|
|
13993
|
+
};
|
|
13994
|
+
}
|
|
13995
|
+
if (msg.includes("windsurf")) {
|
|
13996
|
+
return {
|
|
13997
|
+
provider: "windsurf",
|
|
13998
|
+
model: "claude-3-5-sonnet",
|
|
13999
|
+
confidence: 0.8,
|
|
14000
|
+
mode: "observed"
|
|
14001
|
+
};
|
|
14002
|
+
}
|
|
14003
|
+
if (msg.includes("copilot") || msg.includes("github-actions")) {
|
|
14004
|
+
return {
|
|
14005
|
+
provider: "copilot",
|
|
14006
|
+
model: "gpt-4o",
|
|
14007
|
+
confidence: 0.8,
|
|
14008
|
+
mode: "observed"
|
|
14009
|
+
};
|
|
14010
|
+
}
|
|
14011
|
+
return null;
|
|
14012
|
+
}
|
|
14013
|
+
function harvestTrailerFootprints(repoPath, commitMessage, headSha, commitDate) {
|
|
14014
|
+
if (!commitMessage)
|
|
14015
|
+
return [];
|
|
14016
|
+
const trailers = parseGitTrailers(commitMessage);
|
|
14017
|
+
const footprints = [];
|
|
14018
|
+
const dateIso = commitDate ? commitDate instanceof Date ? commitDate.toISOString() : new Date(commitDate).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
14019
|
+
for (const t2 of trailers) {
|
|
14020
|
+
const rateCard = getRateCard(t2.model);
|
|
14021
|
+
const estInput = 5e3;
|
|
14022
|
+
const estCached = 2500;
|
|
14023
|
+
const estOutput = 600;
|
|
14024
|
+
const cost = computeCost(estInput, estOutput, estCached, rateCard);
|
|
14025
|
+
footprints.push({
|
|
14026
|
+
id: `trailer_${t2.provider}_${(headSha || "head").slice(0, 8)}`,
|
|
14027
|
+
platform: t2.provider,
|
|
14028
|
+
sessionId: `commit_trailer_${t2.provider}`,
|
|
14029
|
+
repoPath,
|
|
14030
|
+
taskTitle: `Commit Trailer (${t2.token}: ${t2.value.slice(0, 30)})`,
|
|
14031
|
+
model: t2.model,
|
|
14032
|
+
stepsCount: 1,
|
|
14033
|
+
filesEdited: [],
|
|
14034
|
+
timestamp: dateIso,
|
|
14035
|
+
boundCommitSha: headSha,
|
|
14036
|
+
tokens: {
|
|
14037
|
+
input: estInput,
|
|
14038
|
+
output: estOutput,
|
|
14039
|
+
cached: estCached
|
|
14040
|
+
},
|
|
14041
|
+
cost,
|
|
14042
|
+
mode: "observed",
|
|
14043
|
+
confidence: 0.9
|
|
14044
|
+
});
|
|
14045
|
+
}
|
|
14046
|
+
return footprints;
|
|
13932
14047
|
}
|
|
13933
14048
|
|
|
14049
|
+
// ../core/dist/harvester/antigravity.js
|
|
14050
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
14051
|
+
var path3 = __toESM(require("path"), 1);
|
|
14052
|
+
var os2 = __toESM(require("os"), 1);
|
|
14053
|
+
var import_node_module = require("module");
|
|
14054
|
+
|
|
13934
14055
|
// ../core/dist/harvester/scoring.js
|
|
13935
14056
|
function normalizeFilePath(filePath, repoPath) {
|
|
13936
14057
|
let p2 = filePath.replace(/\\/g, "/").trim();
|
|
@@ -14068,8 +14189,8 @@ function harvestAntigravityFootprints(repoPath, sinceDate) {
|
|
|
14068
14189
|
const DatabaseSync2 = getSqliteDatabase();
|
|
14069
14190
|
if (!DatabaseSync2)
|
|
14070
14191
|
return footprints;
|
|
14071
|
-
const
|
|
14072
|
-
const antigravityDir = process.env.ANTIGRAVITY_APP_DATA_DIR || path3.join(
|
|
14192
|
+
const homedir7 = os2.homedir();
|
|
14193
|
+
const antigravityDir = process.env.ANTIGRAVITY_APP_DATA_DIR || path3.join(homedir7, ".gemini", "antigravity");
|
|
14073
14194
|
const dbPath = path3.join(antigravityDir, "conversation_summaries.db");
|
|
14074
14195
|
if (!fs2.existsSync(dbPath)) {
|
|
14075
14196
|
return footprints;
|
|
@@ -14181,8 +14302,8 @@ var path4 = __toESM(require("path"), 1);
|
|
|
14181
14302
|
var os3 = __toESM(require("os"), 1);
|
|
14182
14303
|
function harvestClaudeFootprints(repoPath, projectAlias, sinceDate) {
|
|
14183
14304
|
const footprints = [];
|
|
14184
|
-
const
|
|
14185
|
-
const claudeProjectsDir = path4.join(
|
|
14305
|
+
const homedir7 = os3.homedir();
|
|
14306
|
+
const claudeProjectsDir = path4.join(homedir7, ".claude", "projects");
|
|
14186
14307
|
if (!fs3.existsSync(claudeProjectsDir)) {
|
|
14187
14308
|
return footprints;
|
|
14188
14309
|
}
|
|
@@ -14517,13 +14638,116 @@ function harvestCursorFootprints(repoPath, sinceDate) {
|
|
|
14517
14638
|
return footprints;
|
|
14518
14639
|
}
|
|
14519
14640
|
|
|
14520
|
-
// ../core/dist/
|
|
14521
|
-
var import_node_module3 = require("module");
|
|
14522
|
-
var path6 = __toESM(require("path"), 1);
|
|
14641
|
+
// ../core/dist/harvester/aider.js
|
|
14523
14642
|
var fs5 = __toESM(require("fs"), 1);
|
|
14643
|
+
var path6 = __toESM(require("path"), 1);
|
|
14644
|
+
function harvestAiderFootprints(repoPath, sinceDate) {
|
|
14645
|
+
const footprints = [];
|
|
14646
|
+
const historyPath = path6.join(repoPath, ".aider.chat.history.md");
|
|
14647
|
+
if (!fs5.existsSync(historyPath)) {
|
|
14648
|
+
return footprints;
|
|
14649
|
+
}
|
|
14650
|
+
try {
|
|
14651
|
+
const stat = fs5.statSync(historyPath);
|
|
14652
|
+
if (sinceDate && stat.mtime < sinceDate) {
|
|
14653
|
+
return footprints;
|
|
14654
|
+
}
|
|
14655
|
+
const content = fs5.readFileSync(historyPath, "utf-8");
|
|
14656
|
+
const sessionChunks = content.split(/^#\s+aider chat started at\s+/m);
|
|
14657
|
+
for (let i2 = 1; i2 < sessionChunks.length; i2++) {
|
|
14658
|
+
const chunk = sessionChunks[i2];
|
|
14659
|
+
const firstNewline = chunk.indexOf("\n");
|
|
14660
|
+
const dateStr = firstNewline !== -1 ? chunk.slice(0, firstNewline).trim() : chunk.slice(0, 30).trim();
|
|
14661
|
+
const sessionDate = new Date(dateStr);
|
|
14662
|
+
if (sinceDate && !isNaN(sessionDate.getTime()) && sessionDate < sinceDate) {
|
|
14663
|
+
continue;
|
|
14664
|
+
}
|
|
14665
|
+
const timestamp = !isNaN(sessionDate.getTime()) ? sessionDate.toISOString() : stat.mtime.toISOString();
|
|
14666
|
+
const lines = chunk.split("\n");
|
|
14667
|
+
let taskTitle = "";
|
|
14668
|
+
let model = "claude-3-5-sonnet";
|
|
14669
|
+
let boundCommitSha;
|
|
14670
|
+
const filesEdited = /* @__PURE__ */ new Set();
|
|
14671
|
+
let stepCount = 0;
|
|
14672
|
+
let reportedInputTokens = 0;
|
|
14673
|
+
let reportedOutputTokens = 0;
|
|
14674
|
+
let reportedCost = 0;
|
|
14675
|
+
for (const line of lines) {
|
|
14676
|
+
const trimmed2 = line.trim();
|
|
14677
|
+
const modelMatch = trimmed2.match(/^(?:Main\s+)?model:\s*([^\s,]+)/i);
|
|
14678
|
+
if (modelMatch && modelMatch[1]) {
|
|
14679
|
+
model = modelMatch[1].replace(/[`"']/g, "").trim();
|
|
14680
|
+
}
|
|
14681
|
+
if (!taskTitle && trimmed2.startsWith("#### ")) {
|
|
14682
|
+
const query = trimmed2.replace(/^####\s+/, "").trim();
|
|
14683
|
+
if (query && !query.startsWith("/") && !query.startsWith("add ") && !query.startsWith("drop ")) {
|
|
14684
|
+
taskTitle = query.slice(0, 60);
|
|
14685
|
+
}
|
|
14686
|
+
}
|
|
14687
|
+
if (trimmed2.startsWith("#### ") || trimmed2.startsWith("> Applied edit to") || trimmed2.startsWith("> Commit ")) {
|
|
14688
|
+
stepCount++;
|
|
14689
|
+
}
|
|
14690
|
+
const editMatch = trimmed2.match(/^>\s*(?:Applied edit to|Wrote|Updated)\s+([^\s]+)/i);
|
|
14691
|
+
if (editMatch && editMatch[1]) {
|
|
14692
|
+
filesEdited.add(normalizeFilePath(editMatch[1], repoPath));
|
|
14693
|
+
}
|
|
14694
|
+
const commitMatch = trimmed2.match(/^>\s*Commit\s+([a-f0-9]{7,40})/i);
|
|
14695
|
+
if (commitMatch && commitMatch[1]) {
|
|
14696
|
+
boundCommitSha = commitMatch[1];
|
|
14697
|
+
}
|
|
14698
|
+
const tokenMatch = trimmed2.match(/Tokens:\s*([0-9\.]+)k?\s*sent,\s*([0-9\.]+)k?\s*received/i);
|
|
14699
|
+
if (tokenMatch && tokenMatch[1] && tokenMatch[2]) {
|
|
14700
|
+
const sentMult = trimmed2.includes(tokenMatch[1] + "k") ? 1e3 : 1;
|
|
14701
|
+
const recvMult = trimmed2.includes(tokenMatch[2] + "k") ? 1e3 : 1;
|
|
14702
|
+
reportedInputTokens += Math.round(parseFloat(tokenMatch[1]) * sentMult);
|
|
14703
|
+
reportedOutputTokens += Math.round(parseFloat(tokenMatch[2]) * recvMult);
|
|
14704
|
+
}
|
|
14705
|
+
const costMatch = trimmed2.match(/Cost:\s*\$([0-9\.]+)\s*(?:message|session)/i);
|
|
14706
|
+
if (costMatch && costMatch[1]) {
|
|
14707
|
+
reportedCost = Math.max(reportedCost, parseFloat(costMatch[1]));
|
|
14708
|
+
}
|
|
14709
|
+
}
|
|
14710
|
+
if (stepCount > 0 || filesEdited.size > 0) {
|
|
14711
|
+
const rateCard = getRateCard(model);
|
|
14712
|
+
const estInput = reportedInputTokens > 0 ? reportedInputTokens : Math.max(stepCount * 2500, 3e3);
|
|
14713
|
+
const estCached = Math.round(estInput * 0.5);
|
|
14714
|
+
const estOutput = reportedOutputTokens > 0 ? reportedOutputTokens : Math.max(stepCount * 350, 400);
|
|
14715
|
+
const cost = reportedCost > 0 ? reportedCost : computeCost(estInput, estOutput, estCached, rateCard);
|
|
14716
|
+
footprints.push({
|
|
14717
|
+
id: `aider_${i2}_${timestamp.slice(0, 10)}`,
|
|
14718
|
+
platform: "aider",
|
|
14719
|
+
sessionId: `aider_session_${i2}`,
|
|
14720
|
+
repoPath,
|
|
14721
|
+
taskTitle: taskTitle || "Aider Pairing Session",
|
|
14722
|
+
model,
|
|
14723
|
+
stepsCount: Math.max(stepCount, 1),
|
|
14724
|
+
filesEdited: Array.from(filesEdited),
|
|
14725
|
+
timestamp,
|
|
14726
|
+
boundCommitSha,
|
|
14727
|
+
tokens: {
|
|
14728
|
+
input: estInput,
|
|
14729
|
+
output: estOutput,
|
|
14730
|
+
cached: estCached
|
|
14731
|
+
},
|
|
14732
|
+
cost,
|
|
14733
|
+
mode: reportedInputTokens > 0 ? "verified" : "imported",
|
|
14734
|
+
confidence: boundCommitSha ? 0.95 : 0.85,
|
|
14735
|
+
rawTranscriptPath: historyPath
|
|
14736
|
+
});
|
|
14737
|
+
}
|
|
14738
|
+
}
|
|
14739
|
+
} catch {
|
|
14740
|
+
}
|
|
14741
|
+
return footprints;
|
|
14742
|
+
}
|
|
14743
|
+
|
|
14744
|
+
// ../core/dist/harvester/windsurf.js
|
|
14745
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
14746
|
+
var path7 = __toESM(require("path"), 1);
|
|
14524
14747
|
var os5 = __toESM(require("os"), 1);
|
|
14748
|
+
var import_node_module3 = require("module");
|
|
14525
14749
|
var import_meta3 = {};
|
|
14526
|
-
function
|
|
14750
|
+
function getSqliteDatabase3() {
|
|
14527
14751
|
try {
|
|
14528
14752
|
const mod = "node:sqlite";
|
|
14529
14753
|
if (typeof require !== "undefined") {
|
|
@@ -14539,6 +14763,128 @@ function getDatabaseSyncClass() {
|
|
|
14539
14763
|
return null;
|
|
14540
14764
|
}
|
|
14541
14765
|
}
|
|
14766
|
+
function harvestWindsurfFootprints(repoPath, sinceDate) {
|
|
14767
|
+
const footprints = [];
|
|
14768
|
+
const DatabaseSync2 = getSqliteDatabase3();
|
|
14769
|
+
if (!DatabaseSync2)
|
|
14770
|
+
return footprints;
|
|
14771
|
+
const normTarget = repoPath.toLowerCase().replace(/\\/g, "/").replace(/\/$/, "");
|
|
14772
|
+
const targetBasename = path7.basename(repoPath).toLowerCase();
|
|
14773
|
+
let storageDir = "";
|
|
14774
|
+
if (process.platform === "win32") {
|
|
14775
|
+
storageDir = path7.join(process.env.APPDATA || path7.join(os5.homedir(), "AppData", "Roaming"), "Windsurf", "User", "workspaceStorage");
|
|
14776
|
+
} else if (process.platform === "darwin") {
|
|
14777
|
+
storageDir = path7.join(os5.homedir(), "Library", "Application Support", "Windsurf", "User", "workspaceStorage");
|
|
14778
|
+
} else {
|
|
14779
|
+
storageDir = path7.join(os5.homedir(), ".config", "Windsurf", "User", "workspaceStorage");
|
|
14780
|
+
}
|
|
14781
|
+
if (!fs6.existsSync(storageDir))
|
|
14782
|
+
return footprints;
|
|
14783
|
+
try {
|
|
14784
|
+
const wsDirs = fs6.readdirSync(storageDir);
|
|
14785
|
+
for (const ws of wsDirs) {
|
|
14786
|
+
const wsPath = path7.join(storageDir, ws);
|
|
14787
|
+
const wsJsonPath = path7.join(wsPath, "workspace.json");
|
|
14788
|
+
if (!fs6.existsSync(wsJsonPath))
|
|
14789
|
+
continue;
|
|
14790
|
+
try {
|
|
14791
|
+
const wsJson = JSON.parse(fs6.readFileSync(wsJsonPath, "utf-8"));
|
|
14792
|
+
let folderUri = wsJson.folder || wsJson.workspace || "";
|
|
14793
|
+
try {
|
|
14794
|
+
folderUri = decodeURIComponent(folderUri.replace(/^file:\/\/\/?/, ""));
|
|
14795
|
+
} catch {
|
|
14796
|
+
}
|
|
14797
|
+
const folder = folderUri.toLowerCase().replace(/\\/g, "/");
|
|
14798
|
+
if (!folder.includes(normTarget) && !normTarget.includes(folder) && !folder.endsWith(targetBasename)) {
|
|
14799
|
+
continue;
|
|
14800
|
+
}
|
|
14801
|
+
const dbFile = path7.join(wsPath, "state.vscdb");
|
|
14802
|
+
if (!fs6.existsSync(dbFile))
|
|
14803
|
+
continue;
|
|
14804
|
+
const dbStat = fs6.statSync(dbFile);
|
|
14805
|
+
if (sinceDate && dbStat.mtime < sinceDate)
|
|
14806
|
+
continue;
|
|
14807
|
+
const db = new DatabaseSync2(dbFile, { readOnly: true });
|
|
14808
|
+
const rows = db.prepare("SELECT key, value FROM ItemTable WHERE key LIKE '%cascade%' OR key LIKE '%codeium%' LIMIT 5").all();
|
|
14809
|
+
if (rows && rows.length > 0) {
|
|
14810
|
+
let stepCount = 0;
|
|
14811
|
+
let taskTitle = "";
|
|
14812
|
+
let model = "claude-3-5-sonnet";
|
|
14813
|
+
const filesEditedSet = /* @__PURE__ */ new Set();
|
|
14814
|
+
for (const row of rows) {
|
|
14815
|
+
try {
|
|
14816
|
+
const parsed = JSON.parse(row.value);
|
|
14817
|
+
if (Array.isArray(parsed)) {
|
|
14818
|
+
stepCount += parsed.length;
|
|
14819
|
+
} else if (parsed && typeof parsed === "object") {
|
|
14820
|
+
if (parsed.steps || parsed.messages) {
|
|
14821
|
+
stepCount += (parsed.steps || parsed.messages).length;
|
|
14822
|
+
}
|
|
14823
|
+
if (parsed.title)
|
|
14824
|
+
taskTitle = String(parsed.title);
|
|
14825
|
+
if (parsed.model)
|
|
14826
|
+
model = String(parsed.model);
|
|
14827
|
+
}
|
|
14828
|
+
} catch {
|
|
14829
|
+
}
|
|
14830
|
+
}
|
|
14831
|
+
const count = Math.max(stepCount, 1);
|
|
14832
|
+
const rateCard = getRateCard(model);
|
|
14833
|
+
const estInput = count * 2500;
|
|
14834
|
+
const estCached = Math.round(estInput * 0.6);
|
|
14835
|
+
const estOutput = count * 300;
|
|
14836
|
+
const cost = computeCost(estInput, estOutput, estCached, rateCard);
|
|
14837
|
+
footprints.push({
|
|
14838
|
+
id: `windsurf_${ws}`,
|
|
14839
|
+
platform: "windsurf",
|
|
14840
|
+
sessionId: ws,
|
|
14841
|
+
repoPath,
|
|
14842
|
+
taskTitle: taskTitle || "Windsurf Cascade Session",
|
|
14843
|
+
model,
|
|
14844
|
+
stepsCount: count,
|
|
14845
|
+
filesEdited: Array.from(filesEditedSet),
|
|
14846
|
+
timestamp: dbStat.mtime.toISOString(),
|
|
14847
|
+
tokens: {
|
|
14848
|
+
input: estInput,
|
|
14849
|
+
output: estOutput,
|
|
14850
|
+
cached: estCached
|
|
14851
|
+
},
|
|
14852
|
+
cost,
|
|
14853
|
+
mode: "imported",
|
|
14854
|
+
confidence: 0.85,
|
|
14855
|
+
rawTranscriptPath: dbFile
|
|
14856
|
+
});
|
|
14857
|
+
}
|
|
14858
|
+
} catch {
|
|
14859
|
+
}
|
|
14860
|
+
}
|
|
14861
|
+
} catch {
|
|
14862
|
+
}
|
|
14863
|
+
return footprints;
|
|
14864
|
+
}
|
|
14865
|
+
|
|
14866
|
+
// ../core/dist/db.js
|
|
14867
|
+
var import_node_module4 = require("module");
|
|
14868
|
+
var path8 = __toESM(require("path"), 1);
|
|
14869
|
+
var fs7 = __toESM(require("fs"), 1);
|
|
14870
|
+
var os6 = __toESM(require("os"), 1);
|
|
14871
|
+
var import_meta4 = {};
|
|
14872
|
+
function getDatabaseSyncClass() {
|
|
14873
|
+
try {
|
|
14874
|
+
const mod = "node:sqlite";
|
|
14875
|
+
if (typeof require !== "undefined") {
|
|
14876
|
+
return require(mod).DatabaseSync;
|
|
14877
|
+
}
|
|
14878
|
+
} catch {
|
|
14879
|
+
}
|
|
14880
|
+
try {
|
|
14881
|
+
const mod = "node:sqlite";
|
|
14882
|
+
const req = (0, import_node_module4.createRequire)(import_meta4.url);
|
|
14883
|
+
return req(mod).DatabaseSync;
|
|
14884
|
+
} catch {
|
|
14885
|
+
return null;
|
|
14886
|
+
}
|
|
14887
|
+
}
|
|
14542
14888
|
var DatabaseSync = getDatabaseSyncClass();
|
|
14543
14889
|
var LocalStateDB = class {
|
|
14544
14890
|
db;
|
|
@@ -14550,11 +14896,11 @@ var LocalStateDB = class {
|
|
|
14550
14896
|
if (inMemory || process.env.CI === "true" || process.env.QODEWK_NO_DB === "true") {
|
|
14551
14897
|
this.db = new DatabaseSync(":memory:");
|
|
14552
14898
|
} else {
|
|
14553
|
-
const qodewkDir =
|
|
14554
|
-
if (!
|
|
14555
|
-
|
|
14899
|
+
const qodewkDir = path8.join(os6.homedir(), ".qodewk");
|
|
14900
|
+
if (!fs7.existsSync(qodewkDir)) {
|
|
14901
|
+
fs7.mkdirSync(qodewkDir, { recursive: true });
|
|
14556
14902
|
}
|
|
14557
|
-
const dbPath =
|
|
14903
|
+
const dbPath = path8.join(qodewkDir, "state.db");
|
|
14558
14904
|
this.db = new DatabaseSync(dbPath);
|
|
14559
14905
|
}
|
|
14560
14906
|
this.migrate();
|
|
@@ -14666,8 +15012,37 @@ var LocalStateDB = class {
|
|
|
14666
15012
|
return null;
|
|
14667
15013
|
return JSON.parse(row.payload_json);
|
|
14668
15014
|
}
|
|
14669
|
-
|
|
14670
|
-
if (this.db)
|
|
15015
|
+
getRecentReceipts(limit = 10) {
|
|
15016
|
+
if (!this.db)
|
|
15017
|
+
return [];
|
|
15018
|
+
try {
|
|
15019
|
+
const rows = this.db.prepare("SELECT payload_json, claim_token, sync_status, created_at FROM receipts ORDER BY created_at DESC LIMIT ?").all(limit);
|
|
15020
|
+
return rows.map((r2) => ({
|
|
15021
|
+
receipt: JSON.parse(r2.payload_json),
|
|
15022
|
+
claimToken: r2.claim_token || void 0,
|
|
15023
|
+
syncStatus: r2.sync_status || "local",
|
|
15024
|
+
createdAt: r2.created_at
|
|
15025
|
+
}));
|
|
15026
|
+
} catch {
|
|
15027
|
+
return [];
|
|
15028
|
+
}
|
|
15029
|
+
}
|
|
15030
|
+
getStats() {
|
|
15031
|
+
if (!this.db)
|
|
15032
|
+
return { totalReceipts: 0, totalFootprints: 0 };
|
|
15033
|
+
try {
|
|
15034
|
+
const rRow = this.db.prepare("SELECT COUNT(*) as cnt FROM receipts").get();
|
|
15035
|
+
const fRow = this.db.prepare("SELECT COUNT(*) as cnt FROM agent_footprints").get();
|
|
15036
|
+
return {
|
|
15037
|
+
totalReceipts: rRow?.cnt || 0,
|
|
15038
|
+
totalFootprints: fRow?.cnt || 0
|
|
15039
|
+
};
|
|
15040
|
+
} catch {
|
|
15041
|
+
return { totalReceipts: 0, totalFootprints: 0 };
|
|
15042
|
+
}
|
|
15043
|
+
}
|
|
15044
|
+
close() {
|
|
15045
|
+
if (this.db) {
|
|
14671
15046
|
this.db.close();
|
|
14672
15047
|
}
|
|
14673
15048
|
}
|
|
@@ -14717,6 +15092,18 @@ async function harvestUniversalFootprints(options) {
|
|
|
14717
15092
|
const cursorFootprints = harvestCursorFootprints(options.repoPath, sinceDate);
|
|
14718
15093
|
allFootprints.push(...cursorFootprints);
|
|
14719
15094
|
}
|
|
15095
|
+
if (!options.platform || options.platform === "all" || options.platform === "aider") {
|
|
15096
|
+
const aiderFootprints = harvestAiderFootprints(options.repoPath, sinceDate);
|
|
15097
|
+
allFootprints.push(...aiderFootprints);
|
|
15098
|
+
}
|
|
15099
|
+
if (!options.platform || options.platform === "all" || options.platform === "windsurf") {
|
|
15100
|
+
const windsurfFootprints = harvestWindsurfFootprints(options.repoPath, sinceDate);
|
|
15101
|
+
allFootprints.push(...windsurfFootprints);
|
|
15102
|
+
}
|
|
15103
|
+
if (options.gitContext?.commitMessage) {
|
|
15104
|
+
const trailerFps = harvestTrailerFootprints(options.repoPath, options.gitContext.commitMessage, options.gitContext.headSha, options.gitContext.commitDate);
|
|
15105
|
+
allFootprints.push(...trailerFps);
|
|
15106
|
+
}
|
|
14720
15107
|
const { primary, rankedFootprints } = selectPrimaryFootprint(allFootprints, options.gitContext);
|
|
14721
15108
|
allFootprints = rankedFootprints;
|
|
14722
15109
|
try {
|
|
@@ -14911,6 +15298,7 @@ async function generateReceipt(options = {}) {
|
|
|
14911
15298
|
gitContext: {
|
|
14912
15299
|
headSha: metrics.headSha,
|
|
14913
15300
|
commitDate: metrics.commitDate,
|
|
15301
|
+
commitMessage: metrics.commitMessage,
|
|
14914
15302
|
changedFiles: metrics.changedFiles,
|
|
14915
15303
|
branch: metrics.branch
|
|
14916
15304
|
}
|
|
@@ -14999,99 +15387,969 @@ async function generateReceipt(options = {}) {
|
|
|
14999
15387
|
return ReceiptV1Schema.parse(receipt);
|
|
15000
15388
|
}
|
|
15001
15389
|
|
|
15002
|
-
// src/
|
|
15003
|
-
var
|
|
15004
|
-
|
|
15005
|
-
|
|
15006
|
-
|
|
15007
|
-
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15011
|
-
|
|
15012
|
-
|
|
15013
|
-
|
|
15014
|
-
|
|
15390
|
+
// src/receipt-view.ts
|
|
15391
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
15392
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
15393
|
+
|
|
15394
|
+
// src/barcode.ts
|
|
15395
|
+
var CODE128_PATTERNS = [
|
|
15396
|
+
"11011001100",
|
|
15397
|
+
"11001101100",
|
|
15398
|
+
"11001100110",
|
|
15399
|
+
"10010011000",
|
|
15400
|
+
"10010001100",
|
|
15401
|
+
"10001001100",
|
|
15402
|
+
"10011001000",
|
|
15403
|
+
"10011000100",
|
|
15404
|
+
"10001100100",
|
|
15405
|
+
"11001001000",
|
|
15406
|
+
"11001000100",
|
|
15407
|
+
"11000100100",
|
|
15408
|
+
"10110011100",
|
|
15409
|
+
"10011011100",
|
|
15410
|
+
"10011001110",
|
|
15411
|
+
"10111001100",
|
|
15412
|
+
"10011101100",
|
|
15413
|
+
"10011100110",
|
|
15414
|
+
"11001110010",
|
|
15415
|
+
"11001011100",
|
|
15416
|
+
"11001001110",
|
|
15417
|
+
"11011100100",
|
|
15418
|
+
"11001110100",
|
|
15419
|
+
"11101101110",
|
|
15420
|
+
"11101001100",
|
|
15421
|
+
"11100101100",
|
|
15422
|
+
"11100100110",
|
|
15423
|
+
"11101100100",
|
|
15424
|
+
"11100110100",
|
|
15425
|
+
"11100110010",
|
|
15426
|
+
"11011011000",
|
|
15427
|
+
"11011000110",
|
|
15428
|
+
"11000110110",
|
|
15429
|
+
"10100011000",
|
|
15430
|
+
"10001011000",
|
|
15431
|
+
"10001000110",
|
|
15432
|
+
"10110001000",
|
|
15433
|
+
"10001101000",
|
|
15434
|
+
"10001100010",
|
|
15435
|
+
"11010001000",
|
|
15436
|
+
"11000101000",
|
|
15437
|
+
"11000100010",
|
|
15438
|
+
"10110111000",
|
|
15439
|
+
"10110001110",
|
|
15440
|
+
"10001101110",
|
|
15441
|
+
"10111011000",
|
|
15442
|
+
"10111000110",
|
|
15443
|
+
"10001110110",
|
|
15444
|
+
"11101110110",
|
|
15445
|
+
"11010001110",
|
|
15446
|
+
"11000101110",
|
|
15447
|
+
"11011101000",
|
|
15448
|
+
"11011100010",
|
|
15449
|
+
"11011101110",
|
|
15450
|
+
"11101011000",
|
|
15451
|
+
"11101000110",
|
|
15452
|
+
"11100010110",
|
|
15453
|
+
"11101101000",
|
|
15454
|
+
"11101100010",
|
|
15455
|
+
"11100011010",
|
|
15456
|
+
"11101111010",
|
|
15457
|
+
"11001000010",
|
|
15458
|
+
"11110001010",
|
|
15459
|
+
"10100110000",
|
|
15460
|
+
"10100001100",
|
|
15461
|
+
"10010110000",
|
|
15462
|
+
"10010000110",
|
|
15463
|
+
"10000101100",
|
|
15464
|
+
"10000100110",
|
|
15465
|
+
"10110010000",
|
|
15466
|
+
"10110000100",
|
|
15467
|
+
"10011010000",
|
|
15468
|
+
"10011000010",
|
|
15469
|
+
"10000110100",
|
|
15470
|
+
"10000110010",
|
|
15471
|
+
"11000010010",
|
|
15472
|
+
"11001010000",
|
|
15473
|
+
"11110111010",
|
|
15474
|
+
"11000010100",
|
|
15475
|
+
"10001111010",
|
|
15476
|
+
"10100111100",
|
|
15477
|
+
"10010111100",
|
|
15478
|
+
"10010011110",
|
|
15479
|
+
"10111100100",
|
|
15480
|
+
"10011110100",
|
|
15481
|
+
"10011110010",
|
|
15482
|
+
"11110100100",
|
|
15483
|
+
"11110010100",
|
|
15484
|
+
"11110010010",
|
|
15485
|
+
"11011011110",
|
|
15486
|
+
"11011110110",
|
|
15487
|
+
"11110110110",
|
|
15488
|
+
"10101111000",
|
|
15489
|
+
"10100011110",
|
|
15490
|
+
"10001011110",
|
|
15491
|
+
"10111101000",
|
|
15492
|
+
"10111100010",
|
|
15493
|
+
"11110101000",
|
|
15494
|
+
"11110100010",
|
|
15495
|
+
"10111011110",
|
|
15496
|
+
"10111101110",
|
|
15497
|
+
"11101011110",
|
|
15498
|
+
"11110101110",
|
|
15499
|
+
"11010000100",
|
|
15500
|
+
"11010010000",
|
|
15501
|
+
"11010011100",
|
|
15502
|
+
"1100011101011"
|
|
15503
|
+
];
|
|
15504
|
+
var START_B = 104;
|
|
15505
|
+
var STOP = 106;
|
|
15506
|
+
function encodeCode128B(text) {
|
|
15507
|
+
const codes = [START_B];
|
|
15508
|
+
for (const ch of text) {
|
|
15509
|
+
const code = ch.charCodeAt(0) - 32;
|
|
15510
|
+
if (code < 0 || code > 95) {
|
|
15511
|
+
throw new Error(`Code 128-B cannot encode character: ${JSON.stringify(ch)}`);
|
|
15015
15512
|
}
|
|
15016
|
-
|
|
15513
|
+
codes.push(code);
|
|
15514
|
+
}
|
|
15515
|
+
let checksum = START_B;
|
|
15516
|
+
for (let i2 = 1; i2 < codes.length; i2++) {
|
|
15517
|
+
checksum += codes[i2] * i2;
|
|
15017
15518
|
}
|
|
15018
|
-
|
|
15519
|
+
codes.push(checksum % 103);
|
|
15520
|
+
codes.push(STOP);
|
|
15521
|
+
return codes;
|
|
15019
15522
|
}
|
|
15020
|
-
function
|
|
15021
|
-
|
|
15523
|
+
function code128Modules(text) {
|
|
15524
|
+
const codes = encodeCode128B(text);
|
|
15525
|
+
let modules = "";
|
|
15526
|
+
for (const code of codes) {
|
|
15527
|
+
modules += CODE128_PATTERNS[code] ?? "";
|
|
15528
|
+
}
|
|
15529
|
+
return modules;
|
|
15022
15530
|
}
|
|
15023
|
-
function
|
|
15531
|
+
function renderTerminalBarcode(text, options = {}) {
|
|
15532
|
+
const maxWidth = Math.max(16, options.maxWidth ?? 52);
|
|
15533
|
+
const height = Math.max(2, options.height ?? 3);
|
|
15534
|
+
const quietZone = Math.max(0, options.quietZone ?? 10);
|
|
15535
|
+
let payload = text;
|
|
15536
|
+
payload = [...payload].filter((ch) => {
|
|
15537
|
+
const c3 = ch.charCodeAt(0);
|
|
15538
|
+
return c3 >= 32 && c3 <= 126;
|
|
15539
|
+
}).join("");
|
|
15540
|
+
if (!payload) payload = "QODEWK";
|
|
15541
|
+
let modules;
|
|
15024
15542
|
try {
|
|
15025
|
-
|
|
15026
|
-
db.saveReceipt(receipt, claimToken);
|
|
15027
|
-
db.close();
|
|
15543
|
+
modules = code128Modules(payload);
|
|
15028
15544
|
} catch {
|
|
15545
|
+
modules = code128Modules("QODEWK");
|
|
15029
15546
|
}
|
|
15547
|
+
const withQuiet = "0".repeat(quietZone) + modules + "0".repeat(quietZone);
|
|
15548
|
+
const scaled = downsampleModules(withQuiet, maxWidth);
|
|
15549
|
+
const row = modulesToBlocks(scaled);
|
|
15550
|
+
return Array.from({ length: height }, () => row);
|
|
15030
15551
|
}
|
|
15031
|
-
function
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
15039
|
-
|
|
15040
|
-
|
|
15041
|
-
if (!match?.[1]) return null;
|
|
15042
|
-
let gitDir = match[1].trim();
|
|
15043
|
-
if (!path7.isAbsolute(gitDir)) {
|
|
15044
|
-
gitDir = path7.resolve(cwd, gitDir);
|
|
15045
|
-
}
|
|
15046
|
-
const commonFile = path7.join(gitDir, "commondir");
|
|
15047
|
-
if (fs6.existsSync(commonFile)) {
|
|
15048
|
-
let common = fs6.readFileSync(commonFile, "utf-8").trim();
|
|
15049
|
-
if (!path7.isAbsolute(common)) {
|
|
15050
|
-
common = path7.resolve(gitDir, common);
|
|
15051
|
-
}
|
|
15052
|
-
gitCommonDir = common;
|
|
15053
|
-
} else if (path7.basename(path7.dirname(gitDir)) === "worktrees") {
|
|
15054
|
-
gitCommonDir = path7.dirname(path7.dirname(gitDir));
|
|
15055
|
-
} else {
|
|
15056
|
-
gitCommonDir = gitDir;
|
|
15552
|
+
function downsampleModules(modules, maxWidth) {
|
|
15553
|
+
if (modules.length <= maxWidth) return modules;
|
|
15554
|
+
const out = [];
|
|
15555
|
+
const ratio = modules.length / maxWidth;
|
|
15556
|
+
for (let i2 = 0; i2 < maxWidth; i2++) {
|
|
15557
|
+
const start = Math.floor(i2 * ratio);
|
|
15558
|
+
const end = Math.max(start + 1, Math.floor((i2 + 1) * ratio));
|
|
15559
|
+
let bars = 0;
|
|
15560
|
+
for (let j2 = start; j2 < end && j2 < modules.length; j2++) {
|
|
15561
|
+
if (modules[j2] === "1") bars++;
|
|
15057
15562
|
}
|
|
15563
|
+
out.push(bars * 2 >= end - start ? "1" : "0");
|
|
15058
15564
|
}
|
|
15059
|
-
return
|
|
15565
|
+
return out.join("");
|
|
15060
15566
|
}
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
# Non-blocking Qodewk background recorder (< 5ms)
|
|
15066
|
-
if command -v qodewk >/dev/null 2>&1 || command -v pnpm >/dev/null 2>&1 || [ -f "./node_modules/.bin/qodewk" ]; then
|
|
15067
|
-
( ( qodewk record || pnpm qodewk record || npx qodewk record ) >/dev/null 2>&1 & )
|
|
15068
|
-
fi
|
|
15069
|
-
${HOOK_MARKER_END}
|
|
15070
|
-
`;
|
|
15071
|
-
function installHookFile(hookFile) {
|
|
15072
|
-
let content = "";
|
|
15073
|
-
if (fs6.existsSync(hookFile)) {
|
|
15074
|
-
content = fs6.readFileSync(hookFile, "utf-8");
|
|
15075
|
-
} else {
|
|
15076
|
-
content = "#!/bin/sh\n";
|
|
15077
|
-
}
|
|
15078
|
-
if (content.includes(HOOK_MARKER_BEGIN)) {
|
|
15079
|
-
return "exists";
|
|
15567
|
+
function modulesToBlocks(modules) {
|
|
15568
|
+
let out = "";
|
|
15569
|
+
for (const bit of modules) {
|
|
15570
|
+
out += bit === "1" ? "\u2588" : " ";
|
|
15080
15571
|
}
|
|
15081
|
-
|
|
15082
|
-
return "installed";
|
|
15572
|
+
return out;
|
|
15083
15573
|
}
|
|
15084
|
-
function
|
|
15085
|
-
|
|
15086
|
-
const
|
|
15087
|
-
if (
|
|
15088
|
-
|
|
15089
|
-
|
|
15090
|
-
|
|
15091
|
-
|
|
15574
|
+
function pickBarcodePayload(input) {
|
|
15575
|
+
const maxChars = input.maxChars ?? 24;
|
|
15576
|
+
const candidates = [];
|
|
15577
|
+
if (input.publicUrl) candidates.push(input.publicUrl);
|
|
15578
|
+
if (input.displayHost && input.receiptId) {
|
|
15579
|
+
candidates.push(`${input.displayHost}/r/${input.receiptId}`);
|
|
15580
|
+
}
|
|
15581
|
+
candidates.push(input.receiptId);
|
|
15582
|
+
if (input.receiptId.length > 12) {
|
|
15583
|
+
candidates.push(input.receiptId.replace(/^rec_/, "").slice(0, 12));
|
|
15584
|
+
}
|
|
15585
|
+
for (const c3 of candidates) {
|
|
15586
|
+
if (c3.length <= maxChars) return c3;
|
|
15587
|
+
}
|
|
15588
|
+
return candidates[candidates.length - 1].slice(0, maxChars);
|
|
15092
15589
|
}
|
|
15093
|
-
|
|
15094
|
-
|
|
15590
|
+
|
|
15591
|
+
// src/theme.ts
|
|
15592
|
+
var THEME = {
|
|
15593
|
+
primary: "#cc785c",
|
|
15594
|
+
primaryActive: "#a9583e",
|
|
15595
|
+
primaryDisabled: "#e6dfd8",
|
|
15596
|
+
ink: "#141413",
|
|
15597
|
+
body: "#3d3d3a",
|
|
15598
|
+
bodyStrong: "#252523",
|
|
15599
|
+
muted: "#6c6a64",
|
|
15600
|
+
mutedSoft: "#8e8b82",
|
|
15601
|
+
hairline: "#e6dfd8",
|
|
15602
|
+
hairlineSoft: "#ebe6df",
|
|
15603
|
+
canvas: "#faf9f5",
|
|
15604
|
+
surfaceCard: "#efe9de",
|
|
15605
|
+
surfaceCreamStrong: "#e8e0d2",
|
|
15606
|
+
surfaceDark: "#181715",
|
|
15607
|
+
surfaceDarkElevated: "#252320",
|
|
15608
|
+
surfaceDarkSoft: "#1f1e1b",
|
|
15609
|
+
teal: "#5db8a6",
|
|
15610
|
+
amber: "#e8a55a",
|
|
15611
|
+
success: "#5db872",
|
|
15612
|
+
error: "#c64545"
|
|
15613
|
+
};
|
|
15614
|
+
var ansiHex = (hexColor) => {
|
|
15615
|
+
const num = parseInt(hexColor.replace("#", ""), 16);
|
|
15616
|
+
const r2 = num >> 16 & 255;
|
|
15617
|
+
const g = num >> 8 & 255;
|
|
15618
|
+
const b2 = num & 255;
|
|
15619
|
+
return (text) => `\x1B[38;2;${r2};${g};${b2}m${text}\x1B[39m`;
|
|
15620
|
+
};
|
|
15621
|
+
var colors = {
|
|
15622
|
+
coral: ansiHex(THEME.primary),
|
|
15623
|
+
coralActive: ansiHex(THEME.primaryActive),
|
|
15624
|
+
muted: ansiHex(THEME.muted),
|
|
15625
|
+
mutedSoft: ansiHex(THEME.mutedSoft),
|
|
15626
|
+
teal: ansiHex(THEME.teal),
|
|
15627
|
+
amber: ansiHex(THEME.amber),
|
|
15628
|
+
green: ansiHex(THEME.success),
|
|
15629
|
+
red: ansiHex(THEME.error),
|
|
15630
|
+
hairline: ansiHex(THEME.hairline),
|
|
15631
|
+
canvas: ansiHex(THEME.canvas)
|
|
15632
|
+
};
|
|
15633
|
+
var stripAnsi = (str) => {
|
|
15634
|
+
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1B\([B0]/g, "");
|
|
15635
|
+
};
|
|
15636
|
+
var visibleWidth = (str) => {
|
|
15637
|
+
return stripAnsi(str).length;
|
|
15638
|
+
};
|
|
15639
|
+
|
|
15640
|
+
// src/receipt-view.ts
|
|
15641
|
+
function buildTerminalReceipt(receipt, publicUrl) {
|
|
15642
|
+
const lines = [];
|
|
15643
|
+
const coral = colors.coral;
|
|
15644
|
+
const green = colors.green;
|
|
15645
|
+
const red = colors.red;
|
|
15646
|
+
const teal = colors.teal;
|
|
15647
|
+
const INNER_WIDTH2 = 52;
|
|
15648
|
+
const push = (line) => lines.push(line);
|
|
15649
|
+
const printRow = (content, width = INNER_WIDTH2) => {
|
|
15650
|
+
const visLen = visibleWidth(content);
|
|
15651
|
+
const pad = Math.max(0, width - visLen);
|
|
15652
|
+
push(` | ${content}${" ".repeat(pad)} |`);
|
|
15653
|
+
};
|
|
15654
|
+
const printRowSplit = (left, right, width = INNER_WIDTH2) => {
|
|
15655
|
+
const leftVis = visibleWidth(left);
|
|
15656
|
+
const rightVis = visibleWidth(right);
|
|
15657
|
+
const pad = Math.max(1, width - leftVis - rightVis);
|
|
15658
|
+
push(` | ${left}${" ".repeat(pad)}${right} |`);
|
|
15659
|
+
};
|
|
15660
|
+
const printCenteredRow = (content, width = INNER_WIDTH2) => {
|
|
15661
|
+
const visLen = visibleWidth(content);
|
|
15662
|
+
const totalPad = Math.max(0, width - visLen);
|
|
15663
|
+
const leftPad = Math.floor(totalPad / 2);
|
|
15664
|
+
const rightPad = totalPad - leftPad;
|
|
15665
|
+
push(` | ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} |`);
|
|
15666
|
+
};
|
|
15667
|
+
const printDivider = (char = "=", width = INNER_WIDTH2) => {
|
|
15668
|
+
push(` | ${char.repeat(width)} |`);
|
|
15669
|
+
};
|
|
15670
|
+
const totalTokens = (receipt.ai.tokens.input + receipt.ai.tokens.output).toLocaleString();
|
|
15671
|
+
const inputK = `${Math.round(receipt.ai.tokens.input / 1e3)}k`;
|
|
15672
|
+
const outputK = `${Math.round(receipt.ai.tokens.output / 1e3)}k`;
|
|
15673
|
+
const costPrefix = receipt.ai.mode === "verified" ? "$" : "~$";
|
|
15674
|
+
const confidencePercent = `${Math.round(receipt.ai.confidence * 100)}%`;
|
|
15675
|
+
push("");
|
|
15676
|
+
push(" " + import_picocolors.default.bold(coral("/\\".repeat(28))));
|
|
15677
|
+
printCenteredRow(import_picocolors.default.bold(import_picocolors.default.white("Q O D E W K")));
|
|
15678
|
+
printCenteredRow(coral("*** PROOF OF SHIPMENT ***"));
|
|
15679
|
+
printRow("");
|
|
15680
|
+
printRowSplit(
|
|
15681
|
+
`ID: ${receipt.receipt.id.slice(0, 24)}`,
|
|
15682
|
+
`DATE: ${receipt.receipt.createdAt.slice(0, 10)}`
|
|
15683
|
+
);
|
|
15684
|
+
printRowSplit(
|
|
15685
|
+
`REPO: ${receipt.repository.projectAlias.slice(0, 18)}`,
|
|
15686
|
+
`BRANCH: ${receipt.repository.branch.slice(0, 16)}`
|
|
15687
|
+
);
|
|
15688
|
+
if (receipt.ai.task) {
|
|
15689
|
+
const taskClean = receipt.ai.task.length > 44 ? receipt.ai.task.slice(0, 43) + "\u2026" : receipt.ai.task;
|
|
15690
|
+
printRow(`TASK: ${taskClean}`);
|
|
15691
|
+
}
|
|
15692
|
+
printDivider("=");
|
|
15693
|
+
const itemsHeader = receipt.repository.commitsCount && receipt.repository.commitsCount > 1 ? `ITEMS CHANGED (${receipt.repository.commitsCount} COMMITS)` : "ITEMS CHANGED";
|
|
15694
|
+
printRowSplit(itemsHeader, "QTY");
|
|
15695
|
+
printDivider("-");
|
|
15696
|
+
printRowSplit("Files Touched", String(receipt.mutation.files));
|
|
15697
|
+
printRowSplit("Lines Inserted", green("+ " + receipt.mutation.insertions));
|
|
15698
|
+
printRowSplit("Lines Deleted", red("- " + receipt.mutation.deletions));
|
|
15699
|
+
printRowSplit(
|
|
15700
|
+
"Net Code Delta",
|
|
15701
|
+
teal((receipt.mutation.netLines >= 0 ? "+ " : "- ") + Math.abs(receipt.mutation.netLines))
|
|
15702
|
+
);
|
|
15703
|
+
printDivider("-");
|
|
15704
|
+
printRow("AI TELEMETRY & ATTRIBUTION");
|
|
15705
|
+
const provString = receipt.ai.provider + " \xB7 " + (receipt.ai.model || "Unknown");
|
|
15706
|
+
const cleanProv = provString.length > 40 ? provString.slice(0, 39) + "\u2026" : provString;
|
|
15707
|
+
printRow(`Provider: ${cleanProv}`);
|
|
15708
|
+
if (receipt.ai.sessions && receipt.ai.sessions.length > 1) {
|
|
15709
|
+
const others = receipt.ai.sessions.slice(1).map((s) => s.provider).filter((p2, i2, arr) => arr.indexOf(p2) === i2 && p2 !== receipt.ai.provider);
|
|
15710
|
+
if (others.length > 0) {
|
|
15711
|
+
printRow(import_picocolors.default.dim(`Also seen: ${others.join(", ")}`));
|
|
15712
|
+
}
|
|
15713
|
+
}
|
|
15714
|
+
if (receipt.ai.aiWrittenRatio !== void 0) {
|
|
15715
|
+
const aiPct = Math.round(receipt.ai.aiWrittenRatio * 100);
|
|
15716
|
+
printRowSplit("AI Written Code", `${aiPct}% (Human: ${100 - aiPct}%)`);
|
|
15717
|
+
}
|
|
15718
|
+
const tokenDetail = `${inputK} in (${Math.round(receipt.ai.tokens.cached / 1e3)}k cached) / ${outputK} out`;
|
|
15719
|
+
const cleanTokens = tokenDetail.length > 40 ? tokenDetail.slice(0, 39) + "\u2026" : tokenDetail;
|
|
15720
|
+
printRow(`Tokens: ${cleanTokens}`);
|
|
15721
|
+
printRowSplit("Total Tokens:", totalTokens);
|
|
15722
|
+
printDivider("=");
|
|
15723
|
+
const costLabel = receipt.ai.mode === "verified" ? "VERIFIED AI COST" : "ESTIMATED AI COST";
|
|
15724
|
+
printRowSplit(costLabel, import_picocolors.default.bold(coral(costPrefix + receipt.ai.cost.toFixed(2))));
|
|
15725
|
+
printRowSplit(`CONFIDENCE: ${confidencePercent}`, `[Mode: ${receipt.ai.mode}]`);
|
|
15726
|
+
printDivider("=");
|
|
15727
|
+
printRow("");
|
|
15728
|
+
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || process.env.QODEWK_APP_URL || "https://qodewk.flinkeo.online";
|
|
15729
|
+
const isPublished = Boolean(publicUrl);
|
|
15730
|
+
const displayHost = baseUrl.replace(/^https?:\/\//, "");
|
|
15731
|
+
const barcodePayload = pickBarcodePayload({
|
|
15732
|
+
publicUrl,
|
|
15733
|
+
receiptId: receipt.receipt.id,
|
|
15734
|
+
displayHost,
|
|
15735
|
+
maxChars: 28
|
|
15736
|
+
});
|
|
15737
|
+
const barcodeRows = renderTerminalBarcode(barcodePayload, {
|
|
15738
|
+
maxWidth: INNER_WIDTH2,
|
|
15739
|
+
height: 3,
|
|
15740
|
+
quietZone: 8
|
|
15741
|
+
});
|
|
15742
|
+
for (const barRow of barcodeRows) {
|
|
15743
|
+
printCenteredRow(import_picocolors.default.bold(barRow));
|
|
15744
|
+
}
|
|
15745
|
+
if (isPublished) {
|
|
15746
|
+
printCenteredRow(import_picocolors.default.cyan(displayHost));
|
|
15747
|
+
printCenteredRow(import_picocolors.default.underline(import_picocolors.default.cyan(`r/${receipt.receipt.id}`)));
|
|
15748
|
+
} else {
|
|
15749
|
+
printCenteredRow(import_picocolors.default.yellow("[ LOCAL RECORD \u2014 NOT PUBLISHED ]"));
|
|
15750
|
+
}
|
|
15751
|
+
printRow("");
|
|
15752
|
+
if (process.env.QODEWK_TELEMETRY === "off") {
|
|
15753
|
+
printRow(` ${teal("[\u2713]")} QODEWK_TELEMETRY=off (Cloud sync disabled)`);
|
|
15754
|
+
}
|
|
15755
|
+
printRow(` ${green("[\u2713]")} Source code was never uploaded to Qodewk`);
|
|
15756
|
+
push(" " + import_picocolors.default.bold(coral("\\/".repeat(28))));
|
|
15757
|
+
push("");
|
|
15758
|
+
if (isPublished && publicUrl) {
|
|
15759
|
+
push(` ${import_picocolors.default.dim("Public Receipt:")} ${import_picocolors.default.underline(import_picocolors.default.cyan(publicUrl))}`);
|
|
15760
|
+
} else {
|
|
15761
|
+
push(` ${import_picocolors.default.dim("Saved to local DB:")} ${import_picocolors.default.dim("~/.qodewk/state.db")}`);
|
|
15762
|
+
push(` ${import_picocolors.default.dim("To publish & get shareable URL:")} ${import_picocolors.default.cyan("qodewk share")}`);
|
|
15763
|
+
push(` ${import_picocolors.default.dim("Interactive menu:")} ${import_picocolors.default.cyan("qodewk menu")}`);
|
|
15764
|
+
}
|
|
15765
|
+
push("");
|
|
15766
|
+
return lines.join("\n");
|
|
15767
|
+
}
|
|
15768
|
+
async function renderTerminalReceipt(receipt, publicUrl) {
|
|
15769
|
+
console.log(buildTerminalReceipt(receipt, publicUrl));
|
|
15770
|
+
}
|
|
15771
|
+
async function outputReceipt(receipt, options, publicUrl) {
|
|
15772
|
+
const format = options.json ? "json" : options.format || "terminal";
|
|
15773
|
+
let content;
|
|
15774
|
+
if (format === "json") {
|
|
15775
|
+
content = JSON.stringify(receipt, null, 2);
|
|
15776
|
+
} else if (format === "markdown") {
|
|
15777
|
+
content = formatMarkdownReceipt(receipt, publicUrl);
|
|
15778
|
+
} else {
|
|
15779
|
+
content = buildTerminalReceipt(receipt, publicUrl);
|
|
15780
|
+
}
|
|
15781
|
+
if (options.out) {
|
|
15782
|
+
const fileContent = format === "terminal" ? stripAnsi(content) : content;
|
|
15783
|
+
fs8.writeFileSync(options.out, fileContent.endsWith("\n") ? fileContent : fileContent + "\n", "utf-8");
|
|
15784
|
+
console.log(import_picocolors.default.green(`\u2713 Receipt written to ${options.out}`));
|
|
15785
|
+
}
|
|
15786
|
+
if (!options.out) {
|
|
15787
|
+
if (format === "terminal") {
|
|
15788
|
+
console.log(content);
|
|
15789
|
+
} else {
|
|
15790
|
+
console.log(content);
|
|
15791
|
+
}
|
|
15792
|
+
}
|
|
15793
|
+
}
|
|
15794
|
+
|
|
15795
|
+
// src/hooks.ts
|
|
15796
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
15797
|
+
var path9 = __toESM(require("path"), 1);
|
|
15798
|
+
var HOOK_MARKER_BEGIN = "# --- BEGIN QODEWK HOOK ---";
|
|
15799
|
+
var HOOK_MARKER_END = "# --- END QODEWK HOOK ---";
|
|
15800
|
+
var HOOK_SNIPPET = `
|
|
15801
|
+
${HOOK_MARKER_BEGIN}
|
|
15802
|
+
# Non-blocking Qodewk background recorder (< 5ms)
|
|
15803
|
+
if command -v qodewk >/dev/null 2>&1 || command -v pnpm >/dev/null 2>&1 || [ -f "./node_modules/.bin/qodewk" ]; then
|
|
15804
|
+
( ( qodewk record || pnpm qodewk record || npx qodewk record ) >/dev/null 2>&1 & )
|
|
15805
|
+
fi
|
|
15806
|
+
${HOOK_MARKER_END}
|
|
15807
|
+
`;
|
|
15808
|
+
function resolveGitHooksDir(cwd = process.cwd()) {
|
|
15809
|
+
const gitPath = path9.join(cwd, ".git");
|
|
15810
|
+
if (!fs9.existsSync(gitPath)) return null;
|
|
15811
|
+
let gitCommonDir;
|
|
15812
|
+
const stat = fs9.statSync(gitPath);
|
|
15813
|
+
if (stat.isDirectory()) {
|
|
15814
|
+
gitCommonDir = gitPath;
|
|
15815
|
+
} else {
|
|
15816
|
+
const content = fs9.readFileSync(gitPath, "utf-8");
|
|
15817
|
+
const match = content.match(/gitdir:\s*(.+)/i);
|
|
15818
|
+
if (!match?.[1]) return null;
|
|
15819
|
+
let gitDir = match[1].trim();
|
|
15820
|
+
if (!path9.isAbsolute(gitDir)) {
|
|
15821
|
+
gitDir = path9.resolve(cwd, gitDir);
|
|
15822
|
+
}
|
|
15823
|
+
const commonFile = path9.join(gitDir, "commondir");
|
|
15824
|
+
if (fs9.existsSync(commonFile)) {
|
|
15825
|
+
let common = fs9.readFileSync(commonFile, "utf-8").trim();
|
|
15826
|
+
if (!path9.isAbsolute(common)) {
|
|
15827
|
+
common = path9.resolve(gitDir, common);
|
|
15828
|
+
}
|
|
15829
|
+
gitCommonDir = common;
|
|
15830
|
+
} else if (path9.basename(path9.dirname(gitDir)) === "worktrees") {
|
|
15831
|
+
gitCommonDir = path9.dirname(path9.dirname(gitDir));
|
|
15832
|
+
} else {
|
|
15833
|
+
gitCommonDir = gitDir;
|
|
15834
|
+
}
|
|
15835
|
+
}
|
|
15836
|
+
return path9.join(gitCommonDir, "hooks");
|
|
15837
|
+
}
|
|
15838
|
+
function checkHookStatus(hooksDir) {
|
|
15839
|
+
if (!hooksDir || !fs9.existsSync(hooksDir)) {
|
|
15840
|
+
return {
|
|
15841
|
+
isGit: Boolean(hooksDir),
|
|
15842
|
+
hooksDir,
|
|
15843
|
+
postCommitInstalled: false,
|
|
15844
|
+
postRewriteInstalled: false
|
|
15845
|
+
};
|
|
15846
|
+
}
|
|
15847
|
+
const postCommit = path9.join(hooksDir, "post-commit");
|
|
15848
|
+
const postRewrite = path9.join(hooksDir, "post-rewrite");
|
|
15849
|
+
const hasHook = (p2) => {
|
|
15850
|
+
if (!fs9.existsSync(p2)) return false;
|
|
15851
|
+
try {
|
|
15852
|
+
const content = fs9.readFileSync(p2, "utf-8");
|
|
15853
|
+
return content.includes(HOOK_MARKER_BEGIN);
|
|
15854
|
+
} catch {
|
|
15855
|
+
return false;
|
|
15856
|
+
}
|
|
15857
|
+
};
|
|
15858
|
+
return {
|
|
15859
|
+
isGit: true,
|
|
15860
|
+
hooksDir,
|
|
15861
|
+
postCommitInstalled: hasHook(postCommit),
|
|
15862
|
+
postRewriteInstalled: hasHook(postRewrite)
|
|
15863
|
+
};
|
|
15864
|
+
}
|
|
15865
|
+
function installHookFile(hookFile) {
|
|
15866
|
+
let content = "";
|
|
15867
|
+
if (fs9.existsSync(hookFile)) {
|
|
15868
|
+
content = fs9.readFileSync(hookFile, "utf-8");
|
|
15869
|
+
} else {
|
|
15870
|
+
content = "#!/bin/sh\n";
|
|
15871
|
+
}
|
|
15872
|
+
if (content.includes(HOOK_MARKER_BEGIN)) {
|
|
15873
|
+
return "exists";
|
|
15874
|
+
}
|
|
15875
|
+
fs9.writeFileSync(hookFile, content + HOOK_SNIPPET, { mode: 493 });
|
|
15876
|
+
return "installed";
|
|
15877
|
+
}
|
|
15878
|
+
function uninstallHookFile(hookFile) {
|
|
15879
|
+
if (!fs9.existsSync(hookFile)) return "absent";
|
|
15880
|
+
const content = fs9.readFileSync(hookFile, "utf-8");
|
|
15881
|
+
if (!content.includes(HOOK_MARKER_BEGIN)) return "missing";
|
|
15882
|
+
const regex = new RegExp(`\\n?${HOOK_MARKER_BEGIN}[\\s\\S]*?${HOOK_MARKER_END}\\n?`, "g");
|
|
15883
|
+
const updated = content.replace(regex, "");
|
|
15884
|
+
fs9.writeFileSync(hookFile, updated, { mode: 493 });
|
|
15885
|
+
return "removed";
|
|
15886
|
+
}
|
|
15887
|
+
|
|
15888
|
+
// src/menu.ts
|
|
15889
|
+
var readline = __toESM(require("readline"), 1);
|
|
15890
|
+
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
15891
|
+
var INNER_WIDTH = 58;
|
|
15892
|
+
var SHARE_PAYLOAD_MAX_BYTES = 5e4;
|
|
15893
|
+
var MENU_ITEMS = [
|
|
15894
|
+
{
|
|
15895
|
+
id: "receipt",
|
|
15896
|
+
key: "1",
|
|
15897
|
+
label: "Generate Local Receipt",
|
|
15898
|
+
description: "Inspect git diff and print digital receipt"
|
|
15899
|
+
},
|
|
15900
|
+
{
|
|
15901
|
+
id: "audit",
|
|
15902
|
+
key: "2",
|
|
15903
|
+
label: "Audit Branch or Revision Range",
|
|
15904
|
+
description: "Compare against base commit or upstream branch"
|
|
15905
|
+
},
|
|
15906
|
+
{
|
|
15907
|
+
id: "share",
|
|
15908
|
+
key: "3",
|
|
15909
|
+
label: "Publish Receipt to Cloud",
|
|
15910
|
+
description: "Privacy-safe shareable URL & claim token"
|
|
15911
|
+
},
|
|
15912
|
+
{
|
|
15913
|
+
id: "hooks",
|
|
15914
|
+
key: "4",
|
|
15915
|
+
label: "Configure Git Hooks",
|
|
15916
|
+
description: "Non-blocking background telemetry recording"
|
|
15917
|
+
},
|
|
15918
|
+
{
|
|
15919
|
+
id: "storage",
|
|
15920
|
+
key: "5",
|
|
15921
|
+
label: "Database & Storage Status",
|
|
15922
|
+
description: "Inspect local SQLite (~/.qodewk/state.db) records"
|
|
15923
|
+
},
|
|
15924
|
+
{
|
|
15925
|
+
id: "exit",
|
|
15926
|
+
key: "0",
|
|
15927
|
+
label: "Exit",
|
|
15928
|
+
description: "Return to shell"
|
|
15929
|
+
}
|
|
15930
|
+
];
|
|
15931
|
+
function buildMenuFrame(selectedIndex, items = MENU_ITEMS) {
|
|
15932
|
+
const lines = [];
|
|
15933
|
+
const coral = colors.coral;
|
|
15934
|
+
const mutedSoft = colors.mutedSoft;
|
|
15935
|
+
const amber = colors.amber;
|
|
15936
|
+
const border = colors.mutedSoft;
|
|
15937
|
+
const push = (line) => lines.push(line);
|
|
15938
|
+
const printRow = (content, width = INNER_WIDTH) => {
|
|
15939
|
+
const visLen = visibleWidth(content);
|
|
15940
|
+
const pad = Math.max(0, width - visLen);
|
|
15941
|
+
push(` ${border("\u2502")} ${content}${" ".repeat(pad)} ${border("\u2502")}`);
|
|
15942
|
+
};
|
|
15943
|
+
const printCenteredRow = (content, width = INNER_WIDTH) => {
|
|
15944
|
+
const visLen = visibleWidth(content);
|
|
15945
|
+
const totalPad = Math.max(0, width - visLen);
|
|
15946
|
+
const leftPad = Math.floor(totalPad / 2);
|
|
15947
|
+
const rightPad = totalPad - leftPad;
|
|
15948
|
+
push(` ${border("\u2502")} ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} ${border("\u2502")}`);
|
|
15949
|
+
};
|
|
15950
|
+
const printDivider = (width = INNER_WIDTH) => {
|
|
15951
|
+
push(` ${border("\u251C" + "\u2500".repeat(width + 2) + "\u2524")}`);
|
|
15952
|
+
};
|
|
15953
|
+
push("");
|
|
15954
|
+
push(` ${border("\u250C" + "\u2500".repeat(INNER_WIDTH + 2) + "\u2510")}`);
|
|
15955
|
+
printCenteredRow(import_picocolors2.default.bold(import_picocolors2.default.white("Q O D E W K")));
|
|
15956
|
+
printCenteredRow(coral("Telemetry Control Panel"));
|
|
15957
|
+
printDivider();
|
|
15958
|
+
printCenteredRow(mutedSoft("Use \u2191 / \u2193 to navigate \xB7 Enter to select \xB7 q to quit"));
|
|
15959
|
+
printDivider();
|
|
15960
|
+
printRow("");
|
|
15961
|
+
const mainItems = items.filter((item) => item.id !== "exit");
|
|
15962
|
+
const exitItem = items.find((item) => item.id === "exit");
|
|
15963
|
+
for (let i2 = 0; i2 < mainItems.length; i2++) {
|
|
15964
|
+
const item = mainItems[i2];
|
|
15965
|
+
const itemIndex = items.indexOf(item);
|
|
15966
|
+
const isSelected = itemIndex === selectedIndex;
|
|
15967
|
+
if (isSelected) {
|
|
15968
|
+
const pointer = import_picocolors2.default.bold(coral("\u203A"));
|
|
15969
|
+
const keyTag = import_picocolors2.default.bold(coral(`[${item.key}]`));
|
|
15970
|
+
const label = import_picocolors2.default.bold(import_picocolors2.default.white(item.label));
|
|
15971
|
+
printRow(` ${pointer} ${keyTag} ${label}`);
|
|
15972
|
+
printRow(` ${amber(item.description)}`);
|
|
15973
|
+
} else {
|
|
15974
|
+
const keyTag = mutedSoft(`[${item.key}]`);
|
|
15975
|
+
const label = import_picocolors2.default.dim(import_picocolors2.default.white(item.label));
|
|
15976
|
+
printRow(` ${keyTag} ${label}`);
|
|
15977
|
+
printRow(` ${import_picocolors2.default.dim(item.description)}`);
|
|
15978
|
+
}
|
|
15979
|
+
if (i2 < mainItems.length - 1) {
|
|
15980
|
+
printRow("");
|
|
15981
|
+
}
|
|
15982
|
+
}
|
|
15983
|
+
printRow("");
|
|
15984
|
+
if (exitItem) {
|
|
15985
|
+
printDivider();
|
|
15986
|
+
const exitIndex = items.indexOf(exitItem);
|
|
15987
|
+
const isSelected = exitIndex === selectedIndex;
|
|
15988
|
+
if (isSelected) {
|
|
15989
|
+
const pointer = import_picocolors2.default.bold(coral("\u203A"));
|
|
15990
|
+
const keyTag = import_picocolors2.default.bold(coral(`[${exitItem.key}]`));
|
|
15991
|
+
const label = import_picocolors2.default.bold(import_picocolors2.default.white(exitItem.label));
|
|
15992
|
+
printRow(` ${pointer} ${keyTag} ${label}`);
|
|
15993
|
+
printRow(` ${amber(exitItem.description)}`);
|
|
15994
|
+
} else {
|
|
15995
|
+
const keyTag = mutedSoft(`[${exitItem.key}]`);
|
|
15996
|
+
const label = import_picocolors2.default.dim(import_picocolors2.default.white(exitItem.label));
|
|
15997
|
+
printRow(` ${keyTag} ${label}`);
|
|
15998
|
+
printRow(` ${import_picocolors2.default.dim(exitItem.description)}`);
|
|
15999
|
+
}
|
|
16000
|
+
}
|
|
16001
|
+
printDivider();
|
|
16002
|
+
printCenteredRow(import_picocolors2.default.dim("[\u2713] Source code was never uploaded to Qodewk"));
|
|
16003
|
+
push(` ${border("\u2514" + "\u2500".repeat(INNER_WIDTH + 2) + "\u2518")}`);
|
|
16004
|
+
push("");
|
|
16005
|
+
return lines.join("\n");
|
|
16006
|
+
}
|
|
16007
|
+
function askLine(promptText) {
|
|
16008
|
+
return new Promise((resolve4) => {
|
|
16009
|
+
const rl = readline.createInterface({
|
|
16010
|
+
input: process.stdin,
|
|
16011
|
+
output: process.stdout
|
|
16012
|
+
});
|
|
16013
|
+
rl.question(promptText, (answer) => {
|
|
16014
|
+
rl.close();
|
|
16015
|
+
resolve4(answer.trim());
|
|
16016
|
+
});
|
|
16017
|
+
});
|
|
16018
|
+
}
|
|
16019
|
+
function waitForKeyToReturn() {
|
|
16020
|
+
return new Promise((resolve4) => {
|
|
16021
|
+
console.log(import_picocolors2.default.dim("\n Press any key or Enter to return to menu..."));
|
|
16022
|
+
if (!process.stdin.isTTY) {
|
|
16023
|
+
resolve4();
|
|
16024
|
+
return;
|
|
16025
|
+
}
|
|
16026
|
+
const wasRaw = process.stdin.isRaw;
|
|
16027
|
+
process.stdin.setRawMode(true);
|
|
16028
|
+
process.stdin.resume();
|
|
16029
|
+
const onKey = () => {
|
|
16030
|
+
process.stdin.removeListener("data", onKey);
|
|
16031
|
+
if (wasRaw !== void 0) process.stdin.setRawMode(wasRaw);
|
|
16032
|
+
resolve4();
|
|
16033
|
+
};
|
|
16034
|
+
process.stdin.once("data", onKey);
|
|
16035
|
+
});
|
|
16036
|
+
}
|
|
16037
|
+
async function runInteractiveMenu() {
|
|
16038
|
+
if (!process.stdin.isTTY) {
|
|
16039
|
+
console.log(buildMenuFrame(0));
|
|
16040
|
+
console.log(import_picocolors2.default.yellow("Interactive menu requires a TTY terminal. Use `qodewk --help` for commands."));
|
|
16041
|
+
return;
|
|
16042
|
+
}
|
|
16043
|
+
let selectedIndex = 0;
|
|
16044
|
+
let active = true;
|
|
16045
|
+
let lastRenderedLinesCount = 0;
|
|
16046
|
+
const render = () => {
|
|
16047
|
+
const frame = buildMenuFrame(selectedIndex);
|
|
16048
|
+
const lineCount = frame.split("\n").length;
|
|
16049
|
+
if (lastRenderedLinesCount > 0) {
|
|
16050
|
+
readline.cursorTo(process.stdout, 0);
|
|
16051
|
+
readline.moveCursor(process.stdout, 0, -lastRenderedLinesCount);
|
|
16052
|
+
readline.clearScreenDown(process.stdout);
|
|
16053
|
+
}
|
|
16054
|
+
process.stdout.write(frame);
|
|
16055
|
+
lastRenderedLinesCount = lineCount;
|
|
16056
|
+
};
|
|
16057
|
+
const cleanup = () => {
|
|
16058
|
+
try {
|
|
16059
|
+
process.stdin.setRawMode(false);
|
|
16060
|
+
} catch {
|
|
16061
|
+
}
|
|
16062
|
+
process.stdout.write("\x1B[?25h");
|
|
16063
|
+
};
|
|
16064
|
+
process.on("exit", cleanup);
|
|
16065
|
+
const executeSelectedAction = async () => {
|
|
16066
|
+
cleanup();
|
|
16067
|
+
console.log("");
|
|
16068
|
+
lastRenderedLinesCount = 0;
|
|
16069
|
+
const selectedItem = MENU_ITEMS[selectedIndex];
|
|
16070
|
+
switch (selectedItem.id) {
|
|
16071
|
+
case "receipt": {
|
|
16072
|
+
console.log(import_picocolors2.default.dim(" [\xB7] Generating local receipt from git diff..."));
|
|
16073
|
+
try {
|
|
16074
|
+
const receipt = await generateReceipt({ isPublic: false });
|
|
16075
|
+
const db = new LocalStateDB();
|
|
16076
|
+
db.saveReceipt(receipt);
|
|
16077
|
+
db.close();
|
|
16078
|
+
await renderTerminalReceipt(receipt);
|
|
16079
|
+
} catch (err) {
|
|
16080
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16081
|
+
console.error(import_picocolors2.default.red(`
|
|
16082
|
+
Failed to generate receipt: ${message}`));
|
|
16083
|
+
}
|
|
16084
|
+
await waitForKeyToReturn();
|
|
16085
|
+
break;
|
|
16086
|
+
}
|
|
16087
|
+
case "audit": {
|
|
16088
|
+
console.log(import_picocolors2.default.bold(import_picocolors2.default.white("\n Audit Branch or Revision Diff")));
|
|
16089
|
+
console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
16090
|
+
let defaultBase = "origin/main";
|
|
16091
|
+
try {
|
|
16092
|
+
defaultBase = await detectDefaultBaseBranch(process.cwd());
|
|
16093
|
+
} catch {
|
|
16094
|
+
}
|
|
16095
|
+
const base = await askLine(
|
|
16096
|
+
` \u203A Base git ref or commit SHA [default: ${defaultBase}]: `
|
|
16097
|
+
);
|
|
16098
|
+
const head = await askLine(
|
|
16099
|
+
` \u203A Head git ref or commit SHA [default: HEAD]: `
|
|
16100
|
+
);
|
|
16101
|
+
console.log(import_picocolors2.default.dim("\n [\xB7] Auditing git revision range..."));
|
|
16102
|
+
try {
|
|
16103
|
+
const receipt = await generateReceipt({
|
|
16104
|
+
baseSha: base || defaultBase,
|
|
16105
|
+
headSha: head || "HEAD",
|
|
16106
|
+
isPublic: false
|
|
16107
|
+
});
|
|
16108
|
+
const db = new LocalStateDB();
|
|
16109
|
+
db.saveReceipt(receipt);
|
|
16110
|
+
db.close();
|
|
16111
|
+
await renderTerminalReceipt(receipt);
|
|
16112
|
+
} catch (err) {
|
|
16113
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16114
|
+
console.error(import_picocolors2.default.red(`
|
|
16115
|
+
Audit failed: ${message}`));
|
|
16116
|
+
}
|
|
16117
|
+
await waitForKeyToReturn();
|
|
16118
|
+
break;
|
|
16119
|
+
}
|
|
16120
|
+
case "share": {
|
|
16121
|
+
console.log(import_picocolors2.default.dim(" [\xB7] Generating and sanitizing receipt for cloud publishing..."));
|
|
16122
|
+
try {
|
|
16123
|
+
const receipt = await generateReceipt({ isPublic: false });
|
|
16124
|
+
if (process.env.QODEWK_TELEMETRY === "off") {
|
|
16125
|
+
console.log(import_picocolors2.default.yellow("\n Cloud publishing is disabled by QODEWK_TELEMETRY=off."));
|
|
16126
|
+
await renderTerminalReceipt(receipt);
|
|
16127
|
+
await waitForKeyToReturn();
|
|
16128
|
+
break;
|
|
16129
|
+
}
|
|
16130
|
+
const sanitized = sanitizeReceiptForShare(receipt);
|
|
16131
|
+
let body = JSON.stringify(sanitized);
|
|
16132
|
+
if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES && sanitized.ai.sessions) {
|
|
16133
|
+
const trimmed2 = {
|
|
16134
|
+
...sanitized,
|
|
16135
|
+
ai: { ...sanitized.ai, sessions: void 0 }
|
|
16136
|
+
};
|
|
16137
|
+
body = JSON.stringify(trimmed2);
|
|
16138
|
+
}
|
|
16139
|
+
const endpoint = process.env.QODEWK_API_URL || `${process.env.NEXT_PUBLIC_APP_URL || process.env.QODEWK_APP_URL || "https://qodewk.flinkeo.online"}/api/receipts`;
|
|
16140
|
+
console.log(import_picocolors2.default.dim(` [\xB7] Uploading metadata to ${endpoint}...`));
|
|
16141
|
+
const response = await fetch(endpoint, {
|
|
16142
|
+
method: "POST",
|
|
16143
|
+
headers: {
|
|
16144
|
+
"Content-Type": "application/json",
|
|
16145
|
+
"Content-Length": String(Buffer.byteLength(body, "utf-8"))
|
|
16146
|
+
},
|
|
16147
|
+
body
|
|
16148
|
+
});
|
|
16149
|
+
if (!response.ok) {
|
|
16150
|
+
const errText = await response.text().catch(() => "");
|
|
16151
|
+
throw new Error(`API responded with ${response.status}${errText ? `: ${errText.slice(0, 100)}` : ""}`);
|
|
16152
|
+
}
|
|
16153
|
+
const data = await response.json();
|
|
16154
|
+
const db = new LocalStateDB();
|
|
16155
|
+
db.saveReceipt(sanitized, data.claimToken);
|
|
16156
|
+
db.close();
|
|
16157
|
+
console.log("");
|
|
16158
|
+
console.log(colors.green(" [\u2713] Published successfully."));
|
|
16159
|
+
console.log(` ${import_picocolors2.default.dim("Public URL:")} ${import_picocolors2.default.underline(import_picocolors2.default.cyan(data.url))}`);
|
|
16160
|
+
console.log(` ${import_picocolors2.default.bold(colors.amber("Claim token:"))} ${colors.amber(data.claimToken)}`);
|
|
16161
|
+
console.log(import_picocolors2.default.dim(" (Saved to ~/.qodewk/state.db for future authorship proofs)\n"));
|
|
16162
|
+
await renderTerminalReceipt(sanitized, data.url);
|
|
16163
|
+
} catch (err) {
|
|
16164
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16165
|
+
console.error(import_picocolors2.default.red(`
|
|
16166
|
+
Share failed: ${message}`));
|
|
16167
|
+
}
|
|
16168
|
+
await waitForKeyToReturn();
|
|
16169
|
+
break;
|
|
16170
|
+
}
|
|
16171
|
+
case "hooks": {
|
|
16172
|
+
await manageHooksSubmenu();
|
|
16173
|
+
break;
|
|
16174
|
+
}
|
|
16175
|
+
case "storage": {
|
|
16176
|
+
await showStorageStatus();
|
|
16177
|
+
break;
|
|
16178
|
+
}
|
|
16179
|
+
case "exit": {
|
|
16180
|
+
active = false;
|
|
16181
|
+
cleanup();
|
|
16182
|
+
console.log(import_picocolors2.default.dim(" Exited Qodewk.\n"));
|
|
16183
|
+
process.exit(0);
|
|
16184
|
+
return;
|
|
16185
|
+
}
|
|
16186
|
+
}
|
|
16187
|
+
};
|
|
16188
|
+
const manageHooksSubmenu = async () => {
|
|
16189
|
+
const hooksDir = resolveGitHooksDir();
|
|
16190
|
+
const status = checkHookStatus(hooksDir);
|
|
16191
|
+
console.log(import_picocolors2.default.bold(import_picocolors2.default.white("\n Qodewk Git Hooks Management")));
|
|
16192
|
+
console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
16193
|
+
if (!status.isGit) {
|
|
16194
|
+
console.log(import_picocolors2.default.yellow(" Not inside a Git repository. Hooks cannot be configured."));
|
|
16195
|
+
await waitForKeyToReturn();
|
|
16196
|
+
return;
|
|
16197
|
+
}
|
|
16198
|
+
console.log(` Hooks directory: ${import_picocolors2.default.dim(status.hooksDir || "None")}`);
|
|
16199
|
+
console.log(
|
|
16200
|
+
` post-commit: ${status.postCommitInstalled ? colors.green("[\u2713 Installed]") : import_picocolors2.default.dim("[\xB7 Not installed]")}`
|
|
16201
|
+
);
|
|
16202
|
+
console.log(
|
|
16203
|
+
` post-rewrite: ${status.postRewriteInstalled ? colors.green("[\u2713 Installed]") : import_picocolors2.default.dim("[\xB7 Not installed]")}`
|
|
16204
|
+
);
|
|
16205
|
+
console.log("");
|
|
16206
|
+
console.log(" [1] Install non-blocking hooks (< 5ms background recorder)");
|
|
16207
|
+
console.log(" [2] Uninstall Qodewk hooks");
|
|
16208
|
+
console.log(" [0] Back to main menu");
|
|
16209
|
+
console.log("");
|
|
16210
|
+
const choice = await askLine(" \u203A Select option [0-2]: ");
|
|
16211
|
+
if (choice === "1") {
|
|
16212
|
+
if (status.hooksDir) {
|
|
16213
|
+
const path11 = await import("path");
|
|
16214
|
+
const targets = ["post-commit", "post-rewrite"];
|
|
16215
|
+
for (const t2 of targets) {
|
|
16216
|
+
installHookFile(path11.join(status.hooksDir, t2));
|
|
16217
|
+
}
|
|
16218
|
+
console.log(colors.green("\n [\u2713] Non-blocking hooks installed successfully."));
|
|
16219
|
+
}
|
|
16220
|
+
} else if (choice === "2") {
|
|
16221
|
+
if (status.hooksDir) {
|
|
16222
|
+
const path11 = await import("path");
|
|
16223
|
+
const targets = ["post-commit", "post-rewrite"];
|
|
16224
|
+
for (const t2 of targets) {
|
|
16225
|
+
uninstallHookFile(path11.join(status.hooksDir, t2));
|
|
16226
|
+
}
|
|
16227
|
+
console.log(colors.green("\n [\u2713] Qodewk hooks removed."));
|
|
16228
|
+
}
|
|
16229
|
+
}
|
|
16230
|
+
await waitForKeyToReturn();
|
|
16231
|
+
};
|
|
16232
|
+
const showStorageStatus = async () => {
|
|
16233
|
+
console.log(import_picocolors2.default.bold(import_picocolors2.default.white("\n Qodewk Local Database & Storage Status")));
|
|
16234
|
+
console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
16235
|
+
try {
|
|
16236
|
+
const db = new LocalStateDB();
|
|
16237
|
+
const stats = db.getStats();
|
|
16238
|
+
const recent = db.getRecentReceipts(5);
|
|
16239
|
+
db.close();
|
|
16240
|
+
console.log(` Database path: ${import_picocolors2.default.dim("~/.qodewk/state.db")}`);
|
|
16241
|
+
console.log(` Total saved receipts: ${import_picocolors2.default.bold(import_picocolors2.default.white(String(stats.totalReceipts)))}`);
|
|
16242
|
+
console.log(` Total agent footprints: ${import_picocolors2.default.bold(import_picocolors2.default.white(String(stats.totalFootprints)))}`);
|
|
16243
|
+
console.log("");
|
|
16244
|
+
if (recent.length === 0) {
|
|
16245
|
+
console.log(import_picocolors2.default.dim(" No stored receipts yet. Run 'Generate Local Receipt' to record your first."));
|
|
16246
|
+
} else {
|
|
16247
|
+
console.log(import_picocolors2.default.dim(" Recent Receipts:"));
|
|
16248
|
+
console.log(import_picocolors2.default.dim(" " + "ID".padEnd(26) + "DATE".padEnd(12) + "BRANCH".padEnd(18) + "COST"));
|
|
16249
|
+
console.log(import_picocolors2.default.dim(" " + "\u2500".repeat(60)));
|
|
16250
|
+
for (const item of recent) {
|
|
16251
|
+
const id = item.receipt.receipt.id.slice(0, 24).padEnd(26);
|
|
16252
|
+
const date = item.receipt.receipt.createdAt.slice(0, 10).padEnd(12);
|
|
16253
|
+
const branch = (item.receipt.repository.branch || "unknown").slice(0, 16).padEnd(18);
|
|
16254
|
+
const cost = colors.coral(`$${item.receipt.ai.cost.toFixed(2)}`);
|
|
16255
|
+
console.log(` ${id}${date}${branch}${cost}`);
|
|
16256
|
+
}
|
|
16257
|
+
}
|
|
16258
|
+
console.log("");
|
|
16259
|
+
console.log(` ${colors.green("[\u2713]")} ${import_picocolors2.default.dim("Privacy guarantee: raw source code is never stored in SQLite")}`);
|
|
16260
|
+
} catch (err) {
|
|
16261
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16262
|
+
console.error(import_picocolors2.default.red(` Failed to inspect storage: ${message}`));
|
|
16263
|
+
}
|
|
16264
|
+
await waitForKeyToReturn();
|
|
16265
|
+
};
|
|
16266
|
+
readline.emitKeypressEvents(process.stdin);
|
|
16267
|
+
const startLoop = () => {
|
|
16268
|
+
process.stdout.write("\x1B[?25l");
|
|
16269
|
+
process.stdin.setRawMode(true);
|
|
16270
|
+
process.stdin.resume();
|
|
16271
|
+
render();
|
|
16272
|
+
const onKeypress = async (_str, key) => {
|
|
16273
|
+
if (!active) return;
|
|
16274
|
+
if (key.ctrl && key.name === "c") {
|
|
16275
|
+
cleanup();
|
|
16276
|
+
process.exit(0);
|
|
16277
|
+
}
|
|
16278
|
+
if (key.name === "q" || key.name === "escape") {
|
|
16279
|
+
cleanup();
|
|
16280
|
+
console.log(import_picocolors2.default.dim("\n Exited Qodewk.\n"));
|
|
16281
|
+
process.exit(0);
|
|
16282
|
+
}
|
|
16283
|
+
if (key.name === "up" || key.name === "k") {
|
|
16284
|
+
selectedIndex = (selectedIndex - 1 + MENU_ITEMS.length) % MENU_ITEMS.length;
|
|
16285
|
+
render();
|
|
16286
|
+
return;
|
|
16287
|
+
}
|
|
16288
|
+
if (key.name === "down" || key.name === "j") {
|
|
16289
|
+
selectedIndex = (selectedIndex + 1) % MENU_ITEMS.length;
|
|
16290
|
+
render();
|
|
16291
|
+
return;
|
|
16292
|
+
}
|
|
16293
|
+
const itemByKey = MENU_ITEMS.findIndex((item) => item.key === key.name || item.key === _str);
|
|
16294
|
+
if (itemByKey !== -1) {
|
|
16295
|
+
selectedIndex = itemByKey;
|
|
16296
|
+
render();
|
|
16297
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
16298
|
+
await executeSelectedAction();
|
|
16299
|
+
if (active) {
|
|
16300
|
+
startLoop();
|
|
16301
|
+
}
|
|
16302
|
+
return;
|
|
16303
|
+
}
|
|
16304
|
+
if (key.name === "return" || key.name === "enter") {
|
|
16305
|
+
process.stdin.removeListener("keypress", onKeypress);
|
|
16306
|
+
await executeSelectedAction();
|
|
16307
|
+
if (active) {
|
|
16308
|
+
startLoop();
|
|
16309
|
+
}
|
|
16310
|
+
return;
|
|
16311
|
+
}
|
|
16312
|
+
};
|
|
16313
|
+
process.stdin.on("keypress", onKeypress);
|
|
16314
|
+
};
|
|
16315
|
+
startLoop();
|
|
16316
|
+
}
|
|
16317
|
+
|
|
16318
|
+
// src/index.ts
|
|
16319
|
+
var SHARE_PAYLOAD_MAX_BYTES2 = 5e4;
|
|
16320
|
+
function resolveCliVersion() {
|
|
16321
|
+
try {
|
|
16322
|
+
const argv1 = process.argv[1] ? path10.dirname(path10.resolve(process.argv[1])) : process.cwd();
|
|
16323
|
+
const candidates = [
|
|
16324
|
+
path10.join(argv1, "..", "package.json"),
|
|
16325
|
+
path10.join(argv1, "package.json")
|
|
16326
|
+
];
|
|
16327
|
+
for (const candidate of candidates) {
|
|
16328
|
+
if (!fs10.existsSync(candidate)) continue;
|
|
16329
|
+
const pkg = JSON.parse(fs10.readFileSync(candidate, "utf-8"));
|
|
16330
|
+
if (pkg.name === "qodewk" && pkg.version) return pkg.version;
|
|
16331
|
+
}
|
|
16332
|
+
} catch {
|
|
16333
|
+
}
|
|
16334
|
+
return "0.3.0";
|
|
16335
|
+
}
|
|
16336
|
+
function resolveSince(options) {
|
|
16337
|
+
return options.today ? "today" : options.since;
|
|
16338
|
+
}
|
|
16339
|
+
function persistReceipt(receipt, claimToken) {
|
|
16340
|
+
try {
|
|
16341
|
+
const db = new LocalStateDB();
|
|
16342
|
+
db.saveReceipt(receipt, claimToken);
|
|
16343
|
+
db.close();
|
|
16344
|
+
} catch {
|
|
16345
|
+
}
|
|
16346
|
+
}
|
|
16347
|
+
var program2 = new Command();
|
|
16348
|
+
program2.name("qodewk").description("Universal telemetry and digital receipt generator for the AI coding agent era").version(resolveCliVersion()).option("-i, --interactive", "Launch interactive terminal control panel").option("--menu", "Launch interactive terminal control panel").option("-j, --json", "Output receipt in machine-readable JSON format").option("-f, --format <format>", "Output format (terminal, json, markdown)", "terminal").option("-o, --out <path>", "Write receipt output to specified file path").option("-p, --provider <provider>", "Specify AI provider (antigravity, claude, cursor, etc.)").option("-m, --model <model>", "Specify AI model identifier").option("-s, --since <duration>", "Harvest agent footprints since duration (e.g. today, 24h, 7d)").option("--today", "Harvest agent footprints for today").option("--platform <platform>", "Filter agent platform (antigravity, claude, cursor, all)").option("--anon", "Anonymize branch name in output").option("--local", "Force local-only mode (never open network sockets)").option("--barcode", "Render classic 1D thermal barcode (always on; kept for compatibility)").option("--notes", "Persist receipt into local Git note (refs/notes/qodewk)").action(async (options) => {
|
|
16349
|
+
if (options.interactive || options.menu) {
|
|
16350
|
+
await runInteractiveMenu();
|
|
16351
|
+
return;
|
|
16352
|
+
}
|
|
15095
16353
|
try {
|
|
15096
16354
|
const receipt = await generateReceipt({
|
|
15097
16355
|
provider: options.provider,
|
|
@@ -15102,14 +16360,25 @@ program2.name("qodewk").description("Universal telemetry and digital receipt gen
|
|
|
15102
16360
|
isPublic: false
|
|
15103
16361
|
});
|
|
15104
16362
|
persistReceipt(receipt);
|
|
16363
|
+
if (options.notes) {
|
|
16364
|
+
try {
|
|
16365
|
+
await writeGitReceiptNote(receipt.repository.headSha, receipt);
|
|
16366
|
+
console.log(import_picocolors3.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`));
|
|
16367
|
+
} catch (noteErr) {
|
|
16368
|
+
console.warn(import_picocolors3.default.yellow(`Warning: Could not write Git note: ${noteErr.message}`));
|
|
16369
|
+
}
|
|
16370
|
+
}
|
|
15105
16371
|
await outputReceipt(receipt, options);
|
|
15106
16372
|
} catch (err) {
|
|
15107
16373
|
const message = err instanceof Error ? err.message : String(err);
|
|
15108
|
-
console.error(
|
|
16374
|
+
console.error(import_picocolors3.default.red(`Error generating receipt: ${message}`));
|
|
15109
16375
|
process.exit(1);
|
|
15110
16376
|
}
|
|
15111
16377
|
});
|
|
15112
|
-
program2.command("
|
|
16378
|
+
program2.command("menu").description("Launch interactive terminal control panel").action(async () => {
|
|
16379
|
+
await runInteractiveMenu();
|
|
16380
|
+
});
|
|
16381
|
+
program2.command("audit").description("Audit PR or branch diff against a target base commit").option("-b, --base <base>", "Base git ref or commit SHA (e.g. origin/main)").option("-H, --head <head>", "Head git ref or commit SHA").option("-f, --format <format>", "Output format (terminal, json, markdown)", "terminal").option("-o, --out <path>", "Write receipt output to specified file path").option("-p, --provider <provider>", "Specify AI provider").option("-m, --model <model>", "Specify AI model").option("-s, --since <duration>", "Harvest agent footprints since duration").option("--today", "Harvest agent footprints for today").option("--platform <platform>", "Filter agent platform").option("--anon", "Anonymize branch name in output").option("--barcode", "Render classic 1D thermal barcode (always on; kept for compatibility)").action(async (options) => {
|
|
15113
16382
|
try {
|
|
15114
16383
|
const receipt = await generateReceipt({
|
|
15115
16384
|
baseSha: options.base,
|
|
@@ -15125,7 +16394,7 @@ program2.command("audit").description("Audit PR or branch diff against a target
|
|
|
15125
16394
|
await outputReceipt(receipt, options);
|
|
15126
16395
|
} catch (err) {
|
|
15127
16396
|
const message = err instanceof Error ? err.message : String(err);
|
|
15128
|
-
console.error(
|
|
16397
|
+
console.error(import_picocolors3.default.red(`Error auditing git range: ${message}`));
|
|
15129
16398
|
process.exit(1);
|
|
15130
16399
|
}
|
|
15131
16400
|
});
|
|
@@ -15142,31 +16411,31 @@ program2.command("share").description("Publish privacy-safe receipt to Qodewk cl
|
|
|
15142
16411
|
const localFlag = program2.opts().local === true;
|
|
15143
16412
|
if (process.env.QODEWK_TELEMETRY === "off" || localFlag) {
|
|
15144
16413
|
console.log(
|
|
15145
|
-
|
|
16414
|
+
import_picocolors3.default.yellow(
|
|
15146
16415
|
`
|
|
15147
16416
|
Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"}).`
|
|
15148
16417
|
)
|
|
15149
16418
|
);
|
|
15150
|
-
console.log(
|
|
16419
|
+
console.log(import_picocolors3.default.dim("Telemetry remains strictly stored in local SQLite (~/.qodewk/state.db).\n"));
|
|
15151
16420
|
persistReceipt(receipt);
|
|
15152
16421
|
await renderTerminalReceipt(receipt);
|
|
15153
16422
|
return;
|
|
15154
16423
|
}
|
|
15155
16424
|
const sanitized = sanitizeReceiptForShare(receipt);
|
|
15156
16425
|
let body = JSON.stringify(sanitized);
|
|
15157
|
-
if (Buffer.byteLength(body, "utf-8") >
|
|
16426
|
+
if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES2 && sanitized.ai.sessions) {
|
|
15158
16427
|
const trimmed2 = {
|
|
15159
16428
|
...sanitized,
|
|
15160
16429
|
ai: { ...sanitized.ai, sessions: void 0 }
|
|
15161
16430
|
};
|
|
15162
16431
|
body = JSON.stringify(trimmed2);
|
|
15163
16432
|
}
|
|
15164
|
-
if (Buffer.byteLength(body, "utf-8") >
|
|
15165
|
-
console.error(
|
|
16433
|
+
if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES2) {
|
|
16434
|
+
console.error(import_picocolors3.default.red("Sanitized receipt still exceeds the 50 KB cloud payload limit."));
|
|
15166
16435
|
process.exit(1);
|
|
15167
16436
|
}
|
|
15168
16437
|
const endpoint = process.env.QODEWK_API_URL || `${process.env.NEXT_PUBLIC_APP_URL || process.env.QODEWK_APP_URL || "https://qodewk.flinkeo.online"}/api/receipts`;
|
|
15169
|
-
console.log(
|
|
16438
|
+
console.log(import_picocolors3.default.dim(`Publishing receipt ${sanitized.receipt.id} to ${endpoint}...`));
|
|
15170
16439
|
try {
|
|
15171
16440
|
const response = await fetch(endpoint, {
|
|
15172
16441
|
method: "POST",
|
|
@@ -15183,11 +16452,11 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
|
|
|
15183
16452
|
const data = await response.json();
|
|
15184
16453
|
persistReceipt(sanitized, data.claimToken);
|
|
15185
16454
|
console.log("");
|
|
15186
|
-
console.log(
|
|
15187
|
-
console.log(` ${
|
|
15188
|
-
console.log(` ${
|
|
15189
|
-
console.log(` ${
|
|
15190
|
-
console.log(
|
|
16455
|
+
console.log(import_picocolors3.default.green(" Published successfully."));
|
|
16456
|
+
console.log(` ${import_picocolors3.default.dim("Public URL:")} ${import_picocolors3.default.underline(import_picocolors3.default.cyan(data.url))}`);
|
|
16457
|
+
console.log(` ${import_picocolors3.default.bold(import_picocolors3.default.yellow(" Claim token (store securely \u2014 shown once):"))}`);
|
|
16458
|
+
console.log(` ${import_picocolors3.default.yellow(data.claimToken)}`);
|
|
16459
|
+
console.log(import_picocolors3.default.dim(" Saved to ~/.qodewk/state.db \u2014 required to prove authorship later."));
|
|
15191
16460
|
console.log("");
|
|
15192
16461
|
await renderTerminalReceipt(sanitized, data.url);
|
|
15193
16462
|
if (options.json) {
|
|
@@ -15195,14 +16464,14 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
|
|
|
15195
16464
|
}
|
|
15196
16465
|
} catch (networkErr) {
|
|
15197
16466
|
const message = networkErr instanceof Error ? networkErr.message : String(networkErr);
|
|
15198
|
-
console.log(
|
|
16467
|
+
console.log(import_picocolors3.default.yellow(`
|
|
15199
16468
|
Could not reach cloud API (${message}). Rendered locally:`));
|
|
15200
16469
|
persistReceipt(receipt);
|
|
15201
16470
|
await renderTerminalReceipt(receipt);
|
|
15202
16471
|
}
|
|
15203
16472
|
} catch (err) {
|
|
15204
16473
|
const message = err instanceof Error ? err.message : String(err);
|
|
15205
|
-
console.error(
|
|
16474
|
+
console.error(import_picocolors3.default.red(`Error sharing receipt: ${message}`));
|
|
15206
16475
|
process.exit(1);
|
|
15207
16476
|
}
|
|
15208
16477
|
});
|
|
@@ -15220,35 +16489,35 @@ hookCommand.command("install").description("Install non-blocking post-commit and
|
|
|
15220
16489
|
try {
|
|
15221
16490
|
const hooksDir = resolveGitHooksDir();
|
|
15222
16491
|
if (!hooksDir) {
|
|
15223
|
-
console.error(
|
|
16492
|
+
console.error(import_picocolors3.default.red("Error: Current directory is not a Git repository (.git not found)."));
|
|
15224
16493
|
process.exit(1);
|
|
15225
16494
|
}
|
|
15226
|
-
if (!
|
|
15227
|
-
|
|
16495
|
+
if (!fs10.existsSync(hooksDir)) {
|
|
16496
|
+
fs10.mkdirSync(hooksDir, { recursive: true });
|
|
15228
16497
|
}
|
|
15229
16498
|
const targets = ["post-commit", "post-rewrite"];
|
|
15230
16499
|
let installed = 0;
|
|
15231
16500
|
let existing = 0;
|
|
15232
16501
|
for (const name of targets) {
|
|
15233
|
-
const result = installHookFile(
|
|
16502
|
+
const result = installHookFile(path10.join(hooksDir, name));
|
|
15234
16503
|
if (result === "installed") installed++;
|
|
15235
16504
|
else existing++;
|
|
15236
16505
|
}
|
|
15237
16506
|
if (installed === 0 && existing > 0) {
|
|
15238
|
-
console.log(
|
|
16507
|
+
console.log(import_picocolors3.default.yellow("Qodewk Git hooks are already installed (post-commit, post-rewrite)."));
|
|
15239
16508
|
return;
|
|
15240
16509
|
}
|
|
15241
16510
|
console.log(
|
|
15242
|
-
|
|
16511
|
+
import_picocolors3.default.green(
|
|
15243
16512
|
`\u2713 Non-blocking Qodewk hooks installed in ${hooksDir} (post-commit${installed > 1 || existing > 0 ? ", post-rewrite" : installed === 1 && targets.length === 2 ? " + post-rewrite" : ""})`
|
|
15244
16513
|
)
|
|
15245
16514
|
);
|
|
15246
16515
|
if (existing > 0) {
|
|
15247
|
-
console.log(
|
|
16516
|
+
console.log(import_picocolors3.default.dim(` (${existing} hook file(s) already contained the Qodewk marker)`));
|
|
15248
16517
|
}
|
|
15249
16518
|
} catch (err) {
|
|
15250
16519
|
const message = err instanceof Error ? err.message : String(err);
|
|
15251
|
-
console.error(
|
|
16520
|
+
console.error(import_picocolors3.default.red(`Failed to install Git hook: ${message}`));
|
|
15252
16521
|
process.exit(1);
|
|
15253
16522
|
}
|
|
15254
16523
|
});
|
|
@@ -15256,190 +16525,73 @@ hookCommand.command("uninstall").description("Remove Qodewk post-commit and post
|
|
|
15256
16525
|
try {
|
|
15257
16526
|
const hooksDir = resolveGitHooksDir();
|
|
15258
16527
|
if (!hooksDir) {
|
|
15259
|
-
console.log(
|
|
16528
|
+
console.log(import_picocolors3.default.yellow("No Git repository found."));
|
|
15260
16529
|
return;
|
|
15261
16530
|
}
|
|
15262
16531
|
const targets = ["post-commit", "post-rewrite"];
|
|
15263
16532
|
let removed = 0;
|
|
15264
16533
|
for (const name of targets) {
|
|
15265
|
-
const result = uninstallHookFile(
|
|
16534
|
+
const result = uninstallHookFile(path10.join(hooksDir, name));
|
|
15266
16535
|
if (result === "removed") removed++;
|
|
15267
16536
|
}
|
|
15268
16537
|
if (removed === 0) {
|
|
15269
|
-
console.log(
|
|
16538
|
+
console.log(import_picocolors3.default.yellow("Qodewk hooks are not installed."));
|
|
15270
16539
|
return;
|
|
15271
16540
|
}
|
|
15272
|
-
console.log(
|
|
16541
|
+
console.log(import_picocolors3.default.green(`\u2713 Qodewk hook markers removed from ${removed} file(s).`));
|
|
15273
16542
|
} catch (err) {
|
|
15274
16543
|
const message = err instanceof Error ? err.message : String(err);
|
|
15275
|
-
console.error(
|
|
16544
|
+
console.error(import_picocolors3.default.red(`Failed to uninstall hook: ${message}`));
|
|
15276
16545
|
process.exit(1);
|
|
15277
16546
|
}
|
|
15278
16547
|
});
|
|
15279
|
-
var
|
|
15280
|
-
|
|
15281
|
-
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
var stripAnsi = (str) => {
|
|
15287
|
-
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1B\([B0]/g, "");
|
|
15288
|
-
};
|
|
15289
|
-
var visibleWidth = (str) => {
|
|
15290
|
-
return stripAnsi(str).length;
|
|
15291
|
-
};
|
|
15292
|
-
function buildTerminalReceipt(receipt, publicUrl) {
|
|
15293
|
-
const lines = [];
|
|
15294
|
-
const coral = ansiHex("#cc785c");
|
|
15295
|
-
const green = ansiHex("#5db872");
|
|
15296
|
-
const red = ansiHex("#c64545");
|
|
15297
|
-
const teal = ansiHex("#5db8a6");
|
|
15298
|
-
const INNER_WIDTH = 52;
|
|
15299
|
-
const push = (line) => lines.push(line);
|
|
15300
|
-
const printRow = (content, width = INNER_WIDTH) => {
|
|
15301
|
-
const visLen = visibleWidth(content);
|
|
15302
|
-
const pad = Math.max(0, width - visLen);
|
|
15303
|
-
push(` | ${content}${" ".repeat(pad)} |`);
|
|
15304
|
-
};
|
|
15305
|
-
const printRowSplit = (left, right, width = INNER_WIDTH) => {
|
|
15306
|
-
const leftVis = visibleWidth(left);
|
|
15307
|
-
const rightVis = visibleWidth(right);
|
|
15308
|
-
const pad = Math.max(1, width - leftVis - rightVis);
|
|
15309
|
-
push(` | ${left}${" ".repeat(pad)}${right} |`);
|
|
15310
|
-
};
|
|
15311
|
-
const printCenteredRow = (content, width = INNER_WIDTH) => {
|
|
15312
|
-
const visLen = visibleWidth(content);
|
|
15313
|
-
const totalPad = Math.max(0, width - visLen);
|
|
15314
|
-
const leftPad = Math.floor(totalPad / 2);
|
|
15315
|
-
const rightPad = totalPad - leftPad;
|
|
15316
|
-
push(` | ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} |`);
|
|
15317
|
-
};
|
|
15318
|
-
const printDivider = (char = "=", width = INNER_WIDTH) => {
|
|
15319
|
-
push(` | ${char.repeat(width)} |`);
|
|
15320
|
-
};
|
|
15321
|
-
const totalTokens = (receipt.ai.tokens.input + receipt.ai.tokens.output).toLocaleString();
|
|
15322
|
-
const inputK = `${Math.round(receipt.ai.tokens.input / 1e3)}k`;
|
|
15323
|
-
const outputK = `${Math.round(receipt.ai.tokens.output / 1e3)}k`;
|
|
15324
|
-
const costPrefix = receipt.ai.mode === "verified" ? "$" : "~$";
|
|
15325
|
-
const confidencePercent = `${Math.round(receipt.ai.confidence * 100)}%`;
|
|
15326
|
-
push("");
|
|
15327
|
-
push(" " + import_picocolors.default.bold(coral("/\\".repeat(28))));
|
|
15328
|
-
printCenteredRow(import_picocolors.default.bold(import_picocolors.default.white("Q O D E W K")));
|
|
15329
|
-
printCenteredRow(coral("*** PROOF OF SHIPMENT ***"));
|
|
15330
|
-
printRow("");
|
|
15331
|
-
printRowSplit(
|
|
15332
|
-
`ID: ${receipt.receipt.id.slice(0, 24)}`,
|
|
15333
|
-
`DATE: ${receipt.receipt.createdAt.slice(0, 10)}`
|
|
15334
|
-
);
|
|
15335
|
-
printRowSplit(
|
|
15336
|
-
`REPO: ${receipt.repository.projectAlias.slice(0, 18)}`,
|
|
15337
|
-
`BRANCH: ${receipt.repository.branch.slice(0, 16)}`
|
|
15338
|
-
);
|
|
15339
|
-
if (receipt.ai.task) {
|
|
15340
|
-
const taskClean = receipt.ai.task.length > 44 ? receipt.ai.task.slice(0, 43) + "\u2026" : receipt.ai.task;
|
|
15341
|
-
printRow(`TASK: ${taskClean}`);
|
|
15342
|
-
}
|
|
15343
|
-
printDivider("=");
|
|
15344
|
-
const itemsHeader = receipt.repository.commitsCount && receipt.repository.commitsCount > 1 ? `ITEMS CHANGED (${receipt.repository.commitsCount} COMMITS)` : "ITEMS CHANGED";
|
|
15345
|
-
printRowSplit(itemsHeader, "QTY");
|
|
15346
|
-
printDivider("-");
|
|
15347
|
-
printRowSplit("Files Touched", String(receipt.mutation.files));
|
|
15348
|
-
printRowSplit("Lines Inserted", green("+ " + receipt.mutation.insertions));
|
|
15349
|
-
printRowSplit("Lines Deleted", red("- " + receipt.mutation.deletions));
|
|
15350
|
-
printRowSplit(
|
|
15351
|
-
"Net Code Delta",
|
|
15352
|
-
teal((receipt.mutation.netLines >= 0 ? "+ " : "- ") + Math.abs(receipt.mutation.netLines))
|
|
15353
|
-
);
|
|
15354
|
-
printDivider("-");
|
|
15355
|
-
printRow("AI TELEMETRY & ATTRIBUTION");
|
|
15356
|
-
const provString = receipt.ai.provider + " \xB7 " + (receipt.ai.model || "Unknown");
|
|
15357
|
-
const cleanProv = provString.length > 40 ? provString.slice(0, 39) + "\u2026" : provString;
|
|
15358
|
-
printRow(`Provider: ${cleanProv}`);
|
|
15359
|
-
if (receipt.ai.sessions && receipt.ai.sessions.length > 1) {
|
|
15360
|
-
const others = receipt.ai.sessions.slice(1).map((s) => s.provider).filter((p2, i2, arr) => arr.indexOf(p2) === i2 && p2 !== receipt.ai.provider);
|
|
15361
|
-
if (others.length > 0) {
|
|
15362
|
-
printRow(import_picocolors.default.dim(`Also seen: ${others.join(", ")}`));
|
|
16548
|
+
var notesCmd = program2.command("notes").description("Manage local Git notes receipts (refs/notes/qodewk)");
|
|
16549
|
+
notesCmd.command("show [commit]").description("Display Qodewk receipt attached to a Git commit note").option("-j, --json", "Output receipt as JSON").action(async (commit = "HEAD", opts) => {
|
|
16550
|
+
try {
|
|
16551
|
+
const receipt = await readGitReceiptNote(commit);
|
|
16552
|
+
if (!receipt) {
|
|
16553
|
+
console.log(import_picocolors3.default.yellow(`No Qodewk receipt note found on commit '${commit}'.`));
|
|
16554
|
+
return;
|
|
15363
16555
|
}
|
|
16556
|
+
if (opts.json) {
|
|
16557
|
+
console.log(JSON.stringify(receipt, null, 2));
|
|
16558
|
+
} else {
|
|
16559
|
+
await outputReceipt(receipt, { format: "terminal" });
|
|
16560
|
+
}
|
|
16561
|
+
} catch (err) {
|
|
16562
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16563
|
+
console.error(import_picocolors3.default.red(`Error reading Git note: ${message}`));
|
|
16564
|
+
process.exit(1);
|
|
15364
16565
|
}
|
|
15365
|
-
|
|
15366
|
-
|
|
15367
|
-
|
|
15368
|
-
|
|
15369
|
-
|
|
15370
|
-
|
|
15371
|
-
|
|
15372
|
-
|
|
15373
|
-
|
|
15374
|
-
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
printDivider("=");
|
|
15378
|
-
printRow("");
|
|
15379
|
-
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || process.env.QODEWK_APP_URL || "https://qodewk.flinkeo.online";
|
|
15380
|
-
const isPublished = Boolean(publicUrl);
|
|
15381
|
-
const displayHost = baseUrl.replace(/^https?:\/\//, "");
|
|
15382
|
-
const barcodePayload = pickBarcodePayload({
|
|
15383
|
-
publicUrl,
|
|
15384
|
-
receiptId: receipt.receipt.id,
|
|
15385
|
-
displayHost,
|
|
15386
|
-
maxChars: 28
|
|
15387
|
-
});
|
|
15388
|
-
const barcodeRows = renderTerminalBarcode(barcodePayload, {
|
|
15389
|
-
maxWidth: INNER_WIDTH,
|
|
15390
|
-
height: 3,
|
|
15391
|
-
quietZone: 8
|
|
15392
|
-
});
|
|
15393
|
-
for (const barRow of barcodeRows) {
|
|
15394
|
-
printCenteredRow(import_picocolors.default.bold(barRow));
|
|
15395
|
-
}
|
|
15396
|
-
if (isPublished) {
|
|
15397
|
-
printCenteredRow(import_picocolors.default.cyan(displayHost));
|
|
15398
|
-
printCenteredRow(import_picocolors.default.underline(import_picocolors.default.cyan(`r/${receipt.receipt.id}`)));
|
|
15399
|
-
} else {
|
|
15400
|
-
printCenteredRow(import_picocolors.default.yellow("[ LOCAL RECORD \u2014 NOT PUBLISHED ]"));
|
|
15401
|
-
}
|
|
15402
|
-
printRow("");
|
|
15403
|
-
if (process.env.QODEWK_TELEMETRY === "off") {
|
|
15404
|
-
printRow(` ${teal("[\u2713]")} QODEWK_TELEMETRY=off (Cloud sync disabled)`);
|
|
15405
|
-
}
|
|
15406
|
-
printRow(` ${green("[\u2713]")} Source code was never uploaded to Qodewk`);
|
|
15407
|
-
push(" " + import_picocolors.default.bold(coral("\\/".repeat(28))));
|
|
15408
|
-
push("");
|
|
15409
|
-
if (isPublished && publicUrl) {
|
|
15410
|
-
push(` ${import_picocolors.default.dim("Public Receipt:")} ${import_picocolors.default.underline(import_picocolors.default.cyan(publicUrl))}`);
|
|
15411
|
-
} else {
|
|
15412
|
-
push(` ${import_picocolors.default.dim("Saved to local DB:")} ${import_picocolors.default.dim("~/.qodewk/state.db")}`);
|
|
15413
|
-
push(` ${import_picocolors.default.dim("To publish & get shareable URL:")} ${import_picocolors.default.cyan("qodewk share")}`);
|
|
15414
|
-
}
|
|
15415
|
-
push("");
|
|
15416
|
-
return lines.join("\n");
|
|
15417
|
-
}
|
|
15418
|
-
async function renderTerminalReceipt(receipt, publicUrl) {
|
|
15419
|
-
console.log(buildTerminalReceipt(receipt, publicUrl));
|
|
15420
|
-
}
|
|
15421
|
-
async function outputReceipt(receipt, options, publicUrl) {
|
|
15422
|
-
const format = options.json ? "json" : options.format || "terminal";
|
|
15423
|
-
let content;
|
|
15424
|
-
if (format === "json") {
|
|
15425
|
-
content = JSON.stringify(receipt, null, 2);
|
|
15426
|
-
} else if (format === "markdown") {
|
|
15427
|
-
content = formatMarkdownReceipt(receipt, publicUrl);
|
|
15428
|
-
} else {
|
|
15429
|
-
content = buildTerminalReceipt(receipt, publicUrl);
|
|
15430
|
-
}
|
|
15431
|
-
if (options.out) {
|
|
15432
|
-
const fileContent = format === "terminal" ? stripAnsi(content) : content;
|
|
15433
|
-
fs6.writeFileSync(options.out, fileContent.endsWith("\n") ? fileContent : fileContent + "\n", "utf-8");
|
|
15434
|
-
console.log(import_picocolors.default.green(`\u2713 Receipt written to ${options.out}`));
|
|
16566
|
+
});
|
|
16567
|
+
notesCmd.command("write [commit]").description("Generate and attach receipt to a Git commit note").action(async (commit = "HEAD") => {
|
|
16568
|
+
try {
|
|
16569
|
+
const receipt = await generateReceipt({ headSha: commit });
|
|
16570
|
+
await writeGitReceiptNote(receipt.repository.headSha, receipt);
|
|
16571
|
+
console.log(
|
|
16572
|
+
import_picocolors3.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`)
|
|
16573
|
+
);
|
|
16574
|
+
} catch (err) {
|
|
16575
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16576
|
+
console.error(import_picocolors3.default.red(`Error writing Git note: ${message}`));
|
|
16577
|
+
process.exit(1);
|
|
15435
16578
|
}
|
|
15436
|
-
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
15440
|
-
|
|
16579
|
+
});
|
|
16580
|
+
notesCmd.command("list").description("List all commits with attached Qodewk receipts").action(async () => {
|
|
16581
|
+
try {
|
|
16582
|
+
const shas = await listGitReceiptNotes();
|
|
16583
|
+
if (shas.length === 0) {
|
|
16584
|
+
console.log(import_picocolors3.default.yellow("No Qodewk Git notes found in repository."));
|
|
16585
|
+
return;
|
|
15441
16586
|
}
|
|
15442
|
-
|
|
16587
|
+
console.log(import_picocolors3.default.bold(`Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
|
|
16588
|
+
for (const sha of shas) {
|
|
16589
|
+
console.log(` ${import_picocolors3.default.cyan(sha.slice(0, 10))} ${import_picocolors3.default.dim(sha)}`);
|
|
16590
|
+
}
|
|
16591
|
+
} catch (err) {
|
|
16592
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
16593
|
+
console.error(import_picocolors3.default.red(`Error listing Git notes: ${message}`));
|
|
16594
|
+
process.exit(1);
|
|
15443
16595
|
}
|
|
15444
|
-
}
|
|
16596
|
+
});
|
|
15445
16597
|
program2.parse(process.argv);
|