codex-wakatime 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/index.cjs +62 -40
  3. package/package.json +12 -2
package/README.md CHANGED
@@ -39,6 +39,8 @@ codex-wakatime --install
39
39
  ```
40
40
 
41
41
  This adds `notify = ["codex-wakatime"]` to your `~/.codex/config.toml`.
42
+ If you already have a `notify` command configured, codex-wakatime replaces it
43
+ because Codex supports a single notify command.
42
44
 
43
45
  ## How It Works
44
46
 
package/dist/index.cjs CHANGED
@@ -279,16 +279,17 @@ var path7 = __toESM(require("node:path"), 1);
279
279
 
280
280
  // src/extractor.ts
281
281
  var path = __toESM(require("node:path"), 1);
282
- var PATTERNS = [
282
+ var READ_PATTERNS = [
283
283
  // Code block headers: ```typescript:src/index.ts or ```ts:src/index.ts
284
284
  /```\w*:([^\n`]+)/g,
285
285
  // Backtick paths with extension: `src/foo/bar.ts`
286
286
  /`([^`\s]+\.\w{1,6})`/g,
287
- // Action patterns: Read/List/Created/Modified/Updated/Wrote/Edited/Deleted file.ts
288
- /(?:Read|List|Create|Created|Modify|Modified|Update|Updated|Write|Wrote|Edit|Edited|Delete|Deleted)\s+`?([^\s`\n]+\.\w{1,6})`?/gi,
289
287
  // File path in quotes: "src/file.ts" or 'src/file.ts'
290
- /["']([^"'\s]+\.\w{1,6})["']/g
288
+ /["']([^"'\s]+\.\w{1,6})["']/g,
289
+ // Read action patterns: Read/List file.ts
290
+ /(?:Read|List)\s+`?([^\s`\n]+\.\w{1,6})`?/gi
291
291
  ];
292
+ var WRITE_PATTERN = /(?:Create|Created|Modify|Modified|Update|Updated|Write|Wrote|Edit|Edited|Delete|Deleted)\s+`?([^\s`\n]+\.\w{1,6})`?/gi;
292
293
  function isValidFilePath(p) {
293
294
  if (!p || p.length === 0) return false;
294
295
  if (p.startsWith("http://") || p.startsWith("https://") || p.includes("://"))
@@ -306,22 +307,35 @@ function normalizePath(filePath, cwd) {
306
307
  }
307
308
  return path.normalize(path.join(cwd, cleaned));
308
309
  }
309
- function extractFilePaths(message, cwd) {
310
+ function extractFiles(message, cwd) {
310
311
  if (!message || message.length === 0) {
311
312
  return [];
312
313
  }
313
- const files = /* @__PURE__ */ new Set();
314
- for (const pattern of PATTERNS) {
314
+ const fileMap = /* @__PURE__ */ new Map();
315
+ WRITE_PATTERN.lastIndex = 0;
316
+ for (const match of message.matchAll(WRITE_PATTERN)) {
317
+ const filePath = match[1];
318
+ if (filePath && isValidFilePath(filePath)) {
319
+ const normalized = normalizePath(filePath, cwd);
320
+ fileMap.set(normalized, true);
321
+ }
322
+ }
323
+ for (const pattern of READ_PATTERNS) {
315
324
  pattern.lastIndex = 0;
316
325
  for (const match of message.matchAll(pattern)) {
317
326
  const filePath = match[1];
318
327
  if (filePath && isValidFilePath(filePath)) {
319
328
  const normalized = normalizePath(filePath, cwd);
320
- files.add(normalized);
329
+ if (!fileMap.has(normalized)) {
330
+ fileMap.set(normalized, false);
331
+ }
321
332
  }
322
333
  }
323
334
  }
324
- return Array.from(files);
335
+ return Array.from(fileMap.entries()).map(([filePath, isWrite]) => ({
336
+ path: filePath,
337
+ isWrite
338
+ }));
325
339
  }
326
340
 
327
341
  // src/install.ts
@@ -421,20 +435,15 @@ function formatTomlValue(value) {
421
435
  }
422
436
  return String(value);
423
437
  }
424
- function normalizeNotifyValue(value) {
425
- if (Array.isArray(value)) return value.slice();
426
- if (typeof value === "string") return [value];
427
- return [];
428
- }
429
- function hasNotifyEntry(entries, command) {
430
- return entries.some(
431
- (entry) => typeof entry === "string" && entry === command
432
- );
433
- }
434
- function removeNotifyEntry(entries, command) {
435
- return entries.filter(
436
- (entry) => !(typeof entry === "string" && entry === command)
437
- );
438
+ function normalizeNotifyCommand(value) {
439
+ if (Array.isArray(value)) {
440
+ const entries = value.filter(
441
+ (entry) => typeof entry === "string" && entry.length > 0
442
+ );
443
+ return entries.length > 0 ? entries : void 0;
444
+ }
445
+ if (typeof value === "string" && value.length > 0) return [value];
446
+ return void 0;
438
447
  }
439
448
  function getPluginCommand() {
440
449
  return ["codex-wakatime"];
@@ -457,12 +466,17 @@ function installHook() {
457
466
  }
458
467
  }
459
468
  const pluginCommand = getPluginCommand()[0];
460
- const existingNotify = normalizeNotifyValue(config.notify);
461
- if (hasNotifyEntry(existingNotify, pluginCommand)) {
469
+ const existingNotify = normalizeNotifyCommand(config.notify);
470
+ if (existingNotify?.[0] === pluginCommand) {
462
471
  console.log("codex-wakatime is already configured");
463
472
  return;
464
473
  }
465
- config.notify = [...existingNotify, pluginCommand];
474
+ if (existingNotify && existingNotify.length > 0) {
475
+ console.warn(
476
+ "Existing Codex notify command found; replacing with codex-wakatime"
477
+ );
478
+ }
479
+ config.notify = [pluginCommand];
466
480
  const newContent = stringifyToml(config);
467
481
  fs.writeFileSync(CODEX_CONFIG_PATH, newContent);
468
482
  console.log(`Updated ${CODEX_CONFIG_PATH}`);
@@ -482,17 +496,12 @@ function uninstallHook() {
482
496
  const content = fs.readFileSync(CODEX_CONFIG_PATH, "utf-8");
483
497
  const config = parseToml(content);
484
498
  const pluginCommand = getPluginCommand()[0];
485
- const existingNotify = normalizeNotifyValue(config.notify);
486
- if (!hasNotifyEntry(existingNotify, pluginCommand)) {
499
+ const existingNotify = normalizeNotifyCommand(config.notify);
500
+ if (!existingNotify || existingNotify[0] !== pluginCommand) {
487
501
  console.log("codex-wakatime was not configured");
488
502
  return;
489
503
  }
490
- const updatedNotify = removeNotifyEntry(existingNotify, pluginCommand);
491
- if (updatedNotify.length === 0) {
492
- delete config.notify;
493
- } else {
494
- config.notify = updatedNotify;
495
- }
504
+ delete config.notify;
496
505
  const newContent = stringifyToml(config);
497
506
  fs.writeFileSync(CODEX_CONFIG_PATH, newContent);
498
507
  console.log("codex-wakatime notification hook removed");
@@ -647,7 +656,7 @@ var os6 = __toESM(require("node:os"), 1);
647
656
  var package_default = {
648
657
  $schema: "https://json.schemastore.org/package.json",
649
658
  name: "codex-wakatime",
650
- version: "1.0.1",
659
+ version: "1.1.1",
651
660
  description: "WakaTime plugin for OpenAI Codex CLI - Track AI coding activity and time spent",
652
661
  repository: {
653
662
  type: "git",
@@ -671,7 +680,8 @@ var package_default = {
671
680
  test: "vitest",
672
681
  "test:run": "vitest run",
673
682
  "test:coverage": "vitest run --coverage",
674
- prepublishOnly: "npm run build"
683
+ prepublishOnly: "npm run build",
684
+ prepare: "husky"
675
685
  },
676
686
  keywords: [
677
687
  "codex",
@@ -686,12 +696,16 @@ var package_default = {
686
696
  license: "MIT",
687
697
  devDependencies: {
688
698
  "@biomejs/biome": "^2.3.10",
699
+ "@commitlint/cli": "^20.2.0",
700
+ "@commitlint/config-conventional": "^20.2.0",
689
701
  "@semantic-release/changelog": "^6.0.3",
690
702
  "@semantic-release/git": "^10.0.1",
691
703
  "@types/node": "^22.0.0",
692
704
  "@types/which": "^3.0.0",
693
705
  "@vitest/coverage-v8": "^4.0.16",
694
706
  esbuild: "^0.25.0",
707
+ husky: "^9.1.7",
708
+ "lint-staged": "^16.2.7",
695
709
  "semantic-release": "^25.0.2",
696
710
  typescript: "^5.0.0",
697
711
  vitest: "^4.0.16"
@@ -699,6 +713,11 @@ var package_default = {
699
713
  dependencies: {
700
714
  "@iarna/toml": "^3.0.0",
701
715
  which: "^4.0.0"
716
+ },
717
+ "lint-staged": {
718
+ "*.{ts,js,json}": [
719
+ "biome check --write"
720
+ ]
702
721
  }
703
722
  };
704
723
 
@@ -1099,16 +1118,19 @@ async function main() {
1099
1118
  }
1100
1119
  const assistantMessage = notification["last-assistant-message"] ?? "";
1101
1120
  const cwd = notification.cwd;
1102
- const files = extractFilePaths(assistantMessage, cwd);
1121
+ const files = extractFiles(assistantMessage, cwd);
1103
1122
  logger.debug(`Extracted ${files.length} files from message`);
1104
1123
  if (files.length > 0) {
1105
1124
  for (const file of files) {
1106
- logger.debug(`Sending heartbeat for file: ${file}`);
1125
+ logger.debug(
1126
+ `Sending heartbeat for file: ${file.path} (isWrite: ${file.isWrite})`
1127
+ );
1107
1128
  sendHeartbeat({
1108
- entity: file,
1129
+ entity: file.path,
1109
1130
  entityType: "file",
1110
1131
  category: "ai coding",
1111
- projectFolder: cwd
1132
+ projectFolder: cwd,
1133
+ isWrite: file.isWrite
1112
1134
  });
1113
1135
  }
1114
1136
  } else {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "codex-wakatime",
4
- "version": "1.0.1",
4
+ "version": "1.1.1",
5
5
  "description": "WakaTime plugin for OpenAI Codex CLI - Track AI coding activity and time spent",
6
6
  "repository": {
7
7
  "type": "git",
@@ -25,7 +25,8 @@
25
25
  "test": "vitest",
26
26
  "test:run": "vitest run",
27
27
  "test:coverage": "vitest run --coverage",
28
- "prepublishOnly": "npm run build"
28
+ "prepublishOnly": "npm run build",
29
+ "prepare": "husky"
29
30
  },
30
31
  "keywords": [
31
32
  "codex",
@@ -40,12 +41,16 @@
40
41
  "license": "MIT",
41
42
  "devDependencies": {
42
43
  "@biomejs/biome": "^2.3.10",
44
+ "@commitlint/cli": "^20.2.0",
45
+ "@commitlint/config-conventional": "^20.2.0",
43
46
  "@semantic-release/changelog": "^6.0.3",
44
47
  "@semantic-release/git": "^10.0.1",
45
48
  "@types/node": "^22.0.0",
46
49
  "@types/which": "^3.0.0",
47
50
  "@vitest/coverage-v8": "^4.0.16",
48
51
  "esbuild": "^0.25.0",
52
+ "husky": "^9.1.7",
53
+ "lint-staged": "^16.2.7",
49
54
  "semantic-release": "^25.0.2",
50
55
  "typescript": "^5.0.0",
51
56
  "vitest": "^4.0.16"
@@ -53,5 +58,10 @@
53
58
  "dependencies": {
54
59
  "@iarna/toml": "^3.0.0",
55
60
  "which": "^4.0.0"
61
+ },
62
+ "lint-staged": {
63
+ "*.{ts,js,json}": [
64
+ "biome check --write"
65
+ ]
56
66
  }
57
67
  }