qodewk 0.10.0 → 0.11.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.
Files changed (2) hide show
  1. package/dist/index.cjs +721 -306
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1157,7 +1157,7 @@ var require_command = __commonJS({
1157
1157
  "use strict";
1158
1158
  var EventEmitter2 = require("events").EventEmitter;
1159
1159
  var childProcess = require("child_process");
1160
- var path17 = require("path");
1160
+ var path18 = require("path");
1161
1161
  var fs16 = require("fs");
1162
1162
  var process3 = require("process");
1163
1163
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -2157,9 +2157,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2157
2157
  let launchWithNode = false;
2158
2158
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2159
2159
  function findFile(baseDir, baseName) {
2160
- const localBin = path17.resolve(baseDir, baseName);
2160
+ const localBin = path18.resolve(baseDir, baseName);
2161
2161
  if (fs16.existsSync(localBin)) return localBin;
2162
- if (sourceExt.includes(path17.extname(baseName))) return void 0;
2162
+ if (sourceExt.includes(path18.extname(baseName))) return void 0;
2163
2163
  const foundExt = sourceExt.find(
2164
2164
  (ext) => fs16.existsSync(`${localBin}${ext}`)
2165
2165
  );
@@ -2177,17 +2177,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
2177
2177
  } catch {
2178
2178
  resolvedScriptPath = this._scriptPath;
2179
2179
  }
2180
- executableDir = path17.resolve(
2181
- path17.dirname(resolvedScriptPath),
2180
+ executableDir = path18.resolve(
2181
+ path18.dirname(resolvedScriptPath),
2182
2182
  executableDir
2183
2183
  );
2184
2184
  }
2185
2185
  if (executableDir) {
2186
2186
  let localFile = findFile(executableDir, executableFile);
2187
2187
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2188
- const legacyName = path17.basename(
2188
+ const legacyName = path18.basename(
2189
2189
  this._scriptPath,
2190
- path17.extname(this._scriptPath)
2190
+ path18.extname(this._scriptPath)
2191
2191
  );
2192
2192
  if (legacyName !== this._name) {
2193
2193
  localFile = findFile(
@@ -2198,7 +2198,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2198
2198
  }
2199
2199
  executableFile = localFile || executableFile;
2200
2200
  }
2201
- launchWithNode = sourceExt.includes(path17.extname(executableFile));
2201
+ launchWithNode = sourceExt.includes(path18.extname(executableFile));
2202
2202
  let proc;
2203
2203
  if (process3.platform !== "win32") {
2204
2204
  if (launchWithNode) {
@@ -3045,7 +3045,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3045
3045
  * @return {Command}
3046
3046
  */
3047
3047
  nameFromFilename(filename) {
3048
- this._name = path17.basename(filename, path17.extname(filename));
3048
+ this._name = path18.basename(filename, path18.extname(filename));
3049
3049
  return this;
3050
3050
  }
3051
3051
  /**
@@ -3059,9 +3059,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3059
3059
  * @param {string} [path]
3060
3060
  * @return {(string|null|Command)}
3061
3061
  */
3062
- executableDir(path18) {
3063
- if (path18 === void 0) return this._executableDir;
3064
- this._executableDir = path18;
3062
+ executableDir(path19) {
3063
+ if (path19 === void 0) return this._executableDir;
3064
+ this._executableDir = path19;
3065
3065
  return this;
3066
3066
  }
3067
3067
  /**
@@ -4207,10 +4207,10 @@ var require_src2 = __commonJS({
4207
4207
  var fs_1 = require("fs");
4208
4208
  var debug_1 = __importDefault(require_src());
4209
4209
  var log = debug_1.default("@kwsites/file-exists");
4210
- function check(path17, isFile, isDirectory) {
4211
- log(`checking %s`, path17);
4210
+ function check(path18, isFile, isDirectory) {
4211
+ log(`checking %s`, path18);
4212
4212
  try {
4213
- const stat = fs_1.statSync(path17);
4213
+ const stat = fs_1.statSync(path18);
4214
4214
  if (stat.isFile() && isFile) {
4215
4215
  log(`[OK] path represents a file`);
4216
4216
  return true;
@@ -4230,8 +4230,8 @@ var require_src2 = __commonJS({
4230
4230
  throw e;
4231
4231
  }
4232
4232
  }
4233
- function exists2(path17, type = exports2.READABLE) {
4234
- return check(path17, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
4233
+ function exists2(path18, type = exports2.READABLE) {
4234
+ return check(path18, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
4235
4235
  }
4236
4236
  exports2.exists = exists2;
4237
4237
  exports2.FILE = 1;
@@ -4842,8 +4842,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
4842
4842
  function forEachLineWithContent(input, callback) {
4843
4843
  return toLinesWithContent(input, true).map((line) => callback(line));
4844
4844
  }
4845
- function folderExists(path17) {
4846
- return (0, import_file_exists.exists)(path17, import_file_exists.FOLDER);
4845
+ function folderExists(path18) {
4846
+ return (0, import_file_exists.exists)(path18, import_file_exists.FOLDER);
4847
4847
  }
4848
4848
  function append(target, item) {
4849
4849
  if (Array.isArray(target)) {
@@ -5034,8 +5034,8 @@ function checkIsRepoRootTask() {
5034
5034
  commands,
5035
5035
  format: "utf-8",
5036
5036
  onError,
5037
- parser(path17) {
5038
- return /^\.(git)?$/.test(path17.trim());
5037
+ parser(path18) {
5038
+ return /^\.(git)?$/.test(path18.trim());
5039
5039
  }
5040
5040
  };
5041
5041
  }
@@ -5291,11 +5291,11 @@ function parseGrep(grep) {
5291
5291
  const paths = /* @__PURE__ */ new Set();
5292
5292
  const results = {};
5293
5293
  forEachLineWithContent(grep, (input) => {
5294
- const [path17, line, preview] = input.split(NULL);
5295
- paths.add(path17);
5296
- (results[path17] = results[path17] || []).push({
5294
+ const [path18, line, preview] = input.split(NULL);
5295
+ paths.add(path18);
5296
+ (results[path18] = results[path18] || []).push({
5297
5297
  line: asNumber(line),
5298
- path: path17,
5298
+ path: path18,
5299
5299
  preview
5300
5300
  });
5301
5301
  });
@@ -5592,14 +5592,14 @@ function hashObjectTask(filePath, write) {
5592
5592
  }
5593
5593
  return straightThroughStringTask(commands, true);
5594
5594
  }
5595
- function parseInit(bare, path17, text) {
5595
+ function parseInit(bare, path18, text) {
5596
5596
  const response = String(text).trim();
5597
5597
  let result;
5598
5598
  if (result = initResponseRegex.exec(response)) {
5599
- return new InitSummary(bare, path17, false, result[1]);
5599
+ return new InitSummary(bare, path18, false, result[1]);
5600
5600
  }
5601
5601
  if (result = reInitResponseRegex.exec(response)) {
5602
- return new InitSummary(bare, path17, true, result[1]);
5602
+ return new InitSummary(bare, path18, true, result[1]);
5603
5603
  }
5604
5604
  let gitDir = "";
5605
5605
  const tokens = response.split(" ");
@@ -5610,12 +5610,12 @@ function parseInit(bare, path17, text) {
5610
5610
  break;
5611
5611
  }
5612
5612
  }
5613
- return new InitSummary(bare, path17, /^re/i.test(response), gitDir);
5613
+ return new InitSummary(bare, path18, /^re/i.test(response), gitDir);
5614
5614
  }
5615
5615
  function hasBareCommand(command) {
5616
5616
  return command.includes(bareCommand);
5617
5617
  }
5618
- function initTask(bare = false, path17, customArgs) {
5618
+ function initTask(bare = false, path18, customArgs) {
5619
5619
  const commands = ["init", ...customArgs];
5620
5620
  if (bare && !hasBareCommand(commands)) {
5621
5621
  commands.splice(1, 0, bareCommand);
@@ -5624,7 +5624,7 @@ function initTask(bare = false, path17, customArgs) {
5624
5624
  commands,
5625
5625
  format: "utf-8",
5626
5626
  parser(text) {
5627
- return parseInit(commands.includes("--bare"), path17, text);
5627
+ return parseInit(commands.includes("--bare"), path18, text);
5628
5628
  }
5629
5629
  };
5630
5630
  }
@@ -5903,14 +5903,14 @@ function splitLine(result, lineStr) {
5903
5903
  default:
5904
5904
  return;
5905
5905
  }
5906
- function data(index, workingDir, path17) {
5906
+ function data(index, workingDir, path18) {
5907
5907
  const raw = `${index}${workingDir}`;
5908
5908
  const handler = parsers6.get(raw);
5909
5909
  if (handler) {
5910
- handler(result, path17);
5910
+ handler(result, path18);
5911
5911
  }
5912
5912
  if (raw !== "##" && raw !== "!!") {
5913
- result.files.push(new FileStatusSummary(path17, index, workingDir));
5913
+ result.files.push(new FileStatusSummary(path18, index, workingDir));
5914
5914
  }
5915
5915
  }
5916
5916
  }
@@ -6097,8 +6097,8 @@ function deleteBranchTask(branch, forceDelete = false) {
6097
6097
  return task;
6098
6098
  }
6099
6099
  function toPath(input) {
6100
- const path17 = input.trim().replace(/^["']|["']$/g, "");
6101
- return path17 && (0, import_node_path.normalize)(path17);
6100
+ const path18 = input.trim().replace(/^["']|["']$/g, "");
6101
+ return path18 && (0, import_node_path.normalize)(path18);
6102
6102
  }
6103
6103
  function checkIgnoreTask(paths) {
6104
6104
  return {
@@ -6237,8 +6237,8 @@ function stashListTask(opt = {}, customArgs) {
6237
6237
  parser: parser4
6238
6238
  };
6239
6239
  }
6240
- function addSubModuleTask(repo, path17) {
6241
- return subModuleTask(["add", repo, path17]);
6240
+ function addSubModuleTask(repo, path18) {
6241
+ return subModuleTask(["add", repo, path18]);
6242
6242
  }
6243
6243
  function initSubModuleTask(customArgs) {
6244
6244
  return subModuleTask(["init", ...customArgs]);
@@ -6646,12 +6646,12 @@ function gitP(...args) {
6646
6646
  );
6647
6647
  }
6648
6648
  return chain.then(function() {
6649
- return new Promise(function(resolve6, reject) {
6649
+ return new Promise(function(resolve7, reject) {
6650
6650
  const callback = (err, result) => {
6651
6651
  if (err) {
6652
6652
  return reject(toError(err));
6653
6653
  }
6654
- resolve6(result);
6654
+ resolve7(result);
6655
6655
  };
6656
6656
  args2.push(callback);
6657
6657
  git2[fn].apply(git2, args2);
@@ -7570,9 +7570,9 @@ var init_esm = __esm({
7570
7570
  "src/lib/responses/InitSummary.ts"() {
7571
7571
  "use strict";
7572
7572
  InitSummary = class {
7573
- constructor(bare, path17, existing, gitDir) {
7573
+ constructor(bare, path18, existing, gitDir) {
7574
7574
  this.bare = bare;
7575
- this.path = path17;
7575
+ this.path = path18;
7576
7576
  this.existing = existing;
7577
7577
  this.gitDir = gitDir;
7578
7578
  }
@@ -8105,12 +8105,12 @@ var init_esm = __esm({
8105
8105
  "use strict";
8106
8106
  fromPathRegex = /^(.+)\0(.+)$/;
8107
8107
  FileStatusSummary = class {
8108
- constructor(path17, index, working_dir) {
8109
- this.path = path17;
8108
+ constructor(path18, index, working_dir) {
8109
+ this.path = path18;
8110
8110
  this.index = index;
8111
8111
  this.working_dir = working_dir;
8112
8112
  if (index === "R" || working_dir === "R") {
8113
- const detail = fromPathRegex.exec(path17) || [null, path17, path17];
8113
+ const detail = fromPathRegex.exec(path18) || [null, path18, path18];
8114
8114
  this.from = detail[2] || "";
8115
8115
  this.path = detail[1] || "";
8116
8116
  }
@@ -8372,9 +8372,9 @@ var init_esm = __esm({
8372
8372
  next
8373
8373
  );
8374
8374
  }
8375
- hashObject(path17, write) {
8375
+ hashObject(path18, write) {
8376
8376
  return this._runTask(
8377
- hashObjectTask(path17, write === true),
8377
+ hashObjectTask(path18, write === true),
8378
8378
  trailingFunctionArgument(arguments)
8379
8379
  );
8380
8380
  }
@@ -9011,8 +9011,8 @@ var init_esm = __esm({
9011
9011
  }
9012
9012
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
9013
9013
  };
9014
- Git2.prototype.submoduleAdd = function(repo, path17, then) {
9015
- return this._runTask(addSubModuleTask2(repo, path17), trailingFunctionArgument2(arguments));
9014
+ Git2.prototype.submoduleAdd = function(repo, path18, then) {
9015
+ return this._runTask(addSubModuleTask2(repo, path18), trailingFunctionArgument2(arguments));
9016
9016
  };
9017
9017
  Git2.prototype.submoduleUpdate = function(args, then) {
9018
9018
  return this._runTask(
@@ -9319,7 +9319,7 @@ var init_esm = __esm({
9319
9319
 
9320
9320
  // src/index.ts
9321
9321
  var fs15 = __toESM(require("fs"), 1);
9322
- var path16 = __toESM(require("path"), 1);
9322
+ var path17 = __toESM(require("path"), 1);
9323
9323
 
9324
9324
  // ../../node_modules/.pnpm/commander@13.1.0/node_modules/commander/esm.mjs
9325
9325
  var import_index = __toESM(require_commander(), 1);
@@ -9339,7 +9339,7 @@ var {
9339
9339
  } = import_index.default;
9340
9340
 
9341
9341
  // src/index.ts
9342
- var import_picocolors4 = __toESM(require_picocolors(), 1);
9342
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
9343
9343
 
9344
9344
  // ../core/dist/index.js
9345
9345
  var crypto2 = __toESM(require("crypto"), 1);
@@ -9822,8 +9822,8 @@ function getErrorMap() {
9822
9822
 
9823
9823
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
9824
9824
  var makeIssue = (params) => {
9825
- const { data, path: path17, errorMaps, issueData } = params;
9826
- const fullPath = [...path17, ...issueData.path || []];
9825
+ const { data, path: path18, errorMaps, issueData } = params;
9826
+ const fullPath = [...path18, ...issueData.path || []];
9827
9827
  const fullIssue = {
9828
9828
  ...issueData,
9829
9829
  path: fullPath
@@ -9939,11 +9939,11 @@ var errorUtil;
9939
9939
 
9940
9940
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
9941
9941
  var ParseInputLazyPath = class {
9942
- constructor(parent, value, path17, key) {
9942
+ constructor(parent, value, path18, key) {
9943
9943
  this._cachedPath = [];
9944
9944
  this.parent = parent;
9945
9945
  this.data = value;
9946
- this._path = path17;
9946
+ this._path = path18;
9947
9947
  this._key = key;
9948
9948
  }
9949
9949
  get path() {
@@ -13394,11 +13394,13 @@ var AttributionModeSchema = external_exports.enum([
13394
13394
  "unknown"
13395
13395
  ]);
13396
13396
  var ProviderSessionSchema = external_exports.object({
13397
+ sessionId: external_exports.string().optional(),
13397
13398
  provider: external_exports.string(),
13398
13399
  // e.g. "anthropic", "openai", "cursor", "copilot", "gemini", "antigravity"
13399
13400
  model: external_exports.string().optional(),
13400
13401
  task: external_exports.string().optional(),
13401
13402
  filesTouched: external_exports.array(external_exports.string()).optional(),
13403
+ turnsCount: external_exports.number().int().nonnegative().optional(),
13402
13404
  tokens: external_exports.object({
13403
13405
  input: external_exports.number().int().nonnegative().default(0),
13404
13406
  output: external_exports.number().int().nonnegative().default(0),
@@ -13406,7 +13408,8 @@ var ProviderSessionSchema = external_exports.object({
13406
13408
  }),
13407
13409
  cost: external_exports.number().nonnegative(),
13408
13410
  confidence: external_exports.number().min(0).max(1),
13409
- mode: AttributionModeSchema
13411
+ mode: AttributionModeSchema,
13412
+ createdAt: external_exports.string().optional()
13410
13413
  });
13411
13414
  var ReceiptV1Schema = external_exports.object({
13412
13415
  version: external_exports.literal("1.0"),
@@ -13957,6 +13960,16 @@ var RATE_CARDS = {
13957
13960
  cacheWritePerMTok: 0.1,
13958
13961
  contextWindow: 1e6
13959
13962
  },
13963
+ "gemini-3-6-flash": {
13964
+ id: "gemini-3-6-flash",
13965
+ provider: "google",
13966
+ name: "Gemini 3.6 Flash",
13967
+ inputPerMTok: 0.1,
13968
+ outputPerMTok: 0.4,
13969
+ cacheReadPerMTok: 0.025,
13970
+ cacheWritePerMTok: 0.1,
13971
+ contextWindow: 1e6
13972
+ },
13960
13973
  "gemini-2-5-pro": {
13961
13974
  id: "gemini-2-5-pro",
13962
13975
  provider: "google",
@@ -14065,9 +14078,14 @@ var MODEL_ALIASES = {
14065
14078
  "gemini-3-1-pro": "gemini-2-5-pro",
14066
14079
  "gemini-3-pro": "gemini-2-5-pro",
14067
14080
  "gemini-3-1-flash": "gemini-3-8-flash",
14081
+ "gemini-3.8-flash": "gemini-3-8-flash",
14082
+ "gemini-3.6-flash": "gemini-3-6-flash",
14083
+ "gemini-3-6": "gemini-3-6-flash",
14068
14084
  "gemini-2.0-flash": "gemini-2-0-flash",
14069
14085
  "gemini-1.5-pro": "gemini-1-5-pro",
14070
14086
  "gemini-1.5-flash": "gemini-2-0-flash",
14087
+ "google/gemini-3.8-flash": "gemini-3-8-flash",
14088
+ "google/gemini-3.6-flash": "gemini-3-6-flash",
14071
14089
  // DeepSeek aliases
14072
14090
  "deepseek-chat": "deepseek-v3",
14073
14091
  "deepseek-coder": "deepseek-v3",
@@ -14352,6 +14370,31 @@ function harvestTrailerFootprints(repoPath, commitMessage, headSha, commitDate)
14352
14370
  }
14353
14371
  return footprints;
14354
14372
  }
14373
+ function discoverAntigravityEnvironment() {
14374
+ const isAgent = process.env.ANTIGRAVITY_AGENT === "1" || Boolean(process.env.ANTIGRAVITY_CONVERSATION_ID);
14375
+ const homedir12 = os2.homedir();
14376
+ const antigravityDir = process.env.ANTIGRAVITY_APP_DATA_DIR || path2.join(homedir12, ".gemini", "antigravity");
14377
+ if (isAgent) {
14378
+ return {
14379
+ provider: "antigravity",
14380
+ model: "claude-sonnet-4-6-thinking",
14381
+ confidence: 0.85,
14382
+ mode: "observed"
14383
+ };
14384
+ }
14385
+ if (fs.existsSync(antigravityDir)) {
14386
+ return {
14387
+ provider: "antigravity",
14388
+ model: "claude-sonnet-4-6-thinking",
14389
+ confidence: 0.65,
14390
+ mode: "estimated"
14391
+ };
14392
+ }
14393
+ return null;
14394
+ }
14395
+
14396
+ // ../core/dist/harvester/index.js
14397
+ var path11 = __toESM(require("path"), 1);
14355
14398
 
14356
14399
  // ../core/dist/harvester/antigravity.js
14357
14400
  var fs2 = __toESM(require("fs"), 1);
@@ -14361,7 +14404,8 @@ var import_node_module = require("module");
14361
14404
 
14362
14405
  // ../core/dist/harvester/scoring.js
14363
14406
  function normalizeFilePath(filePath, repoPath) {
14364
- let p2 = filePath.replace(/\\/g, "/").trim();
14407
+ let p2 = filePath.trim().replace(/^["']|["']$/g, "").replace(/\\/g, "/");
14408
+ p2 = p2.replace(/\/+/g, "/");
14365
14409
  p2 = p2.replace(/^file:\/\/\/?/, "");
14366
14410
  if (repoPath) {
14367
14411
  const normRepo = repoPath.replace(/\\/g, "/").replace(/\/$/, "");
@@ -14396,7 +14440,8 @@ function scoreFootprint(fp, gitCtx) {
14396
14440
  if (found)
14397
14441
  matches++;
14398
14442
  }
14399
- const ratio = matches / normChanged.length;
14443
+ const maxPossibleMatches = Math.min(normChanged.length, normEdited.length);
14444
+ const ratio = maxPossibleMatches > 0 ? matches / maxPossibleMatches : 0;
14400
14445
  if (matches > 0) {
14401
14446
  score += ratio * 0.4;
14402
14447
  } else {
@@ -15776,38 +15821,86 @@ function parseSinceOption2(since) {
15776
15821
  }
15777
15822
  return void 0;
15778
15823
  }
15779
- async function harvestUniversalFootprints(options) {
15780
- const sinceDate = parseSinceOption2(options.since);
15781
- const alias = options.projectAlias || "";
15782
- let allFootprints = [];
15783
- if (!options.platform || options.platform === "all" || options.platform === "antigravity") {
15784
- const agFootprints = harvestAntigravityFootprints(options.repoPath, sinceDate);
15824
+ function harvestRawPlatformFootprints(repoPath, alias, sinceDate, platform) {
15825
+ const allFootprints = [];
15826
+ if (!platform || platform === "all" || platform === "antigravity") {
15827
+ const agFootprints = harvestAntigravityFootprints(repoPath, sinceDate);
15785
15828
  allFootprints.push(...agFootprints);
15786
15829
  }
15787
- if (!options.platform || options.platform === "all" || options.platform === "claude") {
15788
- const claudeFootprints = harvestClaudeFootprints(options.repoPath, alias, sinceDate);
15830
+ if (!platform || platform === "all" || platform === "claude") {
15831
+ const claudeFootprints = harvestClaudeFootprints(repoPath, alias, sinceDate);
15789
15832
  allFootprints.push(...claudeFootprints);
15790
15833
  }
15791
- if (!options.platform || options.platform === "all" || options.platform === "cursor") {
15792
- const cursorFootprints = harvestCursorFootprints(options.repoPath, sinceDate);
15834
+ if (!platform || platform === "all" || platform === "cursor") {
15835
+ const cursorFootprints = harvestCursorFootprints(repoPath, sinceDate);
15793
15836
  allFootprints.push(...cursorFootprints);
15794
15837
  }
15795
- if (!options.platform || options.platform === "all" || options.platform === "aider") {
15796
- const aiderFootprints = harvestAiderFootprints(options.repoPath, sinceDate);
15838
+ if (!platform || platform === "all" || platform === "aider") {
15839
+ const aiderFootprints = harvestAiderFootprints(repoPath, sinceDate);
15797
15840
  allFootprints.push(...aiderFootprints);
15798
15841
  }
15799
- if (!options.platform || options.platform === "all" || options.platform === "windsurf") {
15800
- const windsurfFootprints = harvestWindsurfFootprints(options.repoPath, sinceDate);
15842
+ if (!platform || platform === "all" || platform === "windsurf") {
15843
+ const windsurfFootprints = harvestWindsurfFootprints(repoPath, sinceDate);
15801
15844
  allFootprints.push(...windsurfFootprints);
15802
15845
  }
15803
- if (!options.platform || options.platform === "all" || options.platform === "cline") {
15804
- const clineFootprints = harvestClineFootprints(options.repoPath, sinceDate);
15846
+ if (!platform || platform === "all" || platform === "cline") {
15847
+ const clineFootprints = harvestClineFootprints(repoPath, sinceDate);
15805
15848
  allFootprints.push(...clineFootprints);
15806
15849
  }
15807
- if (!options.platform || options.platform === "all" || options.platform === "opencode") {
15808
- const opencodeFootprints = harvestOpenCodeFootprints(options.repoPath, sinceDate);
15850
+ if (!platform || platform === "all" || platform === "opencode") {
15851
+ const opencodeFootprints = harvestOpenCodeFootprints(repoPath, sinceDate);
15809
15852
  allFootprints.push(...opencodeFootprints);
15810
15853
  }
15854
+ return allFootprints;
15855
+ }
15856
+ async function listProjectChats(options = {}) {
15857
+ const repoPath = options.repoPath || process.cwd();
15858
+ const alias = options.projectAlias || path11.basename(path11.resolve(repoPath)) || "project";
15859
+ let sinceDate;
15860
+ let windowDescription = "All-time";
15861
+ if (!options.all) {
15862
+ if (options.since) {
15863
+ sinceDate = parseSinceOption2(options.since);
15864
+ windowDescription = typeof options.since === "string" ? `Since ${options.since}` : `Since ${options.since.toISOString().slice(0, 10)}`;
15865
+ } else {
15866
+ sinceDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
15867
+ windowDescription = "Last 30 Days";
15868
+ }
15869
+ }
15870
+ const allFootprints = harvestRawPlatformFootprints(repoPath, alias, sinceDate, options.platform);
15871
+ allFootprints.sort((a, b2) => new Date(b2.timestamp).getTime() - new Date(a.timestamp).getTime());
15872
+ let totalInput = 0;
15873
+ let totalOutput = 0;
15874
+ let totalCached = 0;
15875
+ let totalCost = 0;
15876
+ let totalSteps = 0;
15877
+ for (const fp of allFootprints) {
15878
+ totalInput += fp.tokens.input;
15879
+ totalOutput += fp.tokens.output;
15880
+ totalCached += fp.tokens.cached;
15881
+ totalCost += fp.cost;
15882
+ totalSteps += fp.stepsCount || 0;
15883
+ }
15884
+ return {
15885
+ repoPath,
15886
+ projectAlias: alias,
15887
+ windowDescription,
15888
+ totalCost: Number(totalCost.toFixed(4)),
15889
+ totalTokens: {
15890
+ input: totalInput,
15891
+ output: totalOutput,
15892
+ cached: totalCached
15893
+ },
15894
+ totalSteps,
15895
+ sessionsCount: allFootprints.length,
15896
+ chats: allFootprints
15897
+ };
15898
+ }
15899
+ async function harvestUniversalFootprints(options) {
15900
+ const parsedSince = parseSinceOption2(options.since);
15901
+ const sinceDate = parsedSince ? new Date(parsedSince.getTime() - 24 * 60 * 60 * 1e3) : void 0;
15902
+ const alias = options.projectAlias || "";
15903
+ let allFootprints = harvestRawPlatformFootprints(options.repoPath, alias, sinceDate, options.platform);
15811
15904
  if (options.gitContext?.commitMessage) {
15812
15905
  const trailerFps = harvestTrailerFootprints(options.repoPath, options.gitContext.commitMessage, options.gitContext.headSha, options.gitContext.commitDate);
15813
15906
  allFootprints.push(...trailerFps);
@@ -15934,15 +16027,15 @@ function estimateCost(options) {
15934
16027
 
15935
16028
  // ../core/dist/pricing-sync.js
15936
16029
  var fs10 = __toESM(require("fs"), 1);
15937
- var path11 = __toESM(require("path"), 1);
16030
+ var path12 = __toESM(require("path"), 1);
15938
16031
  var os10 = __toESM(require("os"), 1);
15939
16032
  async function syncDynamicPricing(options) {
15940
16033
  try {
15941
- const qodewkDir = path11.join(os10.homedir(), ".qodewk");
16034
+ const qodewkDir = path12.join(os10.homedir(), ".qodewk");
15942
16035
  if (!fs10.existsSync(qodewkDir)) {
15943
16036
  fs10.mkdirSync(qodewkDir, { recursive: true });
15944
16037
  }
15945
- const cacheFile = path11.join(qodewkDir, "pricing_registry_cache.json");
16038
+ const cacheFile = path12.join(qodewkDir, "pricing_registry_cache.json");
15946
16039
  const TTL_MS = 24 * 60 * 60 * 1e3;
15947
16040
  const now = Date.now();
15948
16041
  if (!options?.force && fs10.existsSync(cacheFile)) {
@@ -15977,7 +16070,7 @@ async function syncDynamicPricing(options) {
15977
16070
 
15978
16071
  // ../core/dist/env.js
15979
16072
  var fs11 = __toESM(require("fs"), 1);
15980
- var path12 = __toESM(require("path"), 1);
16073
+ var path13 = __toESM(require("path"), 1);
15981
16074
  var os11 = __toESM(require("os"), 1);
15982
16075
  var isEnvLoaded = false;
15983
16076
  function loadQodewkEnv(startDir = process.cwd()) {
@@ -15985,11 +16078,11 @@ function loadQodewkEnv(startDir = process.cwd()) {
15985
16078
  return;
15986
16079
  isEnvLoaded = true;
15987
16080
  const candidates = [
15988
- path12.join(startDir, ".env.local"),
15989
- path12.join(startDir, ".env"),
15990
- path12.join(startDir, "apps", "web", ".env.local"),
15991
- path12.join(startDir, "apps", "web", ".env"),
15992
- path12.join(os11.homedir(), ".qodewk", "config.env")
16081
+ path13.join(startDir, ".env.local"),
16082
+ path13.join(startDir, ".env"),
16083
+ path13.join(startDir, "apps", "web", ".env.local"),
16084
+ path13.join(startDir, "apps", "web", ".env"),
16085
+ path13.join(os11.homedir(), ".qodewk", "config.env")
15993
16086
  ];
15994
16087
  for (const envPath of candidates) {
15995
16088
  if (!fs11.existsSync(envPath))
@@ -16065,7 +16158,7 @@ function formatMarkdownReceipt(receipt, publicUrl) {
16065
16158
 
16066
16159
  // ../core/dist/doctor.js
16067
16160
  var fs12 = __toESM(require("fs"), 1);
16068
- var path13 = __toESM(require("path"), 1);
16161
+ var path14 = __toESM(require("path"), 1);
16069
16162
  var os12 = __toESM(require("os"), 1);
16070
16163
  var import_node_child_process = require("child_process");
16071
16164
  var HOOK_MARKER_BEGIN = "# --- BEGIN QODEWK HOOK ---";
@@ -16073,7 +16166,7 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16073
16166
  const homedir12 = os12.homedir();
16074
16167
  const results = [];
16075
16168
  const agEnv = process.env.ANTIGRAVITY_APP_DATA_DIR;
16076
- const agHome = path13.join(homedir12, ".gemini", "antigravity");
16169
+ const agHome = path14.join(homedir12, ".gemini", "antigravity");
16077
16170
  const agPath = agEnv && fs12.existsSync(agEnv) ? agEnv : fs12.existsSync(agHome) ? agHome : void 0;
16078
16171
  results.push({
16079
16172
  id: "antigravity",
@@ -16082,7 +16175,7 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16082
16175
  path: agPath,
16083
16176
  details: agPath ? "Antigravity brain telemetry detected" : "No active session brain found"
16084
16177
  });
16085
- const claudeProjects = path13.join(homedir12, ".claude", "projects");
16178
+ const claudeProjects = path14.join(homedir12, ".claude", "projects");
16086
16179
  const claudeExists = fs12.existsSync(claudeProjects);
16087
16180
  results.push({
16088
16181
  id: "claude",
@@ -16093,15 +16186,15 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16093
16186
  });
16094
16187
  let cursorPath;
16095
16188
  if (process.platform === "win32") {
16096
- const c3 = path13.join(process.env.APPDATA || path13.join(homedir12, "AppData", "Roaming"), "Cursor", "User", "workspaceStorage");
16189
+ const c3 = path14.join(process.env.APPDATA || path14.join(homedir12, "AppData", "Roaming"), "Cursor", "User", "workspaceStorage");
16097
16190
  if (fs12.existsSync(c3))
16098
16191
  cursorPath = c3;
16099
16192
  } else if (process.platform === "darwin") {
16100
- const c3 = path13.join(homedir12, "Library", "Application Support", "Cursor", "User", "workspaceStorage");
16193
+ const c3 = path14.join(homedir12, "Library", "Application Support", "Cursor", "User", "workspaceStorage");
16101
16194
  if (fs12.existsSync(c3))
16102
16195
  cursorPath = c3;
16103
16196
  } else {
16104
- const c3 = path13.join(homedir12, ".config", "Cursor", "User", "workspaceStorage");
16197
+ const c3 = path14.join(homedir12, ".config", "Cursor", "User", "workspaceStorage");
16105
16198
  if (fs12.existsSync(c3))
16106
16199
  cursorPath = c3;
16107
16200
  }
@@ -16114,15 +16207,15 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16114
16207
  });
16115
16208
  let windsurfPath;
16116
16209
  if (process.platform === "win32") {
16117
- const w = path13.join(process.env.APPDATA || path13.join(homedir12, "AppData", "Roaming"), "Windsurf", "User", "workspaceStorage");
16210
+ const w = path14.join(process.env.APPDATA || path14.join(homedir12, "AppData", "Roaming"), "Windsurf", "User", "workspaceStorage");
16118
16211
  if (fs12.existsSync(w))
16119
16212
  windsurfPath = w;
16120
16213
  } else if (process.platform === "darwin") {
16121
- const w = path13.join(homedir12, "Library", "Application Support", "Windsurf", "User", "workspaceStorage");
16214
+ const w = path14.join(homedir12, "Library", "Application Support", "Windsurf", "User", "workspaceStorage");
16122
16215
  if (fs12.existsSync(w))
16123
16216
  windsurfPath = w;
16124
16217
  } else {
16125
- const w = path13.join(homedir12, ".config", "Windsurf", "User", "workspaceStorage");
16218
+ const w = path14.join(homedir12, ".config", "Windsurf", "User", "workspaceStorage");
16126
16219
  if (fs12.existsSync(w))
16127
16220
  windsurfPath = w;
16128
16221
  }
@@ -16134,16 +16227,16 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16134
16227
  details: windsurfPath ? "Cascade session workspace storage detected" : "Windsurf IDE storage not detected"
16135
16228
  });
16136
16229
  let clinePath;
16137
- const localCline = path13.join(repoPath, ".cline");
16138
- const localRoo = path13.join(repoPath, ".roo");
16230
+ const localCline = path14.join(repoPath, ".cline");
16231
+ const localRoo = path14.join(repoPath, ".roo");
16139
16232
  if (fs12.existsSync(localCline)) {
16140
16233
  clinePath = localCline;
16141
16234
  } else if (fs12.existsSync(localRoo)) {
16142
16235
  clinePath = localRoo;
16143
16236
  } else {
16144
- const appData = process.platform === "win32" ? process.env.APPDATA || path13.join(homedir12, "AppData", "Roaming") : process.platform === "darwin" ? path13.join(homedir12, "Library", "Application Support") : path13.join(homedir12, ".config");
16145
- const clineExt = path13.join(appData, "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "tasks");
16146
- const rooExt = path13.join(appData, "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "tasks");
16237
+ const appData = process.platform === "win32" ? process.env.APPDATA || path14.join(homedir12, "AppData", "Roaming") : process.platform === "darwin" ? path14.join(homedir12, "Library", "Application Support") : path14.join(homedir12, ".config");
16238
+ const clineExt = path14.join(appData, "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "tasks");
16239
+ const rooExt = path14.join(appData, "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "tasks");
16147
16240
  if (fs12.existsSync(clineExt))
16148
16241
  clinePath = clineExt;
16149
16242
  else if (fs12.existsSync(rooExt))
@@ -16156,7 +16249,7 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16156
16249
  path: clinePath,
16157
16250
  details: clinePath ? "VS Code autonomous agent task storage detected" : "No active Cline or Roo Code tasks found"
16158
16251
  });
16159
- const aiderPath = path13.join(repoPath, ".aider.chat.history.md");
16252
+ const aiderPath = path14.join(repoPath, ".aider.chat.history.md");
16160
16253
  const aiderExists = fs12.existsSync(aiderPath);
16161
16254
  results.push({
16162
16255
  id: "aider",
@@ -16165,8 +16258,8 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16165
16258
  path: aiderExists ? aiderPath : void 0,
16166
16259
  details: aiderExists ? "Repository pairing transcript found" : "No repo-local .aider.chat.history.md found"
16167
16260
  });
16168
- const localOpenCode = path13.join(repoPath, ".opencode");
16169
- const homeOpenCode = path13.join(homedir12, ".opencode", "sessions");
16261
+ const localOpenCode = path14.join(repoPath, ".opencode");
16262
+ const homeOpenCode = path14.join(homedir12, ".opencode", "sessions");
16170
16263
  const opencodePath = fs12.existsSync(localOpenCode) ? localOpenCode : fs12.existsSync(homeOpenCode) ? homeOpenCode : void 0;
16171
16264
  results.push({
16172
16265
  id: "opencode",
@@ -16178,32 +16271,38 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16178
16271
  return results;
16179
16272
  }
16180
16273
  function resolveHooksDir(cwd = process.cwd()) {
16181
- const gitPath = path13.join(cwd, ".git");
16182
- if (!fs12.existsSync(gitPath))
16183
- return null;
16274
+ let curr = path14.resolve(cwd);
16275
+ let gitPath = path14.join(curr, ".git");
16276
+ while (!fs12.existsSync(gitPath)) {
16277
+ const parent = path14.dirname(curr);
16278
+ if (parent === curr)
16279
+ return null;
16280
+ curr = parent;
16281
+ gitPath = path14.join(curr, ".git");
16282
+ }
16184
16283
  try {
16185
16284
  const stat = fs12.statSync(gitPath);
16186
16285
  if (stat.isDirectory()) {
16187
- return path13.join(gitPath, "hooks");
16286
+ return path14.join(gitPath, "hooks");
16188
16287
  }
16189
16288
  const content = fs12.readFileSync(gitPath, "utf-8");
16190
16289
  const match = content.match(/gitdir:\s*(.+)/i);
16191
16290
  if (!match?.[1])
16192
16291
  return null;
16193
16292
  let gitDir = match[1].trim();
16194
- if (!path13.isAbsolute(gitDir)) {
16195
- gitDir = path13.resolve(cwd, gitDir);
16293
+ if (!path14.isAbsolute(gitDir)) {
16294
+ gitDir = path14.resolve(curr, gitDir);
16196
16295
  }
16197
- const commonFile = path13.join(gitDir, "commondir");
16296
+ const commonFile = path14.join(gitDir, "commondir");
16198
16297
  if (fs12.existsSync(commonFile)) {
16199
16298
  let common = fs12.readFileSync(commonFile, "utf-8").trim();
16200
- if (!path13.isAbsolute(common))
16201
- common = path13.resolve(gitDir, common);
16202
- return path13.join(common, "hooks");
16203
- } else if (path13.basename(path13.dirname(gitDir)) === "worktrees") {
16204
- return path13.join(path13.dirname(path13.dirname(gitDir)), "hooks");
16299
+ if (!path14.isAbsolute(common))
16300
+ common = path14.resolve(gitDir, common);
16301
+ return path14.join(common, "hooks");
16302
+ } else if (path14.basename(path14.dirname(gitDir)) === "worktrees") {
16303
+ return path14.join(path14.dirname(path14.dirname(gitDir)), "hooks");
16205
16304
  }
16206
- return path13.join(gitDir, "hooks");
16305
+ return path14.join(gitDir, "hooks");
16207
16306
  } catch {
16208
16307
  return null;
16209
16308
  }
@@ -16219,8 +16318,8 @@ function auditGitHooks(repoPath = process.cwd()) {
16219
16318
  markerFound: false
16220
16319
  };
16221
16320
  }
16222
- const postCommit = path13.join(hooksDir, "post-commit");
16223
- const postRewrite = path13.join(hooksDir, "post-rewrite");
16321
+ const postCommit = path14.join(hooksDir, "post-commit");
16322
+ const postRewrite = path14.join(hooksDir, "post-rewrite");
16224
16323
  const hasMarker = (filePath) => {
16225
16324
  if (!fs12.existsSync(filePath))
16226
16325
  return false;
@@ -16284,7 +16383,7 @@ async function benchmarkHookLatency(trials = 3) {
16284
16383
  }
16285
16384
  }
16286
16385
  function auditStorageHealth() {
16287
- const dbPath = path13.join(os12.homedir(), ".qodewk", "state.db");
16386
+ const dbPath = path14.join(os12.homedir(), ".qodewk", "state.db");
16288
16387
  try {
16289
16388
  const db = new LocalStateDB();
16290
16389
  const stats = db.getStats();
@@ -16311,7 +16410,7 @@ function auditStorageHealth() {
16311
16410
  }
16312
16411
  function auditPricingSync() {
16313
16412
  const modelsCount = Object.keys(RATE_CARDS).length;
16314
- const cachedJson = path13.join(os12.homedir(), ".qodewk", "pricing.json");
16413
+ const cachedJson = path14.join(os12.homedir(), ".qodewk", "pricing.json");
16315
16414
  const hasCached = fs12.existsSync(cachedJson);
16316
16415
  return {
16317
16416
  modelsLoaded: modelsCount,
@@ -16335,7 +16434,7 @@ async function runDiagnostics(options = {}) {
16335
16434
  }
16336
16435
  return {
16337
16436
  overallStatus,
16338
- version: "0.10.0",
16437
+ version: "0.11.0",
16339
16438
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
16340
16439
  repoPath,
16341
16440
  agents,
@@ -16398,14 +16497,17 @@ async function generateReceipt(options = {}) {
16398
16497
  const model = options.model || primaryFp?.model || detected?.model;
16399
16498
  const task = options.task || primaryFp?.taskTitle || (harvestResult.tasks.length > 0 ? harvestResult.tasks[0] : void 0);
16400
16499
  const sessions = harvestResult.footprints.map((fp) => ({
16500
+ sessionId: fp.sessionId,
16401
16501
  provider: fp.platform,
16402
16502
  model: fp.model,
16403
16503
  task: fp.taskTitle,
16404
16504
  filesTouched: fp.filesEdited,
16505
+ turnsCount: fp.stepsCount,
16405
16506
  tokens: fp.tokens,
16406
16507
  cost: fp.cost,
16407
16508
  confidence: fp.confidence,
16408
- mode: fp.mode
16509
+ mode: fp.mode,
16510
+ createdAt: fp.timestamp
16409
16511
  }));
16410
16512
  const aiWrittenRatio = computeAiWrittenRatio(metrics.changedFiles, harvestResult.filesEdited);
16411
16513
  const costResult = estimateCost({
@@ -16816,11 +16918,20 @@ function buildTerminalReceipt(receipt, publicUrl) {
16816
16918
  const provString = receipt.ai.provider + " \xB7 " + (receipt.ai.model || "Unknown");
16817
16919
  const cleanProv = provString.length > 40 ? provString.slice(0, 39) + "\u2026" : provString;
16818
16920
  printRow(`Provider: ${cleanProv}`);
16819
- if (receipt.ai.sessions && receipt.ai.sessions.length > 1) {
16820
- const others = receipt.ai.sessions.slice(1).map((s) => s.provider).filter((p2, i2, arr) => arr.indexOf(p2) === i2 && p2 !== receipt.ai.provider);
16821
- if (others.length > 0) {
16822
- printRow(import_picocolors.default.dim(`Also seen: ${others.join(", ")}`));
16921
+ if (receipt.ai.sessions && receipt.ai.sessions.length > 0) {
16922
+ printDivider("-");
16923
+ printRow(`ITEMIZED SESSIONS (${receipt.ai.sessions.length}):`);
16924
+ for (const s of receipt.ai.sessions.slice(0, 5)) {
16925
+ const taskLabel = s.task ? s.task.length > 18 ? s.task.slice(0, 17) + "\u2026" : s.task : s.sessionId ? "#" + s.sessionId.slice(0, 8) : s.provider;
16926
+ const cleanMod = (s.model || s.provider).replace(/^(claude-|gemini-|gpt-)/, "");
16927
+ const modelLabel = ` (${cleanMod.length > 11 ? cleanMod.slice(0, 10) + "\u2026" : cleanMod})`;
16928
+ const sCost = s.mode === "verified" ? `$${s.cost.toFixed(2)}` : `~$${s.cost.toFixed(2)}`;
16929
+ printRowSplit(`\u2022 ${taskLabel}${import_picocolors.default.dim(modelLabel)}`, teal(sCost));
16930
+ }
16931
+ if (receipt.ai.sessions.length > 5) {
16932
+ printRow(import_picocolors.default.dim(` ... and ${receipt.ai.sessions.length - 5} more sessions`));
16823
16933
  }
16934
+ printDivider("-");
16824
16935
  }
16825
16936
  if (receipt.ai.aiWrittenRatio !== void 0) {
16826
16937
  const aiPct = Math.round(receipt.ai.aiWrittenRatio * 100);
@@ -16905,7 +17016,7 @@ async function outputReceipt(receipt, options, publicUrl) {
16905
17016
 
16906
17017
  // src/hooks.ts
16907
17018
  var fs14 = __toESM(require("fs"), 1);
16908
- var path14 = __toESM(require("path"), 1);
17019
+ var path15 = __toESM(require("path"), 1);
16909
17020
  var HOOK_MARKER_BEGIN2 = "# --- BEGIN QODEWK HOOK ---";
16910
17021
  var HOOK_MARKER_END = "# --- END QODEWK HOOK ---";
16911
17022
  var HOOK_SNIPPET = `
@@ -16917,7 +17028,7 @@ fi
16917
17028
  ${HOOK_MARKER_END}
16918
17029
  `;
16919
17030
  function resolveGitHooksDir(cwd = process.cwd()) {
16920
- const gitPath = path14.join(cwd, ".git");
17031
+ const gitPath = path15.join(cwd, ".git");
16921
17032
  if (!fs14.existsSync(gitPath)) return null;
16922
17033
  let gitCommonDir;
16923
17034
  const stat = fs14.statSync(gitPath);
@@ -16928,23 +17039,23 @@ function resolveGitHooksDir(cwd = process.cwd()) {
16928
17039
  const match = content.match(/gitdir:\s*(.+)/i);
16929
17040
  if (!match?.[1]) return null;
16930
17041
  let gitDir = match[1].trim();
16931
- if (!path14.isAbsolute(gitDir)) {
16932
- gitDir = path14.resolve(cwd, gitDir);
17042
+ if (!path15.isAbsolute(gitDir)) {
17043
+ gitDir = path15.resolve(cwd, gitDir);
16933
17044
  }
16934
- const commonFile = path14.join(gitDir, "commondir");
17045
+ const commonFile = path15.join(gitDir, "commondir");
16935
17046
  if (fs14.existsSync(commonFile)) {
16936
17047
  let common = fs14.readFileSync(commonFile, "utf-8").trim();
16937
- if (!path14.isAbsolute(common)) {
16938
- common = path14.resolve(gitDir, common);
17048
+ if (!path15.isAbsolute(common)) {
17049
+ common = path15.resolve(gitDir, common);
16939
17050
  }
16940
17051
  gitCommonDir = common;
16941
- } else if (path14.basename(path14.dirname(gitDir)) === "worktrees") {
16942
- gitCommonDir = path14.dirname(path14.dirname(gitDir));
17052
+ } else if (path15.basename(path15.dirname(gitDir)) === "worktrees") {
17053
+ gitCommonDir = path15.dirname(path15.dirname(gitDir));
16943
17054
  } else {
16944
17055
  gitCommonDir = gitDir;
16945
17056
  }
16946
17057
  }
16947
- return path14.join(gitCommonDir, "hooks");
17058
+ return path15.join(gitCommonDir, "hooks");
16948
17059
  }
16949
17060
  function checkHookStatus(hooksDir) {
16950
17061
  if (!hooksDir || !fs14.existsSync(hooksDir)) {
@@ -16955,8 +17066,8 @@ function checkHookStatus(hooksDir) {
16955
17066
  postRewriteInstalled: false
16956
17067
  };
16957
17068
  }
16958
- const postCommit = path14.join(hooksDir, "post-commit");
16959
- const postRewrite = path14.join(hooksDir, "post-rewrite");
17069
+ const postCommit = path15.join(hooksDir, "post-commit");
17070
+ const postRewrite = path15.join(hooksDir, "post-rewrite");
16960
17071
  const hasHook = (p2) => {
16961
17072
  if (!fs14.existsSync(p2)) return false;
16962
17073
  try {
@@ -16998,8 +17109,8 @@ function uninstallHookFile(hookFile) {
16998
17109
 
16999
17110
  // src/menu.ts
17000
17111
  var readline = __toESM(require("readline"), 1);
17001
- var path15 = __toESM(require("path"), 1);
17002
- var import_picocolors3 = __toESM(require_picocolors(), 1);
17112
+ var path16 = __toESM(require("path"), 1);
17113
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
17003
17114
 
17004
17115
  // src/doctor-view.ts
17005
17116
  var import_picocolors2 = __toESM(require_picocolors(), 1);
@@ -17086,6 +17197,98 @@ function formatHookTestReport(hooks, benchmark) {
17086
17197
  return lines.join("\n");
17087
17198
  }
17088
17199
 
17200
+ // src/chat-view.ts
17201
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
17202
+ function buildTerminalChatLedger(report) {
17203
+ const lines = [];
17204
+ const coral = colors.coral;
17205
+ const teal = colors.teal;
17206
+ const green = colors.green;
17207
+ const INNER_WIDTH = 68;
17208
+ const push = (line) => lines.push(line);
17209
+ const printRow = (content, width = INNER_WIDTH) => {
17210
+ const visLen = visibleWidth(content);
17211
+ const pad = Math.max(0, width - visLen);
17212
+ push(` | ${content}${" ".repeat(pad)} |`);
17213
+ };
17214
+ const printRowSplit = (left, right, width = INNER_WIDTH) => {
17215
+ const leftVis = visibleWidth(left);
17216
+ const rightVis = visibleWidth(right);
17217
+ const pad = Math.max(1, width - leftVis - rightVis);
17218
+ push(` | ${left}${" ".repeat(pad)}${right} |`);
17219
+ };
17220
+ const printCenteredRow = (content, width = INNER_WIDTH) => {
17221
+ const visLen = visibleWidth(content);
17222
+ const totalPad = Math.max(0, width - visLen);
17223
+ const leftPad = Math.floor(totalPad / 2);
17224
+ const rightPad = totalPad - leftPad;
17225
+ push(` | ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} |`);
17226
+ };
17227
+ const printDivider = (char = "=", width = INNER_WIDTH) => {
17228
+ push(` | ${char.repeat(width)} |`);
17229
+ };
17230
+ push("");
17231
+ push(" " + import_picocolors3.default.bold(coral("/\\".repeat(36))));
17232
+ printCenteredRow(import_picocolors3.default.bold(import_picocolors3.default.white("Q O D E W K")));
17233
+ printCenteredRow(coral("*** WORKSPACE CHAT TELEMETRY LEDGER ***"));
17234
+ printRow("");
17235
+ printRowSplit(
17236
+ `REPO: ${report.projectAlias.slice(0, 24)}`,
17237
+ `WINDOW: ${report.windowDescription}`
17238
+ );
17239
+ printRowSplit(
17240
+ `CHATS: ${report.sessionsCount} sessions`,
17241
+ `STEPS: ${report.totalSteps.toLocaleString()} steps`
17242
+ );
17243
+ printDivider("=");
17244
+ if (report.chats.length === 0) {
17245
+ printCenteredRow(import_picocolors3.default.dim("No agent chat sessions found in this workspace window."));
17246
+ printRow("");
17247
+ } else {
17248
+ const colTask = "CHAT / TASK".padEnd(28);
17249
+ const colModel = "MODEL".padEnd(18);
17250
+ const colTok = "TOKENS".padStart(8);
17251
+ const colCost = "COST".padStart(10);
17252
+ printRow(`${colTask} ${colModel} ${colTok} ${colCost}`);
17253
+ printDivider("-");
17254
+ for (const chat of report.chats) {
17255
+ const cleanTitle = (chat.taskTitle || chat.sessionId || "Untitled Session").replace(/\n/g, " ").trim();
17256
+ const taskDisplay = (cleanTitle.length > 27 ? cleanTitle.slice(0, 26) + "\u2026" : cleanTitle).padEnd(28);
17257
+ const cleanModel = (chat.model || chat.platform || "default").replace(/^(claude-|gemini-|gpt-)/, "").slice(0, 17);
17258
+ const modelDisplay = cleanModel.padEnd(18);
17259
+ const tokK = `${Math.round((chat.tokens.input + chat.tokens.output) / 1e3)}k`.padStart(8);
17260
+ const costStr = (chat.mode === "verified" ? `$${chat.cost.toFixed(2)}` : `~$${chat.cost.toFixed(2)}`).padStart(10);
17261
+ printRow(`${taskDisplay} ${import_picocolors3.default.dim(modelDisplay)} ${teal(tokK)} ${coral(costStr)}`);
17262
+ }
17263
+ }
17264
+ printDivider("=");
17265
+ const totalTokK = `${Math.round((report.totalTokens.input + report.totalTokens.output) / 1e3)}k tokens`;
17266
+ printRowSplit("TOTAL ESTIMATED TOKENS:", green(totalTokK));
17267
+ printRowSplit("TOTAL ESTIMATED SPEND:", import_picocolors3.default.bold(coral(`~$${report.totalCost.toFixed(2)}`)));
17268
+ printDivider("=");
17269
+ printCenteredRow(import_picocolors3.default.dim("[\u2713] Zero code exfiltration \xB7 Telemetry calculated locally"));
17270
+ push(" " + import_picocolors3.default.bold(coral("\\/".repeat(36))));
17271
+ push("");
17272
+ return lines.join("\n");
17273
+ }
17274
+ function buildMarkdownChatLedger(report) {
17275
+ const lines = [];
17276
+ lines.push(`### \u{1F916} Qodewk Workspace Chat Telemetry Ledger`);
17277
+ lines.push(`**Repository:** \`${report.projectAlias}\` | **Window:** ${report.windowDescription} | **Total Spend:** \`~$${report.totalCost.toFixed(2)}\``);
17278
+ lines.push("");
17279
+ lines.push("| Chat / Task | Platform | Model | Steps | Tokens | Cost |");
17280
+ lines.push("| :--- | :--- | :--- | :--- | :--- | :--- |");
17281
+ for (const chat of report.chats) {
17282
+ const title = (chat.taskTitle || chat.sessionId).replace(/\|/g, "\\|").trim();
17283
+ const tokensK = `${Math.round((chat.tokens.input + chat.tokens.output) / 1e3)}k`;
17284
+ const cost = chat.mode === "verified" ? `$${chat.cost.toFixed(2)}` : `~$${chat.cost.toFixed(2)}`;
17285
+ lines.push(`| ${title} | \`${chat.platform}\` | \`${chat.model}\` | ${chat.stepsCount} | ${tokensK} | ${cost} |`);
17286
+ }
17287
+ lines.push("");
17288
+ lines.push(`*Total Sessions: ${report.sessionsCount} \xB7 Total Steps: ${report.totalSteps.toLocaleString()}*`);
17289
+ return lines.join("\n");
17290
+ }
17291
+
17089
17292
  // src/menu.ts
17090
17293
  var SHARE_PAYLOAD_MAX_BYTES = 5e4;
17091
17294
  var BANNER_LINES = [
@@ -17139,6 +17342,12 @@ var MENU_ITEMS = [
17139
17342
  label: "System Health & Diagnostics",
17140
17343
  description: "Audit AI agents, Git hooks, SQLite & pricing registry (doctor)"
17141
17344
  },
17345
+ {
17346
+ id: "chats",
17347
+ key: "8",
17348
+ label: "Workspace Chats & Cost Ledger",
17349
+ description: "Inspect all agent conversation sessions and model costs (chats)"
17350
+ },
17142
17351
  {
17143
17352
  id: "exit",
17144
17353
  key: "0",
@@ -17184,7 +17393,45 @@ var RECEIPT_HORIZON_ITEMS = [
17184
17393
  description: "Return to previous screen"
17185
17394
  }
17186
17395
  ];
17187
- function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Control Panel", subtitle = "\u2191\u2193 move \xB7 enter select \xB7 0-7 quick jump \xB7 q quit", options = {}) {
17396
+ var SHARE_HORIZON_ITEMS = [
17397
+ {
17398
+ id: "latest",
17399
+ key: "1",
17400
+ label: "Latest Changes (Default)",
17401
+ description: "Publish git working tree or latest commit to cloud"
17402
+ },
17403
+ {
17404
+ id: "today",
17405
+ key: "2",
17406
+ label: "Today's Work Session",
17407
+ description: "Publish commits & agent activity since midnight (--today)"
17408
+ },
17409
+ {
17410
+ id: "yesterday",
17411
+ key: "3",
17412
+ label: "Yesterday's Work",
17413
+ description: "Publish activity from yesterday to now (--since yesterday)"
17414
+ },
17415
+ {
17416
+ id: "week",
17417
+ key: "4",
17418
+ label: "Past 7 Days (Sprint)",
17419
+ description: "Publish weekly sprint telemetry across all agents (--since 7d)"
17420
+ },
17421
+ {
17422
+ id: "custom",
17423
+ key: "5",
17424
+ label: "Custom Duration",
17425
+ description: "Specify hours (e.g. 12h) or days (e.g. 3d, 14d) to publish"
17426
+ },
17427
+ {
17428
+ id: "back",
17429
+ key: "0",
17430
+ label: "Back to Main Menu",
17431
+ description: "Return to previous screen"
17432
+ }
17433
+ ];
17434
+ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Control Panel", subtitle = "\u2191\u2193 move \xB7 enter select \xB7 0-8 quick jump \xB7 q quit", options = {}) {
17188
17435
  const lines = [];
17189
17436
  const push = (line) => lines.push(line);
17190
17437
  if (options.showBanner ?? true) {
@@ -17195,21 +17442,31 @@ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Co
17195
17442
  }
17196
17443
  }
17197
17444
  push("");
17198
- const badge = bg.teal(import_picocolors3.default.bold(colors.ink(" qodewk ")));
17199
- push(` ${colors.mutedSoft("\u250C")} ${badge} ${import_picocolors3.default.dim("v0.10.0")}`);
17445
+ const badge = bg.teal(import_picocolors4.default.bold(colors.ink(" qodewk ")));
17446
+ push(` ${colors.mutedSoft("\u250C")} ${badge} ${import_picocolors4.default.dim("v0.11.0")}`);
17200
17447
  push(` ${colors.mutedSoft("\u2502")}`);
17201
17448
  if (options.actionContext) {
17202
- push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Action:")} ${import_picocolors3.default.white(options.actionContext)}`);
17449
+ push(` ${colors.teal("\u25C7")} ${import_picocolors4.default.dim("Action:")} ${import_picocolors4.default.white(options.actionContext)}`);
17203
17450
  push(` ${colors.mutedSoft("\u2502")}`);
17204
17451
  } else {
17205
17452
  const repo = options.repoContext?.alias || "Qodewk";
17206
17453
  const branch = options.repoContext?.branch ? `(${options.repoContext.branch})` : "";
17207
- push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Repository:")} ${import_picocolors3.default.white(repo)} ${import_picocolors3.default.dim(branch)}`);
17454
+ push(` ${colors.teal("\u25C7")} ${import_picocolors4.default.dim("Repository:")} ${import_picocolors4.default.white(repo)} ${import_picocolors4.default.dim(branch)}`);
17208
17455
  push(` ${colors.mutedSoft("\u2502")}`);
17209
- push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Telemetry:")} ${import_picocolors3.default.white("Claude Warm Editorial Rate Cards")}`);
17456
+ let telemetryLabel = "Multi-Model Rate Cards (Active)";
17457
+ try {
17458
+ const agEnv = discoverAntigravityEnvironment();
17459
+ if (agEnv && agEnv.mode === "observed") {
17460
+ telemetryLabel = "Google Antigravity (Active)";
17461
+ } else if (agEnv) {
17462
+ telemetryLabel = "Google Antigravity Detected";
17463
+ }
17464
+ } catch {
17465
+ }
17466
+ push(` ${colors.teal("\u25C7")} ${import_picocolors4.default.dim("Telemetry:")} ${import_picocolors4.default.white(telemetryLabel)}`);
17210
17467
  push(` ${colors.mutedSoft("\u2502")}`);
17211
17468
  }
17212
- push(` ${colors.coral("\u25C6")} ${import_picocolors3.default.bold(import_picocolors3.default.white(title))}`);
17469
+ push(` ${colors.coral("\u25C6")} ${import_picocolors4.default.bold(import_picocolors4.default.white(title))}`);
17213
17470
  push(` ${colors.mutedSoft("\u2502")}`);
17214
17471
  const selectedItem = items[selectedIndex] || items[0];
17215
17472
  for (let i2 = 0; i2 < items.length; i2++) {
@@ -17217,44 +17474,44 @@ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Co
17217
17474
  const isSelected = i2 === selectedIndex;
17218
17475
  if (isSelected) {
17219
17476
  push(
17220
- ` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.bold(colors.coral("\u203A"))} ${import_picocolors3.default.bold(colors.coral(item.key))} ${import_picocolors3.default.bold(import_picocolors3.default.white(item.label))}`
17477
+ ` ${colors.mutedSoft("\u2502")} ${import_picocolors4.default.bold(colors.coral("\u203A"))} ${import_picocolors4.default.bold(colors.coral(item.key))} ${import_picocolors4.default.bold(import_picocolors4.default.white(item.label))}`
17221
17478
  );
17222
17479
  } else {
17223
17480
  push(
17224
- ` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.dim(item.key)} ${import_picocolors3.default.dim(import_picocolors3.default.white(item.label))}`
17481
+ ` ${colors.mutedSoft("\u2502")} ${import_picocolors4.default.dim(item.key)} ${import_picocolors4.default.dim(import_picocolors4.default.white(item.label))}`
17225
17482
  );
17226
17483
  }
17227
17484
  }
17228
17485
  const divider = colors.mutedSoft("\u2500".repeat(58));
17229
17486
  push(` ${colors.mutedSoft("\u2502")}`);
17230
17487
  push(` ${colors.mutedSoft("\u2502")} ${divider}`);
17231
- push(` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.bold(import_picocolors3.default.dim("Description"))}`);
17488
+ push(` ${colors.mutedSoft("\u2502")} ${import_picocolors4.default.bold(import_picocolors4.default.dim("Description"))}`);
17232
17489
  push(` ${colors.mutedSoft("\u2502")} ${colors.amber(selectedItem.description)}`);
17233
17490
  push(` ${colors.mutedSoft("\u2502")} ${divider}`);
17234
17491
  push(` ${colors.mutedSoft("\u2502")}`);
17235
- push(` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.dim(subtitle)}`);
17236
- push(` ${colors.mutedSoft("\u2502")} ${colors.green("[\u2713]")} ${import_picocolors3.default.dim("Source code was never uploaded to Qodewk")}`);
17492
+ push(` ${colors.mutedSoft("\u2502")} ${import_picocolors4.default.dim(subtitle)}`);
17493
+ push(` ${colors.mutedSoft("\u2502")} ${colors.green("[\u2713]")} ${import_picocolors4.default.dim("Source code was never uploaded to Qodewk")}`);
17237
17494
  push(` ${colors.mutedSoft("\u2514")}`);
17238
17495
  push("");
17239
17496
  return lines.join("\n");
17240
17497
  }
17241
17498
  function askLine(promptText) {
17242
- return new Promise((resolve6) => {
17499
+ return new Promise((resolve7) => {
17243
17500
  const rl = readline.createInterface({
17244
17501
  input: process.stdin,
17245
17502
  output: process.stdout
17246
17503
  });
17247
17504
  rl.question(promptText, (answer) => {
17248
17505
  rl.close();
17249
- resolve6(answer.trim());
17506
+ resolve7(answer.trim());
17250
17507
  });
17251
17508
  });
17252
17509
  }
17253
17510
  function waitForKeyToReturn() {
17254
- return new Promise((resolve6) => {
17255
- console.log(import_picocolors3.default.dim("\n Press any key or Enter to return to menu..."));
17511
+ return new Promise((resolve7) => {
17512
+ console.log(import_picocolors4.default.dim("\n Press any key or Enter to return to menu..."));
17256
17513
  if (!process.stdin.isTTY) {
17257
- resolve6();
17514
+ resolve7();
17258
17515
  return;
17259
17516
  }
17260
17517
  const wasRaw = process.stdin.isRaw;
@@ -17263,11 +17520,90 @@ function waitForKeyToReturn() {
17263
17520
  const onKey = () => {
17264
17521
  process.stdin.removeListener("data", onKey);
17265
17522
  if (wasRaw !== void 0) process.stdin.setRawMode(wasRaw);
17266
- resolve6();
17523
+ resolve7();
17524
+ };
17525
+ process.stdin.once("data", onKey);
17526
+ });
17527
+ }
17528
+ function waitForKeyOrAction(promptText) {
17529
+ return new Promise((resolve7) => {
17530
+ console.log(promptText);
17531
+ if (!process.stdin.isTTY) {
17532
+ resolve7("");
17533
+ return;
17534
+ }
17535
+ const wasRaw = process.stdin.isRaw;
17536
+ process.stdin.setRawMode(true);
17537
+ process.stdin.resume();
17538
+ const onKey = (data) => {
17539
+ process.stdin.removeListener("data", onKey);
17540
+ if (wasRaw !== void 0) process.stdin.setRawMode(wasRaw);
17541
+ const str = data.toString();
17542
+ resolve7(str);
17267
17543
  };
17268
17544
  process.stdin.once("data", onKey);
17269
17545
  });
17270
17546
  }
17547
+ async function publishReceiptToCloud(receipt) {
17548
+ if (process.env.QODEWK_TELEMETRY === "off") {
17549
+ console.log(import_picocolors4.default.yellow("\n Cloud publishing is disabled by QODEWK_TELEMETRY=off."));
17550
+ return null;
17551
+ }
17552
+ const sanitized = sanitizeReceiptForShare(receipt);
17553
+ let body = JSON.stringify(sanitized);
17554
+ if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES && sanitized.ai.sessions) {
17555
+ const trimmed2 = {
17556
+ ...sanitized,
17557
+ ai: { ...sanitized.ai, sessions: void 0 }
17558
+ };
17559
+ body = JSON.stringify(trimmed2);
17560
+ }
17561
+ if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES) {
17562
+ console.error(import_picocolors4.default.red(" Sanitized receipt still exceeds the 50 KB cloud payload limit."));
17563
+ return null;
17564
+ }
17565
+ const endpoint = resolveApiUrl();
17566
+ console.log(import_picocolors4.default.dim(`
17567
+ [\xB7] Publishing receipt to ${endpoint}...`));
17568
+ try {
17569
+ const response = await fetch(endpoint, {
17570
+ method: "POST",
17571
+ headers: {
17572
+ "Content-Type": "application/json",
17573
+ "Content-Length": String(Buffer.byteLength(body, "utf-8"))
17574
+ },
17575
+ body
17576
+ });
17577
+ if (!response.ok) {
17578
+ const errText = await response.text().catch(() => "");
17579
+ if (response.status === 503) {
17580
+ console.log(import_picocolors4.default.yellow("\n Notice: Remote server requires durable storage (Supabase or PostgreSQL) in production"));
17581
+ console.log(import_picocolors4.default.dim(" to protect receipts from serverless cold-start data loss."));
17582
+ console.log(import_picocolors4.default.dim(` Endpoint: ${endpoint}`));
17583
+ console.log(colors.green("\n [\u2713] Your receipt is safely saved locally in: ~/.qodewk/state.db"));
17584
+ console.log(import_picocolors4.default.dim(" You can also save it as a local Git note: qodewk --notes\n"));
17585
+ return null;
17586
+ }
17587
+ throw new Error(`API responded with ${response.status}: ${errText.slice(0, 100)}`);
17588
+ }
17589
+ const data = await response.json();
17590
+ const db = new LocalStateDB();
17591
+ db.saveReceipt(sanitized, data.claimToken);
17592
+ db.close();
17593
+ console.log("");
17594
+ console.log(colors.green(" [\u2713] Published successfully."));
17595
+ console.log(` ${import_picocolors4.default.dim("Public URL:")} ${import_picocolors4.default.underline(import_picocolors4.default.cyan(data.url))}`);
17596
+ console.log(` ${import_picocolors4.default.bold(colors.amber("Claim token:"))} ${colors.amber(data.claimToken)}`);
17597
+ console.log(import_picocolors4.default.dim(" (Saved to ~/.qodewk/state.db for future authorship proofs)\n"));
17598
+ await renderTerminalReceipt(sanitized, data.url);
17599
+ return data;
17600
+ } catch (err) {
17601
+ const message = err instanceof Error ? err.message : String(err);
17602
+ console.error(import_picocolors4.default.red(`
17603
+ Share failed: ${message}`));
17604
+ return null;
17605
+ }
17606
+ }
17271
17607
  var cachedRepoContext = null;
17272
17608
  async function getRepoContext() {
17273
17609
  if (cachedRepoContext) return cachedRepoContext;
@@ -17281,7 +17617,7 @@ async function getRepoContext() {
17281
17617
  }
17282
17618
  const branchSummary = await git.branch();
17283
17619
  const branch = branchSummary.current || "HEAD";
17284
- const alias = path15.basename(process.cwd());
17620
+ const alias = path16.basename(process.cwd());
17285
17621
  cachedRepoContext = { alias, branch };
17286
17622
  return cachedRepoContext;
17287
17623
  } catch {
@@ -17292,7 +17628,7 @@ async function getRepoContext() {
17292
17628
  async function runInteractiveMenu() {
17293
17629
  if (!process.stdin.isTTY) {
17294
17630
  console.log(buildMenuFrame(0));
17295
- console.log(import_picocolors3.default.yellow("Interactive menu requires a TTY terminal. Use `qodewk --help` for commands."));
17631
+ console.log(import_picocolors4.default.yellow("Interactive menu requires a TTY terminal. Use `qodewk --help` for commands."));
17296
17632
  return;
17297
17633
  }
17298
17634
  const repoContext = await getRepoContext();
@@ -17300,12 +17636,16 @@ async function runInteractiveMenu() {
17300
17636
  let selectedIndex = 0;
17301
17637
  let active = true;
17302
17638
  let lastRenderedLinesCount = 0;
17303
- const getActiveItems = () => currentScreen === "main" ? MENU_ITEMS : RECEIPT_HORIZON_ITEMS;
17639
+ const getActiveItems = () => {
17640
+ if (currentScreen === "receipt_horizon") return RECEIPT_HORIZON_ITEMS;
17641
+ if (currentScreen === "share_horizon") return SHARE_HORIZON_ITEMS;
17642
+ return MENU_ITEMS;
17643
+ };
17304
17644
  const render = () => {
17305
17645
  const items = getActiveItems();
17306
- const title = currentScreen === "main" ? "Telemetry Control Panel" : "Generate Local Receipt";
17646
+ const title = currentScreen === "main" ? "Telemetry Control Panel" : currentScreen === "receipt_horizon" ? "Generate Local Receipt" : "Publish Receipt to Cloud";
17307
17647
  const subtitle = currentScreen === "main" ? "\u2191\u2193 move \xB7 enter select \xB7 0-7 quick jump \xB7 q quit" : "\u2191\u2193 move \xB7 enter select \xB7 0-5 quick jump \xB7 esc / 0 back";
17308
- const actionContext = currentScreen === "receipt_horizon" ? "Generate Local Receipt" : void 0;
17648
+ const actionContext = currentScreen === "receipt_horizon" ? "Generate Local Receipt" : currentScreen === "share_horizon" ? "Publish Receipt to Cloud" : void 0;
17309
17649
  const showBanner = currentScreen === "main";
17310
17650
  const frame = buildMenuFrame(selectedIndex, items, title, subtitle, {
17311
17651
  repoContext,
@@ -17345,25 +17685,70 @@ async function runInteractiveMenu() {
17345
17685
  since = "7d";
17346
17686
  label = "past 7 days weekly sprint (--since 7d)";
17347
17687
  } else if (item.id === "custom") {
17348
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white(" Custom Telemetry Horizon")));
17349
- console.log(import_picocolors3.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"));
17688
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white(" Custom Telemetry Horizon")));
17689
+ console.log(import_picocolors4.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"));
17350
17690
  const input = await askLine(" \u203A Enter duration or date (e.g. 12h, 3d, 2026-10-01): ");
17351
17691
  if (input) {
17352
17692
  since = input;
17353
17693
  label = `custom range: ${input}`;
17354
17694
  }
17355
17695
  }
17356
- console.log(import_picocolors3.default.dim(` [\xB7] Generating local receipt for ${label}...`));
17696
+ console.log(import_picocolors4.default.dim(` [\xB7] Generating local receipt for ${label}...`));
17357
17697
  try {
17358
17698
  const receipt = await generateReceipt({ since, isPublic: false });
17359
17699
  const db = new LocalStateDB();
17360
17700
  db.saveReceipt(receipt);
17361
17701
  db.close();
17362
17702
  await renderTerminalReceipt(receipt);
17703
+ console.log("");
17704
+ const actionKey = await waitForKeyOrAction(
17705
+ ` ${colors.coral("[s]")} ${import_picocolors4.default.white("Publish this receipt to cloud")} \xB7 ${import_picocolors4.default.dim("[any other key] Return to menu")}`
17706
+ );
17707
+ if (actionKey.trim().toLowerCase() === "s") {
17708
+ await publishReceiptToCloud(receipt);
17709
+ await waitForKeyToReturn();
17710
+ }
17363
17711
  } catch (err) {
17364
17712
  const message = err instanceof Error ? err.message : String(err);
17365
- console.error(import_picocolors3.default.red(`
17713
+ console.error(import_picocolors4.default.red(`
17366
17714
  Failed to generate receipt: ${message}`));
17715
+ await waitForKeyToReturn();
17716
+ }
17717
+ currentScreen = "main";
17718
+ selectedIndex = 0;
17719
+ };
17720
+ const executeShareHorizon = async (item) => {
17721
+ cleanup();
17722
+ console.log("");
17723
+ lastRenderedLinesCount = 0;
17724
+ let since = void 0;
17725
+ let label = "latest git diff";
17726
+ if (item.id === "today") {
17727
+ since = "today";
17728
+ label = "today's work session (--today)";
17729
+ } else if (item.id === "yesterday") {
17730
+ since = "yesterday";
17731
+ label = "yesterday's work (--since yesterday)";
17732
+ } else if (item.id === "week") {
17733
+ since = "7d";
17734
+ label = "past 7 days weekly sprint (--since 7d)";
17735
+ } else if (item.id === "custom") {
17736
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white(" Custom Telemetry Horizon for Cloud Publish")));
17737
+ console.log(import_picocolors4.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"));
17738
+ const input = await askLine(" \u203A Enter duration or date (e.g. 12h, 3d, 2026-10-01): ");
17739
+ if (input) {
17740
+ since = input;
17741
+ label = `custom range: ${input}`;
17742
+ }
17743
+ }
17744
+ console.log(import_picocolors4.default.dim(` [\xB7] Generating and publishing receipt for ${label}...`));
17745
+ try {
17746
+ const receipt = await generateReceipt({ since, isPublic: false });
17747
+ await publishReceiptToCloud(receipt);
17748
+ } catch (err) {
17749
+ const message = err instanceof Error ? err.message : String(err);
17750
+ console.error(import_picocolors4.default.red(`
17751
+ Share failed: ${message}`));
17367
17752
  }
17368
17753
  await waitForKeyToReturn();
17369
17754
  currentScreen = "main";
@@ -17376,8 +17761,8 @@ async function runInteractiveMenu() {
17376
17761
  const selectedItem = MENU_ITEMS[selectedIndex];
17377
17762
  switch (selectedItem.id) {
17378
17763
  case "audit": {
17379
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Audit Branch or Revision Diff")));
17380
- console.log(import_picocolors3.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"));
17764
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Audit Branch or Revision Diff")));
17765
+ console.log(import_picocolors4.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"));
17381
17766
  let defaultBase = "origin/main";
17382
17767
  try {
17383
17768
  defaultBase = await detectDefaultBaseBranch(process.cwd());
@@ -17389,7 +17774,7 @@ async function runInteractiveMenu() {
17389
17774
  const head = await askLine(
17390
17775
  ` \u203A Head git ref or commit SHA [default: HEAD]: `
17391
17776
  );
17392
- console.log(import_picocolors3.default.dim("\n [\xB7] Auditing git revision range..."));
17777
+ console.log(import_picocolors4.default.dim("\n [\xB7] Auditing git revision range..."));
17393
17778
  try {
17394
17779
  const receipt = await generateReceipt({
17395
17780
  baseSha: base || defaultBase,
@@ -17402,71 +17787,15 @@ async function runInteractiveMenu() {
17402
17787
  await renderTerminalReceipt(receipt);
17403
17788
  } catch (err) {
17404
17789
  const message = err instanceof Error ? err.message : String(err);
17405
- console.error(import_picocolors3.default.red(`
17790
+ console.error(import_picocolors4.default.red(`
17406
17791
  Audit failed: ${message}`));
17407
17792
  }
17408
17793
  await waitForKeyToReturn();
17409
17794
  break;
17410
17795
  }
17411
17796
  case "share": {
17412
- console.log(import_picocolors3.default.dim(" [\xB7] Generating and sanitizing receipt for cloud publishing..."));
17413
- try {
17414
- const receipt = await generateReceipt({ isPublic: false });
17415
- if (process.env.QODEWK_TELEMETRY === "off") {
17416
- console.log(import_picocolors3.default.yellow("\n Cloud publishing is disabled by QODEWK_TELEMETRY=off."));
17417
- await renderTerminalReceipt(receipt);
17418
- await waitForKeyToReturn();
17419
- break;
17420
- }
17421
- const sanitized = sanitizeReceiptForShare(receipt);
17422
- let body = JSON.stringify(sanitized);
17423
- if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES && sanitized.ai.sessions) {
17424
- const trimmed2 = {
17425
- ...sanitized,
17426
- ai: { ...sanitized.ai, sessions: void 0 }
17427
- };
17428
- body = JSON.stringify(trimmed2);
17429
- }
17430
- const endpoint = resolveApiUrl();
17431
- console.log(import_picocolors3.default.dim(` [\xB7] Uploading metadata to ${endpoint}...`));
17432
- const response = await fetch(endpoint, {
17433
- method: "POST",
17434
- headers: {
17435
- "Content-Type": "application/json",
17436
- "Content-Length": String(Buffer.byteLength(body, "utf-8"))
17437
- },
17438
- body
17439
- });
17440
- if (!response.ok) {
17441
- const errText = await response.text().catch(() => "");
17442
- if (response.status === 503) {
17443
- console.log(import_picocolors3.default.yellow("\n Notice: Remote server requires durable storage (Supabase or PostgreSQL) in production"));
17444
- console.log(import_picocolors3.default.dim(" to protect receipts from serverless cold-start data loss."));
17445
- console.log(import_picocolors3.default.dim(` Endpoint: ${endpoint}`));
17446
- console.log(colors.green("\n [\u2713] Your receipt is safely saved locally in: ~/.qodewk/state.db"));
17447
- console.log(import_picocolors3.default.dim(" You can also save it as a local Git note: qodewk --notes\n"));
17448
- await renderTerminalReceipt(sanitized);
17449
- await waitForKeyToReturn();
17450
- break;
17451
- }
17452
- throw new Error(`API responded with ${response.status}${errText ? `: ${errText.slice(0, 100)}` : ""}`);
17453
- }
17454
- const data = await response.json();
17455
- const db = new LocalStateDB();
17456
- db.saveReceipt(sanitized, data.claimToken);
17457
- db.close();
17458
- console.log("");
17459
- console.log(colors.green(" [\u2713] Published successfully."));
17460
- console.log(` ${import_picocolors3.default.dim("Public URL:")} ${import_picocolors3.default.underline(import_picocolors3.default.cyan(data.url))}`);
17461
- console.log(` ${import_picocolors3.default.bold(colors.amber("Claim token:"))} ${colors.amber(data.claimToken)}`);
17462
- console.log(import_picocolors3.default.dim(" (Saved to ~/.qodewk/state.db for future authorship proofs)\n"));
17463
- await renderTerminalReceipt(sanitized, data.url);
17464
- } catch (err) {
17465
- const message = err instanceof Error ? err.message : String(err);
17466
- console.error(import_picocolors3.default.red(`
17467
- Share failed: ${message}`));
17468
- }
17469
- await waitForKeyToReturn();
17797
+ currentScreen = "share_horizon";
17798
+ selectedIndex = 0;
17470
17799
  break;
17471
17800
  }
17472
17801
  case "hooks": {
@@ -17485,10 +17814,14 @@ async function runInteractiveMenu() {
17485
17814
  await runDoctorDiagnosticsAction();
17486
17815
  break;
17487
17816
  }
17817
+ case "chats": {
17818
+ await showChatsAction();
17819
+ break;
17820
+ }
17488
17821
  case "exit": {
17489
17822
  active = false;
17490
17823
  cleanup();
17491
- console.log(import_picocolors3.default.dim(" Exited Qodewk.\n"));
17824
+ console.log(import_picocolors4.default.dim(" Exited Qodewk.\n"));
17492
17825
  process.exit(0);
17493
17826
  return;
17494
17827
  }
@@ -17497,19 +17830,19 @@ async function runInteractiveMenu() {
17497
17830
  const manageHooksSubmenu = async () => {
17498
17831
  const hooksDir = resolveGitHooksDir();
17499
17832
  const status = checkHookStatus(hooksDir);
17500
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk Git Hooks Management")));
17501
- console.log(import_picocolors3.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"));
17833
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Git Hooks Management")));
17834
+ console.log(import_picocolors4.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"));
17502
17835
  if (!status.isGit) {
17503
- console.log(import_picocolors3.default.yellow(" Not inside a Git repository. Hooks cannot be configured."));
17836
+ console.log(import_picocolors4.default.yellow(" Not inside a Git repository. Hooks cannot be configured."));
17504
17837
  await waitForKeyToReturn();
17505
17838
  return;
17506
17839
  }
17507
- console.log(` Hooks directory: ${import_picocolors3.default.dim(status.hooksDir || "None")}`);
17840
+ console.log(` Hooks directory: ${import_picocolors4.default.dim(status.hooksDir || "None")}`);
17508
17841
  console.log(
17509
- ` post-commit: ${status.postCommitInstalled ? colors.green("[\u2713 Installed]") : import_picocolors3.default.dim("[\xB7 Not installed]")}`
17842
+ ` post-commit: ${status.postCommitInstalled ? colors.green("[\u2713 Installed]") : import_picocolors4.default.dim("[\xB7 Not installed]")}`
17510
17843
  );
17511
17844
  console.log(
17512
- ` post-rewrite: ${status.postRewriteInstalled ? colors.green("[\u2713 Installed]") : import_picocolors3.default.dim("[\xB7 Not installed]")}`
17845
+ ` post-rewrite: ${status.postRewriteInstalled ? colors.green("[\u2713 Installed]") : import_picocolors4.default.dim("[\xB7 Not installed]")}`
17513
17846
  );
17514
17847
  console.log("");
17515
17848
  console.log(" [1] Install non-blocking hooks (< 5ms background recorder)");
@@ -17522,7 +17855,7 @@ async function runInteractiveMenu() {
17522
17855
  if (status.hooksDir) {
17523
17856
  const targets = ["post-commit", "post-rewrite"];
17524
17857
  for (const t2 of targets) {
17525
- installHookFile(path15.join(status.hooksDir, t2));
17858
+ installHookFile(path16.join(status.hooksDir, t2));
17526
17859
  }
17527
17860
  console.log(colors.green("\n [\u2713] Non-blocking hooks installed successfully."));
17528
17861
  }
@@ -17530,7 +17863,7 @@ async function runInteractiveMenu() {
17530
17863
  if (status.hooksDir) {
17531
17864
  const targets = ["post-commit", "post-rewrite"];
17532
17865
  for (const t2 of targets) {
17533
- uninstallHookFile(path15.join(status.hooksDir, t2));
17866
+ uninstallHookFile(path16.join(status.hooksDir, t2));
17534
17867
  }
17535
17868
  console.log(colors.green("\n [\u2713] Qodewk hooks removed."));
17536
17869
  }
@@ -17542,8 +17875,8 @@ async function runInteractiveMenu() {
17542
17875
  await waitForKeyToReturn();
17543
17876
  };
17544
17877
  const manageGitNotesSubmenu = async () => {
17545
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk Git Notes Management (refs/notes/qodewk)")));
17546
- console.log(import_picocolors3.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"));
17878
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Git Notes Management (refs/notes/qodewk)")));
17879
+ console.log(import_picocolors4.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"));
17547
17880
  console.log(" [1] List commits with attached Qodewk notes");
17548
17881
  console.log(" [2] Show receipt note on a commit (default: HEAD)");
17549
17882
  console.log(" [3] Attach receipt note to a Git commit (default: HEAD)");
@@ -17554,17 +17887,17 @@ async function runInteractiveMenu() {
17554
17887
  try {
17555
17888
  const shas = await listGitReceiptNotes();
17556
17889
  if (shas.length === 0) {
17557
- console.log(import_picocolors3.default.yellow("\n No Qodewk Git notes found in repository."));
17890
+ console.log(import_picocolors4.default.yellow("\n No Qodewk Git notes found in repository."));
17558
17891
  } else {
17559
- console.log(import_picocolors3.default.bold(`
17892
+ console.log(import_picocolors4.default.bold(`
17560
17893
  Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
17561
17894
  for (const sha of shas) {
17562
- console.log(` ${import_picocolors3.default.cyan(sha.slice(0, 10))} ${import_picocolors3.default.dim(sha)}`);
17895
+ console.log(` ${import_picocolors4.default.cyan(sha.slice(0, 10))} ${import_picocolors4.default.dim(sha)}`);
17563
17896
  }
17564
17897
  }
17565
17898
  } catch (err) {
17566
17899
  const message = err instanceof Error ? err.message : String(err);
17567
- console.error(import_picocolors3.default.red(`
17900
+ console.error(import_picocolors4.default.red(`
17568
17901
  Error listing Git notes: ${message}`));
17569
17902
  }
17570
17903
  } else if (choice === "2") {
@@ -17572,20 +17905,20 @@ async function runInteractiveMenu() {
17572
17905
  try {
17573
17906
  const receipt = await readGitReceiptNote(commit);
17574
17907
  if (!receipt) {
17575
- console.log(import_picocolors3.default.yellow(`
17908
+ console.log(import_picocolors4.default.yellow(`
17576
17909
  No Qodewk receipt note found on commit '${commit}'.`));
17577
17910
  } else {
17578
17911
  await renderTerminalReceipt(receipt);
17579
17912
  }
17580
17913
  } catch (err) {
17581
17914
  const message = err instanceof Error ? err.message : String(err);
17582
- console.error(import_picocolors3.default.red(`
17915
+ console.error(import_picocolors4.default.red(`
17583
17916
  Error reading Git note: ${message}`));
17584
17917
  }
17585
17918
  } else if (choice === "3") {
17586
17919
  const commit = await askLine(" \u203A Commit SHA to attach note [default: HEAD]: ") || "HEAD";
17587
17920
  try {
17588
- console.log(import_picocolors3.default.dim(`
17921
+ console.log(import_picocolors4.default.dim(`
17589
17922
  [\xB7] Generating receipt for ${commit}...`));
17590
17923
  const receipt = await generateReceipt({ headSha: commit });
17591
17924
  await writeGitReceiptNote(receipt.repository.headSha, receipt);
@@ -17595,30 +17928,30 @@ async function runInteractiveMenu() {
17595
17928
  );
17596
17929
  } catch (err) {
17597
17930
  const message = err instanceof Error ? err.message : String(err);
17598
- console.error(import_picocolors3.default.red(`
17931
+ console.error(import_picocolors4.default.red(`
17599
17932
  Error writing Git note: ${message}`));
17600
17933
  }
17601
17934
  }
17602
17935
  await waitForKeyToReturn();
17603
17936
  };
17604
17937
  const showStorageStatus = async () => {
17605
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk Local Database & Storage Status")));
17606
- console.log(import_picocolors3.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"));
17938
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Local Database & Storage Status")));
17939
+ console.log(import_picocolors4.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"));
17607
17940
  try {
17608
17941
  const db = new LocalStateDB();
17609
17942
  const stats = db.getStats();
17610
17943
  const recent = db.getRecentReceipts(5);
17611
17944
  db.close();
17612
- console.log(` Database path: ${import_picocolors3.default.dim("~/.qodewk/state.db")}`);
17613
- console.log(` Total saved receipts: ${import_picocolors3.default.bold(import_picocolors3.default.white(String(stats.totalReceipts)))}`);
17614
- console.log(` Total agent footprints: ${import_picocolors3.default.bold(import_picocolors3.default.white(String(stats.totalFootprints)))}`);
17945
+ console.log(` Database path: ${import_picocolors4.default.dim("~/.qodewk/state.db")}`);
17946
+ console.log(` Total saved receipts: ${import_picocolors4.default.bold(import_picocolors4.default.white(String(stats.totalReceipts)))}`);
17947
+ console.log(` Total agent footprints: ${import_picocolors4.default.bold(import_picocolors4.default.white(String(stats.totalFootprints)))}`);
17615
17948
  console.log("");
17616
17949
  if (recent.length === 0) {
17617
- console.log(import_picocolors3.default.dim(" No stored receipts yet. Run 'Generate Local Receipt' to record your first."));
17950
+ console.log(import_picocolors4.default.dim(" No stored receipts yet. Run 'Generate Local Receipt' to record your first."));
17618
17951
  } else {
17619
- console.log(import_picocolors3.default.dim(" Recent Receipts:"));
17620
- console.log(import_picocolors3.default.dim(" " + "ID".padEnd(26) + "DATE".padEnd(12) + "BRANCH".padEnd(18) + "COST"));
17621
- console.log(import_picocolors3.default.dim(" " + "\u2500".repeat(60)));
17952
+ console.log(import_picocolors4.default.dim(" Recent Receipts:"));
17953
+ console.log(import_picocolors4.default.dim(" " + "ID".padEnd(26) + "DATE".padEnd(12) + "BRANCH".padEnd(18) + "COST"));
17954
+ console.log(import_picocolors4.default.dim(" " + "\u2500".repeat(60)));
17622
17955
  for (const item of recent) {
17623
17956
  const id = item.receipt.receipt.id.slice(0, 24).padEnd(26);
17624
17957
  const date = item.receipt.receipt.createdAt.slice(0, 10).padEnd(12);
@@ -17628,23 +17961,52 @@ async function runInteractiveMenu() {
17628
17961
  }
17629
17962
  }
17630
17963
  console.log("");
17631
- console.log(` ${colors.green("[\u2713]")} ${import_picocolors3.default.dim("Privacy guarantee: raw source code is never stored in SQLite")}`);
17964
+ console.log(` ${colors.green("[\u2713]")} ${import_picocolors4.default.dim("Privacy guarantee: raw source code is never stored in SQLite")}`);
17965
+ if (recent.length > 0) {
17966
+ console.log("");
17967
+ const ans = await askLine(" \u203A Enter receipt ID prefix to publish to cloud [Enter to return]: ");
17968
+ if (ans) {
17969
+ const matched = recent.find((r2) => r2.receipt.receipt.id.toLowerCase().startsWith(ans.toLowerCase()));
17970
+ if (matched) {
17971
+ await publishReceiptToCloud(matched.receipt);
17972
+ await waitForKeyToReturn();
17973
+ return;
17974
+ } else {
17975
+ console.log(import_picocolors4.default.yellow(` No stored receipt matching '${ans}' found.`));
17976
+ }
17977
+ }
17978
+ }
17632
17979
  } catch (err) {
17633
17980
  const message = err instanceof Error ? err.message : String(err);
17634
- console.error(import_picocolors3.default.red(` Failed to inspect storage: ${message}`));
17981
+ console.error(import_picocolors4.default.red(` Failed to inspect storage: ${message}`));
17635
17982
  }
17636
17983
  await waitForKeyToReturn();
17637
17984
  };
17638
17985
  const runDoctorDiagnosticsAction = async () => {
17639
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk System Health & Diagnostics (Doctor)")));
17640
- console.log(import_picocolors3.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"));
17641
- console.log(import_picocolors3.default.dim(" [\xB7] Running diagnostic audit across agents, hooks, storage, and pricing...\n"));
17986
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk System Health & Diagnostics (Doctor)")));
17987
+ console.log(import_picocolors4.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"));
17988
+ console.log(import_picocolors4.default.dim(" [\xB7] Running diagnostic audit across agents, hooks, storage, and pricing...\n"));
17642
17989
  try {
17643
17990
  const report = await runDiagnostics();
17644
17991
  console.log(formatDoctorReport(report));
17645
17992
  } catch (err) {
17646
17993
  const message = err instanceof Error ? err.message : String(err);
17647
- console.error(import_picocolors3.default.red(` Diagnostic check failed: ${message}`));
17994
+ console.error(import_picocolors4.default.red(` Diagnostic check failed: ${message}`));
17995
+ }
17996
+ await waitForKeyToReturn();
17997
+ };
17998
+ const showChatsAction = async () => {
17999
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Workspace Chat Telemetry & Cost Ledger")));
18000
+ console.log(import_picocolors4.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"));
18001
+ console.log(import_picocolors4.default.dim(" [\xB7] Scanning local IDE transcripts (Antigravity, Cursor, Claude, Windsurf, Cline)...\n"));
18002
+ try {
18003
+ const report = await listProjectChats({
18004
+ repoPath: process.cwd()
18005
+ });
18006
+ console.log(buildTerminalChatLedger(report));
18007
+ } catch (err) {
18008
+ const message = err instanceof Error ? err.message : String(err);
18009
+ console.error(import_picocolors4.default.red(` Failed to inspect workspace chats: ${message}`));
17648
18010
  }
17649
18011
  await waitForKeyToReturn();
17650
18012
  };
@@ -17669,7 +18031,7 @@ async function runInteractiveMenu() {
17669
18031
  return;
17670
18032
  }
17671
18033
  cleanup();
17672
- console.log(import_picocolors3.default.dim("\n Exited Qodewk.\n"));
18034
+ console.log(import_picocolors4.default.dim("\n Exited Qodewk.\n"));
17673
18035
  process.exit(0);
17674
18036
  }
17675
18037
  if (key.name === "up" || key.name === "k") {
@@ -17682,7 +18044,9 @@ async function runInteractiveMenu() {
17682
18044
  render();
17683
18045
  return;
17684
18046
  }
17685
- const itemByKey = items.findIndex((item) => item.key === key.name || item.key === _str);
18047
+ const itemByKey = items.findIndex(
18048
+ (item) => item.key === key.name || item.key === _str || _str && _str.toLowerCase() === "c" && item.id === "chats"
18049
+ );
17686
18050
  if (itemByKey !== -1) {
17687
18051
  selectedIndex = itemByKey;
17688
18052
  render();
@@ -17695,8 +18059,14 @@ async function runInteractiveMenu() {
17695
18059
  if (active) startLoop();
17696
18060
  return;
17697
18061
  }
18062
+ if (selected.id === "share") {
18063
+ currentScreen = "share_horizon";
18064
+ selectedIndex = 0;
18065
+ if (active) startLoop();
18066
+ return;
18067
+ }
17698
18068
  await executeSelectedAction();
17699
- } else {
18069
+ } else if (currentScreen === "receipt_horizon") {
17700
18070
  if (selected.id === "back") {
17701
18071
  currentScreen = "main";
17702
18072
  selectedIndex = 0;
@@ -17704,6 +18074,14 @@ async function runInteractiveMenu() {
17704
18074
  return;
17705
18075
  }
17706
18076
  await executeReceiptHorizon(selected);
18077
+ } else if (currentScreen === "share_horizon") {
18078
+ if (selected.id === "back") {
18079
+ currentScreen = "main";
18080
+ selectedIndex = 0;
18081
+ if (active) startLoop();
18082
+ return;
18083
+ }
18084
+ await executeShareHorizon(selected);
17707
18085
  }
17708
18086
  if (active) {
17709
18087
  startLoop();
@@ -17720,8 +18098,14 @@ async function runInteractiveMenu() {
17720
18098
  if (active) startLoop();
17721
18099
  return;
17722
18100
  }
18101
+ if (selected.id === "share") {
18102
+ currentScreen = "share_horizon";
18103
+ selectedIndex = 0;
18104
+ if (active) startLoop();
18105
+ return;
18106
+ }
17723
18107
  await executeSelectedAction();
17724
- } else {
18108
+ } else if (currentScreen === "receipt_horizon") {
17725
18109
  if (selected.id === "back") {
17726
18110
  currentScreen = "main";
17727
18111
  selectedIndex = 0;
@@ -17729,6 +18113,14 @@ async function runInteractiveMenu() {
17729
18113
  return;
17730
18114
  }
17731
18115
  await executeReceiptHorizon(selected);
18116
+ } else if (currentScreen === "share_horizon") {
18117
+ if (selected.id === "back") {
18118
+ currentScreen = "main";
18119
+ selectedIndex = 0;
18120
+ if (active) startLoop();
18121
+ return;
18122
+ }
18123
+ await executeShareHorizon(selected);
17732
18124
  }
17733
18125
  if (active) {
17734
18126
  startLoop();
@@ -17746,10 +18138,10 @@ loadQodewkEnv();
17746
18138
  var SHARE_PAYLOAD_MAX_BYTES2 = 5e4;
17747
18139
  function resolveCliVersion() {
17748
18140
  try {
17749
- const argv1 = process.argv[1] ? path16.dirname(path16.resolve(process.argv[1])) : process.cwd();
18141
+ const argv1 = process.argv[1] ? path17.dirname(path17.resolve(process.argv[1])) : process.cwd();
17750
18142
  const candidates = [
17751
- path16.join(argv1, "..", "package.json"),
17752
- path16.join(argv1, "package.json")
18143
+ path17.join(argv1, "..", "package.json"),
18144
+ path17.join(argv1, "package.json")
17753
18145
  ];
17754
18146
  for (const candidate of candidates) {
17755
18147
  if (!fs15.existsSync(candidate)) continue;
@@ -17758,7 +18150,7 @@ function resolveCliVersion() {
17758
18150
  }
17759
18151
  } catch {
17760
18152
  }
17761
- return "0.10.0";
18153
+ return "0.11.0";
17762
18154
  }
17763
18155
  function resolveSince(options) {
17764
18156
  return options.today ? "today" : options.since;
@@ -17796,21 +18188,44 @@ program2.name("qodewk").description("Universal telemetry and digital receipt gen
17796
18188
  if (options.notes) {
17797
18189
  try {
17798
18190
  await writeGitReceiptNote(receipt.repository.headSha, receipt);
17799
- console.log(import_picocolors4.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`));
18191
+ console.log(import_picocolors5.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`));
17800
18192
  } catch (noteErr) {
17801
- console.warn(import_picocolors4.default.yellow(`Warning: Could not write Git note: ${noteErr.message}`));
18193
+ console.warn(import_picocolors5.default.yellow(`Warning: Could not write Git note: ${noteErr.message}`));
17802
18194
  }
17803
18195
  }
17804
18196
  await outputReceipt(receipt, options);
17805
18197
  } catch (err) {
17806
18198
  const message = err instanceof Error ? err.message : String(err);
17807
- console.error(import_picocolors4.default.red(`Error generating receipt: ${message}`));
18199
+ console.error(import_picocolors5.default.red(`Error generating receipt: ${message}`));
17808
18200
  process.exit(1);
17809
18201
  }
17810
18202
  });
17811
18203
  program2.command("menu").description("Launch interactive terminal control panel").action(async () => {
17812
18204
  await runInteractiveMenu();
17813
18205
  });
18206
+ program2.command("chats").description("Inspect AI chat sessions and model cost ledger for current workspace").option("-s, --since <duration>", "Filter chats since duration (e.g. today, 24h, 7d, 30d)").option("--today", "Filter chats for today").option("--all", "Show all-time workspace chats (bypass 30-day default window)").option("-p, --platform <platform>", "Filter agent platform (antigravity, claude, cursor, etc.)").option("-j, --json", "Output chat telemetry report in machine-readable JSON format").option("-f, --format <format>", "Output format (terminal, json, markdown)", "terminal").action(async (options) => {
18207
+ try {
18208
+ const since = options.today ? "today" : options.since;
18209
+ const report = await listProjectChats({
18210
+ repoPath: process.cwd(),
18211
+ since,
18212
+ platform: options.platform,
18213
+ all: options.all
18214
+ });
18215
+ const isJson = Boolean(options.json || program2.opts().json || options.format === "json");
18216
+ if (isJson) {
18217
+ console.log(JSON.stringify(report, null, 2));
18218
+ } else if (options.format === "markdown") {
18219
+ console.log(buildMarkdownChatLedger(report));
18220
+ } else {
18221
+ console.log(buildTerminalChatLedger(report));
18222
+ }
18223
+ } catch (err) {
18224
+ const message = err instanceof Error ? err.message : String(err);
18225
+ console.error(import_picocolors5.default.red(`Error listing workspace chats: ${message}`));
18226
+ process.exit(1);
18227
+ }
18228
+ });
17814
18229
  program2.command("doctor").description("Run complete diagnostic health check of AI agents, git hooks, and local telemetry").option("-j, --json", "Output diagnostic report in machine-readable JSON format").action(async (options) => {
17815
18230
  try {
17816
18231
  const isJson = Boolean(options.json || program2.opts().json);
@@ -17825,7 +18240,7 @@ program2.command("doctor").description("Run complete diagnostic health check of
17825
18240
  }
17826
18241
  } catch (err) {
17827
18242
  const message = err instanceof Error ? err.message : String(err);
17828
- console.error(import_picocolors4.default.red(`Error running diagnostics: ${message}`));
18243
+ console.error(import_picocolors5.default.red(`Error running diagnostics: ${message}`));
17829
18244
  process.exit(1);
17830
18245
  }
17831
18246
  });
@@ -17845,7 +18260,7 @@ program2.command("audit").description("Audit PR or branch diff against a target
17845
18260
  await outputReceipt(receipt, options);
17846
18261
  } catch (err) {
17847
18262
  const message = err instanceof Error ? err.message : String(err);
17848
- console.error(import_picocolors4.default.red(`Error auditing git range: ${message}`));
18263
+ console.error(import_picocolors5.default.red(`Error auditing git range: ${message}`));
17849
18264
  process.exit(1);
17850
18265
  }
17851
18266
  });
@@ -17862,12 +18277,12 @@ program2.command("share").description("Publish privacy-safe receipt to Qodewk cl
17862
18277
  const localFlag = program2.opts().local === true;
17863
18278
  if (process.env.QODEWK_TELEMETRY === "off" || localFlag) {
17864
18279
  console.log(
17865
- import_picocolors4.default.yellow(
18280
+ import_picocolors5.default.yellow(
17866
18281
  `
17867
18282
  Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"}).`
17868
18283
  )
17869
18284
  );
17870
- console.log(import_picocolors4.default.dim("Telemetry remains strictly stored in local SQLite (~/.qodewk/state.db).\n"));
18285
+ console.log(import_picocolors5.default.dim("Telemetry remains strictly stored in local SQLite (~/.qodewk/state.db).\n"));
17871
18286
  persistReceipt(receipt);
17872
18287
  await renderTerminalReceipt(receipt);
17873
18288
  return;
@@ -17882,11 +18297,11 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
17882
18297
  body = JSON.stringify(trimmed2);
17883
18298
  }
17884
18299
  if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES2) {
17885
- console.error(import_picocolors4.default.red("Sanitized receipt still exceeds the 50 KB cloud payload limit."));
18300
+ console.error(import_picocolors5.default.red("Sanitized receipt still exceeds the 50 KB cloud payload limit."));
17886
18301
  process.exit(1);
17887
18302
  }
17888
18303
  const endpoint = resolveApiUrl();
17889
- console.log(import_picocolors4.default.dim(`Publishing receipt ${sanitized.receipt.id} to ${endpoint}...`));
18304
+ console.log(import_picocolors5.default.dim(`Publishing receipt ${sanitized.receipt.id} to ${endpoint}...`));
17890
18305
  try {
17891
18306
  const response = await fetch(endpoint, {
17892
18307
  method: "POST",
@@ -17903,11 +18318,11 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
17903
18318
  const data = await response.json();
17904
18319
  persistReceipt(sanitized, data.claimToken);
17905
18320
  console.log("");
17906
- console.log(import_picocolors4.default.green(" Published successfully."));
17907
- console.log(` ${import_picocolors4.default.dim("Public URL:")} ${import_picocolors4.default.underline(import_picocolors4.default.cyan(data.url))}`);
17908
- console.log(` ${import_picocolors4.default.bold(import_picocolors4.default.yellow(" Claim token (store securely \u2014 shown once):"))}`);
17909
- console.log(` ${import_picocolors4.default.yellow(data.claimToken)}`);
17910
- console.log(import_picocolors4.default.dim(" Saved to ~/.qodewk/state.db \u2014 required to prove authorship later."));
18321
+ console.log(import_picocolors5.default.green(" Published successfully."));
18322
+ console.log(` ${import_picocolors5.default.dim("Public URL:")} ${import_picocolors5.default.underline(import_picocolors5.default.cyan(data.url))}`);
18323
+ console.log(` ${import_picocolors5.default.bold(import_picocolors5.default.yellow(" Claim token (store securely \u2014 shown once):"))}`);
18324
+ console.log(` ${import_picocolors5.default.yellow(data.claimToken)}`);
18325
+ console.log(import_picocolors5.default.dim(" Saved to ~/.qodewk/state.db \u2014 required to prove authorship later."));
17911
18326
  console.log("");
17912
18327
  await renderTerminalReceipt(sanitized, data.url);
17913
18328
  if (options.json) {
@@ -17915,14 +18330,14 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
17915
18330
  }
17916
18331
  } catch (networkErr) {
17917
18332
  const message = networkErr instanceof Error ? networkErr.message : String(networkErr);
17918
- console.log(import_picocolors4.default.yellow(`
18333
+ console.log(import_picocolors5.default.yellow(`
17919
18334
  Could not reach cloud API (${message}). Rendered locally:`));
17920
18335
  persistReceipt(receipt);
17921
18336
  await renderTerminalReceipt(receipt);
17922
18337
  }
17923
18338
  } catch (err) {
17924
18339
  const message = err instanceof Error ? err.message : String(err);
17925
- console.error(import_picocolors4.default.red(`Error sharing receipt: ${message}`));
18340
+ console.error(import_picocolors5.default.red(`Error sharing receipt: ${message}`));
17926
18341
  process.exit(1);
17927
18342
  }
17928
18343
  });
@@ -17940,7 +18355,7 @@ hookCommand.command("install").description("Install non-blocking post-commit and
17940
18355
  try {
17941
18356
  const hooksDir = resolveGitHooksDir();
17942
18357
  if (!hooksDir) {
17943
- console.error(import_picocolors4.default.red("Error: Current directory is not a Git repository (.git not found)."));
18358
+ console.error(import_picocolors5.default.red("Error: Current directory is not a Git repository (.git not found)."));
17944
18359
  process.exit(1);
17945
18360
  }
17946
18361
  if (!fs15.existsSync(hooksDir)) {
@@ -17950,25 +18365,25 @@ hookCommand.command("install").description("Install non-blocking post-commit and
17950
18365
  let installed = 0;
17951
18366
  let existing = 0;
17952
18367
  for (const name of targets) {
17953
- const result = installHookFile(path16.join(hooksDir, name));
18368
+ const result = installHookFile(path17.join(hooksDir, name));
17954
18369
  if (result === "installed") installed++;
17955
18370
  else existing++;
17956
18371
  }
17957
18372
  if (installed === 0 && existing > 0) {
17958
- console.log(import_picocolors4.default.yellow("Qodewk Git hooks are already installed (post-commit, post-rewrite)."));
18373
+ console.log(import_picocolors5.default.yellow("Qodewk Git hooks are already installed (post-commit, post-rewrite)."));
17959
18374
  return;
17960
18375
  }
17961
18376
  console.log(
17962
- import_picocolors4.default.green(
18377
+ import_picocolors5.default.green(
17963
18378
  `\u2713 Non-blocking Qodewk hooks installed in ${hooksDir} (post-commit${installed > 1 || existing > 0 ? ", post-rewrite" : installed === 1 && targets.length === 2 ? " + post-rewrite" : ""})`
17964
18379
  )
17965
18380
  );
17966
18381
  if (existing > 0) {
17967
- console.log(import_picocolors4.default.dim(` (${existing} hook file(s) already contained the Qodewk marker)`));
18382
+ console.log(import_picocolors5.default.dim(` (${existing} hook file(s) already contained the Qodewk marker)`));
17968
18383
  }
17969
18384
  } catch (err) {
17970
18385
  const message = err instanceof Error ? err.message : String(err);
17971
- console.error(import_picocolors4.default.red(`Failed to install Git hook: ${message}`));
18386
+ console.error(import_picocolors5.default.red(`Failed to install Git hook: ${message}`));
17972
18387
  process.exit(1);
17973
18388
  }
17974
18389
  });
@@ -17976,23 +18391,23 @@ hookCommand.command("uninstall").description("Remove Qodewk post-commit and post
17976
18391
  try {
17977
18392
  const hooksDir = resolveGitHooksDir();
17978
18393
  if (!hooksDir) {
17979
- console.log(import_picocolors4.default.yellow("No Git repository found."));
18394
+ console.log(import_picocolors5.default.yellow("No Git repository found."));
17980
18395
  return;
17981
18396
  }
17982
18397
  const targets = ["post-commit", "post-rewrite"];
17983
18398
  let removed = 0;
17984
18399
  for (const name of targets) {
17985
- const result = uninstallHookFile(path16.join(hooksDir, name));
18400
+ const result = uninstallHookFile(path17.join(hooksDir, name));
17986
18401
  if (result === "removed") removed++;
17987
18402
  }
17988
18403
  if (removed === 0) {
17989
- console.log(import_picocolors4.default.yellow("Qodewk hooks are not installed."));
18404
+ console.log(import_picocolors5.default.yellow("Qodewk hooks are not installed."));
17990
18405
  return;
17991
18406
  }
17992
- console.log(import_picocolors4.default.green(`\u2713 Qodewk hook markers removed from ${removed} file(s).`));
18407
+ console.log(import_picocolors5.default.green(`\u2713 Qodewk hook markers removed from ${removed} file(s).`));
17993
18408
  } catch (err) {
17994
18409
  const message = err instanceof Error ? err.message : String(err);
17995
- console.error(import_picocolors4.default.red(`Failed to uninstall hook: ${message}`));
18410
+ console.error(import_picocolors5.default.red(`Failed to uninstall hook: ${message}`));
17996
18411
  process.exit(1);
17997
18412
  }
17998
18413
  });
@@ -18011,7 +18426,7 @@ hookCommand.command("test").aliases(["verify", "check"]).description("Verify non
18011
18426
  }
18012
18427
  } catch (err) {
18013
18428
  const message = err instanceof Error ? err.message : String(err);
18014
- console.error(import_picocolors4.default.red(`Error testing hooks: ${message}`));
18429
+ console.error(import_picocolors5.default.red(`Error testing hooks: ${message}`));
18015
18430
  process.exit(1);
18016
18431
  }
18017
18432
  });
@@ -18020,7 +18435,7 @@ notesCmd.command("show [commit]").description("Display Qodewk receipt attached t
18020
18435
  try {
18021
18436
  const receipt = await readGitReceiptNote(commit);
18022
18437
  if (!receipt) {
18023
- console.log(import_picocolors4.default.yellow(`No Qodewk receipt note found on commit '${commit}'.`));
18438
+ console.log(import_picocolors5.default.yellow(`No Qodewk receipt note found on commit '${commit}'.`));
18024
18439
  return;
18025
18440
  }
18026
18441
  if (opts.json) {
@@ -18030,7 +18445,7 @@ notesCmd.command("show [commit]").description("Display Qodewk receipt attached t
18030
18445
  }
18031
18446
  } catch (err) {
18032
18447
  const message = err instanceof Error ? err.message : String(err);
18033
- console.error(import_picocolors4.default.red(`Error reading Git note: ${message}`));
18448
+ console.error(import_picocolors5.default.red(`Error reading Git note: ${message}`));
18034
18449
  process.exit(1);
18035
18450
  }
18036
18451
  });
@@ -18039,11 +18454,11 @@ notesCmd.command("write [commit]").description("Generate and attach receipt to a
18039
18454
  const receipt = await generateReceipt({ headSha: commit });
18040
18455
  await writeGitReceiptNote(receipt.repository.headSha, receipt);
18041
18456
  console.log(
18042
- import_picocolors4.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`)
18457
+ import_picocolors5.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`)
18043
18458
  );
18044
18459
  } catch (err) {
18045
18460
  const message = err instanceof Error ? err.message : String(err);
18046
- console.error(import_picocolors4.default.red(`Error writing Git note: ${message}`));
18461
+ console.error(import_picocolors5.default.red(`Error writing Git note: ${message}`));
18047
18462
  process.exit(1);
18048
18463
  }
18049
18464
  });
@@ -18051,16 +18466,16 @@ notesCmd.command("list").description("List all commits with attached Qodewk rece
18051
18466
  try {
18052
18467
  const shas = await listGitReceiptNotes();
18053
18468
  if (shas.length === 0) {
18054
- console.log(import_picocolors4.default.yellow("No Qodewk Git notes found in repository."));
18469
+ console.log(import_picocolors5.default.yellow("No Qodewk Git notes found in repository."));
18055
18470
  return;
18056
18471
  }
18057
- console.log(import_picocolors4.default.bold(`Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
18472
+ console.log(import_picocolors5.default.bold(`Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
18058
18473
  for (const sha of shas) {
18059
- console.log(` ${import_picocolors4.default.cyan(sha.slice(0, 10))} ${import_picocolors4.default.dim(sha)}`);
18474
+ console.log(` ${import_picocolors5.default.cyan(sha.slice(0, 10))} ${import_picocolors5.default.dim(sha)}`);
18060
18475
  }
18061
18476
  } catch (err) {
18062
18477
  const message = err instanceof Error ? err.message : String(err);
18063
- console.error(import_picocolors4.default.red(`Error listing Git notes: ${message}`));
18478
+ console.error(import_picocolors5.default.red(`Error listing Git notes: ${message}`));
18064
18479
  process.exit(1);
18065
18480
  }
18066
18481
  });