qodewk 0.9.2 → 0.10.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.
- package/dist/index.cjs +894 -273
- 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
|
|
1161
|
-
var
|
|
1160
|
+
var path17 = require("path");
|
|
1161
|
+
var fs16 = 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 (
|
|
2142
|
+
if (fs16.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 =
|
|
2161
|
-
if (
|
|
2162
|
-
if (sourceExt.includes(
|
|
2160
|
+
const localBin = path17.resolve(baseDir, baseName);
|
|
2161
|
+
if (fs16.existsSync(localBin)) return localBin;
|
|
2162
|
+
if (sourceExt.includes(path17.extname(baseName))) return void 0;
|
|
2163
2163
|
const foundExt = sourceExt.find(
|
|
2164
|
-
(ext) =>
|
|
2164
|
+
(ext) => fs16.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 =
|
|
2176
|
+
resolvedScriptPath = fs16.realpathSync(this._scriptPath);
|
|
2177
2177
|
} catch {
|
|
2178
2178
|
resolvedScriptPath = this._scriptPath;
|
|
2179
2179
|
}
|
|
2180
|
-
executableDir =
|
|
2181
|
-
|
|
2180
|
+
executableDir = path17.resolve(
|
|
2181
|
+
path17.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 =
|
|
2188
|
+
const legacyName = path17.basename(
|
|
2189
2189
|
this._scriptPath,
|
|
2190
|
-
|
|
2190
|
+
path17.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(
|
|
2201
|
+
launchWithNode = sourceExt.includes(path17.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 =
|
|
3048
|
+
this._name = path17.basename(filename, path17.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(
|
|
3063
|
-
if (
|
|
3064
|
-
this._executableDir =
|
|
3062
|
+
executableDir(path18) {
|
|
3063
|
+
if (path18 === void 0) return this._executableDir;
|
|
3064
|
+
this._executableDir = path18;
|
|
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(
|
|
4211
|
-
log(`checking %s`,
|
|
4210
|
+
function check(path17, isFile, isDirectory) {
|
|
4211
|
+
log(`checking %s`, path17);
|
|
4212
4212
|
try {
|
|
4213
|
-
const stat = fs_1.statSync(
|
|
4213
|
+
const stat = fs_1.statSync(path17);
|
|
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(
|
|
4234
|
-
return check(
|
|
4233
|
+
function exists2(path17, type = exports2.READABLE) {
|
|
4234
|
+
return check(path17, (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(
|
|
4846
|
-
return (0, import_file_exists.exists)(
|
|
4845
|
+
function folderExists(path17) {
|
|
4846
|
+
return (0, import_file_exists.exists)(path17, 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(
|
|
5038
|
-
return /^\.(git)?$/.test(
|
|
5037
|
+
parser(path17) {
|
|
5038
|
+
return /^\.(git)?$/.test(path17.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 [
|
|
5295
|
-
paths.add(
|
|
5296
|
-
(results[
|
|
5294
|
+
const [path17, line, preview] = input.split(NULL);
|
|
5295
|
+
paths.add(path17);
|
|
5296
|
+
(results[path17] = results[path17] || []).push({
|
|
5297
5297
|
line: asNumber(line),
|
|
5298
|
-
path:
|
|
5298
|
+
path: path17,
|
|
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,
|
|
5595
|
+
function parseInit(bare, path17, text) {
|
|
5596
5596
|
const response = String(text).trim();
|
|
5597
5597
|
let result;
|
|
5598
5598
|
if (result = initResponseRegex.exec(response)) {
|
|
5599
|
-
return new InitSummary(bare,
|
|
5599
|
+
return new InitSummary(bare, path17, false, result[1]);
|
|
5600
5600
|
}
|
|
5601
5601
|
if (result = reInitResponseRegex.exec(response)) {
|
|
5602
|
-
return new InitSummary(bare,
|
|
5602
|
+
return new InitSummary(bare, path17, true, result[1]);
|
|
5603
5603
|
}
|
|
5604
5604
|
let gitDir = "";
|
|
5605
5605
|
const tokens = response.split(" ");
|
|
@@ -5610,12 +5610,12 @@ function parseInit(bare, path16, text) {
|
|
|
5610
5610
|
break;
|
|
5611
5611
|
}
|
|
5612
5612
|
}
|
|
5613
|
-
return new InitSummary(bare,
|
|
5613
|
+
return new InitSummary(bare, path17, /^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,
|
|
5618
|
+
function initTask(bare = false, path17, 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, path16, customArgs) {
|
|
|
5624
5624
|
commands,
|
|
5625
5625
|
format: "utf-8",
|
|
5626
5626
|
parser(text) {
|
|
5627
|
-
return parseInit(commands.includes("--bare"),
|
|
5627
|
+
return parseInit(commands.includes("--bare"), path17, 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,
|
|
5906
|
+
function data(index, workingDir, path17) {
|
|
5907
5907
|
const raw = `${index}${workingDir}`;
|
|
5908
5908
|
const handler = parsers6.get(raw);
|
|
5909
5909
|
if (handler) {
|
|
5910
|
-
handler(result,
|
|
5910
|
+
handler(result, path17);
|
|
5911
5911
|
}
|
|
5912
5912
|
if (raw !== "##" && raw !== "!!") {
|
|
5913
|
-
result.files.push(new FileStatusSummary(
|
|
5913
|
+
result.files.push(new FileStatusSummary(path17, 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
|
|
6101
|
-
return
|
|
6100
|
+
const path17 = input.trim().replace(/^["']|["']$/g, "");
|
|
6101
|
+
return path17 && (0, import_node_path.normalize)(path17);
|
|
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,
|
|
6241
|
-
return subModuleTask(["add", repo,
|
|
6240
|
+
function addSubModuleTask(repo, path17) {
|
|
6241
|
+
return subModuleTask(["add", repo, path17]);
|
|
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(
|
|
6649
|
+
return new Promise(function(resolve6, reject) {
|
|
6650
6650
|
const callback = (err, result) => {
|
|
6651
6651
|
if (err) {
|
|
6652
6652
|
return reject(toError(err));
|
|
6653
6653
|
}
|
|
6654
|
-
|
|
6654
|
+
resolve6(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,
|
|
7573
|
+
constructor(bare, path17, existing, gitDir) {
|
|
7574
7574
|
this.bare = bare;
|
|
7575
|
-
this.path =
|
|
7575
|
+
this.path = path17;
|
|
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(
|
|
8109
|
-
this.path =
|
|
8108
|
+
constructor(path17, index, working_dir) {
|
|
8109
|
+
this.path = path17;
|
|
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(
|
|
8113
|
+
const detail = fromPathRegex.exec(path17) || [null, path17, path17];
|
|
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(
|
|
8375
|
+
hashObject(path17, write) {
|
|
8376
8376
|
return this._runTask(
|
|
8377
|
-
hashObjectTask(
|
|
8377
|
+
hashObjectTask(path17, 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,
|
|
9015
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
9014
|
+
Git2.prototype.submoduleAdd = function(repo, path17, then) {
|
|
9015
|
+
return this._runTask(addSubModuleTask2(repo, path17), 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
|
|
9322
|
-
var
|
|
9321
|
+
var fs15 = __toESM(require("fs"), 1);
|
|
9322
|
+
var path16 = __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
|
|
9342
|
+
var import_picocolors4 = __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:
|
|
9826
|
-
const fullPath = [...
|
|
9825
|
+
const { data, path: path17, errorMaps, issueData } = params;
|
|
9826
|
+
const fullPath = [...path17, ...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,
|
|
9942
|
+
constructor(parent, value, path17, key) {
|
|
9943
9943
|
this._cachedPath = [];
|
|
9944
9944
|
this.parent = parent;
|
|
9945
9945
|
this.data = value;
|
|
9946
|
-
this._path =
|
|
9946
|
+
this._path = path17;
|
|
9947
9947
|
this._key = key;
|
|
9948
9948
|
}
|
|
9949
9949
|
get path() {
|
|
@@ -14352,6 +14352,28 @@ function harvestTrailerFootprints(repoPath, commitMessage, headSha, commitDate)
|
|
|
14352
14352
|
}
|
|
14353
14353
|
return footprints;
|
|
14354
14354
|
}
|
|
14355
|
+
function discoverAntigravityEnvironment() {
|
|
14356
|
+
const isAgent = process.env.ANTIGRAVITY_AGENT === "1" || Boolean(process.env.ANTIGRAVITY_CONVERSATION_ID);
|
|
14357
|
+
const homedir12 = os2.homedir();
|
|
14358
|
+
const antigravityDir = process.env.ANTIGRAVITY_APP_DATA_DIR || path2.join(homedir12, ".gemini", "antigravity");
|
|
14359
|
+
if (isAgent) {
|
|
14360
|
+
return {
|
|
14361
|
+
provider: "antigravity",
|
|
14362
|
+
model: "claude-sonnet-4-6-thinking",
|
|
14363
|
+
confidence: 0.85,
|
|
14364
|
+
mode: "observed"
|
|
14365
|
+
};
|
|
14366
|
+
}
|
|
14367
|
+
if (fs.existsSync(antigravityDir)) {
|
|
14368
|
+
return {
|
|
14369
|
+
provider: "antigravity",
|
|
14370
|
+
model: "claude-sonnet-4-6-thinking",
|
|
14371
|
+
confidence: 0.65,
|
|
14372
|
+
mode: "estimated"
|
|
14373
|
+
};
|
|
14374
|
+
}
|
|
14375
|
+
return null;
|
|
14376
|
+
}
|
|
14355
14377
|
|
|
14356
14378
|
// ../core/dist/harvester/antigravity.js
|
|
14357
14379
|
var fs2 = __toESM(require("fs"), 1);
|
|
@@ -14396,7 +14418,8 @@ function scoreFootprint(fp, gitCtx) {
|
|
|
14396
14418
|
if (found)
|
|
14397
14419
|
matches++;
|
|
14398
14420
|
}
|
|
14399
|
-
const
|
|
14421
|
+
const maxPossibleMatches = Math.min(normChanged.length, normEdited.length);
|
|
14422
|
+
const ratio = maxPossibleMatches > 0 ? matches / maxPossibleMatches : 0;
|
|
14400
14423
|
if (matches > 0) {
|
|
14401
14424
|
score += ratio * 0.4;
|
|
14402
14425
|
} else {
|
|
@@ -14496,8 +14519,8 @@ function harvestAntigravityFootprints(repoPath, sinceDate) {
|
|
|
14496
14519
|
const DatabaseSync2 = getSqliteDatabase();
|
|
14497
14520
|
if (!DatabaseSync2)
|
|
14498
14521
|
return footprints;
|
|
14499
|
-
const
|
|
14500
|
-
const antigravityDir = process.env.ANTIGRAVITY_APP_DATA_DIR || path3.join(
|
|
14522
|
+
const homedir12 = os3.homedir();
|
|
14523
|
+
const antigravityDir = process.env.ANTIGRAVITY_APP_DATA_DIR || path3.join(homedir12, ".gemini", "antigravity");
|
|
14501
14524
|
const dbPath = path3.join(antigravityDir, "conversation_summaries.db");
|
|
14502
14525
|
if (!fs2.existsSync(dbPath)) {
|
|
14503
14526
|
return footprints;
|
|
@@ -14599,8 +14622,8 @@ var path4 = __toESM(require("path"), 1);
|
|
|
14599
14622
|
var os4 = __toESM(require("os"), 1);
|
|
14600
14623
|
function harvestClaudeFootprints(repoPath, projectAlias, sinceDate) {
|
|
14601
14624
|
const footprints = [];
|
|
14602
|
-
const
|
|
14603
|
-
const claudeProjectsDir = path4.join(
|
|
14625
|
+
const homedir12 = os4.homedir();
|
|
14626
|
+
const claudeProjectsDir = path4.join(homedir12, ".claude", "projects");
|
|
14604
14627
|
if (!fs3.existsSync(claudeProjectsDir)) {
|
|
14605
14628
|
return footprints;
|
|
14606
14629
|
}
|
|
@@ -15175,9 +15198,9 @@ function resolveClineStorageDirs(customDir) {
|
|
|
15175
15198
|
if (process.env.ROO_STORAGE_DIR && fs7.existsSync(process.env.ROO_STORAGE_DIR)) {
|
|
15176
15199
|
dirs.push(process.env.ROO_STORAGE_DIR);
|
|
15177
15200
|
}
|
|
15178
|
-
const
|
|
15201
|
+
const homedir12 = os7.homedir();
|
|
15179
15202
|
if (process.platform === "win32") {
|
|
15180
|
-
const appData = process.env.APPDATA || path8.join(
|
|
15203
|
+
const appData = process.env.APPDATA || path8.join(homedir12, "AppData", "Roaming");
|
|
15181
15204
|
const ideRoots = ["Code", "Code - Insiders", "Cursor", "Windsurf"];
|
|
15182
15205
|
const extensionIds = [
|
|
15183
15206
|
"saoudrizwan.claude-dev",
|
|
@@ -15191,7 +15214,7 @@ function resolveClineStorageDirs(customDir) {
|
|
|
15191
15214
|
}
|
|
15192
15215
|
}
|
|
15193
15216
|
} else if (process.platform === "darwin") {
|
|
15194
|
-
const appSupport = path8.join(
|
|
15217
|
+
const appSupport = path8.join(homedir12, "Library", "Application Support");
|
|
15195
15218
|
const ideRoots = ["Code", "Code - Insiders", "Cursor", "Windsurf"];
|
|
15196
15219
|
const extensionIds = [
|
|
15197
15220
|
"saoudrizwan.claude-dev",
|
|
@@ -15205,7 +15228,7 @@ function resolveClineStorageDirs(customDir) {
|
|
|
15205
15228
|
}
|
|
15206
15229
|
}
|
|
15207
15230
|
} else {
|
|
15208
|
-
const configRoot = process.env.XDG_CONFIG_HOME || path8.join(
|
|
15231
|
+
const configRoot = process.env.XDG_CONFIG_HOME || path8.join(homedir12, ".config");
|
|
15209
15232
|
const ideRoots = ["Code", "Code - Insiders", "Cursor", "Windsurf"];
|
|
15210
15233
|
const extensionIds = [
|
|
15211
15234
|
"saoudrizwan.claude-dev",
|
|
@@ -15777,7 +15800,8 @@ function parseSinceOption2(since) {
|
|
|
15777
15800
|
return void 0;
|
|
15778
15801
|
}
|
|
15779
15802
|
async function harvestUniversalFootprints(options) {
|
|
15780
|
-
const
|
|
15803
|
+
const parsedSince = parseSinceOption2(options.since);
|
|
15804
|
+
const sinceDate = parsedSince ? new Date(parsedSince.getTime() - 24 * 60 * 60 * 1e3) : void 0;
|
|
15781
15805
|
const alias = options.projectAlias || "";
|
|
15782
15806
|
let allFootprints = [];
|
|
15783
15807
|
if (!options.platform || options.platform === "all" || options.platform === "antigravity") {
|
|
@@ -16063,6 +16087,289 @@ function formatMarkdownReceipt(receipt, publicUrl) {
|
|
|
16063
16087
|
return lines.join("\n");
|
|
16064
16088
|
}
|
|
16065
16089
|
|
|
16090
|
+
// ../core/dist/doctor.js
|
|
16091
|
+
var fs12 = __toESM(require("fs"), 1);
|
|
16092
|
+
var path13 = __toESM(require("path"), 1);
|
|
16093
|
+
var os12 = __toESM(require("os"), 1);
|
|
16094
|
+
var import_node_child_process = require("child_process");
|
|
16095
|
+
var HOOK_MARKER_BEGIN = "# --- BEGIN QODEWK HOOK ---";
|
|
16096
|
+
function auditAgentEnvironments(repoPath = process.cwd()) {
|
|
16097
|
+
const homedir12 = os12.homedir();
|
|
16098
|
+
const results = [];
|
|
16099
|
+
const agEnv = process.env.ANTIGRAVITY_APP_DATA_DIR;
|
|
16100
|
+
const agHome = path13.join(homedir12, ".gemini", "antigravity");
|
|
16101
|
+
const agPath = agEnv && fs12.existsSync(agEnv) ? agEnv : fs12.existsSync(agHome) ? agHome : void 0;
|
|
16102
|
+
results.push({
|
|
16103
|
+
id: "antigravity",
|
|
16104
|
+
name: "Google Antigravity",
|
|
16105
|
+
status: agPath ? "active" : "not_detected",
|
|
16106
|
+
path: agPath,
|
|
16107
|
+
details: agPath ? "Antigravity brain telemetry detected" : "No active session brain found"
|
|
16108
|
+
});
|
|
16109
|
+
const claudeProjects = path13.join(homedir12, ".claude", "projects");
|
|
16110
|
+
const claudeExists = fs12.existsSync(claudeProjects);
|
|
16111
|
+
results.push({
|
|
16112
|
+
id: "claude",
|
|
16113
|
+
name: "Claude Code CLI",
|
|
16114
|
+
status: claudeExists ? "active" : "not_detected",
|
|
16115
|
+
path: claudeExists ? claudeProjects : void 0,
|
|
16116
|
+
details: claudeExists ? "Claude project session directory found" : "No ~/.claude/projects directory found"
|
|
16117
|
+
});
|
|
16118
|
+
let cursorPath;
|
|
16119
|
+
if (process.platform === "win32") {
|
|
16120
|
+
const c3 = path13.join(process.env.APPDATA || path13.join(homedir12, "AppData", "Roaming"), "Cursor", "User", "workspaceStorage");
|
|
16121
|
+
if (fs12.existsSync(c3))
|
|
16122
|
+
cursorPath = c3;
|
|
16123
|
+
} else if (process.platform === "darwin") {
|
|
16124
|
+
const c3 = path13.join(homedir12, "Library", "Application Support", "Cursor", "User", "workspaceStorage");
|
|
16125
|
+
if (fs12.existsSync(c3))
|
|
16126
|
+
cursorPath = c3;
|
|
16127
|
+
} else {
|
|
16128
|
+
const c3 = path13.join(homedir12, ".config", "Cursor", "User", "workspaceStorage");
|
|
16129
|
+
if (fs12.existsSync(c3))
|
|
16130
|
+
cursorPath = c3;
|
|
16131
|
+
}
|
|
16132
|
+
results.push({
|
|
16133
|
+
id: "cursor",
|
|
16134
|
+
name: "Cursor IDE",
|
|
16135
|
+
status: cursorPath ? "active" : "not_detected",
|
|
16136
|
+
path: cursorPath,
|
|
16137
|
+
details: cursorPath ? "Cursor workspace storage detected" : "Cursor IDE storage not detected"
|
|
16138
|
+
});
|
|
16139
|
+
let windsurfPath;
|
|
16140
|
+
if (process.platform === "win32") {
|
|
16141
|
+
const w = path13.join(process.env.APPDATA || path13.join(homedir12, "AppData", "Roaming"), "Windsurf", "User", "workspaceStorage");
|
|
16142
|
+
if (fs12.existsSync(w))
|
|
16143
|
+
windsurfPath = w;
|
|
16144
|
+
} else if (process.platform === "darwin") {
|
|
16145
|
+
const w = path13.join(homedir12, "Library", "Application Support", "Windsurf", "User", "workspaceStorage");
|
|
16146
|
+
if (fs12.existsSync(w))
|
|
16147
|
+
windsurfPath = w;
|
|
16148
|
+
} else {
|
|
16149
|
+
const w = path13.join(homedir12, ".config", "Windsurf", "User", "workspaceStorage");
|
|
16150
|
+
if (fs12.existsSync(w))
|
|
16151
|
+
windsurfPath = w;
|
|
16152
|
+
}
|
|
16153
|
+
results.push({
|
|
16154
|
+
id: "windsurf",
|
|
16155
|
+
name: "Windsurf IDE",
|
|
16156
|
+
status: windsurfPath ? "active" : "not_detected",
|
|
16157
|
+
path: windsurfPath,
|
|
16158
|
+
details: windsurfPath ? "Cascade session workspace storage detected" : "Windsurf IDE storage not detected"
|
|
16159
|
+
});
|
|
16160
|
+
let clinePath;
|
|
16161
|
+
const localCline = path13.join(repoPath, ".cline");
|
|
16162
|
+
const localRoo = path13.join(repoPath, ".roo");
|
|
16163
|
+
if (fs12.existsSync(localCline)) {
|
|
16164
|
+
clinePath = localCline;
|
|
16165
|
+
} else if (fs12.existsSync(localRoo)) {
|
|
16166
|
+
clinePath = localRoo;
|
|
16167
|
+
} 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");
|
|
16171
|
+
if (fs12.existsSync(clineExt))
|
|
16172
|
+
clinePath = clineExt;
|
|
16173
|
+
else if (fs12.existsSync(rooExt))
|
|
16174
|
+
clinePath = rooExt;
|
|
16175
|
+
}
|
|
16176
|
+
results.push({
|
|
16177
|
+
id: "cline",
|
|
16178
|
+
name: "Cline / Roo Code",
|
|
16179
|
+
status: clinePath ? "active" : "not_detected",
|
|
16180
|
+
path: clinePath,
|
|
16181
|
+
details: clinePath ? "VS Code autonomous agent task storage detected" : "No active Cline or Roo Code tasks found"
|
|
16182
|
+
});
|
|
16183
|
+
const aiderPath = path13.join(repoPath, ".aider.chat.history.md");
|
|
16184
|
+
const aiderExists = fs12.existsSync(aiderPath);
|
|
16185
|
+
results.push({
|
|
16186
|
+
id: "aider",
|
|
16187
|
+
name: "Aider CLI",
|
|
16188
|
+
status: aiderExists ? "active" : "not_detected",
|
|
16189
|
+
path: aiderExists ? aiderPath : void 0,
|
|
16190
|
+
details: aiderExists ? "Repository pairing transcript found" : "No repo-local .aider.chat.history.md found"
|
|
16191
|
+
});
|
|
16192
|
+
const localOpenCode = path13.join(repoPath, ".opencode");
|
|
16193
|
+
const homeOpenCode = path13.join(homedir12, ".opencode", "sessions");
|
|
16194
|
+
const opencodePath = fs12.existsSync(localOpenCode) ? localOpenCode : fs12.existsSync(homeOpenCode) ? homeOpenCode : void 0;
|
|
16195
|
+
results.push({
|
|
16196
|
+
id: "opencode",
|
|
16197
|
+
name: "OpenCode CLI",
|
|
16198
|
+
status: opencodePath ? "active" : "not_detected",
|
|
16199
|
+
path: opencodePath,
|
|
16200
|
+
details: opencodePath ? "OpenCode session history detected" : "No OpenCode session files found"
|
|
16201
|
+
});
|
|
16202
|
+
return results;
|
|
16203
|
+
}
|
|
16204
|
+
function resolveHooksDir(cwd = process.cwd()) {
|
|
16205
|
+
const gitPath = path13.join(cwd, ".git");
|
|
16206
|
+
if (!fs12.existsSync(gitPath))
|
|
16207
|
+
return null;
|
|
16208
|
+
try {
|
|
16209
|
+
const stat = fs12.statSync(gitPath);
|
|
16210
|
+
if (stat.isDirectory()) {
|
|
16211
|
+
return path13.join(gitPath, "hooks");
|
|
16212
|
+
}
|
|
16213
|
+
const content = fs12.readFileSync(gitPath, "utf-8");
|
|
16214
|
+
const match = content.match(/gitdir:\s*(.+)/i);
|
|
16215
|
+
if (!match?.[1])
|
|
16216
|
+
return null;
|
|
16217
|
+
let gitDir = match[1].trim();
|
|
16218
|
+
if (!path13.isAbsolute(gitDir)) {
|
|
16219
|
+
gitDir = path13.resolve(cwd, gitDir);
|
|
16220
|
+
}
|
|
16221
|
+
const commonFile = path13.join(gitDir, "commondir");
|
|
16222
|
+
if (fs12.existsSync(commonFile)) {
|
|
16223
|
+
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");
|
|
16229
|
+
}
|
|
16230
|
+
return path13.join(gitDir, "hooks");
|
|
16231
|
+
} catch {
|
|
16232
|
+
return null;
|
|
16233
|
+
}
|
|
16234
|
+
}
|
|
16235
|
+
function auditGitHooks(repoPath = process.cwd()) {
|
|
16236
|
+
const hooksDir = resolveHooksDir(repoPath);
|
|
16237
|
+
if (!hooksDir || !fs12.existsSync(hooksDir)) {
|
|
16238
|
+
return {
|
|
16239
|
+
isGitRepo: Boolean(hooksDir),
|
|
16240
|
+
hooksDir,
|
|
16241
|
+
postCommitInstalled: false,
|
|
16242
|
+
postRewriteInstalled: false,
|
|
16243
|
+
markerFound: false
|
|
16244
|
+
};
|
|
16245
|
+
}
|
|
16246
|
+
const postCommit = path13.join(hooksDir, "post-commit");
|
|
16247
|
+
const postRewrite = path13.join(hooksDir, "post-rewrite");
|
|
16248
|
+
const hasMarker = (filePath) => {
|
|
16249
|
+
if (!fs12.existsSync(filePath))
|
|
16250
|
+
return false;
|
|
16251
|
+
try {
|
|
16252
|
+
return fs12.readFileSync(filePath, "utf-8").includes(HOOK_MARKER_BEGIN);
|
|
16253
|
+
} catch {
|
|
16254
|
+
return false;
|
|
16255
|
+
}
|
|
16256
|
+
};
|
|
16257
|
+
const commitOk = hasMarker(postCommit);
|
|
16258
|
+
const rewriteOk = hasMarker(postRewrite);
|
|
16259
|
+
return {
|
|
16260
|
+
isGitRepo: true,
|
|
16261
|
+
hooksDir,
|
|
16262
|
+
postCommitInstalled: commitOk,
|
|
16263
|
+
postRewriteInstalled: rewriteOk,
|
|
16264
|
+
markerFound: commitOk || rewriteOk
|
|
16265
|
+
};
|
|
16266
|
+
}
|
|
16267
|
+
async function benchmarkHookLatency(trials = 3) {
|
|
16268
|
+
const samples = [];
|
|
16269
|
+
for (let i2 = 0; i2 < trials; i2++) {
|
|
16270
|
+
const start = process.hrtime.bigint();
|
|
16271
|
+
try {
|
|
16272
|
+
const child = (0, import_node_child_process.spawn)(process.execPath, ["-e", "process.exit(0)"], {
|
|
16273
|
+
detached: true,
|
|
16274
|
+
stdio: "ignore",
|
|
16275
|
+
windowsHide: true
|
|
16276
|
+
});
|
|
16277
|
+
child.unref();
|
|
16278
|
+
const end = process.hrtime.bigint();
|
|
16279
|
+
const diffMs = Number(end - start) / 1e6;
|
|
16280
|
+
samples.push(diffMs);
|
|
16281
|
+
} catch {
|
|
16282
|
+
samples.push(99);
|
|
16283
|
+
}
|
|
16284
|
+
}
|
|
16285
|
+
const minMs = samples.length > 0 ? Math.min(...samples) : 99;
|
|
16286
|
+
const roundedMs = Number(minMs.toFixed(2));
|
|
16287
|
+
if (roundedMs < 5) {
|
|
16288
|
+
return {
|
|
16289
|
+
executionMs: roundedMs,
|
|
16290
|
+
passedInvariant: true,
|
|
16291
|
+
status: "pass",
|
|
16292
|
+
message: `Detached in ${roundedMs} ms (passed < 5ms invariant)`
|
|
16293
|
+
};
|
|
16294
|
+
} else if (roundedMs < 45) {
|
|
16295
|
+
return {
|
|
16296
|
+
executionMs: roundedMs,
|
|
16297
|
+
passedInvariant: true,
|
|
16298
|
+
status: "warn",
|
|
16299
|
+
message: `Detached in ${roundedMs} ms (acceptable cold spawn, target is < 5ms)`
|
|
16300
|
+
};
|
|
16301
|
+
} else {
|
|
16302
|
+
return {
|
|
16303
|
+
executionMs: roundedMs,
|
|
16304
|
+
passedInvariant: false,
|
|
16305
|
+
status: "fail",
|
|
16306
|
+
message: `Detached in ${roundedMs} ms (exceeded non-blocking threshold)`
|
|
16307
|
+
};
|
|
16308
|
+
}
|
|
16309
|
+
}
|
|
16310
|
+
function auditStorageHealth() {
|
|
16311
|
+
const dbPath = path13.join(os12.homedir(), ".qodewk", "state.db");
|
|
16312
|
+
try {
|
|
16313
|
+
const db = new LocalStateDB();
|
|
16314
|
+
const stats = db.getStats();
|
|
16315
|
+
db.close();
|
|
16316
|
+
let sizeBytes = 0;
|
|
16317
|
+
if (fs12.existsSync(dbPath)) {
|
|
16318
|
+
sizeBytes = fs12.statSync(dbPath).size;
|
|
16319
|
+
}
|
|
16320
|
+
return {
|
|
16321
|
+
healthy: true,
|
|
16322
|
+
dbPath,
|
|
16323
|
+
receiptsCount: stats.totalReceipts,
|
|
16324
|
+
footprintsCount: stats.totalFootprints,
|
|
16325
|
+
sizeBytes
|
|
16326
|
+
};
|
|
16327
|
+
} catch {
|
|
16328
|
+
return {
|
|
16329
|
+
healthy: false,
|
|
16330
|
+
dbPath,
|
|
16331
|
+
receiptsCount: 0,
|
|
16332
|
+
footprintsCount: 0
|
|
16333
|
+
};
|
|
16334
|
+
}
|
|
16335
|
+
}
|
|
16336
|
+
function auditPricingSync() {
|
|
16337
|
+
const modelsCount = Object.keys(RATE_CARDS).length;
|
|
16338
|
+
const cachedJson = path13.join(os12.homedir(), ".qodewk", "pricing.json");
|
|
16339
|
+
const hasCached = fs12.existsSync(cachedJson);
|
|
16340
|
+
return {
|
|
16341
|
+
modelsLoaded: modelsCount,
|
|
16342
|
+
cachedRegistryPresent: hasCached,
|
|
16343
|
+
status: modelsCount > 0 ? "active" : "offline"
|
|
16344
|
+
};
|
|
16345
|
+
}
|
|
16346
|
+
async function runDiagnostics(options = {}) {
|
|
16347
|
+
const repoPath = options.repoPath || process.cwd();
|
|
16348
|
+
const agents = auditAgentEnvironments(repoPath);
|
|
16349
|
+
const hooks = auditGitHooks(repoPath);
|
|
16350
|
+
const benchmark = await benchmarkHookLatency();
|
|
16351
|
+
const storage = auditStorageHealth();
|
|
16352
|
+
const pricing = auditPricingSync();
|
|
16353
|
+
const activeAgents = agents.filter((a) => a.status === "active").length;
|
|
16354
|
+
let overallStatus = "healthy";
|
|
16355
|
+
if (!storage.healthy || !hooks.isGitRepo) {
|
|
16356
|
+
overallStatus = "error";
|
|
16357
|
+
} else if (!hooks.markerFound || activeAgents === 0) {
|
|
16358
|
+
overallStatus = "warning";
|
|
16359
|
+
}
|
|
16360
|
+
return {
|
|
16361
|
+
overallStatus,
|
|
16362
|
+
version: "0.10.1",
|
|
16363
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16364
|
+
repoPath,
|
|
16365
|
+
agents,
|
|
16366
|
+
hooks,
|
|
16367
|
+
benchmark,
|
|
16368
|
+
storage,
|
|
16369
|
+
pricing
|
|
16370
|
+
};
|
|
16371
|
+
}
|
|
16372
|
+
|
|
16066
16373
|
// ../core/dist/index.js
|
|
16067
16374
|
function sanitizeReceiptForShare(receipt) {
|
|
16068
16375
|
const sessions = receipt.ai.sessions?.map((s) => ({
|
|
@@ -16194,7 +16501,7 @@ async function generateReceipt(options = {}) {
|
|
|
16194
16501
|
}
|
|
16195
16502
|
|
|
16196
16503
|
// src/receipt-view.ts
|
|
16197
|
-
var
|
|
16504
|
+
var fs13 = __toESM(require("fs"), 1);
|
|
16198
16505
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
16199
16506
|
|
|
16200
16507
|
// src/barcode.ts
|
|
@@ -16608,7 +16915,7 @@ async function outputReceipt(receipt, options, publicUrl) {
|
|
|
16608
16915
|
}
|
|
16609
16916
|
if (options.out) {
|
|
16610
16917
|
const fileContent = format === "terminal" ? stripAnsi(content) : content;
|
|
16611
|
-
|
|
16918
|
+
fs13.writeFileSync(options.out, fileContent.endsWith("\n") ? fileContent : fileContent + "\n", "utf-8");
|
|
16612
16919
|
console.log(import_picocolors.default.green(`\u2713 Receipt written to ${options.out}`));
|
|
16613
16920
|
}
|
|
16614
16921
|
if (!options.out) {
|
|
@@ -16621,12 +16928,12 @@ async function outputReceipt(receipt, options, publicUrl) {
|
|
|
16621
16928
|
}
|
|
16622
16929
|
|
|
16623
16930
|
// src/hooks.ts
|
|
16624
|
-
var
|
|
16625
|
-
var
|
|
16626
|
-
var
|
|
16931
|
+
var fs14 = __toESM(require("fs"), 1);
|
|
16932
|
+
var path14 = __toESM(require("path"), 1);
|
|
16933
|
+
var HOOK_MARKER_BEGIN2 = "# --- BEGIN QODEWK HOOK ---";
|
|
16627
16934
|
var HOOK_MARKER_END = "# --- END QODEWK HOOK ---";
|
|
16628
16935
|
var HOOK_SNIPPET = `
|
|
16629
|
-
${
|
|
16936
|
+
${HOOK_MARKER_BEGIN2}
|
|
16630
16937
|
# Non-blocking Qodewk background recorder (< 5ms)
|
|
16631
16938
|
if command -v qodewk >/dev/null 2>&1 || command -v pnpm >/dev/null 2>&1 || [ -f "./node_modules/.bin/qodewk" ]; then
|
|
16632
16939
|
( ( qodewk record || pnpm qodewk record || npx qodewk record ) >/dev/null 2>&1 & )
|
|
@@ -16634,37 +16941,37 @@ fi
|
|
|
16634
16941
|
${HOOK_MARKER_END}
|
|
16635
16942
|
`;
|
|
16636
16943
|
function resolveGitHooksDir(cwd = process.cwd()) {
|
|
16637
|
-
const gitPath =
|
|
16638
|
-
if (!
|
|
16944
|
+
const gitPath = path14.join(cwd, ".git");
|
|
16945
|
+
if (!fs14.existsSync(gitPath)) return null;
|
|
16639
16946
|
let gitCommonDir;
|
|
16640
|
-
const stat =
|
|
16947
|
+
const stat = fs14.statSync(gitPath);
|
|
16641
16948
|
if (stat.isDirectory()) {
|
|
16642
16949
|
gitCommonDir = gitPath;
|
|
16643
16950
|
} else {
|
|
16644
|
-
const content =
|
|
16951
|
+
const content = fs14.readFileSync(gitPath, "utf-8");
|
|
16645
16952
|
const match = content.match(/gitdir:\s*(.+)/i);
|
|
16646
16953
|
if (!match?.[1]) return null;
|
|
16647
16954
|
let gitDir = match[1].trim();
|
|
16648
|
-
if (!
|
|
16649
|
-
gitDir =
|
|
16955
|
+
if (!path14.isAbsolute(gitDir)) {
|
|
16956
|
+
gitDir = path14.resolve(cwd, gitDir);
|
|
16650
16957
|
}
|
|
16651
|
-
const commonFile =
|
|
16652
|
-
if (
|
|
16653
|
-
let common =
|
|
16654
|
-
if (!
|
|
16655
|
-
common =
|
|
16958
|
+
const commonFile = path14.join(gitDir, "commondir");
|
|
16959
|
+
if (fs14.existsSync(commonFile)) {
|
|
16960
|
+
let common = fs14.readFileSync(commonFile, "utf-8").trim();
|
|
16961
|
+
if (!path14.isAbsolute(common)) {
|
|
16962
|
+
common = path14.resolve(gitDir, common);
|
|
16656
16963
|
}
|
|
16657
16964
|
gitCommonDir = common;
|
|
16658
|
-
} else if (
|
|
16659
|
-
gitCommonDir =
|
|
16965
|
+
} else if (path14.basename(path14.dirname(gitDir)) === "worktrees") {
|
|
16966
|
+
gitCommonDir = path14.dirname(path14.dirname(gitDir));
|
|
16660
16967
|
} else {
|
|
16661
16968
|
gitCommonDir = gitDir;
|
|
16662
16969
|
}
|
|
16663
16970
|
}
|
|
16664
|
-
return
|
|
16971
|
+
return path14.join(gitCommonDir, "hooks");
|
|
16665
16972
|
}
|
|
16666
16973
|
function checkHookStatus(hooksDir) {
|
|
16667
|
-
if (!hooksDir || !
|
|
16974
|
+
if (!hooksDir || !fs14.existsSync(hooksDir)) {
|
|
16668
16975
|
return {
|
|
16669
16976
|
isGit: Boolean(hooksDir),
|
|
16670
16977
|
hooksDir,
|
|
@@ -16672,13 +16979,13 @@ function checkHookStatus(hooksDir) {
|
|
|
16672
16979
|
postRewriteInstalled: false
|
|
16673
16980
|
};
|
|
16674
16981
|
}
|
|
16675
|
-
const postCommit =
|
|
16676
|
-
const postRewrite =
|
|
16982
|
+
const postCommit = path14.join(hooksDir, "post-commit");
|
|
16983
|
+
const postRewrite = path14.join(hooksDir, "post-rewrite");
|
|
16677
16984
|
const hasHook = (p2) => {
|
|
16678
|
-
if (!
|
|
16985
|
+
if (!fs14.existsSync(p2)) return false;
|
|
16679
16986
|
try {
|
|
16680
|
-
const content =
|
|
16681
|
-
return content.includes(
|
|
16987
|
+
const content = fs14.readFileSync(p2, "utf-8");
|
|
16988
|
+
return content.includes(HOOK_MARKER_BEGIN2);
|
|
16682
16989
|
} catch {
|
|
16683
16990
|
return false;
|
|
16684
16991
|
}
|
|
@@ -16692,31 +16999,118 @@ function checkHookStatus(hooksDir) {
|
|
|
16692
16999
|
}
|
|
16693
17000
|
function installHookFile(hookFile) {
|
|
16694
17001
|
let content = "";
|
|
16695
|
-
if (
|
|
16696
|
-
content =
|
|
17002
|
+
if (fs14.existsSync(hookFile)) {
|
|
17003
|
+
content = fs14.readFileSync(hookFile, "utf-8");
|
|
16697
17004
|
} else {
|
|
16698
17005
|
content = "#!/bin/sh\n";
|
|
16699
17006
|
}
|
|
16700
|
-
if (content.includes(
|
|
17007
|
+
if (content.includes(HOOK_MARKER_BEGIN2)) {
|
|
16701
17008
|
return "exists";
|
|
16702
17009
|
}
|
|
16703
|
-
|
|
17010
|
+
fs14.writeFileSync(hookFile, content + HOOK_SNIPPET, { mode: 493 });
|
|
16704
17011
|
return "installed";
|
|
16705
17012
|
}
|
|
16706
17013
|
function uninstallHookFile(hookFile) {
|
|
16707
|
-
if (!
|
|
16708
|
-
const content =
|
|
16709
|
-
if (!content.includes(
|
|
16710
|
-
const regex = new RegExp(`\\n?${
|
|
17014
|
+
if (!fs14.existsSync(hookFile)) return "absent";
|
|
17015
|
+
const content = fs14.readFileSync(hookFile, "utf-8");
|
|
17016
|
+
if (!content.includes(HOOK_MARKER_BEGIN2)) return "missing";
|
|
17017
|
+
const regex = new RegExp(`\\n?${HOOK_MARKER_BEGIN2}[\\s\\S]*?${HOOK_MARKER_END}\\n?`, "g");
|
|
16711
17018
|
const updated = content.replace(regex, "");
|
|
16712
|
-
|
|
17019
|
+
fs14.writeFileSync(hookFile, updated, { mode: 493 });
|
|
16713
17020
|
return "removed";
|
|
16714
17021
|
}
|
|
16715
17022
|
|
|
16716
17023
|
// src/menu.ts
|
|
16717
17024
|
var readline = __toESM(require("readline"), 1);
|
|
16718
|
-
var
|
|
17025
|
+
var path15 = __toESM(require("path"), 1);
|
|
17026
|
+
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
17027
|
+
|
|
17028
|
+
// src/doctor-view.ts
|
|
16719
17029
|
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
17030
|
+
function formatDoctorReport(report) {
|
|
17031
|
+
const lines = [];
|
|
17032
|
+
const push = (l) => lines.push(l);
|
|
17033
|
+
push("");
|
|
17034
|
+
const badge = bg.teal(import_picocolors2.default.bold(colors.ink(" qodewk doctor ")));
|
|
17035
|
+
push(` ${colors.mutedSoft("\u250C")} ${badge} ${import_picocolors2.default.dim(`v${report.version}`)}`);
|
|
17036
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17037
|
+
push(` ${colors.teal("\u25C7")} ${import_picocolors2.default.bold(import_picocolors2.default.white("AI Agent Environment"))}`);
|
|
17038
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17039
|
+
for (const agent of report.agents) {
|
|
17040
|
+
const isAct = agent.status === "active";
|
|
17041
|
+
const icon = isAct ? colors.green("\u2713") : import_picocolors2.default.dim("-");
|
|
17042
|
+
const namePad = agent.name.padEnd(20, ".");
|
|
17043
|
+
const statusText = isAct ? colors.green("Active") : import_picocolors2.default.dim("Not detected");
|
|
17044
|
+
const detail = agent.path ? import_picocolors2.default.dim(` (${agent.path})`) : "";
|
|
17045
|
+
push(` ${colors.mutedSoft("\u2502")} ${icon} ${import_picocolors2.default.white(namePad)} ${statusText}${detail}`);
|
|
17046
|
+
}
|
|
17047
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17048
|
+
push(` ${colors.teal("\u25C7")} ${import_picocolors2.default.bold(import_picocolors2.default.white("Git Hook Telemetry"))}`);
|
|
17049
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17050
|
+
const hookDirText = report.hooks.hooksDir ? import_picocolors2.default.dim(` (${report.hooks.hooksDir})`) : "";
|
|
17051
|
+
const pcIcon = report.hooks.postCommitInstalled ? colors.green("\u2713") : colors.red("\xD7");
|
|
17052
|
+
const pcStatus = report.hooks.postCommitInstalled ? colors.green("Installed") : colors.red("Missing");
|
|
17053
|
+
push(` ${colors.mutedSoft("\u2502")} ${pcIcon} ${import_picocolors2.default.white("post-commit hook ...")} ${pcStatus}${hookDirText}`);
|
|
17054
|
+
const prIcon = report.hooks.postRewriteInstalled ? colors.green("\u2713") : colors.red("\xD7");
|
|
17055
|
+
const prStatus = report.hooks.postRewriteInstalled ? colors.green("Installed") : colors.red("Missing");
|
|
17056
|
+
push(` ${colors.mutedSoft("\u2502")} ${prIcon} ${import_picocolors2.default.white("post-rewrite hook ..")} ${prStatus}`);
|
|
17057
|
+
const bench = report.benchmark;
|
|
17058
|
+
const benchIcon = bench.status === "pass" ? colors.green("\u2713") : bench.status === "warn" ? colors.amber("!") : colors.red("\xD7");
|
|
17059
|
+
const benchColor = bench.status === "pass" ? colors.green : bench.status === "warn" ? colors.amber : colors.red;
|
|
17060
|
+
push(` ${colors.mutedSoft("\u2502")} ${benchIcon} ${import_picocolors2.default.white("Hook spawn latency .")} ${benchColor(`${bench.executionMs} ms`)} ${import_picocolors2.default.dim(`(${bench.message})`)}`);
|
|
17061
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17062
|
+
push(` ${colors.teal("\u25C7")} ${import_picocolors2.default.bold(import_picocolors2.default.white("Local Storage & Pricing"))}`);
|
|
17063
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17064
|
+
const dbIcon = report.storage.healthy ? colors.green("\u2713") : colors.red("\xD7");
|
|
17065
|
+
const dbStatus = report.storage.healthy ? colors.green("Healthy") : colors.red("Failed");
|
|
17066
|
+
const dbDetail = report.storage.healthy ? import_picocolors2.default.dim(` (${report.storage.receiptsCount} receipts, ${report.storage.footprintsCount} footprints)`) : "";
|
|
17067
|
+
push(` ${colors.mutedSoft("\u2502")} ${dbIcon} ${import_picocolors2.default.white("SQLite Database ....")} ${dbStatus}${dbDetail}`);
|
|
17068
|
+
const prcIcon = report.pricing.status === "active" ? colors.green("\u2713") : colors.red("\xD7");
|
|
17069
|
+
const prcStatus = report.pricing.status === "active" ? colors.green("Active") : colors.red("Offline");
|
|
17070
|
+
push(` ${colors.mutedSoft("\u2502")} ${prcIcon} ${import_picocolors2.default.white("Rate Card Registry .")} ${prcStatus} ${import_picocolors2.default.dim(`(${report.pricing.modelsLoaded} model rate cards loaded)`)}`);
|
|
17071
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17072
|
+
if (report.overallStatus === "healthy") {
|
|
17073
|
+
push(` ${colors.coral("\u25C6")} ${import_picocolors2.default.bold(colors.green("All Systems Operational \u2014 Telemetry Ready"))}`);
|
|
17074
|
+
} else if (report.overallStatus === "warning") {
|
|
17075
|
+
push(` ${colors.amber("\u25C6")} ${import_picocolors2.default.bold(colors.amber("Operational with Warnings \u2014 Run `qodewk hook install` to enable automatic recording"))}`);
|
|
17076
|
+
} else {
|
|
17077
|
+
push(` ${colors.red("\u25C6")} ${import_picocolors2.default.bold(colors.red("Diagnostic Issues Detected \u2014 Check Git repository or database status"))}`);
|
|
17078
|
+
}
|
|
17079
|
+
push(` ${colors.mutedSoft("\u2514")}`);
|
|
17080
|
+
push("");
|
|
17081
|
+
return lines.join("\n");
|
|
17082
|
+
}
|
|
17083
|
+
function formatHookTestReport(hooks, benchmark) {
|
|
17084
|
+
const lines = [];
|
|
17085
|
+
const push = (l) => lines.push(l);
|
|
17086
|
+
push("");
|
|
17087
|
+
const badge = bg.teal(import_picocolors2.default.bold(colors.ink(" qodewk hook test ")));
|
|
17088
|
+
push(` ${colors.mutedSoft("\u250C")} ${badge}`);
|
|
17089
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17090
|
+
const pcIcon = hooks.postCommitInstalled ? colors.green("\u2713") : colors.red("\xD7");
|
|
17091
|
+
const pcStatus = hooks.postCommitInstalled ? colors.green("Installed") : colors.red("Missing");
|
|
17092
|
+
push(` ${colors.mutedSoft("\u2502")} ${pcIcon} post-commit hook: ${pcStatus}`);
|
|
17093
|
+
const prIcon = hooks.postRewriteInstalled ? colors.green("\u2713") : colors.red("\xD7");
|
|
17094
|
+
const prStatus = hooks.postRewriteInstalled ? colors.green("Installed") : colors.red("Missing");
|
|
17095
|
+
push(` ${colors.mutedSoft("\u2502")} ${prIcon} post-rewrite hook: ${prStatus}`);
|
|
17096
|
+
const benchIcon = benchmark.status === "pass" ? colors.green("\u2713") : benchmark.status === "warn" ? colors.amber("!") : colors.red("\xD7");
|
|
17097
|
+
const benchColor = benchmark.status === "pass" ? colors.green : benchmark.status === "warn" ? colors.amber : colors.red;
|
|
17098
|
+
push(` ${colors.mutedSoft("\u2502")} ${benchIcon} Detachment Latency: ${benchColor(`${benchmark.executionMs} ms`)}`);
|
|
17099
|
+
push(` ${colors.mutedSoft("\u2502")} ${import_picocolors2.default.dim(benchmark.message)}`);
|
|
17100
|
+
push(` ${colors.mutedSoft("\u2502")}`);
|
|
17101
|
+
if (benchmark.passedInvariant && hooks.markerFound) {
|
|
17102
|
+
push(` ${colors.coral("\u25C6")} ${import_picocolors2.default.bold(colors.green("Non-blocking Hook Verified (< 5ms Invariant Passed)"))}`);
|
|
17103
|
+
} else if (!hooks.markerFound) {
|
|
17104
|
+
push(` ${colors.amber("\u25C6")} ${import_picocolors2.default.bold(colors.amber("Hooks Not Installed \u2014 Run `qodewk hook install`"))}`);
|
|
17105
|
+
} else {
|
|
17106
|
+
push(` ${colors.red("\u25C6")} ${import_picocolors2.default.bold(colors.red("Latency Threshold Exceeded \u2014 Reinstall recommended"))}`);
|
|
17107
|
+
}
|
|
17108
|
+
push(` ${colors.mutedSoft("\u2514")}`);
|
|
17109
|
+
push("");
|
|
17110
|
+
return lines.join("\n");
|
|
17111
|
+
}
|
|
17112
|
+
|
|
17113
|
+
// src/menu.ts
|
|
16720
17114
|
var SHARE_PAYLOAD_MAX_BYTES = 5e4;
|
|
16721
17115
|
var BANNER_LINES = [
|
|
16722
17116
|
" \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",
|
|
@@ -16763,6 +17157,12 @@ var MENU_ITEMS = [
|
|
|
16763
17157
|
label: "Git Notes Management",
|
|
16764
17158
|
description: "Inspect & attach receipts to refs/notes/qodewk"
|
|
16765
17159
|
},
|
|
17160
|
+
{
|
|
17161
|
+
id: "doctor",
|
|
17162
|
+
key: "7",
|
|
17163
|
+
label: "System Health & Diagnostics",
|
|
17164
|
+
description: "Audit AI agents, Git hooks, SQLite & pricing registry (doctor)"
|
|
17165
|
+
},
|
|
16766
17166
|
{
|
|
16767
17167
|
id: "exit",
|
|
16768
17168
|
key: "0",
|
|
@@ -16808,7 +17208,45 @@ var RECEIPT_HORIZON_ITEMS = [
|
|
|
16808
17208
|
description: "Return to previous screen"
|
|
16809
17209
|
}
|
|
16810
17210
|
];
|
|
16811
|
-
|
|
17211
|
+
var SHARE_HORIZON_ITEMS = [
|
|
17212
|
+
{
|
|
17213
|
+
id: "latest",
|
|
17214
|
+
key: "1",
|
|
17215
|
+
label: "Latest Changes (Default)",
|
|
17216
|
+
description: "Publish git working tree or latest commit to cloud"
|
|
17217
|
+
},
|
|
17218
|
+
{
|
|
17219
|
+
id: "today",
|
|
17220
|
+
key: "2",
|
|
17221
|
+
label: "Today's Work Session",
|
|
17222
|
+
description: "Publish commits & agent activity since midnight (--today)"
|
|
17223
|
+
},
|
|
17224
|
+
{
|
|
17225
|
+
id: "yesterday",
|
|
17226
|
+
key: "3",
|
|
17227
|
+
label: "Yesterday's Work",
|
|
17228
|
+
description: "Publish activity from yesterday to now (--since yesterday)"
|
|
17229
|
+
},
|
|
17230
|
+
{
|
|
17231
|
+
id: "week",
|
|
17232
|
+
key: "4",
|
|
17233
|
+
label: "Past 7 Days (Sprint)",
|
|
17234
|
+
description: "Publish weekly sprint telemetry across all agents (--since 7d)"
|
|
17235
|
+
},
|
|
17236
|
+
{
|
|
17237
|
+
id: "custom",
|
|
17238
|
+
key: "5",
|
|
17239
|
+
label: "Custom Duration",
|
|
17240
|
+
description: "Specify hours (e.g. 12h) or days (e.g. 3d, 14d) to publish"
|
|
17241
|
+
},
|
|
17242
|
+
{
|
|
17243
|
+
id: "back",
|
|
17244
|
+
key: "0",
|
|
17245
|
+
label: "Back to Main Menu",
|
|
17246
|
+
description: "Return to previous screen"
|
|
17247
|
+
}
|
|
17248
|
+
];
|
|
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 = {}) {
|
|
16812
17250
|
const lines = [];
|
|
16813
17251
|
const push = (line) => lines.push(line);
|
|
16814
17252
|
if (options.showBanner ?? true) {
|
|
@@ -16819,21 +17257,31 @@ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Co
|
|
|
16819
17257
|
}
|
|
16820
17258
|
}
|
|
16821
17259
|
push("");
|
|
16822
|
-
const badge = bg.teal(
|
|
16823
|
-
push(` ${colors.mutedSoft("\u250C")} ${badge} ${
|
|
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")}`);
|
|
16824
17262
|
push(` ${colors.mutedSoft("\u2502")}`);
|
|
16825
17263
|
if (options.actionContext) {
|
|
16826
|
-
push(` ${colors.teal("\u25C7")} ${
|
|
17264
|
+
push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Action:")} ${import_picocolors3.default.white(options.actionContext)}`);
|
|
16827
17265
|
push(` ${colors.mutedSoft("\u2502")}`);
|
|
16828
17266
|
} else {
|
|
16829
17267
|
const repo = options.repoContext?.alias || "Qodewk";
|
|
16830
17268
|
const branch = options.repoContext?.branch ? `(${options.repoContext.branch})` : "";
|
|
16831
|
-
push(` ${colors.teal("\u25C7")} ${
|
|
17269
|
+
push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Repository:")} ${import_picocolors3.default.white(repo)} ${import_picocolors3.default.dim(branch)}`);
|
|
16832
17270
|
push(` ${colors.mutedSoft("\u2502")}`);
|
|
16833
|
-
|
|
17271
|
+
let telemetryLabel = "Multi-Model Rate Cards (Active)";
|
|
17272
|
+
try {
|
|
17273
|
+
const agEnv = discoverAntigravityEnvironment();
|
|
17274
|
+
if (agEnv && agEnv.mode === "observed") {
|
|
17275
|
+
telemetryLabel = "Google Antigravity (Active)";
|
|
17276
|
+
} else if (agEnv) {
|
|
17277
|
+
telemetryLabel = "Google Antigravity Detected";
|
|
17278
|
+
}
|
|
17279
|
+
} catch {
|
|
17280
|
+
}
|
|
17281
|
+
push(` ${colors.teal("\u25C7")} ${import_picocolors3.default.dim("Telemetry:")} ${import_picocolors3.default.white(telemetryLabel)}`);
|
|
16834
17282
|
push(` ${colors.mutedSoft("\u2502")}`);
|
|
16835
17283
|
}
|
|
16836
|
-
push(` ${colors.coral("\u25C6")} ${
|
|
17284
|
+
push(` ${colors.coral("\u25C6")} ${import_picocolors3.default.bold(import_picocolors3.default.white(title))}`);
|
|
16837
17285
|
push(` ${colors.mutedSoft("\u2502")}`);
|
|
16838
17286
|
const selectedItem = items[selectedIndex] || items[0];
|
|
16839
17287
|
for (let i2 = 0; i2 < items.length; i2++) {
|
|
@@ -16841,44 +17289,44 @@ function buildMenuFrame(selectedIndex, items = MENU_ITEMS, title = "Telemetry Co
|
|
|
16841
17289
|
const isSelected = i2 === selectedIndex;
|
|
16842
17290
|
if (isSelected) {
|
|
16843
17291
|
push(
|
|
16844
|
-
` ${colors.mutedSoft("\u2502")} ${
|
|
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))}`
|
|
16845
17293
|
);
|
|
16846
17294
|
} else {
|
|
16847
17295
|
push(
|
|
16848
|
-
` ${colors.mutedSoft("\u2502")} ${
|
|
17296
|
+
` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.dim(item.key)} ${import_picocolors3.default.dim(import_picocolors3.default.white(item.label))}`
|
|
16849
17297
|
);
|
|
16850
17298
|
}
|
|
16851
17299
|
}
|
|
16852
17300
|
const divider = colors.mutedSoft("\u2500".repeat(58));
|
|
16853
17301
|
push(` ${colors.mutedSoft("\u2502")}`);
|
|
16854
17302
|
push(` ${colors.mutedSoft("\u2502")} ${divider}`);
|
|
16855
|
-
push(` ${colors.mutedSoft("\u2502")} ${
|
|
17303
|
+
push(` ${colors.mutedSoft("\u2502")} ${import_picocolors3.default.bold(import_picocolors3.default.dim("Description"))}`);
|
|
16856
17304
|
push(` ${colors.mutedSoft("\u2502")} ${colors.amber(selectedItem.description)}`);
|
|
16857
17305
|
push(` ${colors.mutedSoft("\u2502")} ${divider}`);
|
|
16858
17306
|
push(` ${colors.mutedSoft("\u2502")}`);
|
|
16859
|
-
push(` ${colors.mutedSoft("\u2502")} ${
|
|
16860
|
-
push(` ${colors.mutedSoft("\u2502")} ${colors.green("[\u2713]")} ${
|
|
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")}`);
|
|
16861
17309
|
push(` ${colors.mutedSoft("\u2514")}`);
|
|
16862
17310
|
push("");
|
|
16863
17311
|
return lines.join("\n");
|
|
16864
17312
|
}
|
|
16865
17313
|
function askLine(promptText) {
|
|
16866
|
-
return new Promise((
|
|
17314
|
+
return new Promise((resolve6) => {
|
|
16867
17315
|
const rl = readline.createInterface({
|
|
16868
17316
|
input: process.stdin,
|
|
16869
17317
|
output: process.stdout
|
|
16870
17318
|
});
|
|
16871
17319
|
rl.question(promptText, (answer) => {
|
|
16872
17320
|
rl.close();
|
|
16873
|
-
|
|
17321
|
+
resolve6(answer.trim());
|
|
16874
17322
|
});
|
|
16875
17323
|
});
|
|
16876
17324
|
}
|
|
16877
17325
|
function waitForKeyToReturn() {
|
|
16878
|
-
return new Promise((
|
|
16879
|
-
console.log(
|
|
17326
|
+
return new Promise((resolve6) => {
|
|
17327
|
+
console.log(import_picocolors3.default.dim("\n Press any key or Enter to return to menu..."));
|
|
16880
17328
|
if (!process.stdin.isTTY) {
|
|
16881
|
-
|
|
17329
|
+
resolve6();
|
|
16882
17330
|
return;
|
|
16883
17331
|
}
|
|
16884
17332
|
const wasRaw = process.stdin.isRaw;
|
|
@@ -16887,11 +17335,90 @@ function waitForKeyToReturn() {
|
|
|
16887
17335
|
const onKey = () => {
|
|
16888
17336
|
process.stdin.removeListener("data", onKey);
|
|
16889
17337
|
if (wasRaw !== void 0) process.stdin.setRawMode(wasRaw);
|
|
16890
|
-
|
|
17338
|
+
resolve6();
|
|
16891
17339
|
};
|
|
16892
17340
|
process.stdin.once("data", onKey);
|
|
16893
17341
|
});
|
|
16894
17342
|
}
|
|
17343
|
+
function waitForKeyOrAction(promptText) {
|
|
17344
|
+
return new Promise((resolve6) => {
|
|
17345
|
+
console.log(promptText);
|
|
17346
|
+
if (!process.stdin.isTTY) {
|
|
17347
|
+
resolve6("");
|
|
17348
|
+
return;
|
|
17349
|
+
}
|
|
17350
|
+
const wasRaw = process.stdin.isRaw;
|
|
17351
|
+
process.stdin.setRawMode(true);
|
|
17352
|
+
process.stdin.resume();
|
|
17353
|
+
const onKey = (data) => {
|
|
17354
|
+
process.stdin.removeListener("data", onKey);
|
|
17355
|
+
if (wasRaw !== void 0) process.stdin.setRawMode(wasRaw);
|
|
17356
|
+
const str = data.toString();
|
|
17357
|
+
resolve6(str);
|
|
17358
|
+
};
|
|
17359
|
+
process.stdin.once("data", onKey);
|
|
17360
|
+
});
|
|
17361
|
+
}
|
|
17362
|
+
async function publishReceiptToCloud(receipt) {
|
|
17363
|
+
if (process.env.QODEWK_TELEMETRY === "off") {
|
|
17364
|
+
console.log(import_picocolors3.default.yellow("\n Cloud publishing is disabled by QODEWK_TELEMETRY=off."));
|
|
17365
|
+
return null;
|
|
17366
|
+
}
|
|
17367
|
+
const sanitized = sanitizeReceiptForShare(receipt);
|
|
17368
|
+
let body = JSON.stringify(sanitized);
|
|
17369
|
+
if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES && sanitized.ai.sessions) {
|
|
17370
|
+
const trimmed2 = {
|
|
17371
|
+
...sanitized,
|
|
17372
|
+
ai: { ...sanitized.ai, sessions: void 0 }
|
|
17373
|
+
};
|
|
17374
|
+
body = JSON.stringify(trimmed2);
|
|
17375
|
+
}
|
|
17376
|
+
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."));
|
|
17378
|
+
return null;
|
|
17379
|
+
}
|
|
17380
|
+
const endpoint = resolveApiUrl();
|
|
17381
|
+
console.log(import_picocolors3.default.dim(`
|
|
17382
|
+
[\xB7] Publishing receipt to ${endpoint}...`));
|
|
17383
|
+
try {
|
|
17384
|
+
const response = await fetch(endpoint, {
|
|
17385
|
+
method: "POST",
|
|
17386
|
+
headers: {
|
|
17387
|
+
"Content-Type": "application/json",
|
|
17388
|
+
"Content-Length": String(Buffer.byteLength(body, "utf-8"))
|
|
17389
|
+
},
|
|
17390
|
+
body
|
|
17391
|
+
});
|
|
17392
|
+
if (!response.ok) {
|
|
17393
|
+
const errText = await response.text().catch(() => "");
|
|
17394
|
+
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}`));
|
|
17398
|
+
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"));
|
|
17400
|
+
return null;
|
|
17401
|
+
}
|
|
17402
|
+
throw new Error(`API responded with ${response.status}: ${errText.slice(0, 100)}`);
|
|
17403
|
+
}
|
|
17404
|
+
const data = await response.json();
|
|
17405
|
+
const db = new LocalStateDB();
|
|
17406
|
+
db.saveReceipt(sanitized, data.claimToken);
|
|
17407
|
+
db.close();
|
|
17408
|
+
console.log("");
|
|
17409
|
+
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"));
|
|
17413
|
+
await renderTerminalReceipt(sanitized, data.url);
|
|
17414
|
+
return data;
|
|
17415
|
+
} catch (err) {
|
|
17416
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
17417
|
+
console.error(import_picocolors3.default.red(`
|
|
17418
|
+
Share failed: ${message}`));
|
|
17419
|
+
return null;
|
|
17420
|
+
}
|
|
17421
|
+
}
|
|
16895
17422
|
var cachedRepoContext = null;
|
|
16896
17423
|
async function getRepoContext() {
|
|
16897
17424
|
if (cachedRepoContext) return cachedRepoContext;
|
|
@@ -16905,7 +17432,7 @@ async function getRepoContext() {
|
|
|
16905
17432
|
}
|
|
16906
17433
|
const branchSummary = await git.branch();
|
|
16907
17434
|
const branch = branchSummary.current || "HEAD";
|
|
16908
|
-
const alias =
|
|
17435
|
+
const alias = path15.basename(process.cwd());
|
|
16909
17436
|
cachedRepoContext = { alias, branch };
|
|
16910
17437
|
return cachedRepoContext;
|
|
16911
17438
|
} catch {
|
|
@@ -16916,7 +17443,7 @@ async function getRepoContext() {
|
|
|
16916
17443
|
async function runInteractiveMenu() {
|
|
16917
17444
|
if (!process.stdin.isTTY) {
|
|
16918
17445
|
console.log(buildMenuFrame(0));
|
|
16919
|
-
console.log(
|
|
17446
|
+
console.log(import_picocolors3.default.yellow("Interactive menu requires a TTY terminal. Use `qodewk --help` for commands."));
|
|
16920
17447
|
return;
|
|
16921
17448
|
}
|
|
16922
17449
|
const repoContext = await getRepoContext();
|
|
@@ -16924,12 +17451,16 @@ async function runInteractiveMenu() {
|
|
|
16924
17451
|
let selectedIndex = 0;
|
|
16925
17452
|
let active = true;
|
|
16926
17453
|
let lastRenderedLinesCount = 0;
|
|
16927
|
-
const getActiveItems = () =>
|
|
17454
|
+
const getActiveItems = () => {
|
|
17455
|
+
if (currentScreen === "receipt_horizon") return RECEIPT_HORIZON_ITEMS;
|
|
17456
|
+
if (currentScreen === "share_horizon") return SHARE_HORIZON_ITEMS;
|
|
17457
|
+
return MENU_ITEMS;
|
|
17458
|
+
};
|
|
16928
17459
|
const render = () => {
|
|
16929
17460
|
const items = getActiveItems();
|
|
16930
|
-
const title = currentScreen === "main" ? "Telemetry Control Panel" : "Generate Local Receipt";
|
|
16931
|
-
const subtitle = currentScreen === "main" ? "\u2191\u2193 move \xB7 enter select \xB7 0-
|
|
16932
|
-
const actionContext = currentScreen === "receipt_horizon" ? "Generate Local Receipt" : void 0;
|
|
17461
|
+
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";
|
|
17463
|
+
const actionContext = currentScreen === "receipt_horizon" ? "Generate Local Receipt" : currentScreen === "share_horizon" ? "Publish Receipt to Cloud" : void 0;
|
|
16933
17464
|
const showBanner = currentScreen === "main";
|
|
16934
17465
|
const frame = buildMenuFrame(selectedIndex, items, title, subtitle, {
|
|
16935
17466
|
repoContext,
|
|
@@ -16969,25 +17500,70 @@ async function runInteractiveMenu() {
|
|
|
16969
17500
|
since = "7d";
|
|
16970
17501
|
label = "past 7 days weekly sprint (--since 7d)";
|
|
16971
17502
|
} else if (item.id === "custom") {
|
|
16972
|
-
console.log(
|
|
16973
|
-
console.log(
|
|
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"));
|
|
16974
17505
|
const input = await askLine(" \u203A Enter duration or date (e.g. 12h, 3d, 2026-10-01): ");
|
|
16975
17506
|
if (input) {
|
|
16976
17507
|
since = input;
|
|
16977
17508
|
label = `custom range: ${input}`;
|
|
16978
17509
|
}
|
|
16979
17510
|
}
|
|
16980
|
-
console.log(
|
|
17511
|
+
console.log(import_picocolors3.default.dim(` [\xB7] Generating local receipt for ${label}...`));
|
|
16981
17512
|
try {
|
|
16982
17513
|
const receipt = await generateReceipt({ since, isPublic: false });
|
|
16983
17514
|
const db = new LocalStateDB();
|
|
16984
17515
|
db.saveReceipt(receipt);
|
|
16985
17516
|
db.close();
|
|
16986
17517
|
await renderTerminalReceipt(receipt);
|
|
17518
|
+
console.log("");
|
|
17519
|
+
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")}`
|
|
17521
|
+
);
|
|
17522
|
+
if (actionKey.trim().toLowerCase() === "s") {
|
|
17523
|
+
await publishReceiptToCloud(receipt);
|
|
17524
|
+
await waitForKeyToReturn();
|
|
17525
|
+
}
|
|
16987
17526
|
} catch (err) {
|
|
16988
17527
|
const message = err instanceof Error ? err.message : String(err);
|
|
16989
|
-
console.error(
|
|
17528
|
+
console.error(import_picocolors3.default.red(`
|
|
16990
17529
|
Failed to generate receipt: ${message}`));
|
|
17530
|
+
await waitForKeyToReturn();
|
|
17531
|
+
}
|
|
17532
|
+
currentScreen = "main";
|
|
17533
|
+
selectedIndex = 0;
|
|
17534
|
+
};
|
|
17535
|
+
const executeShareHorizon = async (item) => {
|
|
17536
|
+
cleanup();
|
|
17537
|
+
console.log("");
|
|
17538
|
+
lastRenderedLinesCount = 0;
|
|
17539
|
+
let since = void 0;
|
|
17540
|
+
let label = "latest git diff";
|
|
17541
|
+
if (item.id === "today") {
|
|
17542
|
+
since = "today";
|
|
17543
|
+
label = "today's work session (--today)";
|
|
17544
|
+
} else if (item.id === "yesterday") {
|
|
17545
|
+
since = "yesterday";
|
|
17546
|
+
label = "yesterday's work (--since yesterday)";
|
|
17547
|
+
} else if (item.id === "week") {
|
|
17548
|
+
since = "7d";
|
|
17549
|
+
label = "past 7 days weekly sprint (--since 7d)";
|
|
17550
|
+
} 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"));
|
|
17553
|
+
const input = await askLine(" \u203A Enter duration or date (e.g. 12h, 3d, 2026-10-01): ");
|
|
17554
|
+
if (input) {
|
|
17555
|
+
since = input;
|
|
17556
|
+
label = `custom range: ${input}`;
|
|
17557
|
+
}
|
|
17558
|
+
}
|
|
17559
|
+
console.log(import_picocolors3.default.dim(` [\xB7] Generating and publishing receipt for ${label}...`));
|
|
17560
|
+
try {
|
|
17561
|
+
const receipt = await generateReceipt({ since, isPublic: false });
|
|
17562
|
+
await publishReceiptToCloud(receipt);
|
|
17563
|
+
} catch (err) {
|
|
17564
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
17565
|
+
console.error(import_picocolors3.default.red(`
|
|
17566
|
+
Share failed: ${message}`));
|
|
16991
17567
|
}
|
|
16992
17568
|
await waitForKeyToReturn();
|
|
16993
17569
|
currentScreen = "main";
|
|
@@ -17000,8 +17576,8 @@ async function runInteractiveMenu() {
|
|
|
17000
17576
|
const selectedItem = MENU_ITEMS[selectedIndex];
|
|
17001
17577
|
switch (selectedItem.id) {
|
|
17002
17578
|
case "audit": {
|
|
17003
|
-
console.log(
|
|
17004
|
-
console.log(
|
|
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"));
|
|
17005
17581
|
let defaultBase = "origin/main";
|
|
17006
17582
|
try {
|
|
17007
17583
|
defaultBase = await detectDefaultBaseBranch(process.cwd());
|
|
@@ -17013,7 +17589,7 @@ async function runInteractiveMenu() {
|
|
|
17013
17589
|
const head = await askLine(
|
|
17014
17590
|
` \u203A Head git ref or commit SHA [default: HEAD]: `
|
|
17015
17591
|
);
|
|
17016
|
-
console.log(
|
|
17592
|
+
console.log(import_picocolors3.default.dim("\n [\xB7] Auditing git revision range..."));
|
|
17017
17593
|
try {
|
|
17018
17594
|
const receipt = await generateReceipt({
|
|
17019
17595
|
baseSha: base || defaultBase,
|
|
@@ -17026,71 +17602,15 @@ async function runInteractiveMenu() {
|
|
|
17026
17602
|
await renderTerminalReceipt(receipt);
|
|
17027
17603
|
} catch (err) {
|
|
17028
17604
|
const message = err instanceof Error ? err.message : String(err);
|
|
17029
|
-
console.error(
|
|
17605
|
+
console.error(import_picocolors3.default.red(`
|
|
17030
17606
|
Audit failed: ${message}`));
|
|
17031
17607
|
}
|
|
17032
17608
|
await waitForKeyToReturn();
|
|
17033
17609
|
break;
|
|
17034
17610
|
}
|
|
17035
17611
|
case "share": {
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
const receipt = await generateReceipt({ isPublic: false });
|
|
17039
|
-
if (process.env.QODEWK_TELEMETRY === "off") {
|
|
17040
|
-
console.log(import_picocolors2.default.yellow("\n Cloud publishing is disabled by QODEWK_TELEMETRY=off."));
|
|
17041
|
-
await renderTerminalReceipt(receipt);
|
|
17042
|
-
await waitForKeyToReturn();
|
|
17043
|
-
break;
|
|
17044
|
-
}
|
|
17045
|
-
const sanitized = sanitizeReceiptForShare(receipt);
|
|
17046
|
-
let body = JSON.stringify(sanitized);
|
|
17047
|
-
if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES && sanitized.ai.sessions) {
|
|
17048
|
-
const trimmed2 = {
|
|
17049
|
-
...sanitized,
|
|
17050
|
-
ai: { ...sanitized.ai, sessions: void 0 }
|
|
17051
|
-
};
|
|
17052
|
-
body = JSON.stringify(trimmed2);
|
|
17053
|
-
}
|
|
17054
|
-
const endpoint = resolveApiUrl();
|
|
17055
|
-
console.log(import_picocolors2.default.dim(` [\xB7] Uploading metadata to ${endpoint}...`));
|
|
17056
|
-
const response = await fetch(endpoint, {
|
|
17057
|
-
method: "POST",
|
|
17058
|
-
headers: {
|
|
17059
|
-
"Content-Type": "application/json",
|
|
17060
|
-
"Content-Length": String(Buffer.byteLength(body, "utf-8"))
|
|
17061
|
-
},
|
|
17062
|
-
body
|
|
17063
|
-
});
|
|
17064
|
-
if (!response.ok) {
|
|
17065
|
-
const errText = await response.text().catch(() => "");
|
|
17066
|
-
if (response.status === 503) {
|
|
17067
|
-
console.log(import_picocolors2.default.yellow("\n Notice: Remote server requires durable storage (Supabase or PostgreSQL) in production"));
|
|
17068
|
-
console.log(import_picocolors2.default.dim(" to protect receipts from serverless cold-start data loss."));
|
|
17069
|
-
console.log(import_picocolors2.default.dim(` Endpoint: ${endpoint}`));
|
|
17070
|
-
console.log(colors.green("\n [\u2713] Your receipt is safely saved locally in: ~/.qodewk/state.db"));
|
|
17071
|
-
console.log(import_picocolors2.default.dim(" You can also save it as a local Git note: qodewk --notes\n"));
|
|
17072
|
-
await renderTerminalReceipt(sanitized);
|
|
17073
|
-
await waitForKeyToReturn();
|
|
17074
|
-
break;
|
|
17075
|
-
}
|
|
17076
|
-
throw new Error(`API responded with ${response.status}${errText ? `: ${errText.slice(0, 100)}` : ""}`);
|
|
17077
|
-
}
|
|
17078
|
-
const data = await response.json();
|
|
17079
|
-
const db = new LocalStateDB();
|
|
17080
|
-
db.saveReceipt(sanitized, data.claimToken);
|
|
17081
|
-
db.close();
|
|
17082
|
-
console.log("");
|
|
17083
|
-
console.log(colors.green(" [\u2713] Published successfully."));
|
|
17084
|
-
console.log(` ${import_picocolors2.default.dim("Public URL:")} ${import_picocolors2.default.underline(import_picocolors2.default.cyan(data.url))}`);
|
|
17085
|
-
console.log(` ${import_picocolors2.default.bold(colors.amber("Claim token:"))} ${colors.amber(data.claimToken)}`);
|
|
17086
|
-
console.log(import_picocolors2.default.dim(" (Saved to ~/.qodewk/state.db for future authorship proofs)\n"));
|
|
17087
|
-
await renderTerminalReceipt(sanitized, data.url);
|
|
17088
|
-
} catch (err) {
|
|
17089
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
17090
|
-
console.error(import_picocolors2.default.red(`
|
|
17091
|
-
Share failed: ${message}`));
|
|
17092
|
-
}
|
|
17093
|
-
await waitForKeyToReturn();
|
|
17612
|
+
currentScreen = "share_horizon";
|
|
17613
|
+
selectedIndex = 0;
|
|
17094
17614
|
break;
|
|
17095
17615
|
}
|
|
17096
17616
|
case "hooks": {
|
|
@@ -17105,10 +17625,14 @@ async function runInteractiveMenu() {
|
|
|
17105
17625
|
await manageGitNotesSubmenu();
|
|
17106
17626
|
break;
|
|
17107
17627
|
}
|
|
17628
|
+
case "doctor": {
|
|
17629
|
+
await runDoctorDiagnosticsAction();
|
|
17630
|
+
break;
|
|
17631
|
+
}
|
|
17108
17632
|
case "exit": {
|
|
17109
17633
|
active = false;
|
|
17110
17634
|
cleanup();
|
|
17111
|
-
console.log(
|
|
17635
|
+
console.log(import_picocolors3.default.dim(" Exited Qodewk.\n"));
|
|
17112
17636
|
process.exit(0);
|
|
17113
17637
|
return;
|
|
17114
17638
|
}
|
|
@@ -17117,31 +17641,32 @@ async function runInteractiveMenu() {
|
|
|
17117
17641
|
const manageHooksSubmenu = async () => {
|
|
17118
17642
|
const hooksDir = resolveGitHooksDir();
|
|
17119
17643
|
const status = checkHookStatus(hooksDir);
|
|
17120
|
-
console.log(
|
|
17121
|
-
console.log(
|
|
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"));
|
|
17122
17646
|
if (!status.isGit) {
|
|
17123
|
-
console.log(
|
|
17647
|
+
console.log(import_picocolors3.default.yellow(" Not inside a Git repository. Hooks cannot be configured."));
|
|
17124
17648
|
await waitForKeyToReturn();
|
|
17125
17649
|
return;
|
|
17126
17650
|
}
|
|
17127
|
-
console.log(` Hooks directory: ${
|
|
17651
|
+
console.log(` Hooks directory: ${import_picocolors3.default.dim(status.hooksDir || "None")}`);
|
|
17128
17652
|
console.log(
|
|
17129
|
-
` post-commit: ${status.postCommitInstalled ? colors.green("[\u2713 Installed]") :
|
|
17653
|
+
` post-commit: ${status.postCommitInstalled ? colors.green("[\u2713 Installed]") : import_picocolors3.default.dim("[\xB7 Not installed]")}`
|
|
17130
17654
|
);
|
|
17131
17655
|
console.log(
|
|
17132
|
-
` post-rewrite: ${status.postRewriteInstalled ? colors.green("[\u2713 Installed]") :
|
|
17656
|
+
` post-rewrite: ${status.postRewriteInstalled ? colors.green("[\u2713 Installed]") : import_picocolors3.default.dim("[\xB7 Not installed]")}`
|
|
17133
17657
|
);
|
|
17134
17658
|
console.log("");
|
|
17135
17659
|
console.log(" [1] Install non-blocking hooks (< 5ms background recorder)");
|
|
17136
17660
|
console.log(" [2] Uninstall Qodewk hooks");
|
|
17661
|
+
console.log(" [3] Test & benchmark hook latency (< 5ms invariant)");
|
|
17137
17662
|
console.log(" [0] Back to main menu");
|
|
17138
17663
|
console.log("");
|
|
17139
|
-
const choice = await askLine(" \u203A Select option [0-
|
|
17664
|
+
const choice = await askLine(" \u203A Select option [0-3]: ");
|
|
17140
17665
|
if (choice === "1") {
|
|
17141
17666
|
if (status.hooksDir) {
|
|
17142
17667
|
const targets = ["post-commit", "post-rewrite"];
|
|
17143
17668
|
for (const t2 of targets) {
|
|
17144
|
-
installHookFile(
|
|
17669
|
+
installHookFile(path15.join(status.hooksDir, t2));
|
|
17145
17670
|
}
|
|
17146
17671
|
console.log(colors.green("\n [\u2713] Non-blocking hooks installed successfully."));
|
|
17147
17672
|
}
|
|
@@ -17149,16 +17674,20 @@ async function runInteractiveMenu() {
|
|
|
17149
17674
|
if (status.hooksDir) {
|
|
17150
17675
|
const targets = ["post-commit", "post-rewrite"];
|
|
17151
17676
|
for (const t2 of targets) {
|
|
17152
|
-
uninstallHookFile(
|
|
17677
|
+
uninstallHookFile(path15.join(status.hooksDir, t2));
|
|
17153
17678
|
}
|
|
17154
17679
|
console.log(colors.green("\n [\u2713] Qodewk hooks removed."));
|
|
17155
17680
|
}
|
|
17681
|
+
} else if (choice === "3") {
|
|
17682
|
+
const hooks = auditGitHooks();
|
|
17683
|
+
const bench = await benchmarkHookLatency();
|
|
17684
|
+
console.log(formatHookTestReport(hooks, bench));
|
|
17156
17685
|
}
|
|
17157
17686
|
await waitForKeyToReturn();
|
|
17158
17687
|
};
|
|
17159
17688
|
const manageGitNotesSubmenu = async () => {
|
|
17160
|
-
console.log(
|
|
17161
|
-
console.log(
|
|
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"));
|
|
17162
17691
|
console.log(" [1] List commits with attached Qodewk notes");
|
|
17163
17692
|
console.log(" [2] Show receipt note on a commit (default: HEAD)");
|
|
17164
17693
|
console.log(" [3] Attach receipt note to a Git commit (default: HEAD)");
|
|
@@ -17169,17 +17698,17 @@ async function runInteractiveMenu() {
|
|
|
17169
17698
|
try {
|
|
17170
17699
|
const shas = await listGitReceiptNotes();
|
|
17171
17700
|
if (shas.length === 0) {
|
|
17172
|
-
console.log(
|
|
17701
|
+
console.log(import_picocolors3.default.yellow("\n No Qodewk Git notes found in repository."));
|
|
17173
17702
|
} else {
|
|
17174
|
-
console.log(
|
|
17703
|
+
console.log(import_picocolors3.default.bold(`
|
|
17175
17704
|
Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
|
|
17176
17705
|
for (const sha of shas) {
|
|
17177
|
-
console.log(` ${
|
|
17706
|
+
console.log(` ${import_picocolors3.default.cyan(sha.slice(0, 10))} ${import_picocolors3.default.dim(sha)}`);
|
|
17178
17707
|
}
|
|
17179
17708
|
}
|
|
17180
17709
|
} catch (err) {
|
|
17181
17710
|
const message = err instanceof Error ? err.message : String(err);
|
|
17182
|
-
console.error(
|
|
17711
|
+
console.error(import_picocolors3.default.red(`
|
|
17183
17712
|
Error listing Git notes: ${message}`));
|
|
17184
17713
|
}
|
|
17185
17714
|
} else if (choice === "2") {
|
|
@@ -17187,20 +17716,20 @@ async function runInteractiveMenu() {
|
|
|
17187
17716
|
try {
|
|
17188
17717
|
const receipt = await readGitReceiptNote(commit);
|
|
17189
17718
|
if (!receipt) {
|
|
17190
|
-
console.log(
|
|
17719
|
+
console.log(import_picocolors3.default.yellow(`
|
|
17191
17720
|
No Qodewk receipt note found on commit '${commit}'.`));
|
|
17192
17721
|
} else {
|
|
17193
17722
|
await renderTerminalReceipt(receipt);
|
|
17194
17723
|
}
|
|
17195
17724
|
} catch (err) {
|
|
17196
17725
|
const message = err instanceof Error ? err.message : String(err);
|
|
17197
|
-
console.error(
|
|
17726
|
+
console.error(import_picocolors3.default.red(`
|
|
17198
17727
|
Error reading Git note: ${message}`));
|
|
17199
17728
|
}
|
|
17200
17729
|
} else if (choice === "3") {
|
|
17201
17730
|
const commit = await askLine(" \u203A Commit SHA to attach note [default: HEAD]: ") || "HEAD";
|
|
17202
17731
|
try {
|
|
17203
|
-
console.log(
|
|
17732
|
+
console.log(import_picocolors3.default.dim(`
|
|
17204
17733
|
[\xB7] Generating receipt for ${commit}...`));
|
|
17205
17734
|
const receipt = await generateReceipt({ headSha: commit });
|
|
17206
17735
|
await writeGitReceiptNote(receipt.repository.headSha, receipt);
|
|
@@ -17210,30 +17739,30 @@ async function runInteractiveMenu() {
|
|
|
17210
17739
|
);
|
|
17211
17740
|
} catch (err) {
|
|
17212
17741
|
const message = err instanceof Error ? err.message : String(err);
|
|
17213
|
-
console.error(
|
|
17742
|
+
console.error(import_picocolors3.default.red(`
|
|
17214
17743
|
Error writing Git note: ${message}`));
|
|
17215
17744
|
}
|
|
17216
17745
|
}
|
|
17217
17746
|
await waitForKeyToReturn();
|
|
17218
17747
|
};
|
|
17219
17748
|
const showStorageStatus = async () => {
|
|
17220
|
-
console.log(
|
|
17221
|
-
console.log(
|
|
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"));
|
|
17222
17751
|
try {
|
|
17223
17752
|
const db = new LocalStateDB();
|
|
17224
17753
|
const stats = db.getStats();
|
|
17225
17754
|
const recent = db.getRecentReceipts(5);
|
|
17226
17755
|
db.close();
|
|
17227
|
-
console.log(` Database path: ${
|
|
17228
|
-
console.log(` Total saved receipts: ${
|
|
17229
|
-
console.log(` Total agent footprints: ${
|
|
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)))}`);
|
|
17230
17759
|
console.log("");
|
|
17231
17760
|
if (recent.length === 0) {
|
|
17232
|
-
console.log(
|
|
17761
|
+
console.log(import_picocolors3.default.dim(" No stored receipts yet. Run 'Generate Local Receipt' to record your first."));
|
|
17233
17762
|
} else {
|
|
17234
|
-
console.log(
|
|
17235
|
-
console.log(
|
|
17236
|
-
console.log(
|
|
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)));
|
|
17237
17766
|
for (const item of recent) {
|
|
17238
17767
|
const id = item.receipt.receipt.id.slice(0, 24).padEnd(26);
|
|
17239
17768
|
const date = item.receipt.receipt.createdAt.slice(0, 10).padEnd(12);
|
|
@@ -17243,10 +17772,37 @@ async function runInteractiveMenu() {
|
|
|
17243
17772
|
}
|
|
17244
17773
|
}
|
|
17245
17774
|
console.log("");
|
|
17246
|
-
console.log(` ${colors.green("[\u2713]")} ${
|
|
17775
|
+
console.log(` ${colors.green("[\u2713]")} ${import_picocolors3.default.dim("Privacy guarantee: raw source code is never stored in SQLite")}`);
|
|
17776
|
+
if (recent.length > 0) {
|
|
17777
|
+
console.log("");
|
|
17778
|
+
const ans = await askLine(" \u203A Enter receipt ID prefix to publish to cloud [Enter to return]: ");
|
|
17779
|
+
if (ans) {
|
|
17780
|
+
const matched = recent.find((r2) => r2.receipt.receipt.id.toLowerCase().startsWith(ans.toLowerCase()));
|
|
17781
|
+
if (matched) {
|
|
17782
|
+
await publishReceiptToCloud(matched.receipt);
|
|
17783
|
+
await waitForKeyToReturn();
|
|
17784
|
+
return;
|
|
17785
|
+
} else {
|
|
17786
|
+
console.log(import_picocolors3.default.yellow(` No stored receipt matching '${ans}' found.`));
|
|
17787
|
+
}
|
|
17788
|
+
}
|
|
17789
|
+
}
|
|
17790
|
+
} catch (err) {
|
|
17791
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
17792
|
+
console.error(import_picocolors3.default.red(` Failed to inspect storage: ${message}`));
|
|
17793
|
+
}
|
|
17794
|
+
await waitForKeyToReturn();
|
|
17795
|
+
};
|
|
17796
|
+
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"));
|
|
17800
|
+
try {
|
|
17801
|
+
const report = await runDiagnostics();
|
|
17802
|
+
console.log(formatDoctorReport(report));
|
|
17247
17803
|
} catch (err) {
|
|
17248
17804
|
const message = err instanceof Error ? err.message : String(err);
|
|
17249
|
-
console.error(
|
|
17805
|
+
console.error(import_picocolors3.default.red(` Diagnostic check failed: ${message}`));
|
|
17250
17806
|
}
|
|
17251
17807
|
await waitForKeyToReturn();
|
|
17252
17808
|
};
|
|
@@ -17271,7 +17827,7 @@ async function runInteractiveMenu() {
|
|
|
17271
17827
|
return;
|
|
17272
17828
|
}
|
|
17273
17829
|
cleanup();
|
|
17274
|
-
console.log(
|
|
17830
|
+
console.log(import_picocolors3.default.dim("\n Exited Qodewk.\n"));
|
|
17275
17831
|
process.exit(0);
|
|
17276
17832
|
}
|
|
17277
17833
|
if (key.name === "up" || key.name === "k") {
|
|
@@ -17297,8 +17853,14 @@ async function runInteractiveMenu() {
|
|
|
17297
17853
|
if (active) startLoop();
|
|
17298
17854
|
return;
|
|
17299
17855
|
}
|
|
17856
|
+
if (selected.id === "share") {
|
|
17857
|
+
currentScreen = "share_horizon";
|
|
17858
|
+
selectedIndex = 0;
|
|
17859
|
+
if (active) startLoop();
|
|
17860
|
+
return;
|
|
17861
|
+
}
|
|
17300
17862
|
await executeSelectedAction();
|
|
17301
|
-
} else {
|
|
17863
|
+
} else if (currentScreen === "receipt_horizon") {
|
|
17302
17864
|
if (selected.id === "back") {
|
|
17303
17865
|
currentScreen = "main";
|
|
17304
17866
|
selectedIndex = 0;
|
|
@@ -17306,6 +17868,14 @@ async function runInteractiveMenu() {
|
|
|
17306
17868
|
return;
|
|
17307
17869
|
}
|
|
17308
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);
|
|
17309
17879
|
}
|
|
17310
17880
|
if (active) {
|
|
17311
17881
|
startLoop();
|
|
@@ -17322,8 +17892,14 @@ async function runInteractiveMenu() {
|
|
|
17322
17892
|
if (active) startLoop();
|
|
17323
17893
|
return;
|
|
17324
17894
|
}
|
|
17895
|
+
if (selected.id === "share") {
|
|
17896
|
+
currentScreen = "share_horizon";
|
|
17897
|
+
selectedIndex = 0;
|
|
17898
|
+
if (active) startLoop();
|
|
17899
|
+
return;
|
|
17900
|
+
}
|
|
17325
17901
|
await executeSelectedAction();
|
|
17326
|
-
} else {
|
|
17902
|
+
} else if (currentScreen === "receipt_horizon") {
|
|
17327
17903
|
if (selected.id === "back") {
|
|
17328
17904
|
currentScreen = "main";
|
|
17329
17905
|
selectedIndex = 0;
|
|
@@ -17331,6 +17907,14 @@ async function runInteractiveMenu() {
|
|
|
17331
17907
|
return;
|
|
17332
17908
|
}
|
|
17333
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);
|
|
17334
17918
|
}
|
|
17335
17919
|
if (active) {
|
|
17336
17920
|
startLoop();
|
|
@@ -17348,19 +17932,19 @@ loadQodewkEnv();
|
|
|
17348
17932
|
var SHARE_PAYLOAD_MAX_BYTES2 = 5e4;
|
|
17349
17933
|
function resolveCliVersion() {
|
|
17350
17934
|
try {
|
|
17351
|
-
const argv1 = process.argv[1] ?
|
|
17935
|
+
const argv1 = process.argv[1] ? path16.dirname(path16.resolve(process.argv[1])) : process.cwd();
|
|
17352
17936
|
const candidates = [
|
|
17353
|
-
|
|
17354
|
-
|
|
17937
|
+
path16.join(argv1, "..", "package.json"),
|
|
17938
|
+
path16.join(argv1, "package.json")
|
|
17355
17939
|
];
|
|
17356
17940
|
for (const candidate of candidates) {
|
|
17357
|
-
if (!
|
|
17358
|
-
const pkg = JSON.parse(
|
|
17941
|
+
if (!fs15.existsSync(candidate)) continue;
|
|
17942
|
+
const pkg = JSON.parse(fs15.readFileSync(candidate, "utf-8"));
|
|
17359
17943
|
if (pkg.name === "qodewk" && pkg.version) return pkg.version;
|
|
17360
17944
|
}
|
|
17361
17945
|
} catch {
|
|
17362
17946
|
}
|
|
17363
|
-
return "0.
|
|
17947
|
+
return "0.10.1";
|
|
17364
17948
|
}
|
|
17365
17949
|
function resolveSince(options) {
|
|
17366
17950
|
return options.today ? "today" : options.since;
|
|
@@ -17398,21 +17982,39 @@ program2.name("qodewk").description("Universal telemetry and digital receipt gen
|
|
|
17398
17982
|
if (options.notes) {
|
|
17399
17983
|
try {
|
|
17400
17984
|
await writeGitReceiptNote(receipt.repository.headSha, receipt);
|
|
17401
|
-
console.log(
|
|
17985
|
+
console.log(import_picocolors4.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`));
|
|
17402
17986
|
} catch (noteErr) {
|
|
17403
|
-
console.warn(
|
|
17987
|
+
console.warn(import_picocolors4.default.yellow(`Warning: Could not write Git note: ${noteErr.message}`));
|
|
17404
17988
|
}
|
|
17405
17989
|
}
|
|
17406
17990
|
await outputReceipt(receipt, options);
|
|
17407
17991
|
} catch (err) {
|
|
17408
17992
|
const message = err instanceof Error ? err.message : String(err);
|
|
17409
|
-
console.error(
|
|
17993
|
+
console.error(import_picocolors4.default.red(`Error generating receipt: ${message}`));
|
|
17410
17994
|
process.exit(1);
|
|
17411
17995
|
}
|
|
17412
17996
|
});
|
|
17413
17997
|
program2.command("menu").description("Launch interactive terminal control panel").action(async () => {
|
|
17414
17998
|
await runInteractiveMenu();
|
|
17415
17999
|
});
|
|
18000
|
+
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
|
+
try {
|
|
18002
|
+
const isJson = Boolean(options.json || program2.opts().json);
|
|
18003
|
+
const report = await runDiagnostics();
|
|
18004
|
+
if (isJson) {
|
|
18005
|
+
console.log(JSON.stringify(report, null, 2));
|
|
18006
|
+
} else {
|
|
18007
|
+
console.log(formatDoctorReport(report));
|
|
18008
|
+
}
|
|
18009
|
+
if (report.overallStatus === "error") {
|
|
18010
|
+
process.exit(1);
|
|
18011
|
+
}
|
|
18012
|
+
} catch (err) {
|
|
18013
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
18014
|
+
console.error(import_picocolors4.default.red(`Error running diagnostics: ${message}`));
|
|
18015
|
+
process.exit(1);
|
|
18016
|
+
}
|
|
18017
|
+
});
|
|
17416
18018
|
program2.command("audit").description("Audit PR or branch diff against a target base commit").option("-b, --base <base>", "Base git ref or commit SHA (e.g. origin/main)").option("-H, --head <head>", "Head git ref or commit SHA").option("-f, --format <format>", "Output format (terminal, json, markdown)", "terminal").option("-o, --out <path>", "Write receipt output to specified file path").option("-p, --provider <provider>", "Specify AI provider").option("-m, --model <model>", "Specify AI model").option("-s, --since <duration>", "Harvest agent footprints since duration").option("--today", "Harvest agent footprints for today").option("--platform <platform>", "Filter agent platform").option("--anon", "Anonymize branch name in output").option("--barcode", "Render classic 1D thermal barcode (always on; kept for compatibility)").action(async (options) => {
|
|
17417
18019
|
try {
|
|
17418
18020
|
const receipt = await generateReceipt({
|
|
@@ -17429,7 +18031,7 @@ program2.command("audit").description("Audit PR or branch diff against a target
|
|
|
17429
18031
|
await outputReceipt(receipt, options);
|
|
17430
18032
|
} catch (err) {
|
|
17431
18033
|
const message = err instanceof Error ? err.message : String(err);
|
|
17432
|
-
console.error(
|
|
18034
|
+
console.error(import_picocolors4.default.red(`Error auditing git range: ${message}`));
|
|
17433
18035
|
process.exit(1);
|
|
17434
18036
|
}
|
|
17435
18037
|
});
|
|
@@ -17446,12 +18048,12 @@ program2.command("share").description("Publish privacy-safe receipt to Qodewk cl
|
|
|
17446
18048
|
const localFlag = program2.opts().local === true;
|
|
17447
18049
|
if (process.env.QODEWK_TELEMETRY === "off" || localFlag) {
|
|
17448
18050
|
console.log(
|
|
17449
|
-
|
|
18051
|
+
import_picocolors4.default.yellow(
|
|
17450
18052
|
`
|
|
17451
18053
|
Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"}).`
|
|
17452
18054
|
)
|
|
17453
18055
|
);
|
|
17454
|
-
console.log(
|
|
18056
|
+
console.log(import_picocolors4.default.dim("Telemetry remains strictly stored in local SQLite (~/.qodewk/state.db).\n"));
|
|
17455
18057
|
persistReceipt(receipt);
|
|
17456
18058
|
await renderTerminalReceipt(receipt);
|
|
17457
18059
|
return;
|
|
@@ -17466,11 +18068,11 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
|
|
|
17466
18068
|
body = JSON.stringify(trimmed2);
|
|
17467
18069
|
}
|
|
17468
18070
|
if (Buffer.byteLength(body, "utf-8") > SHARE_PAYLOAD_MAX_BYTES2) {
|
|
17469
|
-
console.error(
|
|
18071
|
+
console.error(import_picocolors4.default.red("Sanitized receipt still exceeds the 50 KB cloud payload limit."));
|
|
17470
18072
|
process.exit(1);
|
|
17471
18073
|
}
|
|
17472
18074
|
const endpoint = resolveApiUrl();
|
|
17473
|
-
console.log(
|
|
18075
|
+
console.log(import_picocolors4.default.dim(`Publishing receipt ${sanitized.receipt.id} to ${endpoint}...`));
|
|
17474
18076
|
try {
|
|
17475
18077
|
const response = await fetch(endpoint, {
|
|
17476
18078
|
method: "POST",
|
|
@@ -17487,11 +18089,11 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
|
|
|
17487
18089
|
const data = await response.json();
|
|
17488
18090
|
persistReceipt(sanitized, data.claimToken);
|
|
17489
18091
|
console.log("");
|
|
17490
|
-
console.log(
|
|
17491
|
-
console.log(` ${
|
|
17492
|
-
console.log(` ${
|
|
17493
|
-
console.log(` ${
|
|
17494
|
-
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."));
|
|
17495
18097
|
console.log("");
|
|
17496
18098
|
await renderTerminalReceipt(sanitized, data.url);
|
|
17497
18099
|
if (options.json) {
|
|
@@ -17499,14 +18101,14 @@ Cloud publishing is disabled (${localFlag ? "--local" : "QODEWK_TELEMETRY=off"})
|
|
|
17499
18101
|
}
|
|
17500
18102
|
} catch (networkErr) {
|
|
17501
18103
|
const message = networkErr instanceof Error ? networkErr.message : String(networkErr);
|
|
17502
|
-
console.log(
|
|
18104
|
+
console.log(import_picocolors4.default.yellow(`
|
|
17503
18105
|
Could not reach cloud API (${message}). Rendered locally:`));
|
|
17504
18106
|
persistReceipt(receipt);
|
|
17505
18107
|
await renderTerminalReceipt(receipt);
|
|
17506
18108
|
}
|
|
17507
18109
|
} catch (err) {
|
|
17508
18110
|
const message = err instanceof Error ? err.message : String(err);
|
|
17509
|
-
console.error(
|
|
18111
|
+
console.error(import_picocolors4.default.red(`Error sharing receipt: ${message}`));
|
|
17510
18112
|
process.exit(1);
|
|
17511
18113
|
}
|
|
17512
18114
|
});
|
|
@@ -17524,35 +18126,35 @@ hookCommand.command("install").description("Install non-blocking post-commit and
|
|
|
17524
18126
|
try {
|
|
17525
18127
|
const hooksDir = resolveGitHooksDir();
|
|
17526
18128
|
if (!hooksDir) {
|
|
17527
|
-
console.error(
|
|
18129
|
+
console.error(import_picocolors4.default.red("Error: Current directory is not a Git repository (.git not found)."));
|
|
17528
18130
|
process.exit(1);
|
|
17529
18131
|
}
|
|
17530
|
-
if (!
|
|
17531
|
-
|
|
18132
|
+
if (!fs15.existsSync(hooksDir)) {
|
|
18133
|
+
fs15.mkdirSync(hooksDir, { recursive: true });
|
|
17532
18134
|
}
|
|
17533
18135
|
const targets = ["post-commit", "post-rewrite"];
|
|
17534
18136
|
let installed = 0;
|
|
17535
18137
|
let existing = 0;
|
|
17536
18138
|
for (const name of targets) {
|
|
17537
|
-
const result = installHookFile(
|
|
18139
|
+
const result = installHookFile(path16.join(hooksDir, name));
|
|
17538
18140
|
if (result === "installed") installed++;
|
|
17539
18141
|
else existing++;
|
|
17540
18142
|
}
|
|
17541
18143
|
if (installed === 0 && existing > 0) {
|
|
17542
|
-
console.log(
|
|
18144
|
+
console.log(import_picocolors4.default.yellow("Qodewk Git hooks are already installed (post-commit, post-rewrite)."));
|
|
17543
18145
|
return;
|
|
17544
18146
|
}
|
|
17545
18147
|
console.log(
|
|
17546
|
-
|
|
18148
|
+
import_picocolors4.default.green(
|
|
17547
18149
|
`\u2713 Non-blocking Qodewk hooks installed in ${hooksDir} (post-commit${installed > 1 || existing > 0 ? ", post-rewrite" : installed === 1 && targets.length === 2 ? " + post-rewrite" : ""})`
|
|
17548
18150
|
)
|
|
17549
18151
|
);
|
|
17550
18152
|
if (existing > 0) {
|
|
17551
|
-
console.log(
|
|
18153
|
+
console.log(import_picocolors4.default.dim(` (${existing} hook file(s) already contained the Qodewk marker)`));
|
|
17552
18154
|
}
|
|
17553
18155
|
} catch (err) {
|
|
17554
18156
|
const message = err instanceof Error ? err.message : String(err);
|
|
17555
|
-
console.error(
|
|
18157
|
+
console.error(import_picocolors4.default.red(`Failed to install Git hook: ${message}`));
|
|
17556
18158
|
process.exit(1);
|
|
17557
18159
|
}
|
|
17558
18160
|
});
|
|
@@ -17560,23 +18162,42 @@ hookCommand.command("uninstall").description("Remove Qodewk post-commit and post
|
|
|
17560
18162
|
try {
|
|
17561
18163
|
const hooksDir = resolveGitHooksDir();
|
|
17562
18164
|
if (!hooksDir) {
|
|
17563
|
-
console.log(
|
|
18165
|
+
console.log(import_picocolors4.default.yellow("No Git repository found."));
|
|
17564
18166
|
return;
|
|
17565
18167
|
}
|
|
17566
18168
|
const targets = ["post-commit", "post-rewrite"];
|
|
17567
18169
|
let removed = 0;
|
|
17568
18170
|
for (const name of targets) {
|
|
17569
|
-
const result = uninstallHookFile(
|
|
18171
|
+
const result = uninstallHookFile(path16.join(hooksDir, name));
|
|
17570
18172
|
if (result === "removed") removed++;
|
|
17571
18173
|
}
|
|
17572
18174
|
if (removed === 0) {
|
|
17573
|
-
console.log(
|
|
18175
|
+
console.log(import_picocolors4.default.yellow("Qodewk hooks are not installed."));
|
|
17574
18176
|
return;
|
|
17575
18177
|
}
|
|
17576
|
-
console.log(
|
|
18178
|
+
console.log(import_picocolors4.default.green(`\u2713 Qodewk hook markers removed from ${removed} file(s).`));
|
|
18179
|
+
} catch (err) {
|
|
18180
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
18181
|
+
console.error(import_picocolors4.default.red(`Failed to uninstall hook: ${message}`));
|
|
18182
|
+
process.exit(1);
|
|
18183
|
+
}
|
|
18184
|
+
});
|
|
18185
|
+
hookCommand.command("test").aliases(["verify", "check"]).description("Verify non-blocking Git hook installation and benchmark latency (< 5ms invariant)").option("-j, --json", "Output benchmark in JSON format").action(async (options) => {
|
|
18186
|
+
try {
|
|
18187
|
+
const hooks = auditGitHooks();
|
|
18188
|
+
const benchmark = await benchmarkHookLatency();
|
|
18189
|
+
const isJson = Boolean(options.json || program2.opts().json);
|
|
18190
|
+
if (isJson) {
|
|
18191
|
+
console.log(JSON.stringify({ hooks, benchmark }, null, 2));
|
|
18192
|
+
} else {
|
|
18193
|
+
console.log(formatHookTestReport(hooks, benchmark));
|
|
18194
|
+
}
|
|
18195
|
+
if (!benchmark.passedInvariant) {
|
|
18196
|
+
process.exit(1);
|
|
18197
|
+
}
|
|
17577
18198
|
} catch (err) {
|
|
17578
18199
|
const message = err instanceof Error ? err.message : String(err);
|
|
17579
|
-
console.error(
|
|
18200
|
+
console.error(import_picocolors4.default.red(`Error testing hooks: ${message}`));
|
|
17580
18201
|
process.exit(1);
|
|
17581
18202
|
}
|
|
17582
18203
|
});
|
|
@@ -17585,7 +18206,7 @@ notesCmd.command("show [commit]").description("Display Qodewk receipt attached t
|
|
|
17585
18206
|
try {
|
|
17586
18207
|
const receipt = await readGitReceiptNote(commit);
|
|
17587
18208
|
if (!receipt) {
|
|
17588
|
-
console.log(
|
|
18209
|
+
console.log(import_picocolors4.default.yellow(`No Qodewk receipt note found on commit '${commit}'.`));
|
|
17589
18210
|
return;
|
|
17590
18211
|
}
|
|
17591
18212
|
if (opts.json) {
|
|
@@ -17595,7 +18216,7 @@ notesCmd.command("show [commit]").description("Display Qodewk receipt attached t
|
|
|
17595
18216
|
}
|
|
17596
18217
|
} catch (err) {
|
|
17597
18218
|
const message = err instanceof Error ? err.message : String(err);
|
|
17598
|
-
console.error(
|
|
18219
|
+
console.error(import_picocolors4.default.red(`Error reading Git note: ${message}`));
|
|
17599
18220
|
process.exit(1);
|
|
17600
18221
|
}
|
|
17601
18222
|
});
|
|
@@ -17604,11 +18225,11 @@ notesCmd.command("write [commit]").description("Generate and attach receipt to a
|
|
|
17604
18225
|
const receipt = await generateReceipt({ headSha: commit });
|
|
17605
18226
|
await writeGitReceiptNote(receipt.repository.headSha, receipt);
|
|
17606
18227
|
console.log(
|
|
17607
|
-
|
|
18228
|
+
import_picocolors4.default.green(`\u2713 Attached receipt note to ${receipt.repository.headSha.slice(0, 7)} (refs/notes/qodewk)`)
|
|
17608
18229
|
);
|
|
17609
18230
|
} catch (err) {
|
|
17610
18231
|
const message = err instanceof Error ? err.message : String(err);
|
|
17611
|
-
console.error(
|
|
18232
|
+
console.error(import_picocolors4.default.red(`Error writing Git note: ${message}`));
|
|
17612
18233
|
process.exit(1);
|
|
17613
18234
|
}
|
|
17614
18235
|
});
|
|
@@ -17616,16 +18237,16 @@ notesCmd.command("list").description("List all commits with attached Qodewk rece
|
|
|
17616
18237
|
try {
|
|
17617
18238
|
const shas = await listGitReceiptNotes();
|
|
17618
18239
|
if (shas.length === 0) {
|
|
17619
|
-
console.log(
|
|
18240
|
+
console.log(import_picocolors4.default.yellow("No Qodewk Git notes found in repository."));
|
|
17620
18241
|
return;
|
|
17621
18242
|
}
|
|
17622
|
-
console.log(
|
|
18243
|
+
console.log(import_picocolors4.default.bold(`Found ${shas.length} commit note(s) in refs/notes/qodewk:`));
|
|
17623
18244
|
for (const sha of shas) {
|
|
17624
|
-
console.log(` ${
|
|
18245
|
+
console.log(` ${import_picocolors4.default.cyan(sha.slice(0, 10))} ${import_picocolors4.default.dim(sha)}`);
|
|
17625
18246
|
}
|
|
17626
18247
|
} catch (err) {
|
|
17627
18248
|
const message = err instanceof Error ? err.message : String(err);
|
|
17628
|
-
console.error(
|
|
18249
|
+
console.error(import_picocolors4.default.red(`Error listing Git notes: ${message}`));
|
|
17629
18250
|
process.exit(1);
|
|
17630
18251
|
}
|
|
17631
18252
|
});
|