qodewk 0.10.1 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.cjs +617 -353
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1157,8 +1157,8 @@ 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");
1161
- var fs16 = require("fs");
1160
+ var path18 = require("path");
1161
+ var fs17 = require("fs");
1162
1162
  var process3 = require("process");
1163
1163
  var { Argument: Argument2, humanReadableArgName } = require_argument();
1164
1164
  var { CommanderError: CommanderError2 } = require_error();
@@ -2139,7 +2139,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2139
2139
  * @param {string} subcommandName
2140
2140
  */
2141
2141
  _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
2142
- if (fs16.existsSync(executableFile)) return;
2142
+ if (fs17.existsSync(executableFile)) return;
2143
2143
  const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
2144
2144
  const executableMissing = `'${executableFile}' does not exist
2145
2145
  - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
@@ -2157,11 +2157,11 @@ 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);
2161
- if (fs16.existsSync(localBin)) return localBin;
2162
- if (sourceExt.includes(path17.extname(baseName))) return void 0;
2160
+ const localBin = path18.resolve(baseDir, baseName);
2161
+ if (fs17.existsSync(localBin)) return localBin;
2162
+ if (sourceExt.includes(path18.extname(baseName))) return void 0;
2163
2163
  const foundExt = sourceExt.find(
2164
- (ext) => fs16.existsSync(`${localBin}${ext}`)
2164
+ (ext) => fs17.existsSync(`${localBin}${ext}`)
2165
2165
  );
2166
2166
  if (foundExt) return `${localBin}${foundExt}`;
2167
2167
  return void 0;
@@ -2173,21 +2173,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
2173
2173
  if (this._scriptPath) {
2174
2174
  let resolvedScriptPath;
2175
2175
  try {
2176
- resolvedScriptPath = fs16.realpathSync(this._scriptPath);
2176
+ resolvedScriptPath = fs17.realpathSync(this._scriptPath);
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(resolve8, reject) {
6650
6650
  const callback = (err, result) => {
6651
6651
  if (err) {
6652
6652
  return reject(toError(err));
6653
6653
  }
6654
- resolve6(result);
6654
+ resolve8(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(
@@ -9318,8 +9318,8 @@ var init_esm = __esm({
9318
9318
  });
9319
9319
 
9320
9320
  // src/index.ts
9321
- var fs15 = __toESM(require("fs"), 1);
9322
- var path16 = __toESM(require("path"), 1);
9321
+ var fs16 = __toESM(require("fs"), 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",
@@ -14375,6 +14393,9 @@ function discoverAntigravityEnvironment() {
14375
14393
  return null;
14376
14394
  }
14377
14395
 
14396
+ // ../core/dist/harvester/index.js
14397
+ var path11 = __toESM(require("path"), 1);
14398
+
14378
14399
  // ../core/dist/harvester/antigravity.js
14379
14400
  var fs2 = __toESM(require("fs"), 1);
14380
14401
  var path3 = __toESM(require("path"), 1);
@@ -14383,7 +14404,8 @@ var import_node_module = require("module");
14383
14404
 
14384
14405
  // ../core/dist/harvester/scoring.js
14385
14406
  function normalizeFilePath(filePath, repoPath) {
14386
- let p2 = filePath.replace(/\\/g, "/").trim();
14407
+ let p2 = filePath.trim().replace(/^["']|["']$/g, "").replace(/\\/g, "/");
14408
+ p2 = p2.replace(/\/+/g, "/");
14387
14409
  p2 = p2.replace(/^file:\/\/\/?/, "");
14388
14410
  if (repoPath) {
14389
14411
  const normRepo = repoPath.replace(/\\/g, "/").replace(/\/$/, "");
@@ -15799,39 +15821,86 @@ function parseSinceOption2(since) {
15799
15821
  }
15800
15822
  return void 0;
15801
15823
  }
15802
- async function harvestUniversalFootprints(options) {
15803
- const parsedSince = parseSinceOption2(options.since);
15804
- const sinceDate = parsedSince ? new Date(parsedSince.getTime() - 24 * 60 * 60 * 1e3) : void 0;
15805
- const alias = options.projectAlias || "";
15806
- let allFootprints = [];
15807
- if (!options.platform || options.platform === "all" || options.platform === "antigravity") {
15808
- 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);
15809
15828
  allFootprints.push(...agFootprints);
15810
15829
  }
15811
- if (!options.platform || options.platform === "all" || options.platform === "claude") {
15812
- const claudeFootprints = harvestClaudeFootprints(options.repoPath, alias, sinceDate);
15830
+ if (!platform || platform === "all" || platform === "claude") {
15831
+ const claudeFootprints = harvestClaudeFootprints(repoPath, alias, sinceDate);
15813
15832
  allFootprints.push(...claudeFootprints);
15814
15833
  }
15815
- if (!options.platform || options.platform === "all" || options.platform === "cursor") {
15816
- const cursorFootprints = harvestCursorFootprints(options.repoPath, sinceDate);
15834
+ if (!platform || platform === "all" || platform === "cursor") {
15835
+ const cursorFootprints = harvestCursorFootprints(repoPath, sinceDate);
15817
15836
  allFootprints.push(...cursorFootprints);
15818
15837
  }
15819
- if (!options.platform || options.platform === "all" || options.platform === "aider") {
15820
- const aiderFootprints = harvestAiderFootprints(options.repoPath, sinceDate);
15838
+ if (!platform || platform === "all" || platform === "aider") {
15839
+ const aiderFootprints = harvestAiderFootprints(repoPath, sinceDate);
15821
15840
  allFootprints.push(...aiderFootprints);
15822
15841
  }
15823
- if (!options.platform || options.platform === "all" || options.platform === "windsurf") {
15824
- const windsurfFootprints = harvestWindsurfFootprints(options.repoPath, sinceDate);
15842
+ if (!platform || platform === "all" || platform === "windsurf") {
15843
+ const windsurfFootprints = harvestWindsurfFootprints(repoPath, sinceDate);
15825
15844
  allFootprints.push(...windsurfFootprints);
15826
15845
  }
15827
- if (!options.platform || options.platform === "all" || options.platform === "cline") {
15828
- const clineFootprints = harvestClineFootprints(options.repoPath, sinceDate);
15846
+ if (!platform || platform === "all" || platform === "cline") {
15847
+ const clineFootprints = harvestClineFootprints(repoPath, sinceDate);
15829
15848
  allFootprints.push(...clineFootprints);
15830
15849
  }
15831
- if (!options.platform || options.platform === "all" || options.platform === "opencode") {
15832
- const opencodeFootprints = harvestOpenCodeFootprints(options.repoPath, sinceDate);
15850
+ if (!platform || platform === "all" || platform === "opencode") {
15851
+ const opencodeFootprints = harvestOpenCodeFootprints(repoPath, sinceDate);
15833
15852
  allFootprints.push(...opencodeFootprints);
15834
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);
15835
15904
  if (options.gitContext?.commitMessage) {
15836
15905
  const trailerFps = harvestTrailerFootprints(options.repoPath, options.gitContext.commitMessage, options.gitContext.headSha, options.gitContext.commitDate);
15837
15906
  allFootprints.push(...trailerFps);
@@ -15958,15 +16027,15 @@ function estimateCost(options) {
15958
16027
 
15959
16028
  // ../core/dist/pricing-sync.js
15960
16029
  var fs10 = __toESM(require("fs"), 1);
15961
- var path11 = __toESM(require("path"), 1);
16030
+ var path12 = __toESM(require("path"), 1);
15962
16031
  var os10 = __toESM(require("os"), 1);
15963
16032
  async function syncDynamicPricing(options) {
15964
16033
  try {
15965
- const qodewkDir = path11.join(os10.homedir(), ".qodewk");
16034
+ const qodewkDir = path12.join(os10.homedir(), ".qodewk");
15966
16035
  if (!fs10.existsSync(qodewkDir)) {
15967
16036
  fs10.mkdirSync(qodewkDir, { recursive: true });
15968
16037
  }
15969
- const cacheFile = path11.join(qodewkDir, "pricing_registry_cache.json");
16038
+ const cacheFile = path12.join(qodewkDir, "pricing_registry_cache.json");
15970
16039
  const TTL_MS = 24 * 60 * 60 * 1e3;
15971
16040
  const now = Date.now();
15972
16041
  if (!options?.force && fs10.existsSync(cacheFile)) {
@@ -16001,7 +16070,7 @@ async function syncDynamicPricing(options) {
16001
16070
 
16002
16071
  // ../core/dist/env.js
16003
16072
  var fs11 = __toESM(require("fs"), 1);
16004
- var path12 = __toESM(require("path"), 1);
16073
+ var path13 = __toESM(require("path"), 1);
16005
16074
  var os11 = __toESM(require("os"), 1);
16006
16075
  var isEnvLoaded = false;
16007
16076
  function loadQodewkEnv(startDir = process.cwd()) {
@@ -16009,11 +16078,11 @@ function loadQodewkEnv(startDir = process.cwd()) {
16009
16078
  return;
16010
16079
  isEnvLoaded = true;
16011
16080
  const candidates = [
16012
- path12.join(startDir, ".env.local"),
16013
- path12.join(startDir, ".env"),
16014
- path12.join(startDir, "apps", "web", ".env.local"),
16015
- path12.join(startDir, "apps", "web", ".env"),
16016
- 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")
16017
16086
  ];
16018
16087
  for (const envPath of candidates) {
16019
16088
  if (!fs11.existsSync(envPath))
@@ -16089,7 +16158,7 @@ function formatMarkdownReceipt(receipt, publicUrl) {
16089
16158
 
16090
16159
  // ../core/dist/doctor.js
16091
16160
  var fs12 = __toESM(require("fs"), 1);
16092
- var path13 = __toESM(require("path"), 1);
16161
+ var path14 = __toESM(require("path"), 1);
16093
16162
  var os12 = __toESM(require("os"), 1);
16094
16163
  var import_node_child_process = require("child_process");
16095
16164
  var HOOK_MARKER_BEGIN = "# --- BEGIN QODEWK HOOK ---";
@@ -16097,7 +16166,7 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16097
16166
  const homedir12 = os12.homedir();
16098
16167
  const results = [];
16099
16168
  const agEnv = process.env.ANTIGRAVITY_APP_DATA_DIR;
16100
- const agHome = path13.join(homedir12, ".gemini", "antigravity");
16169
+ const agHome = path14.join(homedir12, ".gemini", "antigravity");
16101
16170
  const agPath = agEnv && fs12.existsSync(agEnv) ? agEnv : fs12.existsSync(agHome) ? agHome : void 0;
16102
16171
  results.push({
16103
16172
  id: "antigravity",
@@ -16106,7 +16175,7 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16106
16175
  path: agPath,
16107
16176
  details: agPath ? "Antigravity brain telemetry detected" : "No active session brain found"
16108
16177
  });
16109
- const claudeProjects = path13.join(homedir12, ".claude", "projects");
16178
+ const claudeProjects = path14.join(homedir12, ".claude", "projects");
16110
16179
  const claudeExists = fs12.existsSync(claudeProjects);
16111
16180
  results.push({
16112
16181
  id: "claude",
@@ -16117,15 +16186,15 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16117
16186
  });
16118
16187
  let cursorPath;
16119
16188
  if (process.platform === "win32") {
16120
- 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");
16121
16190
  if (fs12.existsSync(c3))
16122
16191
  cursorPath = c3;
16123
16192
  } else if (process.platform === "darwin") {
16124
- const c3 = path13.join(homedir12, "Library", "Application Support", "Cursor", "User", "workspaceStorage");
16193
+ const c3 = path14.join(homedir12, "Library", "Application Support", "Cursor", "User", "workspaceStorage");
16125
16194
  if (fs12.existsSync(c3))
16126
16195
  cursorPath = c3;
16127
16196
  } else {
16128
- const c3 = path13.join(homedir12, ".config", "Cursor", "User", "workspaceStorage");
16197
+ const c3 = path14.join(homedir12, ".config", "Cursor", "User", "workspaceStorage");
16129
16198
  if (fs12.existsSync(c3))
16130
16199
  cursorPath = c3;
16131
16200
  }
@@ -16138,15 +16207,15 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16138
16207
  });
16139
16208
  let windsurfPath;
16140
16209
  if (process.platform === "win32") {
16141
- 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");
16142
16211
  if (fs12.existsSync(w))
16143
16212
  windsurfPath = w;
16144
16213
  } else if (process.platform === "darwin") {
16145
- const w = path13.join(homedir12, "Library", "Application Support", "Windsurf", "User", "workspaceStorage");
16214
+ const w = path14.join(homedir12, "Library", "Application Support", "Windsurf", "User", "workspaceStorage");
16146
16215
  if (fs12.existsSync(w))
16147
16216
  windsurfPath = w;
16148
16217
  } else {
16149
- const w = path13.join(homedir12, ".config", "Windsurf", "User", "workspaceStorage");
16218
+ const w = path14.join(homedir12, ".config", "Windsurf", "User", "workspaceStorage");
16150
16219
  if (fs12.existsSync(w))
16151
16220
  windsurfPath = w;
16152
16221
  }
@@ -16158,16 +16227,16 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16158
16227
  details: windsurfPath ? "Cascade session workspace storage detected" : "Windsurf IDE storage not detected"
16159
16228
  });
16160
16229
  let clinePath;
16161
- const localCline = path13.join(repoPath, ".cline");
16162
- const localRoo = path13.join(repoPath, ".roo");
16230
+ const localCline = path14.join(repoPath, ".cline");
16231
+ const localRoo = path14.join(repoPath, ".roo");
16163
16232
  if (fs12.existsSync(localCline)) {
16164
16233
  clinePath = localCline;
16165
16234
  } else if (fs12.existsSync(localRoo)) {
16166
16235
  clinePath = localRoo;
16167
16236
  } else {
16168
- 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");
16169
- const clineExt = path13.join(appData, "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "tasks");
16170
- 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");
16171
16240
  if (fs12.existsSync(clineExt))
16172
16241
  clinePath = clineExt;
16173
16242
  else if (fs12.existsSync(rooExt))
@@ -16180,7 +16249,7 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16180
16249
  path: clinePath,
16181
16250
  details: clinePath ? "VS Code autonomous agent task storage detected" : "No active Cline or Roo Code tasks found"
16182
16251
  });
16183
- const aiderPath = path13.join(repoPath, ".aider.chat.history.md");
16252
+ const aiderPath = path14.join(repoPath, ".aider.chat.history.md");
16184
16253
  const aiderExists = fs12.existsSync(aiderPath);
16185
16254
  results.push({
16186
16255
  id: "aider",
@@ -16189,8 +16258,8 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16189
16258
  path: aiderExists ? aiderPath : void 0,
16190
16259
  details: aiderExists ? "Repository pairing transcript found" : "No repo-local .aider.chat.history.md found"
16191
16260
  });
16192
- const localOpenCode = path13.join(repoPath, ".opencode");
16193
- const homeOpenCode = path13.join(homedir12, ".opencode", "sessions");
16261
+ const localOpenCode = path14.join(repoPath, ".opencode");
16262
+ const homeOpenCode = path14.join(homedir12, ".opencode", "sessions");
16194
16263
  const opencodePath = fs12.existsSync(localOpenCode) ? localOpenCode : fs12.existsSync(homeOpenCode) ? homeOpenCode : void 0;
16195
16264
  results.push({
16196
16265
  id: "opencode",
@@ -16202,32 +16271,38 @@ function auditAgentEnvironments(repoPath = process.cwd()) {
16202
16271
  return results;
16203
16272
  }
16204
16273
  function resolveHooksDir(cwd = process.cwd()) {
16205
- const gitPath = path13.join(cwd, ".git");
16206
- if (!fs12.existsSync(gitPath))
16207
- 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
+ }
16208
16283
  try {
16209
16284
  const stat = fs12.statSync(gitPath);
16210
16285
  if (stat.isDirectory()) {
16211
- return path13.join(gitPath, "hooks");
16286
+ return path14.join(gitPath, "hooks");
16212
16287
  }
16213
16288
  const content = fs12.readFileSync(gitPath, "utf-8");
16214
16289
  const match = content.match(/gitdir:\s*(.+)/i);
16215
16290
  if (!match?.[1])
16216
16291
  return null;
16217
16292
  let gitDir = match[1].trim();
16218
- if (!path13.isAbsolute(gitDir)) {
16219
- gitDir = path13.resolve(cwd, gitDir);
16293
+ if (!path14.isAbsolute(gitDir)) {
16294
+ gitDir = path14.resolve(curr, gitDir);
16220
16295
  }
16221
- const commonFile = path13.join(gitDir, "commondir");
16296
+ const commonFile = path14.join(gitDir, "commondir");
16222
16297
  if (fs12.existsSync(commonFile)) {
16223
16298
  let common = fs12.readFileSync(commonFile, "utf-8").trim();
16224
- if (!path13.isAbsolute(common))
16225
- common = path13.resolve(gitDir, common);
16226
- return path13.join(common, "hooks");
16227
- } else if (path13.basename(path13.dirname(gitDir)) === "worktrees") {
16228
- 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");
16229
16304
  }
16230
- return path13.join(gitDir, "hooks");
16305
+ return path14.join(gitDir, "hooks");
16231
16306
  } catch {
16232
16307
  return null;
16233
16308
  }
@@ -16243,8 +16318,8 @@ function auditGitHooks(repoPath = process.cwd()) {
16243
16318
  markerFound: false
16244
16319
  };
16245
16320
  }
16246
- const postCommit = path13.join(hooksDir, "post-commit");
16247
- const postRewrite = path13.join(hooksDir, "post-rewrite");
16321
+ const postCommit = path14.join(hooksDir, "post-commit");
16322
+ const postRewrite = path14.join(hooksDir, "post-rewrite");
16248
16323
  const hasMarker = (filePath) => {
16249
16324
  if (!fs12.existsSync(filePath))
16250
16325
  return false;
@@ -16308,7 +16383,7 @@ async function benchmarkHookLatency(trials = 3) {
16308
16383
  }
16309
16384
  }
16310
16385
  function auditStorageHealth() {
16311
- const dbPath = path13.join(os12.homedir(), ".qodewk", "state.db");
16386
+ const dbPath = path14.join(os12.homedir(), ".qodewk", "state.db");
16312
16387
  try {
16313
16388
  const db = new LocalStateDB();
16314
16389
  const stats = db.getStats();
@@ -16335,7 +16410,7 @@ function auditStorageHealth() {
16335
16410
  }
16336
16411
  function auditPricingSync() {
16337
16412
  const modelsCount = Object.keys(RATE_CARDS).length;
16338
- const cachedJson = path13.join(os12.homedir(), ".qodewk", "pricing.json");
16413
+ const cachedJson = path14.join(os12.homedir(), ".qodewk", "pricing.json");
16339
16414
  const hasCached = fs12.existsSync(cachedJson);
16340
16415
  return {
16341
16416
  modelsLoaded: modelsCount,
@@ -16359,7 +16434,7 @@ async function runDiagnostics(options = {}) {
16359
16434
  }
16360
16435
  return {
16361
16436
  overallStatus,
16362
- version: "0.10.1",
16437
+ version: "0.11.1",
16363
16438
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
16364
16439
  repoPath,
16365
16440
  agents,
@@ -16422,14 +16497,17 @@ async function generateReceipt(options = {}) {
16422
16497
  const model = options.model || primaryFp?.model || detected?.model;
16423
16498
  const task = options.task || primaryFp?.taskTitle || (harvestResult.tasks.length > 0 ? harvestResult.tasks[0] : void 0);
16424
16499
  const sessions = harvestResult.footprints.map((fp) => ({
16500
+ sessionId: fp.sessionId,
16425
16501
  provider: fp.platform,
16426
16502
  model: fp.model,
16427
16503
  task: fp.taskTitle,
16428
16504
  filesTouched: fp.filesEdited,
16505
+ turnsCount: fp.stepsCount,
16429
16506
  tokens: fp.tokens,
16430
16507
  cost: fp.cost,
16431
16508
  confidence: fp.confidence,
16432
- mode: fp.mode
16509
+ mode: fp.mode,
16510
+ createdAt: fp.timestamp
16433
16511
  }));
16434
16512
  const aiWrittenRatio = computeAiWrittenRatio(metrics.changedFiles, harvestResult.filesEdited);
16435
16513
  const costResult = estimateCost({
@@ -16840,11 +16918,20 @@ function buildTerminalReceipt(receipt, publicUrl) {
16840
16918
  const provString = receipt.ai.provider + " \xB7 " + (receipt.ai.model || "Unknown");
16841
16919
  const cleanProv = provString.length > 40 ? provString.slice(0, 39) + "\u2026" : provString;
16842
16920
  printRow(`Provider: ${cleanProv}`);
16843
- if (receipt.ai.sessions && receipt.ai.sessions.length > 1) {
16844
- const others = receipt.ai.sessions.slice(1).map((s) => s.provider).filter((p2, i2, arr) => arr.indexOf(p2) === i2 && p2 !== receipt.ai.provider);
16845
- if (others.length > 0) {
16846
- 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));
16847
16930
  }
16931
+ if (receipt.ai.sessions.length > 5) {
16932
+ printRow(import_picocolors.default.dim(` ... and ${receipt.ai.sessions.length - 5} more sessions`));
16933
+ }
16934
+ printDivider("-");
16848
16935
  }
16849
16936
  if (receipt.ai.aiWrittenRatio !== void 0) {
16850
16937
  const aiPct = Math.round(receipt.ai.aiWrittenRatio * 100);
@@ -16929,7 +17016,7 @@ async function outputReceipt(receipt, options, publicUrl) {
16929
17016
 
16930
17017
  // src/hooks.ts
16931
17018
  var fs14 = __toESM(require("fs"), 1);
16932
- var path14 = __toESM(require("path"), 1);
17019
+ var path15 = __toESM(require("path"), 1);
16933
17020
  var HOOK_MARKER_BEGIN2 = "# --- BEGIN QODEWK HOOK ---";
16934
17021
  var HOOK_MARKER_END = "# --- END QODEWK HOOK ---";
16935
17022
  var HOOK_SNIPPET = `
