ronds_ai 0.1.1 → 0.1.3

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/bin/ronds_ai.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const { runCodeRecord, saveCliError } = require('../lib/code_record');
4
+ const { runDoctor } = require('../lib/doctor');
4
5
  const { deployHooks } = require('../lib/hooks_deploy');
5
6
 
6
7
  const SUPPORTED_SOURCES = new Set(['claude', 'cursor']);
@@ -9,16 +10,19 @@ function printUsage() {
9
10
  process.stderr.write([
10
11
  'Usage:',
11
12
  ' ronds_ai record <tool>',
13
+ ' ronds_ai doctor <tool>',
12
14
  ' ronds_ai hooks deploy',
13
15
  '',
14
- 'Supported tools for record:',
16
+ 'Supported tools:',
15
17
  ' claude',
16
18
  ' cursor',
17
19
  '',
18
20
  'Examples:',
19
- ' npx ronds_ai record claude',
20
- ' npx ronds_ai record cursor',
21
- ' npx ronds_ai hooks deploy',
21
+ ' npx ronds_ai@latest record claude',
22
+ ' npx ronds_ai@latest record cursor',
23
+ ' npx ronds_ai@latest doctor claude',
24
+ ' npx ronds_ai@latest doctor cursor',
25
+ ' npx ronds_ai@latest hooks deploy',
22
26
  ].join('\n'));
23
27
  process.stderr.write('\n');
24
28
  }
@@ -49,6 +53,19 @@ async function run() {
49
53
  return;
50
54
  }
51
55
 
