x7-code-line 0.3.0 → 0.4.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.
@@ -1,8 +1,8 @@
1
- #!/usr/bin/env node
2
-
3
- const { runCli } = require("../src/cli");
4
-
5
- runCli(process.argv.slice(2)).catch((error) => {
6
- console.error(`[x7-code-line] ${error.message}`);
7
- process.exit(1);
8
- });
1
+ #!/usr/bin/env node
2
+
3
+ const { runCli } = require("../src/cli");
4
+
5
+ runCli(process.argv.slice(2)).catch((error) => {
6
+ console.error(`[x7-code-line] ${error.message}`);
7
+ process.exit(1);
8
+ });
@@ -1,4 +1,4 @@
1
- #!/bin/sh
2
- set -eu
3
-
4
- npx --no-install x7-code-line git-commit-msg "$1"
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ npx --no-install x7-code-line git-commit-msg "$1"
@@ -1,4 +1,4 @@
1
- #!/bin/sh
2
- set -eu
3
-
4
- npx --no-install x7-code-line git-pre-commit "$@"
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ npx --no-install x7-code-line git-pre-commit "$@"
package/package.json CHANGED
@@ -1,30 +1,30 @@
1
- {
2
- "name": "x7-code-line",
3
- "version": "0.3.0",
4
- "description": "Install Cursor, Codex, and git hooks for x7 code line workflows.",
5
- "main": "src/index.js",
6
- "bin": {
7
- "x7-code-line": "bin/x7-code-line.js"
8
- },
9
- "scripts": {
10
- "postinstall": "node src/postinstall.js",
11
- "test": "node test/install.test.js"
12
- },
13
- "files": [
14
- "bin/",
15
- "hooks/",
16
- "src/",
17
- "templates/"
18
- ],
19
- "keywords": [
20
- "cursor",
21
- "codex",
22
- "hooks",
23
- "git-hooks"
24
- ],
25
- "author": "",
26
- "license": "MIT",
27
- "engines": {
28
- "node": ">=18"
29
- }
30
- }
1
+ {
2
+ "name": "x7-code-line",
3
+ "version": "0.4.0",
4
+ "description": "Install Cursor, Codex, and git hooks for x7 code line workflows.",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "x7-code-line": "bin/x7-code-line.js"
8
+ },
9
+ "scripts": {
10
+ "postinstall": "node src/postinstall.js",
11
+ "test": "node test/install.test.js"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "hooks/",
16
+ "src/",
17
+ "templates/"
18
+ ],
19
+ "keywords": [
20
+ "cursor",
21
+ "codex",
22
+ "hooks",
23
+ "git-hooks"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "engines": {
28
+ "node": ">=18"
29
+ }
30
+ }
@@ -1,62 +1,93 @@
1
- "use strict";
2
-
3
- const {
4
- AI_DIFF_CACHE_FILE,
5
- NORMAL_DIFF_CACHE_FILE,
6
- addProjectId,
7
- getProjectIds,
8
- readLineIdCache,
9
- readProjects,
10
- writeLineIdCache
11
- } = require("./cache");
12
- const { getGitDiffLineIds } = require("./diff-lines");
13
-
1
+ "use strict";
2
+
3
+ const {
4
+ AI_DIFF_CACHE_FILE,
5
+ NORMAL_DIFF_CACHE_FILE,
6
+ addProjectId,
7
+ getProjectIds,
8
+ readLineIdCache,
9
+ readProjects,
10
+ writeLineIdCache
11
+ } = require("./cache");
12
+ const { getGitDiffLineIds } = require("./diff-lines");
13
+
14
14
  function handlePromptSubmit(baseDir = process.env.INIT_CWD || process.cwd()) {
15
+ log("prompt-submit", `start base=${baseDir}`);
15
16
  const projects = readProjects(baseDir);
16
17
  const aiCache = readLineIdCache(baseDir, AI_DIFF_CACHE_FILE);
17
18
  const normalCache = readLineIdCache(baseDir, NORMAL_DIFF_CACHE_FILE);
18
19
 
19
20
  for (const projectDir of projects) {
21
+ log("prompt-submit", `project ${projectDir}`);
20
22
  const aiIds = getProjectIds(aiCache, projectDir);
21
- for (const id of safelyGetDiffLineIds(projectDir)) {
23
+ const ids = safelyGetDiffLineIds("prompt-submit", projectDir);
24
+ let addedCount = 0;
25
+ for (const id of ids) {
22
26
  if (!aiIds.has(id)) {
23
- addProjectId(normalCache, projectDir, id);
27
+ if (addProjectId(normalCache, projectDir, id)) {
28
+ addedCount += 1;
29
+ }
24
30
  }
25
31
  }
32
+ log("prompt-submit", `project ${projectDir} cached=${addedCount}`);
26
33
  }
27
34
 
28
- writeLineIdCache(baseDir, NORMAL_DIFF_CACHE_FILE, normalCache);
35
+ writeCache("prompt-submit", baseDir, NORMAL_DIFF_CACHE_FILE, normalCache);
36
+ log("prompt-submit", "end");
29
37
  }
30
38
 
31
39
  function handleStop(baseDir = process.env.INIT_CWD || process.cwd()) {
40
+ log("stop", `start base=${baseDir}`);
32
41
  const projects = readProjects(baseDir);
33
42
  const aiCache = readLineIdCache(baseDir, AI_DIFF_CACHE_FILE);
34
43
  const normalCache = readLineIdCache(baseDir, NORMAL_DIFF_CACHE_FILE);
35
44
 
36
45
  for (const projectDir of projects) {
46
+ log("stop", `project ${projectDir}`);
37
47
  const normalIds = getProjectIds(normalCache, projectDir);
38
- for (const id of safelyGetDiffLineIds(projectDir)) {
48
+ const ids = safelyGetDiffLineIds("stop", projectDir);
49
+ let addedCount = 0;
50
+ for (const id of ids) {
39
51
  if (!normalIds.has(id)) {
40
- addProjectId(aiCache, projectDir, id);
52
+ if (addProjectId(aiCache, projectDir, id)) {
53
+ addedCount += 1;
54
+ }
41
55
  }
42
56
  }
57
+ log("stop", `project ${projectDir} cached=${addedCount}`);
43
58
  }
44
59
 
45
- writeLineIdCache(baseDir, AI_DIFF_CACHE_FILE, aiCache);
60
+ writeCache("stop", baseDir, AI_DIFF_CACHE_FILE, aiCache);
61
+ log("stop", "end");
46
62
  }
47
63
 
48
- function safelyGetDiffLineIds(projectDir) {
64
+ function safelyGetDiffLineIds(command, projectDir) {
65
+ log(command, `reading diff ${projectDir}`);
49
66
  try {
50
- return getGitDiffLineIds(projectDir);
67
+ const ids = getGitDiffLineIds(projectDir);
68
+ log(command, `read diff success ${projectDir} count=${ids.length}`);
69
+ return ids;
51
70
  } catch (error) {
52
- if (process.env.X7_CODE_LINE_DEBUG === "1") {
53
- console.error(`[x7-code-line] skip ${projectDir}: ${error.message}`);
54
- }
71
+ log(command, `read diff failed ${projectDir}: ${error.message}`);
55
72
  return [];
56
73
  }
57
74
  }
58
75
 
59
- module.exports = {
60
- handlePromptSubmit,
61
- handleStop
62
- };
76
+ function writeCache(command, baseDir, fileName, cache) {
77
+ try {
78
+ writeLineIdCache(baseDir, fileName, cache);
79
+ log(command, `write cache success ${fileName}`);
80
+ } catch (error) {
81
+ log(command, `write cache failed ${fileName}: ${error.message}`);
82
+ throw error;
83
+ }
84
+ }
85
+
86
+ function log(command, message) {
87
+ console.error(`[x7-code-line] ${command} ${message}`);
88
+ }
89
+
90
+ module.exports = {
91
+ handlePromptSubmit,
92
+ handleStop
93
+ };
package/src/cache.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  const fs = require("node:fs");
4
+ const os = require("node:os");
4
5
  const path = require("node:path");
5
6
 
6
7
  const CACHE_DIR_NAME = ".x7-code-line";
@@ -8,98 +9,150 @@ const PROJECTS_CACHE_FILE = "projects.json";
8
9
  const AI_DIFF_CACHE_FILE = "ai-diff-line-ids.json";
9
10
  const NORMAL_DIFF_CACHE_FILE = "normal-diff-line-ids.json";
10
11
  const PENDING_COMMIT_FILE = "pending-commit.json";
11
-
12
+ const BASE_POINTER_FILE = ".x7-code-line-base.json";
13
+
12
14
  function getCacheDir(baseDir = process.env.INIT_CWD || process.cwd()) {
13
15
  return path.join(path.resolve(baseDir), CACHE_DIR_NAME);
14
16
  }
15
17
 
16
- function ensureCacheFiles(baseDir) {
17
- const cacheDir = getCacheDir(baseDir);
18
- fs.mkdirSync(cacheDir, { recursive: true });
19
- ensureJson(path.join(cacheDir, PROJECTS_CACHE_FILE), { projects: [] });
20
- ensureJson(path.join(cacheDir, AI_DIFF_CACHE_FILE), { projects: {} });
21
- ensureJson(path.join(cacheDir, NORMAL_DIFF_CACHE_FILE), { projects: {} });
22
- return cacheDir;
23
- }
24
-
25
- function writeProjects(baseDir, projectDirs) {
26
- const cacheDir = ensureCacheFiles(baseDir);
27
- const projects = [...new Set(projectDirs.map((dir) => path.resolve(dir)))];
28
- writeJson(path.join(cacheDir, PROJECTS_CACHE_FILE), { projects });
18
+ function getInstallFile(baseDir = process.env.INIT_CWD || process.cwd()) {
19
+ return path.join(getCacheDir(baseDir), "install.json");
29
20
  }
30
21
 
31
- function readProjects(baseDir = process.env.INIT_CWD || process.cwd()) {
32
- const cacheDir = ensureCacheFiles(baseDir);
33
- const cache = readJson(path.join(cacheDir, PROJECTS_CACHE_FILE), { projects: [] });
34
- const projects = Array.isArray(cache.projects) ? cache.projects : [];
35
- return projects.map((project) => path.resolve(project));
36
- }
37
-
38
- function readLineIdCache(baseDir, fileName) {
39
- const cacheDir = ensureCacheFiles(baseDir);
40
- const cache = readJson(path.join(cacheDir, fileName), { projects: {} });
41
- return cache && typeof cache === "object" && !Array.isArray(cache) ? cache : { projects: {} };
22
+ function getBasePointerPath() {
23
+ if (process.env.X7_CODE_LINE_POINTER_PATH) {
24
+ return path.resolve(process.env.X7_CODE_LINE_POINTER_PATH);
25
+ }
26
+ return path.join(os.homedir(), BASE_POINTER_FILE);
42
27
  }
43
-
44
- function writeLineIdCache(baseDir, fileName, cache) {
45
- const cacheDir = ensureCacheFiles(baseDir);
46
- writeJson(path.join(cacheDir, fileName), cache);
28
+
29
+ function ensureCacheFiles(baseDir) {
30
+ const cacheDir = getCacheDir(baseDir);
31
+ fs.mkdirSync(cacheDir, { recursive: true });
32
+ ensureJson(path.join(cacheDir, PROJECTS_CACHE_FILE), { projects: [] });
33
+ ensureJson(path.join(cacheDir, AI_DIFF_CACHE_FILE), { projects: {} });
34
+ ensureJson(path.join(cacheDir, NORMAL_DIFF_CACHE_FILE), { projects: {} });
35
+ return cacheDir;
36
+ }
37
+
38
+ function writeProjects(baseDir, projectDirs) {
39
+ const cacheDir = ensureCacheFiles(baseDir);
40
+ const projects = [...new Set(projectDirs.map((dir) => path.resolve(dir)))];
41
+ writeJson(path.join(cacheDir, PROJECTS_CACHE_FILE), { projects });
42
+ }
43
+
44
+ function readProjects(baseDir = process.env.INIT_CWD || process.cwd()) {
45
+ const cacheDir = ensureCacheFiles(baseDir);
46
+ const cache = readJson(path.join(cacheDir, PROJECTS_CACHE_FILE), { projects: [] });
47
+ const projects = Array.isArray(cache.projects) ? cache.projects : [];
48
+ return projects.map((project) => path.resolve(project));
49
+ }
50
+
51
+ function readLineIdCache(baseDir, fileName) {
52
+ const cacheDir = ensureCacheFiles(baseDir);
53
+ const cache = readJson(path.join(cacheDir, fileName), { projects: {} });
54
+ return cache && typeof cache === "object" && !Array.isArray(cache) ? cache : { projects: {} };
55
+ }
56
+
57
+ function writeLineIdCache(baseDir, fileName, cache) {
58
+ const cacheDir = ensureCacheFiles(baseDir);
59
+ writeJson(path.join(cacheDir, fileName), cache);
60
+ }
61
+
62
+ function getProjectIds(cache, projectDir) {
63
+ const key = path.resolve(projectDir);
64
+ const ids = cache.projects && Array.isArray(cache.projects[key]) ? cache.projects[key] : [];
65
+ return new Set(ids);
66
+ }
67
+
68
+ function addProjectId(cache, projectDir, id) {
69
+ const key = path.resolve(projectDir);
70
+ if (!cache.projects || typeof cache.projects !== "object" || Array.isArray(cache.projects)) {
71
+ cache.projects = {};
72
+ }
73
+ if (!Array.isArray(cache.projects[key])) {
74
+ cache.projects[key] = [];
75
+ }
76
+ if (!cache.projects[key].includes(id)) {
77
+ cache.projects[key].push(id);
78
+ return true;
79
+ }
80
+ return false;
81
+ }
82
+
83
+ function clearProjectIds(cache, projectDir) {
84
+ const key = path.resolve(projectDir);
85
+ if (!cache.projects || typeof cache.projects !== "object" || Array.isArray(cache.projects)) {
86
+ cache.projects = {};
87
+ return false;
88
+ }
89
+ if (Object.prototype.hasOwnProperty.call(cache.projects, key)) {
90
+ delete cache.projects[key];
91
+ return true;
92
+ }
93
+ return false;
47
94
  }
48
95
 
49
- function getProjectIds(cache, projectDir) {
50
- const key = path.resolve(projectDir);
51
- const ids = cache.projects && Array.isArray(cache.projects[key]) ? cache.projects[key] : [];
52
- return new Set(ids);
96
+ function writeBasePointer(baseDir) {
97
+ const pointerPath = getBasePointerPath();
98
+ fs.mkdirSync(path.dirname(pointerPath), { recursive: true });
99
+ writeJson(pointerPath, { baseDir: path.resolve(baseDir) });
53
100
  }
54
101
 
55
- function addProjectId(cache, projectDir, id) {
56
- const key = path.resolve(projectDir);
57
- if (!cache.projects || typeof cache.projects !== "object" || Array.isArray(cache.projects)) {
58
- cache.projects = {};
102
+ function readBasePointer() {
103
+ const pointer = readJson(getBasePointerPath(), {});
104
+ if (!pointer || typeof pointer.baseDir !== "string" || !pointer.baseDir.trim()) {
105
+ return undefined;
59
106
  }
60
- if (!Array.isArray(cache.projects[key])) {
61
- cache.projects[key] = [];
62
- }
63
- if (!cache.projects[key].includes(id)) {
64
- cache.projects[key].push(id);
65
- return true;
66
- }
67
- return false;
68
- }
69
107
 
70
- function clearProjectIds(cache, projectDir) {
71
- const key = path.resolve(projectDir);
72
- if (!cache.projects || typeof cache.projects !== "object" || Array.isArray(cache.projects)) {
73
- cache.projects = {};
74
- return false;
75
- }
76
- if (Object.prototype.hasOwnProperty.call(cache.projects, key)) {
77
- delete cache.projects[key];
78
- return true;
79
- }
80
- return false;
108
+ const baseDir = path.resolve(pointer.baseDir);
109
+ return hasInstallFile(baseDir) ? baseDir : undefined;
81
110
  }
82
111
 
83
- function ensureJson(filePath, defaultValue) {
84
- if (!fs.existsSync(filePath)) {
85
- writeJson(filePath, defaultValue);
112
+ function findInstalledBase(startDir) {
113
+ let current = path.resolve(startDir);
114
+
115
+ while (true) {
116
+ if (hasInstallFile(current)) {
117
+ return current;
118
+ }
119
+ const parent = path.dirname(current);
120
+ if (parent === current) {
121
+ return undefined;
122
+ }
123
+ current = parent;
86
124
  }
87
125
  }
88
126
 
89
- function readJson(filePath, defaultValue) {
127
+ function hasInstallFile(baseDir) {
90
128
  try {
91
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
129
+ return fs.statSync(getInstallFile(baseDir)).isFile();
92
130
  } catch {
93
- return defaultValue;
131
+ return false;
94
132
  }
95
133
  }
96
-
97
- function writeJson(filePath, value) {
98
- fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
99
- }
100
-
101
- module.exports = {
134
+
135
+ function ensureJson(filePath, defaultValue) {
136
+ if (!fs.existsSync(filePath)) {
137
+ writeJson(filePath, defaultValue);
138
+ }
139
+ }
140
+
141
+ function readJson(filePath, defaultValue) {
142
+ try {
143
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
144
+ } catch {
145
+ return defaultValue;
146
+ }
147
+ }
148
+
149
+ function writeJson(filePath, value) {
150
+ fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
151
+ }
152
+
153
+ module.exports = {
102
154
  AI_DIFF_CACHE_FILE,
155
+ BASE_POINTER_FILE,
103
156
  CACHE_DIR_NAME,
104
157
  NORMAL_DIFF_CACHE_FILE,
105
158
  PENDING_COMMIT_FILE,
@@ -107,10 +160,16 @@ module.exports = {
107
160
  addProjectId,
108
161
  clearProjectIds,
109
162
  ensureCacheFiles,
163
+ findInstalledBase,
164
+ getBasePointerPath,
110
165
  getCacheDir,
166
+ getInstallFile,
111
167
  getProjectIds,
168
+ hasInstallFile,
112
169
  readLineIdCache,
170
+ readBasePointer,
113
171
  readProjects,
172
+ writeBasePointer,
114
173
  writeLineIdCache,
115
174
  writeProjects
116
175
  };