@@ -16941,7 +17028,7 @@ fi
16941
17028
  ${HOOK_MARKER_END}
16942
17029
  `;
16943
17030
  function resolveGitHooksDir(cwd = process.cwd()) {
16944
- const gitPath = path14.join(cwd, ".git");
17031
+ const gitPath = path15.join(cwd, ".git");
16945
17032
  if (!fs14.existsSync(gitPath)) return null;
16946
17033
  let gitCommonDir;
16947
17034
  const stat = fs14.statSync(gitPath);
@@ -16952,23 +17039,23 @@ function resolveGitHooksDir(cwd = process.cwd()) {
16952
17039
  const match = content.match(/gitdir:\s*(.+)/i);
16953
17040
  if (!match?.[1]) return null;
16954
17041
  let gitDir = match[1].trim();
16955
- if (!path14.isAbsolute(gitDir)) {
16956
- gitDir = path14.resolve(cwd, gitDir);
17042
+ if (!path15.isAbsolute(gitDir)) {
17043
+ gitDir = path15.resolve(cwd, gitDir);
16957
17044
  }
16958
- const commonFile = path14.join(gitDir, "commondir");
17045
+ const commonFile = path15.join(gitDir, "commondir");
16959
17046
  if (fs14.existsSync(commonFile)) {
16960
17047
  let common = fs14.readFileSync(commonFile, "utf-8").trim();
16961
- if (!path14.isAbsolute(common)) {
16962
- common = path14.resolve(gitDir, common);
17048
+ if (!path15.isAbsolute(common)) {
17049
+ common = path15.resolve(gitDir, common);
16963
17050
  }
16964
17051
  gitCommonDir = common;
16965
- } else if (path14.basename(path14.dirname(gitDir)) === "worktrees") {
16966
- gitCommonDir = path14.dirname(path14.dirname(gitDir));
17052
+ } else if (path15.basename(path15.dirname(gitDir)) === "worktrees") {
17053
+ gitCommonDir = path15.dirname(path15.dirname(gitDir));
16967
17054
  } else {
16968
17055
  gitCommonDir = gitDir;
16969
17056
  }
16970
17057
  }
16971
- return path14.join(gitCommonDir, "hooks");
17058
+ return path15.join(gitCommonDir, "hooks");
16972
17059
  }
16973
17060
  function checkHookStatus(hooksDir) {
16974
17061
  if (!hooksDir || !fs14.existsSync(hooksDir)) {
@@ -16979,8 +17066,8 @@ function checkHookStatus(hooksDir) {
16979
17066
  postRewriteInstalled: false
16980
17067
  };
16981
17068
  }
16982
- const postCommit = path14.join(hooksDir, "post-commit");
16983
- const postRewrite = path14.join(hooksDir, "post-rewrite");
17069
+ const postCommit = path15.join(hooksDir, "post-commit");
17070
+ const postRewrite = path15.join(hooksDir, "post-rewrite");
16984
17071
  const hasHook = (p2) => {
16985
17072
  if (!fs14.existsSync(p2)) return false;
16986
17073
  try {
@@ -17022,8 +17109,9 @@ function uninstallHookFile(hookFile) {
17022
17109
 
17023
17110
  // src/menu.ts
17024
17111
  var readline = __toESM(require("readline"), 1);
17025
- var path15 = __toESM(require("path"), 1);
17026
- var import_picocolors3 = __toESM(require_picocolors(), 1);
17112
+ var path16 = __toESM(require("path"), 1);
17113
+ var fs15 = __toESM(require("fs"), 1);
17114
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
17027
17115
 
17028
17116
  // src/doctor-view.ts
17029
17117
  var import_picocolors2 = __toESM(require_picocolors(), 1);
@@ -17110,6 +17198,98 @@ function formatHookTestReport(hooks, benchmark) {
17110
17198
  return lines.join("\n");
17111
17199
  }
17112
17200
 
17201
+ // src/chat-view.ts
17202
+ var import_picocolors3 = __toESM(require_picocolors(), 1);
17203
+ function buildTerminalChatLedger(report) {
17204
+ const lines = [];
17205
+ const coral = colors.coral;
17206
+ const teal = colors.teal;
17207
+ const green = colors.green;
17208
+ const INNER_WIDTH = 68;
17209
+ const push = (line) => lines.push(line);
17210
+ const printRow = (content, width = INNER_WIDTH) => {
17211
+ const visLen = visibleWidth(content);
17212
+ const pad = Math.max(0, width - visLen);
17213
+ push(` | ${content}${" ".repeat(pad)} |`);
17214
+ };
17215
+ const printRowSplit = (left, right, width = INNER_WIDTH) => {
17216
+ const leftVis = visibleWidth(left);
17217
+ const rightVis = visibleWidth(right);
17218
+ const pad = Math.max(1, width - leftVis - rightVis);
17219
+ push(` | ${left}${" ".repeat(pad)}${right} |`);
17220
+ };
17221
+ const printCenteredRow = (content, width = INNER_WIDTH) => {
17222
+ const visLen = visibleWidth(content);
17223
+ const totalPad = Math.max(0, width - visLen);
17224
+ const leftPad = Math.floor(totalPad / 2);
17225
+ const rightPad = totalPad - leftPad;
17226
+ push(` | ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} |`);
17227
+ };
17228
+ const printDivider = (char = "=", width = INNER_WIDTH) => {
17229
+ push(` | ${char.repeat(width)} |`);
17230
+ };
17231
+ push("");
17232
+ push(" " + import_picocolors3.default.bold(coral("/\\".repeat(36))));
17233
+ printCenteredRow(import_picocolors3.default.bold(import_picocolors3.default.white("Q O D E W K")));
17234
+ printCenteredRow(coral("*** WORKSPACE CHAT TELEMETRY LEDGER ***"));
17235
+ printRow("");
17236
+ printRowSplit(
17237
+ `REPO: ${report.projectAlias.slice(0, 24)}`,
17238
+ `WINDOW: ${report.windowDescription}`
17239
+ );
17240
+ printRowSplit(
17241
+ `CHATS: ${report.sessionsCount} sessions`,
17242
+ `STEPS: ${report.totalSteps.toLocaleString()} steps`
17243
+ );
17244
+ printDivider("=");
17245
+ if (report.chats.length === 0) {
17246
+ printCenteredRow(import_picocolors3.default.dim("No agent chat sessions found in this workspace window."));
17247
+ printRow("");
17248
+ } else {
17249
+ const colTask = "CHAT / TASK".padEnd(28);
17250
+ const colModel = "MODEL".padEnd(18);
17251
+ const colTok = "TOKENS".padStart(8);
17252
+ const colCost = "COST".padStart(10);
17253
+ printRow(`${colTask} ${colModel} ${colTok} ${colCost}`);
17254
+ printDivider("-");
17255
+ for (const chat of report.chats) {
17256
+ const cleanTitle = (chat.taskTitle || chat.sessionId || "Untitled Session").replace(/\n/g, " ").trim();
17257
+ const taskDisplay = (cleanTitle.length > 27 ? cleanTitle.slice(0, 26) + "\u2026" : cleanTitle).padEnd(28);
17258
+ const cleanModel = (chat.model || chat.platform || "default").replace(/^(claude-|gemini-|gpt-)/, "").slice(0, 17);
17259
+ const modelDisplay = cleanModel.padEnd(18);
17260
+ const tokK = `${Math.round((chat.tokens.input + chat.tokens.output) / 1e3)}k`.padStart(8);
17261
+ const costStr = (chat.mode === "verified" ? `$${chat.cost.toFixed(2)}` : `~$${chat.cost.toFixed(2)}`).padStart(10);
17262
+ printRow(`${taskDisplay} ${import_picocolors3.default.dim(modelDisplay)} ${teal(tokK)} ${coral(costStr)}`);
17263
+ }
17264
+ }
17265
+ printDivider("=");
17266
+ const totalTokK = `${Math.round((report.totalTokens.input + report.totalTokens.output) / 1e3)}k tokens`;
17267
+ printRowSplit("TOTAL ESTIMATED TOKENS:", green(totalTokK));
17268
+ printRowSplit("TOTAL ESTIMATED SPEND:", import_picocolors3.default.bold(coral(`~$${report.totalCost.toFixed(2)}`)));
17269
+ printDivider("=");
17270
+ printCenteredRow(import_picocolors3.default.dim("[\u2713] Zero code exfiltration \xB7 Telemetry calculated locally"));
17271
+ push(" " + import_picocolors3.default.bold(coral("\\/".repeat(36))));
17272
+ push("");
17273
+ return lines.join("\n");
17274
+ }
17275
+ function buildMarkdownChatLedger(report) {
17276
+ const lines = [];
17277
+ lines.push(`### \u{1F916} Qodewk Workspace Chat Telemetry Ledger`);
17278
+ lines.push(`**Repository:** \`${report.projectAlias}\` | **Window:** ${report.windowDescription} | **Total Spend:** \`~$${report.totalCost.toFixed(2)}\``);
17279
+ lines.push("");
17280
+ lines.push("| Chat / Task | Platform | Model | Steps | Tokens | Cost |");
17281
+ lines.push("| :--- | :--- | :--- | :--- | :--- | :--- |");
17282
+ for (const chat of report.chats) {
17283
+ const title = (chat.taskTitle || chat.sessionId).replace(/\|/g, "\\|").trim();
17284
+ const tokensK = `${Math.round((chat.tokens.input + chat.tokens.output) / 1e3)}k`;
17285
+ const cost = chat.mode === "verified" ? `$${chat.cost.toFixed(2)}` : `~$${chat.cost.toFixed(2)}`;
17286
+ lines.push(`| ${title} | \`${chat.platform}\` | \`${chat.model}\` | ${chat.stepsCount} | ${tokensK} | ${cost} |`);
17287
+ }
17288
+ lines.push("");
17289
+ lines.push(`*Total Sessions: ${report.sessionsCount} \xB7 Total Steps: ${report.totalSteps.toLocaleString()}*`);
17290
+ return lines.join("\n");
17291
+ }
17292
+
17113
17293
  // src/menu.ts
