qodewk 0.1.5 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +819 -228
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -739,10 +739,10 @@ ${itemIndentStr}`);
|
|
|
739
739
|
let sumChunks = [chunks.shift()];
|
|
740
740
|
let sumWidth = this.displayWidth(sumChunks[0]);
|
|
741
741
|
chunks.forEach((chunk) => {
|
|
742
|
-
const
|
|
743
|
-
if (sumWidth +
|
|
742
|
+
const visibleWidth2 = this.displayWidth(chunk);
|
|
743
|
+
if (sumWidth + visibleWidth2 <= width) {
|
|
744
744
|
sumChunks.push(chunk);
|
|
745
|
-
sumWidth +=
|
|
745
|
+
sumWidth += visibleWidth2;
|
|
746
746
|
return;
|
|
747
747
|
}
|
|
748
748
|
wrappedLines.push(sumChunks.join(""));
|
|
@@ -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 path7 = require("path");
|
|
1157
|
+
var fs7 = 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 (fs7.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 = path7.resolve(baseDir, baseName);
|
|
2157
|
+
if (fs7.existsSync(localBin)) return localBin;
|
|
2158
|
+
if (sourceExt.includes(path7.extname(baseName))) return void 0;
|
|
2159
2159
|
const foundExt = sourceExt.find(
|
|
2160
|
-
(ext) =>
|
|
2160
|
+
(ext) => fs7.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 = fs7.realpathSync(this._scriptPath);
|
|
2173
2173
|
} catch {
|
|
2174
2174
|
resolvedScriptPath = this._scriptPath;
|
|
2175
2175
|
}
|
|
2176
|
-
executableDir =
|
|
2177
|
-
|
|
2176
|
+
executableDir = path7.resolve(
|
|
2177
|
+
path7.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 = path7.basename(
|
|
2185
2185
|
this._scriptPath,
|
|
2186
|
-
|
|
2186
|
+
path7.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(path7.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 = path7.basename(filename, path7.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(path8) {
|
|
3059
|
+
if (path8 === void 0) return this._executableDir;
|
|
3060
|
+
this._executableDir = path8;
|
|
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(path7, isFile, isDirectory) {
|
|
4071
|
+
log(`checking %s`, path7);
|
|
4072
4072
|
try {
|
|
4073
|
-
const stat = fs_1.statSync(
|
|
4073
|
+
const stat = fs_1.statSync(path7);
|
|
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(path7, type = exports2.READABLE) {
|
|
4094
|
+
return check(path7, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
|
|
4095
4095
|
}
|
|
4096
4096
|
exports2.exists = exists2;
|
|
4097
4097
|
exports2.FILE = 1;
|
|
@@ -4155,7 +4155,7 @@ var require_dist2 = __commonJS({
|
|
|
4155
4155
|
});
|
|
4156
4156
|
|
|
4157
4157
|
// src/index.ts
|
|
4158
|
-
var
|
|
4158
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
4159
4159
|
|
|
4160
4160
|
// ../../node_modules/.pnpm/commander@13.1.0/node_modules/commander/esm.mjs
|
|
4161
4161
|
var import_index = __toESM(require_commander(), 1);
|
|
@@ -4658,8 +4658,8 @@ function getErrorMap() {
|
|
|
4658
4658
|
|
|
4659
4659
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
4660
4660
|
var makeIssue = (params) => {
|
|
4661
|
-
const { data, path:
|
|
4662
|
-
const fullPath = [...
|
|
4661
|
+
const { data, path: path7, errorMaps, issueData } = params;
|
|
4662
|
+
const fullPath = [...path7, ...issueData.path || []];
|
|
4663
4663
|
const fullIssue = {
|
|
4664
4664
|
...issueData,
|
|
4665
4665
|
path: fullPath
|
|
@@ -4775,11 +4775,11 @@ var errorUtil;
|
|
|
4775
4775
|
|
|
4776
4776
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
4777
4777
|
var ParseInputLazyPath = class {
|
|
4778
|
-
constructor(parent, value,
|
|
4778
|
+
constructor(parent, value, path7, key) {
|
|
4779
4779
|
this._cachedPath = [];
|
|
4780
4780
|
this.parent = parent;
|
|
4781
4781
|
this.data = value;
|
|
4782
|
-
this._path =
|
|
4782
|
+
this._path = path7;
|
|
4783
4783
|
this._key = key;
|
|
4784
4784
|
}
|
|
4785
4785
|
get path() {
|
|
@@ -8231,8 +8231,10 @@ var AttributionModeSchema = external_exports.enum([
|
|
|
8231
8231
|
]);
|
|
8232
8232
|
var ProviderSessionSchema = external_exports.object({
|
|
8233
8233
|
provider: external_exports.string(),
|
|
8234
|
-
// e.g. "anthropic", "openai", "cursor", "copilot", "gemini"
|
|
8234
|
+
// e.g. "anthropic", "openai", "cursor", "copilot", "gemini", "antigravity"
|
|
8235
8235
|
model: external_exports.string().optional(),
|
|
8236
|
+
task: external_exports.string().optional(),
|
|
8237
|
+
filesTouched: external_exports.array(external_exports.string()).optional(),
|
|
8236
8238
|
tokens: external_exports.object({
|
|
8237
8239
|
input: external_exports.number().int().nonnegative().default(0),
|
|
8238
8240
|
output: external_exports.number().int().nonnegative().default(0),
|
|
@@ -8274,6 +8276,8 @@ var ReceiptV1Schema = external_exports.object({
|
|
|
8274
8276
|
ai: external_exports.object({
|
|
8275
8277
|
provider: external_exports.string(),
|
|
8276
8278
|
model: external_exports.string().optional(),
|
|
8279
|
+
task: external_exports.string().optional(),
|
|
8280
|
+
aiWrittenRatio: external_exports.number().min(0).max(1).optional(),
|
|
8277
8281
|
tokens: external_exports.object({
|
|
8278
8282
|
input: external_exports.number().int().nonnegative(),
|
|
8279
8283
|
output: external_exports.number().int().nonnegative(),
|
|
@@ -8887,8 +8891,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
8887
8891
|
function forEachLineWithContent(input, callback) {
|
|
8888
8892
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
8889
8893
|
}
|
|
8890
|
-
function folderExists(
|
|
8891
|
-
return (0, import_file_exists.exists)(
|
|
8894
|
+
function folderExists(path7) {
|
|
8895
|
+
return (0, import_file_exists.exists)(path7, import_file_exists.FOLDER);
|
|
8892
8896
|
}
|
|
8893
8897
|
function append(target, item) {
|
|
8894
8898
|
if (Array.isArray(target)) {
|
|
@@ -9290,8 +9294,8 @@ function checkIsRepoRootTask() {
|
|
|
9290
9294
|
commands,
|
|
9291
9295
|
format: "utf-8",
|
|
9292
9296
|
onError,
|
|
9293
|
-
parser(
|
|
9294
|
-
return /^\.(git)?$/.test(
|
|
9297
|
+
parser(path7) {
|
|
9298
|
+
return /^\.(git)?$/.test(path7.trim());
|
|
9295
9299
|
}
|
|
9296
9300
|
};
|
|
9297
9301
|
}
|
|
@@ -9725,11 +9729,11 @@ function parseGrep(grep) {
|
|
|
9725
9729
|
const paths = /* @__PURE__ */ new Set();
|
|
9726
9730
|
const results = {};
|
|
9727
9731
|
forEachLineWithContent(grep, (input) => {
|
|
9728
|
-
const [
|
|
9729
|
-
paths.add(
|
|
9730
|
-
(results[
|
|
9732
|
+
const [path7, line, preview] = input.split(NULL);
|
|
9733
|
+
paths.add(path7);
|
|
9734
|
+
(results[path7] = results[path7] || []).push({
|
|
9731
9735
|
line: asNumber(line),
|
|
9732
|
-
path:
|
|
9736
|
+
path: path7,
|
|
9733
9737
|
preview
|
|
9734
9738
|
});
|
|
9735
9739
|
});
|
|
@@ -10493,14 +10497,14 @@ var init_hash_object = __esm({
|
|
|
10493
10497
|
init_task();
|
|
10494
10498
|
}
|
|
10495
10499
|
});
|
|
10496
|
-
function parseInit(bare,
|
|
10500
|
+
function parseInit(bare, path7, text) {
|
|
10497
10501
|
const response = String(text).trim();
|
|
10498
10502
|
let result;
|
|
10499
10503
|
if (result = initResponseRegex.exec(response)) {
|
|
10500
|
-
return new InitSummary(bare,
|
|
10504
|
+
return new InitSummary(bare, path7, false, result[1]);
|
|
10501
10505
|
}
|
|
10502
10506
|
if (result = reInitResponseRegex.exec(response)) {
|
|
10503
|
-
return new InitSummary(bare,
|
|
10507
|
+
return new InitSummary(bare, path7, true, result[1]);
|
|
10504
10508
|
}
|
|
10505
10509
|
let gitDir = "";
|
|
10506
10510
|
const tokens = response.split(" ");
|
|
@@ -10511,7 +10515,7 @@ function parseInit(bare, path4, text) {
|
|
|
10511
10515
|
break;
|
|
10512
10516
|
}
|
|
10513
10517
|
}
|
|
10514
|
-
return new InitSummary(bare,
|
|
10518
|
+
return new InitSummary(bare, path7, /^re/i.test(response), gitDir);
|
|
10515
10519
|
}
|
|
10516
10520
|
var InitSummary;
|
|
10517
10521
|
var initResponseRegex;
|
|
@@ -10520,9 +10524,9 @@ var init_InitSummary = __esm({
|
|
|
10520
10524
|
"src/lib/responses/InitSummary.ts"() {
|
|
10521
10525
|
"use strict";
|
|
10522
10526
|
InitSummary = class {
|
|
10523
|
-
constructor(bare,
|
|
10527
|
+
constructor(bare, path7, existing, gitDir) {
|
|
10524
10528
|
this.bare = bare;
|
|
10525
|
-
this.path =
|
|
10529
|
+
this.path = path7;
|
|
10526
10530
|
this.existing = existing;
|
|
10527
10531
|
this.gitDir = gitDir;
|
|
10528
10532
|
}
|
|
@@ -10534,7 +10538,7 @@ var init_InitSummary = __esm({
|
|
|
10534
10538
|
function hasBareCommand(command) {
|
|
10535
10539
|
return command.includes(bareCommand);
|
|
10536
10540
|
}
|
|
10537
|
-
function initTask(bare = false,
|
|
10541
|
+
function initTask(bare = false, path7, customArgs) {
|
|
10538
10542
|
const commands = ["init", ...customArgs];
|
|
10539
10543
|
if (bare && !hasBareCommand(commands)) {
|
|
10540
10544
|
commands.splice(1, 0, bareCommand);
|
|
@@ -10543,7 +10547,7 @@ function initTask(bare = false, path4, customArgs) {
|
|
|
10543
10547
|
commands,
|
|
10544
10548
|
format: "utf-8",
|
|
10545
10549
|
parser(text) {
|
|
10546
|
-
return parseInit(commands.includes("--bare"),
|
|
10550
|
+
return parseInit(commands.includes("--bare"), path7, text);
|
|
10547
10551
|
}
|
|
10548
10552
|
};
|
|
10549
10553
|
}
|
|
@@ -11358,12 +11362,12 @@ var init_FileStatusSummary = __esm({
|
|
|
11358
11362
|
"use strict";
|
|
11359
11363
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
11360
11364
|
FileStatusSummary = class {
|
|
11361
|
-
constructor(
|
|
11362
|
-
this.path =
|
|
11365
|
+
constructor(path7, index, working_dir) {
|
|
11366
|
+
this.path = path7;
|
|
11363
11367
|
this.index = index;
|
|
11364
11368
|
this.working_dir = working_dir;
|
|
11365
11369
|
if (index === "R" || working_dir === "R") {
|
|
11366
|
-
const detail = fromPathRegex.exec(
|
|
11370
|
+
const detail = fromPathRegex.exec(path7) || [null, path7, path7];
|
|
11367
11371
|
this.from = detail[2] || "";
|
|
11368
11372
|
this.path = detail[1] || "";
|
|
11369
11373
|
}
|
|
@@ -11394,14 +11398,14 @@ function splitLine(result, lineStr) {
|
|
|
11394
11398
|
default:
|
|
11395
11399
|
return;
|
|
11396
11400
|
}
|
|
11397
|
-
function data(index, workingDir,
|
|
11401
|
+
function data(index, workingDir, path7) {
|
|
11398
11402
|
const raw = `${index}${workingDir}`;
|
|
11399
11403
|
const handler = parsers6.get(raw);
|
|
11400
11404
|
if (handler) {
|
|
11401
|
-
handler(result,
|
|
11405
|
+
handler(result, path7);
|
|
11402
11406
|
}
|
|
11403
11407
|
if (raw !== "##" && raw !== "!!") {
|
|
11404
|
-
result.files.push(new FileStatusSummary(
|
|
11408
|
+
result.files.push(new FileStatusSummary(path7, index, workingDir));
|
|
11405
11409
|
}
|
|
11406
11410
|
}
|
|
11407
11411
|
}
|
|
@@ -11752,9 +11756,9 @@ var init_simple_git_api = __esm({
|
|
|
11752
11756
|
next
|
|
11753
11757
|
);
|
|
11754
11758
|
}
|
|
11755
|
-
hashObject(
|
|
11759
|
+
hashObject(path7, write) {
|
|
11756
11760
|
return this._runTask(
|
|
11757
|
-
hashObjectTask(
|
|
11761
|
+
hashObjectTask(path7, write === true),
|
|
11758
11762
|
trailingFunctionArgument(arguments)
|
|
11759
11763
|
);
|
|
11760
11764
|
}
|
|
@@ -12108,8 +12112,8 @@ var init_branch = __esm({
|
|
|
12108
12112
|
}
|
|
12109
12113
|
});
|
|
12110
12114
|
function toPath(input) {
|
|
12111
|
-
const
|
|
12112
|
-
return
|
|
12115
|
+
const path7 = input.trim().replace(/^["']|["']$/g, "");
|
|
12116
|
+
return path7 && (0, import_node_path.normalize)(path7);
|
|
12113
12117
|
}
|
|
12114
12118
|
var parseCheckIgnore;
|
|
12115
12119
|
var init_CheckIgnore = __esm({
|
|
@@ -12394,8 +12398,8 @@ __export2(sub_module_exports, {
|
|
|
12394
12398
|
subModuleTask: () => subModuleTask,
|
|
12395
12399
|
updateSubModuleTask: () => updateSubModuleTask
|
|
12396
12400
|
});
|
|
12397
|
-
function addSubModuleTask(repo,
|
|
12398
|
-
return subModuleTask(["add", repo,
|
|
12401
|
+
function addSubModuleTask(repo, path7) {
|
|
12402
|
+
return subModuleTask(["add", repo, path7]);
|
|
12399
12403
|
}
|
|
12400
12404
|
function initSubModuleTask(customArgs) {
|
|
12401
12405
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -12709,8 +12713,8 @@ var require_git = __commonJS2({
|
|
|
12709
12713
|
}
|
|
12710
12714
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
12711
12715
|
};
|
|
12712
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
12713
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
12716
|
+
Git2.prototype.submoduleAdd = function(repo, path7, then) {
|
|
12717
|
+
return this._runTask(addSubModuleTask2(repo, path7), trailingFunctionArgument2(arguments));
|
|
12714
12718
|
};
|
|
12715
12719
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
12716
12720
|
return this._runTask(
|
|
@@ -13402,6 +13406,22 @@ function detectProviderFromCommit(commitMessage) {
|
|
|
13402
13406
|
mode: "observed"
|
|
13403
13407
|
};
|
|
13404
13408
|
}
|
|
13409
|
+
if (msg.includes("antigravity")) {
|
|
13410
|
+
return {
|
|
13411
|
+
provider: "antigravity",
|
|
13412
|
+
model: "claude-sonnet-4-6-thinking",
|
|
13413
|
+
confidence: 0.85,
|
|
13414
|
+
mode: "observed"
|
|
13415
|
+
};
|
|
13416
|
+
}
|
|
13417
|
+
if (msg.includes("gemini")) {
|
|
13418
|
+
return {
|
|
13419
|
+
provider: "google",
|
|
13420
|
+
model: "gemini-3-8-flash",
|
|
13421
|
+
confidence: 0.85,
|
|
13422
|
+
mode: "observed"
|
|
13423
|
+
};
|
|
13424
|
+
}
|
|
13405
13425
|
if (msg.includes("cursor")) {
|
|
13406
13426
|
return {
|
|
13407
13427
|
provider: "cursor",
|
|
@@ -13420,57 +13440,12 @@ function detectProviderFromCommit(commitMessage) {
|
|
|
13420
13440
|
}
|
|
13421
13441
|
return null;
|
|
13422
13442
|
}
|
|
13423
|
-
|
|
13424
|
-
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13428
|
-
|
|
13429
|
-
}
|
|
13430
|
-
try {
|
|
13431
|
-
const projectDirs = fs.readdirSync(claudeProjectsDir);
|
|
13432
|
-
const matchedDir = projectDirs.find((d) => d.toLowerCase().includes(projectAlias.toLowerCase()));
|
|
13433
|
-
if (matchedDir) {
|
|
13434
|
-
const sessionPath = path2.join(claudeProjectsDir, matchedDir);
|
|
13435
|
-
const files = fs.readdirSync(sessionPath).filter((f) => f.endsWith(".jsonl"));
|
|
13436
|
-
if (files.length > 0) {
|
|
13437
|
-
const latestFile = path2.join(sessionPath, files[files.length - 1]);
|
|
13438
|
-
const content = fs.readFileSync(latestFile, "utf-8");
|
|
13439
|
-
const lines = content.trim().split("\n");
|
|
13440
|
-
let inputTokens = 0;
|
|
13441
|
-
let outputTokens = 0;
|
|
13442
|
-
let cachedTokens = 0;
|
|
13443
|
-
for (const line of lines) {
|
|
13444
|
-
try {
|
|
13445
|
-
const data = JSON.parse(line);
|
|
13446
|
-
if (data.usage) {
|
|
13447
|
-
inputTokens += data.usage.input_tokens || 0;
|
|
13448
|
-
outputTokens += data.usage.output_tokens || 0;
|
|
13449
|
-
cachedTokens += data.usage.cache_read_input_tokens || 0;
|
|
13450
|
-
}
|
|
13451
|
-
} catch {
|
|
13452
|
-
}
|
|
13453
|
-
}
|
|
13454
|
-
if (inputTokens > 0 || outputTokens > 0) {
|
|
13455
|
-
sessions.push({
|
|
13456
|
-
provider: "anthropic",
|
|
13457
|
-
model: "claude-3-7-sonnet",
|
|
13458
|
-
tokens: {
|
|
13459
|
-
input: inputTokens,
|
|
13460
|
-
output: outputTokens,
|
|
13461
|
-
cached: cachedTokens
|
|
13462
|
-
},
|
|
13463
|
-
cost: Number((((inputTokens - cachedTokens) * 3 + cachedTokens * 0.3 + outputTokens * 15) / 1e6).toFixed(4)),
|
|
13464
|
-
confidence: 0.95,
|
|
13465
|
-
mode: "verified"
|
|
13466
|
-
});
|
|
13467
|
-
}
|
|
13468
|
-
}
|
|
13469
|
-
}
|
|
13470
|
-
} catch {
|
|
13471
|
-
}
|
|
13472
|
-
return sessions;
|
|
13473
|
-
}
|
|
13443
|
+
|
|
13444
|
+
// ../core/dist/harvester/antigravity.js
|
|
13445
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
13446
|
+
var path3 = __toESM(require("path"), 1);
|
|
13447
|
+
var os2 = __toESM(require("os"), 1);
|
|
13448
|
+
var import_node_module = require("module");
|
|
13474
13449
|
|
|
13475
13450
|
// ../pricing/dist/index.js
|
|
13476
13451
|
var RATE_CARDS = {
|
|
@@ -13485,6 +13460,26 @@ var RATE_CARDS = {
|
|
|
13485
13460
|
cacheWritePerMTok: 5,
|
|
13486
13461
|
contextWindow: 2e5
|
|
13487
13462
|
},
|
|
13463
|
+
"claude-opus-4-6-thinking": {
|
|
13464
|
+
id: "claude-opus-4-6-thinking",
|
|
13465
|
+
provider: "anthropic",
|
|
13466
|
+
name: "Claude Opus 4.6 Thinking",
|
|
13467
|
+
inputPerMTok: 5,
|
|
13468
|
+
outputPerMTok: 25,
|
|
13469
|
+
cacheReadPerMTok: 0.25,
|
|
13470
|
+
cacheWritePerMTok: 6.25,
|
|
13471
|
+
contextWindow: 2e5
|
|
13472
|
+
},
|
|
13473
|
+
"claude-sonnet-4-6-thinking": {
|
|
13474
|
+
id: "claude-sonnet-4-6-thinking",
|
|
13475
|
+
provider: "anthropic",
|
|
13476
|
+
name: "Claude Sonnet 4.6 Thinking",
|
|
13477
|
+
inputPerMTok: 3,
|
|
13478
|
+
outputPerMTok: 15,
|
|
13479
|
+
cacheReadPerMTok: 0.3,
|
|
13480
|
+
cacheWritePerMTok: 3.75,
|
|
13481
|
+
contextWindow: 2e5
|
|
13482
|
+
},
|
|
13488
13483
|
"claude-3-7-sonnet": {
|
|
13489
13484
|
id: "claude-3-7-sonnet",
|
|
13490
13485
|
provider: "anthropic",
|
|
@@ -13537,6 +13532,26 @@ var RATE_CARDS = {
|
|
|
13537
13532
|
contextWindow: 2e5
|
|
13538
13533
|
},
|
|
13539
13534
|
// Google
|
|
13535
|
+
"gemini-3-8-flash": {
|
|
13536
|
+
id: "gemini-3-8-flash",
|
|
13537
|
+
provider: "google",
|
|
13538
|
+
name: "Gemini 3.8 Flash",
|
|
13539
|
+
inputPerMTok: 0.1,
|
|
13540
|
+
outputPerMTok: 0.4,
|
|
13541
|
+
cacheReadPerMTok: 0.025,
|
|
13542
|
+
cacheWritePerMTok: 0.1,
|
|
13543
|
+
contextWindow: 1e6
|
|
13544
|
+
},
|
|
13545
|
+
"gemini-2-5-pro": {
|
|
13546
|
+
id: "gemini-2-5-pro",
|
|
13547
|
+
provider: "google",
|
|
13548
|
+
name: "Gemini 2.5 Pro",
|
|
13549
|
+
inputPerMTok: 1.25,
|
|
13550
|
+
outputPerMTok: 5,
|
|
13551
|
+
cacheReadPerMTok: 0.3,
|
|
13552
|
+
cacheWritePerMTok: 1.25,
|
|
13553
|
+
contextWindow: 2e6
|
|
13554
|
+
},
|
|
13540
13555
|
"gemini-2-0-flash": {
|
|
13541
13556
|
id: "gemini-2-0-flash",
|
|
13542
13557
|
provider: "google",
|
|
@@ -13594,7 +13609,27 @@ function getRateCard(modelId) {
|
|
|
13594
13609
|
if (!modelId)
|
|
13595
13610
|
return RATE_CARDS["default"];
|
|
13596
13611
|
const key = modelId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
13597
|
-
|
|
13612
|
+
if (RATE_CARDS[key])
|
|
13613
|
+
return RATE_CARDS[key];
|
|
13614
|
+
if (key.includes("opus")) {
|
|
13615
|
+
return RATE_CARDS["claude-opus-4-6-thinking"] || RATE_CARDS["claude-opus-4"];
|
|
13616
|
+
}
|
|
13617
|
+
if (key.includes("sonnet") && (key.includes("4-6") || key.includes("thinking"))) {
|
|
13618
|
+
return RATE_CARDS["claude-sonnet-4-6-thinking"];
|
|
13619
|
+
}
|
|
13620
|
+
if (key.includes("3-7") || key.includes("sonnet-3-7")) {
|
|
13621
|
+
return RATE_CARDS["claude-3-7-sonnet"];
|
|
13622
|
+
}
|
|
13623
|
+
if (key.includes("3-5") || key.includes("sonnet-3-5")) {
|
|
13624
|
+
return RATE_CARDS["claude-3-5-sonnet"];
|
|
13625
|
+
}
|
|
13626
|
+
if (key.includes("gemini") && key.includes("flash")) {
|
|
13627
|
+
return RATE_CARDS["gemini-3-8-flash"] || RATE_CARDS["gemini-2-0-flash"];
|
|
13628
|
+
}
|
|
13629
|
+
if (key.includes("gemini") && (key.includes("pro") || key.includes("2-5"))) {
|
|
13630
|
+
return RATE_CARDS["gemini-2-5-pro"] || RATE_CARDS["gemini-1-5-pro"];
|
|
13631
|
+
}
|
|
13632
|
+
return RATE_CARDS["default"];
|
|
13598
13633
|
}
|
|
13599
13634
|
function computeCost(inputTokens, outputTokens, cachedTokens, card) {
|
|
13600
13635
|
const freshInput = Math.max(0, inputTokens - cachedTokens);
|
|
@@ -13604,91 +13639,348 @@ function computeCost(inputTokens, outputTokens, cachedTokens, card) {
|
|
|
13604
13639
|
return Number((freshCost + cacheCost + outCost).toFixed(4));
|
|
13605
13640
|
}
|
|
13606
13641
|
|
|
13607
|
-
// ../core/dist/
|
|
13608
|
-
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
let totalCost = 0;
|
|
13615
|
-
for (const s of options.sessions) {
|
|
13616
|
-
totalInput += s.tokens.input;
|
|
13617
|
-
totalOutput += s.tokens.output;
|
|
13618
|
-
totalCached += s.tokens.cached;
|
|
13619
|
-
totalCost += s.cost;
|
|
13642
|
+
// ../core/dist/harvester/antigravity.js
|
|
13643
|
+
var import_meta = {};
|
|
13644
|
+
function getSqliteDatabase() {
|
|
13645
|
+
try {
|
|
13646
|
+
const mod = "node:sqlite";
|
|
13647
|
+
if (typeof require !== "undefined") {
|
|
13648
|
+
return require(mod).DatabaseSync;
|
|
13620
13649
|
}
|
|
13621
|
-
|
|
13622
|
-
provider: primary.provider,
|
|
13623
|
-
model: primary.model || "claude-3-7-sonnet",
|
|
13624
|
-
tokens: {
|
|
13625
|
-
input: totalInput,
|
|
13626
|
-
output: totalOutput,
|
|
13627
|
-
cached: totalCached
|
|
13628
|
-
},
|
|
13629
|
-
cost: Number(totalCost.toFixed(4)),
|
|
13630
|
-
mode: primary.mode,
|
|
13631
|
-
confidence: primary.confidence,
|
|
13632
|
-
sessions: options.sessions
|
|
13633
|
-
};
|
|
13650
|
+
} catch {
|
|
13634
13651
|
}
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
if (options.files >= 10) {
|
|
13642
|
-
multiplier = 60;
|
|
13643
|
-
} else if (options.files >= 3) {
|
|
13644
|
-
multiplier = 35;
|
|
13652
|
+
try {
|
|
13653
|
+
const mod = "node:sqlite";
|
|
13654
|
+
const req = (0, import_node_module.createRequire)(import_meta.url);
|
|
13655
|
+
return req(mod).DatabaseSync;
|
|
13656
|
+
} catch {
|
|
13657
|
+
return null;
|
|
13645
13658
|
}
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
const
|
|
13649
|
-
const
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
const
|
|
13653
|
-
|
|
13654
|
-
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
13658
|
-
|
|
13659
|
-
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
|
|
13659
|
+
}
|
|
13660
|
+
function harvestAntigravityFootprints(repoPath, sinceDate) {
|
|
13661
|
+
const footprints = [];
|
|
13662
|
+
const DatabaseSync2 = getSqliteDatabase();
|
|
13663
|
+
if (!DatabaseSync2)
|
|
13664
|
+
return footprints;
|
|
13665
|
+
const homedir6 = os2.homedir();
|
|
13666
|
+
const antigravityDir = process.env.ANTIGRAVITY_APP_DATA_DIR || path3.join(homedir6, ".gemini", "antigravity");
|
|
13667
|
+
const dbPath = path3.join(antigravityDir, "conversation_summaries.db");
|
|
13668
|
+
if (!fs2.existsSync(dbPath)) {
|
|
13669
|
+
return footprints;
|
|
13670
|
+
}
|
|
13671
|
+
try {
|
|
13672
|
+
const db = new DatabaseSync2(dbPath, { readOnly: true });
|
|
13673
|
+
const normTarget = repoPath.toLowerCase().replace(/\\/g, "/");
|
|
13674
|
+
const rows = db.prepare("SELECT conversation_id, title, preview, step_count, last_modified_time, workspace_uris FROM conversation_summaries ORDER BY last_modified_time DESC LIMIT 50").all();
|
|
13675
|
+
for (const row of rows) {
|
|
13676
|
+
if (!row.workspace_uris)
|
|
13677
|
+
continue;
|
|
13678
|
+
let matched = false;
|
|
13679
|
+
try {
|
|
13680
|
+
const uris = JSON.parse(row.workspace_uris);
|
|
13681
|
+
matched = uris.some((u) => {
|
|
13682
|
+
const decoded = decodeURIComponent(u.replace(/^file:\/\/\/?/, "")).toLowerCase().replace(/\\/g, "/");
|
|
13683
|
+
return decoded.includes(normTarget) || normTarget.includes(decoded);
|
|
13684
|
+
});
|
|
13685
|
+
} catch {
|
|
13686
|
+
continue;
|
|
13687
|
+
}
|
|
13688
|
+
if (!matched)
|
|
13689
|
+
continue;
|
|
13690
|
+
const rowTime = new Date(row.last_modified_time);
|
|
13691
|
+
if (sinceDate && rowTime < sinceDate) {
|
|
13692
|
+
continue;
|
|
13693
|
+
}
|
|
13694
|
+
const transcriptPath = path3.join(antigravityDir, "brain", row.conversation_id, ".system_generated", "logs", "transcript.jsonl");
|
|
13695
|
+
let detectedModel = "claude-sonnet-4-6-thinking";
|
|
13696
|
+
const filesEdited = /* @__PURE__ */ new Set();
|
|
13697
|
+
if (fs2.existsSync(transcriptPath)) {
|
|
13698
|
+
try {
|
|
13699
|
+
const content = fs2.readFileSync(transcriptPath, "utf-8");
|
|
13700
|
+
const lines = content.split("\n");
|
|
13701
|
+
for (const line of lines) {
|
|
13702
|
+
if (!line.trim())
|
|
13703
|
+
continue;
|
|
13704
|
+
if (line.includes("Model Selection")) {
|
|
13705
|
+
const match = line.match(/Model Selection` from .*?to ([^\.\(\n\r]+)/);
|
|
13706
|
+
if (match && match[1]) {
|
|
13707
|
+
const rawModel = match[1].trim();
|
|
13708
|
+
if (rawModel.toLowerCase().includes("opus"))
|
|
13709
|
+
detectedModel = "claude-opus-4-6-thinking";
|
|
13710
|
+
else if (rawModel.toLowerCase().includes("sonnet"))
|
|
13711
|
+
detectedModel = "claude-sonnet-4-6-thinking";
|
|
13712
|
+
else if (rawModel.toLowerCase().includes("flash"))
|
|
13713
|
+
detectedModel = "gemini-3-8-flash";
|
|
13714
|
+
else if (rawModel.toLowerCase().includes("pro"))
|
|
13715
|
+
detectedModel = "gemini-2-5-pro";
|
|
13716
|
+
else
|
|
13717
|
+
detectedModel = rawModel.toLowerCase().replace(/\s+/g, "-");
|
|
13718
|
+
}
|
|
13719
|
+
}
|
|
13720
|
+
if (line.includes('"replace_file_content"') || line.includes('"write_to_file"')) {
|
|
13721
|
+
try {
|
|
13722
|
+
const obj = JSON.parse(line);
|
|
13723
|
+
if (obj.tool_calls) {
|
|
13724
|
+
for (const tc of obj.tool_calls) {
|
|
13725
|
+
if ((tc.name === "replace_file_content" || tc.name === "write_to_file") && tc.args) {
|
|
13726
|
+
const file = tc.args.TargetFile || tc.args.targetFile;
|
|
13727
|
+
if (file) {
|
|
13728
|
+
filesEdited.add(path3.relative(repoPath, file.replace(/"/g, "")).replace(/\\/g, "/"));
|
|
13729
|
+
}
|
|
13730
|
+
}
|
|
13731
|
+
}
|
|
13732
|
+
}
|
|
13733
|
+
} catch {
|
|
13734
|
+
}
|
|
13735
|
+
}
|
|
13736
|
+
}
|
|
13737
|
+
} catch {
|
|
13738
|
+
}
|
|
13739
|
+
}
|
|
13740
|
+
const rateCard = getRateCard(detectedModel);
|
|
13741
|
+
const stepCount = row.step_count || 1;
|
|
13742
|
+
const estimatedInput = Math.max(stepCount * 1500, 4e3);
|
|
13743
|
+
const estimatedCached = Math.round(estimatedInput * 0.7);
|
|
13744
|
+
const estimatedOutput = Math.max(stepCount * 180, 400);
|
|
13745
|
+
const cost = computeCost(estimatedInput, estimatedOutput, estimatedCached, rateCard);
|
|
13746
|
+
footprints.push({
|
|
13747
|
+
id: `antigravity_${row.conversation_id}`,
|
|
13748
|
+
platform: "antigravity",
|
|
13749
|
+
sessionId: row.conversation_id,
|
|
13750
|
+
repoPath,
|
|
13751
|
+
taskTitle: row.title || row.preview || "Antigravity Task",
|
|
13752
|
+
model: detectedModel,
|
|
13753
|
+
stepsCount: stepCount,
|
|
13754
|
+
filesEdited: Array.from(filesEdited),
|
|
13755
|
+
timestamp: row.last_modified_time,
|
|
13668
13756
|
tokens: {
|
|
13669
|
-
input:
|
|
13670
|
-
output:
|
|
13671
|
-
cached:
|
|
13757
|
+
input: estimatedInput,
|
|
13758
|
+
output: estimatedOutput,
|
|
13759
|
+
cached: estimatedCached
|
|
13672
13760
|
},
|
|
13673
13761
|
cost,
|
|
13674
|
-
|
|
13675
|
-
|
|
13762
|
+
mode: "verified",
|
|
13763
|
+
confidence: 0.95,
|
|
13764
|
+
rawTranscriptPath: transcriptPath
|
|
13765
|
+
});
|
|
13766
|
+
}
|
|
13767
|
+
} catch {
|
|
13768
|
+
}
|
|
13769
|
+
return footprints;
|
|
13770
|
+
}
|
|
13771
|
+
|
|
13772
|
+
// ../core/dist/harvester/claude.js
|
|
13773
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
13774
|
+
var path4 = __toESM(require("path"), 1);
|
|
13775
|
+
var os3 = __toESM(require("os"), 1);
|
|
13776
|
+
function harvestClaudeFootprints(repoPath, projectAlias, sinceDate) {
|
|
13777
|
+
const footprints = [];
|
|
13778
|
+
const homedir6 = os3.homedir();
|
|
13779
|
+
const claudeProjectsDir = path4.join(homedir6, ".claude", "projects");
|
|
13780
|
+
if (!fs3.existsSync(claudeProjectsDir)) {
|
|
13781
|
+
return footprints;
|
|
13782
|
+
}
|
|
13783
|
+
try {
|
|
13784
|
+
const projectDirs = fs3.readdirSync(claudeProjectsDir);
|
|
13785
|
+
const matchedDir = projectDirs.find((d) => d.toLowerCase().includes(projectAlias.toLowerCase()) || projectAlias.toLowerCase().includes(d.toLowerCase()));
|
|
13786
|
+
if (!matchedDir)
|
|
13787
|
+
return footprints;
|
|
13788
|
+
const sessionDir = path4.join(claudeProjectsDir, matchedDir);
|
|
13789
|
+
const files = fs3.readdirSync(sessionDir).filter((f) => f.endsWith(".jsonl"));
|
|
13790
|
+
for (const f of files) {
|
|
13791
|
+
const filePath = path4.join(sessionDir, f);
|
|
13792
|
+
const stat = fs3.statSync(filePath);
|
|
13793
|
+
if (sinceDate && stat.mtime < sinceDate)
|
|
13794
|
+
continue;
|
|
13795
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
13796
|
+
const lines = content.trim().split("\n");
|
|
13797
|
+
let inputTokens = 0;
|
|
13798
|
+
let outputTokens = 0;
|
|
13799
|
+
let cachedTokens = 0;
|
|
13800
|
+
let taskTitle = "";
|
|
13801
|
+
let model = "claude-3-7-sonnet";
|
|
13802
|
+
const filesEdited = /* @__PURE__ */ new Set();
|
|
13803
|
+
for (const line of lines) {
|
|
13804
|
+
if (!line.trim())
|
|
13805
|
+
continue;
|
|
13806
|
+
try {
|
|
13807
|
+
const data = JSON.parse(line);
|
|
13808
|
+
if (data.model)
|
|
13809
|
+
model = data.model;
|
|
13810
|
+
if (data.usage) {
|
|
13811
|
+
inputTokens += data.usage.input_tokens || 0;
|
|
13812
|
+
outputTokens += data.usage.output_tokens || 0;
|
|
13813
|
+
cachedTokens += data.usage.cache_read_input_tokens || 0;
|
|
13814
|
+
}
|
|
13815
|
+
if (!taskTitle && data.type === "user_message" && data.text) {
|
|
13816
|
+
taskTitle = data.text.slice(0, 60).replace(/\n/g, " ");
|
|
13817
|
+
}
|
|
13818
|
+
if (data.tool_name === "Edit" || data.tool_name === "Write") {
|
|
13819
|
+
if (data.tool_input?.file_path) {
|
|
13820
|
+
filesEdited.add(path4.relative(repoPath, data.tool_input.file_path).replace(/\\/g, "/"));
|
|
13821
|
+
}
|
|
13822
|
+
}
|
|
13823
|
+
} catch {
|
|
13824
|
+
}
|
|
13676
13825
|
}
|
|
13677
|
-
|
|
13678
|
-
|
|
13826
|
+
if (inputTokens > 0 || outputTokens > 0) {
|
|
13827
|
+
const rateCard = getRateCard(model);
|
|
13828
|
+
const cost = computeCost(inputTokens, outputTokens, cachedTokens, rateCard);
|
|
13829
|
+
footprints.push({
|
|
13830
|
+
id: `claude_${f.replace(/\.jsonl$/, "")}`,
|
|
13831
|
+
platform: "claude",
|
|
13832
|
+
sessionId: f.replace(/\.jsonl$/, ""),
|
|
13833
|
+
repoPath,
|
|
13834
|
+
taskTitle: taskTitle || "Claude Code Task",
|
|
13835
|
+
model,
|
|
13836
|
+
stepsCount: lines.length,
|
|
13837
|
+
filesEdited: Array.from(filesEdited),
|
|
13838
|
+
timestamp: stat.mtime.toISOString(),
|
|
13839
|
+
tokens: {
|
|
13840
|
+
input: inputTokens,
|
|
13841
|
+
output: outputTokens,
|
|
13842
|
+
cached: cachedTokens
|
|
13843
|
+
},
|
|
13844
|
+
cost,
|
|
13845
|
+
mode: "verified",
|
|
13846
|
+
confidence: 0.95,
|
|
13847
|
+
rawTranscriptPath: filePath
|
|
13848
|
+
});
|
|
13849
|
+
}
|
|
13850
|
+
}
|
|
13851
|
+
} catch {
|
|
13852
|
+
}
|
|
13853
|
+
return footprints;
|
|
13854
|
+
}
|
|
13855
|
+
|
|
13856
|
+
// ../core/dist/harvester/cursor.js
|
|
13857
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
13858
|
+
var path5 = __toESM(require("path"), 1);
|
|
13859
|
+
var os4 = __toESM(require("os"), 1);
|
|
13860
|
+
var import_node_module2 = require("module");
|
|
13861
|
+
var import_meta2 = {};
|
|
13862
|
+
function getSqliteDatabase2() {
|
|
13863
|
+
try {
|
|
13864
|
+
const mod = "node:sqlite";
|
|
13865
|
+
if (typeof require !== "undefined") {
|
|
13866
|
+
return require(mod).DatabaseSync;
|
|
13867
|
+
}
|
|
13868
|
+
} catch {
|
|
13869
|
+
}
|
|
13870
|
+
try {
|
|
13871
|
+
const mod = "node:sqlite";
|
|
13872
|
+
const req = (0, import_node_module2.createRequire)(import_meta2.url);
|
|
13873
|
+
return req(mod).DatabaseSync;
|
|
13874
|
+
} catch {
|
|
13875
|
+
return null;
|
|
13876
|
+
}
|
|
13877
|
+
}
|
|
13878
|
+
function harvestCursorFootprints(repoPath, sinceDate) {
|
|
13879
|
+
const footprints = [];
|
|
13880
|
+
const DatabaseSync2 = getSqliteDatabase2();
|
|
13881
|
+
if (!DatabaseSync2)
|
|
13882
|
+
return footprints;
|
|
13883
|
+
let storageDir = "";
|
|
13884
|
+
if (process.platform === "win32") {
|
|
13885
|
+
storageDir = path5.join(process.env.APPDATA || path5.join(os4.homedir(), "AppData", "Roaming"), "Cursor", "User", "workspaceStorage");
|
|
13886
|
+
} else if (process.platform === "darwin") {
|
|
13887
|
+
storageDir = path5.join(os4.homedir(), "Library", "Application Support", "Cursor", "User", "workspaceStorage");
|
|
13888
|
+
} else {
|
|
13889
|
+
storageDir = path5.join(os4.homedir(), ".config", "Cursor", "User", "workspaceStorage");
|
|
13890
|
+
}
|
|
13891
|
+
if (!fs4.existsSync(storageDir))
|
|
13892
|
+
return footprints;
|
|
13893
|
+
try {
|
|
13894
|
+
const normTarget = repoPath.toLowerCase().replace(/\\/g, "/");
|
|
13895
|
+
const wsDirs = fs4.readdirSync(storageDir);
|
|
13896
|
+
for (const ws of wsDirs) {
|
|
13897
|
+
const wsPath = path5.join(storageDir, ws);
|
|
13898
|
+
const wsJsonPath = path5.join(wsPath, "workspace.json");
|
|
13899
|
+
if (!fs4.existsSync(wsJsonPath))
|
|
13900
|
+
continue;
|
|
13901
|
+
try {
|
|
13902
|
+
const wsJson = JSON.parse(fs4.readFileSync(wsJsonPath, "utf-8"));
|
|
13903
|
+
const folder = (wsJson.folder || wsJson.workspace || "").toLowerCase().replace(/\\/g, "/");
|
|
13904
|
+
if (!folder.includes(normTarget) && !normTarget.includes(folder))
|
|
13905
|
+
continue;
|
|
13906
|
+
const dbFile = path5.join(wsPath, "state.vscdb");
|
|
13907
|
+
if (!fs4.existsSync(dbFile))
|
|
13908
|
+
continue;
|
|
13909
|
+
const dbStat = fs4.statSync(dbFile);
|
|
13910
|
+
if (sinceDate && dbStat.mtime < sinceDate)
|
|
13911
|
+
continue;
|
|
13912
|
+
const db = new DatabaseSync2(dbFile, { readOnly: true });
|
|
13913
|
+
const row = db.prepare("SELECT value FROM ItemTable WHERE key = 'workbench.panel.aichat.chatdata' OR key = 'aiService.generations' LIMIT 1").get();
|
|
13914
|
+
if (row && row.value) {
|
|
13915
|
+
const parsed = JSON.parse(row.value);
|
|
13916
|
+
const tabs = parsed.tabs || (Array.isArray(parsed) ? parsed : []);
|
|
13917
|
+
let stepCount = 0;
|
|
13918
|
+
let taskTitle = "";
|
|
13919
|
+
let model = "claude-3-5-sonnet";
|
|
13920
|
+
for (const tab of tabs) {
|
|
13921
|
+
const bubbles = tab.bubbles || [];
|
|
13922
|
+
stepCount += bubbles.length;
|
|
13923
|
+
if (!taskTitle && tab.chatTitle)
|
|
13924
|
+
taskTitle = tab.chatTitle;
|
|
13925
|
+
for (const b2 of bubbles) {
|
|
13926
|
+
if (b2.modelType)
|
|
13927
|
+
model = b2.modelType;
|
|
13928
|
+
}
|
|
13929
|
+
}
|
|
13930
|
+
if (stepCount > 0) {
|
|
13931
|
+
const rateCard = getRateCard(model);
|
|
13932
|
+
const estInput = stepCount * 2500;
|
|
13933
|
+
const estCached = Math.round(estInput * 0.6);
|
|
13934
|
+
const estOutput = stepCount * 250;
|
|
13935
|
+
const cost = computeCost(estInput, estOutput, estCached, rateCard);
|
|
13936
|
+
footprints.push({
|
|
13937
|
+
id: `cursor_${ws}`,
|
|
13938
|
+
platform: "cursor",
|
|
13939
|
+
sessionId: ws,
|
|
13940
|
+
repoPath,
|
|
13941
|
+
taskTitle: taskTitle || "Cursor AI Session",
|
|
13942
|
+
model,
|
|
13943
|
+
stepsCount: stepCount,
|
|
13944
|
+
filesEdited: [],
|
|
13945
|
+
timestamp: dbStat.mtime.toISOString(),
|
|
13946
|
+
tokens: {
|
|
13947
|
+
input: estInput,
|
|
13948
|
+
output: estOutput,
|
|
13949
|
+
cached: estCached
|
|
13950
|
+
},
|
|
13951
|
+
cost,
|
|
13952
|
+
mode: "imported",
|
|
13953
|
+
confidence: 0.85,
|
|
13954
|
+
rawTranscriptPath: dbFile
|
|
13955
|
+
});
|
|
13956
|
+
}
|
|
13957
|
+
}
|
|
13958
|
+
} catch {
|
|
13959
|
+
}
|
|
13960
|
+
}
|
|
13961
|
+
} catch {
|
|
13962
|
+
}
|
|
13963
|
+
return footprints;
|
|
13679
13964
|
}
|
|
13680
13965
|
|
|
13681
13966
|
// ../core/dist/db.js
|
|
13682
|
-
var
|
|
13683
|
-
var
|
|
13684
|
-
var
|
|
13685
|
-
var
|
|
13686
|
-
var
|
|
13967
|
+
var import_node_module3 = require("module");
|
|
13968
|
+
var path6 = __toESM(require("path"), 1);
|
|
13969
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
13970
|
+
var os5 = __toESM(require("os"), 1);
|
|
13971
|
+
var import_meta3 = {};
|
|
13687
13972
|
function getDatabaseSyncClass() {
|
|
13688
13973
|
try {
|
|
13689
|
-
const
|
|
13690
|
-
|
|
13691
|
-
|
|
13974
|
+
const mod = "node:sqlite";
|
|
13975
|
+
if (typeof require !== "undefined") {
|
|
13976
|
+
return require(mod).DatabaseSync;
|
|
13977
|
+
}
|
|
13978
|
+
} catch {
|
|
13979
|
+
}
|
|
13980
|
+
try {
|
|
13981
|
+
const mod = "node:sqlite";
|
|
13982
|
+
const req = (0, import_node_module3.createRequire)(import_meta3.url);
|
|
13983
|
+
return req(mod).DatabaseSync;
|
|
13692
13984
|
} catch {
|
|
13693
13985
|
return null;
|
|
13694
13986
|
}
|
|
@@ -13704,11 +13996,11 @@ var LocalStateDB = class {
|
|
|
13704
13996
|
if (inMemory || process.env.CI === "true" || process.env.QODEWK_NO_DB === "true") {
|
|
13705
13997
|
this.db = new DatabaseSync(":memory:");
|
|
13706
13998
|
} else {
|
|
13707
|
-
const qodewkDir =
|
|
13708
|
-
if (!
|
|
13709
|
-
|
|
13999
|
+
const qodewkDir = path6.join(os5.homedir(), ".qodewk");
|
|
14000
|
+
if (!fs5.existsSync(qodewkDir)) {
|
|
14001
|
+
fs5.mkdirSync(qodewkDir, { recursive: true });
|
|
13710
14002
|
}
|
|
13711
|
-
const dbPath =
|
|
14003
|
+
const dbPath = path6.join(qodewkDir, "state.db");
|
|
13712
14004
|
this.db = new DatabaseSync(dbPath);
|
|
13713
14005
|
}
|
|
13714
14006
|
this.migrate();
|
|
@@ -13749,8 +14041,60 @@ var LocalStateDB = class {
|
|
|
13749
14041
|
sync_status TEXT DEFAULT 'local',
|
|
13750
14042
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
13751
14043
|
);
|
|
14044
|
+
|
|
14045
|
+
CREATE TABLE IF NOT EXISTS agent_footprints (
|
|
14046
|
+
id TEXT PRIMARY KEY,
|
|
14047
|
+
platform TEXT NOT NULL,
|
|
14048
|
+
repo_path TEXT NOT NULL,
|
|
14049
|
+
session_id TEXT NOT NULL,
|
|
14050
|
+
task_title TEXT,
|
|
14051
|
+
model TEXT NOT NULL,
|
|
14052
|
+
steps_count INTEGER DEFAULT 0,
|
|
14053
|
+
files_edited TEXT,
|
|
14054
|
+
timestamp DATETIME NOT NULL,
|
|
14055
|
+
tokens_input INTEGER DEFAULT 0,
|
|
14056
|
+
tokens_output INTEGER DEFAULT 0,
|
|
14057
|
+
tokens_cached INTEGER DEFAULT 0,
|
|
14058
|
+
cost REAL DEFAULT 0,
|
|
14059
|
+
mode TEXT DEFAULT 'verified',
|
|
14060
|
+
confidence REAL DEFAULT 0.9,
|
|
14061
|
+
raw_transcript_path TEXT,
|
|
14062
|
+
captured_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
14063
|
+
);
|
|
13752
14064
|
`);
|
|
13753
14065
|
}
|
|
14066
|
+
saveFootprint(fp) {
|
|
14067
|
+
if (!this.db)
|
|
14068
|
+
return;
|
|
14069
|
+
try {
|
|
14070
|
+
const stmt = this.db.prepare(`
|
|
14071
|
+
INSERT OR REPLACE INTO agent_footprints (
|
|
14072
|
+
id, platform, repo_path, session_id, task_title, model, steps_count,
|
|
14073
|
+
files_edited, timestamp, tokens_input, tokens_output, tokens_cached,
|
|
14074
|
+
cost, mode, confidence, raw_transcript_path
|
|
14075
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
14076
|
+
`);
|
|
14077
|
+
stmt.run(fp.id, fp.platform, fp.repoPath, fp.sessionId, fp.taskTitle || null, fp.model, fp.stepsCount || 0, JSON.stringify(fp.filesEdited || []), fp.timestamp, fp.tokens.input, fp.tokens.output, fp.tokens.cached, fp.cost, fp.mode, fp.confidence, fp.rawTranscriptPath || null);
|
|
14078
|
+
} catch {
|
|
14079
|
+
}
|
|
14080
|
+
}
|
|
14081
|
+
getFootprints(repoPath, sinceDate) {
|
|
14082
|
+
if (!this.db)
|
|
14083
|
+
return [];
|
|
14084
|
+
try {
|
|
14085
|
+
const normTarget = repoPath.toLowerCase().replace(/\\/g, "/");
|
|
14086
|
+
let query = "SELECT * FROM agent_footprints WHERE LOWER(REPLACE(repo_path, '\\', '/')) LIKE ? ";
|
|
14087
|
+
const params = [`%${normTarget}%`];
|
|
14088
|
+
if (sinceDate) {
|
|
14089
|
+
query += "AND timestamp >= ? ";
|
|
14090
|
+
params.push(sinceDate.toISOString());
|
|
14091
|
+
}
|
|
14092
|
+
query += "ORDER BY timestamp DESC";
|
|
14093
|
+
return this.db.prepare(query).all(...params);
|
|
14094
|
+
} catch {
|
|
14095
|
+
return [];
|
|
14096
|
+
}
|
|
14097
|
+
}
|
|
13754
14098
|
saveReceipt(receipt, claimToken) {
|
|
13755
14099
|
if (!this.db)
|
|
13756
14100
|
return;
|
|
@@ -13775,6 +14119,170 @@ var LocalStateDB = class {
|
|
|
13775
14119
|
}
|
|
13776
14120
|
};
|
|
13777
14121
|
|
|
14122
|
+
// ../core/dist/harvester/index.js
|
|
14123
|
+
function parseSinceOption(since) {
|
|
14124
|
+
if (!since)
|
|
14125
|
+
return void 0;
|
|
14126
|
+
if (since instanceof Date)
|
|
14127
|
+
return since;
|
|
14128
|
+
const s = since.trim().toLowerCase();
|
|
14129
|
+
const now = /* @__PURE__ */ new Date();
|
|
14130
|
+
if (s === "today") {
|
|
14131
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
14132
|
+
return today;
|
|
14133
|
+
}
|
|
14134
|
+
const hoursMatch = s.match(/^(\d+)\s*h(?:ours?)?$/);
|
|
14135
|
+
if (hoursMatch && hoursMatch[1]) {
|
|
14136
|
+
const hours = parseInt(hoursMatch[1], 10);
|
|
14137
|
+
return new Date(now.getTime() - hours * 60 * 60 * 1e3);
|
|
14138
|
+
}
|
|
14139
|
+
const daysMatch = s.match(/^(\d+)\s*d(?:ays?)?$/);
|
|
14140
|
+
if (daysMatch && daysMatch[1]) {
|
|
14141
|
+
const days = parseInt(daysMatch[1], 10);
|
|
14142
|
+
return new Date(now.getTime() - days * 24 * 60 * 60 * 1e3);
|
|
14143
|
+
}
|
|
14144
|
+
const parsed = new Date(since);
|
|
14145
|
+
if (!isNaN(parsed.getTime())) {
|
|
14146
|
+
return parsed;
|
|
14147
|
+
}
|
|
14148
|
+
return void 0;
|
|
14149
|
+
}
|
|
14150
|
+
async function harvestUniversalFootprints(options) {
|
|
14151
|
+
const sinceDate = parseSinceOption(options.since);
|
|
14152
|
+
const alias = options.projectAlias || "";
|
|
14153
|
+
let allFootprints = [];
|
|
14154
|
+
if (!options.platform || options.platform === "all" || options.platform === "antigravity") {
|
|
14155
|
+
const agFootprints = harvestAntigravityFootprints(options.repoPath, sinceDate);
|
|
14156
|
+
allFootprints.push(...agFootprints);
|
|
14157
|
+
}
|
|
14158
|
+
if (!options.platform || options.platform === "all" || options.platform === "claude") {
|
|
14159
|
+
const claudeFootprints = harvestClaudeFootprints(options.repoPath, alias, sinceDate);
|
|
14160
|
+
allFootprints.push(...claudeFootprints);
|
|
14161
|
+
}
|
|
14162
|
+
if (!options.platform || options.platform === "all" || options.platform === "cursor") {
|
|
14163
|
+
const cursorFootprints = harvestCursorFootprints(options.repoPath, sinceDate);
|
|
14164
|
+
allFootprints.push(...cursorFootprints);
|
|
14165
|
+
}
|
|
14166
|
+
allFootprints.sort((a, b2) => new Date(b2.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
14167
|
+
try {
|
|
14168
|
+
const db = new LocalStateDB();
|
|
14169
|
+
for (const fp of allFootprints) {
|
|
14170
|
+
db.saveFootprint(fp);
|
|
14171
|
+
}
|
|
14172
|
+
db.close();
|
|
14173
|
+
} catch {
|
|
14174
|
+
}
|
|
14175
|
+
const platforms = Array.from(new Set(allFootprints.map((f) => f.platform)));
|
|
14176
|
+
const models = Array.from(new Set(allFootprints.map((f) => f.model)));
|
|
14177
|
+
const tasks = Array.from(new Set(allFootprints.map((f) => f.taskTitle).filter(Boolean)));
|
|
14178
|
+
const filesSet = /* @__PURE__ */ new Set();
|
|
14179
|
+
for (const fp of allFootprints) {
|
|
14180
|
+
for (const f of fp.filesEdited)
|
|
14181
|
+
filesSet.add(f);
|
|
14182
|
+
}
|
|
14183
|
+
let totalInput = 0;
|
|
14184
|
+
let totalOutput = 0;
|
|
14185
|
+
let totalCached = 0;
|
|
14186
|
+
let totalCost = 0;
|
|
14187
|
+
for (const fp of allFootprints) {
|
|
14188
|
+
totalInput += fp.tokens.input;
|
|
14189
|
+
totalOutput += fp.tokens.output;
|
|
14190
|
+
totalCached += fp.tokens.cached;
|
|
14191
|
+
totalCost += fp.cost;
|
|
14192
|
+
}
|
|
14193
|
+
const primary = allFootprints[0];
|
|
14194
|
+
return {
|
|
14195
|
+
footprints: allFootprints,
|
|
14196
|
+
primaryFootprint: primary,
|
|
14197
|
+
platforms,
|
|
14198
|
+
models,
|
|
14199
|
+
tasks,
|
|
14200
|
+
filesEdited: Array.from(filesSet),
|
|
14201
|
+
totalTokens: {
|
|
14202
|
+
input: totalInput,
|
|
14203
|
+
output: totalOutput,
|
|
14204
|
+
cached: totalCached
|
|
14205
|
+
},
|
|
14206
|
+
totalCost: Number(totalCost.toFixed(4)),
|
|
14207
|
+
mode: primary ? primary.mode : "unknown",
|
|
14208
|
+
confidence: primary ? primary.confidence : 0.45
|
|
14209
|
+
};
|
|
14210
|
+
}
|
|
14211
|
+
|
|
14212
|
+
// ../core/dist/estimator.js
|
|
14213
|
+
function estimateCost(options) {
|
|
14214
|
+
if (options.sessions && options.sessions.length > 0) {
|
|
14215
|
+
const primary = options.sessions[0];
|
|
14216
|
+
let totalInput = 0;
|
|
14217
|
+
let totalOutput = 0;
|
|
14218
|
+
let totalCached = 0;
|
|
14219
|
+
let totalCost = 0;
|
|
14220
|
+
for (const s of options.sessions) {
|
|
14221
|
+
totalInput += s.tokens.input;
|
|
14222
|
+
totalOutput += s.tokens.output;
|
|
14223
|
+
totalCached += s.tokens.cached;
|
|
14224
|
+
totalCost += s.cost;
|
|
14225
|
+
}
|
|
14226
|
+
return {
|
|
14227
|
+
provider: primary.provider,
|
|
14228
|
+
model: primary.model || "claude-3-7-sonnet",
|
|
14229
|
+
tokens: {
|
|
14230
|
+
input: totalInput,
|
|
14231
|
+
output: totalOutput,
|
|
14232
|
+
cached: totalCached
|
|
14233
|
+
},
|
|
14234
|
+
cost: Number(totalCost.toFixed(4)),
|
|
14235
|
+
mode: primary.mode,
|
|
14236
|
+
confidence: primary.confidence,
|
|
14237
|
+
sessions: options.sessions
|
|
14238
|
+
};
|
|
14239
|
+
}
|
|
14240
|
+
const provider = options.provider || "generic";
|
|
14241
|
+
const model = options.model || (provider === "antigravity" ? "claude-sonnet-4-6-thinking" : provider === "anthropic" ? "claude-3-7-sonnet" : "standard-frontier");
|
|
14242
|
+
const rateCard = getRateCard(model);
|
|
14243
|
+
const approxChars = (options.insertions + options.deletions) * 35;
|
|
14244
|
+
const baseCodeTokens = Math.max(Math.round(approxChars / 4), 50);
|
|
14245
|
+
let multiplier = 15;
|
|
14246
|
+
if (options.files >= 10) {
|
|
14247
|
+
multiplier = 60;
|
|
14248
|
+
} else if (options.files >= 3) {
|
|
14249
|
+
multiplier = 35;
|
|
14250
|
+
}
|
|
14251
|
+
const maxContextCap = rateCard.contextWindow || 2e5;
|
|
14252
|
+
const estimatedInputTokens = Math.min(baseCodeTokens * multiplier, maxContextCap);
|
|
14253
|
+
const estimatedOutputTokens = Math.max(Math.round(options.insertions * 35 / 4), 50);
|
|
14254
|
+
const cachedTokens = Math.round(estimatedInputTokens * 0.6);
|
|
14255
|
+
const cost = computeCost(estimatedInputTokens, estimatedOutputTokens, cachedTokens, rateCard);
|
|
14256
|
+
const confidence = options.confidence !== void 0 ? options.confidence : options.provider ? 0.65 : 0.45;
|
|
14257
|
+
const mode = options.mode || (options.provider ? "estimated" : "unknown");
|
|
14258
|
+
return {
|
|
14259
|
+
provider,
|
|
14260
|
+
model,
|
|
14261
|
+
tokens: {
|
|
14262
|
+
input: estimatedInputTokens,
|
|
14263
|
+
output: estimatedOutputTokens,
|
|
14264
|
+
cached: cachedTokens
|
|
14265
|
+
},
|
|
14266
|
+
cost,
|
|
14267
|
+
mode,
|
|
14268
|
+
confidence,
|
|
14269
|
+
sessions: [
|
|
14270
|
+
{
|
|
14271
|
+
provider,
|
|
14272
|
+
model,
|
|
14273
|
+
tokens: {
|
|
14274
|
+
input: estimatedInputTokens,
|
|
14275
|
+
output: estimatedOutputTokens,
|
|
14276
|
+
cached: cachedTokens
|
|
14277
|
+
},
|
|
14278
|
+
cost,
|
|
14279
|
+
confidence,
|
|
14280
|
+
mode
|
|
14281
|
+
}
|
|
14282
|
+
]
|
|
14283
|
+
};
|
|
14284
|
+
}
|
|
14285
|
+
|
|
13778
14286
|
// ../core/dist/format.js
|
|
13779
14287
|
function formatMarkdownReceipt(receipt, publicUrl) {
|
|
13780
14288
|
const url = publicUrl || `https://qodewk.dev/r/${receipt.receipt.id}`;
|
|
@@ -13812,18 +14320,40 @@ async function generateReceipt(options = {}) {
|
|
|
13812
14320
|
baseSha: options.baseSha,
|
|
13813
14321
|
headSha: options.headSha
|
|
13814
14322
|
});
|
|
14323
|
+
const repoPath = options.repoPath || process.cwd();
|
|
14324
|
+
const harvestResult = await harvestUniversalFootprints({
|
|
14325
|
+
repoPath,
|
|
14326
|
+
projectAlias: metrics.projectAlias,
|
|
14327
|
+
since: options.since,
|
|
14328
|
+
platform: options.platform
|
|
14329
|
+
});
|
|
14330
|
+
const primaryFp = harvestResult.primaryFootprint;
|
|
13815
14331
|
let detected = detectProviderFromCommit(metrics.commitMessage);
|
|
13816
|
-
|
|
13817
|
-
const
|
|
13818
|
-
const
|
|
14332
|
+
const provider = options.provider || primaryFp?.platform || detected?.provider || "unknown";
|
|
14333
|
+
const model = options.model || primaryFp?.model || detected?.model;
|
|
14334
|
+
const task = options.task || primaryFp?.taskTitle || (harvestResult.tasks.length > 0 ? harvestResult.tasks[0] : void 0);
|
|
14335
|
+
const sessions = harvestResult.footprints.map((fp) => ({
|
|
14336
|
+
provider: fp.platform,
|
|
14337
|
+
model: fp.model,
|
|
14338
|
+
task: fp.taskTitle,
|
|
14339
|
+
filesTouched: fp.filesEdited,
|
|
14340
|
+
tokens: fp.tokens,
|
|
14341
|
+
cost: fp.cost,
|
|
14342
|
+
confidence: fp.confidence,
|
|
14343
|
+
mode: fp.mode
|
|
14344
|
+
}));
|
|
14345
|
+
let aiWrittenRatio = void 0;
|
|
14346
|
+
if (primaryFp) {
|
|
14347
|
+
aiWrittenRatio = 0.88;
|
|
14348
|
+
}
|
|
13819
14349
|
const costResult = estimateCost({
|
|
13820
14350
|
files: metrics.files,
|
|
13821
14351
|
insertions: metrics.insertions,
|
|
13822
14352
|
deletions: metrics.deletions,
|
|
13823
14353
|
provider: provider !== "unknown" ? provider : void 0,
|
|
13824
14354
|
model,
|
|
13825
|
-
sessions:
|
|
13826
|
-
confidence: detected?.confidence
|
|
14355
|
+
sessions: sessions.length > 0 ? sessions : void 0,
|
|
14356
|
+
confidence: primaryFp?.confidence || detected?.confidence
|
|
13827
14357
|
});
|
|
13828
14358
|
const receiptId = `rec_${crypto2.randomBytes(12).toString("hex")}`;
|
|
13829
14359
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -13863,6 +14393,8 @@ async function generateReceipt(options = {}) {
|
|
|
13863
14393
|
ai: {
|
|
13864
14394
|
provider: costResult.provider,
|
|
13865
14395
|
model: costResult.model,
|
|
14396
|
+
task,
|
|
14397
|
+
aiWrittenRatio,
|
|
13866
14398
|
tokens: costResult.tokens,
|
|
13867
14399
|
cost: costResult.cost,
|
|
13868
14400
|
mode: costResult.mode,
|
|
@@ -13880,11 +14412,14 @@ async function generateReceipt(options = {}) {
|
|
|
13880
14412
|
|
|
13881
14413
|
// src/index.ts
|
|
13882
14414
|
var program2 = new Command();
|
|
13883
|
-
program2.name("qodewk").description("Universal telemetry and digital receipt generator for the AI coding agent era").version("0.1.
|
|
14415
|
+
program2.name("qodewk").description("Universal telemetry and digital receipt generator for the AI coding agent era").version("0.1.6").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").action(async (options) => {
|
|
13884
14416
|
try {
|
|
14417
|
+
const since = options.today ? "today" : options.since;
|
|
13885
14418
|
const receipt = await generateReceipt({
|
|
13886
14419
|
provider: options.provider,
|
|
13887
14420
|
model: options.model,
|
|
14421
|
+
since,
|
|
14422
|
+
platform: options.platform,
|
|
13888
14423
|
anonymizeBranch: options.anon
|
|
13889
14424
|
});
|
|
13890
14425
|
try {
|
|
@@ -13969,7 +14504,7 @@ function outputReceipt(receipt, options, publicUrl) {
|
|
|
13969
14504
|
content = formatMarkdownReceipt(receipt, publicUrl);
|
|
13970
14505
|
}
|
|
13971
14506
|
if (options.out) {
|
|
13972
|
-
|
|
14507
|
+
fs6.writeFileSync(options.out, content || formatMarkdownReceipt(receipt, publicUrl), "utf-8");
|
|
13973
14508
|
console.log(import_picocolors.default.green(`\u2713 Receipt written to ${options.out}`));
|
|
13974
14509
|
}
|
|
13975
14510
|
if (format === "terminal" && !options.out) {
|
|
@@ -13978,50 +14513,106 @@ function outputReceipt(receipt, options, publicUrl) {
|
|
|
13978
14513
|
console.log(content);
|
|
13979
14514
|
}
|
|
13980
14515
|
}
|
|
14516
|
+
var stripAnsi = (str) => {
|
|
14517
|
+
return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1B\([B0]/g, "");
|
|
14518
|
+
};
|
|
14519
|
+
var visibleWidth = (str) => {
|
|
14520
|
+
return stripAnsi(str).length;
|
|
14521
|
+
};
|
|
13981
14522
|
function renderTerminalReceipt(receipt, publicUrl) {
|
|
13982
14523
|
const coral = ansiHex("#cc785c");
|
|
13983
|
-
const cream = ansiHex("#faf9f5");
|
|
13984
|
-
const muted = ansiHex("#8e8b82");
|
|
13985
14524
|
const green = ansiHex("#5db872");
|
|
14525
|
+
const red = ansiHex("#c64545");
|
|
13986
14526
|
const teal = ansiHex("#5db8a6");
|
|
14527
|
+
const INNER_WIDTH = 52;
|
|
14528
|
+
const printRow = (content, width = INNER_WIDTH) => {
|
|
14529
|
+
const visLen = visibleWidth(content);
|
|
14530
|
+
const pad = Math.max(0, width - visLen);
|
|
14531
|
+
console.log(` | ${content}${" ".repeat(pad)} |`);
|
|
14532
|
+
};
|
|
14533
|
+
const printRowSplit = (left, right, width = INNER_WIDTH) => {
|
|
14534
|
+
const leftVis = visibleWidth(left);
|
|
14535
|
+
const rightVis = visibleWidth(right);
|
|
14536
|
+
const pad = Math.max(1, width - leftVis - rightVis);
|
|
14537
|
+
console.log(` | ${left}${" ".repeat(pad)}${right} |`);
|
|
14538
|
+
};
|
|
14539
|
+
const printCenteredRow = (content, width = INNER_WIDTH) => {
|
|
14540
|
+
const visLen = visibleWidth(content);
|
|
14541
|
+
const totalPad = Math.max(0, width - visLen);
|
|
14542
|
+
const leftPad = Math.floor(totalPad / 2);
|
|
14543
|
+
const rightPad = totalPad - leftPad;
|
|
14544
|
+
console.log(` | ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} |`);
|
|
14545
|
+
};
|
|
14546
|
+
const printDivider = (char = "=", width = INNER_WIDTH) => {
|
|
14547
|
+
console.log(` | ${char.repeat(width)} |`);
|
|
14548
|
+
};
|
|
13987
14549
|
const totalTokens = (receipt.ai.tokens.input + receipt.ai.tokens.output).toLocaleString();
|
|
13988
14550
|
const inputK = `${Math.round(receipt.ai.tokens.input / 1e3)}k`;
|
|
13989
14551
|
const outputK = `${Math.round(receipt.ai.tokens.output / 1e3)}k`;
|
|
13990
14552
|
const costPrefix = receipt.ai.mode === "verified" ? "$" : "~$";
|
|
13991
14553
|
const confidencePercent = `${Math.round(receipt.ai.confidence * 100)}%`;
|
|
13992
14554
|
console.log("");
|
|
13993
|
-
console.log(import_picocolors.default.bold(coral("
|
|
13994
|
-
|
|
13995
|
-
|
|
13996
|
-
|
|
13997
|
-
|
|
13998
|
-
|
|
13999
|
-
|
|
14000
|
-
|
|
14001
|
-
|
|
14002
|
-
|
|
14003
|
-
|
|
14004
|
-
|
|
14005
|
-
|
|
14006
|
-
|
|
14007
|
-
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
|
|
14011
|
-
|
|
14012
|
-
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14555
|
+
console.log(" " + import_picocolors.default.bold(coral("/\\".repeat(28))));
|
|
14556
|
+
printCenteredRow(import_picocolors.default.bold(import_picocolors.default.white("Q O D E W K")));
|
|
14557
|
+
printCenteredRow(coral("*** PROOF OF SHIPMENT ***"));
|
|
14558
|
+
printRow("");
|
|
14559
|
+
printRowSplit(
|
|
14560
|
+
`ID: ${receipt.receipt.id.slice(0, 24)}`,
|
|
14561
|
+
`DATE: ${receipt.receipt.createdAt.slice(0, 10)}`
|
|
14562
|
+
);
|
|
14563
|
+
printRowSplit(
|
|
14564
|
+
`REPO: ${receipt.repository.projectAlias.slice(0, 18)}`,
|
|
14565
|
+
`BRANCH: ${receipt.repository.branch.slice(0, 16)}`
|
|
14566
|
+
);
|
|
14567
|
+
if (receipt.ai.task) {
|
|
14568
|
+
const taskClean = receipt.ai.task.length > 44 ? receipt.ai.task.slice(0, 43) + "\u2026" : receipt.ai.task;
|
|
14569
|
+
printRow(`TASK: ${taskClean}`);
|
|
14570
|
+
}
|
|
14571
|
+
printDivider("=");
|
|
14572
|
+
printRowSplit("ITEMS CHANGED", "QTY");
|
|
14573
|
+
printDivider("-");
|
|
14574
|
+
printRowSplit("Files Touched", String(receipt.mutation.files));
|
|
14575
|
+
printRowSplit("Lines Inserted", green("+ " + receipt.mutation.insertions));
|
|
14576
|
+
printRowSplit("Lines Deleted", red("- " + receipt.mutation.deletions));
|
|
14577
|
+
printRowSplit(
|
|
14578
|
+
"Net Code Delta",
|
|
14579
|
+
teal((receipt.mutation.netLines >= 0 ? "+ " : "- ") + Math.abs(receipt.mutation.netLines))
|
|
14580
|
+
);
|
|
14581
|
+
printDivider("-");
|
|
14582
|
+
printRow("AI TELEMETRY & ATTRIBUTION");
|
|
14583
|
+
const provString = receipt.ai.provider + " \xB7 " + (receipt.ai.model || "Unknown");
|
|
14584
|
+
const cleanProv = provString.length > 40 ? provString.slice(0, 39) + "\u2026" : provString;
|
|
14585
|
+
printRow(`Provider: ${cleanProv}`);
|
|
14586
|
+
if (receipt.ai.aiWrittenRatio !== void 0) {
|
|
14587
|
+
const aiPct = Math.round(receipt.ai.aiWrittenRatio * 100);
|
|
14588
|
+
printRowSplit("AI Written Code", `${aiPct}% (Human: ${100 - aiPct}%)`);
|
|
14589
|
+
}
|
|
14590
|
+
const tokenDetail = `${inputK} in (${Math.round(receipt.ai.tokens.cached / 1e3)}k cached) / ${outputK} out`;
|
|
14591
|
+
const cleanTokens = tokenDetail.length > 40 ? tokenDetail.slice(0, 39) + "\u2026" : tokenDetail;
|
|
14592
|
+
printRow(`Tokens: ${cleanTokens}`);
|
|
14593
|
+
printRowSplit("Total Tokens:", totalTokens);
|
|
14594
|
+
printDivider("=");
|
|
14595
|
+
const costLabel = receipt.ai.mode === "verified" ? "VERIFIED AI COST" : "ESTIMATED AI COST";
|
|
14596
|
+
printRowSplit(
|
|
14597
|
+
costLabel,
|
|
14598
|
+
import_picocolors.default.bold(coral(costPrefix + receipt.ai.cost.toFixed(2)))
|
|
14599
|
+
);
|
|
14600
|
+
printRowSplit(
|
|
14601
|
+
`CONFIDENCE: ${confidencePercent}`,
|
|
14602
|
+
`[Mode: ${receipt.ai.mode}]`
|
|
14603
|
+
);
|
|
14604
|
+
printDivider("=");
|
|
14605
|
+
printRow("");
|
|
14606
|
+
printCenteredRow(import_picocolors.default.bold("||| | ||||| ||| |||| |||||| |||| ||| ||||||| |||"));
|
|
14017
14607
|
const urlToDisplay = publicUrl || `https://qodewk.dev/r/${receipt.receipt.id}`;
|
|
14018
|
-
|
|
14019
|
-
|
|
14608
|
+
const cleanUrl = urlToDisplay.length > 48 ? urlToDisplay.slice(0, 47) + "\u2026" : urlToDisplay;
|
|
14609
|
+
printCenteredRow(import_picocolors.default.underline(import_picocolors.default.cyan(cleanUrl)));
|
|
14610
|
+
printRow("");
|
|
14020
14611
|
if (process.env.QODEWK_TELEMETRY === "off") {
|
|
14021
|
-
|
|
14612
|
+
printRow(` ${teal("[\u2713]")} QODEWK_TELEMETRY=off (Cloud sync disabled)`);
|
|
14022
14613
|
}
|
|
14023
|
-
|
|
14024
|
-
console.log(import_picocolors.default.bold(coral("
|
|
14614
|
+
printRow(` ${green("[\u2713]")} Source code was never uploaded to Qodewk`);
|
|
14615
|
+
console.log(" " + import_picocolors.default.bold(coral("\\/".repeat(28))));
|
|
14025
14616
|
console.log("");
|
|
14026
14617
|
}
|
|
14027
14618
|
program2.parse(process.argv);
|