@workscribe/cli 1.8.0 → 1.9.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 +92 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -121,7 +121,7 @@ function applyMigrations(db) {
|
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
const applied = new Set(
|
|
124
|
-
db.prepare("SELECT version FROM schema_migrations").all().map((
|
|
124
|
+
db.prepare("SELECT version FROM schema_migrations").all().map((row) => row.version)
|
|
125
125
|
);
|
|
126
126
|
for (const migration of MIGRATIONS) {
|
|
127
127
|
if (applied.has(migration.version)) continue;
|
|
@@ -208,7 +208,7 @@ function updateSessionSummary(sessionId, summary) {
|
|
|
208
208
|
function getLastEventIds(n) {
|
|
209
209
|
const db = getDb();
|
|
210
210
|
const rows = db.prepare("SELECT id FROM events ORDER BY id DESC LIMIT $n").all({ n });
|
|
211
|
-
return rows.map((
|
|
211
|
+
return rows.map((row) => row.id);
|
|
212
212
|
}
|
|
213
213
|
function getEventsByIds(ids) {
|
|
214
214
|
if (ids.length === 0) return [];
|
|
@@ -488,7 +488,7 @@ function makeRule(pattern, category, extract = () => ({})) {
|
|
|
488
488
|
function extractPackages(cmd, afterKeyword) {
|
|
489
489
|
const idx = cmd.indexOf(afterKeyword);
|
|
490
490
|
if (idx === -1) return [];
|
|
491
|
-
return cmd.slice(idx + afterKeyword.length).trim().split(/\s+/).filter((
|
|
491
|
+
return cmd.slice(idx + afterKeyword.length).trim().split(/\s+/).filter((part) => part && !part.startsWith("-"));
|
|
492
492
|
}
|
|
493
493
|
var RULES = [
|
|
494
494
|
// ─── Git operations ───────────────────────────────────────────────────────
|
|
@@ -506,7 +506,7 @@ var RULES = [
|
|
|
506
506
|
}),
|
|
507
507
|
makeRule(/^git\s+(checkout|switch)\b/, "branch_switch", (_m, cmd) => {
|
|
508
508
|
const parts = cmd.split(/\s+/);
|
|
509
|
-
const branch = parts.find((
|
|
509
|
+
const branch = parts.find((part) => !part.startsWith("-") && part !== "git" && part !== parts[1]);
|
|
510
510
|
return { branch: branch ?? null };
|
|
511
511
|
}),
|
|
512
512
|
makeRule(/^git\s+(merge|rebase)\b/, "code_merge", (_m, cmd) => {
|
|
@@ -572,7 +572,7 @@ var RULES = [
|
|
|
572
572
|
makeRule(/^yarn\s+test\b/, "test_run", () => ({ tool: "yarn" })),
|
|
573
573
|
makeRule(/^pnpm\s+test\b/, "test_run", () => ({ tool: "pnpm" })),
|
|
574
574
|
makeRule(/^bun\s+test\b/, "test_run", () => ({ tool: "bun" })),
|
|
575
|
-
makeRule(/^(jest|vitest)\b/, "test_run", (
|
|
575
|
+
makeRule(/^(jest|vitest)\b/, "test_run", (match) => ({ tool: match[1] })),
|
|
576
576
|
makeRule(/^pytest\b/, "test_run", () => ({ tool: "pytest" })),
|
|
577
577
|
makeRule(/^go\s+test\b/, "test_run", () => ({ tool: "go" })),
|
|
578
578
|
makeRule(/^cargo\s+test\b/, "test_run", () => ({ tool: "cargo" })),
|
|
@@ -580,19 +580,19 @@ var RULES = [
|
|
|
580
580
|
makeRule(/^(php\s+)?phpunit\b/, "test_run", () => ({ tool: "phpunit" })),
|
|
581
581
|
// ─── Build ────────────────────────────────────────────────────────────────
|
|
582
582
|
makeRule(/^npm\s+run\s+build\b/, "build", () => ({ tool: "npm" })),
|
|
583
|
-
makeRule(/^(yarn|pnpm)\s+build\b/, "build", (
|
|
583
|
+
makeRule(/^(yarn|pnpm)\s+build\b/, "build", (match) => ({ tool: match[1] })),
|
|
584
584
|
makeRule(/^bun\s+run\s+build\b/, "build", () => ({ tool: "bun" })),
|
|
585
|
-
makeRule(/^(make|gmake)\b/, "build", (
|
|
585
|
+
makeRule(/^(make|gmake)\b/, "build", (match) => ({ tool: match[1] })),
|
|
586
586
|
makeRule(/^cargo\s+build\b/, "build", () => ({ tool: "cargo" })),
|
|
587
587
|
makeRule(/^go\s+build\b/, "build", () => ({ tool: "go" })),
|
|
588
588
|
makeRule(/^docker\s+build\b/, "build", () => ({ tool: "docker" })),
|
|
589
|
-
makeRule(/^(mvn|gradle)\b/, "build", (
|
|
589
|
+
makeRule(/^(mvn|gradle)\b/, "build", (match) => ({ tool: match[1] })),
|
|
590
590
|
// ─── Dev server ───────────────────────────────────────────────────────────
|
|
591
591
|
makeRule(/^npm\s+run\s+(dev|start|serve)\b/, "server_run", (_m, cmd) => ({
|
|
592
592
|
tool: "npm",
|
|
593
593
|
script: cmd.split(/\s+/)[2]
|
|
594
594
|
})),
|
|
595
|
-
makeRule(/^(yarn|pnpm)\s+(dev|start)\b/, "server_run", (
|
|
595
|
+
makeRule(/^(yarn|pnpm)\s+(dev|start)\b/, "server_run", (match) => ({ tool: match[1], script: match[2] })),
|
|
596
596
|
makeRule(/^bun\s+run\s+(dev|start|serve)\b/, "server_run", (_m, cmd) => ({
|
|
597
597
|
tool: "bun",
|
|
598
598
|
script: cmd.split(/\s+/)[2]
|
|
@@ -634,7 +634,7 @@ var RULES = [
|
|
|
634
634
|
tool: cmd.split(/\s+/)[1]
|
|
635
635
|
})),
|
|
636
636
|
// ─── Scripts ──────────────────────────────────────────────────────────────
|
|
637
|
-
makeRule(/^(bash|sh|zsh|fish)\s+\S+/, "script_run", (
|
|
637
|
+
makeRule(/^(bash|sh|zsh|fish)\s+\S+/, "script_run", (match) => ({ shell: match[1] })),
|
|
638
638
|
makeRule(/^node\s+\S+\.(?:js|mjs|cjs)\b/, "script_run", () => ({ runtime: "node" })),
|
|
639
639
|
makeRule(/^python3?\s+\S+\.py\b/, "script_run", () => ({ runtime: "python" })),
|
|
640
640
|
// ─── Environment ──────────────────────────────────────────────────────────
|
|
@@ -653,18 +653,18 @@ var RULES = [
|
|
|
653
653
|
script: cmd.split(/\s+/)[2]
|
|
654
654
|
})),
|
|
655
655
|
// ─── Code search ─────────────────────────────────────────────────────────
|
|
656
|
-
makeRule(/^(grep|egrep|fgrep)\b/, "code_search", (
|
|
657
|
-
makeRule(/^(rg|ag|ack|ripgrep)\b/, "code_search", (
|
|
656
|
+
makeRule(/^(grep|egrep|fgrep)\b/, "code_search", (match) => ({ tool: match[1] })),
|
|
657
|
+
makeRule(/^(rg|ag|ack|ripgrep)\b/, "code_search", (match) => ({ tool: match[1] })),
|
|
658
658
|
makeRule(/^find\s/, "code_search", () => ({ tool: "find" })),
|
|
659
659
|
// ─── Code read ────────────────────────────────────────────────────────────
|
|
660
|
-
makeRule(/^(cat|bat|less|more)\s+\S+/, "code_read", (
|
|
661
|
-
makeRule(/^(head|tail)\b/, "code_read", (
|
|
660
|
+
makeRule(/^(cat|bat|less|more)\s+\S+/, "code_read", (match) => ({ tool: match[1] })),
|
|
661
|
+
makeRule(/^(head|tail)\b/, "code_read", (match) => ({ tool: match[1] })),
|
|
662
662
|
// ─── File operations ──────────────────────────────────────────────────────
|
|
663
|
-
makeRule(/^(cp|rsync)\b/, "file_ops", (
|
|
663
|
+
makeRule(/^(cp|rsync)\b/, "file_ops", (match) => ({ tool: match[1] })),
|
|
664
664
|
makeRule(/^(mv)\b/, "file_ops", () => ({ tool: "mv" })),
|
|
665
|
-
makeRule(/^(rm|rmdir)\b/, "file_ops", (
|
|
666
|
-
makeRule(/^(mkdir|touch|ln)\b/, "file_ops", (
|
|
667
|
-
makeRule(/^(chmod|chown|chgrp)\b/, "file_ops", (
|
|
665
|
+
makeRule(/^(rm|rmdir)\b/, "file_ops", (match) => ({ tool: match[1] })),
|
|
666
|
+
makeRule(/^(mkdir|touch|ln)\b/, "file_ops", (match) => ({ tool: match[1] })),
|
|
667
|
+
makeRule(/^(chmod|chown|chgrp)\b/, "file_ops", (match) => ({ tool: match[1] })),
|
|
668
668
|
// ─── AI terminal tools (registry-driven) ─────────────────────────────────
|
|
669
669
|
...loadAIToolRegistry().flatMap((entry) => {
|
|
670
670
|
try {
|
|
@@ -800,6 +800,11 @@ function captureCommand(opts) {
|
|
|
800
800
|
const { repoName, branch } = getGitContext(cwd, nameOverride);
|
|
801
801
|
const { category, metadata } = normalizeCommand(safeCommand);
|
|
802
802
|
if (category === "ai_session" && config.capture.aiTools === false) return;
|
|
803
|
+
if (category === "other") {
|
|
804
|
+
const firstToken = safeCommand.trim().split(/\s+/)[0];
|
|
805
|
+
if (firstToken) metadata.tool = firstToken;
|
|
806
|
+
metadata.hint = safeCommand.trim().slice(0, 120);
|
|
807
|
+
}
|
|
803
808
|
if (opts.source) metadata.source = opts.source;
|
|
804
809
|
if (category === "ai_session") {
|
|
805
810
|
if (opts.gitBefore) {
|
|
@@ -977,8 +982,8 @@ var claudeCodeIntegration = {
|
|
|
977
982
|
const postToolUse = settings.hooks?.PostToolUse ?? [];
|
|
978
983
|
return postToolUse.some((entry) => {
|
|
979
984
|
const hooks = entry.hooks ?? [];
|
|
980
|
-
return hooks.some((
|
|
981
|
-
const hook =
|
|
985
|
+
return hooks.some((hookItem) => {
|
|
986
|
+
const hook = hookItem;
|
|
982
987
|
return typeof hook.command === "string" && hook.command.includes("workscribe _hook");
|
|
983
988
|
});
|
|
984
989
|
});
|
|
@@ -1061,7 +1066,7 @@ function registerInit(program2) {
|
|
|
1061
1066
|
}
|
|
1062
1067
|
}
|
|
1063
1068
|
const installedTools = loadAIToolRegistry().filter(
|
|
1064
|
-
(
|
|
1069
|
+
(entry) => entry.hook !== null && AI_HOOK_INTEGRATIONS[entry.hook]?.isInstalled()
|
|
1065
1070
|
);
|
|
1066
1071
|
if (installedTools.length === 0) {
|
|
1067
1072
|
log.info("No AI coding tools detected \u2014 re-run workscribe init after installing one");
|
|
@@ -1260,7 +1265,7 @@ var CATEGORY_COLORS = {
|
|
|
1260
1265
|
other: import_chalk4.default.gray
|
|
1261
1266
|
};
|
|
1262
1267
|
var AI_TOOL_DISPLAY_NAMES = Object.fromEntries(
|
|
1263
|
-
loadAIToolRegistry().map((
|
|
1268
|
+
loadAIToolRegistry().map((entry) => [entry.tool, entry.displayName])
|
|
1264
1269
|
);
|
|
1265
1270
|
function registerEvents(program2) {
|
|
1266
1271
|
program2.command("events").description("List captured events").option("--date <YYYY-MM-DD>", "date to list events for (default: today)").option("--limit <n>", "max events to show", parseInt).action((opts) => {
|
|
@@ -1352,18 +1357,18 @@ function getOrBuildSessions(date) {
|
|
|
1352
1357
|
const existing = getSessionsForDate(date);
|
|
1353
1358
|
const events = getEventsForDate(date);
|
|
1354
1359
|
if (events.length === 0) return [];
|
|
1355
|
-
const cachedEventCount = existing.reduce((sum,
|
|
1360
|
+
const cachedEventCount = existing.reduce((sum, sessionRow) => sum + sessionRow.event_count, 0);
|
|
1356
1361
|
if (existing.length > 0 && cachedEventCount === events.length) {
|
|
1357
|
-
return existing.map((
|
|
1358
|
-
id:
|
|
1359
|
-
date:
|
|
1360
|
-
startedAt:
|
|
1361
|
-
endedAt:
|
|
1362
|
-
repoName:
|
|
1363
|
-
durationMinutes: minutesBetween(
|
|
1364
|
-
eventCount:
|
|
1365
|
-
summary:
|
|
1366
|
-
events: getEventsBySessionId(
|
|
1362
|
+
return existing.map((sessionRow) => ({
|
|
1363
|
+
id: sessionRow.id,
|
|
1364
|
+
date: sessionRow.date,
|
|
1365
|
+
startedAt: sessionRow.started_at,
|
|
1366
|
+
endedAt: sessionRow.ended_at,
|
|
1367
|
+
repoName: sessionRow.repo_name,
|
|
1368
|
+
durationMinutes: minutesBetween(sessionRow.started_at, sessionRow.ended_at),
|
|
1369
|
+
eventCount: sessionRow.event_count,
|
|
1370
|
+
summary: sessionRow.summary,
|
|
1371
|
+
events: getEventsBySessionId(sessionRow.id)
|
|
1367
1372
|
}));
|
|
1368
1373
|
}
|
|
1369
1374
|
const savedSummaries = /* @__PURE__ */ new Map();
|
|
@@ -1492,9 +1497,14 @@ function buildUserMessage(payload) {
|
|
|
1492
1497
|
const counts = /* @__PURE__ */ new Map();
|
|
1493
1498
|
for (const event of session.events) {
|
|
1494
1499
|
if (EXCLUDED.has(event.category)) continue;
|
|
1495
|
-
const meta = Object.keys(event.metadata).length > 0 ? ` ${JSON.stringify(event.metadata)}` : "";
|
|
1496
1500
|
const failed = event.exitCode !== null && event.exitCode !== 0 ? " [failed]" : "";
|
|
1497
|
-
|
|
1501
|
+
let key;
|
|
1502
|
+
if (event.hint) {
|
|
1503
|
+
key = `other [${event.hint}]${failed}`;
|
|
1504
|
+
} else {
|
|
1505
|
+
const meta = Object.keys(event.metadata).length > 0 ? ` ${JSON.stringify(event.metadata)}` : "";
|
|
1506
|
+
key = `${event.category}${meta}${failed}`;
|
|
1507
|
+
}
|
|
1498
1508
|
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
1499
1509
|
}
|
|
1500
1510
|
for (const [key, count] of counts) {
|
|
@@ -1549,9 +1559,14 @@ function buildWeeklyMessage(payload) {
|
|
|
1549
1559
|
const counts = /* @__PURE__ */ new Map();
|
|
1550
1560
|
for (const e of s.events) {
|
|
1551
1561
|
if (EXCLUDED.has(e.category)) continue;
|
|
1552
|
-
const meta = Object.keys(e.metadata).length > 0 ? ` ${JSON.stringify(e.metadata)}` : "";
|
|
1553
1562
|
const failed = e.exitCode !== null && e.exitCode !== 0 ? " [failed]" : "";
|
|
1554
|
-
|
|
1563
|
+
let key;
|
|
1564
|
+
if (e.hint) {
|
|
1565
|
+
key = `other [${e.hint}]${failed}`;
|
|
1566
|
+
} else {
|
|
1567
|
+
const meta = Object.keys(e.metadata).length > 0 ? ` ${JSON.stringify(e.metadata)}` : "";
|
|
1568
|
+
key = `${e.category}${meta}${failed}`;
|
|
1569
|
+
}
|
|
1555
1570
|
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
1556
1571
|
}
|
|
1557
1572
|
const eventLine = [...counts.entries()].map(([k, n]) => `${n > 1 ? `${n}x ` : ""}${k}`).join(", ");
|
|
@@ -1607,7 +1622,7 @@ var AnthropicProvider = class {
|
|
|
1607
1622
|
throw new Error(`Anthropic API error ${response.status}: ${body}`);
|
|
1608
1623
|
}
|
|
1609
1624
|
const data = await response.json();
|
|
1610
|
-
return data.content.find((
|
|
1625
|
+
return data.content.find((block) => block.type === "text")?.text ?? "";
|
|
1611
1626
|
}
|
|
1612
1627
|
async summarizeWeek(payload) {
|
|
1613
1628
|
const response = await fetchWithTimeout("https://api.anthropic.com/v1/messages", {
|
|
@@ -1629,7 +1644,7 @@ var AnthropicProvider = class {
|
|
|
1629
1644
|
throw new Error(`Anthropic API error ${response.status}: ${body}`);
|
|
1630
1645
|
}
|
|
1631
1646
|
const data = await response.json();
|
|
1632
|
-
return data.content.find((
|
|
1647
|
+
return data.content.find((block) => block.type === "text")?.text ?? "";
|
|
1633
1648
|
}
|
|
1634
1649
|
};
|
|
1635
1650
|
|
|
@@ -1815,7 +1830,7 @@ function isSlackWebhookUrl(url) {
|
|
|
1815
1830
|
|
|
1816
1831
|
// src/cli/summary.ts
|
|
1817
1832
|
function parseBullets(text) {
|
|
1818
|
-
return text.split("\n").map((
|
|
1833
|
+
return text.split("\n").map((line) => line.replace(/^[•\-]\s*/, "").trim()).filter(Boolean);
|
|
1819
1834
|
}
|
|
1820
1835
|
function eventRowToPayload(row) {
|
|
1821
1836
|
let metadata = {};
|
|
@@ -1823,12 +1838,18 @@ function eventRowToPayload(row) {
|
|
|
1823
1838
|
if (row.metadata) metadata = JSON.parse(row.metadata);
|
|
1824
1839
|
} catch {
|
|
1825
1840
|
}
|
|
1826
|
-
|
|
1841
|
+
const payload = {
|
|
1827
1842
|
category: row.category,
|
|
1828
1843
|
metadata,
|
|
1829
1844
|
exitCode: row.exit_code,
|
|
1830
1845
|
durationMs: row.duration_ms
|
|
1831
1846
|
};
|
|
1847
|
+
if (row.category === "other" && typeof metadata.hint === "string") {
|
|
1848
|
+
payload.hint = metadata.hint;
|
|
1849
|
+
const { hint: _h, tool: _t, ...rest } = metadata;
|
|
1850
|
+
payload.metadata = rest;
|
|
1851
|
+
}
|
|
1852
|
+
return payload;
|
|
1832
1853
|
}
|
|
1833
1854
|
function sessionToPayload(s, date) {
|
|
1834
1855
|
return {
|
|
@@ -1875,7 +1896,7 @@ function registerSummary(program2) {
|
|
|
1875
1896
|
for (const day of days) {
|
|
1876
1897
|
const sessions2 = getOrBuildSessions(day);
|
|
1877
1898
|
if (sessions2.length > 0) {
|
|
1878
|
-
weeklyDays.push({ date: day, sessions: sessions2.map((
|
|
1899
|
+
weeklyDays.push({ date: day, sessions: sessions2.map((session) => sessionToPayload(session, day)) });
|
|
1879
1900
|
}
|
|
1880
1901
|
}
|
|
1881
1902
|
if (weeklyDays.length === 0) {
|
|
@@ -1897,7 +1918,7 @@ function registerSummary(program2) {
|
|
|
1897
1918
|
log.plain("");
|
|
1898
1919
|
log.info(`Generating weekly summary via ${import_chalk6.default.cyan(config.ai.provider)}\u2026`);
|
|
1899
1920
|
try {
|
|
1900
|
-
const summary = provider.summarizeWeek ? await provider.summarizeWeek(payload) : await provider.summarize({ date: today, sessions: weeklyDays.flatMap((
|
|
1921
|
+
const summary = provider.summarizeWeek ? await provider.summarizeWeek(payload) : await provider.summarize({ date: today, sessions: weeklyDays.flatMap((day) => day.sessions) });
|
|
1901
1922
|
log.plain("");
|
|
1902
1923
|
log.plain(summary);
|
|
1903
1924
|
log.plain("");
|
|
@@ -1926,16 +1947,16 @@ function registerSummary(program2) {
|
|
|
1926
1947
|
}
|
|
1927
1948
|
const jsonMode = config.summary?.format === "json";
|
|
1928
1949
|
if (!opts.fresh) {
|
|
1929
|
-
const allCached = sessions.every((
|
|
1950
|
+
const allCached = sessions.every((session) => session.summary);
|
|
1930
1951
|
if (allCached) {
|
|
1931
|
-
const fullSummary2 = sessions.map((
|
|
1952
|
+
const fullSummary2 = sessions.map((session) => session.summary).join("\n\n");
|
|
1932
1953
|
log.plain("");
|
|
1933
1954
|
if (jsonMode) {
|
|
1934
|
-
const jsonOut = sessions.map((
|
|
1935
|
-
project:
|
|
1936
|
-
branch:
|
|
1937
|
-
durationMinutes:
|
|
1938
|
-
bullets: parseBullets(
|
|
1955
|
+
const jsonOut = sessions.map((session) => ({
|
|
1956
|
+
project: session.repoName,
|
|
1957
|
+
branch: session.events[0]?.branch ?? null,
|
|
1958
|
+
durationMinutes: session.durationMinutes,
|
|
1959
|
+
bullets: parseBullets(session.summary.replace(/^## .+\n/, ""))
|
|
1939
1960
|
}));
|
|
1940
1961
|
log.plain(JSON.stringify({ date, sessions: jsonOut }, null, 2));
|
|
1941
1962
|
} else {
|
|
@@ -1997,7 +2018,18 @@ function eventRowToPayload2(row) {
|
|
|
1997
2018
|
if (row.metadata) metadata = JSON.parse(row.metadata);
|
|
1998
2019
|
} catch {
|
|
1999
2020
|
}
|
|
2000
|
-
|
|
2021
|
+
const payload = {
|
|
2022
|
+
category: row.category,
|
|
2023
|
+
metadata,
|
|
2024
|
+
exitCode: row.exit_code,
|
|
2025
|
+
durationMs: row.duration_ms
|
|
2026
|
+
};
|
|
2027
|
+
if (row.category === "other" && typeof metadata.hint === "string") {
|
|
2028
|
+
payload.hint = metadata.hint;
|
|
2029
|
+
const { hint: _h, tool: _t, ...rest } = metadata;
|
|
2030
|
+
payload.metadata = rest;
|
|
2031
|
+
}
|
|
2032
|
+
return payload;
|
|
2001
2033
|
}
|
|
2002
2034
|
function registerExport(program2) {
|
|
2003
2035
|
program2.command("export").description("Export work summary as a markdown file").option("--date <YYYY-MM-DD>", "date to export (default: today)").option("--output <path>", "output file path (default: ~/.workscribe/exports/)").action(async (opts) => {
|
|
@@ -2023,14 +2055,14 @@ function registerExport(program2) {
|
|
|
2023
2055
|
log.error(e.message);
|
|
2024
2056
|
process.exit(1);
|
|
2025
2057
|
}
|
|
2026
|
-
const sessionPayloads = sessions.map((
|
|
2058
|
+
const sessionPayloads = sessions.map((session) => ({
|
|
2027
2059
|
date,
|
|
2028
|
-
project:
|
|
2029
|
-
branch:
|
|
2030
|
-
startTime: formatDate(
|
|
2031
|
-
endTime: formatDate(
|
|
2032
|
-
durationMinutes:
|
|
2033
|
-
events:
|
|
2060
|
+
project: session.repoName,
|
|
2061
|
+
branch: session.events[0]?.branch ?? null,
|
|
2062
|
+
startTime: formatDate(session.startedAt),
|
|
2063
|
+
endTime: formatDate(session.endedAt),
|
|
2064
|
+
durationMinutes: session.durationMinutes,
|
|
2065
|
+
events: session.events.map(eventRowToPayload2)
|
|
2034
2066
|
}));
|
|
2035
2067
|
const payload = { date, sessions: sessionPayloads };
|
|
2036
2068
|
log.info(`Generating summary via ${config.ai.provider}\u2026`);
|
|
@@ -2220,7 +2252,7 @@ function detectShellRcFiles() {
|
|
|
2220
2252
|
{ name: "bash", rcFile: import_path10.default.join(import_os6.default.homedir(), ".bashrc") },
|
|
2221
2253
|
{ name: "bash", rcFile: import_path10.default.join(import_os6.default.homedir(), ".bash_profile") }
|
|
2222
2254
|
];
|
|
2223
|
-
return candidates.filter((
|
|
2255
|
+
return candidates.filter((candidate) => import_fs15.default.existsSync(candidate.rcFile) && isHookInstalled(candidate.rcFile));
|
|
2224
2256
|
}
|
|
2225
2257
|
function registerUninstall(program2) {
|
|
2226
2258
|
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) => {
|
|
@@ -2262,7 +2294,7 @@ function registerUninstall(program2) {
|
|
|
2262
2294
|
|
|
2263
2295
|
// src/index.ts
|
|
2264
2296
|
var program = new import_commander.Command();
|
|
2265
|
-
program.name("workscribe").description("Automatic developer work journal").version("1.
|
|
2297
|
+
program.name("workscribe").description("Automatic developer work journal").version("1.9.0");
|
|
2266
2298
|
registerCapture(program);
|
|
2267
2299
|
registerHook(program);
|
|
2268
2300
|
registerInit(program);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/capture/index.ts","../src/db/index.ts","../src/utils/paths.ts","../src/db/migrations/001_initial_schema.ts","../src/db/migrations/index.ts","../src/capture/redact.ts","../src/capture/git.ts","../src/capture/git-snapshot.ts","../src/capture/aider.ts","../src/config/registry.ts","../src/config/ai-tools.json","../src/utils/logger.ts","../src/normalize/patterns.ts","../src/config/index.ts","../src/capture/filter.ts","../src/cli/capture.ts","../src/cli/hook.ts","../src/cli/init.ts","../src/capture/shell-hook.ts","../src/capture/hooks/claude-code.ts","../src/capture/hooks/utils.ts","../src/capture/hooks/index.ts","../src/cli/status.ts","../src/utils/format.ts","../src/cli/events.ts","../src/cli/sessions.ts","../src/sessions/grouper.ts","../src/sessions/detector.ts","../src/cli/summary.ts","../src/ai/prompt.ts","../src/ai/fetch.ts","../src/ai/providers/anthropic.ts","../src/ai/providers/openai.ts","../src/ai/providers/ollama.ts","../src/ai/router.ts","../src/integrations/webhook.ts","../src/integrations/slack.ts","../src/cli/export.ts","../src/cli/config.ts","../src/cli/pause.ts","../src/cli/undo.ts","../src/cli/clear.ts","../src/cli/uninstall.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { registerCapture } from './cli/capture'\nimport { registerHook } from './cli/hook'\n\ndeclare const __WORKSCRIBE_VERSION__: string\nimport { registerInit } from './cli/init'\nimport { registerStatus } from './cli/status'\nimport { registerEvents } from './cli/events'\nimport { registerSessions } from './cli/sessions'\nimport { registerSummary } from './cli/summary'\nimport { registerExport } from './cli/export'\nimport { registerConfig } from './cli/config'\nimport { registerPause } from './cli/pause'\nimport { registerUndo } from './cli/undo'\nimport { registerClear } from './cli/clear'\nimport { registerUninstall } from './cli/uninstall'\n\nconst program = new Command()\n\nprogram.name('workscribe').description('Automatic developer work journal').version(__WORKSCRIBE_VERSION__)\n\nregisterCapture(program)\nregisterHook(program)\nregisterInit(program)\nregisterStatus(program)\nregisterEvents(program)\nregisterSessions(program)\nregisterSummary(program)\nregisterExport(program)\nregisterConfig(program)\nregisterPause(program)\nregisterUndo(program)\nregisterClear(program)\nregisterUninstall(program)\n\nprogram.parse()\n","import fs from 'fs'\nimport { insertEvent, getLastEvent } from '../db'\nimport { redact } from './redact'\nimport { getGitContext } from './git'\nimport { getCommitsSince } from './git-snapshot'\nimport { readLastAiderPrompt } from './aider'\nimport { normalizeCommand } from '../normalize/patterns'\nimport { readConfig } from '../config'\nimport { shouldFilter, isDuplicate } from './filter'\nimport { PAUSE_FLAG_PATH } from '../utils/paths'\nimport { loadAIToolRegistry } from '../config/registry'\n\nexport function captureCommand(opts: {\n command: string\n cwd: string\n exitCode: number | null\n durationMs: number | null\n gitBefore?: string\n source?: string\n}): void {\n // Check pause flag before any I/O\n if (fs.existsSync(PAUSE_FLAG_PATH)) return\n\n const config = readConfig()\n const { command, cwd, exitCode, durationMs } = opts\n\n // 1. Filter noise commands\n if (shouldFilter(command, config.capture.ignore)) return\n\n // 2. Deduplicate: same command + same cwd within 5 seconds\n const last = getLastEvent()\n if (isDuplicate(command, cwd, last ?? undefined)) return\n\n // 3. Redact sensitive patterns\n const safeCommand = redact(command, config.redact.extra)\n\n // 4. Extract git context (with optional per-project name override)\n const nameOverride = config.projects?.[cwd] ?? null\n const { repoName, branch } = getGitContext(cwd, nameOverride)\n\n // 5. Normalize to typed event\n const { category, metadata } = normalizeCommand(safeCommand)\n\n if (category === 'ai_session' && config.capture.aiTools === false) return\n\n if (opts.source) metadata.source = opts.source\n\n // 6. For ai_session events, enrich metadata\n if (category === 'ai_session') {\n // 6a. Commits made during the session\n if (opts.gitBefore) {\n const commits = getCommitsSince(opts.gitBefore, cwd)\n if (commits.length > 0) metadata.commits = commits\n }\n\n // 6b. Last user prompt from history file (e.g. Aider)\n if (config.capture.includeAiderPrompt !== false) {\n const toolEntry = loadAIToolRegistry().find((entry) => entry.tool === metadata.tool)\n if (toolEntry?.contextSource === 'history-file') {\n const prompt = readLastAiderPrompt(cwd)\n if (prompt) metadata.prompt = prompt\n }\n }\n }\n\n // 7. Persist\n insertEvent({\n captured_at: new Date().toISOString(),\n command: safeCommand,\n cwd,\n exit_code: exitCode,\n duration_ms: durationMs,\n repo_name: repoName,\n branch,\n category,\n metadata: Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null,\n })\n}\n","import { DatabaseSync } from 'node:sqlite'\nimport fs from 'fs'\nimport { WORKSCRIBE_DIR, DB_PATH } from '../utils/paths'\nimport type { EventRow, SessionRow } from './types'\nimport { MIGRATIONS } from './migrations'\nexport type { EventRow, SessionRow } from './types'\n\nlet _db: DatabaseSync | null = null\n\nexport function getDb(): DatabaseSync {\n if (_db) return _db\n\n // Ensure ~/.workscribe/ exists\n if (!fs.existsSync(WORKSCRIBE_DIR)) {\n fs.mkdirSync(WORKSCRIBE_DIR, { recursive: true })\n }\n\n // Don't assign to _db until after migrations succeed — if applyMigrations\n // throws, _db stays null so the next call retries cleanly instead of\n // returning a partially-initialised singleton.\n const db = new DatabaseSync(DB_PATH)\n try {\n fs.chmodSync(DB_PATH, 0o600)\n } catch {\n /* ignore if already correct */\n }\n db.exec('PRAGMA journal_mode = WAL')\n db.exec('PRAGMA foreign_keys = ON')\n applyMigrations(db)\n _db = db\n return _db\n}\n\nfunction applyMigrations(db: DatabaseSync): void {\n // Create the migration tracking table if this is the first run\n db.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n\n // Bootstrap: if the events table already exists but schema_migrations is\n // empty, this is an existing install that predates the migration system.\n // Seed version 1 as applied so we don't re-run the initial schema.\n const hasEvents = db.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='events'\").get()\n const hasVersion1 = db.prepare('SELECT version FROM schema_migrations WHERE version = 1').get()\n\n if (hasEvents && !hasVersion1) {\n db.prepare(\"INSERT INTO schema_migrations (version, applied_at) VALUES ($version, datetime('now'))\").run({\n version: 1,\n })\n }\n\n // Collect already-applied versions\n const applied = new Set(\n (db.prepare('SELECT version FROM schema_migrations').all() as { version: number }[]).map((r) => r.version)\n )\n\n // Apply each pending migration in order, wrapped in a transaction so a\n // partial failure leaves the DB cleanly at the previous version.\n for (const migration of MIGRATIONS) {\n if (applied.has(migration.version)) continue\n\n db.exec('BEGIN')\n try {\n db.exec(migration.sql)\n db.prepare(\"INSERT INTO schema_migrations (version, applied_at) VALUES ($version, datetime('now'))\").run({\n version: migration.version,\n })\n db.exec('COMMIT')\n } catch (err) {\n try {\n db.exec('ROLLBACK')\n } catch {\n /* already rolled back or connection lost */\n }\n throw new Error(`Migration ${migration.version} (${migration.description}) failed: ${(err as Error).message}`)\n }\n }\n}\n\n// ─── Typed query helpers ──────────────────────────────────────────────────────\n\nexport function insertEvent(params: {\n captured_at: string\n command: string\n cwd: string\n exit_code: number | null\n duration_ms: number | null\n repo_name: string | null\n branch: string | null\n category: string\n metadata: string | null\n}): void {\n const db = getDb()\n const stmt = db.prepare(`\n INSERT INTO events (captured_at, command, cwd, exit_code, duration_ms, repo_name, branch, category, metadata)\n VALUES ($captured_at, $command, $cwd, $exit_code, $duration_ms, $repo_name, $branch, $category, $metadata)\n `)\n stmt.run(params)\n}\n\nexport function getLastEvent(): EventRow | undefined {\n const db = getDb()\n const stmt = db.prepare('SELECT * FROM events ORDER BY id DESC LIMIT 1')\n return stmt.get() as EventRow | undefined\n}\n\nexport function getEventsForDate(date: string): EventRow[] {\n const db = getDb()\n const stmt = db.prepare(`\n SELECT * FROM events\n WHERE date(captured_at, 'localtime') = $date\n ORDER BY captured_at ASC\n `)\n return stmt.all({ date }) as unknown as EventRow[]\n}\n\nexport function getRecentEvents(limit = 20): EventRow[] {\n const db = getDb()\n const stmt = db.prepare('SELECT * FROM events ORDER BY captured_at DESC LIMIT $limit')\n return stmt.all({ limit }) as unknown as EventRow[]\n}\n\nexport function getEventCount(): number {\n const db = getDb()\n const stmt = db.prepare('SELECT COUNT(*) as count FROM events')\n const row = stmt.get() as { count: number }\n return row.count\n}\n\nexport function insertSession(params: {\n date: string\n started_at: string\n ended_at: string\n repo_name: string | null\n event_count: number\n summary: string | null\n}): number {\n const db = getDb()\n const stmt = db.prepare(`\n INSERT INTO sessions (date, started_at, ended_at, repo_name, event_count, summary)\n VALUES ($date, $started_at, $ended_at, $repo_name, $event_count, $summary)\n `)\n const result = stmt.run(params)\n return Number(result.lastInsertRowid)\n}\n\nexport function insertSessionEvent(sessionId: number, eventId: number): void {\n const db = getDb()\n const stmt = db.prepare(`\n INSERT OR IGNORE INTO session_events (session_id, event_id) VALUES ($session_id, $event_id)\n `)\n stmt.run({ session_id: sessionId, event_id: eventId })\n}\n\nexport function getEventsBySessionId(sessionId: number): EventRow[] {\n const db = getDb()\n const stmt = db.prepare(`\n SELECT e.* FROM events e\n INNER JOIN session_events se ON se.event_id = e.id\n WHERE se.session_id = $session_id\n ORDER BY e.captured_at ASC\n `)\n return stmt.all({ session_id: sessionId }) as unknown as EventRow[]\n}\n\nexport function getSessionsForDate(date: string): SessionRow[] {\n const db = getDb()\n const stmt = db.prepare('SELECT * FROM sessions WHERE date = $date ORDER BY started_at ASC')\n return stmt.all({ date }) as unknown as SessionRow[]\n}\n\nexport function updateSessionSummary(sessionId: number, summary: string): void {\n const db = getDb()\n const stmt = db.prepare('UPDATE sessions SET summary = $summary WHERE id = $id')\n stmt.run({ summary, id: sessionId })\n}\n\nexport function getLastEventIds(n: number): number[] {\n const db = getDb()\n const rows = db.prepare('SELECT id FROM events ORDER BY id DESC LIMIT $n').all({ n }) as { id: number }[]\n return rows.map((r) => r.id)\n}\n\nexport function getEventsByIds(ids: number[]): EventRow[] {\n if (ids.length === 0) return []\n const db = getDb()\n const placeholders = ids.map(() => '?').join(', ')\n return db\n .prepare(`SELECT * FROM events WHERE id IN (${placeholders}) ORDER BY id DESC`)\n .all(...ids) as unknown as EventRow[]\n}\n\nexport function deleteEventsByIds(ids: number[]): void {\n if (ids.length === 0) return\n const db = getDb()\n const placeholders = ids.map(() => '?').join(', ')\n\n const affectedDates = db\n .prepare(`SELECT DISTINCT date(captured_at, 'localtime') as date FROM events WHERE id IN (${placeholders})`)\n .all(...ids) as { date: string }[]\n\n db.prepare(`DELETE FROM events WHERE id IN (${placeholders})`).run(...ids)\n\n for (const { date } of affectedDates) {\n clearSessionsForDate(date)\n }\n}\n\nexport function deleteEventsForDate(date: string): number {\n const db = getDb()\n // Clear sessions (and session_events) before deleting events — FK constraint order\n clearSessionsForDate(date)\n const result = db.prepare(`DELETE FROM events WHERE date(captured_at, 'localtime') = $date`).run({ date }) as {\n changes: number\n }\n return result.changes\n}\n\nexport function clearSessionsForDate(date: string): void {\n const db = getDb()\n // Remove session_events first due to FK constraint\n db.prepare(\n `\n DELETE FROM session_events WHERE session_id IN (\n SELECT id FROM sessions WHERE date = $date\n )\n `\n ).run({ date })\n db.prepare('DELETE FROM sessions WHERE date = $date').run({ date })\n}\n","import path from 'path'\nimport os from 'os'\n\nexport const WORKSCRIBE_DIR = path.join(os.homedir(), '.workscribe')\nexport const DB_PATH = path.join(WORKSCRIBE_DIR, 'workscribe.db')\nexport const CONFIG_PATH = path.join(WORKSCRIBE_DIR, 'config.json')\nexport const DEBUG_LOG_PATH = path.join(WORKSCRIBE_DIR, 'debug.log')\nexport const EXPORTS_DIR = path.join(WORKSCRIBE_DIR, 'exports')\nexport const PAUSE_FLAG_PATH = path.join(WORKSCRIBE_DIR, 'paused')\nexport const WEEKLY_CACHE_DIR = path.join(WORKSCRIBE_DIR, 'weekly-cache')\n","export default {\n version: 1,\n description: 'initial schema',\n sql: `\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n captured_at TEXT NOT NULL,\n command TEXT NOT NULL,\n cwd TEXT NOT NULL,\n exit_code INTEGER,\n duration_ms INTEGER,\n repo_name TEXT,\n branch TEXT,\n category TEXT NOT NULL DEFAULT 'other',\n metadata TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_events_captured_at ON events(captured_at);\n CREATE INDEX IF NOT EXISTS idx_events_repo_name ON events(repo_name);\n\n CREATE TABLE IF NOT EXISTS sessions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n date TEXT NOT NULL,\n started_at TEXT NOT NULL,\n ended_at TEXT NOT NULL,\n repo_name TEXT,\n event_count INTEGER NOT NULL DEFAULT 0,\n summary TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_sessions_date ON sessions(date);\n\n CREATE TABLE IF NOT EXISTS session_events (\n session_id INTEGER NOT NULL REFERENCES sessions(id),\n event_id INTEGER NOT NULL REFERENCES events(id),\n PRIMARY KEY (session_id, event_id)\n );\n `,\n}\n","import initialSchema from './001_initial_schema'\n\nexport interface Migration {\n version: number\n description: string\n sql: string\n}\n\n// Ordered list — append only. Never modify or remove an existing entry.\nexport const MIGRATIONS: Migration[] = [initialSchema]\n","// Patterns that match known sensitive values\nconst BUILTIN_PATTERNS: RegExp[] = [\n // AWS access keys\n /AKIA[0-9A-Z]{16}/g,\n // AWS secret access keys (40 char base64-ish after common env vars)\n /(?<=AWS_SECRET_ACCESS_KEY[=\\s]+)\\S+/gi,\n // GitHub tokens\n /ghp_[a-zA-Z0-9]{36}/g,\n /github_pat_[a-zA-Z0-9_]{82}/g,\n // GitLab tokens\n /glpat-[a-zA-Z0-9\\-]{20}/g,\n // Generic JWTs (three base64url segments)\n /eyJ[a-zA-Z0-9_-]+\\.eyJ[a-zA-Z0-9_-]+\\.[a-zA-Z0-9_-]+/g,\n // Slack tokens and incoming webhook URLs\n /xox[baprs]-[a-zA-Z0-9\\-]+/g,\n /https:\\/\\/hooks\\.slack\\.com\\/services\\/[A-Z0-9]+\\/[A-Z0-9]+\\/[a-zA-Z0-9]+/g,\n // Stripe keys\n /sk_(live|test)_[a-zA-Z0-9]{24,}/g,\n // Values after long-form secret flags (single-char flags like -t/-p/-k are too ambiguous)\n /(?<=--(password|passwd|secret|token|key|api[-_]?key|auth[-_]?token)\\s+)\\S+/gi,\n // export VAR=VALUE where VAR looks sensitive\n /(?<=export\\s+(?:[A-Z_]*(?:TOKEN|SECRET|KEY|PASSWORD|PASS|AUTH|CREDENTIAL)[A-Z_]*)=)\\S+/gi,\n]\n\nexport function redact(command: string, extraPatterns: string[] = []): string {\n let result = command\n\n const allPatterns = [...BUILTIN_PATTERNS]\n\n for (const pattern of extraPatterns) {\n try {\n allPatterns.push(new RegExp(pattern, 'g'))\n } catch {\n // Invalid regex — skip silently\n }\n }\n\n for (const pattern of allPatterns) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0\n result = result.replace(pattern, '[REDACTED]')\n }\n\n return result\n}\n","import { execSync } from 'child_process'\nimport path from 'path'\nimport fs from 'fs'\n\nexport interface GitContext {\n repoName: string | null\n branch: string | null\n}\n\nfunction nameFromRemote(root: string): string | null {\n try {\n const url = execSync('git remote get-url origin', {\n cwd: root,\n timeout: 2000,\n stdio: 'pipe',\n })\n .toString()\n .trim()\n const match = url.match(/\\/([^/]+?)(?:\\.git)?$/)\n return match ? match[1] : null\n } catch {\n return null\n }\n}\n\nfunction nameFromPackageJson(root: string): string | null {\n try {\n const raw = fs.readFileSync(path.join(root, 'package.json'), 'utf-8')\n const pkg = JSON.parse(raw) as { name?: string }\n if (!pkg.name) return null\n return pkg.name.replace(/^@[^/]+\\//, '')\n } catch {\n return null\n }\n}\n\nexport function getGitContext(cwd: string, nameOverride?: string | null): GitContext {\n try {\n const root = execSync('git rev-parse --show-toplevel', {\n cwd,\n timeout: 2000,\n stdio: 'pipe',\n })\n .toString()\n .trim()\n\n const repoName = nameOverride ?? nameFromRemote(root) ?? nameFromPackageJson(root) ?? path.basename(root)\n\n let branch: string | null = null\n try {\n branch =\n execSync('git branch --show-current', {\n cwd,\n timeout: 2000,\n stdio: 'pipe',\n })\n .toString()\n .trim() || null\n } catch {\n // Detached HEAD or not a git repo\n }\n\n return { repoName, branch }\n } catch {\n return { repoName: null, branch: null }\n }\n}\n","import { execSync } from 'child_process'\n\n/**\n * Returns commit subject lines for all commits made between `sha` and HEAD.\n * Returns an empty array if sha is empty, HEAD hasn't moved, or git fails.\n */\nexport function getCommitsSince(sha: string, cwd: string): string[] {\n if (!sha) return []\n try {\n const out = execSync(`git log ${sha}..HEAD --format=%s`, { cwd, timeout: 3000 }).toString().trim()\n return out ? out.split('\\n').filter(Boolean) : []\n } catch {\n return []\n }\n}\n","import fs from 'fs'\nimport path from 'path'\n\nconst HISTORY_FILE = '.aider.chat.history.md'\nconst PROMPT_MAX_LENGTH = 200\n\nexport function readLastAiderPrompt(cwd: string): string | null {\n try {\n const histPath = path.join(cwd, HISTORY_FILE)\n const content = fs.readFileSync(histPath, 'utf-8')\n const matches = [...content.matchAll(/^> (.+)$/gm)]\n if (!matches.length) return null\n return matches[matches.length - 1][1].trim().slice(0, PROMPT_MAX_LENGTH)\n } catch {\n return null\n }\n}\n","import fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport BUILTIN_TOOLS from './ai-tools.json'\nimport { debugLog } from '../utils/logger'\n\nexport interface AIToolEntry {\n tool: string\n displayName: string\n pattern: string\n hook: string | null\n contextSource: string | null\n}\n\nconst USER_REGISTRY_PATH = path.join(os.homedir(), '.workscribe', 'ai-tools.json')\n\nexport function loadAIToolRegistry(): AIToolEntry[] {\n let userEntries: AIToolEntry[] = []\n\n try {\n if (fs.existsSync(USER_REGISTRY_PATH)) {\n const raw = fs.readFileSync(USER_REGISTRY_PATH, 'utf-8')\n const parsed = JSON.parse(raw)\n if (Array.isArray(parsed)) {\n userEntries = parsed\n .filter((entry) => typeof entry.tool === 'string' && typeof entry.pattern === 'string')\n .map((entry) => ({\n tool: entry.tool as string,\n displayName: (entry.displayName as string | undefined) ?? (entry.tool as string),\n pattern: entry.pattern as string,\n hook: (entry.hook as string | null | undefined) ?? null,\n contextSource: (entry.contextSource as string | null | undefined) ?? null,\n }))\n }\n }\n } catch {\n debugLog('registry', 'Failed to load user AI tool registry — using built-ins only')\n }\n\n if (userEntries.length === 0) return BUILTIN_TOOLS as AIToolEntry[]\n\n const userToolSlugs = new Set(userEntries.map((entry) => entry.tool))\n const filteredBuiltins = (BUILTIN_TOOLS as AIToolEntry[]).filter((entry) => !userToolSlugs.has(entry.tool))\n return [...filteredBuiltins, ...userEntries]\n}\n","[\n {\n \"tool\": \"claude\",\n \"displayName\": \"Claude Code\",\n \"pattern\": \"^claude\\\\b\",\n \"hook\": \"claude-code\",\n \"contextSource\": \"hook\"\n },\n {\n \"tool\": \"aider\",\n \"displayName\": \"Aider\",\n \"pattern\": \"^aider\\\\b\",\n \"hook\": null,\n \"contextSource\": \"history-file\"\n },\n {\n \"tool\": \"gemini\",\n \"displayName\": \"Gemini\",\n \"pattern\": \"^gemini\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"gh copilot\",\n \"displayName\": \"GitHub Copilot\",\n \"pattern\": \"^gh\\\\s+copilot\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"cody\",\n \"displayName\": \"Cody\",\n \"pattern\": \"^cody\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"amazon-q\",\n \"displayName\": \"Amazon Q\",\n \"pattern\": \"^q\\\\s+(chat|dev)\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"continue\",\n \"displayName\": \"Continue\",\n \"pattern\": \"^continue\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"cursor\",\n \"displayName\": \"Cursor\",\n \"pattern\": \"^cursor\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n }\n]\n","import chalk from 'chalk'\nimport fs from 'fs'\nimport { DEBUG_LOG_PATH } from './paths'\n\nconst isDebug = process.env.WORKSCRIBE_DEBUG === '1'\n\nexport const log = {\n info: (msg: string) => console.log(chalk.cyan('→'), msg),\n success: (msg: string) => console.log(chalk.green('✓'), msg),\n warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.error(chalk.red('✗'), msg),\n plain: (msg: string) => console.log(msg),\n}\n\nexport function debugLog(context: string, error: unknown): void {\n if (!isDebug) return\n const entry = `[${new Date().toISOString()}] [${context}] ${error instanceof Error ? error.stack : String(error)}\\n`\n try {\n fs.appendFileSync(DEBUG_LOG_PATH, entry, { mode: 0o600 })\n } catch {\n // If we can't write to the debug log, silently ignore\n }\n}\n","import { loadAIToolRegistry } from '../config/registry'\nimport { debugLog } from '../utils/logger'\n\nexport interface NormalizedEvent {\n category: string\n metadata: Record<string, unknown>\n}\n\ninterface Rule {\n // Returns metadata if command matches, null otherwise\n match(cmd: string): NormalizedEvent | null\n}\n\nfunction makeRule(\n pattern: RegExp,\n category: string,\n extract: (match: RegExpMatchArray, cmd: string) => Record<string, unknown> = () => ({})\n): Rule {\n return {\n match(cmd) {\n const m = cmd.match(pattern)\n if (!m) return null\n return { category, metadata: extract(m, cmd) }\n },\n }\n}\n\n// Extract package names from install commands like: npm install foo bar\nfunction extractPackages(cmd: string, afterKeyword: string): string[] {\n const idx = cmd.indexOf(afterKeyword)\n if (idx === -1) return []\n return cmd\n .slice(idx + afterKeyword.length)\n .trim()\n .split(/\\s+/)\n .filter((p) => p && !p.startsWith('-'))\n}\n\nexport const RULES: Rule[] = [\n // ─── Git operations ───────────────────────────────────────────────────────\n makeRule(/^git\\s+commit\\b/, 'code_commit', (_m, cmd) => {\n const msgMatch = cmd.match(/-m\\s+[\"']?([^\"']+)[\"']?/)\n return { message: msgMatch ? msgMatch[1].trim() : null }\n }),\n\n makeRule(/^git\\s+push\\b/, 'code_push', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { remote: parts[2] ?? 'origin', branch: parts[3] ?? null }\n }),\n\n makeRule(/^git\\s+(pull|fetch)\\b/, 'code_pull', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[1], remote: parts[2] ?? 'origin' }\n }),\n\n makeRule(/^git\\s+(checkout|switch)\\b/, 'branch_switch', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n const branch = parts.find((p) => !p.startsWith('-') && p !== 'git' && p !== parts[1])\n return { branch: branch ?? null }\n }),\n\n makeRule(/^git\\s+(merge|rebase)\\b/, 'code_merge', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[1], target: parts[2] ?? null }\n }),\n\n makeRule(/^git\\s+stash\\b/, 'code_stash', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[2] ?? 'push' }\n }),\n\n makeRule(/^git\\s+/, 'git_other', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[1] ?? null }\n }),\n\n // ─── Package managers — install ───────────────────────────────────────────\n makeRule(/^npm\\s+(install|i|add)\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'npm',\n packages: extractPackages(cmd, cmd.includes('install') ? 'install' : cmd.includes(' i ') ? ' i ' : 'add'),\n })),\n\n makeRule(/^(yarn|pnpm)\\s+(install|add)\\b/, 'dependency_install', (m, cmd) => ({\n tool: m[1],\n packages: extractPackages(cmd, 'add'),\n })),\n\n makeRule(/^bun\\s+(install|add)\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'bun',\n packages: extractPackages(cmd, 'add'),\n })),\n\n makeRule(/^pip\\s+(install)\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'pip',\n packages: extractPackages(cmd, 'install'),\n })),\n\n makeRule(/^cargo\\s+add\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'cargo',\n packages: extractPackages(cmd, 'add'),\n })),\n\n makeRule(/^(brew)\\s+install\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'brew',\n packages: extractPackages(cmd, 'install'),\n })),\n\n makeRule(/^go\\s+get\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'go',\n packages: extractPackages(cmd, 'get'),\n })),\n\n // ─── Package managers — remove ────────────────────────────────────────────\n makeRule(/^npm\\s+(uninstall|remove|rm)\\b/, 'dependency_remove', (_m, cmd) => ({\n tool: 'npm',\n packages: extractPackages(cmd, cmd.split(/\\s+/)[1]),\n })),\n\n makeRule(/^(yarn|pnpm)\\s+remove\\b/, 'dependency_remove', (m, cmd) => ({\n tool: m[1],\n packages: extractPackages(cmd, 'remove'),\n })),\n\n makeRule(/^bun\\s+remove\\b/, 'dependency_remove', (_m, cmd) => ({\n tool: 'bun',\n packages: extractPackages(cmd, 'remove'),\n })),\n\n makeRule(/^pip\\s+uninstall\\b/, 'dependency_remove', (_m, cmd) => ({\n tool: 'pip',\n packages: extractPackages(cmd, 'uninstall'),\n })),\n\n // ─── Tests ────────────────────────────────────────────────────────────────\n makeRule(/^npm\\s+(test|run\\s+test)\\b/, 'test_run', () => ({ tool: 'npm' })),\n makeRule(/^yarn\\s+test\\b/, 'test_run', () => ({ tool: 'yarn' })),\n makeRule(/^pnpm\\s+test\\b/, 'test_run', () => ({ tool: 'pnpm' })),\n makeRule(/^bun\\s+test\\b/, 'test_run', () => ({ tool: 'bun' })),\n makeRule(/^(jest|vitest)\\b/, 'test_run', (m) => ({ tool: m[1] })),\n makeRule(/^pytest\\b/, 'test_run', () => ({ tool: 'pytest' })),\n makeRule(/^go\\s+test\\b/, 'test_run', () => ({ tool: 'go' })),\n makeRule(/^cargo\\s+test\\b/, 'test_run', () => ({ tool: 'cargo' })),\n makeRule(/^rspec\\b/, 'test_run', () => ({ tool: 'rspec' })),\n makeRule(/^(php\\s+)?phpunit\\b/, 'test_run', () => ({ tool: 'phpunit' })),\n\n // ─── Build ────────────────────────────────────────────────────────────────\n makeRule(/^npm\\s+run\\s+build\\b/, 'build', () => ({ tool: 'npm' })),\n makeRule(/^(yarn|pnpm)\\s+build\\b/, 'build', (m) => ({ tool: m[1] })),\n makeRule(/^bun\\s+run\\s+build\\b/, 'build', () => ({ tool: 'bun' })),\n makeRule(/^(make|gmake)\\b/, 'build', (m) => ({ tool: m[1] })),\n makeRule(/^cargo\\s+build\\b/, 'build', () => ({ tool: 'cargo' })),\n makeRule(/^go\\s+build\\b/, 'build', () => ({ tool: 'go' })),\n makeRule(/^docker\\s+build\\b/, 'build', () => ({ tool: 'docker' })),\n makeRule(/^(mvn|gradle)\\b/, 'build', (m) => ({ tool: m[1] })),\n\n // ─── Dev server ───────────────────────────────────────────────────────────\n makeRule(/^npm\\s+run\\s+(dev|start|serve)\\b/, 'server_run', (_m, cmd) => ({\n tool: 'npm',\n script: cmd.split(/\\s+/)[2],\n })),\n makeRule(/^(yarn|pnpm)\\s+(dev|start)\\b/, 'server_run', (m) => ({ tool: m[1], script: m[2] })),\n makeRule(/^bun\\s+run\\s+(dev|start|serve)\\b/, 'server_run', (_m, cmd) => ({\n tool: 'bun',\n script: cmd.split(/\\s+/)[2],\n })),\n makeRule(/^python\\s+.*manage\\.py\\s+runserver\\b/, 'server_run', () => ({ tool: 'django' })),\n\n // ─── Infrastructure ───────────────────────────────────────────────────────\n makeRule(/^ssh\\b/, 'infrastructure', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: 'ssh', target: parts[parts.length - 1] }\n }),\n\n makeRule(/^kubectl\\b/, 'infrastructure', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: 'kubectl', subcommand: parts[1] ?? null }\n }),\n\n makeRule(/^(helm|terraform|pulumi)\\b/, 'infrastructure', (m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: m[1], subcommand: parts[1] ?? null }\n }),\n\n makeRule(/^docker\\s+(run|compose|ps|stop|start|rm|exec)\\b/, 'infrastructure', (m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: 'docker', subcommand: parts[1] }\n }),\n\n makeRule(/^(aws|gcloud|az)\\b/, 'infrastructure', (m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: m[1], subcommand: parts[1] ?? null }\n }),\n\n // ─── npx ─────────────────────────────────────────────────────────────────\n makeRule(/^npx\\s+(jest|vitest|mocha|ava|tap)\\b/, 'test_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n makeRule(/^npx\\s+tsc\\b/, 'build', () => ({ tool: 'tsc' })),\n makeRule(/^npx\\s+(eslint|tslint|biome)\\b/, 'lint_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n makeRule(/^npx\\s+(prettier|dprint)\\b/, 'lint_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n makeRule(/^npx\\s+\\S+/, 'script_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n\n // ─── Scripts ──────────────────────────────────────────────────────────────\n makeRule(/^(bash|sh|zsh|fish)\\s+\\S+/, 'script_run', (m) => ({ shell: m[1] })),\n makeRule(/^node\\s+\\S+\\.(?:js|mjs|cjs)\\b/, 'script_run', () => ({ runtime: 'node' })),\n makeRule(/^python3?\\s+\\S+\\.py\\b/, 'script_run', () => ({ runtime: 'python' })),\n\n // ─── Environment ──────────────────────────────────────────────────────────\n makeRule(/^export\\s+\\w+=/, 'environment', (_m, cmd) => {\n const varName = cmd.match(/^export\\s+(\\w+)=/)?.[1] ?? null\n return { variable: varName }\n }),\n makeRule(/^source\\s+/, 'environment', () => ({})),\n\n // ─── generic run scripts ──────────────────────────────────────────────────\n makeRule(/^npm\\s+run\\s+\\S+/, 'script_run', (_m, cmd) => ({\n tool: 'npm',\n script: cmd.split(/\\s+/)[2],\n })),\n\n makeRule(/^bun\\s+run\\s+\\S+/, 'script_run', (_m, cmd) => ({\n tool: 'bun',\n script: cmd.split(/\\s+/)[2],\n })),\n\n // ─── Code search ─────────────────────────────────────────────────────────\n makeRule(/^(grep|egrep|fgrep)\\b/, 'code_search', (m) => ({ tool: m[1] })),\n makeRule(/^(rg|ag|ack|ripgrep)\\b/, 'code_search', (m) => ({ tool: m[1] })),\n makeRule(/^find\\s/, 'code_search', () => ({ tool: 'find' })),\n\n // ─── Code read ────────────────────────────────────────────────────────────\n makeRule(/^(cat|bat|less|more)\\s+\\S+/, 'code_read', (m) => ({ tool: m[1] })),\n makeRule(/^(head|tail)\\b/, 'code_read', (m) => ({ tool: m[1] })),\n\n // ─── File operations ──────────────────────────────────────────────────────\n makeRule(/^(cp|rsync)\\b/, 'file_ops', (m) => ({ tool: m[1] })),\n makeRule(/^(mv)\\b/, 'file_ops', () => ({ tool: 'mv' })),\n makeRule(/^(rm|rmdir)\\b/, 'file_ops', (m) => ({ tool: m[1] })),\n makeRule(/^(mkdir|touch|ln)\\b/, 'file_ops', (m) => ({ tool: m[1] })),\n makeRule(/^(chmod|chown|chgrp)\\b/, 'file_ops', (m) => ({ tool: m[1] })),\n\n // ─── AI terminal tools (registry-driven) ─────────────────────────────────\n ...loadAIToolRegistry().flatMap((entry) => {\n try {\n return [makeRule(new RegExp(entry.pattern), 'ai_session', () => ({ tool: entry.tool }))]\n } catch {\n debugLog('registry', `Skipping tool \"${entry.tool}\" — invalid pattern: ${entry.pattern}`)\n return []\n }\n }),\n]\n\nexport function normalizeCommand(command: string): NormalizedEvent {\n let trimmed = command.trim().replace(/\\s+/g, ' ')\n\n // Strip `git -C <path>` prefix so rules match regardless of working directory flag\n trimmed = trimmed.replace(/^(git)\\s+-C\\s+\\S+\\s+/, '$1 ')\n\n for (const rule of RULES) {\n const result = rule.match(trimmed)\n if (result) return result\n }\n\n return { category: 'other', metadata: {} }\n}\n","import fs from 'fs'\nimport { CONFIG_PATH } from '../utils/paths'\n\nexport interface WorkscribeConfig {\n ai: {\n provider: string // 'anthropic' | 'openai' | 'ollama' | 'openai-compatible'\n apiKey: string\n model: string\n baseUrl: string\n }\n session: {\n idleTimeout: number // minutes\n }\n capture: {\n ignore: string[]\n aiTools: boolean\n includeAiderPrompt: boolean\n }\n redact: {\n extra: string[]\n }\n summary: {\n format: 'markdown' | 'json'\n }\n projects?: Record<string, string> // absolute path → display name override\n integrations?: {\n slackWebhook?: string\n webhook?: string\n }\n}\n\nconst DEFAULTS: WorkscribeConfig = {\n ai: {\n provider: '',\n apiKey: '',\n model: '',\n baseUrl: '',\n },\n session: {\n idleTimeout: 30,\n },\n capture: {\n ignore: ['cd', 'ls', 'll', 'la', 'ls -la', 'ls -l', 'ls -a', 'pwd', 'clear', 'exit', 'history', 'man'],\n aiTools: true,\n includeAiderPrompt: true,\n },\n redact: {\n extra: [],\n },\n summary: {\n format: 'markdown',\n },\n}\n\nexport function readConfig(): WorkscribeConfig {\n if (!fs.existsSync(CONFIG_PATH)) return { ...DEFAULTS }\n try {\n const raw = fs.readFileSync(CONFIG_PATH, 'utf-8')\n const parsed = JSON.parse(raw)\n return deepMerge(DEFAULTS, parsed)\n } catch {\n return { ...DEFAULTS }\n }\n}\n\nexport function writeConfig(config: WorkscribeConfig): void {\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 })\n // Enforce permissions on existing files (mode only applies on creation above)\n try {\n fs.chmodSync(CONFIG_PATH, 0o600)\n } catch {\n /* ignore */\n }\n}\n\nexport function getConfigValue(config: WorkscribeConfig, key: string): unknown {\n const parts = key.split('.')\n let cur: unknown = config\n for (const part of parts) {\n if (cur == null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[part]\n }\n return cur\n}\n\nexport function setConfigValue(config: WorkscribeConfig, key: string, value: string): WorkscribeConfig {\n const parts = key.split('.')\n const result = JSON.parse(JSON.stringify(config)) as WorkscribeConfig\n let cur = result as unknown as Record<string, unknown>\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]\n if (cur[part] == null || typeof cur[part] !== 'object') {\n cur[part] = {}\n }\n cur = cur[part] as Record<string, unknown>\n }\n const lastKey = parts[parts.length - 1]\n // Coerce value type\n if (value === 'true') cur[lastKey] = true\n else if (value === 'false') cur[lastKey] = false\n else if (!isNaN(Number(value))) cur[lastKey] = Number(value)\n else cur[lastKey] = value\n return result\n}\n\nfunction deepMerge<T extends object>(defaults: T, overrides: Partial<T>): T {\n const result = { ...defaults }\n for (const key of Object.keys(overrides) as (keyof T)[]) {\n const val = overrides[key]\n if (val !== null && typeof val === 'object' && !Array.isArray(val) && typeof defaults[key] === 'object') {\n result[key] = deepMerge(defaults[key] as object, val as object) as T[keyof T]\n } else if (val !== undefined) {\n result[key] = val as T[keyof T]\n }\n }\n return result\n}\n","import type { EventRow } from '../db/types'\n\nfunction normalizeForFilter(cmd: string): string {\n return cmd.trim().replace(/\\s+/g, ' ')\n}\n\n// Always filtered regardless of user config — internal tool noise\nconst BUILTIN_IGNORE = new Set(['workscribe'])\n\n/**\n * Returns true if the command should be dropped (noise / ignore list).\n */\nexport function shouldFilter(command: string, ignoreList: string[]): boolean {\n const normalized = normalizeForFilter(command)\n if (!normalized) return true\n\n const baseCmd = normalized.split(' ')[0]\n\n // Built-in filter: always excluded, not user-configurable\n if (BUILTIN_IGNORE.has(baseCmd)) return true\n\n // User-configurable ignore list\n const normalizedIgnore = ignoreList.map(normalizeForFilter)\n if (normalizedIgnore.includes(normalized)) return true\n if (normalizedIgnore.includes(baseCmd)) return true\n\n return false\n}\n\n/**\n * Returns true if this command is a duplicate of the last event\n * (same command + same cwd within the dedup window).\n */\nexport function isDuplicate(\n command: string,\n cwd: string,\n lastEvent: Pick<EventRow, 'command' | 'cwd' | 'captured_at'> | undefined,\n dedupWindowMs = 5000,\n now = Date.now()\n): boolean {\n if (!lastEvent) return false\n const lastTime = new Date(lastEvent.captured_at).getTime()\n return lastEvent.command === normalizeForFilter(command) && lastEvent.cwd === cwd && now - lastTime < dedupWindowMs\n}\n","import { Command } from 'commander'\nimport { captureCommand } from '../capture'\nimport { debugLog } from '../utils/logger'\n\nexport function registerCapture(program: Command): void {\n // Internal command — called by the shell hook, not by the user\n program\n .command('_capture')\n .description('Internal: capture a shell command event (called by shell hook)')\n .option('--cmd <command>', 'command that was executed')\n .option('--cwd <path>', 'working directory')\n .option('--exit <code>', 'exit code', parseInt)\n .option('--duration <ms>', 'duration in milliseconds', parseInt)\n .option('--git-before <sha>', 'git HEAD SHA before this command ran')\n .action((opts) => {\n // Never surface errors to the terminal — this runs silently in the background\n try {\n if (!opts.cmd || !opts.cwd) return\n captureCommand({\n command: opts.cmd,\n cwd: opts.cwd,\n exitCode: opts.exit ?? null,\n durationMs: opts.duration ?? null,\n gitBefore: opts.gitBefore ?? undefined,\n })\n } catch (err) {\n debugLog('_capture', err)\n }\n })\n}\n","import { Command } from 'commander'\nimport { captureCommand } from '../capture'\nimport { readConfig } from '../config'\nimport { debugLog } from '../utils/logger'\n\n/** Parses a Claude Code PostToolUse stdin payload. Returns null if required fields are missing. */\nexport function parseHookPayload(raw: string): { command: string; cwd: string } | null {\n if (!raw.trim()) return null\n const payload = JSON.parse(raw) as Record<string, unknown>\n const toolInput = payload.tool_input as Record<string, unknown> | undefined\n const command = typeof toolInput?.command === 'string' ? toolInput.command : null\n const cwd = typeof payload.cwd === 'string' ? payload.cwd : null\n if (!command || !cwd) return null\n return { command, cwd }\n}\n\nexport function registerHook(program: Command): void {\n // Internal command — called by AI tool hooks (e.g. Claude Code PostToolUse), not by the user\n program\n .command('_hook')\n .description('Internal: capture events from AI tool hooks (stdin JSON payload)')\n .option('--source <source>', 'hook source identifier (e.g. claude-code)')\n .action((opts: { source?: string }) => {\n let raw = ''\n process.stdin.setEncoding('utf-8')\n process.stdin.on('data', (chunk: string) => {\n raw += chunk\n })\n process.stdin.on('end', () => {\n try {\n if (readConfig().capture.aiTools === false) return\n const parsed = parseHookPayload(raw)\n if (!parsed) return\n captureCommand({\n command: parsed.command,\n cwd: parsed.cwd,\n exitCode: null,\n durationMs: null,\n source: opts.source,\n })\n } catch (err) {\n debugLog('_hook', err)\n }\n })\n })\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport prompts from 'prompts'\nimport chalk from 'chalk'\nimport { WORKSCRIBE_DIR, CONFIG_PATH } from '../utils/paths'\nimport { readConfig, writeConfig } from '../config'\nimport { getDb } from '../db'\nimport { log } from '../utils/logger'\nimport { loadAIToolRegistry } from '../config/registry'\nimport { isHookInstalled, isHookOutdated, installHook, updateHook } from '../capture/shell-hook'\nimport { AI_HOOK_INTEGRATIONS } from '../capture/hooks'\n\nfunction detectShell(): { name: string; rcFile: string } | null {\n const shell = process.env.SHELL ?? ''\n if (shell.includes('zsh')) return { name: 'zsh', rcFile: path.join(os.homedir(), '.zshrc') }\n if (shell.includes('bash')) return { name: 'bash', rcFile: path.join(os.homedir(), '.bashrc') }\n return null\n}\n\nexport function registerInit(program: Command): void {\n program\n .command('init')\n .description('Set up Workscribe and install or update shell hooks')\n .action(async () => {\n log.plain(chalk.bold('\\n Workscribe — Developer Work Journal\\n'))\n\n // 1. Create ~/.workscribe/ with owner-only permissions\n if (!fs.existsSync(WORKSCRIBE_DIR)) {\n fs.mkdirSync(WORKSCRIBE_DIR, { recursive: true, mode: 0o700 })\n log.success(`Created ${WORKSCRIBE_DIR}`)\n } else {\n try {\n fs.chmodSync(WORKSCRIBE_DIR, 0o700)\n } catch {\n /* ignore */\n }\n }\n\n // 2. Initialize database (runs migrations)\n getDb()\n log.success('Database initialized')\n\n // 3. Detect shell and install or update hook\n const shell = detectShell()\n if (!shell) {\n log.warn('Could not detect shell. Supported: zsh, bash')\n log.plain(`Manually add the hook from: ${chalk.cyan('shell/hook.zsh')} or ${chalk.cyan('shell/hook.bash')}`)\n } else {\n const hookFile = path.join(__dirname, '..', 'shell', `hook.${shell.name}`)\n if (!fs.existsSync(hookFile)) {\n log.warn(`Hook template not found at ${hookFile}`)\n } else {\n const hookContent = fs.readFileSync(hookFile, 'utf-8')\n if (!fs.existsSync(shell.rcFile)) fs.writeFileSync(shell.rcFile, '')\n\n if (!isHookInstalled(shell.rcFile)) {\n installHook(shell.rcFile, hookContent)\n log.success(`Shell hook installed in ${shell.rcFile}`)\n } else if (isHookOutdated(shell.rcFile, hookContent)) {\n const { update } = await prompts({\n type: 'confirm',\n name: 'update',\n message: `Shell hook in ${shell.rcFile} is outdated. Update?`,\n initial: true,\n })\n if (update) {\n updateHook(shell.rcFile, hookContent)\n log.success(`Shell hook updated in ${shell.rcFile}`)\n } else {\n log.info('Shell hook update skipped')\n }\n } else {\n log.info(`Shell hook up to date in ${shell.rcFile}`)\n }\n }\n }\n\n // 4. AI tool hook integrations (registry-driven — add new tools in src/capture/hooks/)\n const installedTools = loadAIToolRegistry().filter(\n (t) => t.hook !== null && AI_HOOK_INTEGRATIONS[t.hook!]?.isInstalled()\n )\n\n if (installedTools.length === 0) {\n log.info('No AI coding tools detected — re-run workscribe init after installing one')\n } else {\n for (const tool of installedTools) {\n const integration = AI_HOOK_INTEGRATIONS[tool.hook!]!\n\n if (integration.isHookInstalled()) {\n log.info(`${integration.displayName} session hook already installed`)\n } else {\n const { install } = await prompts({\n type: 'confirm',\n name: 'install',\n message: `${integration.displayName} detected. Install session capture hook?`,\n initial: false,\n })\n if (install) {\n integration.install()\n log.success(`${integration.displayName} session hook installed`)\n } else {\n log.info(`${integration.displayName} hook skipped — re-run workscribe init to install later`)\n }\n }\n }\n }\n\n // 5. AI provider setup\n const config = readConfig()\n\n if (config.ai.provider) {\n log.info(`AI provider already configured: ${chalk.cyan(config.ai.provider)}`)\n } else {\n log.plain('')\n const { provider } = await prompts({\n type: 'select',\n name: 'provider',\n message: 'Which AI provider do you want to use?',\n choices: [\n { title: 'Anthropic (Claude) — requires API key', value: 'anthropic' },\n { title: 'OpenAI — requires API key', value: 'openai' },\n { title: 'Ollama (local) — free, runs on your machine', value: 'ollama' },\n { title: 'Other (OpenAI-compatible) — Groq, Together, Mistral…', value: 'openai-compatible' },\n { title: 'Skip — configure later', value: 'skip' },\n ],\n })\n\n if (provider && provider !== 'skip') {\n config.ai.provider = provider\n\n if (provider === 'ollama') {\n log.plain(`\\n ${chalk.dim('Make sure Ollama is running: ollama serve')}`)\n log.plain(\n ` ${chalk.dim('Default model: llama3 (change with: workscribe config set ai.model <model>)')}\\n`\n )\n } else {\n const { apiKey } = await prompts({\n type: 'password',\n name: 'apiKey',\n message: `Enter your ${provider === 'openai-compatible' ? '' : provider + ' '}API key:`,\n })\n if (apiKey) config.ai.apiKey = apiKey\n\n if (provider === 'openai-compatible') {\n const { baseUrl } = await prompts({\n type: 'text',\n name: 'baseUrl',\n message: 'Enter the base URL (e.g. https://api.groq.com/openai/v1):',\n })\n if (baseUrl) config.ai.baseUrl = baseUrl\n }\n }\n\n writeConfig(config)\n log.success(`AI provider set to ${chalk.cyan(provider)}`)\n } else if (provider === 'skip' || !provider) {\n log.info('Skipped — run later: workscribe config set ai.provider <provider>')\n }\n }\n\n // 6. Write config if not exists\n if (!fs.existsSync(CONFIG_PATH)) {\n writeConfig(config)\n log.success('Config file created')\n }\n\n log.plain('')\n log.plain(chalk.bold(' Setup complete!'))\n if (shell) {\n log.plain('')\n log.plain(` Activate capture now: ${chalk.cyan(`source ${shell.rcFile}`)}`)\n log.plain(` Or restart your terminal.`)\n }\n log.plain('')\n log.plain(` ${chalk.dim('workscribe summary')} — generate today\\'s work summary`)\n log.plain(` ${chalk.dim('workscribe status')} — check capture is working`)\n log.plain('')\n })\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { log } from '../utils/logger'\n\nconst HOOK_START = '# workscribe:hook:start'\nconst HOOK_END = '# workscribe:hook:end'\nconst HOOK_PREAMBLE = '# Workscribe — developer work journal'\n\nexport function getInstalledHookBlock(rcFile: string): string | null {\n if (!fs.existsSync(rcFile)) return null\n const content = fs.readFileSync(rcFile, 'utf-8')\n const startIdx = content.indexOf(HOOK_START)\n const endIdx = content.indexOf(HOOK_END)\n if (startIdx === -1 || endIdx === -1) return null\n return content.slice(startIdx, endIdx + HOOK_END.length)\n}\n\nexport function isHookInstalled(rcFile: string): boolean {\n return getInstalledHookBlock(rcFile) !== null\n}\n\nexport function isHookOutdated(rcFile: string, hookContent: string): boolean {\n const installed = getInstalledHookBlock(rcFile)\n if (!installed) return false\n return installed.trim() !== hookContent.trim()\n}\n\nexport function installHook(rcFile: string, hookContent: string): void {\n const backup = `${rcFile}.workscribe-backup-${Date.now()}`\n fs.copyFileSync(rcFile, backup)\n log.info(`Backed up ${rcFile} → ${path.basename(backup)}`)\n fs.appendFileSync(rcFile, `\\n${hookContent}\\n`)\n}\n\nexport function updateHook(rcFile: string, hookContent: string): void {\n const backup = `${rcFile}.workscribe-backup-${Date.now()}`\n fs.copyFileSync(rcFile, backup)\n log.info(`Backed up ${rcFile} → ${path.basename(backup)}`)\n const content = fs.readFileSync(rcFile, 'utf-8')\n const startIdx = content.indexOf(HOOK_START)\n const endIdx = content.indexOf(HOOK_END) + HOOK_END.length\n fs.writeFileSync(rcFile, content.slice(0, startIdx) + hookContent + content.slice(endIdx))\n}\n\nexport function removeHook(rcFile: string): void {\n const backup = `${rcFile}.workscribe-backup-${Date.now()}`\n fs.copyFileSync(rcFile, backup)\n log.info(`Backed up ${rcFile} → ${path.basename(backup)}`)\n const content = fs.readFileSync(rcFile, 'utf-8')\n const startIdx = content.indexOf(HOOK_START)\n const endIdx = content.indexOf(HOOK_END) + HOOK_END.length\n // Also remove the preamble comment lines that installHook writes before HOOK_START\n const preambleIdx = content.lastIndexOf(HOOK_PREAMBLE, startIdx)\n const blockStart = preambleIdx !== -1 ? preambleIdx : startIdx\n const before = content.slice(0, blockStart).replace(/\\n+$/, '\\n')\n const after = content.slice(endIdx).replace(/^\\n/, '')\n fs.writeFileSync(rcFile, before + after)\n}\n","import fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport type { AIHookIntegration } from './types'\nimport { isCommandInstalled } from './utils'\n\nconst CLAUDE_SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json')\n\nfunction readSettings(): Record<string, unknown> {\n if (!fs.existsSync(CLAUDE_SETTINGS_PATH)) return {}\n try {\n return JSON.parse(fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf-8')) as Record<string, unknown>\n } catch {\n return {}\n }\n}\n\nexport const claudeCodeIntegration: AIHookIntegration = {\n displayName: 'Claude Code',\n\n isInstalled() {\n return isCommandInstalled('claude')\n },\n\n isHookInstalled() {\n const settings = readSettings()\n const postToolUse = ((settings.hooks as Record<string, unknown>)?.PostToolUse ?? []) as unknown[]\n return postToolUse.some((entry) => {\n const hooks = ((entry as Record<string, unknown>).hooks ?? []) as unknown[]\n return hooks.some((h) => {\n const hook = h as Record<string, unknown>\n return typeof hook.command === 'string' && hook.command.includes('workscribe _hook')\n })\n })\n },\n\n install() {\n const settings = readSettings()\n const existingHooks = (settings.hooks ?? {}) as Record<string, unknown>\n const existingPostToolUse = (existingHooks.PostToolUse ?? []) as unknown[]\n settings.hooks = {\n ...existingHooks,\n PostToolUse: [\n ...existingPostToolUse,\n {\n matcher: 'Bash',\n hooks: [{ type: 'command', command: 'workscribe _hook --source claude-code', async: true }],\n },\n ],\n }\n fs.mkdirSync(path.dirname(CLAUDE_SETTINGS_PATH), { recursive: true })\n fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2))\n },\n}\n","import { execSync } from 'child_process'\n\n/** Returns true if the given CLI command is available on PATH */\nexport function isCommandInstalled(cmd: string): boolean {\n try {\n execSync(`which ${cmd}`, { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n","import type { AIHookIntegration } from './types'\nimport { claudeCodeIntegration } from './claude-code'\n\n/**\n * Registry of AI tool hook integrations, keyed by the \"hook\" field in src/config/ai-tools.json.\n * Adding support for a new tool = add a new entry here and a corresponding integration file.\n */\nexport const AI_HOOK_INTEGRATIONS: Record<string, AIHookIntegration> = {\n 'claude-code': claudeCodeIntegration,\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport chalk from 'chalk'\nimport { getEventCount, getLastEvent } from '../db'\nimport { readConfig } from '../config'\nimport { log } from '../utils/logger'\nimport { formatDate, todayDate } from '../utils/format'\nimport { getEventsForDate } from '../db'\nimport { PAUSE_FLAG_PATH } from '../utils/paths'\n\nexport function registerStatus(program: Command): void {\n program\n .command('status')\n .description('Show capture status and event counts')\n .action(() => {\n const config = readConfig()\n const total = getEventCount()\n const todayEvents = getEventsForDate(todayDate())\n const last = getLastEvent()\n const isPaused = fs.existsSync(PAUSE_FLAG_PATH)\n\n log.plain('')\n log.plain(chalk.bold(' Workscribe Status'))\n log.plain('')\n\n if (isPaused) {\n log.plain(` Capture ${chalk.yellow('paused')} ${chalk.dim('(run: workscribe resume)')}`)\n } else {\n log.plain(` Capture ${chalk.green('active')}`)\n }\n\n log.plain(` Events today ${chalk.cyan(String(todayEvents.length))}`)\n log.plain(` Events total ${chalk.cyan(String(total))}`)\n\n if (last) {\n log.plain(` Last event ${formatDate(last.captured_at)} ${chalk.dim(last.command.slice(0, 60))}`)\n }\n\n log.plain('')\n log.plain(\n ` AI provider ${config.ai.provider ? chalk.cyan(config.ai.provider) : chalk.yellow('not configured')}`\n )\n if (config.ai.model) log.plain(` Model ${chalk.dim(config.ai.model)}`)\n log.plain('')\n })\n}\n","export function formatDuration(minutes: number): string {\n if (minutes < 60) return `${Math.round(minutes)}m`\n const h = Math.floor(minutes / 60)\n const m = Math.round(minutes % 60)\n return m > 0 ? `${h}h ${m}m` : `${h}h`\n}\n\nexport function formatDate(isoString: string): string {\n return new Date(isoString).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\nexport function todayDate(): string {\n return localDateStr(new Date())\n}\n\nexport function parseDate(input: string): string {\n // Accepts YYYY-MM-DD, returns YYYY-MM-DD. Throws on invalid.\n const d = new Date(input + 'T00:00:00')\n if (isNaN(d.getTime())) throw new Error(`Invalid date: ${input}`)\n return input\n}\n\nfunction localDateStr(d: Date): string {\n const y = d.getFullYear()\n const m = String(d.getMonth() + 1).padStart(2, '0')\n const day = String(d.getDate()).padStart(2, '0')\n return `${y}-${m}-${day}`\n}\n\n// Returns Monday of the ISO week containing dateStr (YYYY-MM-DD)\nexport function startOfWeek(dateStr: string): string {\n const d = new Date(dateStr + 'T00:00:00')\n const day = d.getDay() // 0=Sun\n const diff = day === 0 ? -6 : 1 - day\n d.setDate(d.getDate() + diff)\n return localDateStr(d)\n}\n\n// Returns all YYYY-MM-DD strings from start to end inclusive\nexport function eachDayOfRange(start: string, end: string): string[] {\n const days: string[] = []\n const cur = new Date(start + 'T00:00:00')\n const last = new Date(end + 'T00:00:00')\n while (cur <= last) {\n days.push(localDateStr(cur))\n cur.setDate(cur.getDate() + 1)\n }\n return days\n}\n\n// Returns ISO week string YYYY-WW for a date\nexport function isoWeekKey(dateStr: string): string {\n const d = new Date(dateStr + 'T00:00:00')\n const jan4 = new Date(d.getFullYear(), 0, 4)\n const weekNum = Math.ceil(((d.getTime() - jan4.getTime()) / 86400000 + jan4.getDay() + 1) / 7)\n return `${d.getFullYear()}-W${String(weekNum).padStart(2, '0')}`\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport { getEventsForDate } from '../db'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate, formatDate } from '../utils/format'\nimport { loadAIToolRegistry } from '../config/registry'\n\nconst CATEGORY_COLORS: Record<string, (s: string) => string> = {\n code_commit: chalk.green,\n code_push: chalk.green,\n code_pull: chalk.blue,\n branch_switch: chalk.blue,\n dependency_install: chalk.yellow,\n dependency_remove: chalk.yellow,\n test_run: chalk.magenta,\n build: chalk.cyan,\n server_run: chalk.cyan,\n infrastructure: chalk.red,\n script_run: chalk.white,\n environment: chalk.gray,\n git_other: chalk.blue,\n code_merge: chalk.green,\n code_stash: chalk.blue,\n ai_session: chalk.bold.magenta,\n lint_run: chalk.yellow,\n code_search: chalk.dim.cyan,\n code_read: chalk.dim.white,\n file_ops: chalk.yellow,\n other: chalk.gray,\n}\n\nconst AI_TOOL_DISPLAY_NAMES: Record<string, string> = Object.fromEntries(\n loadAIToolRegistry().map((t) => [t.tool, t.displayName])\n)\n\nexport function registerEvents(program: Command): void {\n program\n .command('events')\n .description('List captured events')\n .option('--date <YYYY-MM-DD>', 'date to list events for (default: today)')\n .option('--limit <n>', 'max events to show', parseInt)\n .action((opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const events = getEventsForDate(date)\n const limit = opts.limit ?? events.length\n\n if (events.length === 0) {\n log.plain(`No events captured for ${date}`)\n return\n }\n\n log.plain('')\n log.plain(chalk.bold(` Events for ${date} (${events.length} total)`))\n log.plain('')\n\n for (const event of events.slice(0, limit)) {\n const colorFn = CATEGORY_COLORS[event.category] ?? chalk.gray\n const time = formatDate(event.captured_at)\n const category = colorFn(event.category.padEnd(20))\n const repo = event.repo_name ? chalk.dim(` [${event.repo_name}]`) : ''\n const exitBadge = event.exit_code && event.exit_code !== 0 ? chalk.red(` ✗${event.exit_code}`) : ''\n\n let cmdDisplay: string\n if (event.category === 'ai_session') {\n let meta: Record<string, unknown> = {}\n try {\n meta = event.metadata ? (JSON.parse(event.metadata) as Record<string, unknown>) : {}\n } catch {\n /* ignore */\n }\n const toolKey = typeof meta.tool === 'string' ? meta.tool : ''\n const toolName = AI_TOOL_DISPLAY_NAMES[toolKey] ?? toolKey\n cmdDisplay = chalk.white(toolName.padEnd(20)) + chalk.magenta(' ✦')\n } else {\n cmdDisplay = chalk.dim(event.command.slice(0, 55))\n }\n\n log.plain(` ${chalk.dim(time)} ${category} ${cmdDisplay}${repo}${exitBadge}`)\n }\n\n if (limit < events.length) {\n log.plain('')\n log.plain(chalk.dim(` … and ${events.length - limit} more (remove --limit to see all)`))\n }\n\n log.plain('')\n })\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport { getOrBuildSessions } from '../sessions/detector'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate, formatDate, formatDuration } from '../utils/format'\n\nexport function registerSessions(program: Command): void {\n program\n .command('sessions')\n .description('List detected work sessions')\n .option('--date <YYYY-MM-DD>', 'date to show sessions for (default: today)')\n .action((opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const sessions = getOrBuildSessions(date)\n\n if (sessions.length === 0) {\n log.plain(`No sessions detected for ${date}`)\n return\n }\n\n log.plain('')\n log.plain(chalk.bold(` Sessions for ${date} (${sessions.length} session${sessions.length > 1 ? 's' : ''})`))\n log.plain('')\n\n for (const session of sessions) {\n const start = formatDate(session.startedAt)\n const end = formatDate(session.endedAt)\n const duration = formatDuration(session.durationMinutes)\n const repo = session.repoName ? chalk.cyan(session.repoName) : chalk.gray('no repo')\n log.plain(\n ` ${chalk.dim(start)} – ${chalk.dim(end)} ${repo} ${chalk.dim(duration)} ${chalk.dim(session.eventCount + ' events')}`\n )\n }\n\n log.plain('')\n })\n}\n","import type { EventRow } from '../db/types'\n\n/**\n * Split a sorted list of events into groups separated by idle gaps.\n */\nexport function splitByIdleGap(events: EventRow[], idleMs: number): EventRow[][] {\n if (events.length === 0) return []\n const groups: EventRow[][] = [[events[0]]]\n\n for (let i = 1; i < events.length; i++) {\n const prev = new Date(events[i - 1].captured_at).getTime()\n const curr = new Date(events[i].captured_at).getTime()\n if (curr - prev >= idleMs) {\n groups.push([events[i]])\n } else {\n groups[groups.length - 1].push(events[i])\n }\n }\n\n return groups\n}\n\n/**\n * Split a list of events into groups by consecutive repo_name.\n * A repo change mid-stream creates a new group.\n */\nexport function splitByRepo(events: EventRow[]): EventRow[][] {\n if (events.length === 0) return []\n const groups: EventRow[][] = [[events[0]]]\n\n for (let i = 1; i < events.length; i++) {\n const prevRepo = events[i - 1].repo_name\n const currRepo = events[i].repo_name\n if (currRepo !== prevRepo) {\n groups.push([events[i]])\n } else {\n groups[groups.length - 1].push(events[i])\n }\n }\n\n return groups\n}\n\nexport function minutesBetween(start: string, end: string): number {\n return (new Date(end).getTime() - new Date(start).getTime()) / 60000\n}\n","import type { EventRow } from '../db/types'\nimport {\n insertSession,\n insertSessionEvent,\n clearSessionsForDate,\n getSessionsForDate,\n getEventsForDate,\n getEventsBySessionId,\n} from '../db'\nimport { readConfig } from '../config'\nimport { splitByIdleGap, splitByRepo, minutesBetween } from './grouper'\n\nexport interface Session {\n id: number\n date: string\n startedAt: string\n endedAt: string\n repoName: string | null\n durationMinutes: number\n eventCount: number\n summary: string | null\n events: EventRow[]\n}\n\nexport function getOrBuildSessions(date: string): Session[] {\n // Check if sessions already exist for this date\n const existing = getSessionsForDate(date)\n const events = getEventsForDate(date)\n\n if (events.length === 0) return []\n\n // If sessions exist and event count matches, use cached\n const cachedEventCount = existing.reduce((sum, s) => sum + s.event_count, 0)\n if (existing.length > 0 && cachedEventCount === events.length) {\n return existing.map((s) => ({\n id: s.id,\n date: s.date,\n startedAt: s.started_at,\n endedAt: s.ended_at,\n repoName: s.repo_name,\n durationMinutes: minutesBetween(s.started_at, s.ended_at),\n eventCount: s.event_count,\n summary: s.summary,\n events: getEventsBySessionId(s.id),\n }))\n }\n\n // Preserve any cached summaries before clearing — keyed by repo+start time\n // so they can be restored to matching sessions after rebuild\n const savedSummaries = new Map<string, string>()\n for (const s of existing) {\n if (s.summary) savedSummaries.set(`${s.repo_name}|${s.started_at}`, s.summary)\n }\n\n // Rebuild sessions\n clearSessionsForDate(date)\n return buildSessions(date, events, savedSummaries)\n}\n\nfunction buildSessions(date: string, events: EventRow[], savedSummaries: Map<string, string> = new Map()): Session[] {\n const config = readConfig()\n const idleMs = config.session.idleTimeout * 60 * 1000\n\n const sessions: Session[] = []\n const timeGroups = splitByIdleGap(events, idleMs)\n\n for (const group of timeGroups) {\n if (group.length === 0) continue\n\n const repoGroups = splitByRepo(group)\n\n for (const repoGroup of repoGroups) {\n if (repoGroup.length === 0) continue\n\n const first = repoGroup[0]\n const last = repoGroup[repoGroup.length - 1]\n const repoName = last.repo_name ?? first.repo_name ?? null\n\n // Restore a previously generated summary if the session boundaries match\n const summary = savedSummaries.get(`${repoName}|${first.captured_at}`) ?? null\n\n const sessionId = insertSession({\n date,\n started_at: first.captured_at,\n ended_at: last.captured_at,\n repo_name: repoName,\n event_count: repoGroup.length,\n summary,\n })\n\n for (const event of repoGroup) {\n insertSessionEvent(sessionId, event.id)\n }\n\n sessions.push({\n id: sessionId,\n date,\n startedAt: first.captured_at,\n endedAt: last.captured_at,\n repoName,\n durationMinutes: minutesBetween(first.captured_at, last.captured_at),\n eventCount: repoGroup.length,\n summary,\n events: repoGroup,\n })\n }\n }\n\n return sessions\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport { getOrBuildSessions } from '../sessions/detector'\nimport { getProvider } from '../ai/router'\nimport { readConfig } from '../config'\nimport { updateSessionSummary } from '../db'\nimport { log } from '../utils/logger'\nimport {\n todayDate,\n parseDate,\n formatDate,\n formatDuration,\n startOfWeek,\n eachDayOfRange,\n isoWeekKey,\n} from '../utils/format'\nimport { postToWebhook } from '../integrations/webhook'\nimport { formatForSlack, isSlackWebhookUrl } from '../integrations/slack'\nimport { WEEKLY_CACHE_DIR } from '../utils/paths'\nimport type { DaySummaryPayload, SessionPayload, EventPayload, WeekSummaryPayload } from '../ai/types'\nimport type { EventRow } from '../db'\n\ninterface SessionSummaryJson {\n project: string | null\n branch: string | null\n durationMinutes: number\n bullets: string[]\n}\n\n/** Parse AI bullet output into a clean string array. Handles both - and • prefixes. */\nexport function parseBullets(text: string): string[] {\n return text\n .split('\\n')\n .map((l) => l.replace(/^[•\\-]\\s*/, '').trim())\n .filter(Boolean)\n}\n\nfunction eventRowToPayload(row: EventRow): EventPayload {\n let metadata: Record<string, unknown> = {}\n try {\n if (row.metadata) metadata = JSON.parse(row.metadata)\n } catch {\n /* ignore */\n }\n return {\n category: row.category,\n metadata,\n exitCode: row.exit_code,\n durationMs: row.duration_ms,\n }\n}\n\nfunction sessionToPayload(s: ReturnType<typeof getOrBuildSessions>[number], date: string): SessionPayload {\n return {\n date,\n project: s.repoName,\n branch: s.events[0]?.branch ?? null,\n startTime: formatDate(s.startedAt),\n endTime: formatDate(s.endedAt),\n durationMinutes: s.durationMinutes,\n events: s.events.map(eventRowToPayload),\n }\n}\n\nasync function handleWebhook(\n opts: { slack?: boolean; webhook?: string },\n config: ReturnType<typeof readConfig>,\n summary: string\n): Promise<void> {\n const webhookUrl = opts.webhook ?? (opts.slack ? config.integrations?.slackWebhook : undefined)\n\n if (webhookUrl) {\n try {\n log.info('Posting to webhook…')\n const username = os.userInfo().username\n const body = isSlackWebhookUrl(webhookUrl) ? formatForSlack(summary, username) : summary\n await postToWebhook(webhookUrl, body)\n log.success('Posted.')\n } catch (e) {\n log.error(`Webhook failed: ${(e as Error).message}`)\n }\n } else if (opts.slack && !config.integrations?.slackWebhook) {\n log.warn('--slack requires integrations.slackWebhook to be set in config')\n }\n}\n\nexport function registerSummary(program: Command): void {\n program\n .command('summary')\n .description('Generate an AI work summary')\n .option('--date <YYYY-MM-DD>', 'date to summarize (default: today)')\n .option('--week', 'summarize the current week')\n .option('--fresh', 'bypass cache and regenerate')\n .option('--slack', 'post summary to Slack webhook from config')\n .option('--webhook <url>', 'post summary to a custom webhook URL')\n .action(async (opts) => {\n const config = readConfig()\n let provider\n try {\n provider = getProvider(config)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n\n // ── Weekly branch ────────────────────────────────────────────────────────\n if (opts.week) {\n const today = todayDate()\n const weekStart = startOfWeek(today)\n const days = eachDayOfRange(weekStart, today)\n\n const weeklyDays: WeekSummaryPayload['days'] = []\n for (const day of days) {\n const sessions = getOrBuildSessions(day)\n if (sessions.length > 0) {\n weeklyDays.push({ date: day, sessions: sessions.map((s) => sessionToPayload(s, day)) })\n }\n }\n\n if (weeklyDays.length === 0) {\n log.plain('No activity captured this week.')\n return\n }\n\n const cacheKey = isoWeekKey(today)\n const cacheFile = path.join(WEEKLY_CACHE_DIR, `${cacheKey}.md`)\n\n if (!opts.fresh && fs.existsSync(cacheFile)) {\n const cached = fs.readFileSync(cacheFile, 'utf-8')\n log.plain('')\n log.plain(cached)\n log.plain('')\n log.plain(chalk.dim(' (cached — use --fresh to regenerate)'))\n await handleWebhook(opts, config, cached)\n return\n }\n\n const payload: WeekSummaryPayload = { weekStart, weekEnd: today, days: weeklyDays }\n\n log.plain('')\n log.info(`Generating weekly summary via ${chalk.cyan(config.ai.provider)}…`)\n\n try {\n const summary = provider.summarizeWeek\n ? await provider.summarizeWeek(payload)\n : await provider.summarize({ date: today, sessions: weeklyDays.flatMap((d) => d.sessions) })\n\n log.plain('')\n log.plain(summary)\n log.plain('')\n\n fs.mkdirSync(WEEKLY_CACHE_DIR, { recursive: true })\n fs.writeFileSync(cacheFile, summary, { encoding: 'utf-8', mode: 0o600 })\n\n await handleWebhook(opts, config, summary)\n } catch (e) {\n log.error(`Weekly summary failed [${config.ai.provider}]: ${(e as Error).message}`)\n process.exit(1)\n }\n return\n }\n\n // ── Daily branch ─────────────────────────────────────────────────────────\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const sessions = getOrBuildSessions(date)\n\n if (sessions.length === 0) {\n log.plain(`No activity captured for ${date}`)\n return\n }\n\n const jsonMode = config.summary?.format === 'json'\n\n if (!opts.fresh) {\n const allCached = sessions.every((s) => s.summary)\n if (allCached) {\n const fullSummary = sessions.map((s) => s.summary!).join('\\n\\n')\n log.plain('')\n if (jsonMode) {\n const jsonOut: SessionSummaryJson[] = sessions.map((s) => ({\n project: s.repoName,\n branch: s.events[0]?.branch ?? null,\n durationMinutes: s.durationMinutes,\n bullets: parseBullets(s.summary!.replace(/^## .+\\n/, '')),\n }))\n log.plain(JSON.stringify({ date, sessions: jsonOut }, null, 2))\n } else {\n log.plain(fullSummary)\n }\n log.plain('')\n log.plain(chalk.dim(' (cached — use --fresh to regenerate)'))\n await handleWebhook(opts, config, fullSummary)\n return\n }\n }\n\n log.plain('')\n log.info(`Generating summary via ${chalk.cyan(config.ai.provider)}…`)\n\n const allSummaries: string[] = []\n const jsonSessions: SessionSummaryJson[] = []\n\n for (const session of sessions) {\n const sessionPayload: DaySummaryPayload = { date, sessions: [sessionToPayload(session, date)] }\n try {\n const bullets = await provider.summarize(sessionPayload)\n const project = session.repoName ?? 'unknown'\n const branch = session.events[0]?.branch ? ` (${session.events[0].branch})` : ''\n const duration = formatDuration(session.durationMinutes)\n const heading = `## ${project}${branch} — ${duration}`\n const summary = `${heading}\\n${bullets.trim()}`\n allSummaries.push(summary)\n updateSessionSummary(session.id, summary)\n if (jsonMode) {\n jsonSessions.push({\n project: session.repoName,\n branch: session.events[0]?.branch ?? null,\n durationMinutes: session.durationMinutes,\n bullets: parseBullets(bullets),\n })\n }\n } catch (e) {\n log.error(`Summary failed [${config.ai.provider}]: ${(e as Error).message}`)\n process.exit(1)\n }\n }\n\n const fullSummary = allSummaries.join('\\n\\n')\n log.plain('')\n if (jsonMode) {\n log.plain(JSON.stringify({ date, sessions: jsonSessions }, null, 2))\n } else {\n log.plain(fullSummary)\n }\n log.plain('')\n\n await handleWebhook(opts, config, fullSummary)\n })\n}\n","import type { DaySummaryPayload, WeekSummaryPayload } from './types'\nimport { formatDuration } from '../utils/format'\n\nexport const SYSTEM_PROMPT = `You write short developer work summaries. Here is an example:\n\nINPUT:\nProject: api-service\nBranch: feature/auth\nDuration: 2h 00m\nEvents:\n - branch_switch {\"branch\":\"feature/auth\"}\n - 2x dependency_install {\"tool\":\"npm\",\"packages\":[\"bcrypt\",\"jsonwebtoken\"]}\n - 2x test_run {\"tool\":\"jest\"} [failed]\n - test_run {\"tool\":\"jest\"}\n - 2x file_ops {\"tool\":\"mkdir\"}\n - code_commit {\"message\":\"fix: auth token validation\"}\n - code_push {\"remote\":\"origin\",\"branch\":\"feature/auth\"}\n\nOUTPUT:\n- Switched to the authentication feature branch and added authentication dependencies (bcrypt, JWT)\n- Resolved failing auth tests\n- Committed and pushed authentication fixes\n\nFor dependency_install events: infer the purpose of packages from their names and describe the domain, not just the packages. Examples: bcrypt/jsonwebtoken → authentication, prisma/mongoose/pg → database, jest/vitest/mocha → testing, axios/got/node-fetch → HTTP client, stripe/paypal → payments, socket.io/ws → real-time. Use your knowledge of common packages. For unfamiliar packages, name them directly without guessing their domain.\n\nEvents like code_push, build, file_ops, and code_stash provide context — fold them into the surrounding narrative rather than listing them as separate bullets. Only surface them directly when they are the main activity (e.g. a standalone build fix, or a significant restructure with no accompanying commits).\n\nFor ai_session events: describe what was built during the AI session using the tool name (e.g. \"via Claude Code\"). If a commits array is present in metadata, use those commit messages to describe what was built. Group all activity from the session into one narrative bullet.\n\nMaximum 5 bullets. Output ONLY the bullet points, nothing else.`\n\n// Categories excluded from the AI payload — investigative/shell noise that adds no signal to summaries\nconst EXCLUDED = new Set(['environment', 'code_search', 'code_read', 'server_run', 'git_other'])\n\nexport function buildUserMessage(payload: DaySummaryPayload): string {\n const lines: string[] = [`Date: ${payload.date}`, '']\n\n for (const session of payload.sessions) {\n lines.push(`Project: ${session.project ?? 'unknown'}`)\n if (session.branch) lines.push(`Branch: ${session.branch}`)\n lines.push(`Duration: ${formatDuration(session.durationMinutes)}`)\n lines.push('Events:')\n\n // Aggregate repeated events so the model sees \"3x build\" not 3 separate build lines\n const counts = new Map<string, number>()\n for (const event of session.events) {\n if (EXCLUDED.has(event.category)) continue\n const meta = Object.keys(event.metadata).length > 0 ? ` ${JSON.stringify(event.metadata)}` : ''\n const failed = event.exitCode !== null && event.exitCode !== 0 ? ' [failed]' : ''\n const key = `${event.category}${meta}${failed}`\n counts.set(key, (counts.get(key) ?? 0) + 1)\n }\n\n for (const [key, count] of counts) {\n lines.push(` - ${count > 1 ? `${count}x ` : ''}${key}`)\n }\n\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n\nexport const WEEKLY_SYSTEM_PROMPT = `You write short weekly developer summaries. Here is an example:\n\nINPUT:\nWeek: 2026-05-18 to 2026-05-22\n\nMonday 2026-05-18:\n Project: api-service (feature/auth) — 2h 10m\n Events: 3x code_commit, 2x test_run, dependency_install\n\nTuesday 2026-05-19:\n Project: api-service (feature/auth) — 1h 30m\n Events: 2x code_commit, test_run, build\n\nWednesday 2026-05-20:\n Project: dashboard (main) — 3h 00m\n Events: 4x code_commit, 2x build, test_run\n\nThursday 2026-05-21:\n Project: api-service (feature/auth) — 1h 00m\n Events: code_commit {\"message\":\"feat: merge auth\"}, branch_switch\n\nFriday 2026-05-22:\n Project: dashboard (main) — 2h 00m\n Events: 3x code_commit, build\n\nOUTPUT:\n## Week of 18 May — 9h 40m across 2 projects\n\n**api-service** (Mon–Thu): Built and shipped the auth feature — JWT setup, token validation fixes, and final merge.\n**dashboard** (Wed, Fri): Active development across 7 commits with builds passing.\n\nNow summarise the following week. Output ONLY the summary — a one-line header then one bullet per active project. Maximum 4 bullets.`\n\nconst DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']\n\nexport function buildWeeklyMessage(payload: WeekSummaryPayload): string {\n const lines: string[] = [`Week: ${payload.weekStart} to ${payload.weekEnd}`, '']\n\n for (const { date, sessions } of payload.days) {\n const dayName = DAY_NAMES[new Date(date + 'T00:00:00').getDay()]\n lines.push(`${dayName} ${date}:`)\n\n for (const s of sessions) {\n const project = s.project ?? 'unknown'\n const branch = s.branch ? ` (${s.branch})` : ''\n lines.push(` Project: ${project}${branch} — ${formatDuration(s.durationMinutes)}`)\n\n const counts = new Map<string, number>()\n for (const e of s.events) {\n if (EXCLUDED.has(e.category)) continue\n const meta = Object.keys(e.metadata).length > 0 ? ` ${JSON.stringify(e.metadata)}` : ''\n const failed = e.exitCode !== null && e.exitCode !== 0 ? ' [failed]' : ''\n const key = `${e.category}${meta}${failed}`\n counts.set(key, (counts.get(key) ?? 0) + 1)\n }\n const eventLine = [...counts.entries()].map(([k, n]) => `${n > 1 ? `${n}x ` : ''}${k}`).join(', ')\n lines.push(` Events: ${eventLine}`)\n }\n\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n","const DEFAULT_TIMEOUT_MS = 30_000\n\nexport async function fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeoutMs = DEFAULT_TIMEOUT_MS\n): Promise<Response> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n return await fetch(url, { ...init, signal: controller.signal })\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error(`Request timed out after ${timeoutMs / 1000}s`)\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n}\n","import type { AIProvider, DaySummaryPayload, WeekSummaryPayload } from '../types'\nimport { SYSTEM_PROMPT, buildUserMessage, WEEKLY_SYSTEM_PROMPT, buildWeeklyMessage } from '../prompt'\nimport { fetchWithTimeout } from '../fetch'\n\nexport class AnthropicProvider implements AIProvider {\n private apiKey: string\n private model: string\n\n constructor(apiKey: string, model?: string) {\n this.apiKey = apiKey\n this.model = model || 'claude-haiku-4-5-20251001'\n }\n\n async summarize(payload: DaySummaryPayload): Promise<string> {\n const response = await fetchWithTimeout('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: this.model,\n max_tokens: 1024,\n system: SYSTEM_PROMPT,\n messages: [{ role: 'user', content: buildUserMessage(payload) }],\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Anthropic API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as { content: Array<{ type: string; text: string }> }\n return data.content.find((c) => c.type === 'text')?.text ?? ''\n }\n\n async summarizeWeek(payload: WeekSummaryPayload): Promise<string> {\n const response = await fetchWithTimeout('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: this.model,\n max_tokens: 1024,\n system: WEEKLY_SYSTEM_PROMPT,\n messages: [{ role: 'user', content: buildWeeklyMessage(payload) }],\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Anthropic API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as { content: Array<{ type: string; text: string }> }\n return data.content.find((c) => c.type === 'text')?.text ?? ''\n }\n}\n","import type { AIProvider, DaySummaryPayload, WeekSummaryPayload } from '../types'\nimport { SYSTEM_PROMPT, buildUserMessage, WEEKLY_SYSTEM_PROMPT, buildWeeklyMessage } from '../prompt'\nimport { fetchWithTimeout } from '../fetch'\n\nexport class OpenAIProvider implements AIProvider {\n private apiKey: string\n private model: string\n private baseUrl: string\n\n constructor(apiKey: string, model?: string, baseUrl?: string) {\n this.apiKey = apiKey\n this.model = model || 'gpt-4o-mini'\n this.baseUrl = baseUrl || 'https://api.openai.com/v1'\n }\n\n async summarize(payload: DaySummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n model: this.model,\n messages: [\n { role: 'system', content: SYSTEM_PROMPT },\n { role: 'user', content: buildUserMessage(payload) },\n ],\n max_tokens: 1024,\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`OpenAI API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as {\n choices: Array<{ message: { content: string } }>\n }\n return data.choices[0]?.message?.content ?? ''\n }\n\n async summarizeWeek(payload: WeekSummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n model: this.model,\n messages: [\n { role: 'system', content: WEEKLY_SYSTEM_PROMPT },\n { role: 'user', content: buildWeeklyMessage(payload) },\n ],\n max_tokens: 1024,\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`OpenAI API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as {\n choices: Array<{ message: { content: string } }>\n }\n return data.choices[0]?.message?.content ?? ''\n }\n}\n","import type { AIProvider, DaySummaryPayload, WeekSummaryPayload } from '../types'\nimport { SYSTEM_PROMPT, buildUserMessage, WEEKLY_SYSTEM_PROMPT, buildWeeklyMessage } from '../prompt'\nimport { fetchWithTimeout } from '../fetch'\n\nexport class OllamaProvider implements AIProvider {\n private model: string\n private baseUrl: string\n\n constructor(model?: string, baseUrl?: string) {\n this.model = model || 'llama3'\n this.baseUrl = baseUrl || 'http://localhost:11434'\n }\n\n async summarize(payload: DaySummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/api/chat`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n stream: false,\n messages: [\n { role: 'system', content: SYSTEM_PROMPT },\n { role: 'user', content: buildUserMessage(payload) },\n ],\n options: {\n num_predict: 300, // hard cap on output tokens — forces conciseness\n temperature: 0.3, // lower temperature = more focused, less wandering\n },\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Ollama error ${response.status}: ${body}. Is Ollama running? Try: ollama serve`)\n }\n\n const data = (await response.json()) as { message: { content: string } }\n return data.message?.content ?? ''\n }\n\n async summarizeWeek(payload: WeekSummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/api/chat`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n stream: false,\n messages: [\n { role: 'system', content: WEEKLY_SYSTEM_PROMPT },\n { role: 'user', content: buildWeeklyMessage(payload) },\n ],\n options: {\n num_predict: 400,\n temperature: 0.3,\n },\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Ollama error ${response.status}: ${body}. Is Ollama running? Try: ollama serve`)\n }\n\n const data = (await response.json()) as { message: { content: string } }\n return data.message?.content ?? ''\n }\n}\n","import type { AIProvider } from './types'\nimport type { WorkscribeConfig } from '../config'\nimport { AnthropicProvider } from './providers/anthropic'\nimport { OpenAIProvider } from './providers/openai'\nimport { OllamaProvider } from './providers/ollama'\n\nexport function getProvider(config: WorkscribeConfig): AIProvider {\n const { provider, apiKey, model, baseUrl } = config.ai\n\n if (!provider) {\n throw new Error(\n 'No AI provider configured.\\nRun: workscribe config set ai.provider <anthropic|openai|ollama|openai-compatible>'\n )\n }\n\n switch (provider) {\n case 'anthropic': {\n if (!apiKey) throw new Error('Anthropic requires an API key.\\nRun: workscribe config set ai.apiKey <your-key>')\n return new AnthropicProvider(apiKey, model || undefined)\n }\n\n case 'openai': {\n if (!apiKey) throw new Error('OpenAI requires an API key.\\nRun: workscribe config set ai.apiKey <your-key>')\n return new OpenAIProvider(apiKey, model || undefined)\n }\n\n case 'openai-compatible': {\n if (!apiKey)\n throw new Error('This provider requires an API key.\\nRun: workscribe config set ai.apiKey <your-key>')\n if (!baseUrl)\n throw new Error('openai-compatible requires a base URL.\\nRun: workscribe config set ai.baseUrl <url>')\n return new OpenAIProvider(apiKey, model || undefined, baseUrl)\n }\n\n case 'ollama': {\n return new OllamaProvider(model || undefined, baseUrl || undefined)\n }\n\n default:\n throw new Error(\n `Unknown provider: \"${provider}\"\\nSupported providers: anthropic, openai, ollama, openai-compatible`\n )\n }\n}\n","import { fetchWithTimeout } from '../ai/fetch'\n\nexport async function postToWebhook(url: string, text: string): Promise<void> {\n const response = await fetchWithTimeout(\n url,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ text }),\n },\n 10_000\n )\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Webhook POST failed ${response.status}: ${body}`)\n }\n}\n","/**\n * Converts workscribe markdown summary output to Slack mrkdwn format.\n *\n * Rules:\n * ## heading → *heading* (bold)\n * - bullet → • bullet\n *\n * An optional username is prepended as a dim header line so recipients\n * can tell who sent the summary in shared channels.\n */\nexport function formatForSlack(markdown: string, username?: string): string {\n const body = markdown.replace(/^## (.+)$/gm, '*$1*').replace(/^- /gm, '• ')\n return username ? `_${username}_\\n${body}` : body\n}\n\nexport function isSlackWebhookUrl(url: string): boolean {\n return url.startsWith('https://hooks.slack.com/')\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport path from 'path'\nimport { getOrBuildSessions } from '../sessions/detector'\nimport { getProvider } from '../ai/router'\nimport { readConfig } from '../config'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate, formatDate } from '../utils/format'\nimport { EXPORTS_DIR } from '../utils/paths'\nimport type { DaySummaryPayload, SessionPayload, EventPayload } from '../ai/types'\nimport type { EventRow } from '../db'\n\nfunction eventRowToPayload(row: EventRow): EventPayload {\n let metadata: Record<string, unknown> = {}\n try {\n if (row.metadata) metadata = JSON.parse(row.metadata)\n } catch {\n /* ignore */\n }\n return { category: row.category, metadata, exitCode: row.exit_code, durationMs: row.duration_ms }\n}\n\nexport function registerExport(program: Command): void {\n program\n .command('export')\n .description('Export work summary as a markdown file')\n .option('--date <YYYY-MM-DD>', 'date to export (default: today)')\n .option('--output <path>', 'output file path (default: ~/.workscribe/exports/)')\n .action(async (opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const sessions = getOrBuildSessions(date)\n if (sessions.length === 0) {\n log.plain(`No activity captured for ${date}`)\n return\n }\n\n const config = readConfig()\n let provider\n try {\n provider = getProvider(config)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n\n const sessionPayloads: SessionPayload[] = sessions.map((s) => ({\n date,\n project: s.repoName,\n branch: s.events[0]?.branch ?? null,\n startTime: formatDate(s.startedAt),\n endTime: formatDate(s.endedAt),\n durationMinutes: s.durationMinutes,\n events: s.events.map(eventRowToPayload),\n }))\n\n const payload: DaySummaryPayload = { date, sessions: sessionPayloads }\n\n log.info(`Generating summary via ${config.ai.provider}…`)\n const summary = await provider.summarize(payload)\n\n const outputPath = opts.output ?? path.join(EXPORTS_DIR, `workscribe-${date}.md`)\n\n if (!fs.existsSync(EXPORTS_DIR)) fs.mkdirSync(EXPORTS_DIR, { recursive: true, mode: 0o700 })\n\n fs.writeFileSync(outputPath, `# Work Summary — ${date}\\n\\n${summary}\\n`, { encoding: 'utf-8', mode: 0o600 })\n log.success(`Saved: ${outputPath}`)\n })\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport { readConfig, writeConfig, getConfigValue, setConfigValue } from '../config'\nimport { log } from '../utils/logger'\n\nexport function registerConfig(program: Command): void {\n const configCmd = program\n .command('config')\n .description('View or update Workscribe configuration')\n .action(() => {\n const config = readConfig()\n log.plain('')\n log.plain(chalk.bold(' Workscribe Config'))\n log.plain('')\n printConfig(config, ' ')\n log.plain('')\n })\n\n configCmd\n .command('set <key> <value>')\n .description('Set a config value (e.g. workscribe config set ai.provider anthropic)')\n .action((key: string, value: string) => {\n const config = readConfig()\n const updated = setConfigValue(config, key, value)\n writeConfig(updated)\n const isSensitive =\n key === 'ai.apiKey' ||\n key.toLowerCase().includes('key') ||\n key.toLowerCase().includes('secret') ||\n key.toLowerCase().includes('token')\n const displayValue = isSensitive ? '[set]' : chalk.yellow(value)\n log.success(`Set ${chalk.cyan(key)} = ${displayValue}`)\n })\n\n configCmd\n .command('get <key>')\n .description('Get a config value')\n .action((key: string) => {\n const config = readConfig()\n const value = getConfigValue(config, key)\n if (value === undefined) {\n log.warn(`Key not found: ${key}`)\n } else {\n const lastSegment = key.split('.').pop() ?? ''\n if (SENSITIVE_KEYS.has(lastSegment) && typeof value === 'string' && value.length > 0) {\n log.plain(`${value.slice(0, 4)}${'*'.repeat(8)} (${value.length} chars)`)\n } else {\n log.plain(String(value))\n }\n }\n })\n}\n\nconst SENSITIVE_KEYS = new Set([\n 'apiKey',\n 'api_key',\n 'secret',\n 'token',\n 'password',\n 'passwd',\n 'webhook',\n 'slackWebhook',\n])\n\nfunction maskValue(key: string, value: unknown): string {\n if (SENSITIVE_KEYS.has(key) && typeof value === 'string' && value.length > 0) {\n return chalk.dim(`${value.slice(0, 4)}${'*'.repeat(8)} (${value.length} chars)`)\n }\n if (Array.isArray(value)) return `[${(value as unknown[]).join(', ')}]`\n return String(value) || chalk.dim('(not set)')\n}\n\nfunction printConfig(obj: unknown, indent: string): void {\n if (typeof obj !== 'object' || obj === null) return\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n log.plain(`${indent}${chalk.bold(key)}:`)\n printConfig(value, indent + ' ')\n } else {\n log.plain(`${indent}${chalk.dim(key)}: ${chalk.yellow(maskValue(key, value))}`)\n }\n }\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport { PAUSE_FLAG_PATH } from '../utils/paths'\nimport { log } from '../utils/logger'\n\nexport function registerPause(program: Command): void {\n program\n .command('pause')\n .description('Pause capture temporarily')\n .action(() => {\n if (fs.existsSync(PAUSE_FLAG_PATH)) {\n log.info('Capture is already paused. Run workscribe resume to restart.')\n return\n }\n fs.writeFileSync(PAUSE_FLAG_PATH, '', { mode: 0o600 })\n log.success('Capture paused. Run workscribe resume to restart.')\n })\n\n program\n .command('resume')\n .description('Resume capture after a pause')\n .action(() => {\n if (!fs.existsSync(PAUSE_FLAG_PATH)) {\n log.info('Capture is not paused.')\n return\n }\n fs.rmSync(PAUSE_FLAG_PATH)\n log.success('Capture resumed.')\n })\n}\n","import { Command } from 'commander'\nimport { getLastEventIds, getEventsByIds, deleteEventsByIds } from '../db'\nimport { log } from '../utils/logger'\n\nexport function registerUndo(program: Command): void {\n program\n .command('undo')\n .description('Remove the last N captured events')\n .option('-n, --count <number>', 'number of events to remove', '1')\n .option('--dry-run', 'preview what would be deleted without deleting')\n .action((opts) => {\n const count = parseInt(opts.count, 10)\n if (isNaN(count) || count < 1) {\n log.error('--count must be a positive integer')\n process.exit(1)\n }\n\n const ids = getLastEventIds(count)\n if (ids.length === 0) {\n log.plain('No events to undo.')\n return\n }\n\n const events = getEventsByIds(ids)\n log.plain('')\n log.plain(`Events to remove (${events.length}):`)\n for (const e of events) {\n log.plain(` ${e.captured_at} ${e.category} ${e.command}`)\n }\n log.plain('')\n\n if (opts.dryRun) {\n log.plain('Dry run — nothing deleted.')\n return\n }\n\n deleteEventsByIds(ids)\n log.success(`Removed ${ids.length} event${ids.length > 1 ? 's' : ''}.`)\n })\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport prompts from 'prompts'\nimport { getEventsForDate, deleteEventsForDate } from '../db'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate } from '../utils/format'\n\nexport function registerClear(program: Command): void {\n program\n .command('clear')\n .description('Delete all captured events for a date')\n .option('--date <YYYY-MM-DD>', 'date to clear (default: today)')\n .option('--dry-run', 'preview what would be deleted without deleting')\n .option('--yes', 'skip confirmation prompt')\n .action(async (opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const events = getEventsForDate(date)\n\n if (events.length === 0) {\n log.plain(`No events found for ${date}.`)\n return\n }\n\n log.plain('')\n log.plain(chalk.bold(` Events for ${date} (${events.length} total)`))\n log.plain('')\n\n // Show a compact summary by category\n const counts = new Map<string, number>()\n for (const e of events) counts.set(e.category, (counts.get(e.category) ?? 0) + 1)\n for (const [cat, n] of counts) {\n log.plain(` ${chalk.dim(String(n).padStart(4))} ${cat}`)\n }\n log.plain('')\n\n if (opts.dryRun) {\n log.plain(chalk.dim(' Dry run — nothing deleted.'))\n log.plain('')\n return\n }\n\n if (!opts.yes) {\n const { confirm } = await prompts({\n type: 'confirm',\n name: 'confirm',\n message: `Delete all ${events.length} events for ${date}?`,\n initial: false,\n })\n if (!confirm) {\n log.plain('Cancelled.')\n return\n }\n }\n\n const deleted = deleteEventsForDate(date)\n log.success(`Cleared ${deleted} event${deleted !== 1 ? 's' : ''} for ${date}.`)\n })\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport prompts from 'prompts'\nimport chalk from 'chalk'\nimport { WORKSCRIBE_DIR } from '../utils/paths'\nimport { isHookInstalled, removeHook } from '../capture/shell-hook'\nimport { log } from '../utils/logger'\n\nfunction detectShellRcFiles(): { name: string; rcFile: string }[] {\n const candidates = [\n { name: 'zsh', rcFile: path.join(os.homedir(), '.zshrc') },\n { name: 'bash', rcFile: path.join(os.homedir(), '.bashrc') },\n { name: 'bash', rcFile: path.join(os.homedir(), '.bash_profile') },\n ]\n return candidates.filter((c) => fs.existsSync(c.rcFile) && isHookInstalled(c.rcFile))\n}\n\nexport function registerUninstall(program: Command): void {\n program\n .command('uninstall')\n .description('Remove shell hooks and optionally delete all Workscribe data')\n .option('--hooks-only', 'remove shell hooks only, skip data deletion prompt (used by npm preuninstall)')\n .action(async (opts) => {\n log.plain(chalk.bold('\\n Workscribe — Uninstall\\n'))\n\n // 1. Remove shell hooks from any rc files that have them\n const hooked = detectShellRcFiles()\n if (hooked.length === 0) {\n log.info('No shell hooks found')\n } else {\n for (const { name, rcFile } of hooked) {\n removeHook(rcFile)\n log.success(`Shell hook removed from ${rcFile}`)\n log.plain(` ${chalk.dim(`Run: source ${rcFile}`)} (or restart your terminal to take effect)`)\n log.plain(\n ` ${chalk.dim(`${name === 'zsh' ? 'unfunction' : 'unset -f'} _workscribe_preexec _workscribe_precmd`)}`\n )\n }\n }\n\n if (opts.hooksOnly) return\n\n // 2. Optionally delete ~/.workscribe/ data\n if (fs.existsSync(WORKSCRIBE_DIR)) {\n log.plain('')\n const { deleteData } = await prompts({\n type: 'confirm',\n name: 'deleteData',\n message: `Delete all Workscribe data in ${WORKSCRIBE_DIR}? (database, config, exports)`,\n initial: false,\n })\n\n if (deleteData) {\n fs.rmSync(WORKSCRIBE_DIR, { recursive: true, force: true })\n log.success(`Deleted ${WORKSCRIBE_DIR}`)\n } else {\n log.info(`Data kept at ${WORKSCRIBE_DIR}`)\n }\n }\n\n log.plain('')\n log.plain(` ${chalk.dim('npm uninstall -g @workscribe/cli')} — remove the CLI itself`)\n log.plain('')\n })\n}\n"],"mappings":"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","names":["import_fs","path","os","fs","import_path","import_fs","fs","path","import_child_process","import_fs","import_path","path","fs","import_fs","import_os","import_path","import_fs","chalk","fs","path","os","fs","import_fs","fs","fs","program","program","import_fs","import_path","import_os","import_chalk","import_fs","import_path","fs","path","import_fs","import_path","import_os","import_child_process","path","os","fs","path","os","program","chalk","fs","prompts","import_fs","import_chalk","program","fs","chalk","import_chalk","chalk","program","import_chalk","program","chalk","import_chalk","import_fs","import_os","import_path","os","program","sessions","path","fs","chalk","fullSummary","import_fs","import_path","eventRowToPayload","program","path","fs","import_chalk","program","chalk","import_fs","program","fs","program","import_chalk","import_prompts","program","chalk","prompts","import_fs","import_path","import_os","import_prompts","import_chalk","path","os","fs","program","chalk","prompts"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/capture/index.ts","../src/db/index.ts","../src/utils/paths.ts","../src/db/migrations/001_initial_schema.ts","../src/db/migrations/index.ts","../src/capture/redact.ts","../src/capture/git.ts","../src/capture/git-snapshot.ts","../src/capture/aider.ts","../src/config/registry.ts","../src/config/ai-tools.json","../src/utils/logger.ts","../src/normalize/patterns.ts","../src/config/index.ts","../src/capture/filter.ts","../src/cli/capture.ts","../src/cli/hook.ts","../src/cli/init.ts","../src/capture/shell-hook.ts","../src/capture/hooks/claude-code.ts","../src/capture/hooks/utils.ts","../src/capture/hooks/index.ts","../src/cli/status.ts","../src/utils/format.ts","../src/cli/events.ts","../src/cli/sessions.ts","../src/sessions/grouper.ts","../src/sessions/detector.ts","../src/cli/summary.ts","../src/ai/prompt.ts","../src/ai/fetch.ts","../src/ai/providers/anthropic.ts","../src/ai/providers/openai.ts","../src/ai/providers/ollama.ts","../src/ai/router.ts","../src/integrations/webhook.ts","../src/integrations/slack.ts","../src/cli/export.ts","../src/cli/config.ts","../src/cli/pause.ts","../src/cli/undo.ts","../src/cli/clear.ts","../src/cli/uninstall.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { registerCapture } from './cli/capture'\nimport { registerHook } from './cli/hook'\n\ndeclare const __WORKSCRIBE_VERSION__: string\nimport { registerInit } from './cli/init'\nimport { registerStatus } from './cli/status'\nimport { registerEvents } from './cli/events'\nimport { registerSessions } from './cli/sessions'\nimport { registerSummary } from './cli/summary'\nimport { registerExport } from './cli/export'\nimport { registerConfig } from './cli/config'\nimport { registerPause } from './cli/pause'\nimport { registerUndo } from './cli/undo'\nimport { registerClear } from './cli/clear'\nimport { registerUninstall } from './cli/uninstall'\n\nconst program = new Command()\n\nprogram.name('workscribe').description('Automatic developer work journal').version(__WORKSCRIBE_VERSION__)\n\nregisterCapture(program)\nregisterHook(program)\nregisterInit(program)\nregisterStatus(program)\nregisterEvents(program)\nregisterSessions(program)\nregisterSummary(program)\nregisterExport(program)\nregisterConfig(program)\nregisterPause(program)\nregisterUndo(program)\nregisterClear(program)\nregisterUninstall(program)\n\nprogram.parse()\n","import fs from 'fs'\nimport { insertEvent, getLastEvent } from '../db'\nimport { redact } from './redact'\nimport { getGitContext } from './git'\nimport { getCommitsSince } from './git-snapshot'\nimport { readLastAiderPrompt } from './aider'\nimport { normalizeCommand } from '../normalize/patterns'\nimport { readConfig } from '../config'\nimport { shouldFilter, isDuplicate } from './filter'\nimport { PAUSE_FLAG_PATH } from '../utils/paths'\nimport { loadAIToolRegistry } from '../config/registry'\n\nexport function captureCommand(opts: {\n command: string\n cwd: string\n exitCode: number | null\n durationMs: number | null\n gitBefore?: string\n source?: string\n}): void {\n // Check pause flag before any I/O\n if (fs.existsSync(PAUSE_FLAG_PATH)) return\n\n const config = readConfig()\n const { command, cwd, exitCode, durationMs } = opts\n\n // 1. Filter noise commands\n if (shouldFilter(command, config.capture.ignore)) return\n\n // 2. Deduplicate: same command + same cwd within 5 seconds\n const last = getLastEvent()\n if (isDuplicate(command, cwd, last ?? undefined)) return\n\n // 3. Redact sensitive patterns\n const safeCommand = redact(command, config.redact.extra)\n\n // 4. Extract git context (with optional per-project name override)\n const nameOverride = config.projects?.[cwd] ?? null\n const { repoName, branch } = getGitContext(cwd, nameOverride)\n\n // 5. Normalize to typed event\n const { category, metadata } = normalizeCommand(safeCommand)\n\n if (category === 'ai_session' && config.capture.aiTools === false) return\n\n // Hint passthrough: preserve context for unrecognised commands so the AI can describe them\n if (category === 'other') {\n const firstToken = safeCommand.trim().split(/\\s+/)[0]\n if (firstToken) metadata.tool = firstToken\n metadata.hint = safeCommand.trim().slice(0, 120)\n }\n\n if (opts.source) metadata.source = opts.source\n\n // 6. For ai_session events, enrich metadata\n if (category === 'ai_session') {\n // 6a. Commits made during the session\n if (opts.gitBefore) {\n const commits = getCommitsSince(opts.gitBefore, cwd)\n if (commits.length > 0) metadata.commits = commits\n }\n\n // 6b. Last user prompt from history file (e.g. Aider)\n if (config.capture.includeAiderPrompt !== false) {\n const toolEntry = loadAIToolRegistry().find((entry) => entry.tool === metadata.tool)\n if (toolEntry?.contextSource === 'history-file') {\n const prompt = readLastAiderPrompt(cwd)\n if (prompt) metadata.prompt = prompt\n }\n }\n }\n\n // 7. Persist\n insertEvent({\n captured_at: new Date().toISOString(),\n command: safeCommand,\n cwd,\n exit_code: exitCode,\n duration_ms: durationMs,\n repo_name: repoName,\n branch,\n category,\n metadata: Object.keys(metadata).length > 0 ? JSON.stringify(metadata) : null,\n })\n}\n","import { DatabaseSync } from 'node:sqlite'\nimport fs from 'fs'\nimport { WORKSCRIBE_DIR, DB_PATH } from '../utils/paths'\nimport type { EventRow, SessionRow } from './types'\nimport { MIGRATIONS } from './migrations'\nexport type { EventRow, SessionRow } from './types'\n\nlet _db: DatabaseSync | null = null\n\nexport function getDb(): DatabaseSync {\n if (_db) return _db\n\n // Ensure ~/.workscribe/ exists\n if (!fs.existsSync(WORKSCRIBE_DIR)) {\n fs.mkdirSync(WORKSCRIBE_DIR, { recursive: true })\n }\n\n // Don't assign to _db until after migrations succeed — if applyMigrations\n // throws, _db stays null so the next call retries cleanly instead of\n // returning a partially-initialised singleton.\n const db = new DatabaseSync(DB_PATH)\n try {\n fs.chmodSync(DB_PATH, 0o600)\n } catch {\n /* ignore if already correct */\n }\n db.exec('PRAGMA journal_mode = WAL')\n db.exec('PRAGMA foreign_keys = ON')\n applyMigrations(db)\n _db = db\n return _db\n}\n\nfunction applyMigrations(db: DatabaseSync): void {\n // Create the migration tracking table if this is the first run\n db.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n\n // Bootstrap: if the events table already exists but schema_migrations is\n // empty, this is an existing install that predates the migration system.\n // Seed version 1 as applied so we don't re-run the initial schema.\n const hasEvents = db.prepare(\"SELECT name FROM sqlite_master WHERE type='table' AND name='events'\").get()\n const hasVersion1 = db.prepare('SELECT version FROM schema_migrations WHERE version = 1').get()\n\n if (hasEvents && !hasVersion1) {\n db.prepare(\"INSERT INTO schema_migrations (version, applied_at) VALUES ($version, datetime('now'))\").run({\n version: 1,\n })\n }\n\n // Collect already-applied versions\n const applied = new Set(\n (db.prepare('SELECT version FROM schema_migrations').all() as { version: number }[]).map((row) => row.version)\n )\n\n // Apply each pending migration in order, wrapped in a transaction so a\n // partial failure leaves the DB cleanly at the previous version.\n for (const migration of MIGRATIONS) {\n if (applied.has(migration.version)) continue\n\n db.exec('BEGIN')\n try {\n db.exec(migration.sql)\n db.prepare(\"INSERT INTO schema_migrations (version, applied_at) VALUES ($version, datetime('now'))\").run({\n version: migration.version,\n })\n db.exec('COMMIT')\n } catch (err) {\n try {\n db.exec('ROLLBACK')\n } catch {\n /* already rolled back or connection lost */\n }\n throw new Error(`Migration ${migration.version} (${migration.description}) failed: ${(err as Error).message}`)\n }\n }\n}\n\n// ─── Typed query helpers ──────────────────────────────────────────────────────\n\nexport function insertEvent(params: {\n captured_at: string\n command: string\n cwd: string\n exit_code: number | null\n duration_ms: number | null\n repo_name: string | null\n branch: string | null\n category: string\n metadata: string | null\n}): void {\n const db = getDb()\n const stmt = db.prepare(`\n INSERT INTO events (captured_at, command, cwd, exit_code, duration_ms, repo_name, branch, category, metadata)\n VALUES ($captured_at, $command, $cwd, $exit_code, $duration_ms, $repo_name, $branch, $category, $metadata)\n `)\n stmt.run(params)\n}\n\nexport function getLastEvent(): EventRow | undefined {\n const db = getDb()\n const stmt = db.prepare('SELECT * FROM events ORDER BY id DESC LIMIT 1')\n return stmt.get() as EventRow | undefined\n}\n\nexport function getEventsForDate(date: string): EventRow[] {\n const db = getDb()\n const stmt = db.prepare(`\n SELECT * FROM events\n WHERE date(captured_at, 'localtime') = $date\n ORDER BY captured_at ASC\n `)\n return stmt.all({ date }) as unknown as EventRow[]\n}\n\nexport function getRecentEvents(limit = 20): EventRow[] {\n const db = getDb()\n const stmt = db.prepare('SELECT * FROM events ORDER BY captured_at DESC LIMIT $limit')\n return stmt.all({ limit }) as unknown as EventRow[]\n}\n\nexport function getEventCount(): number {\n const db = getDb()\n const stmt = db.prepare('SELECT COUNT(*) as count FROM events')\n const row = stmt.get() as { count: number }\n return row.count\n}\n\nexport function insertSession(params: {\n date: string\n started_at: string\n ended_at: string\n repo_name: string | null\n event_count: number\n summary: string | null\n}): number {\n const db = getDb()\n const stmt = db.prepare(`\n INSERT INTO sessions (date, started_at, ended_at, repo_name, event_count, summary)\n VALUES ($date, $started_at, $ended_at, $repo_name, $event_count, $summary)\n `)\n const result = stmt.run(params)\n return Number(result.lastInsertRowid)\n}\n\nexport function insertSessionEvent(sessionId: number, eventId: number): void {\n const db = getDb()\n const stmt = db.prepare(`\n INSERT OR IGNORE INTO session_events (session_id, event_id) VALUES ($session_id, $event_id)\n `)\n stmt.run({ session_id: sessionId, event_id: eventId })\n}\n\nexport function getEventsBySessionId(sessionId: number): EventRow[] {\n const db = getDb()\n const stmt = db.prepare(`\n SELECT e.* FROM events e\n INNER JOIN session_events se ON se.event_id = e.id\n WHERE se.session_id = $session_id\n ORDER BY e.captured_at ASC\n `)\n return stmt.all({ session_id: sessionId }) as unknown as EventRow[]\n}\n\nexport function getSessionsForDate(date: string): SessionRow[] {\n const db = getDb()\n const stmt = db.prepare('SELECT * FROM sessions WHERE date = $date ORDER BY started_at ASC')\n return stmt.all({ date }) as unknown as SessionRow[]\n}\n\nexport function updateSessionSummary(sessionId: number, summary: string): void {\n const db = getDb()\n const stmt = db.prepare('UPDATE sessions SET summary = $summary WHERE id = $id')\n stmt.run({ summary, id: sessionId })\n}\n\nexport function getLastEventIds(n: number): number[] {\n const db = getDb()\n const rows = db.prepare('SELECT id FROM events ORDER BY id DESC LIMIT $n').all({ n }) as { id: number }[]\n return rows.map((row) => row.id)\n}\n\nexport function getEventsByIds(ids: number[]): EventRow[] {\n if (ids.length === 0) return []\n const db = getDb()\n const placeholders = ids.map(() => '?').join(', ')\n return db\n .prepare(`SELECT * FROM events WHERE id IN (${placeholders}) ORDER BY id DESC`)\n .all(...ids) as unknown as EventRow[]\n}\n\nexport function deleteEventsByIds(ids: number[]): void {\n if (ids.length === 0) return\n const db = getDb()\n const placeholders = ids.map(() => '?').join(', ')\n\n const affectedDates = db\n .prepare(`SELECT DISTINCT date(captured_at, 'localtime') as date FROM events WHERE id IN (${placeholders})`)\n .all(...ids) as { date: string }[]\n\n db.prepare(`DELETE FROM events WHERE id IN (${placeholders})`).run(...ids)\n\n for (const { date } of affectedDates) {\n clearSessionsForDate(date)\n }\n}\n\nexport function deleteEventsForDate(date: string): number {\n const db = getDb()\n // Clear sessions (and session_events) before deleting events — FK constraint order\n clearSessionsForDate(date)\n const result = db.prepare(`DELETE FROM events WHERE date(captured_at, 'localtime') = $date`).run({ date }) as {\n changes: number\n }\n return result.changes\n}\n\nexport function clearSessionsForDate(date: string): void {\n const db = getDb()\n // Remove session_events first due to FK constraint\n db.prepare(\n `\n DELETE FROM session_events WHERE session_id IN (\n SELECT id FROM sessions WHERE date = $date\n )\n `\n ).run({ date })\n db.prepare('DELETE FROM sessions WHERE date = $date').run({ date })\n}\n","import path from 'path'\nimport os from 'os'\n\nexport const WORKSCRIBE_DIR = path.join(os.homedir(), '.workscribe')\nexport const DB_PATH = path.join(WORKSCRIBE_DIR, 'workscribe.db')\nexport const CONFIG_PATH = path.join(WORKSCRIBE_DIR, 'config.json')\nexport const DEBUG_LOG_PATH = path.join(WORKSCRIBE_DIR, 'debug.log')\nexport const EXPORTS_DIR = path.join(WORKSCRIBE_DIR, 'exports')\nexport const PAUSE_FLAG_PATH = path.join(WORKSCRIBE_DIR, 'paused')\nexport const WEEKLY_CACHE_DIR = path.join(WORKSCRIBE_DIR, 'weekly-cache')\n","export default {\n version: 1,\n description: 'initial schema',\n sql: `\n CREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n captured_at TEXT NOT NULL,\n command TEXT NOT NULL,\n cwd TEXT NOT NULL,\n exit_code INTEGER,\n duration_ms INTEGER,\n repo_name TEXT,\n branch TEXT,\n category TEXT NOT NULL DEFAULT 'other',\n metadata TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_events_captured_at ON events(captured_at);\n CREATE INDEX IF NOT EXISTS idx_events_repo_name ON events(repo_name);\n\n CREATE TABLE IF NOT EXISTS sessions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n date TEXT NOT NULL,\n started_at TEXT NOT NULL,\n ended_at TEXT NOT NULL,\n repo_name TEXT,\n event_count INTEGER NOT NULL DEFAULT 0,\n summary TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_sessions_date ON sessions(date);\n\n CREATE TABLE IF NOT EXISTS session_events (\n session_id INTEGER NOT NULL REFERENCES sessions(id),\n event_id INTEGER NOT NULL REFERENCES events(id),\n PRIMARY KEY (session_id, event_id)\n );\n `,\n}\n","import initialSchema from './001_initial_schema'\n\nexport interface Migration {\n version: number\n description: string\n sql: string\n}\n\n// Ordered list — append only. Never modify or remove an existing entry.\nexport const MIGRATIONS: Migration[] = [initialSchema]\n","// Patterns that match known sensitive values\nconst BUILTIN_PATTERNS: RegExp[] = [\n // AWS access keys\n /AKIA[0-9A-Z]{16}/g,\n // AWS secret access keys (40 char base64-ish after common env vars)\n /(?<=AWS_SECRET_ACCESS_KEY[=\\s]+)\\S+/gi,\n // GitHub tokens\n /ghp_[a-zA-Z0-9]{36}/g,\n /github_pat_[a-zA-Z0-9_]{82}/g,\n // GitLab tokens\n /glpat-[a-zA-Z0-9\\-]{20}/g,\n // Generic JWTs (three base64url segments)\n /eyJ[a-zA-Z0-9_-]+\\.eyJ[a-zA-Z0-9_-]+\\.[a-zA-Z0-9_-]+/g,\n // Slack tokens and incoming webhook URLs\n /xox[baprs]-[a-zA-Z0-9\\-]+/g,\n /https:\\/\\/hooks\\.slack\\.com\\/services\\/[A-Z0-9]+\\/[A-Z0-9]+\\/[a-zA-Z0-9]+/g,\n // Stripe keys\n /sk_(live|test)_[a-zA-Z0-9]{24,}/g,\n // Values after long-form secret flags (single-char flags like -t/-p/-k are too ambiguous)\n /(?<=--(password|passwd|secret|token|key|api[-_]?key|auth[-_]?token)\\s+)\\S+/gi,\n // export VAR=VALUE where VAR looks sensitive\n /(?<=export\\s+(?:[A-Z_]*(?:TOKEN|SECRET|KEY|PASSWORD|PASS|AUTH|CREDENTIAL)[A-Z_]*)=)\\S+/gi,\n]\n\nexport function redact(command: string, extraPatterns: string[] = []): string {\n let result = command\n\n const allPatterns = [...BUILTIN_PATTERNS]\n\n for (const pattern of extraPatterns) {\n try {\n allPatterns.push(new RegExp(pattern, 'g'))\n } catch {\n // Invalid regex — skip silently\n }\n }\n\n for (const pattern of allPatterns) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0\n result = result.replace(pattern, '[REDACTED]')\n }\n\n return result\n}\n","import { execSync } from 'child_process'\nimport path from 'path'\nimport fs from 'fs'\n\nexport interface GitContext {\n repoName: string | null\n branch: string | null\n}\n\nfunction nameFromRemote(root: string): string | null {\n try {\n const url = execSync('git remote get-url origin', {\n cwd: root,\n timeout: 2000,\n stdio: 'pipe',\n })\n .toString()\n .trim()\n const match = url.match(/\\/([^/]+?)(?:\\.git)?$/)\n return match ? match[1] : null\n } catch {\n return null\n }\n}\n\nfunction nameFromPackageJson(root: string): string | null {\n try {\n const raw = fs.readFileSync(path.join(root, 'package.json'), 'utf-8')\n const pkg = JSON.parse(raw) as { name?: string }\n if (!pkg.name) return null\n return pkg.name.replace(/^@[^/]+\\//, '')\n } catch {\n return null\n }\n}\n\nexport function getGitContext(cwd: string, nameOverride?: string | null): GitContext {\n try {\n const root = execSync('git rev-parse --show-toplevel', {\n cwd,\n timeout: 2000,\n stdio: 'pipe',\n })\n .toString()\n .trim()\n\n const repoName = nameOverride ?? nameFromRemote(root) ?? nameFromPackageJson(root) ?? path.basename(root)\n\n let branch: string | null = null\n try {\n branch =\n execSync('git branch --show-current', {\n cwd,\n timeout: 2000,\n stdio: 'pipe',\n })\n .toString()\n .trim() || null\n } catch {\n // Detached HEAD or not a git repo\n }\n\n return { repoName, branch }\n } catch {\n return { repoName: null, branch: null }\n }\n}\n","import { execSync } from 'child_process'\n\n/**\n * Returns commit subject lines for all commits made between `sha` and HEAD.\n * Returns an empty array if sha is empty, HEAD hasn't moved, or git fails.\n */\nexport function getCommitsSince(sha: string, cwd: string): string[] {\n if (!sha) return []\n try {\n const out = execSync(`git log ${sha}..HEAD --format=%s`, { cwd, timeout: 3000 }).toString().trim()\n return out ? out.split('\\n').filter(Boolean) : []\n } catch {\n return []\n }\n}\n","import fs from 'fs'\nimport path from 'path'\n\nconst HISTORY_FILE = '.aider.chat.history.md'\nconst PROMPT_MAX_LENGTH = 200\n\nexport function readLastAiderPrompt(cwd: string): string | null {\n try {\n const histPath = path.join(cwd, HISTORY_FILE)\n const content = fs.readFileSync(histPath, 'utf-8')\n const matches = [...content.matchAll(/^> (.+)$/gm)]\n if (!matches.length) return null\n return matches[matches.length - 1][1].trim().slice(0, PROMPT_MAX_LENGTH)\n } catch {\n return null\n }\n}\n","import fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport BUILTIN_TOOLS from './ai-tools.json'\nimport { debugLog } from '../utils/logger'\n\nexport interface AIToolEntry {\n tool: string\n displayName: string\n pattern: string\n hook: string | null\n contextSource: string | null\n}\n\nconst USER_REGISTRY_PATH = path.join(os.homedir(), '.workscribe', 'ai-tools.json')\n\nexport function loadAIToolRegistry(): AIToolEntry[] {\n let userEntries: AIToolEntry[] = []\n\n try {\n if (fs.existsSync(USER_REGISTRY_PATH)) {\n const raw = fs.readFileSync(USER_REGISTRY_PATH, 'utf-8')\n const parsed = JSON.parse(raw)\n if (Array.isArray(parsed)) {\n userEntries = parsed\n .filter((entry) => typeof entry.tool === 'string' && typeof entry.pattern === 'string')\n .map((entry) => ({\n tool: entry.tool as string,\n displayName: (entry.displayName as string | undefined) ?? (entry.tool as string),\n pattern: entry.pattern as string,\n hook: (entry.hook as string | null | undefined) ?? null,\n contextSource: (entry.contextSource as string | null | undefined) ?? null,\n }))\n }\n }\n } catch {\n debugLog('registry', 'Failed to load user AI tool registry — using built-ins only')\n }\n\n if (userEntries.length === 0) return BUILTIN_TOOLS as AIToolEntry[]\n\n const userToolSlugs = new Set(userEntries.map((entry) => entry.tool))\n const filteredBuiltins = (BUILTIN_TOOLS as AIToolEntry[]).filter((entry) => !userToolSlugs.has(entry.tool))\n return [...filteredBuiltins, ...userEntries]\n}\n","[\n {\n \"tool\": \"claude\",\n \"displayName\": \"Claude Code\",\n \"pattern\": \"^claude\\\\b\",\n \"hook\": \"claude-code\",\n \"contextSource\": \"hook\"\n },\n {\n \"tool\": \"aider\",\n \"displayName\": \"Aider\",\n \"pattern\": \"^aider\\\\b\",\n \"hook\": null,\n \"contextSource\": \"history-file\"\n },\n {\n \"tool\": \"gemini\",\n \"displayName\": \"Gemini\",\n \"pattern\": \"^gemini\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"gh copilot\",\n \"displayName\": \"GitHub Copilot\",\n \"pattern\": \"^gh\\\\s+copilot\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"cody\",\n \"displayName\": \"Cody\",\n \"pattern\": \"^cody\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"amazon-q\",\n \"displayName\": \"Amazon Q\",\n \"pattern\": \"^q\\\\s+(chat|dev)\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"continue\",\n \"displayName\": \"Continue\",\n \"pattern\": \"^continue\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n },\n {\n \"tool\": \"cursor\",\n \"displayName\": \"Cursor\",\n \"pattern\": \"^cursor\\\\b\",\n \"hook\": null,\n \"contextSource\": null\n }\n]\n","import chalk from 'chalk'\nimport fs from 'fs'\nimport { DEBUG_LOG_PATH } from './paths'\n\nconst isDebug = process.env.WORKSCRIBE_DEBUG === '1'\n\nexport const log = {\n info: (msg: string) => console.log(chalk.cyan('→'), msg),\n success: (msg: string) => console.log(chalk.green('✓'), msg),\n warn: (msg: string) => console.log(chalk.yellow('⚠'), msg),\n error: (msg: string) => console.error(chalk.red('✗'), msg),\n plain: (msg: string) => console.log(msg),\n}\n\nexport function debugLog(context: string, error: unknown): void {\n if (!isDebug) return\n const entry = `[${new Date().toISOString()}] [${context}] ${error instanceof Error ? error.stack : String(error)}\\n`\n try {\n fs.appendFileSync(DEBUG_LOG_PATH, entry, { mode: 0o600 })\n } catch {\n // If we can't write to the debug log, silently ignore\n }\n}\n","import { loadAIToolRegistry } from '../config/registry'\nimport { debugLog } from '../utils/logger'\n\nexport interface NormalizedEvent {\n category: string\n metadata: Record<string, unknown>\n}\n\ninterface Rule {\n // Returns metadata if command matches, null otherwise\n match(cmd: string): NormalizedEvent | null\n}\n\nfunction makeRule(\n pattern: RegExp,\n category: string,\n extract: (match: RegExpMatchArray, cmd: string) => Record<string, unknown> = () => ({})\n): Rule {\n return {\n match(cmd) {\n const m = cmd.match(pattern)\n if (!m) return null\n return { category, metadata: extract(m, cmd) }\n },\n }\n}\n\n// Extract package names from install commands like: npm install foo bar\nfunction extractPackages(cmd: string, afterKeyword: string): string[] {\n const idx = cmd.indexOf(afterKeyword)\n if (idx === -1) return []\n return cmd\n .slice(idx + afterKeyword.length)\n .trim()\n .split(/\\s+/)\n .filter((part) => part && !part.startsWith('-'))\n}\n\nexport const RULES: Rule[] = [\n // ─── Git operations ───────────────────────────────────────────────────────\n makeRule(/^git\\s+commit\\b/, 'code_commit', (_m, cmd) => {\n const msgMatch = cmd.match(/-m\\s+[\"']?([^\"']+)[\"']?/)\n return { message: msgMatch ? msgMatch[1].trim() : null }\n }),\n\n makeRule(/^git\\s+push\\b/, 'code_push', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { remote: parts[2] ?? 'origin', branch: parts[3] ?? null }\n }),\n\n makeRule(/^git\\s+(pull|fetch)\\b/, 'code_pull', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[1], remote: parts[2] ?? 'origin' }\n }),\n\n makeRule(/^git\\s+(checkout|switch)\\b/, 'branch_switch', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n const branch = parts.find((part) => !part.startsWith('-') && part !== 'git' && part !== parts[1])\n return { branch: branch ?? null }\n }),\n\n makeRule(/^git\\s+(merge|rebase)\\b/, 'code_merge', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[1], target: parts[2] ?? null }\n }),\n\n makeRule(/^git\\s+stash\\b/, 'code_stash', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[2] ?? 'push' }\n }),\n\n makeRule(/^git\\s+/, 'git_other', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { subcommand: parts[1] ?? null }\n }),\n\n // ─── Package managers — install ───────────────────────────────────────────\n makeRule(/^npm\\s+(install|i|add)\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'npm',\n packages: extractPackages(cmd, cmd.includes('install') ? 'install' : cmd.includes(' i ') ? ' i ' : 'add'),\n })),\n\n makeRule(/^(yarn|pnpm)\\s+(install|add)\\b/, 'dependency_install', (m, cmd) => ({\n tool: m[1],\n packages: extractPackages(cmd, 'add'),\n })),\n\n makeRule(/^bun\\s+(install|add)\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'bun',\n packages: extractPackages(cmd, 'add'),\n })),\n\n makeRule(/^pip\\s+(install)\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'pip',\n packages: extractPackages(cmd, 'install'),\n })),\n\n makeRule(/^cargo\\s+add\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'cargo',\n packages: extractPackages(cmd, 'add'),\n })),\n\n makeRule(/^(brew)\\s+install\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'brew',\n packages: extractPackages(cmd, 'install'),\n })),\n\n makeRule(/^go\\s+get\\b/, 'dependency_install', (_m, cmd) => ({\n tool: 'go',\n packages: extractPackages(cmd, 'get'),\n })),\n\n // ─── Package managers — remove ────────────────────────────────────────────\n makeRule(/^npm\\s+(uninstall|remove|rm)\\b/, 'dependency_remove', (_m, cmd) => ({\n tool: 'npm',\n packages: extractPackages(cmd, cmd.split(/\\s+/)[1]),\n })),\n\n makeRule(/^(yarn|pnpm)\\s+remove\\b/, 'dependency_remove', (m, cmd) => ({\n tool: m[1],\n packages: extractPackages(cmd, 'remove'),\n })),\n\n makeRule(/^bun\\s+remove\\b/, 'dependency_remove', (_m, cmd) => ({\n tool: 'bun',\n packages: extractPackages(cmd, 'remove'),\n })),\n\n makeRule(/^pip\\s+uninstall\\b/, 'dependency_remove', (_m, cmd) => ({\n tool: 'pip',\n packages: extractPackages(cmd, 'uninstall'),\n })),\n\n // ─── Tests ────────────────────────────────────────────────────────────────\n makeRule(/^npm\\s+(test|run\\s+test)\\b/, 'test_run', () => ({ tool: 'npm' })),\n makeRule(/^yarn\\s+test\\b/, 'test_run', () => ({ tool: 'yarn' })),\n makeRule(/^pnpm\\s+test\\b/, 'test_run', () => ({ tool: 'pnpm' })),\n makeRule(/^bun\\s+test\\b/, 'test_run', () => ({ tool: 'bun' })),\n makeRule(/^(jest|vitest)\\b/, 'test_run', (match) => ({ tool: match[1] })),\n makeRule(/^pytest\\b/, 'test_run', () => ({ tool: 'pytest' })),\n makeRule(/^go\\s+test\\b/, 'test_run', () => ({ tool: 'go' })),\n makeRule(/^cargo\\s+test\\b/, 'test_run', () => ({ tool: 'cargo' })),\n makeRule(/^rspec\\b/, 'test_run', () => ({ tool: 'rspec' })),\n makeRule(/^(php\\s+)?phpunit\\b/, 'test_run', () => ({ tool: 'phpunit' })),\n\n // ─── Build ────────────────────────────────────────────────────────────────\n makeRule(/^npm\\s+run\\s+build\\b/, 'build', () => ({ tool: 'npm' })),\n makeRule(/^(yarn|pnpm)\\s+build\\b/, 'build', (match) => ({ tool: match[1] })),\n makeRule(/^bun\\s+run\\s+build\\b/, 'build', () => ({ tool: 'bun' })),\n makeRule(/^(make|gmake)\\b/, 'build', (match) => ({ tool: match[1] })),\n makeRule(/^cargo\\s+build\\b/, 'build', () => ({ tool: 'cargo' })),\n makeRule(/^go\\s+build\\b/, 'build', () => ({ tool: 'go' })),\n makeRule(/^docker\\s+build\\b/, 'build', () => ({ tool: 'docker' })),\n makeRule(/^(mvn|gradle)\\b/, 'build', (match) => ({ tool: match[1] })),\n\n // ─── Dev server ───────────────────────────────────────────────────────────\n makeRule(/^npm\\s+run\\s+(dev|start|serve)\\b/, 'server_run', (_m, cmd) => ({\n tool: 'npm',\n script: cmd.split(/\\s+/)[2],\n })),\n makeRule(/^(yarn|pnpm)\\s+(dev|start)\\b/, 'server_run', (match) => ({ tool: match[1], script: match[2] })),\n makeRule(/^bun\\s+run\\s+(dev|start|serve)\\b/, 'server_run', (_m, cmd) => ({\n tool: 'bun',\n script: cmd.split(/\\s+/)[2],\n })),\n makeRule(/^python\\s+.*manage\\.py\\s+runserver\\b/, 'server_run', () => ({ tool: 'django' })),\n\n // ─── Infrastructure ───────────────────────────────────────────────────────\n makeRule(/^ssh\\b/, 'infrastructure', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: 'ssh', target: parts[parts.length - 1] }\n }),\n\n makeRule(/^kubectl\\b/, 'infrastructure', (_m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: 'kubectl', subcommand: parts[1] ?? null }\n }),\n\n makeRule(/^(helm|terraform|pulumi)\\b/, 'infrastructure', (m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: m[1], subcommand: parts[1] ?? null }\n }),\n\n makeRule(/^docker\\s+(run|compose|ps|stop|start|rm|exec)\\b/, 'infrastructure', (m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: 'docker', subcommand: parts[1] }\n }),\n\n makeRule(/^(aws|gcloud|az)\\b/, 'infrastructure', (m, cmd) => {\n const parts = cmd.split(/\\s+/)\n return { tool: m[1], subcommand: parts[1] ?? null }\n }),\n\n // ─── npx ─────────────────────────────────────────────────────────────────\n makeRule(/^npx\\s+(jest|vitest|mocha|ava|tap)\\b/, 'test_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n makeRule(/^npx\\s+tsc\\b/, 'build', () => ({ tool: 'tsc' })),\n makeRule(/^npx\\s+(eslint|tslint|biome)\\b/, 'lint_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n makeRule(/^npx\\s+(prettier|dprint)\\b/, 'lint_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n makeRule(/^npx\\s+\\S+/, 'script_run', (_m, cmd) => ({\n tool: cmd.split(/\\s+/)[1],\n })),\n\n // ─── Scripts ──────────────────────────────────────────────────────────────\n makeRule(/^(bash|sh|zsh|fish)\\s+\\S+/, 'script_run', (match) => ({ shell: match[1] })),\n makeRule(/^node\\s+\\S+\\.(?:js|mjs|cjs)\\b/, 'script_run', () => ({ runtime: 'node' })),\n makeRule(/^python3?\\s+\\S+\\.py\\b/, 'script_run', () => ({ runtime: 'python' })),\n\n // ─── Environment ──────────────────────────────────────────────────────────\n makeRule(/^export\\s+\\w+=/, 'environment', (_m, cmd) => {\n const varName = cmd.match(/^export\\s+(\\w+)=/)?.[1] ?? null\n return { variable: varName }\n }),\n makeRule(/^source\\s+/, 'environment', () => ({})),\n\n // ─── generic run scripts ──────────────────────────────────────────────────\n makeRule(/^npm\\s+run\\s+\\S+/, 'script_run', (_m, cmd) => ({\n tool: 'npm',\n script: cmd.split(/\\s+/)[2],\n })),\n\n makeRule(/^bun\\s+run\\s+\\S+/, 'script_run', (_m, cmd) => ({\n tool: 'bun',\n script: cmd.split(/\\s+/)[2],\n })),\n\n // ─── Code search ─────────────────────────────────────────────────────────\n makeRule(/^(grep|egrep|fgrep)\\b/, 'code_search', (match) => ({ tool: match[1] })),\n makeRule(/^(rg|ag|ack|ripgrep)\\b/, 'code_search', (match) => ({ tool: match[1] })),\n makeRule(/^find\\s/, 'code_search', () => ({ tool: 'find' })),\n\n // ─── Code read ────────────────────────────────────────────────────────────\n makeRule(/^(cat|bat|less|more)\\s+\\S+/, 'code_read', (match) => ({ tool: match[1] })),\n makeRule(/^(head|tail)\\b/, 'code_read', (match) => ({ tool: match[1] })),\n\n // ─── File operations ──────────────────────────────────────────────────────\n makeRule(/^(cp|rsync)\\b/, 'file_ops', (match) => ({ tool: match[1] })),\n makeRule(/^(mv)\\b/, 'file_ops', () => ({ tool: 'mv' })),\n makeRule(/^(rm|rmdir)\\b/, 'file_ops', (match) => ({ tool: match[1] })),\n makeRule(/^(mkdir|touch|ln)\\b/, 'file_ops', (match) => ({ tool: match[1] })),\n makeRule(/^(chmod|chown|chgrp)\\b/, 'file_ops', (match) => ({ tool: match[1] })),\n\n // ─── AI terminal tools (registry-driven) ─────────────────────────────────\n ...loadAIToolRegistry().flatMap((entry) => {\n try {\n return [makeRule(new RegExp(entry.pattern), 'ai_session', () => ({ tool: entry.tool }))]\n } catch {\n debugLog('registry', `Skipping tool \"${entry.tool}\" — invalid pattern: ${entry.pattern}`)\n return []\n }\n }),\n]\n\nexport function normalizeCommand(command: string): NormalizedEvent {\n let trimmed = command.trim().replace(/\\s+/g, ' ')\n\n // Strip `git -C <path>` prefix so rules match regardless of working directory flag\n trimmed = trimmed.replace(/^(git)\\s+-C\\s+\\S+\\s+/, '$1 ')\n\n for (const rule of RULES) {\n const result = rule.match(trimmed)\n if (result) return result\n }\n\n return { category: 'other', metadata: {} }\n}\n","import fs from 'fs'\nimport { CONFIG_PATH } from '../utils/paths'\n\nexport interface WorkscribeConfig {\n ai: {\n provider: string // 'anthropic' | 'openai' | 'ollama' | 'openai-compatible'\n apiKey: string\n model: string\n baseUrl: string\n }\n session: {\n idleTimeout: number // minutes\n }\n capture: {\n ignore: string[]\n aiTools: boolean\n includeAiderPrompt: boolean\n }\n redact: {\n extra: string[]\n }\n summary: {\n format: 'markdown' | 'json'\n }\n projects?: Record<string, string> // absolute path → display name override\n integrations?: {\n slackWebhook?: string\n webhook?: string\n }\n}\n\nconst DEFAULTS: WorkscribeConfig = {\n ai: {\n provider: '',\n apiKey: '',\n model: '',\n baseUrl: '',\n },\n session: {\n idleTimeout: 30,\n },\n capture: {\n ignore: ['cd', 'ls', 'll', 'la', 'ls -la', 'ls -l', 'ls -a', 'pwd', 'clear', 'exit', 'history', 'man'],\n aiTools: true,\n includeAiderPrompt: true,\n },\n redact: {\n extra: [],\n },\n summary: {\n format: 'markdown',\n },\n}\n\nexport function readConfig(): WorkscribeConfig {\n if (!fs.existsSync(CONFIG_PATH)) return { ...DEFAULTS }\n try {\n const raw = fs.readFileSync(CONFIG_PATH, 'utf-8')\n const parsed = JSON.parse(raw)\n return deepMerge(DEFAULTS, parsed)\n } catch {\n return { ...DEFAULTS }\n }\n}\n\nexport function writeConfig(config: WorkscribeConfig): void {\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { encoding: 'utf-8', mode: 0o600 })\n // Enforce permissions on existing files (mode only applies on creation above)\n try {\n fs.chmodSync(CONFIG_PATH, 0o600)\n } catch {\n /* ignore */\n }\n}\n\nexport function getConfigValue(config: WorkscribeConfig, key: string): unknown {\n const parts = key.split('.')\n let cur: unknown = config\n for (const part of parts) {\n if (cur == null || typeof cur !== 'object') return undefined\n cur = (cur as Record<string, unknown>)[part]\n }\n return cur\n}\n\nexport function setConfigValue(config: WorkscribeConfig, key: string, value: string): WorkscribeConfig {\n const parts = key.split('.')\n const result = JSON.parse(JSON.stringify(config)) as WorkscribeConfig\n let cur = result as unknown as Record<string, unknown>\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i]\n if (cur[part] == null || typeof cur[part] !== 'object') {\n cur[part] = {}\n }\n cur = cur[part] as Record<string, unknown>\n }\n const lastKey = parts[parts.length - 1]\n // Coerce value type\n if (value === 'true') cur[lastKey] = true\n else if (value === 'false') cur[lastKey] = false\n else if (!isNaN(Number(value))) cur[lastKey] = Number(value)\n else cur[lastKey] = value\n return result\n}\n\nfunction deepMerge<T extends object>(defaults: T, overrides: Partial<T>): T {\n const result = { ...defaults }\n for (const key of Object.keys(overrides) as (keyof T)[]) {\n const val = overrides[key]\n if (val !== null && typeof val === 'object' && !Array.isArray(val) && typeof defaults[key] === 'object') {\n result[key] = deepMerge(defaults[key] as object, val as object) as T[keyof T]\n } else if (val !== undefined) {\n result[key] = val as T[keyof T]\n }\n }\n return result\n}\n","import type { EventRow } from '../db/types'\n\nfunction normalizeForFilter(cmd: string): string {\n return cmd.trim().replace(/\\s+/g, ' ')\n}\n\n// Always filtered regardless of user config — internal tool noise\nconst BUILTIN_IGNORE = new Set(['workscribe'])\n\n/**\n * Returns true if the command should be dropped (noise / ignore list).\n */\nexport function shouldFilter(command: string, ignoreList: string[]): boolean {\n const normalized = normalizeForFilter(command)\n if (!normalized) return true\n\n const baseCmd = normalized.split(' ')[0]\n\n // Built-in filter: always excluded, not user-configurable\n if (BUILTIN_IGNORE.has(baseCmd)) return true\n\n // User-configurable ignore list\n const normalizedIgnore = ignoreList.map(normalizeForFilter)\n if (normalizedIgnore.includes(normalized)) return true\n if (normalizedIgnore.includes(baseCmd)) return true\n\n return false\n}\n\n/**\n * Returns true if this command is a duplicate of the last event\n * (same command + same cwd within the dedup window).\n */\nexport function isDuplicate(\n command: string,\n cwd: string,\n lastEvent: Pick<EventRow, 'command' | 'cwd' | 'captured_at'> | undefined,\n dedupWindowMs = 5000,\n now = Date.now()\n): boolean {\n if (!lastEvent) return false\n const lastTime = new Date(lastEvent.captured_at).getTime()\n return lastEvent.command === normalizeForFilter(command) && lastEvent.cwd === cwd && now - lastTime < dedupWindowMs\n}\n","import { Command } from 'commander'\nimport { captureCommand } from '../capture'\nimport { debugLog } from '../utils/logger'\n\nexport function registerCapture(program: Command): void {\n // Internal command — called by the shell hook, not by the user\n program\n .command('_capture')\n .description('Internal: capture a shell command event (called by shell hook)')\n .option('--cmd <command>', 'command that was executed')\n .option('--cwd <path>', 'working directory')\n .option('--exit <code>', 'exit code', parseInt)\n .option('--duration <ms>', 'duration in milliseconds', parseInt)\n .option('--git-before <sha>', 'git HEAD SHA before this command ran')\n .action((opts) => {\n // Never surface errors to the terminal — this runs silently in the background\n try {\n if (!opts.cmd || !opts.cwd) return\n captureCommand({\n command: opts.cmd,\n cwd: opts.cwd,\n exitCode: opts.exit ?? null,\n durationMs: opts.duration ?? null,\n gitBefore: opts.gitBefore ?? undefined,\n })\n } catch (err) {\n debugLog('_capture', err)\n }\n })\n}\n","import { Command } from 'commander'\nimport { captureCommand } from '../capture'\nimport { readConfig } from '../config'\nimport { debugLog } from '../utils/logger'\n\n/** Parses a Claude Code PostToolUse stdin payload. Returns null if required fields are missing. */\nexport function parseHookPayload(raw: string): { command: string; cwd: string } | null {\n if (!raw.trim()) return null\n const payload = JSON.parse(raw) as Record<string, unknown>\n const toolInput = payload.tool_input as Record<string, unknown> | undefined\n const command = typeof toolInput?.command === 'string' ? toolInput.command : null\n const cwd = typeof payload.cwd === 'string' ? payload.cwd : null\n if (!command || !cwd) return null\n return { command, cwd }\n}\n\nexport function registerHook(program: Command): void {\n // Internal command — called by AI tool hooks (e.g. Claude Code PostToolUse), not by the user\n program\n .command('_hook')\n .description('Internal: capture events from AI tool hooks (stdin JSON payload)')\n .option('--source <source>', 'hook source identifier (e.g. claude-code)')\n .action((opts: { source?: string }) => {\n let raw = ''\n process.stdin.setEncoding('utf-8')\n process.stdin.on('data', (chunk: string) => {\n raw += chunk\n })\n process.stdin.on('end', () => {\n try {\n if (readConfig().capture.aiTools === false) return\n const parsed = parseHookPayload(raw)\n if (!parsed) return\n captureCommand({\n command: parsed.command,\n cwd: parsed.cwd,\n exitCode: null,\n durationMs: null,\n source: opts.source,\n })\n } catch (err) {\n debugLog('_hook', err)\n }\n })\n })\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport prompts from 'prompts'\nimport chalk from 'chalk'\nimport { WORKSCRIBE_DIR, CONFIG_PATH } from '../utils/paths'\nimport { readConfig, writeConfig } from '../config'\nimport { getDb } from '../db'\nimport { log } from '../utils/logger'\nimport { loadAIToolRegistry } from '../config/registry'\nimport { isHookInstalled, isHookOutdated, installHook, updateHook } from '../capture/shell-hook'\nimport { AI_HOOK_INTEGRATIONS } from '../capture/hooks'\n\nfunction detectShell(): { name: string; rcFile: string } | null {\n const shell = process.env.SHELL ?? ''\n if (shell.includes('zsh')) return { name: 'zsh', rcFile: path.join(os.homedir(), '.zshrc') }\n if (shell.includes('bash')) return { name: 'bash', rcFile: path.join(os.homedir(), '.bashrc') }\n return null\n}\n\nexport function registerInit(program: Command): void {\n program\n .command('init')\n .description('Set up Workscribe and install or update shell hooks')\n .action(async () => {\n log.plain(chalk.bold('\\n Workscribe — Developer Work Journal\\n'))\n\n // 1. Create ~/.workscribe/ with owner-only permissions\n if (!fs.existsSync(WORKSCRIBE_DIR)) {\n fs.mkdirSync(WORKSCRIBE_DIR, { recursive: true, mode: 0o700 })\n log.success(`Created ${WORKSCRIBE_DIR}`)\n } else {\n try {\n fs.chmodSync(WORKSCRIBE_DIR, 0o700)\n } catch {\n /* ignore */\n }\n }\n\n // 2. Initialize database (runs migrations)\n getDb()\n log.success('Database initialized')\n\n // 3. Detect shell and install or update hook\n const shell = detectShell()\n if (!shell) {\n log.warn('Could not detect shell. Supported: zsh, bash')\n log.plain(`Manually add the hook from: ${chalk.cyan('shell/hook.zsh')} or ${chalk.cyan('shell/hook.bash')}`)\n } else {\n const hookFile = path.join(__dirname, '..', 'shell', `hook.${shell.name}`)\n if (!fs.existsSync(hookFile)) {\n log.warn(`Hook template not found at ${hookFile}`)\n } else {\n const hookContent = fs.readFileSync(hookFile, 'utf-8')\n if (!fs.existsSync(shell.rcFile)) fs.writeFileSync(shell.rcFile, '')\n\n if (!isHookInstalled(shell.rcFile)) {\n installHook(shell.rcFile, hookContent)\n log.success(`Shell hook installed in ${shell.rcFile}`)\n } else if (isHookOutdated(shell.rcFile, hookContent)) {\n const { update } = await prompts({\n type: 'confirm',\n name: 'update',\n message: `Shell hook in ${shell.rcFile} is outdated. Update?`,\n initial: true,\n })\n if (update) {\n updateHook(shell.rcFile, hookContent)\n log.success(`Shell hook updated in ${shell.rcFile}`)\n } else {\n log.info('Shell hook update skipped')\n }\n } else {\n log.info(`Shell hook up to date in ${shell.rcFile}`)\n }\n }\n }\n\n // 4. AI tool hook integrations (registry-driven — add new tools in src/capture/hooks/)\n const installedTools = loadAIToolRegistry().filter(\n (entry) => entry.hook !== null && AI_HOOK_INTEGRATIONS[entry.hook!]?.isInstalled()\n )\n\n if (installedTools.length === 0) {\n log.info('No AI coding tools detected — re-run workscribe init after installing one')\n } else {\n for (const tool of installedTools) {\n const integration = AI_HOOK_INTEGRATIONS[tool.hook!]!\n\n if (integration.isHookInstalled()) {\n log.info(`${integration.displayName} session hook already installed`)\n } else {\n const { install } = await prompts({\n type: 'confirm',\n name: 'install',\n message: `${integration.displayName} detected. Install session capture hook?`,\n initial: false,\n })\n if (install) {\n integration.install()\n log.success(`${integration.displayName} session hook installed`)\n } else {\n log.info(`${integration.displayName} hook skipped — re-run workscribe init to install later`)\n }\n }\n }\n }\n\n // 5. AI provider setup\n const config = readConfig()\n\n if (config.ai.provider) {\n log.info(`AI provider already configured: ${chalk.cyan(config.ai.provider)}`)\n } else {\n log.plain('')\n const { provider } = await prompts({\n type: 'select',\n name: 'provider',\n message: 'Which AI provider do you want to use?',\n choices: [\n { title: 'Anthropic (Claude) — requires API key', value: 'anthropic' },\n { title: 'OpenAI — requires API key', value: 'openai' },\n { title: 'Ollama (local) — free, runs on your machine', value: 'ollama' },\n { title: 'Other (OpenAI-compatible) — Groq, Together, Mistral…', value: 'openai-compatible' },\n { title: 'Skip — configure later', value: 'skip' },\n ],\n })\n\n if (provider && provider !== 'skip') {\n config.ai.provider = provider\n\n if (provider === 'ollama') {\n log.plain(`\\n ${chalk.dim('Make sure Ollama is running: ollama serve')}`)\n log.plain(\n ` ${chalk.dim('Default model: llama3 (change with: workscribe config set ai.model <model>)')}\\n`\n )\n } else {\n const { apiKey } = await prompts({\n type: 'password',\n name: 'apiKey',\n message: `Enter your ${provider === 'openai-compatible' ? '' : provider + ' '}API key:`,\n })\n if (apiKey) config.ai.apiKey = apiKey\n\n if (provider === 'openai-compatible') {\n const { baseUrl } = await prompts({\n type: 'text',\n name: 'baseUrl',\n message: 'Enter the base URL (e.g. https://api.groq.com/openai/v1):',\n })\n if (baseUrl) config.ai.baseUrl = baseUrl\n }\n }\n\n writeConfig(config)\n log.success(`AI provider set to ${chalk.cyan(provider)}`)\n } else if (provider === 'skip' || !provider) {\n log.info('Skipped — run later: workscribe config set ai.provider <provider>')\n }\n }\n\n // 6. Write config if not exists\n if (!fs.existsSync(CONFIG_PATH)) {\n writeConfig(config)\n log.success('Config file created')\n }\n\n log.plain('')\n log.plain(chalk.bold(' Setup complete!'))\n if (shell) {\n log.plain('')\n log.plain(` Activate capture now: ${chalk.cyan(`source ${shell.rcFile}`)}`)\n log.plain(` Or restart your terminal.`)\n }\n log.plain('')\n log.plain(` ${chalk.dim('workscribe summary')} — generate today\\'s work summary`)\n log.plain(` ${chalk.dim('workscribe status')} — check capture is working`)\n log.plain('')\n })\n}\n","import fs from 'fs'\nimport path from 'path'\nimport { log } from '../utils/logger'\n\nconst HOOK_START = '# workscribe:hook:start'\nconst HOOK_END = '# workscribe:hook:end'\nconst HOOK_PREAMBLE = '# Workscribe — developer work journal'\n\nexport function getInstalledHookBlock(rcFile: string): string | null {\n if (!fs.existsSync(rcFile)) return null\n const content = fs.readFileSync(rcFile, 'utf-8')\n const startIdx = content.indexOf(HOOK_START)\n const endIdx = content.indexOf(HOOK_END)\n if (startIdx === -1 || endIdx === -1) return null\n return content.slice(startIdx, endIdx + HOOK_END.length)\n}\n\nexport function isHookInstalled(rcFile: string): boolean {\n return getInstalledHookBlock(rcFile) !== null\n}\n\nexport function isHookOutdated(rcFile: string, hookContent: string): boolean {\n const installed = getInstalledHookBlock(rcFile)\n if (!installed) return false\n return installed.trim() !== hookContent.trim()\n}\n\nexport function installHook(rcFile: string, hookContent: string): void {\n const backup = `${rcFile}.workscribe-backup-${Date.now()}`\n fs.copyFileSync(rcFile, backup)\n log.info(`Backed up ${rcFile} → ${path.basename(backup)}`)\n fs.appendFileSync(rcFile, `\\n${hookContent}\\n`)\n}\n\nexport function updateHook(rcFile: string, hookContent: string): void {\n const backup = `${rcFile}.workscribe-backup-${Date.now()}`\n fs.copyFileSync(rcFile, backup)\n log.info(`Backed up ${rcFile} → ${path.basename(backup)}`)\n const content = fs.readFileSync(rcFile, 'utf-8')\n const startIdx = content.indexOf(HOOK_START)\n const endIdx = content.indexOf(HOOK_END) + HOOK_END.length\n fs.writeFileSync(rcFile, content.slice(0, startIdx) + hookContent + content.slice(endIdx))\n}\n\nexport function removeHook(rcFile: string): void {\n const backup = `${rcFile}.workscribe-backup-${Date.now()}`\n fs.copyFileSync(rcFile, backup)\n log.info(`Backed up ${rcFile} → ${path.basename(backup)}`)\n const content = fs.readFileSync(rcFile, 'utf-8')\n const startIdx = content.indexOf(HOOK_START)\n const endIdx = content.indexOf(HOOK_END) + HOOK_END.length\n // Also remove the preamble comment lines that installHook writes before HOOK_START\n const preambleIdx = content.lastIndexOf(HOOK_PREAMBLE, startIdx)\n const blockStart = preambleIdx !== -1 ? preambleIdx : startIdx\n const before = content.slice(0, blockStart).replace(/\\n+$/, '\\n')\n const after = content.slice(endIdx).replace(/^\\n/, '')\n fs.writeFileSync(rcFile, before + after)\n}\n","import fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport type { AIHookIntegration } from './types'\nimport { isCommandInstalled } from './utils'\n\nconst CLAUDE_SETTINGS_PATH = path.join(os.homedir(), '.claude', 'settings.json')\n\nfunction readSettings(): Record<string, unknown> {\n if (!fs.existsSync(CLAUDE_SETTINGS_PATH)) return {}\n try {\n return JSON.parse(fs.readFileSync(CLAUDE_SETTINGS_PATH, 'utf-8')) as Record<string, unknown>\n } catch {\n return {}\n }\n}\n\nexport const claudeCodeIntegration: AIHookIntegration = {\n displayName: 'Claude Code',\n\n isInstalled() {\n return isCommandInstalled('claude')\n },\n\n isHookInstalled() {\n const settings = readSettings()\n const postToolUse = ((settings.hooks as Record<string, unknown>)?.PostToolUse ?? []) as unknown[]\n return postToolUse.some((entry) => {\n const hooks = ((entry as Record<string, unknown>).hooks ?? []) as unknown[]\n return hooks.some((hookItem) => {\n const hook = hookItem as Record<string, unknown>\n return typeof hook.command === 'string' && hook.command.includes('workscribe _hook')\n })\n })\n },\n\n install() {\n const settings = readSettings()\n const existingHooks = (settings.hooks ?? {}) as Record<string, unknown>\n const existingPostToolUse = (existingHooks.PostToolUse ?? []) as unknown[]\n settings.hooks = {\n ...existingHooks,\n PostToolUse: [\n ...existingPostToolUse,\n {\n matcher: 'Bash',\n hooks: [{ type: 'command', command: 'workscribe _hook --source claude-code', async: true }],\n },\n ],\n }\n fs.mkdirSync(path.dirname(CLAUDE_SETTINGS_PATH), { recursive: true })\n fs.writeFileSync(CLAUDE_SETTINGS_PATH, JSON.stringify(settings, null, 2))\n },\n}\n","import { execSync } from 'child_process'\n\n/** Returns true if the given CLI command is available on PATH */\nexport function isCommandInstalled(cmd: string): boolean {\n try {\n execSync(`which ${cmd}`, { stdio: 'ignore' })\n return true\n } catch {\n return false\n }\n}\n","import type { AIHookIntegration } from './types'\nimport { claudeCodeIntegration } from './claude-code'\n\n/**\n * Registry of AI tool hook integrations, keyed by the \"hook\" field in src/config/ai-tools.json.\n * Adding support for a new tool = add a new entry here and a corresponding integration file.\n */\nexport const AI_HOOK_INTEGRATIONS: Record<string, AIHookIntegration> = {\n 'claude-code': claudeCodeIntegration,\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport chalk from 'chalk'\nimport { getEventCount, getLastEvent } from '../db'\nimport { readConfig } from '../config'\nimport { log } from '../utils/logger'\nimport { formatDate, todayDate } from '../utils/format'\nimport { getEventsForDate } from '../db'\nimport { PAUSE_FLAG_PATH } from '../utils/paths'\n\nexport function registerStatus(program: Command): void {\n program\n .command('status')\n .description('Show capture status and event counts')\n .action(() => {\n const config = readConfig()\n const total = getEventCount()\n const todayEvents = getEventsForDate(todayDate())\n const last = getLastEvent()\n const isPaused = fs.existsSync(PAUSE_FLAG_PATH)\n\n log.plain('')\n log.plain(chalk.bold(' Workscribe Status'))\n log.plain('')\n\n if (isPaused) {\n log.plain(` Capture ${chalk.yellow('paused')} ${chalk.dim('(run: workscribe resume)')}`)\n } else {\n log.plain(` Capture ${chalk.green('active')}`)\n }\n\n log.plain(` Events today ${chalk.cyan(String(todayEvents.length))}`)\n log.plain(` Events total ${chalk.cyan(String(total))}`)\n\n if (last) {\n log.plain(` Last event ${formatDate(last.captured_at)} ${chalk.dim(last.command.slice(0, 60))}`)\n }\n\n log.plain('')\n log.plain(\n ` AI provider ${config.ai.provider ? chalk.cyan(config.ai.provider) : chalk.yellow('not configured')}`\n )\n if (config.ai.model) log.plain(` Model ${chalk.dim(config.ai.model)}`)\n log.plain('')\n })\n}\n","export function formatDuration(minutes: number): string {\n if (minutes < 60) return `${Math.round(minutes)}m`\n const h = Math.floor(minutes / 60)\n const m = Math.round(minutes % 60)\n return m > 0 ? `${h}h ${m}m` : `${h}h`\n}\n\nexport function formatDate(isoString: string): string {\n return new Date(isoString).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n}\n\nexport function todayDate(): string {\n return localDateStr(new Date())\n}\n\nexport function parseDate(input: string): string {\n // Accepts YYYY-MM-DD, returns YYYY-MM-DD. Throws on invalid.\n const d = new Date(input + 'T00:00:00')\n if (isNaN(d.getTime())) throw new Error(`Invalid date: ${input}`)\n return input\n}\n\nfunction localDateStr(d: Date): string {\n const y = d.getFullYear()\n const m = String(d.getMonth() + 1).padStart(2, '0')\n const day = String(d.getDate()).padStart(2, '0')\n return `${y}-${m}-${day}`\n}\n\n// Returns Monday of the ISO week containing dateStr (YYYY-MM-DD)\nexport function startOfWeek(dateStr: string): string {\n const d = new Date(dateStr + 'T00:00:00')\n const day = d.getDay() // 0=Sun\n const diff = day === 0 ? -6 : 1 - day\n d.setDate(d.getDate() + diff)\n return localDateStr(d)\n}\n\n// Returns all YYYY-MM-DD strings from start to end inclusive\nexport function eachDayOfRange(start: string, end: string): string[] {\n const days: string[] = []\n const cur = new Date(start + 'T00:00:00')\n const last = new Date(end + 'T00:00:00')\n while (cur <= last) {\n days.push(localDateStr(cur))\n cur.setDate(cur.getDate() + 1)\n }\n return days\n}\n\n// Returns ISO week string YYYY-WW for a date\nexport function isoWeekKey(dateStr: string): string {\n const d = new Date(dateStr + 'T00:00:00')\n const jan4 = new Date(d.getFullYear(), 0, 4)\n const weekNum = Math.ceil(((d.getTime() - jan4.getTime()) / 86400000 + jan4.getDay() + 1) / 7)\n return `${d.getFullYear()}-W${String(weekNum).padStart(2, '0')}`\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport { getEventsForDate } from '../db'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate, formatDate } from '../utils/format'\nimport { loadAIToolRegistry } from '../config/registry'\n\nconst CATEGORY_COLORS: Record<string, (s: string) => string> = {\n code_commit: chalk.green,\n code_push: chalk.green,\n code_pull: chalk.blue,\n branch_switch: chalk.blue,\n dependency_install: chalk.yellow,\n dependency_remove: chalk.yellow,\n test_run: chalk.magenta,\n build: chalk.cyan,\n server_run: chalk.cyan,\n infrastructure: chalk.red,\n script_run: chalk.white,\n environment: chalk.gray,\n git_other: chalk.blue,\n code_merge: chalk.green,\n code_stash: chalk.blue,\n ai_session: chalk.bold.magenta,\n lint_run: chalk.yellow,\n code_search: chalk.dim.cyan,\n code_read: chalk.dim.white,\n file_ops: chalk.yellow,\n other: chalk.gray,\n}\n\nconst AI_TOOL_DISPLAY_NAMES: Record<string, string> = Object.fromEntries(\n loadAIToolRegistry().map((entry) => [entry.tool, entry.displayName])\n)\n\nexport function registerEvents(program: Command): void {\n program\n .command('events')\n .description('List captured events')\n .option('--date <YYYY-MM-DD>', 'date to list events for (default: today)')\n .option('--limit <n>', 'max events to show', parseInt)\n .action((opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const events = getEventsForDate(date)\n const limit = opts.limit ?? events.length\n\n if (events.length === 0) {\n log.plain(`No events captured for ${date}`)\n return\n }\n\n log.plain('')\n log.plain(chalk.bold(` Events for ${date} (${events.length} total)`))\n log.plain('')\n\n for (const event of events.slice(0, limit)) {\n const colorFn = CATEGORY_COLORS[event.category] ?? chalk.gray\n const time = formatDate(event.captured_at)\n const category = colorFn(event.category.padEnd(20))\n const repo = event.repo_name ? chalk.dim(` [${event.repo_name}]`) : ''\n const exitBadge = event.exit_code && event.exit_code !== 0 ? chalk.red(` ✗${event.exit_code}`) : ''\n\n let cmdDisplay: string\n if (event.category === 'ai_session') {\n let meta: Record<string, unknown> = {}\n try {\n meta = event.metadata ? (JSON.parse(event.metadata) as Record<string, unknown>) : {}\n } catch {\n /* ignore */\n }\n const toolKey = typeof meta.tool === 'string' ? meta.tool : ''\n const toolName = AI_TOOL_DISPLAY_NAMES[toolKey] ?? toolKey\n cmdDisplay = chalk.white(toolName.padEnd(20)) + chalk.magenta(' ✦')\n } else {\n cmdDisplay = chalk.dim(event.command.slice(0, 55))\n }\n\n log.plain(` ${chalk.dim(time)} ${category} ${cmdDisplay}${repo}${exitBadge}`)\n }\n\n if (limit < events.length) {\n log.plain('')\n log.plain(chalk.dim(` … and ${events.length - limit} more (remove --limit to see all)`))\n }\n\n log.plain('')\n })\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport { getOrBuildSessions } from '../sessions/detector'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate, formatDate, formatDuration } from '../utils/format'\n\nexport function registerSessions(program: Command): void {\n program\n .command('sessions')\n .description('List detected work sessions')\n .option('--date <YYYY-MM-DD>', 'date to show sessions for (default: today)')\n .action((opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const sessions = getOrBuildSessions(date)\n\n if (sessions.length === 0) {\n log.plain(`No sessions detected for ${date}`)\n return\n }\n\n log.plain('')\n log.plain(chalk.bold(` Sessions for ${date} (${sessions.length} session${sessions.length > 1 ? 's' : ''})`))\n log.plain('')\n\n for (const session of sessions) {\n const start = formatDate(session.startedAt)\n const end = formatDate(session.endedAt)\n const duration = formatDuration(session.durationMinutes)\n const repo = session.repoName ? chalk.cyan(session.repoName) : chalk.gray('no repo')\n log.plain(\n ` ${chalk.dim(start)} – ${chalk.dim(end)} ${repo} ${chalk.dim(duration)} ${chalk.dim(session.eventCount + ' events')}`\n )\n }\n\n log.plain('')\n })\n}\n","import type { EventRow } from '../db/types'\n\n/**\n * Split a sorted list of events into groups separated by idle gaps.\n */\nexport function splitByIdleGap(events: EventRow[], idleMs: number): EventRow[][] {\n if (events.length === 0) return []\n const groups: EventRow[][] = [[events[0]]]\n\n for (let i = 1; i < events.length; i++) {\n const prev = new Date(events[i - 1].captured_at).getTime()\n const curr = new Date(events[i].captured_at).getTime()\n if (curr - prev >= idleMs) {\n groups.push([events[i]])\n } else {\n groups[groups.length - 1].push(events[i])\n }\n }\n\n return groups\n}\n\n/**\n * Split a list of events into groups by consecutive repo_name.\n * A repo change mid-stream creates a new group.\n */\nexport function splitByRepo(events: EventRow[]): EventRow[][] {\n if (events.length === 0) return []\n const groups: EventRow[][] = [[events[0]]]\n\n for (let i = 1; i < events.length; i++) {\n const prevRepo = events[i - 1].repo_name\n const currRepo = events[i].repo_name\n if (currRepo !== prevRepo) {\n groups.push([events[i]])\n } else {\n groups[groups.length - 1].push(events[i])\n }\n }\n\n return groups\n}\n\nexport function minutesBetween(start: string, end: string): number {\n return (new Date(end).getTime() - new Date(start).getTime()) / 60000\n}\n","import type { EventRow } from '../db/types'\nimport {\n insertSession,\n insertSessionEvent,\n clearSessionsForDate,\n getSessionsForDate,\n getEventsForDate,\n getEventsBySessionId,\n} from '../db'\nimport { readConfig } from '../config'\nimport { splitByIdleGap, splitByRepo, minutesBetween } from './grouper'\n\nexport interface Session {\n id: number\n date: string\n startedAt: string\n endedAt: string\n repoName: string | null\n durationMinutes: number\n eventCount: number\n summary: string | null\n events: EventRow[]\n}\n\nexport function getOrBuildSessions(date: string): Session[] {\n // Check if sessions already exist for this date\n const existing = getSessionsForDate(date)\n const events = getEventsForDate(date)\n\n if (events.length === 0) return []\n\n // If sessions exist and event count matches, use cached\n const cachedEventCount = existing.reduce((sum, sessionRow) => sum + sessionRow.event_count, 0)\n if (existing.length > 0 && cachedEventCount === events.length) {\n return existing.map((sessionRow) => ({\n id: sessionRow.id,\n date: sessionRow.date,\n startedAt: sessionRow.started_at,\n endedAt: sessionRow.ended_at,\n repoName: sessionRow.repo_name,\n durationMinutes: minutesBetween(sessionRow.started_at, sessionRow.ended_at),\n eventCount: sessionRow.event_count,\n summary: sessionRow.summary,\n events: getEventsBySessionId(sessionRow.id),\n }))\n }\n\n // Preserve any cached summaries before clearing — keyed by repo+start time\n // so they can be restored to matching sessions after rebuild\n const savedSummaries = new Map<string, string>()\n for (const s of existing) {\n if (s.summary) savedSummaries.set(`${s.repo_name}|${s.started_at}`, s.summary)\n }\n\n // Rebuild sessions\n clearSessionsForDate(date)\n return buildSessions(date, events, savedSummaries)\n}\n\nfunction buildSessions(date: string, events: EventRow[], savedSummaries: Map<string, string> = new Map()): Session[] {\n const config = readConfig()\n const idleMs = config.session.idleTimeout * 60 * 1000\n\n const sessions: Session[] = []\n const timeGroups = splitByIdleGap(events, idleMs)\n\n for (const group of timeGroups) {\n if (group.length === 0) continue\n\n const repoGroups = splitByRepo(group)\n\n for (const repoGroup of repoGroups) {\n if (repoGroup.length === 0) continue\n\n const first = repoGroup[0]\n const last = repoGroup[repoGroup.length - 1]\n const repoName = last.repo_name ?? first.repo_name ?? null\n\n // Restore a previously generated summary if the session boundaries match\n const summary = savedSummaries.get(`${repoName}|${first.captured_at}`) ?? null\n\n const sessionId = insertSession({\n date,\n started_at: first.captured_at,\n ended_at: last.captured_at,\n repo_name: repoName,\n event_count: repoGroup.length,\n summary,\n })\n\n for (const event of repoGroup) {\n insertSessionEvent(sessionId, event.id)\n }\n\n sessions.push({\n id: sessionId,\n date,\n startedAt: first.captured_at,\n endedAt: last.captured_at,\n repoName,\n durationMinutes: minutesBetween(first.captured_at, last.captured_at),\n eventCount: repoGroup.length,\n summary,\n events: repoGroup,\n })\n }\n }\n\n return sessions\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport fs from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport { getOrBuildSessions } from '../sessions/detector'\nimport { getProvider } from '../ai/router'\nimport { readConfig } from '../config'\nimport { updateSessionSummary } from '../db'\nimport { log } from '../utils/logger'\nimport {\n todayDate,\n parseDate,\n formatDate,\n formatDuration,\n startOfWeek,\n eachDayOfRange,\n isoWeekKey,\n} from '../utils/format'\nimport { postToWebhook } from '../integrations/webhook'\nimport { formatForSlack, isSlackWebhookUrl } from '../integrations/slack'\nimport { WEEKLY_CACHE_DIR } from '../utils/paths'\nimport type { DaySummaryPayload, SessionPayload, EventPayload, WeekSummaryPayload } from '../ai/types'\nimport type { EventRow } from '../db'\n\ninterface SessionSummaryJson {\n project: string | null\n branch: string | null\n durationMinutes: number\n bullets: string[]\n}\n\n/** Parse AI bullet output into a clean string array. Handles both - and • prefixes. */\nexport function parseBullets(text: string): string[] {\n return text\n .split('\\n')\n .map((line) => line.replace(/^[•\\-]\\s*/, '').trim())\n .filter(Boolean)\n}\n\nfunction eventRowToPayload(row: EventRow): EventPayload {\n let metadata: Record<string, unknown> = {}\n try {\n if (row.metadata) metadata = JSON.parse(row.metadata)\n } catch {\n /* ignore */\n }\n const payload: EventPayload = {\n category: row.category,\n metadata,\n exitCode: row.exit_code,\n durationMs: row.duration_ms,\n }\n if (row.category === 'other' && typeof metadata.hint === 'string') {\n payload.hint = metadata.hint\n const { hint: _h, tool: _t, ...rest } = metadata\n payload.metadata = rest\n }\n return payload\n}\n\nfunction sessionToPayload(s: ReturnType<typeof getOrBuildSessions>[number], date: string): SessionPayload {\n return {\n date,\n project: s.repoName,\n branch: s.events[0]?.branch ?? null,\n startTime: formatDate(s.startedAt),\n endTime: formatDate(s.endedAt),\n durationMinutes: s.durationMinutes,\n events: s.events.map(eventRowToPayload),\n }\n}\n\nasync function handleWebhook(\n opts: { slack?: boolean; webhook?: string },\n config: ReturnType<typeof readConfig>,\n summary: string\n): Promise<void> {\n const webhookUrl = opts.webhook ?? (opts.slack ? config.integrations?.slackWebhook : undefined)\n\n if (webhookUrl) {\n try {\n log.info('Posting to webhook…')\n const username = os.userInfo().username\n const body = isSlackWebhookUrl(webhookUrl) ? formatForSlack(summary, username) : summary\n await postToWebhook(webhookUrl, body)\n log.success('Posted.')\n } catch (e) {\n log.error(`Webhook failed: ${(e as Error).message}`)\n }\n } else if (opts.slack && !config.integrations?.slackWebhook) {\n log.warn('--slack requires integrations.slackWebhook to be set in config')\n }\n}\n\nexport function registerSummary(program: Command): void {\n program\n .command('summary')\n .description('Generate an AI work summary')\n .option('--date <YYYY-MM-DD>', 'date to summarize (default: today)')\n .option('--week', 'summarize the current week')\n .option('--fresh', 'bypass cache and regenerate')\n .option('--slack', 'post summary to Slack webhook from config')\n .option('--webhook <url>', 'post summary to a custom webhook URL')\n .action(async (opts) => {\n const config = readConfig()\n let provider\n try {\n provider = getProvider(config)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n\n // ── Weekly branch ────────────────────────────────────────────────────────\n if (opts.week) {\n const today = todayDate()\n const weekStart = startOfWeek(today)\n const days = eachDayOfRange(weekStart, today)\n\n const weeklyDays: WeekSummaryPayload['days'] = []\n for (const day of days) {\n const sessions = getOrBuildSessions(day)\n if (sessions.length > 0) {\n weeklyDays.push({ date: day, sessions: sessions.map((session) => sessionToPayload(session, day)) })\n }\n }\n\n if (weeklyDays.length === 0) {\n log.plain('No activity captured this week.')\n return\n }\n\n const cacheKey = isoWeekKey(today)\n const cacheFile = path.join(WEEKLY_CACHE_DIR, `${cacheKey}.md`)\n\n if (!opts.fresh && fs.existsSync(cacheFile)) {\n const cached = fs.readFileSync(cacheFile, 'utf-8')\n log.plain('')\n log.plain(cached)\n log.plain('')\n log.plain(chalk.dim(' (cached — use --fresh to regenerate)'))\n await handleWebhook(opts, config, cached)\n return\n }\n\n const payload: WeekSummaryPayload = { weekStart, weekEnd: today, days: weeklyDays }\n\n log.plain('')\n log.info(`Generating weekly summary via ${chalk.cyan(config.ai.provider)}…`)\n\n try {\n const summary = provider.summarizeWeek\n ? await provider.summarizeWeek(payload)\n : await provider.summarize({ date: today, sessions: weeklyDays.flatMap((day) => day.sessions) })\n\n log.plain('')\n log.plain(summary)\n log.plain('')\n\n fs.mkdirSync(WEEKLY_CACHE_DIR, { recursive: true })\n fs.writeFileSync(cacheFile, summary, { encoding: 'utf-8', mode: 0o600 })\n\n await handleWebhook(opts, config, summary)\n } catch (e) {\n log.error(`Weekly summary failed [${config.ai.provider}]: ${(e as Error).message}`)\n process.exit(1)\n }\n return\n }\n\n // ── Daily branch ─────────────────────────────────────────────────────────\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const sessions = getOrBuildSessions(date)\n\n if (sessions.length === 0) {\n log.plain(`No activity captured for ${date}`)\n return\n }\n\n const jsonMode = config.summary?.format === 'json'\n\n if (!opts.fresh) {\n const allCached = sessions.every((session) => session.summary)\n if (allCached) {\n const fullSummary = sessions.map((session) => session.summary!).join('\\n\\n')\n log.plain('')\n if (jsonMode) {\n const jsonOut: SessionSummaryJson[] = sessions.map((session) => ({\n project: session.repoName,\n branch: session.events[0]?.branch ?? null,\n durationMinutes: session.durationMinutes,\n bullets: parseBullets(session.summary!.replace(/^## .+\\n/, '')),\n }))\n log.plain(JSON.stringify({ date, sessions: jsonOut }, null, 2))\n } else {\n log.plain(fullSummary)\n }\n log.plain('')\n log.plain(chalk.dim(' (cached — use --fresh to regenerate)'))\n await handleWebhook(opts, config, fullSummary)\n return\n }\n }\n\n log.plain('')\n log.info(`Generating summary via ${chalk.cyan(config.ai.provider)}…`)\n\n const allSummaries: string[] = []\n const jsonSessions: SessionSummaryJson[] = []\n\n for (const session of sessions) {\n const sessionPayload: DaySummaryPayload = { date, sessions: [sessionToPayload(session, date)] }\n try {\n const bullets = await provider.summarize(sessionPayload)\n const project = session.repoName ?? 'unknown'\n const branch = session.events[0]?.branch ? ` (${session.events[0].branch})` : ''\n const duration = formatDuration(session.durationMinutes)\n const heading = `## ${project}${branch} — ${duration}`\n const summary = `${heading}\\n${bullets.trim()}`\n allSummaries.push(summary)\n updateSessionSummary(session.id, summary)\n if (jsonMode) {\n jsonSessions.push({\n project: session.repoName,\n branch: session.events[0]?.branch ?? null,\n durationMinutes: session.durationMinutes,\n bullets: parseBullets(bullets),\n })\n }\n } catch (e) {\n log.error(`Summary failed [${config.ai.provider}]: ${(e as Error).message}`)\n process.exit(1)\n }\n }\n\n const fullSummary = allSummaries.join('\\n\\n')\n log.plain('')\n if (jsonMode) {\n log.plain(JSON.stringify({ date, sessions: jsonSessions }, null, 2))\n } else {\n log.plain(fullSummary)\n }\n log.plain('')\n\n await handleWebhook(opts, config, fullSummary)\n })\n}\n","import type { DaySummaryPayload, WeekSummaryPayload } from './types'\nimport { formatDuration } from '../utils/format'\n\nexport const SYSTEM_PROMPT = `You write short developer work summaries. Here is an example:\n\nINPUT:\nProject: api-service\nBranch: feature/auth\nDuration: 2h 00m\nEvents:\n - branch_switch {\"branch\":\"feature/auth\"}\n - 2x dependency_install {\"tool\":\"npm\",\"packages\":[\"bcrypt\",\"jsonwebtoken\"]}\n - 2x test_run {\"tool\":\"jest\"} [failed]\n - test_run {\"tool\":\"jest\"}\n - 2x file_ops {\"tool\":\"mkdir\"}\n - code_commit {\"message\":\"fix: auth token validation\"}\n - code_push {\"remote\":\"origin\",\"branch\":\"feature/auth\"}\n\nOUTPUT:\n- Switched to the authentication feature branch and added authentication dependencies (bcrypt, JWT)\n- Resolved failing auth tests\n- Committed and pushed authentication fixes\n\nFor dependency_install events: infer the purpose of packages from their names and describe the domain, not just the packages. Examples: bcrypt/jsonwebtoken → authentication, prisma/mongoose/pg → database, jest/vitest/mocha → testing, axios/got/node-fetch → HTTP client, stripe/paypal → payments, socket.io/ws → real-time. Use your knowledge of common packages. For unfamiliar packages, name them directly without guessing their domain.\n\nEvents like code_push, build, file_ops, and code_stash provide context — fold them into the surrounding narrative rather than listing them as separate bullets. Only surface them directly when they are the main activity (e.g. a standalone build fix, or a significant restructure with no accompanying commits).\n\nFor ai_session events: describe what was built during the AI session using the tool name (e.g. \"via Claude Code\"). If a commits array is present in metadata, use those commit messages to describe what was built. Group all activity from the session into one narrative bullet.\n\nMaximum 5 bullets. Output ONLY the bullet points, nothing else.`\n\n// Categories excluded from the AI payload — investigative/shell noise that adds no signal to summaries\nconst EXCLUDED = new Set(['environment', 'code_search', 'code_read', 'server_run', 'git_other'])\n\nexport function buildUserMessage(payload: DaySummaryPayload): string {\n const lines: string[] = [`Date: ${payload.date}`, '']\n\n for (const session of payload.sessions) {\n lines.push(`Project: ${session.project ?? 'unknown'}`)\n if (session.branch) lines.push(`Branch: ${session.branch}`)\n lines.push(`Duration: ${formatDuration(session.durationMinutes)}`)\n lines.push('Events:')\n\n // Aggregate repeated events so the model sees \"3x build\" not 3 separate build lines\n const counts = new Map<string, number>()\n for (const event of session.events) {\n if (EXCLUDED.has(event.category)) continue\n const failed = event.exitCode !== null && event.exitCode !== 0 ? ' [failed]' : ''\n let key: string\n if (event.hint) {\n key = `other [${event.hint}]${failed}`\n } else {\n const meta = Object.keys(event.metadata).length > 0 ? ` ${JSON.stringify(event.metadata)}` : ''\n key = `${event.category}${meta}${failed}`\n }\n counts.set(key, (counts.get(key) ?? 0) + 1)\n }\n\n for (const [key, count] of counts) {\n lines.push(` - ${count > 1 ? `${count}x ` : ''}${key}`)\n }\n\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n\nexport const WEEKLY_SYSTEM_PROMPT = `You write short weekly developer summaries. Here is an example:\n\nINPUT:\nWeek: 2026-05-18 to 2026-05-22\n\nMonday 2026-05-18:\n Project: api-service (feature/auth) — 2h 10m\n Events: 3x code_commit, 2x test_run, dependency_install\n\nTuesday 2026-05-19:\n Project: api-service (feature/auth) — 1h 30m\n Events: 2x code_commit, test_run, build\n\nWednesday 2026-05-20:\n Project: dashboard (main) — 3h 00m\n Events: 4x code_commit, 2x build, test_run\n\nThursday 2026-05-21:\n Project: api-service (feature/auth) — 1h 00m\n Events: code_commit {\"message\":\"feat: merge auth\"}, branch_switch\n\nFriday 2026-05-22:\n Project: dashboard (main) — 2h 00m\n Events: 3x code_commit, build\n\nOUTPUT:\n## Week of 18 May — 9h 40m across 2 projects\n\n**api-service** (Mon–Thu): Built and shipped the auth feature — JWT setup, token validation fixes, and final merge.\n**dashboard** (Wed, Fri): Active development across 7 commits with builds passing.\n\nNow summarise the following week. Output ONLY the summary — a one-line header then one bullet per active project. Maximum 4 bullets.`\n\nconst DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']\n\nexport function buildWeeklyMessage(payload: WeekSummaryPayload): string {\n const lines: string[] = [`Week: ${payload.weekStart} to ${payload.weekEnd}`, '']\n\n for (const { date, sessions } of payload.days) {\n const dayName = DAY_NAMES[new Date(date + 'T00:00:00').getDay()]\n lines.push(`${dayName} ${date}:`)\n\n for (const s of sessions) {\n const project = s.project ?? 'unknown'\n const branch = s.branch ? ` (${s.branch})` : ''\n lines.push(` Project: ${project}${branch} — ${formatDuration(s.durationMinutes)}`)\n\n const counts = new Map<string, number>()\n for (const e of s.events) {\n if (EXCLUDED.has(e.category)) continue\n const failed = e.exitCode !== null && e.exitCode !== 0 ? ' [failed]' : ''\n let key: string\n if (e.hint) {\n key = `other [${e.hint}]${failed}`\n } else {\n const meta = Object.keys(e.metadata).length > 0 ? ` ${JSON.stringify(e.metadata)}` : ''\n key = `${e.category}${meta}${failed}`\n }\n counts.set(key, (counts.get(key) ?? 0) + 1)\n }\n const eventLine = [...counts.entries()].map(([k, n]) => `${n > 1 ? `${n}x ` : ''}${k}`).join(', ')\n lines.push(` Events: ${eventLine}`)\n }\n\n lines.push('')\n }\n\n return lines.join('\\n')\n}\n","const DEFAULT_TIMEOUT_MS = 30_000\n\nexport async function fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeoutMs = DEFAULT_TIMEOUT_MS\n): Promise<Response> {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n try {\n return await fetch(url, { ...init, signal: controller.signal })\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error(`Request timed out after ${timeoutMs / 1000}s`)\n }\n throw err\n } finally {\n clearTimeout(timer)\n }\n}\n","import type { AIProvider, DaySummaryPayload, WeekSummaryPayload } from '../types'\nimport { SYSTEM_PROMPT, buildUserMessage, WEEKLY_SYSTEM_PROMPT, buildWeeklyMessage } from '../prompt'\nimport { fetchWithTimeout } from '../fetch'\n\nexport class AnthropicProvider implements AIProvider {\n private apiKey: string\n private model: string\n\n constructor(apiKey: string, model?: string) {\n this.apiKey = apiKey\n this.model = model || 'claude-haiku-4-5-20251001'\n }\n\n async summarize(payload: DaySummaryPayload): Promise<string> {\n const response = await fetchWithTimeout('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: this.model,\n max_tokens: 1024,\n system: SYSTEM_PROMPT,\n messages: [{ role: 'user', content: buildUserMessage(payload) }],\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Anthropic API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as { content: Array<{ type: string; text: string }> }\n return data.content.find((block) => block.type === 'text')?.text ?? ''\n }\n\n async summarizeWeek(payload: WeekSummaryPayload): Promise<string> {\n const response = await fetchWithTimeout('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: this.model,\n max_tokens: 1024,\n system: WEEKLY_SYSTEM_PROMPT,\n messages: [{ role: 'user', content: buildWeeklyMessage(payload) }],\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Anthropic API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as { content: Array<{ type: string; text: string }> }\n return data.content.find((block) => block.type === 'text')?.text ?? ''\n }\n}\n","import type { AIProvider, DaySummaryPayload, WeekSummaryPayload } from '../types'\nimport { SYSTEM_PROMPT, buildUserMessage, WEEKLY_SYSTEM_PROMPT, buildWeeklyMessage } from '../prompt'\nimport { fetchWithTimeout } from '../fetch'\n\nexport class OpenAIProvider implements AIProvider {\n private apiKey: string\n private model: string\n private baseUrl: string\n\n constructor(apiKey: string, model?: string, baseUrl?: string) {\n this.apiKey = apiKey\n this.model = model || 'gpt-4o-mini'\n this.baseUrl = baseUrl || 'https://api.openai.com/v1'\n }\n\n async summarize(payload: DaySummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n model: this.model,\n messages: [\n { role: 'system', content: SYSTEM_PROMPT },\n { role: 'user', content: buildUserMessage(payload) },\n ],\n max_tokens: 1024,\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`OpenAI API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as {\n choices: Array<{ message: { content: string } }>\n }\n return data.choices[0]?.message?.content ?? ''\n }\n\n async summarizeWeek(payload: WeekSummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n model: this.model,\n messages: [\n { role: 'system', content: WEEKLY_SYSTEM_PROMPT },\n { role: 'user', content: buildWeeklyMessage(payload) },\n ],\n max_tokens: 1024,\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`OpenAI API error ${response.status}: ${body}`)\n }\n\n const data = (await response.json()) as {\n choices: Array<{ message: { content: string } }>\n }\n return data.choices[0]?.message?.content ?? ''\n }\n}\n","import type { AIProvider, DaySummaryPayload, WeekSummaryPayload } from '../types'\nimport { SYSTEM_PROMPT, buildUserMessage, WEEKLY_SYSTEM_PROMPT, buildWeeklyMessage } from '../prompt'\nimport { fetchWithTimeout } from '../fetch'\n\nexport class OllamaProvider implements AIProvider {\n private model: string\n private baseUrl: string\n\n constructor(model?: string, baseUrl?: string) {\n this.model = model || 'llama3'\n this.baseUrl = baseUrl || 'http://localhost:11434'\n }\n\n async summarize(payload: DaySummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/api/chat`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n stream: false,\n messages: [\n { role: 'system', content: SYSTEM_PROMPT },\n { role: 'user', content: buildUserMessage(payload) },\n ],\n options: {\n num_predict: 300, // hard cap on output tokens — forces conciseness\n temperature: 0.3, // lower temperature = more focused, less wandering\n },\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Ollama error ${response.status}: ${body}. Is Ollama running? Try: ollama serve`)\n }\n\n const data = (await response.json()) as { message: { content: string } }\n return data.message?.content ?? ''\n }\n\n async summarizeWeek(payload: WeekSummaryPayload): Promise<string> {\n const response = await fetchWithTimeout(`${this.baseUrl}/api/chat`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model: this.model,\n stream: false,\n messages: [\n { role: 'system', content: WEEKLY_SYSTEM_PROMPT },\n { role: 'user', content: buildWeeklyMessage(payload) },\n ],\n options: {\n num_predict: 400,\n temperature: 0.3,\n },\n }),\n })\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Ollama error ${response.status}: ${body}. Is Ollama running? Try: ollama serve`)\n }\n\n const data = (await response.json()) as { message: { content: string } }\n return data.message?.content ?? ''\n }\n}\n","import type { AIProvider } from './types'\nimport type { WorkscribeConfig } from '../config'\nimport { AnthropicProvider } from './providers/anthropic'\nimport { OpenAIProvider } from './providers/openai'\nimport { OllamaProvider } from './providers/ollama'\n\nexport function getProvider(config: WorkscribeConfig): AIProvider {\n const { provider, apiKey, model, baseUrl } = config.ai\n\n if (!provider) {\n throw new Error(\n 'No AI provider configured.\\nRun: workscribe config set ai.provider <anthropic|openai|ollama|openai-compatible>'\n )\n }\n\n switch (provider) {\n case 'anthropic': {\n if (!apiKey) throw new Error('Anthropic requires an API key.\\nRun: workscribe config set ai.apiKey <your-key>')\n return new AnthropicProvider(apiKey, model || undefined)\n }\n\n case 'openai': {\n if (!apiKey) throw new Error('OpenAI requires an API key.\\nRun: workscribe config set ai.apiKey <your-key>')\n return new OpenAIProvider(apiKey, model || undefined)\n }\n\n case 'openai-compatible': {\n if (!apiKey)\n throw new Error('This provider requires an API key.\\nRun: workscribe config set ai.apiKey <your-key>')\n if (!baseUrl)\n throw new Error('openai-compatible requires a base URL.\\nRun: workscribe config set ai.baseUrl <url>')\n return new OpenAIProvider(apiKey, model || undefined, baseUrl)\n }\n\n case 'ollama': {\n return new OllamaProvider(model || undefined, baseUrl || undefined)\n }\n\n default:\n throw new Error(\n `Unknown provider: \"${provider}\"\\nSupported providers: anthropic, openai, ollama, openai-compatible`\n )\n }\n}\n","import { fetchWithTimeout } from '../ai/fetch'\n\nexport async function postToWebhook(url: string, text: string): Promise<void> {\n const response = await fetchWithTimeout(\n url,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ text }),\n },\n 10_000\n )\n\n if (!response.ok) {\n const body = await response.text()\n throw new Error(`Webhook POST failed ${response.status}: ${body}`)\n }\n}\n","/**\n * Converts workscribe markdown summary output to Slack mrkdwn format.\n *\n * Rules:\n * ## heading → *heading* (bold)\n * - bullet → • bullet\n *\n * An optional username is prepended as a dim header line so recipients\n * can tell who sent the summary in shared channels.\n */\nexport function formatForSlack(markdown: string, username?: string): string {\n const body = markdown.replace(/^## (.+)$/gm, '*$1*').replace(/^- /gm, '• ')\n return username ? `_${username}_\\n${body}` : body\n}\n\nexport function isSlackWebhookUrl(url: string): boolean {\n return url.startsWith('https://hooks.slack.com/')\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport path from 'path'\nimport { getOrBuildSessions } from '../sessions/detector'\nimport { getProvider } from '../ai/router'\nimport { readConfig } from '../config'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate, formatDate } from '../utils/format'\nimport { EXPORTS_DIR } from '../utils/paths'\nimport type { DaySummaryPayload, SessionPayload, EventPayload } from '../ai/types'\nimport type { EventRow } from '../db'\n\nfunction eventRowToPayload(row: EventRow): EventPayload {\n let metadata: Record<string, unknown> = {}\n try {\n if (row.metadata) metadata = JSON.parse(row.metadata)\n } catch {\n /* ignore */\n }\n const payload: EventPayload = {\n category: row.category,\n metadata,\n exitCode: row.exit_code,\n durationMs: row.duration_ms,\n }\n if (row.category === 'other' && typeof metadata.hint === 'string') {\n payload.hint = metadata.hint\n const { hint: _h, tool: _t, ...rest } = metadata\n payload.metadata = rest\n }\n return payload\n}\n\nexport function registerExport(program: Command): void {\n program\n .command('export')\n .description('Export work summary as a markdown file')\n .option('--date <YYYY-MM-DD>', 'date to export (default: today)')\n .option('--output <path>', 'output file path (default: ~/.workscribe/exports/)')\n .action(async (opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const sessions = getOrBuildSessions(date)\n if (sessions.length === 0) {\n log.plain(`No activity captured for ${date}`)\n return\n }\n\n const config = readConfig()\n let provider\n try {\n provider = getProvider(config)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n\n const sessionPayloads: SessionPayload[] = sessions.map((session) => ({\n date,\n project: session.repoName,\n branch: session.events[0]?.branch ?? null,\n startTime: formatDate(session.startedAt),\n endTime: formatDate(session.endedAt),\n durationMinutes: session.durationMinutes,\n events: session.events.map(eventRowToPayload),\n }))\n\n const payload: DaySummaryPayload = { date, sessions: sessionPayloads }\n\n log.info(`Generating summary via ${config.ai.provider}…`)\n const summary = await provider.summarize(payload)\n\n const outputPath = opts.output ?? path.join(EXPORTS_DIR, `workscribe-${date}.md`)\n\n if (!fs.existsSync(EXPORTS_DIR)) fs.mkdirSync(EXPORTS_DIR, { recursive: true, mode: 0o700 })\n\n fs.writeFileSync(outputPath, `# Work Summary — ${date}\\n\\n${summary}\\n`, { encoding: 'utf-8', mode: 0o600 })\n log.success(`Saved: ${outputPath}`)\n })\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport { readConfig, writeConfig, getConfigValue, setConfigValue } from '../config'\nimport { log } from '../utils/logger'\n\nexport function registerConfig(program: Command): void {\n const configCmd = program\n .command('config')\n .description('View or update Workscribe configuration')\n .action(() => {\n const config = readConfig()\n log.plain('')\n log.plain(chalk.bold(' Workscribe Config'))\n log.plain('')\n printConfig(config, ' ')\n log.plain('')\n })\n\n configCmd\n .command('set <key> <value>')\n .description('Set a config value (e.g. workscribe config set ai.provider anthropic)')\n .action((key: string, value: string) => {\n const config = readConfig()\n const updated = setConfigValue(config, key, value)\n writeConfig(updated)\n const isSensitive =\n key === 'ai.apiKey' ||\n key.toLowerCase().includes('key') ||\n key.toLowerCase().includes('secret') ||\n key.toLowerCase().includes('token')\n const displayValue = isSensitive ? '[set]' : chalk.yellow(value)\n log.success(`Set ${chalk.cyan(key)} = ${displayValue}`)\n })\n\n configCmd\n .command('get <key>')\n .description('Get a config value')\n .action((key: string) => {\n const config = readConfig()\n const value = getConfigValue(config, key)\n if (value === undefined) {\n log.warn(`Key not found: ${key}`)\n } else {\n const lastSegment = key.split('.').pop() ?? ''\n if (SENSITIVE_KEYS.has(lastSegment) && typeof value === 'string' && value.length > 0) {\n log.plain(`${value.slice(0, 4)}${'*'.repeat(8)} (${value.length} chars)`)\n } else {\n log.plain(String(value))\n }\n }\n })\n}\n\nconst SENSITIVE_KEYS = new Set([\n 'apiKey',\n 'api_key',\n 'secret',\n 'token',\n 'password',\n 'passwd',\n 'webhook',\n 'slackWebhook',\n])\n\nfunction maskValue(key: string, value: unknown): string {\n if (SENSITIVE_KEYS.has(key) && typeof value === 'string' && value.length > 0) {\n return chalk.dim(`${value.slice(0, 4)}${'*'.repeat(8)} (${value.length} chars)`)\n }\n if (Array.isArray(value)) return `[${(value as unknown[]).join(', ')}]`\n return String(value) || chalk.dim('(not set)')\n}\n\nfunction printConfig(obj: unknown, indent: string): void {\n if (typeof obj !== 'object' || obj === null) return\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n log.plain(`${indent}${chalk.bold(key)}:`)\n printConfig(value, indent + ' ')\n } else {\n log.plain(`${indent}${chalk.dim(key)}: ${chalk.yellow(maskValue(key, value))}`)\n }\n }\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport { PAUSE_FLAG_PATH } from '../utils/paths'\nimport { log } from '../utils/logger'\n\nexport function registerPause(program: Command): void {\n program\n .command('pause')\n .description('Pause capture temporarily')\n .action(() => {\n if (fs.existsSync(PAUSE_FLAG_PATH)) {\n log.info('Capture is already paused. Run workscribe resume to restart.')\n return\n }\n fs.writeFileSync(PAUSE_FLAG_PATH, '', { mode: 0o600 })\n log.success('Capture paused. Run workscribe resume to restart.')\n })\n\n program\n .command('resume')\n .description('Resume capture after a pause')\n .action(() => {\n if (!fs.existsSync(PAUSE_FLAG_PATH)) {\n log.info('Capture is not paused.')\n return\n }\n fs.rmSync(PAUSE_FLAG_PATH)\n log.success('Capture resumed.')\n })\n}\n","import { Command } from 'commander'\nimport { getLastEventIds, getEventsByIds, deleteEventsByIds } from '../db'\nimport { log } from '../utils/logger'\n\nexport function registerUndo(program: Command): void {\n program\n .command('undo')\n .description('Remove the last N captured events')\n .option('-n, --count <number>', 'number of events to remove', '1')\n .option('--dry-run', 'preview what would be deleted without deleting')\n .action((opts) => {\n const count = parseInt(opts.count, 10)\n if (isNaN(count) || count < 1) {\n log.error('--count must be a positive integer')\n process.exit(1)\n }\n\n const ids = getLastEventIds(count)\n if (ids.length === 0) {\n log.plain('No events to undo.')\n return\n }\n\n const events = getEventsByIds(ids)\n log.plain('')\n log.plain(`Events to remove (${events.length}):`)\n for (const e of events) {\n log.plain(` ${e.captured_at} ${e.category} ${e.command}`)\n }\n log.plain('')\n\n if (opts.dryRun) {\n log.plain('Dry run — nothing deleted.')\n return\n }\n\n deleteEventsByIds(ids)\n log.success(`Removed ${ids.length} event${ids.length > 1 ? 's' : ''}.`)\n })\n}\n","import { Command } from 'commander'\nimport chalk from 'chalk'\nimport prompts from 'prompts'\nimport { getEventsForDate, deleteEventsForDate } from '../db'\nimport { log } from '../utils/logger'\nimport { todayDate, parseDate } from '../utils/format'\n\nexport function registerClear(program: Command): void {\n program\n .command('clear')\n .description('Delete all captured events for a date')\n .option('--date <YYYY-MM-DD>', 'date to clear (default: today)')\n .option('--dry-run', 'preview what would be deleted without deleting')\n .option('--yes', 'skip confirmation prompt')\n .action(async (opts) => {\n let date = todayDate()\n if (opts.date) {\n try {\n date = parseDate(opts.date)\n } catch (e) {\n log.error((e as Error).message)\n process.exit(1)\n }\n }\n\n const events = getEventsForDate(date)\n\n if (events.length === 0) {\n log.plain(`No events found for ${date}.`)\n return\n }\n\n log.plain('')\n log.plain(chalk.bold(` Events for ${date} (${events.length} total)`))\n log.plain('')\n\n // Show a compact summary by category\n const counts = new Map<string, number>()\n for (const e of events) counts.set(e.category, (counts.get(e.category) ?? 0) + 1)\n for (const [cat, n] of counts) {\n log.plain(` ${chalk.dim(String(n).padStart(4))} ${cat}`)\n }\n log.plain('')\n\n if (opts.dryRun) {\n log.plain(chalk.dim(' Dry run — nothing deleted.'))\n log.plain('')\n return\n }\n\n if (!opts.yes) {\n const { confirm } = await prompts({\n type: 'confirm',\n name: 'confirm',\n message: `Delete all ${events.length} events for ${date}?`,\n initial: false,\n })\n if (!confirm) {\n log.plain('Cancelled.')\n return\n }\n }\n\n const deleted = deleteEventsForDate(date)\n log.success(`Cleared ${deleted} event${deleted !== 1 ? 's' : ''} for ${date}.`)\n })\n}\n","import { Command } from 'commander'\nimport fs from 'fs'\nimport path from 'path'\nimport os from 'os'\nimport prompts from 'prompts'\nimport chalk from 'chalk'\nimport { WORKSCRIBE_DIR } from '../utils/paths'\nimport { isHookInstalled, removeHook } from '../capture/shell-hook'\nimport { log } from '../utils/logger'\n\nfunction detectShellRcFiles(): { name: string; rcFile: string }[] {\n const candidates = [\n { name: 'zsh', rcFile: path.join(os.homedir(), '.zshrc') },\n { name: 'bash', rcFile: path.join(os.homedir(), '.bashrc') },\n { name: 'bash', rcFile: path.join(os.homedir(), '.bash_profile') },\n ]\n return candidates.filter((candidate) => fs.existsSync(candidate.rcFile) && isHookInstalled(candidate.rcFile))\n}\n\nexport function registerUninstall(program: Command): void {\n program\n .command('uninstall')\n .description('Remove shell hooks and optionally delete all Workscribe data')\n .option('--hooks-only', 'remove shell hooks only, skip data deletion prompt (used by npm preuninstall)')\n .action(async (opts) => {\n log.plain(chalk.bold('\\n Workscribe — Uninstall\\n'))\n\n // 1. Remove shell hooks from any rc files that have them\n const hooked = detectShellRcFiles()\n if (hooked.length === 0) {\n log.info('No shell hooks found')\n } else {\n for (const { name, rcFile } of hooked) {\n removeHook(rcFile)\n log.success(`Shell hook removed from ${rcFile}`)\n log.plain(` ${chalk.dim(`Run: source ${rcFile}`)} (or restart your terminal to take effect)`)\n log.plain(\n ` ${chalk.dim(`${name === 'zsh' ? 'unfunction' : 'unset -f'} _workscribe_preexec _workscribe_precmd`)}`\n )\n }\n }\n\n if (opts.hooksOnly) return\n\n // 2. Optionally delete ~/.workscribe/ data\n if (fs.existsSync(WORKSCRIBE_DIR)) {\n log.plain('')\n const { deleteData } = await prompts({\n type: 'confirm',\n name: 'deleteData',\n message: `Delete all Workscribe data in ${WORKSCRIBE_DIR}? (database, config, exports)`,\n initial: false,\n })\n\n if (deleteData) {\n fs.rmSync(WORKSCRIBE_DIR, { recursive: true, force: true })\n log.success(`Deleted ${WORKSCRIBE_DIR}`)\n } else {\n log.info(`Data kept at ${WORKSCRIBE_DIR}`)\n }\n }\n\n log.plain('')\n log.plain(` ${chalk.dim('npm uninstall -g @workscribe/cli')} — remove the CLI itself`)\n log.plain('')\n })\n}\n"],"mappings":"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","names":["import_fs","path","os","fs","import_path","import_fs","fs","path","import_child_process","import_fs","import_path","path","fs","import_fs","import_os","import_path","import_fs","chalk","fs","path","os","fs","import_fs","fs","fs","program","program","import_fs","import_path","import_os","import_chalk","import_fs","import_path","fs","path","import_fs","import_path","import_os","import_child_process","path","os","fs","path","os","program","chalk","fs","prompts","import_fs","import_chalk","program","fs","chalk","import_chalk","chalk","program","import_chalk","program","chalk","import_chalk","import_fs","import_os","import_path","os","program","sessions","path","fs","chalk","fullSummary","import_fs","import_path","eventRowToPayload","program","path","fs","import_chalk","program","chalk","import_fs","program","fs","program","import_chalk","import_prompts","program","chalk","prompts","import_fs","import_path","import_os","import_prompts","import_chalk","path","os","fs","program","chalk","prompts"]}
|