17114
17294
  var SHARE_PAYLOAD_MAX_BYTES = 5e4;
17115
17295
  var BANNER_LINES = [
@@ -17163,6 +17343,12 @@ var MENU_ITEMS = [
17163
17343
  label: "System Health & Diagnostics",
17164
17344
  description: "Audit AI agents, Git hooks, SQLite & pricing registry (doctor)"
17165
17345
  },
17346
+ {
17347
+ id: "chats",
17348
+ key: "8",
17349
+ label: "Workspace Chats & Cost Ledger",
17350
+ description: "Inspect all agent conversation sessions and model costs (chats)"
17351
+ },
17166
17352
  {
17167
17353
  id: "exit",
17168
17354
  key: "0",
@@ -17246,9 +17432,36 @@ var SHARE_HORIZON_ITEMS = [
17246
17432
  description: "Return to previous screen"
17247
17433
  }
17248
17434
  ];
17249
- 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 = {}) {
17435
+ function resolveMenuCliVersion() {
17436
+ try {
17437
+ const argv1 = process.argv[1] ? path16.dirname(path16.resolve(process.argv[1])) : process.cwd();
17438
+ const candidates = [
17439
+ path16.join(argv1, "..", "package.json"),
17440
+ path16.join(argv1, "package.json")
17441
+ ];
17442
+ for (const candidate of candidates) {
17443
+ if (!fs15.existsSync(candidate)) continue;
17444
+ const pkg = JSON.parse(fs15.readFileSync(candidate, "utf-8"));
17445
+ if (pkg.name === "qodewk" && pkg.version) return pkg.version;
17446
+ }
17447
+ } catch {
17448
+ }
17449
+ return "0.11.1";
17450
+ }
17451
+ function computeMenuSubtitle(items, isSubmenu = false) {
17452
+ const numericKeys = items.map((item) => parseInt(item.key, 10)).filter((n) => !isNaN(n) && n > 0);
17453
+ const hasZero = items.some((item) => item.key === "0");
17454
+ const maxKey = numericKeys.length > 0 ? Math.max(...numericKeys) : 0;
17455
+ const jumpText = hasZero && maxKey > 0 ? `0-${maxKey} quick jump` : maxKey > 0 ? `1-${maxKey} quick jump` : "enter select";
17456
+ if (isSubmenu) {
17457
+ return `\u2191\u2193 move \xB7 enter select \xB7 ${jumpText} \xB7 esc / 0 back`;
17458
+ }
17459
+ return `\u2191\u2193 move \xB7 enter select \xB7 ${jumpText} \xB7 q quit`;
17460
+ }
17461
+ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Control Panel", subtitle, options = {}) {
17250
17462
  const lines = [];
17251
17463
  const push = (line) => lines.push(line);
17464
+ const effectiveSubtitle = subtitle ?? computeMenuSubtitle(items, items !== MENU_ITEMS);
17252
17465
  if (options.showBanner ?? true) {
17253
17466
  push("");
17254
17467
  for (let i2 = 0; i2 < BANNER_LINES.length; i2++) {
@@ -17257,16 +17470,17 @@ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Co
17257
17470
  }
17258
17471
  }
17259
17472
  push("");
17260
- const badge = bg.teal(import_picocolors3.default.bold(colors.ink(" qodewk ")));
17261
- push(` ${colors.mutedSoft("\u250C")} ${badge} ${import_picocolors3.default.dim("v0.10.1")}`);
17473
+ const badge = bg.teal(import_picocolors4.default.bold(colors.ink(" qodewk ")));
17474
+ const cliVer = resolveMenuCliVersion();
17475
+ push(` ${colors.mutedSoft("\u250C")} ${badge} ${import_picocolors4.default.dim(`v${cliVer}`)}`);
17262
17476
  push(` ${colors.mutedSoft("\u2502")}`);
17263
17477
  if (options.actionContext) {
17264
- push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Action:")} ${import_picocolors3.default.white(options.actionContext)}`);
17478
+ push(` ${colors.teal("\u25C7")} ${import_picocolors4.default.dim("Action:")} ${import_picocolors4.default.white(options.actionContext)}`);
17265
17479
  push(` ${colors.mutedSoft("\u2502")}`);
17266
17480
  } else {
17267
17481
  const repo = options.repoContext?.alias || "Qodewk";
17268
17482
  const branch = options.repoContext?.branch ? `(${options.repoContext.branch})` : "";
17269
- push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Repository:")} ${import_picocolors3.default.white(repo)} ${import_picocolors3.default.dim(branch)}`);
17483
+ push(` ${colors.teal("\u25C7")} ${import_picocolors4.default.dim("Repository:")} ${import_picocolors4.default.white(repo)} ${import_picocolors4.default.dim(branch)}`);
17270
17484
  push(` ${colors.mutedSoft("\u2502")}`);
17271
17485
  let telemetryLabel = "Multi-Model Rate Cards (Active)";
17272
17486
  try {
@@ -17278,10 +17492,10 @@ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Co
17278
17492
  }
17279
17493
  } catch {
17280
17494
  }
17281
- push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Telemetry:")} ${import_picocolors3.default.white(telemetryLabel)}`);
17495
+ push(` ${colors.teal("\u25C7")} ${import_picocolors4.default.dim("Telemetry:")} ${import_picocolors4.default.white(telemetryLabel)}`);
17282
17496
  push(` ${colors.mutedSoft("\u2502")}`);
17283
17497
  }
