qodewk 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.cjs +392 -157
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1153,7 +1153,7 @@ var require_command = __commonJS({
1153
1153
  "use strict";
1154
1154
  var EventEmitter2 = require("events").EventEmitter;
1155
1155
  var childProcess = require("child_process");
1156
- var path11 = require("path");
1156
+ var path12 = require("path");
1157
1157
  var fs11 = require("fs");
1158
1158
  var process2 = require("process");
1159
1159
  var { Argument: Argument2, humanReadableArgName } = require_argument();
@@ -2153,9 +2153,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2153
2153
  let launchWithNode = false;
2154
2154
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
2155
2155
  function findFile(baseDir, baseName) {
2156
- const localBin = path11.resolve(baseDir, baseName);
2156
+ const localBin = path12.resolve(baseDir, baseName);
2157
2157
  if (fs11.existsSync(localBin)) return localBin;
2158
- if (sourceExt.includes(path11.extname(baseName))) return void 0;
2158
+ if (sourceExt.includes(path12.extname(baseName))) return void 0;
2159
2159
  const foundExt = sourceExt.find(
2160
2160
  (ext) => fs11.existsSync(`${localBin}${ext}`)
2161
2161
  );
@@ -2173,17 +2173,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
2173
2173
  } catch {
2174
2174
  resolvedScriptPath = this._scriptPath;
2175
2175
  }
2176
- executableDir = path11.resolve(
2177
- path11.dirname(resolvedScriptPath),
2176
+ executableDir = path12.resolve(
2177
+ path12.dirname(resolvedScriptPath),
2178
2178
  executableDir
2179
2179
  );
2180
2180
  }
2181
2181
  if (executableDir) {
2182
2182
  let localFile = findFile(executableDir, executableFile);
2183
2183
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
2184
- const legacyName = path11.basename(
2184
+ const legacyName = path12.basename(
2185
2185
  this._scriptPath,
2186
- path11.extname(this._scriptPath)
2186
+ path12.extname(this._scriptPath)
2187
2187
  );
2188
2188
  if (legacyName !== this._name) {
2189
2189
  localFile = findFile(
@@ -2194,7 +2194,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2194
2194
  }
2195
2195
  executableFile = localFile || executableFile;
2196
2196
  }
2197
- launchWithNode = sourceExt.includes(path11.extname(executableFile));
2197
+ launchWithNode = sourceExt.includes(path12.extname(executableFile));
2198
2198
  let proc;
2199
2199
  if (process2.platform !== "win32") {
2200
2200
  if (launchWithNode) {
@@ -3041,7 +3041,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
3041
3041
  * @return {Command}
3042
3042
  */
3043
3043
  nameFromFilename(filename) {
3044
- this._name = path11.basename(filename, path11.extname(filename));
3044
+ this._name = path12.basename(filename, path12.extname(filename));
3045
3045
  return this;
3046
3046
  }
3047
3047
  /**
@@ -3055,9 +3055,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
3055
3055
  * @param {string} [path]
3056
3056
  * @return {(string|null|Command)}
3057
3057
  */
3058
- executableDir(path12) {
3059
- if (path12 === void 0) return this._executableDir;
3060
- this._executableDir = path12;
3058
+ executableDir(path13) {
3059
+ if (path13 === void 0) return this._executableDir;
3060
+ this._executableDir = path13;
3061
3061
  return this;
3062
3062
  }
3063
3063
  /**
@@ -4067,10 +4067,10 @@ var require_src2 = __commonJS({
4067
4067
  var fs_1 = require("fs");
4068
4068
  var debug_1 = __importDefault(require_src());
4069
4069
  var log = debug_1.default("@kwsites/file-exists");
4070
- function check(path11, isFile, isDirectory) {
4071
- log(`checking %s`, path11);
4070
+ function check(path12, isFile, isDirectory) {
4071
+ log(`checking %s`, path12);
4072
4072
  try {
4073
- const stat = fs_1.statSync(path11);
4073
+ const stat = fs_1.statSync(path12);
4074
4074
  if (stat.isFile() && isFile) {
4075
4075
  log(`[OK] path represents a file`);
4076
4076
  return true;
@@ -4090,8 +4090,8 @@ var require_src2 = __commonJS({
4090
4090
  throw e;
4091
4091
  }
4092
4092
  }
4093
- function exists2(path11, type = exports2.READABLE) {
4094
- return check(path11, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
4093
+ function exists2(path12, type = exports2.READABLE) {
4094
+ return check(path12, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
4095
4095
  }
4096
4096
  exports2.exists = exists2;
4097
4097
  exports2.FILE = 1;
@@ -4156,7 +4156,7 @@ var require_dist2 = __commonJS({
4156
4156
 
4157
4157
  // src/index.ts
4158
4158
  var fs10 = __toESM(require("fs"), 1);
4159
- var path10 = __toESM(require("path"), 1);
4159
+ var path11 = __toESM(require("path"), 1);
4160
4160
 
4161
4161
  // ../../node_modules/.pnpm/commander@13.1.0/node_modules/commander/esm.mjs
4162
4162
  var import_index = __toESM(require_commander(), 1);
@@ -4659,8 +4659,8 @@ function getErrorMap() {
4659
4659
 
4660
4660
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
4661
4661
  var makeIssue = (params) => {
4662
- const { data, path: path11, errorMaps, issueData } = params;
4663
- const fullPath = [...path11, ...issueData.path || []];
4662
+ const { data, path: path12, errorMaps, issueData } = params;
4663
+ const fullPath = [...path12, ...issueData.path || []];
4664
4664
  const fullIssue = {
4665
4665
  ...issueData,
4666
4666
  path: fullPath
@@ -4776,11 +4776,11 @@ var errorUtil;
4776
4776
 
4777
4777
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
4778
4778
  var ParseInputLazyPath = class {
4779
- constructor(parent, value, path11, key) {
4779
+ constructor(parent, value, path12, key) {
4780
4780
  this._cachedPath = [];
4781
4781
  this.parent = parent;
4782
4782
  this.data = value;
4783
- this._path = path11;
4783
+ this._path = path12;
4784
4784
  this._key = key;
4785
4785
  }
4786
4786
  get path() {
@@ -8892,8 +8892,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
8892
8892
  function forEachLineWithContent(input, callback) {
8893
8893
  return toLinesWithContent(input, true).map((line) => callback(line));
8894
8894
  }
8895
- function folderExists(path11) {
8896
- return (0, import_file_exists.exists)(path11, import_file_exists.FOLDER);
8895
+ function folderExists(path12) {
8896
+ return (0, import_file_exists.exists)(path12, import_file_exists.FOLDER);
8897
8897
  }
8898
8898
  function append(target, item) {
8899
8899
  if (Array.isArray(target)) {
@@ -9295,8 +9295,8 @@ function checkIsRepoRootTask() {
9295
9295
  commands,
9296
9296
  format: "utf-8",
9297
9297
  onError,
9298
- parser(path11) {
9299
- return /^\.(git)?$/.test(path11.trim());
9298
+ parser(path12) {
9299
+ return /^\.(git)?$/.test(path12.trim());
9300
9300
  }
9301
9301
  };
9302
9302
  }
@@ -9730,11 +9730,11 @@ function parseGrep(grep) {
9730
9730
  const paths = /* @__PURE__ */ new Set();
9731
9731
  const results = {};
9732
9732
  forEachLineWithContent(grep, (input) => {
9733
- const [path11, line, preview] = input.split(NULL);
9734
- paths.add(path11);
9735
- (results[path11] = results[path11] || []).push({
9733
+ const [path12, line, preview] = input.split(NULL);
9734
+ paths.add(path12);
9735
+ (results[path12] = results[path12] || []).push({
9736
9736
  line: asNumber(line),
9737
- path: path11,
9737
+ path: path12,
9738
9738
  preview
9739
9739
  });
9740
9740
  });
@@ -10498,14 +10498,14 @@ var init_hash_object = __esm({
10498
10498
  init_task();
10499
10499
  }
10500
10500
  });
10501
- function parseInit(bare, path11, text) {
10501
+ function parseInit(bare, path12, text) {
10502
10502
  const response = String(text).trim();
10503
10503
  let result;
10504
10504
  if (result = initResponseRegex.exec(response)) {
10505
- return new InitSummary(bare, path11, false, result[1]);
10505
+ return new InitSummary(bare, path12, false, result[1]);
10506
10506
  }
10507
10507
  if (result = reInitResponseRegex.exec(response)) {
10508
- return new InitSummary(bare, path11, true, result[1]);
10508
+ return new InitSummary(bare, path12, true, result[1]);
10509
10509
  }
10510
10510
  let gitDir = "";
10511
10511
  const tokens = response.split(" ");
@@ -10516,7 +10516,7 @@ function parseInit(bare, path11, text) {
10516
10516
  break;
10517
10517
  }
10518
10518
  }
10519
- return new InitSummary(bare, path11, /^re/i.test(response), gitDir);
10519
+ return new InitSummary(bare, path12, /^re/i.test(response), gitDir);
10520
10520
  }
10521
10521
  var InitSummary;
10522
10522
  var initResponseRegex;
@@ -10525,9 +10525,9 @@ var init_InitSummary = __esm({
10525
10525
  "src/lib/responses/InitSummary.ts"() {
10526
10526
  "use strict";
10527
10527
  InitSummary = class {
10528
- constructor(bare, path11, existing, gitDir) {
10528
+ constructor(bare, path12, existing, gitDir) {
10529
10529
  this.bare = bare;
10530
- this.path = path11;
10530
+ this.path = path12;
10531
10531
  this.existing = existing;
10532
10532
  this.gitDir = gitDir;
10533
10533
  }
@@ -10539,7 +10539,7 @@ var init_InitSummary = __esm({
10539
10539
  function hasBareCommand(command) {
10540
10540
  return command.includes(bareCommand);
10541
10541
  }
10542
- function initTask(bare = false, path11, customArgs) {
10542
+ function initTask(bare = false, path12, customArgs) {
10543
10543
  const commands = ["init", ...customArgs];
10544
10544
  if (bare && !hasBareCommand(commands)) {
10545
10545
  commands.splice(1, 0, bareCommand);
@@ -10548,7 +10548,7 @@ function initTask(bare = false, path11, customArgs) {
10548
10548
  commands,
10549
10549
  format: "utf-8",
10550
10550
  parser(text) {
10551
- return parseInit(commands.includes("--bare"), path11, text);
10551
+ return parseInit(commands.includes("--bare"), path12, text);
10552
10552
  }
10553
10553
  };
10554
10554
  }
@@ -11363,12 +11363,12 @@ var init_FileStatusSummary = __esm({
11363
11363
  "use strict";
11364
11364
  fromPathRegex = /^(.+)\0(.+)$/;
11365
11365
  FileStatusSummary = class {
11366
- constructor(path11, index, working_dir) {
11367
- this.path = path11;
11366
+ constructor(path12, index, working_dir) {
11367
+ this.path = path12;
11368
11368
  this.index = index;
11369
11369
  this.working_dir = working_dir;
11370
11370
  if (index === "R" || working_dir === "R") {
11371
- const detail = fromPathRegex.exec(path11) || [null, path11, path11];
11371
+ const detail = fromPathRegex.exec(path12) || [null, path12, path12];
11372
11372
  this.from = detail[2] || "";
11373
11373
  this.path = detail[1] || "";
11374
11374
  }
@@ -11399,14 +11399,14 @@ function splitLine(result, lineStr) {
11399
11399
  default:
11400
11400
  return;
11401
11401
  }
11402
- function data(index, workingDir, path11) {
11402
+ function data(index, workingDir, path12) {
11403
11403
  const raw = `${index}${workingDir}`;
11404
11404
  const handler = parsers6.get(raw);
11405
11405
  if (handler) {
11406
- handler(result, path11);
11406
+ handler(result, path12);
11407
11407
  }
11408
11408
  if (raw !== "##" && raw !== "!!") {
11409
- result.files.push(new FileStatusSummary(path11, index, workingDir));
11409
+ result.files.push(new FileStatusSummary(path12, index, workingDir));
11410
11410
  }
11411
11411
  }
11412
11412
  }
@@ -11757,9 +11757,9 @@ var init_simple_git_api = __esm({
11757
11757
  next
11758
11758
  );
11759
11759
  }
11760
- hashObject(path11, write) {
11760
+ hashObject(path12, write) {
11761
11761
  return this._runTask(
11762
- hashObjectTask(path11, write === true),
11762
+ hashObjectTask(path12, write === true),
11763
11763
  trailingFunctionArgument(arguments)
11764
11764
  );
11765
11765
  }
@@ -12113,8 +12113,8 @@ var init_branch = __esm({
12113
12113
  }
12114
12114
  });
12115
12115
  function toPath(input) {
12116
- const path11 = input.trim().replace(/^["']|["']$/g, "");
12117
- return path11 && (0, import_node_path.normalize)(path11);
12116
+ const path12 = input.trim().replace(/^["']|["']$/g, "");
12117
+ return path12 && (0, import_node_path.normalize)(path12);
12118
12118
  }
12119
12119
  var parseCheckIgnore;
12120
12120
  var init_CheckIgnore = __esm({
@@ -12399,8 +12399,8 @@ __export2(sub_module_exports, {
12399
12399
  subModuleTask: () => subModuleTask,
12400
12400
  updateSubModuleTask: () => updateSubModuleTask
12401
12401
  });
12402
- function addSubModuleTask(repo, path11) {
12403
- return subModuleTask(["add", repo, path11]);
12402
+ function addSubModuleTask(repo, path12) {
12403
+ return subModuleTask(["add", repo, path12]);
12404
12404
  }
12405
12405
  function initSubModuleTask(customArgs) {
12406
12406
  return subModuleTask(["init", ...customArgs]);
@@ -12714,8 +12714,8 @@ var require_git = __commonJS2({
12714
12714
  }
12715
12715
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
12716
12716
  };
12717
- Git2.prototype.submoduleAdd = function(repo, path11, then) {
12718
- return this._runTask(addSubModuleTask2(repo, path11), trailingFunctionArgument2(arguments));
12717
+ Git2.prototype.submoduleAdd = function(repo, path12, then) {
12718
+ return this._runTask(addSubModuleTask2(repo, path12), trailingFunctionArgument2(arguments));
12719
12719
  };
12720
12720
  Git2.prototype.submoduleUpdate = function(args, then) {
12721
12721
  return this._runTask(
@@ -13280,6 +13280,9 @@ function parseSinceOption(since) {
13280
13280
  if (s === "today") {
13281
13281
  return new Date(now.getFullYear(), now.getMonth(), now.getDate());
13282
13282
  }
13283
+ if (s === "yesterday") {
13284
+ return new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
13285
+ }
13283
13286
  const hoursMatch = s.match(/^(\d+)\s*h(?:ours?)?$/);
13284
13287
  if (hoursMatch && hoursMatch[1]) {
13285
13288
  const hours = parseInt(hoursMatch[1], 10);
@@ -15060,6 +15063,10 @@ function parseSinceOption2(since) {
15060
15063
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
15061
15064
  return today;
15062
15065
  }
15066
+ if (s === "yesterday") {
15067
+ const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
15068
+ return yesterday;
15069
+ }
15063
15070
  const hoursMatch = s.match(/^(\d+)\s*h(?:ours?)?$/);
15064
15071
  if (hoursMatch && hoursMatch[1]) {
15065
15072
  const hours = parseInt(hoursMatch[1], 10);
@@ -15618,9 +15625,17 @@ var ansiHex = (hexColor) => {
15618
15625
  const b2 = num & 255;
15619
15626
  return (text) => `\x1B[38;2;${r2};${g};${b2}m${text}\x1B[39m`;
15620
15627
  };
15628
+ var bgAnsiHex = (hexColor) => {
15629
+ const num = parseInt(hexColor.replace("#", ""), 16);
15630
+ const r2 = num >> 16 & 255;
15631
+ const g = num >> 8 & 255;
15632
+ const b2 = num & 255;
15633
+ return (text) => `\x1B[48;2;${r2};${g};${b2}m${text}\x1B[49m`;
15634
+ };
15621
15635
  var colors = {
15622
15636
  coral: ansiHex(THEME.primary),
15623
15637
  coralActive: ansiHex(THEME.primaryActive),
15638
+ ink: ansiHex(THEME.ink),
15624
15639
  muted: ansiHex(THEME.muted),
15625
15640
  mutedSoft: ansiHex(THEME.mutedSoft),
15626
15641
  teal: ansiHex(THEME.teal),
@@ -15630,6 +15645,20 @@ var colors = {
15630
15645
  hairline: ansiHex(THEME.hairline),
15631
15646
  canvas: ansiHex(THEME.canvas)
15632
15647
  };
15648
+ var bg = {
15649
+ coral: bgAnsiHex(THEME.primary),
15650
+ teal: bgAnsiHex(THEME.teal),
15651
+ dark: bgAnsiHex(THEME.surfaceDark),
15652
+ card: bgAnsiHex(THEME.surfaceCard)
15653
+ };
15654
+ var bannerGradient = [
15655
+ ansiHex("#e6dfd8"),
15656
+ ansiHex("#b3aca4"),
15657
+ ansiHex("#8e8b82"),
15658
+ ansiHex("#6c6a64"),
15659
+ ansiHex("#454440"),
15660
+ ansiHex("#454440")
15661
+ ];
15633
15662
  var stripAnsi = (str) => {
15634
15663
  return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").replace(/\x1B\([B0]/g, "");
15635
15664
  };
@@ -15644,27 +15673,27 @@ function buildTerminalReceipt(receipt, publicUrl) {
15644
15673
  const green = colors.green;
15645
15674
  const red = colors.red;
15646
15675
  const teal = colors.teal;
15647
- const INNER_WIDTH2 = 52;
15676
+ const INNER_WIDTH = 52;
15648
15677
  const push = (line) => lines.push(line);
15649
- const printRow = (content, width = INNER_WIDTH2) => {
15678
+ const printRow = (content, width = INNER_WIDTH) => {
15650
15679
  const visLen = visibleWidth(content);
15651
15680
  const pad = Math.max(0, width - visLen);
15652
15681
  push(` | ${content}${" ".repeat(pad)} |`);
15653
15682
  };
15654
- const printRowSplit = (left, right, width = INNER_WIDTH2) => {
15683
+ const printRowSplit = (left, right, width = INNER_WIDTH) => {
15655
15684
  const leftVis = visibleWidth(left);
15656
15685
  const rightVis = visibleWidth(right);
15657
15686
  const pad = Math.max(1, width - leftVis - rightVis);
15658
15687
  push(` | ${left}${" ".repeat(pad)}${right} |`);
15659
15688
  };
15660
- const printCenteredRow = (content, width = INNER_WIDTH2) => {
15689
+ const printCenteredRow = (content, width = INNER_WIDTH) => {
15661
15690
  const visLen = visibleWidth(content);
15662
15691
  const totalPad = Math.max(0, width - visLen);
15663
15692
  const leftPad = Math.floor(totalPad / 2);
15664
15693
  const rightPad = totalPad - leftPad;
15665
15694
  push(` | ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} |`);
15666
15695
  };
15667
- const printDivider = (char = "=", width = INNER_WIDTH2) => {
15696
+ const printDivider = (char = "=", width = INNER_WIDTH) => {
15668
15697
  push(` | ${char.repeat(width)} |`);
15669
15698
  };
15670
15699
  const totalTokens = (receipt.ai.tokens.input + receipt.ai.tokens.output).toLocaleString();
@@ -15735,7 +15764,7 @@ function buildTerminalReceipt(receipt, publicUrl) {
15735
15764
  maxChars: 28
15736
15765
  });
15737
15766
  const barcodeRows = renderTerminalBarcode(barcodePayload, {
15738
- maxWidth: INNER_WIDTH2,
15767
+ maxWidth: INNER_WIDTH,
15739
15768
  height: 3,
15740
15769
  quietZone: 8
15741
15770
  });
@@ -15887,9 +15916,17 @@ function uninstallHookFile(hookFile) {
15887
15916
 
15888
15917
  // src/menu.ts
15889
15918
  var readline = __toESM(require("readline"), 1);
15919
+ var path10 = __toESM(require("path"), 1);
15890
15920
  var import_picocolors2 = __toESM(require_picocolors(), 1);
15891
- var INNER_WIDTH = 58;
15892
15921
  var SHARE_PAYLOAD_MAX_BYTES = 5e4;
15922
+ var BANNER_LINES = [
15923
+ " \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557",
15924
+ " \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u255D",
15925
+ " \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2554\u255D ",
15926
+ " \u2588\u2588\u2551\u2584\u2584 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 ",
15927
+ " \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2554\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2557",
15928
+ " \u255A\u2550\u2550\u2580\u2580\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D"
15929
+ ];
15893
15930
  var MENU_ITEMS = [
15894
15931
  {
15895
15932
  id: "receipt",
@@ -15913,7 +15950,7 @@ var MENU_ITEMS = [
15913
15950
  id: "hooks",
15914
15951
  key: "4",
15915
15952
  label: "Configure Git Hooks",
15916
- description: "Non-blocking background telemetry recording"
15953
+ description: "Non-blocking background telemetry recording (< 5ms)"
15917
15954
  },
15918
15955
  {
15919
15956
  id: "storage",
@@ -15921,6 +15958,12 @@ var MENU_ITEMS = [
15921
15958
  label: "Database & Storage Status",
15922
15959
  description: "Inspect local SQLite (~/.qodewk/state.db) records"
15923
15960
  },
15961
+ {
15962
+ id: "notes",
15963
+ key: "6",
15964
+ label: "Git Notes Management",
15965
+ description: "Inspect & attach receipts to refs/notes/qodewk"
15966
+ },
15924
15967
  {
15925
15968
  id: "exit",
15926
15969
  key: "0",
@@ -15928,79 +15971,95 @@ var MENU_ITEMS = [
15928
15971
  description: "Return to shell"
15929
15972
  }
15930
15973
  ];
15931
- function buildMenuFrame(selectedIndex, items = MENU_ITEMS) {
15974
+ var RECEIPT_HORIZON_ITEMS = [
15975
+ {
15976
+ id: "latest",
15977
+ key: "1",
15978
+ label: "Latest Changes (Default)",
15979
+ description: "Current git working tree or latest commit"
15980
+ },
15981
+ {
15982
+ id: "today",
15983
+ key: "2",
15984
+ label: "Today's Work Session",
15985
+ description: "Commits & agent activity since midnight (--today)"
15986
+ },
15987
+ {
15988
+ id: "yesterday",
15989
+ key: "3",
15990
+ label: "Yesterday's Work",
15991
+ description: "Activity from yesterday to now (--since yesterday)"
15992
+ },
15993
+ {
15994
+ id: "week",
15995
+ key: "4",
15996
+ label: "Past 7 Days (Sprint)",
15997
+ description: "Weekly sprint telemetry across all agents (--since 7d)"
15998
+ },
15999
+ {
16000
+ id: "custom",
16001
+ key: "5",
16002
+ label: "Custom Duration",
16003
+ description: "Specify hours (e.g. 12h) or days (e.g. 3d, 14d)"
16004
+ },
16005
+ {
16006
+ id: "back",
16007
+ key: "0",
16008
+ label: "Back to Main Menu",
16009
+ description: "Return to previous screen"
16010
+ }
16011
+ ];
16012
+ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Control Panel", subtitle = "\u2191\u2193 move \xB7 enter select \xB7 0-6 quick jump \xB7 q quit", options = {}) {
15932
16013
  const lines = [];
15933
- const coral = colors.coral;
15934
- const mutedSoft = colors.mutedSoft;
15935
- const amber = colors.amber;
15936
- const border = colors.mutedSoft;
15937
16014
  const push = (line) => lines.push(line);
15938
- const printRow = (content, width = INNER_WIDTH) => {
15939
- const visLen = visibleWidth(content);
15940
- const pad = Math.max(0, width - visLen);
15941
- push(` ${border("\u2502")} ${content}${" ".repeat(pad)} ${border("\u2502")}`);
15942
- };
15943
- const printCenteredRow = (content, width = INNER_WIDTH) => {
15944
- const visLen = visibleWidth(content);
15945
- const totalPad = Math.max(0, width - visLen);
15946
- const leftPad = Math.floor(totalPad / 2);
15947
- const rightPad = totalPad - leftPad;
15948
- push(` ${border("\u2502")} ${" ".repeat(leftPad)}${content}${" ".repeat(rightPad)} ${border("\u2502")}`);
15949
- };
15950
- const printDivider = (width = INNER_WIDTH) => {
15951
- push(` ${border("\u251C" + "\u2500".repeat(width + 2) + "\u2524")}`);
15952
- };
15953
- push("");
15954
- push(` ${border("\u250C" + "\u2500".repeat(INNER_WIDTH + 2) + "\u2510")}`);
15955
- printCenteredRow(import_picocolors2.default.bold(import_picocolors2.default.white("Q O D E W K")));
15956
- printCenteredRow(coral("Telemetry Control Panel"));
15957
- printDivider();
15958
- printCenteredRow(mutedSoft("Use \u2191 / \u2193 to navigate \xB7 Enter to select \xB7 q to quit"));
15959
- printDivider();
15960
- printRow("");
15961
- const mainItems = items.filter((item) => item.id !== "exit");
15962
- const exitItem = items.find((item) => item.id === "exit");
15963
- for (let i2 = 0; i2 < mainItems.length; i2++) {
15964
- const item = mainItems[i2];
15965
- const itemIndex = items.indexOf(item);
15966
- const isSelected = itemIndex === selectedIndex;
15967
- if (isSelected) {
15968
- const pointer = import_picocolors2.default.bold(coral("\u203A"));
15969
- const keyTag = import_picocolors2.default.bold(coral(`[${item.key}]`));
15970
- const label = import_picocolors2.default.bold(import_picocolors2.default.white(item.label));
15971
- printRow(` ${pointer} ${keyTag} ${label}`);
15972
- printRow(` ${amber(item.description)}`);
15973
- } else {
15974
- const keyTag = mutedSoft(`[${item.key}]`);
15975
- const label = import_picocolors2.default.dim(import_picocolors2.default.white(item.label));
15976
- printRow(` ${keyTag} ${label}`);
15977
- printRow(` ${import_picocolors2.default.dim(item.description)}`);
15978
- }
15979
- if (i2 < mainItems.length - 1) {
15980
- printRow("");
16015
+ if (options.showBanner ?? true) {
16016
+ push("");
16017
+ for (let i2 = 0; i2 < BANNER_LINES.length; i2++) {
16018
+ const gradFn = bannerGradient[i2] || bannerGradient[bannerGradient.length - 1];
16019
+ push(gradFn(BANNER_LINES[i2]));
15981
16020
  }
15982
16021
  }
15983
- printRow("");
15984
- if (exitItem) {
15985
- printDivider();
15986
- const exitIndex = items.indexOf(exitItem);
15987
- const isSelected = exitIndex === selectedIndex;
16022
+ push("");
16023
+ const badge = bg.teal(import_picocolors2.default.bold(colors.ink(" qodewk ")));
16024
+ push(` ${colors.mutedSoft("\u250C")} ${badge} ${import_picocolors2.default.dim("v0.8.0")}`);
16025
+ push(` ${colors.mutedSoft("\u2502")}`);
16026
+ if (options.actionContext) {
16027
+ push(` ${colors.teal("\u25C7")} ${import_picocolors2.default.dim("Action:")} ${import_picocolors2.default.white(options.actionContext)}`);
16028
+ push(` ${colors.mutedSoft("\u2502")}`);
16029
+ } else {
16030
+ const repo = options.repoContext?.alias || "Qodewk";
16031
+ const branch = options.repoContext?.branch ? `(${options.repoContext.branch})` : "";
16032
+ push(` ${colors.teal("\u25C7")} ${import_picocolors2.default.dim("Repository:")} ${import_picocolors2.default.white(repo)} ${import_picocolors2.default.dim(branch)}`);
16033
+ push(` ${colors.mutedSoft("\u2502")}`);
16034
+ push(` ${colors.teal("\u25C7")} ${import_picocolors2.default.dim("Telemetry:")} ${import_picocolors2.default.white("Claude Warm Editorial Rate Cards")}`);
16035
+ push(` ${colors.mutedSoft("\u2502")}`);
16036
+ }
16037
+ push(` ${colors.coral("\u25C6")} ${import_picocolors2.default.bold(import_picocolors2.default.white(title))}`);
16038
+ push(` ${colors.mutedSoft("\u2502")}`);
16039
+ const selectedItem = items[selectedIndex] || items[0];
16040
+ for (let i2 = 0; i2 < items.length; i2++) {
16041
+ const item = items[i2];
16042
+ const isSelected = i2 === selectedIndex;
15988
16043
  if (isSelected) {
15989
- const pointer = import_picocolors2.default.bold(coral("\u203A"));
15990
- const keyTag = import_picocolors2.default.bold(coral(`[${exitItem.key}]`));
15991
- const label = import_picocolors2.default.bold(import_picocolors2.default.white(exitItem.label));
15992
- printRow(` ${pointer} ${keyTag} ${label}`);
15993
- printRow(` ${amber(exitItem.description)}`);
16044
+ push(
16045
+ ` ${colors.mutedSoft("\u2502")} ${import_picocolors2.default.bold(colors.coral("\u203A"))} ${import_picocolors2.default.bold(colors.coral(item.key))} ${import_picocolors2.default.bold(import_picocolors2.default.white(item.label))}`
16046
+ );
15994
16047
  } else {
15995
- const keyTag = mutedSoft(`[${exitItem.key}]`);
15996
- const label = import_picocolors2.default.dim(import_picocolors2.default.white(exitItem.label));
15997
- printRow(` ${keyTag} ${label}`);
15998
- printRow(` ${import_picocolors2.default.dim(exitItem.description)}`);
16048
+ push(
16049
+ ` ${colors.mutedSoft("\u2502")} ${import_picocolors2.default.dim(item.key)} ${import_picocolors2.default.dim(import_picocolors2.default.white(item.label))}`
16050
+ );
15999
16051
  }
16000
16052
  }
16001
- printDivider();
16002
- printCenteredRow(import_picocolors2.default.dim("[\u2713] Source code was never uploaded to Qodewk"));
16003
- push(` ${border("\u2514" + "\u2500".repeat(INNER_WIDTH + 2) + "\u2518")}`);
16053
+ const divider = colors.mutedSoft("\u2500".repeat(58));
16054
+ push(` ${colors.mutedSoft("\u2502")}`);
16055
+ push(` ${colors.mutedSoft("\u2502")} ${divider}`);
16056
+ push(` ${colors.mutedSoft("\u2502")} ${import_picocolors2.default.bold(import_picocolors2.default.dim("Description"))}`);
16057
+ push(` ${colors.mutedSoft("\u2502")} ${colors.amber(selectedItem.description)}`);
16058
+ push(` ${colors.mutedSoft("\u2502")} ${divider}`);
16059
+ push(` ${colors.mutedSoft("\u2502")}`);
16060
+ push(` ${colors.mutedSoft("\u2502")} ${import_picocolors2.default.dim(subtitle)}`);
16061
+ push(` ${colors.mutedSoft("\u2502")} ${colors.green("[\u2713]")} ${import_picocolors2.default.dim("Source code was never uploaded to Qodewk")}`);
16062
+ push(` ${colors.mutedSoft("\u2514")}`);
16004
16063
  push("");
16005
16064
  return lines.join("\n");
16006
16065
  }
@@ -16034,17 +16093,50 @@ function waitForKeyToReturn() {
16034
16093
  process.stdin.once("data", onKey);
16035
16094
  });
16036
16095
  }
16096
+ var cachedRepoContext = null;
16097
+ async function getRepoContext() {
16098
+ if (cachedRepoContext) return cachedRepoContext;
16099
+ try {
16100
+ const { simpleGit: simpleGit2 } = await import("simple-git");
16101
+ const git = simpleGit2(process.cwd());
16102
+ const isRepo = await git.checkIsRepo();
16103
+ if (!isRepo) {
16104
+ cachedRepoContext = { alias: "Workspace", branch: "detached" };
16105
+ return cachedRepoContext;
16106
+ }
16107
+ const branchSummary = await git.branch();
16108
+ const branch = branchSummary.current || "HEAD";
16109
+ const alias = path10.basename(process.cwd());
16110
+ cachedRepoContext = { alias, branch };
16111
+ return cachedRepoContext;
16112
+ } catch {
16113
+ cachedRepoContext = { alias: "Workspace", branch: "detached" };
16114
+ return cachedRepoContext;
16115
+ }
16116
+ }
16037
16117
  async function runInteractiveMenu() {
16038
16118
  if (!process.stdin.isTTY) {
16039
16119
  console.log(buildMenuFrame(0));
16040
16120
  console.log(import_picocolors2.default.yellow("Interactive menu requires a TTY terminal. Use `qodewk --help` for commands."));
16041
16121
  return;
16042
16122
  }
16123
+ const repoContext = await getRepoContext();
16124
+ let currentScreen = "main";
16043
16125
  let selectedIndex = 0;
16044
16126
  let active = true;
16045
16127
  let lastRenderedLinesCount = 0;
16128
+ const getActiveItems = () => currentScreen === "main" ? MENU_ITEMS : RECEIPT_HORIZON_ITEMS;
16046
16129
  const render = () => {
16047
- const frame = buildMenuFrame(selectedIndex);
16130
+ const items = getActiveItems();
16131
+ const title = currentScreen === "main" ? "Telemetry Control Panel" : "Generate Local Receipt";
16132
+ const subtitle = currentScreen === "main" ? "\u2191\u2193 move \xB7 enter select \xB7 0-6 quick jump \xB7 q quit" : "\u2191\u2193 move \xB7 enter select \xB7 0-5 quick jump \xB7 esc / 0 back";
16133
+ const actionContext = currentScreen === "receipt_horizon" ? "Generate Local Receipt" : void 0;
16134
+ const showBanner = currentScreen === "main";
16135
+ const frame = buildMenuFrame(selectedIndex, items, title, subtitle, {
16136
+ repoContext,
16137
+ actionContext,
16138
+ showBanner
16139
+ });
16048
16140
  const lineCount = frame.split("\n").length;
16049
16141
  if (lastRenderedLinesCount > 0) {
16050
16142
  readline.cursorTo(process.stdout, 0);
@@ -16062,28 +16154,52 @@ async function runInteractiveMenu() {
16062
16154
  process.stdout.write("\x1B[?25h");
16063
16155
  };
16064
16156
  process.on("exit", cleanup);
16157
+ const executeReceiptHorizon = async (item) => {
16158
+ cleanup();
16159
+ console.log("");
16160
+ lastRenderedLinesCount = 0;
16161
+ let since = void 0;
16162
+ let label = "latest git diff";
16163
+ if (item.id === "today") {
16164
+ since = "today";
16165
+ label = "today's work session (--today)";
16166
+ } else if (item.id === "yesterday") {
16167
+ since = "yesterday";
16168
+ label = "yesterday's work (--since yesterday)";
16169
+ } else if (item.id === "week") {
16170
+ since = "7d";
16171
+ label = "past 7 days weekly sprint (--since 7d)";
16172
+ } else if (item.id === "custom") {
16173
+ console.log(import_picocolors2.default.bold(import_picocolors2.default.white(" Custom Telemetry Horizon")));
16174
+ console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
16175
+ const input = await askLine(" \u203A Enter duration or date (e.g. 12h, 3d, 2026-10-01): ");
16176
+ if (input) {
16177
+ since = input;
16178
+ label = `custom range: ${input}`;
16179
+ }
16180
+ }
16181
+ console.log(import_picocolors2.default.dim(` [\xB7] Generating local receipt for ${label}...`));
16182
+ try {
16183
+ const receipt = await generateReceipt({ since, isPublic: false });
16184
+ const db = new LocalStateDB();
16185
+ db.saveReceipt(receipt);
16186
+ db.close();
16187
+ await renderTerminalReceipt(receipt);
16188
+ } catch (err) {
16189
+ const message = err instanceof Error ? err.message : String(err);
16190
+ console.error(import_picocolors2.default.red(`
16191
+ Failed to generate receipt: ${message}`));
16192
+ }
16193
+ await waitForKeyToReturn();
16194
+ currentScreen = "main";
16195
+ selectedIndex = 0;
16196
+ };
16065
16197
  const executeSelectedAction = async () => {
16066
16198
  cleanup();
16067
16199
  console.log("");
16068
16200
  lastRenderedLinesCount = 0;
16069
16201
  const selectedItem = MENU_ITEMS[selectedIndex];
16070
16202
  switch (selectedItem.id) {
16071
- case "receipt": {
16072
- console.log(import_picocolors2.default.dim(" [\xB7] Generating local receipt from git diff..."));
16073
- try {
16074
- const receipt = await generateReceipt({ isPublic: false });
16075
- const db = new LocalStateDB();
16076
- db.saveReceipt(receipt);
16077
- db.close();
16078
- await renderTerminalReceipt(receipt);
16079
- } catch (err) {
16080
- const message = err instanceof Error ? err.message : String(err);
16081
- console.error(import_picocolors2.default.red(`
16082
- Failed to generate receipt: ${message}`));
16083
- }
16084
- await waitForKeyToReturn();
16085
- break;
16086
- }
16087
16203
  case "audit": {
16088
16204
  console.log(import_picocolors2.default.bold(import_picocolors2.default.white("\n Audit Branch or Revision Diff")));
16089
16205
  console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
@@ -16148,6 +16264,16 @@ async function runInteractiveMenu() {
16148
16264
  });
16149
16265
  if (!response.ok) {
16150
16266
  const errText = await response.text().catch(() => "");
16267
+ if (response.status === 503) {
16268
+ console.log(import_picocolors2.default.yellow("\n Notice: Remote server requires durable storage (Supabase or PostgreSQL) in production"));
16269
+ console.log(import_picocolors2.default.dim(" to protect receipts from serverless cold-start data loss."));
16270
+ console.log(import_picocolors2.default.dim(` Endpoint: ${endpoint}`));
16271
+ console.log(colors.green("\n [\u2713] Your receipt is safely saved locally in: ~/.qodewk/state.db"));
16272
+ console.log(import_picocolors2.default.dim(" You can also save it as a local Git note: qodewk --notes\n"));
16273
+ await renderTerminalReceipt(sanitized);
16274
+ await waitForKeyToReturn();
16275
+ break;
16276
+ }
16151
16277
  throw new Error(`API responded with ${response.status}${errText ? `: ${errText.slice(0, 100)}` : ""}`);
16152
16278
  }
16153
16279
  const data = await response.json();
@@ -16176,6 +16302,10 @@ async function runInteractiveMenu() {
16176
16302
  await showStorageStatus();
16177
16303
  break;
16178
16304
  }
16305
+ case "notes": {
16306
+ await manageGitNotesSubmenu();
16307
+ break;
16308
+ }
16179
16309
  case "exit": {
16180
16310
  active = false;
16181
16311
  cleanup();
@@ -16210,25 +16340,83 @@ async function runInteractiveMenu() {
16210
16340
  const choice = await askLine(" \u203A Select option [0-2]: ");
16211
16341
  if (choice === "1") {
16212
16342
  if (status.hooksDir) {
16213
- const path11 = await import("path");
16214
16343
  const targets = ["post-commit", "post-rewrite"];
16215
16344
  for (const t2 of targets) {
16216
- installHookFile(path11.join(status.hooksDir, t2));
16345
+ installHookFile(path10.join(status.hooksDir, t2));
16217
16346
  }
16218
16347
  console.log(colors.green("\n [\u2713] Non-blocking hooks installed successfully."));
16219
16348
  }
16220
16349
  } else if (choice === "2") {
16221
16350
  if (status.hooksDir) {
16222
- const path11 = await import("path");
16223
16351
  const targets = ["post-commit", "post-rewrite"];
16224
16352
  for (const t2 of targets) {
16225
- uninstallHookFile(path11.join(status.hooksDir, t2));
16353
+ uninstallHookFile(path10.join(status.hooksDir, t2));
16226
16354
  }
16227
16355
  console.log(colors.green("\n [\u2713] Qodewk hooks removed."));
16228
16356
  }
16229
16357
  }
16230
16358
  await waitForKeyToReturn();
16231
16359
  };
16360
+ const manageGitNotesSubmenu = async () => {
16361
+ console.log(import_picocolors2.default.bold(import_picocolors2.default.white("\n Qodewk Git Notes Management (refs/notes/qodewk)")));
16362
+ console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
16363
+ console.log(" [1] List commits with attached Qodewk notes");
16364
+ console.log(" [2] Show receipt note on a commit (default: HEAD)");
16365
+ console.log(" [3] Attach receipt note to a Git commit (default: HEAD)");
16366
+ console.log(" [0] Back to main menu");
16367
+ console.log("");
16368
+ const choice = await askLine(" \u203A Select option [0-3]: ");
16369
+ if (choice === "1") {
16370
+ try {
16371
+ const shas = await listGitReceiptNotes();
16372
+ if (shas.length === 0) {
16373
+ console.log(import_picocolors2.default.yellow("\n No Qodewk Git notes found in repository."));
16374
+ } else {
16375
+ console.log(import_picocolors2.default.bold(`
16376
+ Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
16377
+ for (const sha of shas) {
16378
+ console.log(` ${import_picocolors2.default.cyan(sha.slice(0, 10))} ${import_picocolors2.default.dim(sha)}`);
16379
+ }
16380
+ }
16381
+ } catch (err) {
16382
+ const message = err instanceof Error ? err.message : String(err);
16383
+ console.error(import_picocolors2.default.red(`
16384
+ Error listing Git notes: ${message}`));
16385
+ }
16386
+ } else if (choice === "2") {
16387
+ const commit = await askLine(" \u203A Commit SHA or ref [default: HEAD]: ") || "HEAD";
16388
+ try {
16389
+ const receipt = await readGitReceiptNote(commit);
16390
+ if (!receipt) {
16391
+ console.log(import_picocolors2.default.yellow(`
16392
+ No Qodewk receipt note found on commit '${commit}'.`));
16393
+ } else {
16394
+ await renderTerminalReceipt(receipt);
16395
+ }
16396
+ } catch (err) {
16397
+ const message = err instanceof Error ? err.message : String(err);
16398
+ console.error(import_picocolors2.default.red(`
16399
+ Error reading Git note: ${message}`));
16400
+ }
16401
+ } else if (choice === "3") {
16402
+ const commit = await askLine(" \u203A Commit SHA to attach note [default: HEAD]: ") || "HEAD";
16403
+ try {
16404
+ console.log(import_picocolors2.default.dim(`
16405
+ [\xB7] Generating receipt for ${commit}...`));
16406
+ const receipt = await generateReceipt({ headSha: commit });
16407
+ await writeGitReceiptNote(receipt.repository.headSha, receipt);
16408
+ console.log(
16409
+ colors.green(`
16410
+ [\u2713] Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`)
16411
+ );
16412
+ } catch (err) {
16413
+ const message = err instanceof Error ? err.message : String(err);
16414
+ console.error(import_picocolors2.default.red(`
16415
+ Error writing Git note: ${message}`));
16416
+ }
16417
+ }
16418
+ await waitForKeyToReturn();
16419
+ };
16232
16420
  const showStorageStatus = async () => {
16233
16421
  console.log(import_picocolors2.default.bold(import_picocolors2.default.white("\n Qodewk Local Database & Storage Status")));
16234
16422
  console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
@@ -16271,31 +16459,55 @@ async function runInteractiveMenu() {
16271
16459
  render();
16272
16460
  const onKeypress = async (_str, key) => {
16273
16461
  if (!active) return;
16462
+ const items = getActiveItems();
16274
16463
  if (key.ctrl && key.name === "c") {
16275
16464
  cleanup();
16276
16465
  process.exit(0);
16277
16466
  }
16278
16467
  if (key.name === "q" || key.name === "escape") {
16468
+ if (currentScreen !== "main") {
16469
+ currentScreen = "main";
16470
+ selectedIndex = 0;
16471
+ render();
16472
+ return;
16473
+ }
16279
16474
  cleanup();
16280
16475
  console.log(import_picocolors2.default.dim("\n Exited Qodewk.\n"));
16281
16476
  process.exit(0);
16282
16477
  }
16283
16478
  if (key.name === "up" || key.name === "k") {
16284
- selectedIndex = (selectedIndex - 1 + MENU_ITEMS.length) % MENU_ITEMS.length;
16479
+ selectedIndex = (selectedIndex - 1 + items.length) % items.length;
16285
16480
  render();
16286
16481
  return;
16287
16482
  }
16288
16483
  if (key.name === "down" || key.name === "j") {
16289
- selectedIndex = (selectedIndex + 1) % MENU_ITEMS.length;
16484
+ selectedIndex = (selectedIndex + 1) % items.length;
16290
16485
  render();
16291
16486
  return;
16292
16487
  }
16293
- const itemByKey = MENU_ITEMS.findIndex((item) => item.key === key.name || item.key === _str);
16488
+ const itemByKey = items.findIndex((item) => item.key === key.name || item.key === _str);
16294
16489
  if (itemByKey !== -1) {
16295
16490
  selectedIndex = itemByKey;
16296
16491
  render();
16297
16492
  process.stdin.removeListener("keypress", onKeypress);
16298
- await executeSelectedAction();
16493
+ const selected = items[selectedIndex];
16494
+ if (currentScreen === "main") {
16495
+ if (selected.id === "receipt") {
16496
+ currentScreen = "receipt_horizon";
16497
+ selectedIndex = 0;
16498
+ if (active) startLoop();
16499
+ return;
16500
+ }
16501
+ await executeSelectedAction();
16502
+ } else {
16503
+ if (selected.id === "back") {
16504
+ currentScreen = "main";
16505
+ selectedIndex = 0;
16506
+ if (active) startLoop();
16507
+ return;
16508
+ }
16509
+ await executeReceiptHorizon(selected);
16510
+ }
16299
16511
  if (active) {
16300
16512
  startLoop();
16301
16513
  }
@@ -16303,7 +16515,24 @@ async function runInteractiveMenu() {
16303
16515
  }
16304
16516
  if (key.name === "return" || key.name === "enter") {
16305
16517
  process.stdin.removeListener("keypress", onKeypress);
16306
- await executeSelectedAction();
16518
+ const selected = items[selectedIndex];
16519
+ if (currentScreen === "main") {
16520
+ if (selected.id === "receipt") {
16521
+ currentScreen = "receipt_horizon";
16522
+ selectedIndex = 0;
16523
+ if (active) startLoop();
16524
+ return;
16525
+ }
16526
+ await executeSelectedAction();
16527
+ } else {
16528
+ if (selected.id === "back") {
16529
+ currentScreen = "main";
16530
+ selectedIndex = 0;
16531
+ if (active) startLoop();
16532
+ return;
16533
+ }
16534
+ await executeReceiptHorizon(selected);
16535
+ }
16307
16536
  if (active) {
16308
16537
  startLoop();
16309
16538
  }
@@ -16319,10 +16548,10 @@ async function runInteractiveMenu() {
16319
16548
  var SHARE_PAYLOAD_MAX_BYTES2 = 5e4;
16320
16549
  function resolveCliVersion() {
16321
16550
  try {
16322
- const argv1 = process.argv[1] ? path10.dirname(path10.resolve(process.argv[1])) : process.cwd();
16551
+ const argv1 = process.argv[1] ? path11.dirname(path11.resolve(process.argv[1])) : process.cwd();
16323
16552
  const candidates = [
16324
- path10.join(argv1, "..", "package.json"),
16325
- path10.join(argv1, "package.json")
16553
+ path11.join(argv1, "..", "package.json"),
16554
+ path11.join(argv1, "package.json")
16326
16555
  ];
16327
16556
  for (const candidate of candidates) {
16328
16557
  if (!fs10.existsSync(candidate)) continue;
@@ -16331,7 +16560,7 @@ function resolveCliVersion() {
16331
16560
  }
16332
16561
  } catch {
16333
16562
  }
16334
- return "0.3.0";
16563
+ return "0.8.0";
16335
16564
  }
16336
16565
  function resolveSince(options) {
16337
16566
  return options.today ? "today" : options.since;
@@ -16350,6 +16579,12 @@ program2.name("qodewk").description("Universal telemetry and digital receipt gen
16350
16579
  await runInteractiveMenu();
16351
16580
  return;
16352
16581
  }
16582
+ const hasExplicitOption = options.json || options.out || options.provider || options.model || options.since || options.today || options.platform || options.anon || options.local || options.notes || options.format && options.format !== "terminal";
16583
+ const isInteractiveTerminal = Boolean(process.stdin.isTTY && !process.env.CI);
16584
+ if (!hasExplicitOption && isInteractiveTerminal) {
16585
+ await runInteractiveMenu();
16586
+ return;
16587
+ }
16353
16588
  try {
16354
16589
  const receipt = await generateReceipt({
16355
16590
  provider: options.provider,
@@ -16499,7 +16734,7 @@ hookCommand.command("install").description("Install non-blocking post-commit and
16499
16734
  let installed = 0;
16500
16735
  let existing = 0;
16501
16736
  for (const name of targets) {
16502
- const result = installHookFile(path10.join(hooksDir, name));
16737
+ const result = installHookFile(path11.join(hooksDir, name));
16503
16738
  if (result === "installed") installed++;
16504
16739
  else existing++;
16505
16740
  }
@@ -16531,7 +16766,7 @@ hookCommand.command("uninstall").description("Remove Qodewk post-commit and post
16531
16766
  const targets = ["post-commit", "post-rewrite"];
16532
16767
  let removed = 0;
16533
16768
  for (const name of targets) {
16534
- const result = uninstallHookFile(path10.join(hooksDir, name));
16769
+ const result = uninstallHookFile(path11.join(hooksDir, name));
16535
16770
  if (result === "removed") removed++;
16536
16771
  }
16537
16772
  if (removed === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qodewk",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Universal telemetry and digital receipt generator for the AI coding agent era",
5
5
  "type": "module",
6
6
  "bin": {