@workscribe/cli 1.11.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +497 -149
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/shell/hook.fish +34 -0
package/dist/index.js
CHANGED
|
@@ -41,23 +41,31 @@ Upgrade at https://nodejs.org or via your version manager:
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
// src/capture/index.ts
|
|
44
|
-
var
|
|
44
|
+
var import_fs10 = __toESM(require("fs"));
|
|
45
45
|
|
|
46
46
|
// src/db/index.ts
|
|
47
47
|
var import_node_sqlite = require("node:sqlite");
|
|
48
|
-
var
|
|
48
|
+
var import_fs2 = __toESM(require("fs"));
|
|
49
49
|
|
|
50
50
|
// src/utils/paths.ts
|
|
51
51
|
var import_path = __toESM(require("path"));
|
|
52
52
|
var import_os = __toESM(require("os"));
|
|
53
|
-
var
|
|
54
|
-
var
|
|
55
|
-
var
|
|
56
|
-
var
|
|
57
|
-
var
|
|
58
|
-
var
|
|
59
|
-
var
|
|
60
|
-
var
|
|
53
|
+
var import_fs = __toESM(require("fs"));
|
|
54
|
+
var LEGACY_DIR = import_path.default.join(import_os.default.homedir(), ".workscribe");
|
|
55
|
+
var USE_XDG = !import_fs.default.existsSync(LEGACY_DIR);
|
|
56
|
+
var xdgDataDir = USE_XDG ? import_path.default.join(process.env.XDG_DATA_HOME ?? import_path.default.join(import_os.default.homedir(), ".local", "share"), "workscribe") : LEGACY_DIR;
|
|
57
|
+
var xdgConfigDir = USE_XDG ? import_path.default.join(process.env.XDG_CONFIG_HOME ?? import_path.default.join(import_os.default.homedir(), ".config"), "workscribe") : LEGACY_DIR;
|
|
58
|
+
var xdgStateDir = USE_XDG ? import_path.default.join(process.env.XDG_STATE_HOME ?? import_path.default.join(import_os.default.homedir(), ".local", "state"), "workscribe") : LEGACY_DIR;
|
|
59
|
+
var REQUIRED_DIRS = [.../* @__PURE__ */ new Set([xdgDataDir, xdgConfigDir, xdgStateDir])];
|
|
60
|
+
var WORKSCRIBE_DIR = xdgDataDir;
|
|
61
|
+
var DB_PATH = import_path.default.join(xdgDataDir, "workscribe.db");
|
|
62
|
+
var CONFIG_PATH = import_path.default.join(xdgConfigDir, "config.json");
|
|
63
|
+
var DEBUG_LOG_PATH = import_path.default.join(xdgStateDir, "debug.log");
|
|
64
|
+
var UPDATE_CHECK_PATH = import_path.default.join(xdgStateDir, "update-check.json");
|
|
65
|
+
var EXPORTS_DIR = import_path.default.join(xdgDataDir, "exports");
|
|
66
|
+
var PAUSE_FLAG_PATH = import_path.default.join(xdgStateDir, "paused");
|
|
67
|
+
var WEEKLY_CACHE_DIR = import_path.default.join(xdgDataDir, "weekly-cache");
|
|
68
|
+
var PROFILES_DIR = import_path.default.join(xdgDataDir, "profiles");
|
|
61
69
|
|
|
62
70
|
// src/db/migrations/001_initial_schema.ts
|
|
63
71
|
var initial_schema_default = {
|
|
@@ -126,12 +134,12 @@ var MIGRATIONS = [initial_schema_default, semantic_categories_default];
|
|
|
126
134
|
var _db = null;
|
|
127
135
|
function getDb() {
|
|
128
136
|
if (_db) return _db;
|
|
129
|
-
if (!
|
|
130
|
-
|
|
137
|
+
if (!import_fs2.default.existsSync(WORKSCRIBE_DIR)) {
|
|
138
|
+
import_fs2.default.mkdirSync(WORKSCRIBE_DIR, { recursive: true });
|
|
131
139
|
}
|
|
132
140
|
const db = new import_node_sqlite.DatabaseSync(DB_PATH);
|
|
133
141
|
try {
|
|
134
|
-
|
|
142
|
+
import_fs2.default.chmodSync(DB_PATH, 384);
|
|
135
143
|
} catch {
|
|
136
144
|
}
|
|
137
145
|
db.exec("PRAGMA journal_mode = WAL");
|
|
@@ -345,7 +353,7 @@ function redact(command, extraPatterns = []) {
|
|
|
345
353
|
// src/capture/git.ts
|
|
346
354
|
var import_child_process = require("child_process");
|
|
347
355
|
var import_path2 = __toESM(require("path"));
|
|
348
|
-
var
|
|
356
|
+
var import_fs3 = __toESM(require("fs"));
|
|
349
357
|
function nameFromRemote(root) {
|
|
350
358
|
try {
|
|
351
359
|
const url = (0, import_child_process.execSync)("git remote get-url origin", {
|
|
@@ -361,7 +369,7 @@ function nameFromRemote(root) {
|
|
|
361
369
|
}
|
|
362
370
|
function nameFromPackageJson(root) {
|
|
363
371
|
try {
|
|
364
|
-
const raw =
|
|
372
|
+
const raw = import_fs3.default.readFileSync(import_path2.default.join(root, "package.json"), "utf-8");
|
|
365
373
|
const pkg = JSON.parse(raw);
|
|
366
374
|
if (!pkg.name) return null;
|
|
367
375
|
return pkg.name.replace(/^@[^/]+\//, "");
|
|
@@ -405,14 +413,14 @@ function getCommitsSince(sha, cwd) {
|
|
|
405
413
|
}
|
|
406
414
|
|
|
407
415
|
// src/capture/aider.ts
|
|
408
|
-
var
|
|
416
|
+
var import_fs4 = __toESM(require("fs"));
|
|
409
417
|
var import_path3 = __toESM(require("path"));
|
|
410
418
|
var HISTORY_FILE = ".aider.chat.history.md";
|
|
411
419
|
var PROMPT_MAX_LENGTH = 200;
|
|
412
420
|
function readLastAiderPrompt(cwd) {
|
|
413
421
|
try {
|
|
414
422
|
const histPath = import_path3.default.join(cwd, HISTORY_FILE);
|
|
415
|
-
const content =
|
|
423
|
+
const content = import_fs4.default.readFileSync(histPath, "utf-8");
|
|
416
424
|
const matches = [...content.matchAll(/^> (.+)$/gm)];
|
|
417
425
|
if (!matches.length) return null;
|
|
418
426
|
return matches[matches.length - 1][1].trim().slice(0, PROMPT_MAX_LENGTH);
|
|
@@ -422,7 +430,7 @@ function readLastAiderPrompt(cwd) {
|
|
|
422
430
|
}
|
|
423
431
|
|
|
424
432
|
// src/config/registry.ts
|
|
425
|
-
var
|
|
433
|
+
var import_fs6 = __toESM(require("fs"));
|
|
426
434
|
var import_os2 = __toESM(require("os"));
|
|
427
435
|
var import_path4 = __toESM(require("path"));
|
|
428
436
|
|
|
@@ -488,7 +496,7 @@ var ai_tools_default = [
|
|
|
488
496
|
|
|
489
497
|
// src/utils/logger.ts
|
|
490
498
|
var import_chalk = __toESM(require("chalk"));
|
|
491
|
-
var
|
|
499
|
+
var import_fs5 = __toESM(require("fs"));
|
|
492
500
|
var isDebug = process.env.WORKSCRIBE_DEBUG === "1";
|
|
493
501
|
var log = {
|
|
494
502
|
info: (msg) => console.log(import_chalk.default.cyan("\u2192"), msg),
|
|
@@ -502,7 +510,7 @@ function debugLog(context, error) {
|
|
|
502
510
|
const entry = `[${(/* @__PURE__ */ new Date()).toISOString()}] [${context}] ${error instanceof Error ? error.stack : String(error)}
|
|
503
511
|
`;
|
|
504
512
|
try {
|
|
505
|
-
|
|
513
|
+
import_fs5.default.appendFileSync(DEBUG_LOG_PATH, entry, { mode: 384 });
|
|
506
514
|
} catch {
|
|
507
515
|
}
|
|
508
516
|
}
|
|
@@ -512,8 +520,8 @@ var USER_REGISTRY_PATH = import_path4.default.join(import_os2.default.homedir(),
|
|
|
512
520
|
function loadAIToolRegistry() {
|
|
513
521
|
let userEntries = [];
|
|
514
522
|
try {
|
|
515
|
-
if (
|
|
516
|
-
const raw =
|
|
523
|
+
if (import_fs6.default.existsSync(USER_REGISTRY_PATH)) {
|
|
524
|
+
const raw = import_fs6.default.readFileSync(USER_REGISTRY_PATH, "utf-8");
|
|
517
525
|
const parsed = JSON.parse(raw);
|
|
518
526
|
if (Array.isArray(parsed)) {
|
|
519
527
|
userEntries = parsed.filter((entry) => typeof entry.tool === "string" && typeof entry.pattern === "string").map((entry) => ({
|
|
@@ -535,11 +543,11 @@ function loadAIToolRegistry() {
|
|
|
535
543
|
}
|
|
536
544
|
|
|
537
545
|
// src/profiles/loader.ts
|
|
538
|
-
var
|
|
546
|
+
var import_fs9 = __toESM(require("fs"));
|
|
539
547
|
var import_path6 = __toESM(require("path"));
|
|
540
548
|
|
|
541
549
|
// src/config/index.ts
|
|
542
|
-
var
|
|
550
|
+
var import_fs7 = __toESM(require("fs"));
|
|
543
551
|
var DEFAULTS = {
|
|
544
552
|
ai: {
|
|
545
553
|
provider: "",
|
|
@@ -564,9 +572,9 @@ var DEFAULTS = {
|
|
|
564
572
|
}
|
|
565
573
|
};
|
|
566
574
|
function readConfig() {
|
|
567
|
-
if (!
|
|
575
|
+
if (!import_fs7.default.existsSync(CONFIG_PATH)) return { ...DEFAULTS };
|
|
568
576
|
try {
|
|
569
|
-
const raw =
|
|
577
|
+
const raw = import_fs7.default.readFileSync(CONFIG_PATH, "utf-8");
|
|
570
578
|
const parsed = JSON.parse(raw);
|
|
571
579
|
return deepMerge(DEFAULTS, parsed);
|
|
572
580
|
} catch {
|
|
@@ -574,9 +582,9 @@ function readConfig() {
|
|
|
574
582
|
}
|
|
575
583
|
}
|
|
576
584
|
function writeConfig(config) {
|
|
577
|
-
|
|
585
|
+
import_fs7.default.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { encoding: "utf-8", mode: 384 });
|
|
578
586
|
try {
|
|
579
|
-
|
|
587
|
+
import_fs7.default.chmodSync(CONFIG_PATH, 384);
|
|
580
588
|
} catch {
|
|
581
589
|
}
|
|
582
590
|
}
|
|
@@ -641,21 +649,57 @@ function isValidManifest(m) {
|
|
|
641
649
|
}
|
|
642
650
|
|
|
643
651
|
// src/profiles/fetcher.ts
|
|
644
|
-
var
|
|
652
|
+
var import_fs8 = __toESM(require("fs"));
|
|
645
653
|
var import_path5 = __toESM(require("path"));
|
|
654
|
+
|
|
655
|
+
// src/utils/fetch.ts
|
|
656
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
657
|
+
var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
658
|
+
"ENOTFOUND",
|
|
659
|
+
"ECONNREFUSED",
|
|
660
|
+
"ECONNRESET",
|
|
661
|
+
"ETIMEDOUT",
|
|
662
|
+
"EHOSTUNREACH",
|
|
663
|
+
"ENETUNREACH"
|
|
664
|
+
]);
|
|
665
|
+
function isNetworkError(err) {
|
|
666
|
+
if (!(err instanceof Error)) return false;
|
|
667
|
+
const cause = err.cause;
|
|
668
|
+
const code = err.code ?? (cause instanceof Error ? cause.code : void 0);
|
|
669
|
+
return NETWORK_ERROR_CODES.has(code ?? "");
|
|
670
|
+
}
|
|
671
|
+
async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
672
|
+
const controller = new AbortController();
|
|
673
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
674
|
+
try {
|
|
675
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
676
|
+
} catch (err) {
|
|
677
|
+
if (err.name === "AbortError") {
|
|
678
|
+
throw new Error(`Request timed out after ${timeoutMs / 1e3}s`);
|
|
679
|
+
}
|
|
680
|
+
if (isNetworkError(err)) {
|
|
681
|
+
throw new Error("No internet connection \u2014 try again when you're online");
|
|
682
|
+
}
|
|
683
|
+
throw err;
|
|
684
|
+
} finally {
|
|
685
|
+
clearTimeout(timer);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/profiles/fetcher.ts
|
|
646
690
|
var REGISTRY_BASE = "https://raw.githubusercontent.com/workscribe/profiles/main";
|
|
647
691
|
function manifestCachePath() {
|
|
648
692
|
return import_path5.default.join(PROFILES_DIR, "manifest.json");
|
|
649
693
|
}
|
|
650
694
|
async function fetchManifest() {
|
|
651
|
-
const response = await
|
|
695
|
+
const response = await fetchWithTimeout(`${REGISTRY_BASE}/manifest.json`, {});
|
|
652
696
|
if (!response.ok) throw new Error(`Registry unreachable (${response.status})`);
|
|
653
697
|
const data = await response.json();
|
|
654
698
|
if (!isValidManifest(data)) throw new Error("Manifest format unrecognised");
|
|
655
699
|
return data;
|
|
656
700
|
}
|
|
657
701
|
async function fetchProfile(name) {
|
|
658
|
-
const response = await
|
|
702
|
+
const response = await fetchWithTimeout(`${REGISTRY_BASE}/${name}.json`, {});
|
|
659
703
|
if (response.status === 404) throw new Error(`Profile "${name}" not found in registry`);
|
|
660
704
|
if (!response.ok) throw new Error(`Registry unreachable (${response.status})`);
|
|
661
705
|
const data = await response.json();
|
|
@@ -666,27 +710,27 @@ async function installProfile(name) {
|
|
|
666
710
|
ensureProfilesDir();
|
|
667
711
|
const profile = await fetchProfile(name);
|
|
668
712
|
const dest = import_path5.default.join(PROFILES_DIR, `${name}.json`);
|
|
669
|
-
|
|
713
|
+
import_fs8.default.writeFileSync(dest, JSON.stringify(profile, null, 2), { encoding: "utf-8", mode: 384 });
|
|
670
714
|
debugLog("profiles", `Installed profile "${name}" to ${dest}`);
|
|
671
715
|
}
|
|
672
716
|
async function cacheManifest() {
|
|
673
717
|
ensureProfilesDir();
|
|
674
718
|
const manifest = await fetchManifest();
|
|
675
|
-
|
|
719
|
+
import_fs8.default.writeFileSync(manifestCachePath(), JSON.stringify(manifest, null, 2), { encoding: "utf-8", mode: 384 });
|
|
676
720
|
return manifest;
|
|
677
721
|
}
|
|
678
722
|
function readCachedManifest() {
|
|
679
|
-
if (!
|
|
723
|
+
if (!import_fs8.default.existsSync(manifestCachePath())) return null;
|
|
680
724
|
try {
|
|
681
|
-
const data = JSON.parse(
|
|
725
|
+
const data = JSON.parse(import_fs8.default.readFileSync(manifestCachePath(), "utf-8"));
|
|
682
726
|
return isValidManifest(data) ? data : null;
|
|
683
727
|
} catch {
|
|
684
728
|
return null;
|
|
685
729
|
}
|
|
686
730
|
}
|
|
687
731
|
function ensureProfilesDir() {
|
|
688
|
-
if (!
|
|
689
|
-
|
|
732
|
+
if (!import_fs8.default.existsSync(PROFILES_DIR)) {
|
|
733
|
+
import_fs8.default.mkdirSync(PROFILES_DIR, { recursive: true, mode: 448 });
|
|
690
734
|
}
|
|
691
735
|
}
|
|
692
736
|
|
|
@@ -713,13 +757,13 @@ function compileRule(profileName, rule) {
|
|
|
713
757
|
}
|
|
714
758
|
function loadProfileFromDisk(name) {
|
|
715
759
|
const filePath = import_path6.default.join(PROFILES_DIR, `${name}.json`);
|
|
716
|
-
if (!
|
|
760
|
+
if (!import_fs9.default.existsSync(filePath)) {
|
|
717
761
|
debugLog("profiles", `Profile "${name}" not found in cache \u2014 run: workscribe profile add ${name}`);
|
|
718
762
|
return null;
|
|
719
763
|
}
|
|
720
764
|
let candidate;
|
|
721
765
|
try {
|
|
722
|
-
candidate = JSON.parse(
|
|
766
|
+
candidate = JSON.parse(import_fs9.default.readFileSync(filePath, "utf-8"));
|
|
723
767
|
} catch {
|
|
724
768
|
debugLog("profiles", `Profile "${name}" contains invalid JSON \u2014 skipping`);
|
|
725
769
|
return null;
|
|
@@ -751,8 +795,8 @@ function getActiveProfileAiContexts() {
|
|
|
751
795
|
});
|
|
752
796
|
}
|
|
753
797
|
function getCachedProfiles() {
|
|
754
|
-
if (!
|
|
755
|
-
return
|
|
798
|
+
if (!import_fs9.default.existsSync(PROFILES_DIR)) return [];
|
|
799
|
+
return import_fs9.default.readdirSync(PROFILES_DIR).filter((file) => file.endsWith(".json") && file !== "manifest.json").flatMap((file) => {
|
|
756
800
|
const profile = loadProfileFromDisk(file.replace(/\.json$/, ""));
|
|
757
801
|
return profile ? [profile] : [];
|
|
758
802
|
});
|
|
@@ -764,7 +808,7 @@ function detectProfilesForDirectory(dir) {
|
|
|
764
808
|
return manifest.filter((entry) => {
|
|
765
809
|
if (activeNames.has(entry.name)) return false;
|
|
766
810
|
const indicatorFiles = entry.detect?.files ?? [];
|
|
767
|
-
return indicatorFiles.length > 0 && indicatorFiles.every((file) =>
|
|
811
|
+
return indicatorFiles.length > 0 && indicatorFiles.every((file) => import_fs9.default.existsSync(import_path6.default.join(dir, file)));
|
|
768
812
|
});
|
|
769
813
|
}
|
|
770
814
|
|
|
@@ -1032,7 +1076,7 @@ function isDuplicate(command, cwd, lastEvent, dedupWindowMs = 5e3, now = Date.no
|
|
|
1032
1076
|
|
|
1033
1077
|
// src/capture/index.ts
|
|
1034
1078
|
function captureCommand(opts) {
|
|
1035
|
-
if (
|
|
1079
|
+
if (import_fs10.default.existsSync(PAUSE_FLAG_PATH)) return;
|
|
1036
1080
|
const config = readConfig();
|
|
1037
1081
|
const { command, cwd, exitCode, durationMs } = opts;
|
|
1038
1082
|
if (shouldFilter(command, config.capture.ignore)) return;
|
|
@@ -1133,9 +1177,9 @@ function registerHook(program2) {
|
|
|
1133
1177
|
}
|
|
1134
1178
|
|
|
1135
1179
|
// src/cli/init.ts
|
|
1136
|
-
var
|
|
1180
|
+
var import_fs13 = __toESM(require("fs"));
|
|
1137
1181
|
var import_path9 = __toESM(require("path"));
|
|
1138
|
-
var
|
|
1182
|
+
var import_os5 = __toESM(require("os"));
|
|
1139
1183
|
var import_prompts = __toESM(require("prompts"));
|
|
1140
1184
|
var import_chalk2 = __toESM(require("chalk"));
|
|
1141
1185
|
|
|
@@ -1353,24 +1397,7 @@ function buildWeeklyMessage(payload) {
|
|
|
1353
1397
|
return lines.join("\n");
|
|
1354
1398
|
}
|
|
1355
1399
|
|
|
1356
|
-
// src/ai/
|
|
1357
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
1358
|
-
async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
1359
|
-
const controller = new AbortController();
|
|
1360
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
1361
|
-
try {
|
|
1362
|
-
return await fetch(url, { ...init, signal: controller.signal });
|
|
1363
|
-
} catch (err) {
|
|
1364
|
-
if (err.name === "AbortError") {
|
|
1365
|
-
throw new Error(`Request timed out after ${timeoutMs / 1e3}s`);
|
|
1366
|
-
}
|
|
1367
|
-
throw err;
|
|
1368
|
-
} finally {
|
|
1369
|
-
clearTimeout(timer);
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
// src/ai/providers/index.ts
|
|
1400
|
+
// src/ai/generic-provider.ts
|
|
1374
1401
|
var GenericProvider = class {
|
|
1375
1402
|
constructor(config, model, apiKey, baseUrl, includeCategories = []) {
|
|
1376
1403
|
this.config = config;
|
|
@@ -1414,7 +1441,7 @@ var GenericProvider = class {
|
|
|
1414
1441
|
}
|
|
1415
1442
|
};
|
|
1416
1443
|
|
|
1417
|
-
// src/ai/
|
|
1444
|
+
// src/ai/provider-config.ts
|
|
1418
1445
|
var PROVIDER_CONFIGS = {
|
|
1419
1446
|
anthropic: {
|
|
1420
1447
|
defaultModel: "claude-haiku-4-5-20251001",
|
|
@@ -1538,14 +1565,72 @@ Run: workscribe config set ai.apiKey <your-key>`);
|
|
|
1538
1565
|
}
|
|
1539
1566
|
|
|
1540
1567
|
// src/capture/shell-hook.ts
|
|
1541
|
-
var
|
|
1568
|
+
var import_fs11 = __toESM(require("fs"));
|
|
1542
1569
|
var import_path7 = __toESM(require("path"));
|
|
1570
|
+
var import_os3 = __toESM(require("os"));
|
|
1571
|
+
|
|
1572
|
+
// src/utils/completion-scripts.ts
|
|
1573
|
+
function bashCompletion(commands) {
|
|
1574
|
+
const names = commands.map((command) => command.name).join(" ");
|
|
1575
|
+
return `_workscribe_completion() {
|
|
1576
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
1577
|
+
local prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
1578
|
+
local commands="${names}"
|
|
1579
|
+
case "$prev" in
|
|
1580
|
+
completions) COMPREPLY=( $(compgen -W "bash zsh fish" -- "$cur") ); return ;;
|
|
1581
|
+
config) COMPREPLY=( $(compgen -W "get set list" -- "$cur") ); return ;;
|
|
1582
|
+
profile) COMPREPLY=( $(compgen -W "list add remove update detect suggest" -- "$cur") ); return ;;
|
|
1583
|
+
esac
|
|
1584
|
+
COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
|
|
1585
|
+
}
|
|
1586
|
+
complete -F _workscribe_completion workscribe`;
|
|
1587
|
+
}
|
|
1588
|
+
function zshCompletion(commands) {
|
|
1589
|
+
const commandList = commands.map((command) => ` '${command.name}:${command.description}'`).join("\n");
|
|
1590
|
+
return `#compdef workscribe
|
|
1591
|
+
_workscribe() {
|
|
1592
|
+
local state
|
|
1593
|
+
_arguments '1: :->command' '*: :->args'
|
|
1594
|
+
case $state in
|
|
1595
|
+
command)
|
|
1596
|
+
local -a commands
|
|
1597
|
+
commands=(
|
|
1598
|
+
${commandList}
|
|
1599
|
+
)
|
|
1600
|
+
_describe 'command' commands
|
|
1601
|
+
;;
|
|
1602
|
+
args)
|
|
1603
|
+
case $words[2] in
|
|
1604
|
+
completions) local -a shells; shells=('bash' 'zsh' 'fish'); _describe 'shell' shells ;;
|
|
1605
|
+
config) local -a sub; sub=('get:Get a value' 'set:Set a value' 'list:List all values'); _describe 'subcommand' sub ;;
|
|
1606
|
+
profile) local -a sub; sub=('list' 'add' 'remove' 'update' 'detect' 'suggest'); _describe 'subcommand' sub ;;
|
|
1607
|
+
esac
|
|
1608
|
+
;;
|
|
1609
|
+
esac
|
|
1610
|
+
}
|
|
1611
|
+
_workscribe`;
|
|
1612
|
+
}
|
|
1613
|
+
function fishCompletion(commands) {
|
|
1614
|
+
const lines = [
|
|
1615
|
+
"complete -c workscribe -f",
|
|
1616
|
+
...commands.map(
|
|
1617
|
+
(command) => `complete -c workscribe -n "__fish_use_subcommand" -a ${command.name.padEnd(12)} -d "${command.description}"`
|
|
1618
|
+
),
|
|
1619
|
+
'complete -c workscribe -n "__fish_seen_subcommand_from completions" -a "bash zsh fish"',
|
|
1620
|
+
'complete -c workscribe -n "__fish_seen_subcommand_from config" -a "get set list"',
|
|
1621
|
+
'complete -c workscribe -n "__fish_seen_subcommand_from profile" -a "list add remove update detect suggest"'
|
|
1622
|
+
];
|
|
1623
|
+
return lines.join("\n");
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
// src/capture/shell-hook.ts
|
|
1627
|
+
var FISH_COMPLETIONS_DIR = import_path7.default.join(import_os3.default.homedir(), ".config", "fish", "completions");
|
|
1543
1628
|
var HOOK_START = "# workscribe:hook:start";
|
|
1544
1629
|
var HOOK_END = "# workscribe:hook:end";
|
|
1545
1630
|
var HOOK_PREAMBLE = "# Workscribe \u2014 developer work journal";
|
|
1546
1631
|
function getInstalledHookBlock(rcFile) {
|
|
1547
|
-
if (!
|
|
1548
|
-
const content =
|
|
1632
|
+
if (!import_fs11.default.existsSync(rcFile)) return null;
|
|
1633
|
+
const content = import_fs11.default.readFileSync(rcFile, "utf-8");
|
|
1549
1634
|
const startIdx = content.indexOf(HOOK_START);
|
|
1550
1635
|
const endIdx = content.indexOf(HOOK_END);
|
|
1551
1636
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
@@ -1561,39 +1646,70 @@ function isHookOutdated(rcFile, hookContent) {
|
|
|
1561
1646
|
}
|
|
1562
1647
|
function installHook(rcFile, hookContent) {
|
|
1563
1648
|
const backup = `${rcFile}.workscribe-backup-${Date.now()}`;
|
|
1564
|
-
|
|
1649
|
+
import_fs11.default.copyFileSync(rcFile, backup);
|
|
1565
1650
|
log.info(`Backed up ${rcFile} \u2192 ${import_path7.default.basename(backup)}`);
|
|
1566
|
-
|
|
1651
|
+
import_fs11.default.appendFileSync(rcFile, `
|
|
1567
1652
|
${hookContent}
|
|
1568
1653
|
`);
|
|
1569
1654
|
}
|
|
1570
1655
|
function updateHook(rcFile, hookContent) {
|
|
1571
1656
|
const backup = `${rcFile}.workscribe-backup-${Date.now()}`;
|
|
1572
|
-
|
|
1657
|
+
import_fs11.default.copyFileSync(rcFile, backup);
|
|
1573
1658
|
log.info(`Backed up ${rcFile} \u2192 ${import_path7.default.basename(backup)}`);
|
|
1574
|
-
const content =
|
|
1659
|
+
const content = import_fs11.default.readFileSync(rcFile, "utf-8");
|
|
1575
1660
|
const startIdx = content.indexOf(HOOK_START);
|
|
1576
1661
|
const endIdx = content.indexOf(HOOK_END) + HOOK_END.length;
|
|
1577
|
-
|
|
1662
|
+
import_fs11.default.writeFileSync(rcFile, content.slice(0, startIdx) + hookContent + content.slice(endIdx));
|
|
1578
1663
|
}
|
|
1579
1664
|
function removeHook(rcFile) {
|
|
1580
1665
|
const backup = `${rcFile}.workscribe-backup-${Date.now()}`;
|
|
1581
|
-
|
|
1666
|
+
import_fs11.default.copyFileSync(rcFile, backup);
|
|
1582
1667
|
log.info(`Backed up ${rcFile} \u2192 ${import_path7.default.basename(backup)}`);
|
|
1583
|
-
const content =
|
|
1668
|
+
const content = import_fs11.default.readFileSync(rcFile, "utf-8");
|
|
1584
1669
|
const startIdx = content.indexOf(HOOK_START);
|
|
1585
1670
|
const endIdx = content.indexOf(HOOK_END) + HOOK_END.length;
|
|
1586
1671
|
const preambleIdx = content.lastIndexOf(HOOK_PREAMBLE, startIdx);
|
|
1587
1672
|
const blockStart = preambleIdx !== -1 ? preambleIdx : startIdx;
|
|
1588
1673
|
const before = content.slice(0, blockStart).replace(/\n+$/, "\n");
|
|
1589
1674
|
const after = content.slice(endIdx).replace(/^\n/, "");
|
|
1590
|
-
|
|
1675
|
+
import_fs11.default.writeFileSync(rcFile, before + after);
|
|
1676
|
+
}
|
|
1677
|
+
function isCompletionsInstalled(shell) {
|
|
1678
|
+
if (shell.name === "fish") {
|
|
1679
|
+
return import_fs11.default.existsSync(import_path7.default.join(FISH_COMPLETIONS_DIR, "workscribe.fish"));
|
|
1680
|
+
}
|
|
1681
|
+
try {
|
|
1682
|
+
return import_fs11.default.readFileSync(shell.rcFile, "utf-8").includes("workscribe completions");
|
|
1683
|
+
} catch {
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
function installCompletions(shell, commands) {
|
|
1688
|
+
if (shell.name === "fish") {
|
|
1689
|
+
if (!import_fs11.default.existsSync(FISH_COMPLETIONS_DIR)) {
|
|
1690
|
+
import_fs11.default.mkdirSync(FISH_COMPLETIONS_DIR, { recursive: true });
|
|
1691
|
+
}
|
|
1692
|
+
import_fs11.default.writeFileSync(import_path7.default.join(FISH_COMPLETIONS_DIR, "workscribe.fish"), fishCompletion(commands), { mode: 420 });
|
|
1693
|
+
} else {
|
|
1694
|
+
const script = shell.name === "zsh" ? zshCompletion(commands) : bashCompletion(commands);
|
|
1695
|
+
const cacheFile = import_path7.default.join(WORKSCRIBE_DIR, `completion.${shell.name}`);
|
|
1696
|
+
import_fs11.default.writeFileSync(cacheFile, script, { mode: 420 });
|
|
1697
|
+
const sourceLine = shell.name === "zsh" ? `
|
|
1698
|
+
# Workscribe completions
|
|
1699
|
+
autoload -Uz compinit && compinit
|
|
1700
|
+
source "${cacheFile}"
|
|
1701
|
+
` : `
|
|
1702
|
+
# Workscribe completions
|
|
1703
|
+
source "${cacheFile}"
|
|
1704
|
+
`;
|
|
1705
|
+
import_fs11.default.appendFileSync(shell.rcFile, sourceLine);
|
|
1706
|
+
}
|
|
1591
1707
|
}
|
|
1592
1708
|
|
|
1593
1709
|
// src/capture/hooks/claude-code.ts
|
|
1594
|
-
var
|
|
1710
|
+
var import_fs12 = __toESM(require("fs"));
|
|
1595
1711
|
var import_path8 = __toESM(require("path"));
|
|
1596
|
-
var
|
|
1712
|
+
var import_os4 = __toESM(require("os"));
|
|
1597
1713
|
|
|
1598
1714
|
// src/capture/hooks/utils.ts
|
|
1599
1715
|
var import_child_process3 = require("child_process");
|
|
@@ -1607,11 +1723,11 @@ function isCommandInstalled(cmd) {
|
|
|
1607
1723
|
}
|
|
1608
1724
|
|
|
1609
1725
|
// src/capture/hooks/claude-code.ts
|
|
1610
|
-
var CLAUDE_SETTINGS_PATH = import_path8.default.join(
|
|
1726
|
+
var CLAUDE_SETTINGS_PATH = import_path8.default.join(import_os4.default.homedir(), ".claude", "settings.json");
|
|
1611
1727
|
function readSettings() {
|
|
1612
|
-
if (!
|
|
1728
|
+
if (!import_fs12.default.existsSync(CLAUDE_SETTINGS_PATH)) return {};
|
|
1613
1729
|
try {
|
|
1614
|
-
return JSON.parse(
|
|
1730
|
+
return JSON.parse(import_fs12.default.readFileSync(CLAUDE_SETTINGS_PATH, "utf-8"));
|
|
1615
1731
|
} catch {
|
|
1616
1732
|
return {};
|
|
1617
1733
|
}
|
|
@@ -1646,8 +1762,8 @@ var claudeCodeIntegration = {
|
|
|
1646
1762
|
}
|
|
1647
1763
|
]
|
|
1648
1764
|
};
|
|
1649
|
-
|
|
1650
|
-
|
|
1765
|
+
import_fs12.default.mkdirSync(import_path8.default.dirname(CLAUDE_SETTINGS_PATH), { recursive: true });
|
|
1766
|
+
import_fs12.default.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2));
|
|
1651
1767
|
}
|
|
1652
1768
|
};
|
|
1653
1769
|
|
|
@@ -1656,11 +1772,34 @@ var AI_HOOK_INTEGRATIONS = {
|
|
|
1656
1772
|
"claude-code": claudeCodeIntegration
|
|
1657
1773
|
};
|
|
1658
1774
|
|
|
1775
|
+
// src/cli/completions.ts
|
|
1776
|
+
var HIDDEN_COMMANDS = /* @__PURE__ */ new Set(["_capture", "_hook"]);
|
|
1777
|
+
function getPublicCommands(program2) {
|
|
1778
|
+
return program2.commands.filter((command) => !HIDDEN_COMMANDS.has(command.name())).map((command) => ({ name: command.name(), description: command.description() }));
|
|
1779
|
+
}
|
|
1780
|
+
function registerCompletions(program2) {
|
|
1781
|
+
program2.command("completions [shell]").description("Print shell completion script (bash, zsh, fish)").action((shell) => {
|
|
1782
|
+
const detected = shell ?? (process.env.SHELL ?? "").split("/").at(-1);
|
|
1783
|
+
if (!detected || !["bash", "zsh", "fish"].includes(detected)) {
|
|
1784
|
+
log.error(`Unknown shell: "${detected ?? ""}". Supported: bash, zsh, fish`);
|
|
1785
|
+
log.plain(` Usage: workscribe completions <bash|zsh|fish>`);
|
|
1786
|
+
process.exit(1);
|
|
1787
|
+
}
|
|
1788
|
+
const commands = getPublicCommands(program2);
|
|
1789
|
+
const script = detected === "bash" ? bashCompletion(commands) : detected === "zsh" ? zshCompletion(commands) : fishCompletion(commands);
|
|
1790
|
+
process.stdout.write(script + "\n");
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1659
1794
|
// src/cli/init.ts
|
|
1660
1795
|
function detectShell() {
|
|
1661
1796
|
const shell = process.env.SHELL ?? "";
|
|
1662
|
-
if (shell.includes("zsh")) return { name: "zsh", rcFile: import_path9.default.join(
|
|
1663
|
-
if (shell.includes("bash")) return { name: "bash", rcFile: import_path9.default.join(
|
|
1797
|
+
if (shell.includes("zsh")) return { name: "zsh", rcFile: import_path9.default.join(import_os5.default.homedir(), ".zshrc") };
|
|
1798
|
+
if (shell.includes("bash")) return { name: "bash", rcFile: import_path9.default.join(import_os5.default.homedir(), ".bashrc") };
|
|
1799
|
+
if (shell.includes("fish")) {
|
|
1800
|
+
const confDir = import_path9.default.join(import_os5.default.homedir(), ".config", "fish", "conf.d");
|
|
1801
|
+
return { name: "fish", rcFile: import_path9.default.join(confDir, "workscribe.fish") };
|
|
1802
|
+
}
|
|
1664
1803
|
return null;
|
|
1665
1804
|
}
|
|
1666
1805
|
function step(current, total, label) {
|
|
@@ -1671,19 +1810,21 @@ function registerInit(program2) {
|
|
|
1671
1810
|
program2.command("init").description("Set up Workscribe and install or update shell hooks").action(async () => {
|
|
1672
1811
|
const TOTAL_STEPS = 5;
|
|
1673
1812
|
log.plain(import_chalk2.default.bold("\n Workscribe \u2014 Developer Work Journal\n"));
|
|
1674
|
-
step(1, TOTAL_STEPS, "Creating data
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1813
|
+
step(1, TOTAL_STEPS, "Creating data directories");
|
|
1814
|
+
for (const dir of REQUIRED_DIRS) {
|
|
1815
|
+
if (!import_fs13.default.existsSync(dir)) {
|
|
1816
|
+
import_fs13.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
1817
|
+
log.success(`Created ${dir}`);
|
|
1818
|
+
} else {
|
|
1819
|
+
try {
|
|
1820
|
+
import_fs13.default.chmodSync(dir, 448);
|
|
1821
|
+
} catch {
|
|
1822
|
+
}
|
|
1823
|
+
log.info(`${dir} already exists`);
|
|
1682
1824
|
}
|
|
1683
|
-
log.info(`${WORKSCRIBE_DIR} already exists`);
|
|
1684
1825
|
}
|
|
1685
|
-
if (!
|
|
1686
|
-
|
|
1826
|
+
if (!import_fs13.default.existsSync(PROFILES_DIR)) {
|
|
1827
|
+
import_fs13.default.mkdirSync(PROFILES_DIR, { recursive: true, mode: 448 });
|
|
1687
1828
|
}
|
|
1688
1829
|
step(2, TOTAL_STEPS, "Initialising database");
|
|
1689
1830
|
getDb();
|
|
@@ -1691,15 +1832,21 @@ function registerInit(program2) {
|
|
|
1691
1832
|
step(3, TOTAL_STEPS, "Installing shell hook");
|
|
1692
1833
|
const shell = detectShell();
|
|
1693
1834
|
if (!shell) {
|
|
1694
|
-
log.warn("Could not detect shell. Supported: zsh, bash");
|
|
1695
|
-
log.plain(
|
|
1835
|
+
log.warn("Could not detect shell. Supported: zsh, bash, fish");
|
|
1836
|
+
log.plain(
|
|
1837
|
+
` Manually add the hook from: ${import_chalk2.default.cyan("shell/hook.zsh")}, ${import_chalk2.default.cyan("shell/hook.bash")}, or ${import_chalk2.default.cyan("shell/hook.fish")}`
|
|
1838
|
+
);
|
|
1696
1839
|
} else {
|
|
1697
1840
|
const hookFile = import_path9.default.join(__dirname, "..", "shell", `hook.${shell.name}`);
|
|
1698
|
-
if (!
|
|
1841
|
+
if (!import_fs13.default.existsSync(hookFile)) {
|
|
1699
1842
|
log.warn(`Hook template not found at ${hookFile}`);
|
|
1700
1843
|
} else {
|
|
1701
|
-
const hookContent =
|
|
1702
|
-
if (
|
|
1844
|
+
const hookContent = import_fs13.default.readFileSync(hookFile, "utf-8");
|
|
1845
|
+
if (shell.name === "fish") {
|
|
1846
|
+
const confDir = import_path9.default.dirname(shell.rcFile);
|
|
1847
|
+
if (!import_fs13.default.existsSync(confDir)) import_fs13.default.mkdirSync(confDir, { recursive: true });
|
|
1848
|
+
}
|
|
1849
|
+
if (!import_fs13.default.existsSync(shell.rcFile)) import_fs13.default.writeFileSync(shell.rcFile, "");
|
|
1703
1850
|
if (!isHookInstalled(shell.rcFile)) {
|
|
1704
1851
|
log.plain("");
|
|
1705
1852
|
log.plain(import_chalk2.default.dim(" Workscribe adds a lightweight hook to your shell that captures each"));
|
|
@@ -1725,6 +1872,24 @@ function registerInit(program2) {
|
|
|
1725
1872
|
} else {
|
|
1726
1873
|
log.info(`Shell hook up to date in ${shell.rcFile}`);
|
|
1727
1874
|
}
|
|
1875
|
+
if (isCompletionsInstalled(shell)) {
|
|
1876
|
+
log.info("Shell completions already installed");
|
|
1877
|
+
} else {
|
|
1878
|
+
const { installComps } = await (0, import_prompts.default)({
|
|
1879
|
+
type: "confirm",
|
|
1880
|
+
name: "installComps",
|
|
1881
|
+
message: "Install shell completions (tab-complete workscribe commands)?",
|
|
1882
|
+
initial: true
|
|
1883
|
+
});
|
|
1884
|
+
if (installComps) {
|
|
1885
|
+
try {
|
|
1886
|
+
installCompletions(shell, getPublicCommands(program2));
|
|
1887
|
+
log.success("Shell completions installed");
|
|
1888
|
+
} catch (error) {
|
|
1889
|
+
log.warn(`Completions install failed: ${error.message}`);
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1728
1893
|
}
|
|
1729
1894
|
}
|
|
1730
1895
|
step(4, TOTAL_STEPS, "Detecting AI coding tools");
|
|
@@ -1855,7 +2020,7 @@ function registerInit(program2) {
|
|
|
1855
2020
|
}
|
|
1856
2021
|
}
|
|
1857
2022
|
}
|
|
1858
|
-
if (!
|
|
2023
|
+
if (!import_fs13.default.existsSync(CONFIG_PATH)) {
|
|
1859
2024
|
writeConfig(config);
|
|
1860
2025
|
}
|
|
1861
2026
|
log.plain("");
|
|
@@ -1863,8 +2028,13 @@ function registerInit(program2) {
|
|
|
1863
2028
|
log.plain("");
|
|
1864
2029
|
if (shell) {
|
|
1865
2030
|
log.plain(` Activate capture now:`);
|
|
1866
|
-
|
|
1867
|
-
|
|
2031
|
+
if (shell.name === "fish") {
|
|
2032
|
+
log.plain(` Restart your terminal`);
|
|
2033
|
+
log.plain(` ${import_chalk2.default.dim(`or run: source ${shell.rcFile}`)}`);
|
|
2034
|
+
} else {
|
|
2035
|
+
log.plain(` ${import_chalk2.default.cyan(`source ${shell.rcFile}`)}`);
|
|
2036
|
+
log.plain(` Or restart your terminal.`);
|
|
2037
|
+
}
|
|
1868
2038
|
log.plain("");
|
|
1869
2039
|
}
|
|
1870
2040
|
if (providerConfigured) {
|
|
@@ -1886,7 +2056,7 @@ function registerInit(program2) {
|
|
|
1886
2056
|
}
|
|
1887
2057
|
|
|
1888
2058
|
// src/cli/status.ts
|
|
1889
|
-
var
|
|
2059
|
+
var import_fs14 = __toESM(require("fs"));
|
|
1890
2060
|
var import_chalk3 = __toESM(require("chalk"));
|
|
1891
2061
|
function registerStatus(program2) {
|
|
1892
2062
|
program2.command("status").description("Show capture status and event counts").action(() => {
|
|
@@ -1894,7 +2064,7 @@ function registerStatus(program2) {
|
|
|
1894
2064
|
const total = getEventCount();
|
|
1895
2065
|
const todayEvents = getEventsForDate(todayDate());
|
|
1896
2066
|
const last = getLastEvent();
|
|
1897
|
-
const isPaused =
|
|
2067
|
+
const isPaused = import_fs14.default.existsSync(PAUSE_FLAG_PATH);
|
|
1898
2068
|
log.plain("");
|
|
1899
2069
|
log.plain(import_chalk3.default.bold(" Workscribe Status"));
|
|
1900
2070
|
log.plain("");
|
|
@@ -2154,8 +2324,8 @@ function registerSessions(program2) {
|
|
|
2154
2324
|
|
|
2155
2325
|
// src/cli/summary.ts
|
|
2156
2326
|
var import_chalk6 = __toESM(require("chalk"));
|
|
2157
|
-
var
|
|
2158
|
-
var
|
|
2327
|
+
var import_fs15 = __toESM(require("fs"));
|
|
2328
|
+
var import_os6 = __toESM(require("os"));
|
|
2159
2329
|
var import_path10 = __toESM(require("path"));
|
|
2160
2330
|
|
|
2161
2331
|
// src/integrations/webhook.ts
|
|
@@ -2224,7 +2394,7 @@ async function handleWebhook(opts, config, summary) {
|
|
|
2224
2394
|
if (webhookUrl) {
|
|
2225
2395
|
try {
|
|
2226
2396
|
log.info("Posting to webhook\u2026");
|
|
2227
|
-
const username =
|
|
2397
|
+
const username = import_os6.default.userInfo().username;
|
|
2228
2398
|
const body = isSlackWebhookUrl(webhookUrl) ? formatForSlack(summary, username) : summary;
|
|
2229
2399
|
await postToWebhook(webhookUrl, body);
|
|
2230
2400
|
log.success("Posted.");
|
|
@@ -2262,8 +2432,8 @@ function registerSummary(program2) {
|
|
|
2262
2432
|
}
|
|
2263
2433
|
const cacheKey = isoWeekKey(today);
|
|
2264
2434
|
const cacheFile = import_path10.default.join(WEEKLY_CACHE_DIR, `${cacheKey}.md`);
|
|
2265
|
-
if (!opts.fresh &&
|
|
2266
|
-
const cached =
|
|
2435
|
+
if (!opts.fresh && import_fs15.default.existsSync(cacheFile)) {
|
|
2436
|
+
const cached = import_fs15.default.readFileSync(cacheFile, "utf-8");
|
|
2267
2437
|
log.plain("");
|
|
2268
2438
|
log.plain(cached);
|
|
2269
2439
|
log.plain("");
|
|
@@ -2279,8 +2449,8 @@ function registerSummary(program2) {
|
|
|
2279
2449
|
log.plain("");
|
|
2280
2450
|
log.plain(summary);
|
|
2281
2451
|
log.plain("");
|
|
2282
|
-
|
|
2283
|
-
|
|
2452
|
+
import_fs15.default.mkdirSync(WEEKLY_CACHE_DIR, { recursive: true });
|
|
2453
|
+
import_fs15.default.writeFileSync(cacheFile, summary, { encoding: "utf-8", mode: 384 });
|
|
2284
2454
|
await handleWebhook(opts, config, summary);
|
|
2285
2455
|
} catch (error) {
|
|
2286
2456
|
log.error(`Weekly summary failed [${config.ai.provider}]: ${error.message}`);
|
|
@@ -2398,7 +2568,7 @@ ${bullets.trim()}`;
|
|
|
2398
2568
|
}
|
|
2399
2569
|
|
|
2400
2570
|
// src/cli/export.ts
|
|
2401
|
-
var
|
|
2571
|
+
var import_fs16 = __toESM(require("fs"));
|
|
2402
2572
|
var import_path11 = __toESM(require("path"));
|
|
2403
2573
|
function eventRowToPayload2(row) {
|
|
2404
2574
|
let metadata = {};
|
|
@@ -2456,8 +2626,8 @@ function registerExport(program2) {
|
|
|
2456
2626
|
log.info(`Generating summary via ${config.ai.provider}\u2026`);
|
|
2457
2627
|
const summary = await provider.summarize(payload);
|
|
2458
2628
|
const outputPath = opts.output ?? import_path11.default.join(EXPORTS_DIR, `workscribe-${date}.md`);
|
|
2459
|
-
if (!
|
|
2460
|
-
|
|
2629
|
+
if (!import_fs16.default.existsSync(EXPORTS_DIR)) import_fs16.default.mkdirSync(EXPORTS_DIR, { recursive: true, mode: 448 });
|
|
2630
|
+
import_fs16.default.writeFileSync(outputPath, `# Work Summary \u2014 ${date}
|
|
2461
2631
|
|
|
2462
2632
|
${summary}
|
|
2463
2633
|
`, { encoding: "utf-8", mode: 384 });
|
|
@@ -2529,22 +2699,22 @@ function printConfig(obj, indent) {
|
|
|
2529
2699
|
}
|
|
2530
2700
|
|
|
2531
2701
|
// src/cli/pause.ts
|
|
2532
|
-
var
|
|
2702
|
+
var import_fs17 = __toESM(require("fs"));
|
|
2533
2703
|
function registerPause(program2) {
|
|
2534
2704
|
program2.command("pause").description("Pause capture temporarily").action(() => {
|
|
2535
|
-
if (
|
|
2705
|
+
if (import_fs17.default.existsSync(PAUSE_FLAG_PATH)) {
|
|
2536
2706
|
log.info("Capture is already paused. Run workscribe resume to restart.");
|
|
2537
2707
|
return;
|
|
2538
2708
|
}
|
|
2539
|
-
|
|
2709
|
+
import_fs17.default.writeFileSync(PAUSE_FLAG_PATH, "", { mode: 384 });
|
|
2540
2710
|
log.success("Capture paused. Run workscribe resume to restart.");
|
|
2541
2711
|
});
|
|
2542
2712
|
program2.command("resume").description("Resume capture after a pause").action(() => {
|
|
2543
|
-
if (!
|
|
2713
|
+
if (!import_fs17.default.existsSync(PAUSE_FLAG_PATH)) {
|
|
2544
2714
|
log.info("Capture is not paused.");
|
|
2545
2715
|
return;
|
|
2546
2716
|
}
|
|
2547
|
-
|
|
2717
|
+
import_fs17.default.rmSync(PAUSE_FLAG_PATH);
|
|
2548
2718
|
log.success("Capture resumed.");
|
|
2549
2719
|
});
|
|
2550
2720
|
}
|
|
@@ -2629,18 +2799,19 @@ function registerClear(program2) {
|
|
|
2629
2799
|
}
|
|
2630
2800
|
|
|
2631
2801
|
// src/cli/uninstall.ts
|
|
2632
|
-
var
|
|
2802
|
+
var import_fs18 = __toESM(require("fs"));
|
|
2633
2803
|
var import_path12 = __toESM(require("path"));
|
|
2634
|
-
var
|
|
2804
|
+
var import_os7 = __toESM(require("os"));
|
|
2635
2805
|
var import_prompts3 = __toESM(require("prompts"));
|
|
2636
2806
|
var import_chalk9 = __toESM(require("chalk"));
|
|
2637
2807
|
function detectShellRcFiles() {
|
|
2638
2808
|
const candidates = [
|
|
2639
|
-
{ name: "zsh", rcFile: import_path12.default.join(
|
|
2640
|
-
{ name: "bash", rcFile: import_path12.default.join(
|
|
2641
|
-
{ name: "bash", rcFile: import_path12.default.join(
|
|
2809
|
+
{ name: "zsh", rcFile: import_path12.default.join(import_os7.default.homedir(), ".zshrc") },
|
|
2810
|
+
{ name: "bash", rcFile: import_path12.default.join(import_os7.default.homedir(), ".bashrc") },
|
|
2811
|
+
{ name: "bash", rcFile: import_path12.default.join(import_os7.default.homedir(), ".bash_profile") },
|
|
2812
|
+
{ name: "fish", rcFile: import_path12.default.join(import_os7.default.homedir(), ".config", "fish", "conf.d", "workscribe.fish") }
|
|
2642
2813
|
];
|
|
2643
|
-
return candidates.filter((candidate) =>
|
|
2814
|
+
return candidates.filter((candidate) => import_fs18.default.existsSync(candidate.rcFile) && isHookInstalled(candidate.rcFile));
|
|
2644
2815
|
}
|
|
2645
2816
|
function registerUninstall(program2) {
|
|
2646
2817
|
program2.command("uninstall").description("Remove shell hooks and optionally delete all Workscribe data").option("--hooks-only", "remove shell hooks only, skip data deletion prompt (used by npm preuninstall)").action(async (opts) => {
|
|
@@ -2650,16 +2821,23 @@ function registerUninstall(program2) {
|
|
|
2650
2821
|
log.info("No shell hooks found");
|
|
2651
2822
|
} else {
|
|
2652
2823
|
for (const { name, rcFile } of hooked) {
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2824
|
+
if (name === "fish") {
|
|
2825
|
+
import_fs18.default.unlinkSync(rcFile);
|
|
2826
|
+
log.success(`Shell hook removed: ${rcFile}`);
|
|
2827
|
+
log.plain(` ${import_chalk9.default.dim("Restart your terminal to take effect")}`);
|
|
2828
|
+
} else {
|
|
2829
|
+
removeHook(rcFile);
|
|
2830
|
+
log.success(`Shell hook removed from ${rcFile}`);
|
|
2831
|
+
log.plain(` ${import_chalk9.default.dim(`Run: source ${rcFile}`)} (or restart your terminal to take effect)`);
|
|
2832
|
+
log.plain(
|
|
2833
|
+
` ${import_chalk9.default.dim(`${name === "zsh" ? "unfunction" : "unset -f"} _workscribe_preexec _workscribe_precmd`)}`
|
|
2834
|
+
);
|
|
2835
|
+
}
|
|
2659
2836
|
}
|
|
2660
2837
|
}
|
|
2661
2838
|
if (opts.hooksOnly) return;
|
|
2662
|
-
|
|
2839
|
+
const existingDirs = [...new Set(REQUIRED_DIRS)].filter((dir) => import_fs18.default.existsSync(dir));
|
|
2840
|
+
if (existingDirs.length > 0) {
|
|
2663
2841
|
log.plain("");
|
|
2664
2842
|
const { deleteData } = await (0, import_prompts3.default)({
|
|
2665
2843
|
type: "confirm",
|
|
@@ -2668,8 +2846,10 @@ function registerUninstall(program2) {
|
|
|
2668
2846
|
initial: false
|
|
2669
2847
|
});
|
|
2670
2848
|
if (deleteData) {
|
|
2671
|
-
|
|
2672
|
-
|
|
2849
|
+
for (const dir of existingDirs) {
|
|
2850
|
+
import_fs18.default.rmSync(dir, { recursive: true, force: true });
|
|
2851
|
+
log.success(`Deleted ${dir}`);
|
|
2852
|
+
}
|
|
2673
2853
|
} else {
|
|
2674
2854
|
log.info(`Data kept at ${WORKSCRIBE_DIR}`);
|
|
2675
2855
|
}
|
|
@@ -2681,7 +2861,7 @@ function registerUninstall(program2) {
|
|
|
2681
2861
|
}
|
|
2682
2862
|
|
|
2683
2863
|
// src/cli/profile.ts
|
|
2684
|
-
var
|
|
2864
|
+
var import_fs19 = __toESM(require("fs"));
|
|
2685
2865
|
var import_path13 = __toESM(require("path"));
|
|
2686
2866
|
var import_chalk10 = __toESM(require("chalk"));
|
|
2687
2867
|
var MIN_SUGGEST_COUNT = 5;
|
|
@@ -2728,7 +2908,7 @@ function registerProfile(program2) {
|
|
|
2728
2908
|
log.plain(import_chalk10.default.dim(" " + "\u2500".repeat(60)));
|
|
2729
2909
|
for (const entry of entries) {
|
|
2730
2910
|
const badge = activeNames.has(entry.name) ? import_chalk10.default.green(" [active]") : "";
|
|
2731
|
-
const installed =
|
|
2911
|
+
const installed = import_fs19.default.existsSync(import_path13.default.join(PROFILES_DIR, `${entry.name}.json`)) ? import_chalk10.default.dim(" installed") : "";
|
|
2732
2912
|
log.plain(` ${import_chalk10.default.cyan(entry.name.padEnd(18))} ${entry.displayName.padEnd(28)}${badge}${installed}`);
|
|
2733
2913
|
if (entry.description) log.plain(` ${import_chalk10.default.dim(" ".repeat(18) + entry.description)}`);
|
|
2734
2914
|
}
|
|
@@ -2765,7 +2945,7 @@ function registerProfile(program2) {
|
|
|
2765
2945
|
}
|
|
2766
2946
|
activeNames.delete(name);
|
|
2767
2947
|
const cachePath = import_path13.default.join(PROFILES_DIR, `${name}.json`);
|
|
2768
|
-
if (
|
|
2948
|
+
if (import_fs19.default.existsSync(cachePath)) import_fs19.default.unlinkSync(cachePath);
|
|
2769
2949
|
log.success(`Profile "${name}" removed`);
|
|
2770
2950
|
}
|
|
2771
2951
|
config.capture.profiles = [...activeNames];
|
|
@@ -2829,14 +3009,37 @@ function registerProfile(program2) {
|
|
|
2829
3009
|
const suggestions = [];
|
|
2830
3010
|
for (const entry of manifest) {
|
|
2831
3011
|
if (activeNames.has(entry.name)) continue;
|
|
2832
|
-
const matchedCount = toolCounts.filter(
|
|
3012
|
+
const matchedCount = toolCounts.filter(
|
|
3013
|
+
(toolCount) => entry.keywords.some((keyword) => toolCount.tool.toLowerCase().includes(keyword.toLowerCase()))
|
|
3014
|
+
).reduce((total, toolCount) => total + toolCount.count, 0);
|
|
2833
3015
|
if (matchedCount >= MIN_SUGGEST_COUNT) {
|
|
2834
3016
|
suggestions.push({ entry, count: matchedCount });
|
|
2835
3017
|
}
|
|
2836
3018
|
}
|
|
2837
3019
|
suggestions.sort((a, b) => b.count - a.count);
|
|
2838
3020
|
if (suggestions.length === 0) {
|
|
2839
|
-
|
|
3021
|
+
const activeEntries = manifest.filter((entry) => activeNames.has(entry.name));
|
|
3022
|
+
const isToolCoveredByActiveProfile = (tool) => activeEntries.some(
|
|
3023
|
+
(entry) => entry.keywords.some((keyword) => tool.toLowerCase().includes(keyword.toLowerCase()))
|
|
3024
|
+
);
|
|
3025
|
+
const uncoveredTools = toolCounts.filter((toolCount) => !isToolCoveredByActiveProfile(toolCount.tool));
|
|
3026
|
+
if (uncoveredTools.length === 0) {
|
|
3027
|
+
log.plain("");
|
|
3028
|
+
log.plain("Your active profiles cover all unclassified commands.");
|
|
3029
|
+
log.plain(import_chalk10.default.dim(" Future captures will be classified correctly."));
|
|
3030
|
+
log.plain("");
|
|
3031
|
+
} else {
|
|
3032
|
+
log.plain("");
|
|
3033
|
+
log.plain("No profile matches found for your unclassified commands.");
|
|
3034
|
+
log.plain("");
|
|
3035
|
+
log.plain(import_chalk10.default.dim(" Top unclassified tools:"));
|
|
3036
|
+
for (const { tool, count } of uncoveredTools.slice(0, 5)) {
|
|
3037
|
+
log.plain(import_chalk10.default.dim(` ${tool.padEnd(24)} ${count} event${count === 1 ? "" : "s"}`));
|
|
3038
|
+
}
|
|
3039
|
+
log.plain("");
|
|
3040
|
+
log.plain(import_chalk10.default.dim(" Run workscribe events --category other to review them."));
|
|
3041
|
+
log.plain("");
|
|
3042
|
+
}
|
|
2840
3043
|
return;
|
|
2841
3044
|
}
|
|
2842
3045
|
log.plain("");
|
|
@@ -2848,8 +3051,25 @@ function registerProfile(program2) {
|
|
|
2848
3051
|
);
|
|
2849
3052
|
}
|
|
2850
3053
|
log.plain("");
|
|
2851
|
-
log.plain(
|
|
3054
|
+
log.plain(
|
|
3055
|
+
` Run: ${import_chalk10.default.cyan("workscribe profile add " + suggestions.map((suggestion) => suggestion.entry.name).join(" "))}`
|
|
3056
|
+
);
|
|
2852
3057
|
log.plain("");
|
|
3058
|
+
const allCoveredEntries = [
|
|
3059
|
+
...manifest.filter((entry) => activeNames.has(entry.name)),
|
|
3060
|
+
...suggestions.map((suggestion) => suggestion.entry)
|
|
3061
|
+
];
|
|
3062
|
+
const isToolCoveredAfterInstall = (tool) => allCoveredEntries.some(
|
|
3063
|
+
(entry) => entry.keywords.some((keyword) => tool.toLowerCase().includes(keyword.toLowerCase()))
|
|
3064
|
+
);
|
|
3065
|
+
const stillUncovered = toolCounts.filter((toolCount) => !isToolCoveredAfterInstall(toolCount.tool)).slice(0, 5);
|
|
3066
|
+
if (stillUncovered.length > 0) {
|
|
3067
|
+
log.plain(import_chalk10.default.dim(" Still uncovered after installing:"));
|
|
3068
|
+
for (const { tool, count } of stillUncovered) {
|
|
3069
|
+
log.plain(import_chalk10.default.dim(` ${tool.padEnd(24)} ${count} event${count === 1 ? "" : "s"}`));
|
|
3070
|
+
}
|
|
3071
|
+
log.plain("");
|
|
3072
|
+
}
|
|
2853
3073
|
});
|
|
2854
3074
|
}
|
|
2855
3075
|
|
|
@@ -2874,9 +3094,9 @@ function registerNote(program2) {
|
|
|
2874
3094
|
|
|
2875
3095
|
// src/cli/week.ts
|
|
2876
3096
|
var import_chalk11 = __toESM(require("chalk"));
|
|
2877
|
-
var
|
|
3097
|
+
var import_fs20 = __toESM(require("fs"));
|
|
2878
3098
|
var import_path14 = __toESM(require("path"));
|
|
2879
|
-
var
|
|
3099
|
+
var import_os8 = __toESM(require("os"));
|
|
2880
3100
|
function eventRowToPayload3(row) {
|
|
2881
3101
|
let metadata = {};
|
|
2882
3102
|
try {
|
|
@@ -2915,7 +3135,7 @@ async function postSummary(opts, config, summary) {
|
|
|
2915
3135
|
}
|
|
2916
3136
|
try {
|
|
2917
3137
|
log.info("Posting to webhook\u2026");
|
|
2918
|
-
const username =
|
|
3138
|
+
const username = import_os8.default.userInfo().username;
|
|
2919
3139
|
const body = isSlackWebhookUrl(webhookUrl) ? formatForSlack(summary, username) : summary;
|
|
2920
3140
|
await postToWebhook(webhookUrl, body);
|
|
2921
3141
|
log.success("Posted.");
|
|
@@ -2949,8 +3169,8 @@ function registerWeek(program2) {
|
|
|
2949
3169
|
}
|
|
2950
3170
|
const cacheKey = isoWeekKey(today);
|
|
2951
3171
|
const cacheFile = import_path14.default.join(WEEKLY_CACHE_DIR, `${cacheKey}.md`);
|
|
2952
|
-
if (!opts.fresh &&
|
|
2953
|
-
const cached =
|
|
3172
|
+
if (!opts.fresh && import_fs20.default.existsSync(cacheFile)) {
|
|
3173
|
+
const cached = import_fs20.default.readFileSync(cacheFile, "utf-8");
|
|
2954
3174
|
log.plain("");
|
|
2955
3175
|
log.plain(cached);
|
|
2956
3176
|
log.plain("");
|
|
@@ -2966,8 +3186,8 @@ function registerWeek(program2) {
|
|
|
2966
3186
|
log.plain("");
|
|
2967
3187
|
log.plain(summary);
|
|
2968
3188
|
log.plain("");
|
|
2969
|
-
|
|
2970
|
-
|
|
3189
|
+
import_fs20.default.mkdirSync(WEEKLY_CACHE_DIR, { recursive: true });
|
|
3190
|
+
import_fs20.default.writeFileSync(cacheFile, summary, { encoding: "utf-8", mode: 384 });
|
|
2971
3191
|
await postSummary(opts, config, summary);
|
|
2972
3192
|
} catch (error) {
|
|
2973
3193
|
log.error(`Weekly digest failed [${config.ai.provider}]: ${error.message}`);
|
|
@@ -2976,10 +3196,136 @@ function registerWeek(program2) {
|
|
|
2976
3196
|
});
|
|
2977
3197
|
}
|
|
2978
3198
|
|
|
3199
|
+
// src/cli/bug-report.ts
|
|
3200
|
+
var import_fs21 = __toESM(require("fs"));
|
|
3201
|
+
var import_os9 = __toESM(require("os"));
|
|
3202
|
+
var import_path15 = __toESM(require("path"));
|
|
3203
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
3204
|
+
var GITHUB_ISSUES_URL = "https://github.com/workscribe/workscribe/issues/new";
|
|
3205
|
+
var DEBUG_LOG_TAIL_LINES = 100;
|
|
3206
|
+
function tailFile(filePath, lines) {
|
|
3207
|
+
if (!import_fs21.default.existsSync(filePath)) return "(no debug log found \u2014 set WORKSCRIBE_DEBUG=1 to enable)";
|
|
3208
|
+
const content = import_fs21.default.readFileSync(filePath, "utf-8");
|
|
3209
|
+
const allLines = content.split("\n");
|
|
3210
|
+
return allLines.slice(-lines).join("\n");
|
|
3211
|
+
}
|
|
3212
|
+
function redactConfig() {
|
|
3213
|
+
try {
|
|
3214
|
+
const config = readConfig();
|
|
3215
|
+
if (config.ai.apiKey) config.ai.apiKey = "<redacted>";
|
|
3216
|
+
if (config.integrations?.slackWebhook) config.integrations.slackWebhook = "<redacted>";
|
|
3217
|
+
if (config.integrations?.webhook) config.integrations.webhook = "<redacted>";
|
|
3218
|
+
return JSON.stringify(config, null, 2);
|
|
3219
|
+
} catch {
|
|
3220
|
+
return "(could not read config)";
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
function registerBugReport(program2) {
|
|
3224
|
+
program2.command("bug-report").description("Generate a diagnostic report for filing a bug").action(() => {
|
|
3225
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3226
|
+
const reportPath = import_path15.default.join(WORKSCRIBE_DIR, `bug-report-${timestamp}.txt`);
|
|
3227
|
+
const systemInfo = [
|
|
3228
|
+
`Workscribe version : ${"1.12.0"}`,
|
|
3229
|
+
`Node.js version : ${process.version}`,
|
|
3230
|
+
`Platform : ${process.platform}`,
|
|
3231
|
+
`Architecture : ${process.arch}`,
|
|
3232
|
+
`OS release : ${import_os9.default.release()}`,
|
|
3233
|
+
`Config path : ${CONFIG_PATH}`,
|
|
3234
|
+
`Data directory : ${WORKSCRIBE_DIR}`
|
|
3235
|
+
].join("\n");
|
|
3236
|
+
const report = [
|
|
3237
|
+
"=== Workscribe Bug Report ===",
|
|
3238
|
+
`Generated: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
3239
|
+
"",
|
|
3240
|
+
"--- System ---",
|
|
3241
|
+
systemInfo,
|
|
3242
|
+
"",
|
|
3243
|
+
"--- Config (secrets redacted) ---",
|
|
3244
|
+
redactConfig(),
|
|
3245
|
+
"",
|
|
3246
|
+
`--- Debug log (last ${DEBUG_LOG_TAIL_LINES} lines) ---`,
|
|
3247
|
+
tailFile(DEBUG_LOG_PATH, DEBUG_LOG_TAIL_LINES)
|
|
3248
|
+
].join("\n");
|
|
3249
|
+
try {
|
|
3250
|
+
if (!import_fs21.default.existsSync(WORKSCRIBE_DIR)) {
|
|
3251
|
+
import_fs21.default.mkdirSync(WORKSCRIBE_DIR, { recursive: true, mode: 448 });
|
|
3252
|
+
}
|
|
3253
|
+
import_fs21.default.writeFileSync(reportPath, report, { mode: 384 });
|
|
3254
|
+
} catch (error) {
|
|
3255
|
+
log.error(`Could not write report: ${error.message}`);
|
|
3256
|
+
process.exit(1);
|
|
3257
|
+
}
|
|
3258
|
+
const params = new URLSearchParams({
|
|
3259
|
+
title: `Bug report \u2014 workscribe ${"1.12.0"}`,
|
|
3260
|
+
body: `<!-- Attach ${import_path15.default.basename(reportPath)} or paste the relevant sections below -->
|
|
3261
|
+
|
|
3262
|
+
**Describe the issue:**
|
|
3263
|
+
|
|
3264
|
+
**Steps to reproduce:**
|
|
3265
|
+
|
|
3266
|
+
**Expected behaviour:**`
|
|
3267
|
+
});
|
|
3268
|
+
log.success(`Report written to: ${import_chalk12.default.cyan(reportPath)}`);
|
|
3269
|
+
log.plain("");
|
|
3270
|
+
log.plain(` Open a GitHub issue:`);
|
|
3271
|
+
log.plain(` ${import_chalk12.default.cyan(`${GITHUB_ISSUES_URL}?${params}`)}`);
|
|
3272
|
+
log.plain("");
|
|
3273
|
+
log.plain(import_chalk12.default.dim(` Attach the report or paste the relevant sections into the issue.`));
|
|
3274
|
+
log.plain("");
|
|
3275
|
+
});
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3278
|
+
// src/utils/update-check.ts
|
|
3279
|
+
var import_fs22 = __toESM(require("fs"));
|
|
3280
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
3281
|
+
function readCache() {
|
|
3282
|
+
try {
|
|
3283
|
+
return JSON.parse(import_fs22.default.readFileSync(UPDATE_CHECK_PATH, "utf-8"));
|
|
3284
|
+
} catch {
|
|
3285
|
+
return null;
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
function writeCache(cache) {
|
|
3289
|
+
try {
|
|
3290
|
+
import_fs22.default.writeFileSync(UPDATE_CHECK_PATH, JSON.stringify(cache), { mode: 384 });
|
|
3291
|
+
} catch {
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
function isNewer(latest, current) {
|
|
3295
|
+
const parse = (version) => version.replace(/^v/, "").split(".").map(Number);
|
|
3296
|
+
const [latestMajor, latestMinor, latestPatch] = parse(latest);
|
|
3297
|
+
const [currentMajor, currentMinor, currentPatch] = parse(current);
|
|
3298
|
+
if (latestMajor !== currentMajor) return latestMajor > currentMajor;
|
|
3299
|
+
if (latestMinor !== currentMinor) return latestMinor > currentMinor;
|
|
3300
|
+
return latestPatch > currentPatch;
|
|
3301
|
+
}
|
|
3302
|
+
function checkForUpdate() {
|
|
3303
|
+
const current = "1.12.0";
|
|
3304
|
+
const cache = readCache();
|
|
3305
|
+
if (cache && isNewer(cache.latestVersion, current)) {
|
|
3306
|
+
process.stderr.write(
|
|
3307
|
+
`
|
|
3308
|
+
Update available ${current} \u2192 ${cache.latestVersion}
|
|
3309
|
+
Run: npm install -g @workscribe/cli
|
|
3310
|
+
|
|
3311
|
+
`
|
|
3312
|
+
);
|
|
3313
|
+
}
|
|
3314
|
+
const now = Date.now();
|
|
3315
|
+
if (!cache || now - cache.lastChecked > CHECK_INTERVAL_MS) {
|
|
3316
|
+
fetch("https://registry.npmjs.org/@workscribe/cli/latest").then((response) => response.json()).then((data) => {
|
|
3317
|
+
const latest = data.version;
|
|
3318
|
+
if (latest) writeCache({ lastChecked: now, latestVersion: latest });
|
|
3319
|
+
}).catch(() => {
|
|
3320
|
+
});
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
|
|
2979
3324
|
// src/index.ts
|
|
2980
3325
|
assertNodeVersion(process.versions.node);
|
|
3326
|
+
checkForUpdate();
|
|
2981
3327
|
var program = new import_commander.Command();
|
|
2982
|
-
program.name("workscribe").description("Automatic developer work journal").version("1.
|
|
3328
|
+
program.name("workscribe").description("Automatic developer work journal").version("1.12.0");
|
|
2983
3329
|
registerCapture(program);
|
|
2984
3330
|
registerHook(program);
|
|
2985
3331
|
registerInit(program);
|
|
@@ -2996,5 +3342,7 @@ registerUninstall(program);
|
|
|
2996
3342
|
registerProfile(program);
|
|
2997
3343
|
registerNote(program);
|
|
2998
3344
|
registerWeek(program);
|
|
3345
|
+
registerBugReport(program);
|
|
3346
|
+
registerCompletions(program);
|
|
2999
3347
|
program.parse();
|
|
3000
3348
|
//# sourceMappingURL=index.js.map
|