17284
- push(` ${colors.coral("\u25C6")} ${import_picocolors3.default.bold(import_picocolors3.default.white(title))}`);
17498
+ push(` ${colors.coral("\u25C6")} ${import_picocolors4.default.bold(import_picocolors4.default.white(title))}`);
17285
17499
  push(` ${colors.mutedSoft("\u2502")}`);
17286
17500
  const selectedItem = items[selectedIndex] || items[0];
17287
17501
  for (let i2 = 0; i2 < items.length; i2++) {
@@ -17289,62 +17503,67 @@ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Co
17289
17503
  const isSelected = i2 === selectedIndex;
17290
17504
  if (isSelected) {
17291
17505
  push(
17292
- ` ${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))}`
17506
+ ` ${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))}`
17293
17507
  );
17294
17508
  } else {
17295
17509
  push(
17296
- ` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.dim(item.key)} ${import_picocolors3.default.dim(import_picocolors3.default.white(item.label))}`
17510
+ ` ${colors.mutedSoft("\u2502")} ${import_picocolors4.default.dim(item.key)} ${import_picocolors4.default.dim(import_picocolors4.default.white(item.label))}`
17297
17511
  );
17298
17512
  }
17299
17513
  }
17300
17514
  const divider = colors.mutedSoft("\u2500".repeat(58));
17301
17515
  push(` ${colors.mutedSoft("\u2502")}`);
17302
17516
  push(` ${colors.mutedSoft("\u2502")} ${divider}`);
17303
- push(` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.bold(import_picocolors3.default.dim("Description"))}`);
17517
+ push(` ${colors.mutedSoft("\u2502")} ${import_picocolors4.default.bold(import_picocolors4.default.dim("Description"))}`);
17304
17518
  push(` ${colors.mutedSoft("\u2502")} ${colors.amber(selectedItem.description)}`);
17305
17519
  push(` ${colors.mutedSoft("\u2502")} ${divider}`);
17306
17520
  push(` ${colors.mutedSoft("\u2502")}`);
17307
- push(` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.dim(subtitle)}`);
17308
- push(` ${colors.mutedSoft("\u2502")} ${colors.green("[\u2713]")} ${import_picocolors3.default.dim("Source code was never uploaded to Qodewk")}`);
17521
+ push(` ${colors.mutedSoft("\u2502")} ${import_picocolors4.default.dim(effectiveSubtitle)}`);
17522
+ push(` ${colors.mutedSoft("\u2502")} ${colors.green("[\u2713]")} ${import_picocolors4.default.dim("Source code was never uploaded to Qodewk")}`);
17309
17523
  push(` ${colors.mutedSoft("\u2514")}`);
17310
17524
  push("");
17311
17525
  return lines.join("\n");
17312
17526
  }
