devsplain 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,10 @@
1
1
  # devsplain
2
+ An agent-agnostic CLI tool that adds JSDoc and inline comments using state-of-the-art LLMs while preserving non-comment source lines byte-for-byte through deterministic verification.
2
3
 
3
- An industrial-grade, agent-agnostic CLI tool that automatically adds JSDoc and inline comments to your code using state-of-the-art LLMs, while guaranteeing code integrity with deterministic safety constraints.
4
+ ![devsplain demo](sample.gif)
4
5
 
6
+ devsplain never rewrites executable code.
7
+ If the original source cannot be reproduced exactly after comment insertion, the operation aborts.
5
8
  ---
6
9
 
7
10
  ## Key Features
@@ -35,6 +38,11 @@ Many AI code formatters rewrite your code entirely, exposing you to logic regres
35
38
  ### String Literal Guardrails
36
39
  The engine tracks lexical state across template strings, single quotes, double quotes, and multi-line docstrings (such as Python triple-quotes). Comment insertion is blocked if the target line resides within a string literal, preventing broken syntax.
37
40
 
41
+ ### The `[ds]` AI Tag Guarantee
42
+ Every single comment generated by the LLM is forcibly prefixed with a `[ds]` tag (e.g., `// [ds] This function handles...`).
43
+ This guarantees that the local `devsplain` lexer can mathematically differentiate between your human-written manual comments and the AI-generated comments.
44
+ When you run the `--clean` command, the lexer looks specifically for the `[ds]` prefix and surgically removes only the AI-generated comments, safely preserving 100% of your manual documentation.
45
+
38
46
  ### Why Not AST Verification?
39
47
 
40
48
  AST verification would require language-specific parser dependencies for every supported language.
@@ -3,43 +3,54 @@ const fs = require('fs');
3
3
  const path = require('path');
4
4
  const { spliceComments } = require('./cli');
5
5
 
6
- /** Attempts to execute the post-commit hook [ds] */
6
+ /** Main execution block [ds] */
7
7
  try {
8
- // Get the last commit message [ds]
8
+ // Get the current git directory [ds]
9
+ const gitDir = execSync('git rev-parse --git-dir', { encoding: 'utf8' }).trim();
10
+ const isRebasing = fs.existsSync(path.join(gitDir, 'rebase-merge')) || fs.existsSync(path.join(gitDir, 'rebase-apply'));
11
+ const isMerging = fs.existsSync(path.join(gitDir, 'MERGE_HEAD'));
12
+ const isCherryPicking = fs.existsSync(path.join(gitDir, 'CHERRY_PICK_HEAD'));
13
+
14
+ if (isRebasing || isMerging || isCherryPicking) {
15
+ console.log('[devsplain] Skipping AI comment generation during git rebase/merge/cherry-pick to avoid history conflicts.');
16
+ process.exit(0);
17
+ }
18
+
19
+ /** Check if the current operation is a rebase, merge or cherry-pick [ds] */
9
20
  const lastCommitMsg = execSync('git log -1 --format=%s', { encoding: 'utf8' }).trim();
10
21
  if (lastCommitMsg === 'docs: auto-generated comments by devsplain') {
11
22
  process.exit(0);
12
23
  }
13
24
 
14
- // Get the list of changed files in the last commit [ds]
25
+ // Get the last commit message [ds]
15
26
  const changedFilesStr = execSync('git diff-tree --no-commit-id --name-only -r HEAD', { encoding: 'utf8' }).trim();
16
27
  if (!changedFilesStr) {
17
28
  process.exit(0);
18
29
  }
19
30
  const changedFiles = changedFilesStr.split(/\r?\n/);
20
31
 
21
- /** Defines a list of valid file extensions for commenting [ds] */
32
+ /** List of valid file extensions for commenting [ds] */
22
33
  const validExtensions = [
23
34
  '.js', '.jsx', '.ts', '.tsx', '.html', '.css', '.scss', '.vue', '.svelte',
24
35
  '.py', '.java', '.c', '.cpp', '.cs', '.go', '.rb', '.php', '.rs',
25
36
  '.swift', '.kt', '.dart', '.sh'
26
37
  ];
27
38
 
28
- /** Filters the changed files based on valid extensions and existence [ds] */
39
+ /** Filter files to be commented [ds] */
29
40
  const filesToComment = changedFiles.filter(file => {
30
41
  const ext = path.extname(file).toLowerCase();
31
42
  const isIgnored = file.includes('node_modules/') || file.includes('tests/') || file.includes('__tests__/') || file.includes('fixtures/');
32
43
  return validExtensions.includes(ext) && fs.existsSync(file) && !isIgnored;
33
44
  });
34
45
 
46
+ // Check if there are any files to comment [ds]
35
47
  if (filesToComment.length === 0) {
36
48
  process.exit(0);
37
49
  }
38
50
 
39
- // Log the number of files to be commented [ds]
40
51
  console.log(`[devsplain] Found ${filesToComment.length} file(s) in the last commit to auto-comment.`);
41
52
 
42
- // Parse command-line arguments for commenting mode [ds]
53
+ // Parse command line arguments for mode flag [ds]
43
54
  const args = process.argv.slice(2);
44
55
  let modeFlag = '';
45
56
  if (args.includes('--light')) modeFlag = ' --light';
@@ -47,7 +58,7 @@ try {
47
58
 
48
59
  let commentedAny = false;
49
60
 
50
- /** Iterates through the files to be commented and attempts to comment each one [ds] */
61
+ /** Iterate over files to comment [ds] */
51
62
  for (const file of filesToComment) {
52
63
  try {
53
64
  const ext = path.extname(file).toLowerCase();
@@ -61,7 +72,7 @@ try {
61
72
  } catch (prevErr) {
62
73
  }
63
74
 
64
- // Check if the file has been modified beyond just comments [ds]
75
+ // Compare file content before and after the last commit [ds]
65
76
  if (contentPrev) {
66
77
  const cleanHead = spliceComments(contentHead, [], 'prune', ext);
67
78
  const cleanPrev = spliceComments(contentPrev, [], 'prune', ext);
@@ -73,7 +84,7 @@ try {
73
84
  } catch (cleanErr) {
74
85
  }
75
86
 
76
- // Attempt to comment the file using the cli script [ds]
87
+ // Comment the file using the CLI [ds]
77
88
  console.log(`[devsplain] Automatically commenting file: ${file}`);
78
89
  try {
79
90
  const cliPath = path.join(__dirname, 'cli.js');
@@ -84,7 +95,7 @@ try {
84
95
  }
85
96
  }
86
97
 
87
- /** If any files were commented, stage and commit the changes [ds] */
98
+ /** Stage and commit auto-generated comments if any [ds] */
88
99
  if (commentedAny) {
89
100
  const status = execSync('git diff --name-only', { encoding: 'utf8' }).trim();
90
101
  if (status.length > 0) {
@@ -93,6 +104,7 @@ try {
93
104
  console.log('[devsplain] Comments committed successfully! Rollback via: git reset --hard HEAD~1');
94
105
  }
95
106
  }
107
+ /** Catch and log any errors [ds] */
96
108
  } catch (e) {
97
109
  console.warn(`[devsplain] Warning: post-commit hook script failed: ${e.message}`);
98
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devsplain",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "An agent-agnostic CLI tool that automatically adds JSDoc and inline comments to your code using free LLMs.",
5
5
  "author": "mwahaj36",
6
6
  "license": "MIT",