56
+ if (command === 'doctor') {
57
+ const [tool] = args;
58
+ const normalizedTool = String(tool || '').trim().toLowerCase();
59
+
60
+ if (!SUPPORTED_SOURCES.has(normalizedTool)) {
61
+ throw new Error(`Unsupported doctor tool: ${tool || ''}`);
62
+ }
63
+
64
+ const result = runDoctor(normalizedTool, process.cwd());
65
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
66
+ return;
67
+ }
68
+
52
69
  if (command === 'hooks') {
53
70
  await runHooksCommand(args);
54
71
  return;
package/lib/doctor.js ADDED
@@ -0,0 +1,102 @@
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+ const { execFileSync } = require('child_process');
5
+
6
+ const SUPPORTED_TOOLS = new Set(['claude', 'cursor']);
7
+
8
+ function formatDateStamp(date = new Date()) {
9
+ const year = String(date.getFullYear());
10
+ const month = String(date.getMonth() + 1).padStart(2, '0');
11
+ const day = String(date.getDate()).padStart(2, '0');
12
+ return `${year}${month}${day}`;
13
+ }
14
+
15
+ function getFailedEventDir() {
16
+ return path.join(os.homedir(), '.ronds_ai', 'failed-events');
17
+ }
18
+
19
+ function getRecentLogPaths(tool) {
20
+ const dateStamp = formatDateStamp();
21
+ return [
22
+ path.join(getFailedEventDir(), `${dateStamp}-${tool}-error.jsonl`),
23
+ path.join(getFailedEventDir(), `${dateStamp}-cli-error.jsonl`),
24
+ ];
25
+ }
26
+
27
+ function tailFileLines(filePath, maxLines = 20) {
28
+ if (!fs.existsSync(filePath)) {
29
+ return [];
30
+ }
31
+
32
+ const raw = fs.readFileSync(filePath, 'utf8');
33
+ const lines = raw.split('\n').filter((line) => line.trim() !== '');
34
+ return lines.slice(-maxLines);
35
+ }
36
+
37
+ function readRecentLogs(tool) {
38
+ return getRecentLogPaths(tool).map((filePath) => ({
39
+ path: filePath,
40
+ exists: fs.existsSync(filePath),
41
+ lines: tailFileLines(filePath),
42
+ }));
43
+ }
44
+
45
+ function getConfigChecks(tool, baseDir) {
46
+ if (tool === 'cursor') {
47
+ return [
48
+ {
49
+ label: '.cursor/hooks.json',
50
+ path: path.join(baseDir, '.cursor', 'hooks.json'),
51
+ },
52
+ ];
53
+ }
54
+
55
+ return [
56
+ {
57
+ label: '.claude/settings.json',
58
+ path: path.join(baseDir, '.claude', 'settings.json'),
59
+ },
60
+ {
61
+ label: '.claude/settings.local.json',
62
+ path: path.join(baseDir, '.claude', 'settings.local.json'),
63
+ },
64
+ ];
65
+ }
66
+
67
+ function readGitUserEmail(baseDir) {
68
+ try {
69
+ return execFileSync('git', ['config', 'user.email'], {
70
+ cwd: baseDir,
71
+ encoding: 'utf8',
72
+ stdio: ['ignore', 'pipe', 'pipe'],
73
+ }).trim();
74
+ } catch {
75
+ return '';
76
+ }
77
+ }
78
+
79
+ function runDoctor(tool, targetDir = process.cwd()) {
80
+ const normalizedTool = String(tool || '').trim().toLowerCase();
81
+ if (!SUPPORTED_TOOLS.has(normalizedTool)) {
82
+ throw new Error(`Unsupported doctor tool: ${tool || ''}`);
83
+ }
84
+
85
+ const baseDir = path.resolve(targetDir);
86
+ const configChecks = getConfigChecks(normalizedTool, baseDir).map((item) => ({
87
+ ...item,
88
+ exists: fs.existsSync(item.path),
89
+ }));
90
+
91
+ return {
92
+ tool: normalizedTool,
93
+ targetDir: baseDir,
94
+ gitUserEmail: readGitUserEmail(baseDir),
95
+ configChecks,
96
+ recentLogs: readRecentLogs(normalizedTool),
97
+ };
98
+ }
99
+
100
+ module.exports = {
101
+ runDoctor,
102
+ };
@@ -4,15 +4,19 @@ const path = require('path');
4
4
  const CURSOR_COMMAND = 'npx ronds_ai@latest record cursor';
5
5
  const CLAUDE_COMMAND = 'npx ronds_ai@latest record claude';
6
6
  const CURSOR_OLD_COMMAND = 'node .cursor/hooks/cursor_hook_request.cjs';
7
+ const CURSOR_OLD_JS_COMMAND = 'node .cursor/hooks/cursor_hook_request.js';
7
8
  const CLAUDE_OLD_COMMAND = 'node .claude/hooks/claude_hook_request.cjs';
9
+ const CLAUDE_OLD_JS_COMMAND = 'node .claude/hooks/claude_hook_request.js';
8
10
  const CLAUDE_MATCHER = 'Edit|Write|MultiEdit';
9
11
  const CURSOR_MANAGED_COMMANDS = new Set([
10
12
  CURSOR_COMMAND,
11
13
  CURSOR_OLD_COMMAND,
14
+ CURSOR_OLD_JS_COMMAND,
12
15
  ]);
13
16
  const CLAUDE_MANAGED_COMMANDS = new Set([
14
17
  CLAUDE_COMMAND,
15
18
  CLAUDE_OLD_COMMAND,
19
+ CLAUDE_OLD_JS_COMMAND,
16
20
  ]);
17
21
 
18
22
  function isPlainObject(value) {
@@ -198,8 +202,11 @@ function deployHooks(targetDir = process.cwd()) {
198
202
  const createdFiles = [];
199
203
 
200
204
  removeFileIfExists(path.join(baseDir, '.cursor', 'hooks', 'cursor_hook_request.cjs'), removedFiles);
205
+ removeFileIfExists(path.join(baseDir, '.cursor', 'hooks', 'cursor_hook_request.js'), removedFiles);
201
206
  removeFileIfExists(path.join(baseDir, '.claude', 'hooks', 'claude_hook_request.cjs'), removedFiles);
207
+ removeFileIfExists(path.join(baseDir, '.claude', 'hooks', 'claude_hook_request.js'), removedFiles);
202
208
  removeFileIfExists(path.join(baseDir, '.claude', 'hooks', 'claide_hook_request.cjs'), removedFiles);
209
+ removeFileIfExists(path.join(baseDir, '.claude', 'hooks', 'claide_hook_request.js'), removedFiles);
203
210
 
204
211
  const cursorPath = path.join(baseDir, '.cursor', 'hooks.json');
205
212
  const cursorResult = readJsonFile(cursorPath, {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ronds_ai",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "CLI for reporting AI code edit events.",
5
5
  "bin": {
6
6
  "ronds_ai": "bin/ronds_ai.js"