17313
17527
  function askLine(promptText) {
17314
- return new Promise((resolve6) => {
17528
+ return new Promise((resolve8) => {
17315
17529
  const rl = readline.createInterface({
17316
17530
  input: process.stdin,
17317
17531
  output: process.stdout
17318
17532
  });
17319
17533
  rl.question(promptText, (answer) => {
17320
17534
  rl.close();
17321
- resolve6(answer.trim());
17535
+ resolve8(answer.trim());
17322
17536
  });
17323
17537
  });
17324
17538
  }
17325
17539
  function waitForKeyToReturn() {
17326
- return new Promise((resolve6) => {
17327
- console.log(import_picocolors3.default.dim("\n Press any key or Enter to return to menu..."));
17540
+ return new Promise((resolve8) => {
17541
+ console.log(import_picocolors4.default.dim("\n Press any key or Enter to return to menu..."));
17328
17542
  if (!process.stdin.isTTY) {
17329
- resolve6();
17543
+ resolve8();
17330
17544
  return;
17331
17545
  }
17332
17546
  const wasRaw = process.stdin.isRaw;
17333
17547
  process.stdin.setRawMode(true);
17334
17548
  process.stdin.resume();
17335
- const onKey = () => {
17549
+ const onKey = (data) => {
17336
17550
  process.stdin.removeListener("data", onKey);
17337
17551
  if (wasRaw !== void 0) process.stdin.setRawMode(wasRaw);
17338
- resolve6();
17552
+ if (data && (data[0] === 3 || data.toString() === "")) {
17553
+ process.stdout.write("\x1B[?25h");
17554
+ console.log(import_picocolors4.default.dim("\n Exited Qodewk.\n"));
17555
+ process.exit(0);
17556
+ }
17557
+ resolve8();
17339
17558
  };
17340
17559
  process.stdin.once("data", onKey);
17341
17560
  });
17342
17561
  }
17343
17562
  function waitForKeyOrAction(promptText) {
17344
- return new Promise((resolve6) => {
17563
+ return new Promise((resolve8) => {
17345
17564
  console.log(promptText);
17346
17565
  if (!process.stdin.isTTY) {
17347
- resolve6("");
17566
+ resolve8("");
17348
17567
  return;
17349
17568
  }
17350
17569
  const wasRaw = process.stdin.isRaw;
@@ -17354,14 +17573,19 @@ function waitForKeyOrAction(promptText) {
17354
17573
  process.stdin.removeListener("data", onKey);
17355
17574
  if (wasRaw !== void 0) process.stdin.setRawMode(wasRaw);
17356
17575
  const str = data.toString();
17357
- resolve6(str);
17576
+ if (data[0] === 3 || str === "") {
17577
+ process.stdout.write("\x1B[?25h");
17578
+ console.log(import_picocolors4.default.dim("\n Exited Qodewk.\n"));
17579
+ process.exit(0);
17580
+ }
17581
+ resolve8(str);
17358
17582
  };
17359
17583
  process.stdin.once("data", onKey);
17360
17584
  });
17361
17585
  }
17362
17586
  async function publishReceiptToCloud(receipt) {
17363
17587
  if (process.env.QODEWK_TELEMETRY === "off") {
17364
- console.log(import_picocolors3.default.yellow("\n Cloud publishing is disabled by QODEWK_TELEMETRY=off."));
17588
+ console.log(import_picocolors4.default.yellow("\n Cloud publishing is disabled by QODEWK_TELEMETRY=off."));
17365
17589
  return null;
17366
17590
  }
17367
17591
  const sanitized = sanitizeReceiptForShare(receipt);
@@ -17374,11 +17598,11 @@ async function publishReceiptToCloud(receipt) {
17374
17598
  body = JSON.stringify(trimmed2);
17375
17599
  }
17376
17600
  if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES) {
17377
- console.error(import_picocolors3.default.red(" Sanitized receipt still exceeds the 50 KB cloud payload limit."));
17601
+ console.error(import_picocolors4.default.red(" Sanitized receipt still exceeds the 50 KB cloud payload limit."));
17378
17602
  return null;
17379
17603
  }
17380
17604
  const endpoint = resolveApiUrl();
17381
- console.log(import_picocolors3.default.dim(`
17605
+ console.log(import_picocolors4.default.dim(`
17382
17606
  [\xB7] Publishing receipt to ${endpoint}...`));
17383
17607
  try {
17384
17608
  const response = await fetch(endpoint, {
@@ -17392,11 +17616,11 @@ async function publishReceiptToCloud(receipt) {
17392
17616
  if (!response.ok) {
17393
17617
  const errText = await response.text().catch(() => "");
17394
17618
  if (response.status === 503) {
17395
- console.log(import_picocolors3.default.yellow("\n Notice: Remote server requires durable storage (Supabase or PostgreSQL) in production"));
17396
- console.log(import_picocolors3.default.dim(" to protect receipts from serverless cold-start data loss."));
17397
- console.log(import_picocolors3.default.dim(` Endpoint: ${endpoint}`));
17619
+ console.log(import_picocolors4.default.yellow("\n Notice: Remote server requires durable storage (Supabase or PostgreSQL) in production"));
17620
+ console.log(import_picocolors4.default.dim(" to protect receipts from serverless cold-start data loss."));
17621
+ console.log(import_picocolors4.default.dim(` Endpoint: ${endpoint}`));
17398
17622
  console.log(colors.green("\n [\u2713] Your receipt is safely saved locally in: ~/.qodewk/state.db"));
17399
- console.log(import_picocolors3.default.dim(" You can also save it as a local Git note: qodewk --notes\n"));
17623
+ console.log(import_picocolors4.default.dim(" You can also save it as a local Git note: qodewk --notes\n"));
17400
17624
  return null;
17401
17625
  }
17402
17626
  throw new Error(`API responded with ${response.status}: ${errText.slice(0, 100)}`);
@@ -17407,14 +17631,14 @@ async function publishReceiptToCloud(receipt) {
17407
17631
  db.close();
17408
17632
  console.log("");
17409
17633
  console.log(colors.green(" [\u2713] Published successfully."));
17410
- console.log(` ${import_picocolors3.default.dim("Public URL:")} ${import_picocolors3.default.underline(import_picocolors3.default.cyan(data.url))}`);
17411
- console.log(` ${import_picocolors3.default.bold(colors.amber("Claim token:"))} ${colors.amber(data.claimToken)}`);
17412
- console.log(import_picocolors3.default.dim(" (Saved to ~/.qodewk/state.db for future authorship proofs)\n"));
17634
+ console.log(` ${import_picocolors4.default.dim("Public URL:")} ${import_picocolors4.default.underline(import_picocolors4.default.cyan(data.url))}`);
17635
+ console.log(` ${import_picocolors4.default.bold(colors.amber("Claim token:"))} ${colors.amber(data.claimToken)}`);
17636
+ console.log(import_picocolors4.default.dim(" (Saved to ~/.qodewk/state.db for future authorship proofs)\n"));
17413
17637
  await renderTerminalReceipt(sanitized, data.url);
17414
17638
  return data;
17415
17639
  } catch (err) {
17416
17640
  const message = err instanceof Error ? err.message : String(err);
17417
- console.error(import_picocolors3.default.red(`
17641
+ console.error(import_picocolors4.default.red(`
17418
17642
  Share failed: ${message}`));
17419
17643
  return null;
17420
17644
  }
@@ -17432,7 +17656,7 @@ async function getRepoContext() {
17432
17656
  }
17433
17657
  const branchSummary = await git.branch();
17434
17658
  const branch = branchSummary.current || "HEAD";
17435
- const alias = path15.basename(process.cwd());
17659
+ const alias = path16.basename(process.cwd());
17436
17660
  cachedRepoContext = { alias, branch };
17437
17661
  return cachedRepoContext;
17438
17662
  } catch {
@@ -17443,12 +17667,13 @@ async function getRepoContext() {
17443
17667
  async function runInteractiveMenu() {
17444
17668
  if (!process.stdin.isTTY) {
17445
17669
  console.log(buildMenuFrame(0));
17446
- console.log(import_picocolors3.default.yellow("Interactive menu requires a TTY terminal. Use `qodewk --help` for commands."));
17670
+ console.log(import_picocolors4.default.yellow("Interactive menu requires a TTY terminal. Use `qodewk --help` for commands."));
17447
17671
  return;
17448
17672
  }
17449
17673
  const repoContext = await getRepoContext();
17450
17674
  let currentScreen = "main";
17451
17675
  let selectedIndex = 0;
17676
+ let savedMainIndex = 0;
17452
17677
  let active = true;
17453
17678
  let lastRenderedLinesCount = 0;
17454
17679
  const getActiveItems = () => {
@@ -17459,7 +17684,7 @@ async function runInteractiveMenu() {
17459
17684
  const render = () => {
17460
17685
  const items = getActiveItems();
17461
17686
  const title = currentScreen === "main" ? "Telemetry Control Panel" : currentScreen === "receipt_horizon" ? "Generate Local Receipt" : "Publish Receipt to Cloud";
17462
- 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";
17687
+ const subtitle = computeMenuSubtitle(items, currentScreen !== "main");
17463
17688
  const actionContext = currentScreen === "receipt_horizon" ? "Generate Local Receipt" : currentScreen === "share_horizon" ? "Publish Receipt to Cloud" : void 0;
17464
17689
  const showBanner = currentScreen === "main";
17465
17690
  const frame = buildMenuFrame(selectedIndex, items, title, subtitle, {
@@ -17500,15 +17725,15 @@ async function runInteractiveMenu() {
17500
17725
  since = "7d";
17501
17726
  label = "past 7 days weekly sprint (--since 7d)";
17502
17727
  } else if (item.id === "custom") {
17503
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white(" Custom Telemetry Horizon")));
17504
- 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"));
17728
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white(" Custom Telemetry Horizon")));
17729
+ 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"));
17505
17730
  const input = await askLine(" \u203A Enter duration or date (e.g. 12h, 3d, 2026-10-01): ");
17506
17731
  if (input) {
17507
17732
  since = input;
17508
17733
  label = `custom range: ${input}`;
17509
17734
  }
17510
17735
  }
17511
- console.log(import_picocolors3.default.dim(` [\xB7] Generating local receipt for ${label}...`));
17736
+ console.log(import_picocolors4.default.dim(` [\xB7] Generating local receipt for ${label}...`));
17512
17737
  try {
17513
17738
  const receipt = await generateReceipt({ since, isPublic: false });
17514
17739
  const db = new LocalStateDB();
@@ -17517,7 +17742,7 @@ async function runInteractiveMenu() {
17517
17742
  await renderTerminalReceipt(receipt);
17518
17743
  console.log("");
17519
17744
  const actionKey = await waitForKeyOrAction(
17520
- ` ${colors.coral("[s]")} ${import_picocolors3.default.white("Publish this receipt to cloud")} \xB7 ${import_picocolors3.default.dim("[any other key] Return to menu")}`
17745
+ ` ${colors.coral("[s]")} ${import_picocolors4.default.white("Publish this receipt to cloud")} \xB7 ${import_picocolors4.default.dim("[any other key] Return to menu")}`
17521
17746
  );
17522
17747
  if (actionKey.trim().toLowerCase() === "s") {
17523
17748
  await publishReceiptToCloud(receipt);
@@ -17525,12 +17750,12 @@ async function runInteractiveMenu() {
17525
17750
  }
17526
17751
  } catch (err) {
17527
17752
  const message = err instanceof Error ? err.message : String(err);
17528
- console.error(import_picocolors3.default.red(`
17753
+ console.error(import_picocolors4.default.red(`
17529
17754
  Failed to generate receipt: ${message}`));
17530
17755
  await waitForKeyToReturn();
17531
17756
  }
17532
17757
  currentScreen = "main";
17533
- selectedIndex = 0;
17758
+ selectedIndex = savedMainIndex;
17534
17759
  };
17535
17760
  const executeShareHorizon = async (item) => {
17536
17761
  cleanup();
@@ -17548,26 +17773,26 @@ async function runInteractiveMenu() {
17548
17773
  since = "7d";
17549
17774
  label = "past 7 days weekly sprint (--since 7d)";
17550
17775
  } else if (item.id === "custom") {
17551
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white(" Custom Telemetry Horizon for Cloud Publish")));
17552
- 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"));
17776
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white(" Custom Telemetry Horizon for Cloud Publish")));
17777
+ 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"));
17553
17778
  const input = await askLine(" \u203A Enter duration or date (e.g. 12h, 3d, 2026-10-01): ");
17554
17779
  if (input) {
17555
17780
  since = input;
17556
17781
  label = `custom range: ${input}`;
17557
17782
  }
17558
17783
  }
17559
- console.log(import_picocolors3.default.dim(` [\xB7] Generating and publishing receipt for ${label}...`));
17784
+ console.log(import_picocolors4.default.dim(` [\xB7] Generating and publishing receipt for ${label}...`));
17560
17785
  try {
17561
17786
  const receipt = await generateReceipt({ since, isPublic: false });
17562
17787
  await publishReceiptToCloud(receipt);
17563
17788
  } catch (err) {
17564
17789
  const message = err instanceof Error ? err.message : String(err);
17565
- console.error(import_picocolors3.default.red(`
17790
+ console.error(import_picocolors4.default.red(`
17566
17791
  Share failed: ${message}`));
17567
17792
  }
17568
17793
  await waitForKeyToReturn();
17569
17794
  currentScreen = "main";
17570
- selectedIndex = 0;
17795
+ selectedIndex = savedMainIndex;
17571
17796
  };
17572
17797
  const executeSelectedAction = async () => {
17573
17798
  cleanup();
@@ -17576,8 +17801,8 @@ async function runInteractiveMenu() {
17576
17801
  const selectedItem = MENU_ITEMS[selectedIndex];
17577
17802
  switch (selectedItem.id) {
17578
17803
  case "audit": {
17579
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Audit Branch or Revision Diff")));
17580
- 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"));
17804
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Audit Branch or Revision Diff")));
17805
+ 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"));
17581
17806
  let defaultBase = "origin/main";
17582
17807
  try {
17583
17808
  defaultBase = await detectDefaultBaseBranch(process.cwd());
@@ -17589,7 +17814,7 @@ async function runInteractiveMenu() {
17589
17814
  const head = await askLine(
17590
17815
  ` \u203A Head git ref or commit SHA [default: HEAD]: `
17591
17816
  );
17592
- console.log(import_picocolors3.default.dim("\n [\xB7] Auditing git revision range..."));
17817
+ console.log(import_picocolors4.default.dim("\n [\xB7] Auditing git revision range..."));
17593
17818
  try {
17594
17819
  const receipt = await generateReceipt({
17595
17820
  baseSha: base || defaultBase,
@@ -17602,7 +17827,7 @@ async function runInteractiveMenu() {
17602
17827
  await renderTerminalReceipt(receipt);
17603
17828
  } catch (err) {
17604
17829
  const message = err instanceof Error ? err.message : String(err);
17605
- console.error(import_picocolors3.default.red(`
17830
+ console.error(import_picocolors4.default.red(`
17606
17831
  Audit failed: ${message}`));
17607
17832
  }
17608
17833
  await waitForKeyToReturn();
@@ -17629,10 +17854,14 @@ async function runInteractiveMenu() {
17629
17854
  await runDoctorDiagnosticsAction();
17630
17855
  break;
17631
17856
  }
17857
+ case "chats": {
17858
+ await showChatsAction();
17859
+ break;
17860
+ }
17632
17861
  case "exit": {
17633
17862
  active = false;
17634
17863
  cleanup();
17635
- console.log(import_picocolors3.default.dim(" Exited Qodewk.\n"));
17864
+ console.log(import_picocolors4.default.dim(" Exited Qodewk.\n"));
17636
17865
  process.exit(0);
17637
17866
  return;
17638
17867
  }
@@ -17641,19 +17870,19 @@ async function runInteractiveMenu() {
17641
17870
  const manageHooksSubmenu = async () => {
17642
17871
  const hooksDir = resolveGitHooksDir();
17643
17872
  const status = checkHookStatus(hooksDir);
17644
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk Git Hooks Management")));
17645
- 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"));
17873
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Git Hooks Management")));
17874
+ 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"));
17646
17875
  if (!status.isGit) {
17647
- console.log(import_picocolors3.default.yellow(" Not inside a Git repository. Hooks cannot be configured."));
17876
+ console.log(import_picocolors4.default.yellow(" Not inside a Git repository. Hooks cannot be configured."));
17648
17877
  await waitForKeyToReturn();
17649
17878
  return;
17650
17879
  }
17651
- console.log(` Hooks directory: ${import_picocolors3.default.dim(status.hooksDir || "None")}`);
17880
+ console.log(` Hooks directory: ${import_picocolors4.default.dim(status.hooksDir || "None")}`);
17652
17881
  console.log(
17653
- ` post-commit: ${status.postCommitInstalled ? colors.green("[\u2713 Installed]") : import_picocolors3.default.dim("[\xB7 Not installed]")}`
17882
+ ` post-commit: ${status.postCommitInstalled ? colors.green("[\u2713 Installed]") : import_picocolors4.default.dim("[\xB7 Not installed]")}`
17654
17883
  );
17655
17884
  console.log(
17656
- ` post-rewrite: ${status.postRewriteInstalled ? colors.green("[\u2713 Installed]") : import_picocolors3.default.dim("[\xB7 Not installed]")}`
17885
+ ` post-rewrite: ${status.postRewriteInstalled ? colors.green("[\u2713 Installed]") : import_picocolors4.default.dim("[\xB7 Not installed]")}`
17657
17886
  );
17658
17887
  console.log("");
17659
17888
  console.log(" [1] Install non-blocking hooks (< 5ms background recorder)");
@@ -17662,74 +17891,86 @@ async function runInteractiveMenu() {
17662
17891
  console.log(" [0] Back to main menu");
17663
17892
  console.log("");
17664
17893
  const choice = await askLine(" \u203A Select option [0-3]: ");
17665
- if (choice === "1") {
17894
+ if (choice === "0" || !choice) {
17895
+ return;
17896
+ } else if (choice === "1") {
17666
17897
  if (status.hooksDir) {
17667
17898
  const targets = ["post-commit", "post-rewrite"];
17668
17899
  for (const t2 of targets) {
17669
- installHookFile(path15.join(status.hooksDir, t2));
17900
+ installHookFile(path16.join(status.hooksDir, t2));
17670
17901
  }
17671
17902
  console.log(colors.green("\n [\u2713] Non-blocking hooks installed successfully."));
17672
17903
  }
17904
+ await waitForKeyToReturn();
17673
17905
  } else if (choice === "2") {
17674
17906
  if (status.hooksDir) {
17675
17907
  const targets = ["post-commit", "post-rewrite"];
17676
17908
  for (const t2 of targets) {
17677
- uninstallHookFile(path15.join(status.hooksDir, t2));
17909
+ uninstallHookFile(path16.join(status.hooksDir, t2));
17678
17910
  }
17679
17911
  console.log(colors.green("\n [\u2713] Qodewk hooks removed."));
17680
17912
  }
17913
+ await waitForKeyToReturn();
17681
17914
  } else if (choice === "3") {
17682
17915
  const hooks = auditGitHooks();
17683
17916
  const bench = await benchmarkHookLatency();
17684
17917
  console.log(formatHookTestReport(hooks, bench));
17918
+ await waitForKeyToReturn();
17919
+ } else {
17920
+ console.log(import_picocolors4.default.yellow(`
17921
+ Option '${choice}' is not recognized.`));
17922
+ await waitForKeyToReturn();
17685
17923
  }
17686
- await waitForKeyToReturn();
17687
17924
  };
17688
17925
  const manageGitNotesSubmenu = async () => {
17689
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk Git Notes Management (refs/notes/qodewk)")));
17690
- 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"));
17926
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Git Notes Management (refs/notes/qodewk)")));
17927
+ 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"));
17691
17928
  console.log(" [1] List commits with attached Qodewk notes");
17692
17929
  console.log(" [2] Show receipt note on a commit (default: HEAD)");
17693
17930
  console.log(" [3] Attach receipt note to a Git commit (default: HEAD)");
17694
17931
  console.log(" [0] Back to main menu");
17695
17932
  console.log("");
17696
17933
  const choice = await askLine(" \u203A Select option [0-3]: ");
17697
- if (choice === "1") {
17934
+ if (choice === "0" || !choice) {
17935
+ return;
17936
+ } else if (choice === "1") {
17698
17937
  try {
17699
17938
  const shas = await listGitReceiptNotes();
17700
17939
  if (shas.length === 0) {
17701
- console.log(import_picocolors3.default.yellow("\n No Qodewk Git notes found in repository."));
17940
+ console.log(import_picocolors4.default.yellow("\n No Qodewk Git notes found in repository."));
17702
17941
  } else {
17703
- console.log(import_picocolors3.default.bold(`
17942
+ console.log(import_picocolors4.default.bold(`
17704
17943
  Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
17705
17944
  for (const sha of shas) {
17706
- console.log(` ${import_picocolors3.default.cyan(sha.slice(0, 10))} ${import_picocolors3.default.dim(sha)}`);
17945
+ console.log(` ${import_picocolors4.default.cyan(sha.slice(0, 10))} ${import_picocolors4.default.dim(sha)}`);
17707
17946
  }
17708
17947
  }
17709
17948
  } catch (err) {
17710
17949
  const message = err instanceof Error ? err.message : String(err);
17711
- console.error(import_picocolors3.default.red(`
17950
+ console.error(import_picocolors4.default.red(`
17712
17951
  Error listing Git notes: ${message}`));
17713
17952
  }
17953
+ await waitForKeyToReturn();
17714
17954
  } else if (choice === "2") {
17715
17955
  const commit = await askLine(" \u203A Commit SHA or ref [default: HEAD]: ") || "HEAD";
17716
17956
  try {
17717
17957
  const receipt = await readGitReceiptNote(commit);
17718
17958
  if (!receipt) {
17719
- console.log(import_picocolors3.default.yellow(`
17959
+ console.log(import_picocolors4.default.yellow(`
17720
17960
  No Qodewk receipt note found on commit '${commit}'.`));
17721
17961
  } else {
17722
17962
  await renderTerminalReceipt(receipt);
17723
17963
  }
17724
17964
  } catch (err) {
17725
17965
  const message = err instanceof Error ? err.message : String(err);
17726
- console.error(import_picocolors3.default.red(`
17966
+ console.error(import_picocolors4.default.red(`
17727
17967
  Error reading Git note: ${message}`));
17728
17968
  }
17969
+ await waitForKeyToReturn();
17729
17970
  } else if (choice === "3") {
17730
17971
  const commit = await askLine(" \u203A Commit SHA to attach note [default: HEAD]: ") || "HEAD";
17731
17972
  try {
17732
- console.log(import_picocolors3.default.dim(`
17973
+ console.log(import_picocolors4.default.dim(`
17733
17974
  [\xB7] Generating receipt for ${commit}...`));
17734
17975
  const receipt = await generateReceipt({ headSha: commit });
17735
17976
  await writeGitReceiptNote(receipt.repository.headSha, receipt);
@@ -17739,30 +17980,38 @@ async function runInteractiveMenu() {
17739
17980
  );
17740
17981
  } catch (err) {
17741
17982
  const message = err instanceof Error ? err.message : String(err);
17742
- console.error(import_picocolors3.default.red(`
17983
+ console.error(import_picocolors4.default.red(`
17743
17984
  Error writing Git note: ${message}`));
17744
17985
  }
17986
+ await waitForKeyToReturn();
17987
+ } else {
17988
+ console.log(import_picocolors4.default.yellow(`
17989
+ Option '${choice}' is not recognized.`));
17990
+ await waitForKeyToReturn();
17745
17991
  }
17746
- await waitForKeyToReturn();
17747
17992
  };
17748
17993
  const showStorageStatus = async () => {
17749
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk Local Database & Storage Status")));
17750
- 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"));
17994
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Local Database & Storage Status")));
17995
+ 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"));
17751
17996
  try {
17752
17997
  const db = new LocalStateDB();
17753
17998
  const stats = db.getStats();
17754
17999
  const recent = db.getRecentReceipts(5);
17755
18000
  db.close();
17756
- console.log(` Database path: ${import_picocolors3.default.dim("~/.qodewk/state.db")}`);
17757
- console.log(` Total saved receipts: ${import_picocolors3.default.bold(import_picocolors3.default.white(String(stats.totalReceipts)))}`);
17758
- console.log(` Total agent footprints: ${import_picocolors3.default.bold(import_picocolors3.default.white(String(stats.totalFootprints)))}`);
18001
+ console.log(` Database path: ${import_picocolors4.default.dim("~/.qodewk/state.db")}`);
18002
+ console.log(` Total saved receipts: ${import_picocolors4.default.bold(import_picocolors4.default.white(String(stats.totalReceipts)))}`);
18003
+ console.log(` Total agent footprints: ${import_picocolors4.default.bold(import_picocolors4.default.white(String(stats.totalFootprints)))}`);
17759
18004
  console.log("");
17760
18005
  if (recent.length === 0) {
17761
- console.log(import_picocolors3.default.dim(" No stored receipts yet. Run 'Generate Local Receipt' to record your first."));
18006
+ console.log(import_picocolors4.default.dim(" No stored receipts yet. Run 'Generate Local Receipt' to record your first."));
18007
+ console.log("");
18008
+ console.log(` ${colors.green("[\u2713]")} ${import_picocolors4.default.dim("Privacy guarantee: raw source code is never stored in SQLite")}`);
18009
+ await waitForKeyToReturn();
18010
+ return;
17762
18011
  } else {
17763
- console.log(import_picocolors3.default.dim(" Recent Receipts:"));
17764
- console.log(import_picocolors3.default.dim(" " + "ID".padEnd(26) + "DATE".padEnd(12) + "BRANCH".padEnd(18) + "COST"));
17765
- console.log(import_picocolors3.default.dim(" " + "\u2500".repeat(60)));
18012
+ console.log(import_picocolors4.default.dim(" Recent Receipts:"));
18013
+ console.log(import_picocolors4.default.dim(" " + "ID".padEnd(26) + "DATE".padEnd(12) + "BRANCH".padEnd(18) + "COST"));
18014
+ console.log(import_picocolors4.default.dim(" " + "\u2500".repeat(60)));
17766
18015
  for (const item of recent) {
17767
18016
  const id = item.receipt.receipt.id.slice(0, 24).padEnd(26);
17768
18017
  const date = item.receipt.receipt.createdAt.slice(0, 10).padEnd(12);
@@ -17772,7 +18021,7 @@ async function runInteractiveMenu() {
17772
18021
  }
17773
18022
  }
17774
18023
  console.log("");
17775
- console.log(` ${colors.green("[\u2713]")} ${import_picocolors3.default.dim("Privacy guarantee: raw source code is never stored in SQLite")}`);
18024
+ console.log(` ${colors.green("[\u2713]")} ${import_picocolors4.default.dim("Privacy guarantee: raw source code is never stored in SQLite")}`);
17776
18025
  if (recent.length > 0) {
17777
18026
  console.log("");
17778
18027
  const ans = await askLine(" \u203A Enter receipt ID prefix to publish to cloud [Enter to return]: ");
@@ -17783,26 +18032,45 @@ async function runInteractiveMenu() {
17783
18032
  await waitForKeyToReturn();
17784
18033
  return;
17785
18034
  } else {
17786
- console.log(import_picocolors3.default.yellow(` No stored receipt matching '${ans}' found.`));
18035
+ console.log(import_picocolors4.default.yellow(` No stored receipt matching '${ans}' found.`));
18036
+ await waitForKeyToReturn();
18037
+ return;
17787
18038
  }
18039
+ } else {
18040
+ return;
17788
18041
  }
17789
18042
  }
17790
18043
  } catch (err) {
17791
18044
  const message = err instanceof Error ? err.message : String(err);
17792
- console.error(import_picocolors3.default.red(` Failed to inspect storage: ${message}`));
18045
+ console.error(import_picocolors4.default.red(` Failed to inspect storage: ${message}`));
18046
+ await waitForKeyToReturn();
17793
18047
  }
17794
- await waitForKeyToReturn();
17795
18048
  };
17796
18049
  const runDoctorDiagnosticsAction = async () => {
17797
- console.log(import_picocolors3.default.bold(import_picocolors3.default.white("\n Qodewk System Health & Diagnostics (Doctor)")));
17798
- 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"));
17799
- console.log(import_picocolors3.default.dim(" [\xB7] Running diagnostic audit across agents, hooks, storage, and pricing...\n"));
18050
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk System Health & Diagnostics (Doctor)")));
18051
+ 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"));
18052
+ console.log(import_picocolors4.default.dim(" [\xB7] Running diagnostic audit across agents, hooks, storage, and pricing...\n"));
17800
18053
  try {
17801
18054
  const report = await runDiagnostics();
17802
18055
  console.log(formatDoctorReport(report));
17803
18056
  } catch (err) {
17804
18057
  const message = err instanceof Error ? err.message : String(err);
17805
- console.error(import_picocolors3.default.red(` Diagnostic check failed: ${message}`));
18058
+ console.error(import_picocolors4.default.red(` Diagnostic check failed: ${message}`));
18059
+ }
18060
+ await waitForKeyToReturn();
18061
+ };
18062
+ const showChatsAction = async () => {
18063
+ console.log(import_picocolors4.default.bold(import_picocolors4.default.white("\n Qodewk Workspace Chat Telemetry & Cost Ledger")));
18064
+ 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"));
18065
+ console.log(import_picocolors4.default.dim(" [\xB7] Scanning local IDE transcripts (Antigravity, Cursor, Claude, Windsurf, Cline)...\n"));
18066
+ try {
18067
+ const report = await listProjectChats({
18068
+ repoPath: process.cwd()
18069
+ });
18070
+ console.log(buildTerminalChatLedger(report));
18071
+ } catch (err) {
18072
+ const message = err instanceof Error ? err.message : String(err);
18073
+ console.error(import_picocolors4.default.red(` Failed to inspect workspace chats: ${message}`));
17806
18074
  }
17807
18075
  await waitForKeyToReturn();
17808
18076
  };
@@ -17812,22 +18080,61 @@ async function runInteractiveMenu() {
17812
18080
  process.stdin.setRawMode(true);
17813
18081
  process.stdin.resume();
17814
18082
  render();
18083
+ const executeItem = async (selected) => {
18084
+ if (currentScreen === "main") {
18085
+ if (selected.id === "receipt") {
18086
+ savedMainIndex = selectedIndex;
18087
+ currentScreen = "receipt_horizon";
18088
+ selectedIndex = 0;
18089
+ if (active) startLoop();
18090
+ return;
18091
+ }
18092
+ if (selected.id === "share") {
18093
+ savedMainIndex = selectedIndex;
18094
+ currentScreen = "share_horizon";
18095
+ selectedIndex = 0;
18096
+ if (active) startLoop();
18097
+ return;
18098
+ }
18099
+ await executeSelectedAction();
18100
+ } else if (currentScreen === "receipt_horizon") {
18101
+ if (selected.id === "back") {
18102
+ currentScreen = "main";
18103
+ selectedIndex = savedMainIndex;
18104
+ if (active) startLoop();
18105
+ return;
18106
+ }
18107
+ await executeReceiptHorizon(selected);
18108
+ } else if (currentScreen === "share_horizon") {
18109
+ if (selected.id === "back") {
18110
+ currentScreen = "main";
18111
+ selectedIndex = savedMainIndex;
18112
+ if (active) startLoop();
18113
+ return;
18114
+ }
18115
+ await executeShareHorizon(selected);
18116
+ }
18117
+ if (active) {
18118
+ startLoop();
18119
+ }
18120
+ };
17815
18121
  const onKeypress = async (_str, key) => {
17816
18122
  if (!active) return;
17817
18123
  const items = getActiveItems();
17818
18124
  if (key.ctrl && key.name === "c") {
17819
18125
  cleanup();
18126
+ console.log(import_picocolors4.default.dim("\n Exited Qodewk.\n"));
17820
18127
  process.exit(0);
17821
18128
  }
17822
18129
  if (key.name === "q" || key.name === "escape") {
17823
18130
  if (currentScreen !== "main") {
17824
18131
  currentScreen = "main";
17825
- selectedIndex = 0;
18132
+ selectedIndex = savedMainIndex;
17826
18133
  render();
17827
18134
  return;
17828
18135
  }
17829
18136
  cleanup();
17830
- console.log(import_picocolors3.default.dim("\n Exited Qodewk.\n"));
18137
+ console.log(import_picocolors4.default.dim("\n Exited Qodewk.\n"));
17831
18138
  process.exit(0);
17832
18139
  }
17833
18140
  if (key.name === "up" || key.name === "k") {
@@ -17840,85 +18147,19 @@ async function runInteractiveMenu() {
17840
18147
  render();
17841
18148
  return;
17842
18149
  }
17843
- const itemByKey = items.findIndex((item) => item.key === key.name || item.key === _str);
18150
+ const itemByKey = items.findIndex(
18151
+ (item) => item.key === key.name || item.key === _str
18152
+ );
17844
18153
  if (itemByKey !== -1) {
17845
18154
  selectedIndex = itemByKey;
17846
18155
  render();
17847
18156
  process.stdin.removeListener("keypress", onKeypress);
17848
- const selected = items[selectedIndex];
17849
- if (currentScreen === "main") {
17850
- if (selected.id === "receipt") {
17851
- currentScreen = "receipt_horizon";
17852
- selectedIndex = 0;
17853
- if (active) startLoop();
17854
- return;
17855
- }
17856
- if (selected.id === "share") {
17857
- currentScreen = "share_horizon";
17858
- selectedIndex = 0;
17859
- if (active) startLoop();
17860
- return;
17861
- }
17862
- await executeSelectedAction();
17863
- } else if (currentScreen === "receipt_horizon") {
17864
- if (selected.id === "back") {
17865
- currentScreen = "main";
17866
- selectedIndex = 0;
17867
- if (active) startLoop();
17868
- return;
17869
- }
17870
- await executeReceiptHorizon(selected);
17871
- } else if (currentScreen === "share_horizon") {
17872
- if (selected.id === "back") {
17873
- currentScreen = "main";
17874
- selectedIndex = 0;
17875
- if (active) startLoop();
17876
- return;
17877
- }
17878
- await executeShareHorizon(selected);
17879
- }
17880
- if (active) {
17881
- startLoop();
17882
- }
18157
+ await executeItem(items[selectedIndex]);
17883
18158
  return;
17884
18159
  }
17885
18160
  if (key.name === "return" || key.name === "enter") {
17886
18161
  process.stdin.removeListener("keypress", onKeypress);
17887
- const selected = items[selectedIndex];
17888
- if (currentScreen === "main") {
17889
- if (selected.id === "receipt") {
17890
- currentScreen = "receipt_horizon";
17891
- selectedIndex = 0;
17892
- if (active) startLoop();
17893
- return;
17894
- }
17895
- if (selected.id === "share") {
17896
- currentScreen = "share_horizon";
17897
- selectedIndex = 0;
17898
- if (active) startLoop();
17899
- return;
17900
- }
17901
- await executeSelectedAction();
17902
- } else if (currentScreen === "receipt_horizon") {
17903
- if (selected.id === "back") {
17904
- currentScreen = "main";
17905
- selectedIndex = 0;
17906
- if (active) startLoop();
17907
- return;
17908
- }
17909
- await executeReceiptHorizon(selected);
17910
- } else if (currentScreen === "share_horizon") {
17911
- if (selected.id === "back") {
17912
- currentScreen = "main";
17913
- selectedIndex = 0;
17914
- if (active) startLoop();
17915
- return;
17916
- }
17917
- await executeShareHorizon(selected);
17918
- }
17919
- if (active) {
17920
- startLoop();
17921
- }
18162
+ await executeItem(items[selectedIndex]);
17922
18163
  return;
17923
18164
  }
17924
18165
  };
@@ -17932,19 +18173,19 @@ loadQodewkEnv();
17932
18173
  var SHARE_PAYLOAD_MAX_BYTES2 = 5e4;
17933
18174
  function resolveCliVersion() {
17934
18175
  try {
17935
- const argv1 = process.argv[1] ? path16.dirname(path16.resolve(process.argv[1])) : process.cwd();
18176
+ const argv1 = process.argv[1] ? path17.dirname(path17.resolve(process.argv[1])) : process.cwd();
17936
18177
  const candidates = [
17937
- path16.join(argv1, "..", "package.json"),
17938
- path16.join(argv1, "package.json")
18178
+ path17.join(argv1, "..", "package.json"),
18179
+ path17.join(argv1, "package.json")
17939
18180
  ];
17940
18181
  for (const candidate of candidates) {
17941
- if (!fs15.existsSync(candidate)) continue;
17942
- const pkg = JSON.parse(fs15.readFileSync(candidate, "utf-8"));
18182
+ if (!fs16.existsSync(candidate)) continue;
18183
+ const pkg = JSON.parse(fs16.readFileSync(candidate, "utf-8"));
17943
18184
  if (pkg.name === "qodewk" && pkg.version) return pkg.version;
17944
18185
  }
17945
18186
  } catch {
17946
18187
  }
17947
- return "0.10.1";
18188
+ return "0.11.1";
17948
18189
  }
17949
18190
  function resolveSince(options) {
17950
18191
  return options.today ? "today" : options.since;
@@ -17982,21 +18223,44 @@ program2.name("qodewk").description("Universal telemetry and digital receipt gen
17982
18223
  if (options.notes) {
17983
18224
  try {
17984
18225
  await writeGitReceiptNote(receipt.repository.headSha, receipt);
17985
- console.log(import_picocolors4.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`));
18226
+ console.log(import_picocolors5.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`));
17986
18227
  } catch (noteErr) {
17987
- console.warn(import_picocolors4.default.yellow(`Warning: Could not write Git note: ${noteErr.message}`));
18228
+ console.warn(import_picocolors5.default.yellow(`Warning: Could not write Git note: ${noteErr.message}`));
17988
18229
  }
17989
18230
  }
17990
18231
  await outputReceipt(receipt, options);
17991
18232
  } catch (err) {
17992
18233
  const message = err instanceof Error ? err.message : String(err);
17993
- console.error(import_picocolors4.default.red(`Error generating receipt: ${message}`));
18234
+ console.error(import_picocolors5.default.red(`Error generating receipt: ${message}`));
17994
18235
  process.exit(1);
17995
18236
  }
17996
18237
  });
17997
18238
  program2.command("menu").description("Launch interactive terminal control panel").action(async () => {
17998
18239
  await runInteractiveMenu();
17999
18240
  });
18241
+ 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) => {
18242
+ try {
18243
+ const since = options.today ? "today" : options.since;
18244
+ const report = await listProjectChats({
18245
+ repoPath: process.cwd(),
18246
+ since,
18247
+ platform: options.platform,
18248
+ all: options.all
18249
+ });
18250
+ const isJson = Boolean(options.json || program2.opts().json || options.format === "json");
18251
+ if (isJson) {
18252
+ console.log(JSON.stringify(report, null, 2));
18253
+ } else if (options.format === "markdown") {
18254
+ console.log(buildMarkdownChatLedger(report));
18255
+ } else {
18256
+ console.log(buildTerminalChatLedger(report));
18257
+ }
18258
+ } catch (err) {
18259
+ const message = err instanceof Error ? err.message : String(err);
18260
+ console.error(import_picocolors5.default.red(`Error listing workspace chats: ${message}`));
18261
+ process.exit(1);
18262
+ }
18263
+ });
18000
18264
  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) => {
18001
18265
  try {
18002
18266
  const isJson = Boolean(options.json || program2.opts().json);
@@ -18011,7 +18275,7 @@ program2.command("doctor").description("Run complete diagnostic health check of
18011
18275
  }
18012
18276
  } catch (err) {
18013
18277
  const message = err instanceof Error ? err.message : String(err);
18014
- console.error(import_picocolors4.default.red(`Error running diagnostics: ${message}`));
18278
+ console.error(import_picocolors5.default.red(`Error running diagnostics: ${message}`));
18015
18279
  process.exit(1);
18016
18280
  }
18017
18281
  });
@@ -18031,7 +18295,7 @@ program2.command("audit").description("Audit PR or branch diff against a target
18031
18295
  await outputReceipt(receipt, options);
18032
18296
  } catch (err) {
18033
18297
  const message = err instanceof Error ? err.message : String(err);
18034
- console.error(import_picocolors4.default.red(`Error auditing git range: ${message}`));
18298
+ console.error(import_picocolors5.default.red(`Error auditing git range: ${message}`));
18035
18299
  process.exit(1);
18036
18300
  }
18037
18301
  });
@@ -18048,12 +18312,12 @@ program2.command("share").description("Publish privacy-safe receipt to Qodewk cl
18048
18312
  const localFlag = program2.opts().local === true;
18049
18313
  if (process.env.QODEWK_TELEMETRY === "off" || localFlag) {
18050
18314
  console.log(
18051
- import_picocolors4.default.yellow(
18315
+ import_picocolors5.default.yellow(
18052
18316
  `
18053
18317
  Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"}).`
18054
18318
  )
18055
18319
  );
18056
- console.log(import_picocolors4.default.dim("Telemetry remains strictly stored in local SQLite (~/.qodewk/state.db).\n"));
18320
+ console.log(import_picocolors5.default.dim("Telemetry remains strictly stored in local SQLite (~/.qodewk/state.db).\n"));
18057
18321
  persistReceipt(receipt);
18058
18322
  await renderTerminalReceipt(receipt);
18059
18323
  return;
@@ -18068,11 +18332,11 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
18068
18332
  body = JSON.stringify(trimmed2);
18069
18333
  }
18070
18334
  if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES2) {
18071
- console.error(import_picocolors4.default.red("Sanitized receipt still exceeds the 50 KB cloud payload limit."));
18335
+ console.error(import_picocolors5.default.red("Sanitized receipt still exceeds the 50 KB cloud payload limit."));
18072
18336
  process.exit(1);
18073
18337
  }
18074
18338
  const endpoint = resolveApiUrl();
18075
- console.log(import_picocolors4.default.dim(`Publishing receipt ${sanitized.receipt.id} to ${endpoint}...`));
18339
+ console.log(import_picocolors5.default.dim(`Publishing receipt ${sanitized.receipt.id} to ${endpoint}...`));
18076
18340
  try {
18077
18341
  const response = await fetch(endpoint, {
18078
18342
  method: "POST",
@@ -18089,11 +18353,11 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
18089
18353
  const data = await response.json();
18090
18354
  persistReceipt(sanitized, data.claimToken);
18091
18355
  console.log("");
18092
- console.log(import_picocolors4.default.green(" Published successfully."));
18093
- console.log(` ${import_picocolors4.default.dim("Public URL:")} ${import_picocolors4.default.underline(import_picocolors4.default.cyan(data.url))}`);
18094
- console.log(` ${import_picocolors4.default.bold(import_picocolors4.default.yellow(" Claim token (store securely \u2014 shown once):"))}`);
18095
- console.log(` ${import_picocolors4.default.yellow(data.claimToken)}`);
18096
- console.log(import_picocolors4.default.dim(" Saved to ~/.qodewk/state.db \u2014 required to prove authorship later."));
18356
+ console.log(import_picocolors5.default.green(" Published successfully."));
18357
+ console.log(` ${import_picocolors5.default.dim("Public URL:")} ${import_picocolors5.default.underline(import_picocolors5.default.cyan(data.url))}`);
18358
+ console.log(` ${import_picocolors5.default.bold(import_picocolors5.default.yellow(" Claim token (store securely \u2014 shown once):"))}`);
18359
+ console.log(` ${import_picocolors5.default.yellow(data.claimToken)}`);
18360
+ console.log(import_picocolors5.default.dim(" Saved to ~/.qodewk/state.db \u2014 required to prove authorship later."));
18097
18361
  console.log("");
18098
18362
  await renderTerminalReceipt(sanitized, data.url);
18099
18363
  if (options.json) {
@@ -18101,14 +18365,14 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
18101
18365
  }
18102
18366
  } catch (networkErr) {
18103
18367
  const message = networkErr instanceof Error ? networkErr.message : String(networkErr);
18104
- console.log(import_picocolors4.default.yellow(`
18368
+ console.log(import_picocolors5.default.yellow(`
18105
18369
  Could not reach cloud API (${message}). Rendered locally:`));
18106
18370
  persistReceipt(receipt);
18107
18371
  await renderTerminalReceipt(receipt);
18108
18372
  }
18109
18373
  } catch (err) {
18110
18374
  const message = err instanceof Error ? err.message : String(err);
18111
- console.error(import_picocolors4.default.red(`Error sharing receipt: ${message}`));
18375
+ console.error(import_picocolors5.default.red(`Error sharing receipt: ${message}`));
18112
18376
  process.exit(1);
18113
18377
  }
18114
18378
  });
@@ -18126,35 +18390,35 @@ hookCommand.command("install").description("Install non-blocking post-commit and
18126
18390
  try {
18127
18391
  const hooksDir = resolveGitHooksDir();
18128
18392
  if (!hooksDir) {
18129
- console.error(import_picocolors4.default.red("Error: Current directory is not a Git repository (.git not found)."));
18393
+ console.error(import_picocolors5.default.red("Error: Current directory is not a Git repository (.git not found)."));
18130
18394
  process.exit(1);
18131
18395
  }
18132
- if (!fs15.existsSync(hooksDir)) {
18133
- fs15.mkdirSync(hooksDir, { recursive: true });
18396
+ if (!fs16.existsSync(hooksDir)) {
18397
+ fs16.mkdirSync(hooksDir, { recursive: true });
18134
18398
  }
18135
18399
  const targets = ["post-commit", "post-rewrite"];
18136
18400
  let installed = 0;
18137
18401
  let existing = 0;
18138
18402
  for (const name of targets) {
18139
- const result = installHookFile(path16.join(hooksDir, name));
18403
+ const result = installHookFile(path17.join(hooksDir, name));
18140
18404
  if (result === "installed") installed++;
18141
18405
  else existing++;
18142
18406
  }
18143
18407
  if (installed === 0 && existing > 0) {
18144
- console.log(import_picocolors4.default.yellow("Qodewk Git hooks are already installed (post-commit, post-rewrite)."));
18408
+ console.log(import_picocolors5.default.yellow("Qodewk Git hooks are already installed (post-commit, post-rewrite)."));
18145
18409
  return;
18146
18410
  }
18147
18411
  console.log(
18148
- import_picocolors4.default.green(
18412
+ import_picocolors5.default.green(
18149
18413
  `\u2713 Non-blocking Qodewk hooks installed in ${hooksDir} (post-commit${installed > 1 || existing > 0 ? ", post-rewrite" : installed === 1 && targets.length === 2 ? " + post-rewrite" : ""})`
18150
18414
  )
18151
18415
  );
18152
18416
  if (existing > 0) {
18153
- console.log(import_picocolors4.default.dim(` (${existing} hook file(s) already contained the Qodewk marker)`));
18417
+ console.log(import_picocolors5.default.dim(` (${existing} hook file(s) already contained the Qodewk marker)`));
18154
18418
  }
18155
18419
  } catch (err) {
18156
18420
  const message = err instanceof Error ? err.message : String(err);
18157
- console.error(import_picocolors4.default.red(`Failed to install Git hook: ${message}`));
18421
+ console.error(import_picocolors5.default.red(`Failed to install Git hook: ${message}`));
18158
18422
  process.exit(1);
18159
18423
  }
18160
18424
  });
@@ -18162,23 +18426,23 @@ hookCommand.command("uninstall").description("Remove Qodewk post-commit and post
18162
18426
  try {
18163
18427
  const hooksDir = resolveGitHooksDir();
18164
18428
  if (!hooksDir) {
18165
- console.log(import_picocolors4.default.yellow("No Git repository found."));
18429
+ console.log(import_picocolors5.default.yellow("No Git repository found."));
18166
18430
  return;
18167
18431
  }
18168
18432
  const targets = ["post-commit", "post-rewrite"];
18169
18433
  let removed = 0;
18170
18434
  for (const name of targets) {
18171
- const result = uninstallHookFile(path16.join(hooksDir, name));
18435
+ const result = uninstallHookFile(path17.join(hooksDir, name));
18172
18436
  if (result === "removed") removed++;
18173
18437
  }
18174
18438
  if (removed === 0) {
18175
- console.log(import_picocolors4.default.yellow("Qodewk hooks are not installed."));
18439
+ console.log(import_picocolors5.default.yellow("Qodewk hooks are not installed."));
18176
18440
  return;
18177
18441
  }
18178
- console.log(import_picocolors4.default.green(`\u2713 Qodewk hook markers removed from ${removed} file(s).`));
18442
+ console.log(import_picocolors5.default.green(`\u2713 Qodewk hook markers removed from ${removed} file(s).`));
18179
18443
  } catch (err) {
18180
18444
  const message = err instanceof Error ? err.message : String(err);
18181
- console.error(import_picocolors4.default.red(`Failed to uninstall hook: ${message}`));
18445
+ console.error(import_picocolors5.default.red(`Failed to uninstall hook: ${message}`));
18182
18446
  process.exit(1);
18183
18447
  }
18184
18448
  });
@@ -18197,7 +18461,7 @@ hookCommand.command("test").aliases(["verify", "check"]).description("Verify non
18197
18461
  }
18198
18462
  } catch (err) {
18199
18463
  const message = err instanceof Error ? err.message : String(err);
18200
- console.error(import_picocolors4.default.red(`Error testing hooks: ${message}`));
18464
+ console.error(import_picocolors5.default.red(`Error testing hooks: ${message}`));
18201
18465
  process.exit(1);
18202
18466
  }
18203
18467
  });
@@ -18206,7 +18470,7 @@ notesCmd.command("show [commit]").description("Display Qodewk receipt attached t
18206
18470
  try {
18207
18471
  const receipt = await readGitReceiptNote(commit);
18208
18472
  if (!receipt) {
18209
- console.log(import_picocolors4.default.yellow(`No Qodewk receipt note found on commit '${commit}'.`));
18473
+ console.log(import_picocolors5.default.yellow(`No Qodewk receipt note found on commit '${commit}'.`));
18210
18474
  return;
18211
18475
  }
18212
18476
  if (opts.json) {
@@ -18216,7 +18480,7 @@ notesCmd.command("show [commit]").description("Display Qodewk receipt attached t
18216
18480
  }
18217
18481
  } catch (err) {
18218
18482
  const message = err instanceof Error ? err.message : String(err);
18219
- console.error(import_picocolors4.default.red(`Error reading Git note: ${message}`));
18483
+ console.error(import_picocolors5.default.red(`Error reading Git note: ${message}`));
18220
18484
  process.exit(1);
18221
18485
  }
18222
18486
  });
@@ -18225,11 +18489,11 @@ notesCmd.command("write [commit]").description("Generate and attach receipt to a
18225
18489
  const receipt = await generateReceipt({ headSha: commit });
18226
18490
  await writeGitReceiptNote(receipt.repository.headSha, receipt);
18227
18491
  console.log(
18228
- import_picocolors4.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`)
18492
+ import_picocolors5.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`)
18229
18493
  );
18230
18494
  } catch (err) {
18231
18495
  const message = err instanceof Error ? err.message : String(err);
18232
- console.error(import_picocolors4.default.red(`Error writing Git note: ${message}`));
18496
+ console.error(import_picocolors5.default.red(`Error writing Git note: ${message}`));
18233
18497
  process.exit(1);
18234
18498
  }
18235
18499
  });
@@ -18237,16 +18501,16 @@ notesCmd.command("list").description("List all commits with attached Qodewk rece
18237
18501
  try {
18238
18502
  const shas = await listGitReceiptNotes();
18239
18503
  if (shas.length === 0) {
18240
- console.log(import_picocolors4.default.yellow("No Qodewk Git notes found in repository."));
18504
+ console.log(import_picocolors5.default.yellow("No Qodewk Git notes found in repository."));
18241
18505
  return;
18242
18506
  }
18243
- console.log(import_picocolors4.default.bold(`Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
18507
+ console.log(import_picocolors5.default.bold(`Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
18244
18508
  for (const sha of shas) {
18245
- console.log(` ${import_picocolors4.default.cyan(sha.slice(0, 10))} ${import_picocolors4.default.dim(sha)}`);
18509
+ console.log(` ${import_picocolors5.default.cyan(sha.slice(0, 10))} ${import_picocolors5.default.dim(sha)}`);
18246
18510
  }
18247
18511
  } catch (err) {
18248
18512
  const message = err instanceof Error ? err.message : String(err);
18249
- console.error(import_picocolors4.default.red(`Error listing Git notes: ${message}`));
18513
+ console.error(import_picocolors5.default.red(`Error listing Git notes: ${message}`));
18250
18514
  process.exit(1);
18251
18515
  }
18252
18516
  });