proj-track 1.0.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/README.md +253 -0
- package/dist/commands/clear.d.ts +5 -0
- package/dist/commands/clear.d.ts.map +1 -0
- package/dist/commands/clear.js +15 -0
- package/dist/commands/clear.js.map +1 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +57 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +34 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/pause.d.ts +6 -0
- package/dist/commands/pause.d.ts.map +1 -0
- package/dist/commands/pause.js +24 -0
- package/dist/commands/pause.js.map +1 -0
- package/dist/commands/remove.d.ts +7 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +37 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/resume.d.ts +6 -0
- package/dist/commands/resume.d.ts.map +1 -0
- package/dist/commands/resume.js +24 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +39 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +42 -0
- package/dist/logger.js.map +1 -0
- package/dist/utils/file-handler.d.ts +36 -0
- package/dist/utils/file-handler.d.ts.map +1 -0
- package/dist/utils/file-handler.js +97 -0
- package/dist/utils/file-handler.js.map +1 -0
- package/dist/utils/project-detector.d.ts +17 -0
- package/dist/utils/project-detector.d.ts.map +1 -0
- package/dist/utils/project-detector.js +30 -0
- package/dist/utils/project-detector.js.map +1 -0
- package/dist/utils/security-filter.d.ts +10 -0
- package/dist/utils/security-filter.d.ts.map +1 -0
- package/dist/utils/security-filter.js +79 -0
- package/dist/utils/security-filter.js.map +1 -0
- package/dist/utils/shell-installer.d.ts +16 -0
- package/dist/utils/shell-installer.d.ts.map +1 -0
- package/dist/utils/shell-installer.js +232 -0
- package/dist/utils/shell-installer.js.map +1 -0
- package/package.json +78 -0
- package/scripts/preuninstall.js +97 -0
- package/scripts/release.sh +59 -0
- package/src/hooks/bash-hook.sh +67 -0
- package/src/hooks/zsh-hook.sh +54 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const START_MARKER = '# --- proj-track hook start ---';
|
|
5
|
+
const END_MARKER = '# --- proj-track hook end ---';
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
/**
|
|
9
|
+
* Get the path to the hooks directory (works in both dev and installed contexts).
|
|
10
|
+
*/
|
|
11
|
+
function getHooksDir() {
|
|
12
|
+
const packageRoot = path.resolve(__dirname, '..', '..');
|
|
13
|
+
const srcHooks = path.join(packageRoot, 'src', 'hooks');
|
|
14
|
+
if (fs.existsSync(srcHooks)) {
|
|
15
|
+
return srcHooks;
|
|
16
|
+
}
|
|
17
|
+
return path.join(packageRoot, 'hooks');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Detect which shell config files exist.
|
|
21
|
+
*/
|
|
22
|
+
function getShellConfigs() {
|
|
23
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
24
|
+
const configs = [];
|
|
25
|
+
const bashrc = path.join(home, '.bashrc');
|
|
26
|
+
const zshrc = path.join(home, '.zshrc');
|
|
27
|
+
if (fs.existsSync(bashrc))
|
|
28
|
+
configs.push(bashrc);
|
|
29
|
+
if (fs.existsSync(zshrc))
|
|
30
|
+
configs.push(zshrc);
|
|
31
|
+
if (configs.length === 0) {
|
|
32
|
+
configs.push(bashrc);
|
|
33
|
+
}
|
|
34
|
+
return configs;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Read the appropriate shell hook file content.
|
|
38
|
+
*/
|
|
39
|
+
function getHookContent(shell) {
|
|
40
|
+
const hooksDir = getHooksDir();
|
|
41
|
+
const hookFile = path.join(hooksDir, `${shell}-hook.sh`);
|
|
42
|
+
if (fs.existsSync(hookFile)) {
|
|
43
|
+
return fs.readFileSync(hookFile, 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
return shell === 'zsh' ? getInlineZshHook() : getInlineBashHook();
|
|
46
|
+
}
|
|
47
|
+
function getInlineBashHook() {
|
|
48
|
+
return `${START_MARKER}
|
|
49
|
+
# AUTO-CAPTURE via PROMPT_COMMAND (NOT DEBUG trap - doesn't break arrow keys)
|
|
50
|
+
|
|
51
|
+
# Cleanup any previous installation from shell memory first
|
|
52
|
+
if declare -f __proj_track_capture >/dev/null 2>&1; then
|
|
53
|
+
PROMPT_COMMAND="\${PROMPT_COMMAND//__proj_track_capture;/}"
|
|
54
|
+
PROMPT_COMMAND="\${PROMPT_COMMAND//__proj_track_capture/}"
|
|
55
|
+
unset -f __proj_track_capture 2>/dev/null
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
__proj_track_old_prompt="\${PROMPT_COMMAND:-}"
|
|
59
|
+
|
|
60
|
+
__proj_track_capture() {
|
|
61
|
+
if ! command -v proj-track-logger >/dev/null 2>&1; then
|
|
62
|
+
return
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
local last_cmd
|
|
66
|
+
last_cmd=$(HISTTIMEFORMAT='' builtin history 1 | sed 's/^[ ]*[0-9]*[ ]*//')
|
|
67
|
+
|
|
68
|
+
[ -z "$last_cmd" ] && return
|
|
69
|
+
|
|
70
|
+
[[ "$last_cmd" =~ ^proj-track ]] && return
|
|
71
|
+
[[ "$last_cmd" =~ ^__vsc ]] && return
|
|
72
|
+
[[ "$last_cmd" =~ ^__proj ]] && return
|
|
73
|
+
[[ "$last_cmd" =~ ^__git ]] && return
|
|
74
|
+
|
|
75
|
+
if [ -d ".git" ] || [ -f "package.json" ] || [ -f ".proj-track.json" ]; then
|
|
76
|
+
[ -f ".proj-track-disabled" ] && return
|
|
77
|
+
[ -f ".proj-track.json.paused" ] && return
|
|
78
|
+
(proj-track-logger "$last_cmd" >/dev/null 2>&1 &)
|
|
79
|
+
disown -a 2>/dev/null
|
|
80
|
+
fi
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if [ -n "$__proj_track_old_prompt" ]; then
|
|
84
|
+
PROMPT_COMMAND="__proj_track_capture; \${__proj_track_old_prompt}"
|
|
85
|
+
else
|
|
86
|
+
PROMPT_COMMAND='__proj_track_capture'
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
alias thistory='proj-track list 2>/dev/null'
|
|
90
|
+
alias trun='proj-track run'
|
|
91
|
+
alias tclear='proj-track clear'
|
|
92
|
+
alias tinit='proj-track init'
|
|
93
|
+
alias tremove='proj-track remove'
|
|
94
|
+
alias tpause='proj-track pause'
|
|
95
|
+
alias tresume='proj-track resume'
|
|
96
|
+
${END_MARKER}`;
|
|
97
|
+
}
|
|
98
|
+
function getInlineZshHook() {
|
|
99
|
+
return `${START_MARKER}
|
|
100
|
+
# AUTO-CAPTURE via preexec hook (Zsh native, no DEBUG trap)
|
|
101
|
+
|
|
102
|
+
if typeset -f __proj_track_preexec >/dev/null 2>&1; then
|
|
103
|
+
add-zsh-hook -d preexec __proj_track_preexec 2>/dev/null
|
|
104
|
+
unfunction __proj_track_preexec 2>/dev/null
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
__proj_track_preexec() {
|
|
108
|
+
local cmd="$1"
|
|
109
|
+
|
|
110
|
+
if ! command -v proj-track-logger >/dev/null 2>&1; then
|
|
111
|
+
return
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
[ -z "$cmd" ] && return
|
|
115
|
+
|
|
116
|
+
[[ "$cmd" =~ ^proj-track ]] && return
|
|
117
|
+
[[ "$cmd" =~ ^__vsc ]] && return
|
|
118
|
+
[[ "$cmd" =~ ^__proj ]] && return
|
|
119
|
+
[[ "$cmd" =~ ^__git ]] && return
|
|
120
|
+
|
|
121
|
+
if [ -d ".git" ] || [ -f "package.json" ] || [ -f ".proj-track.json" ]; then
|
|
122
|
+
[ -f ".proj-track-disabled" ] && return
|
|
123
|
+
[ -f ".proj-track.json.paused" ] && return
|
|
124
|
+
(proj-track-logger "$cmd" >/dev/null 2>&1 &)
|
|
125
|
+
disown 2>/dev/null
|
|
126
|
+
fi
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
autoload -Uz add-zsh-hook
|
|
130
|
+
add-zsh-hook preexec __proj_track_preexec
|
|
131
|
+
|
|
132
|
+
alias thistory='proj-track list 2>/dev/null'
|
|
133
|
+
alias trun='proj-track run'
|
|
134
|
+
alias tclear='proj-track clear'
|
|
135
|
+
alias tinit='proj-track init'
|
|
136
|
+
alias tremove='proj-track remove'
|
|
137
|
+
alias tpause='proj-track pause'
|
|
138
|
+
alias tresume='proj-track resume'
|
|
139
|
+
${END_MARKER}`;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if the hook is already installed in a config file.
|
|
143
|
+
*/
|
|
144
|
+
function isInstalled(configPath) {
|
|
145
|
+
if (!fs.existsSync(configPath))
|
|
146
|
+
return false;
|
|
147
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
148
|
+
return content.includes(START_MARKER);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Remove ALL proj-track related content from a config file.
|
|
152
|
+
* Uses line-by-line filtering to cleanly remove everything between
|
|
153
|
+
* start/end markers, including any orphaned partial blocks.
|
|
154
|
+
*/
|
|
155
|
+
function cleanConfig(configPath) {
|
|
156
|
+
if (!fs.existsSync(configPath))
|
|
157
|
+
return;
|
|
158
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
159
|
+
// Nothing to clean
|
|
160
|
+
if (!content.includes('proj-track'))
|
|
161
|
+
return;
|
|
162
|
+
const lines = content.split('\n');
|
|
163
|
+
const cleaned = [];
|
|
164
|
+
let insideBlock = false;
|
|
165
|
+
for (const line of lines) {
|
|
166
|
+
// Detect start of any proj-track block
|
|
167
|
+
if (line.includes('# --- proj-track') && line.includes('start ---')) {
|
|
168
|
+
insideBlock = true;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
// Detect end of any proj-track block
|
|
172
|
+
if (line.includes('# --- proj-track') && line.includes('end ---')) {
|
|
173
|
+
insideBlock = false;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
// Skip lines inside a block
|
|
177
|
+
if (insideBlock)
|
|
178
|
+
continue;
|
|
179
|
+
cleaned.push(line);
|
|
180
|
+
}
|
|
181
|
+
// Remove trailing blank lines that were left behind
|
|
182
|
+
while (cleaned.length > 0 && cleaned[cleaned.length - 1].trim() === '') {
|
|
183
|
+
cleaned.pop();
|
|
184
|
+
}
|
|
185
|
+
// Ensure file ends with a newline
|
|
186
|
+
const newContent = cleaned.join('\n') + '\n';
|
|
187
|
+
fs.writeFileSync(configPath, newContent, 'utf-8');
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Install the shell hook into .bashrc/.zshrc.
|
|
191
|
+
* Returns the list of files that were modified.
|
|
192
|
+
*/
|
|
193
|
+
export function installShellFunction() {
|
|
194
|
+
const configs = getShellConfigs();
|
|
195
|
+
const modified = [];
|
|
196
|
+
for (const configPath of configs) {
|
|
197
|
+
// Clean any existing proj-track content first
|
|
198
|
+
cleanConfig(configPath);
|
|
199
|
+
const shell = configPath.endsWith('.zshrc') ? 'zsh' : 'bash';
|
|
200
|
+
const hookContent = getHookContent(shell);
|
|
201
|
+
fs.appendFileSync(configPath, `\n${hookContent}\n`, 'utf-8');
|
|
202
|
+
modified.push(configPath);
|
|
203
|
+
}
|
|
204
|
+
return modified;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Uninstall the shell hook from all config files.
|
|
208
|
+
* Cleanly removes ALL proj-track content — no leftovers.
|
|
209
|
+
* Returns the list of files that were modified.
|
|
210
|
+
*/
|
|
211
|
+
export function uninstallShellFunction() {
|
|
212
|
+
const configs = getShellConfigs();
|
|
213
|
+
const modified = [];
|
|
214
|
+
for (const configPath of configs) {
|
|
215
|
+
if (!fs.existsSync(configPath))
|
|
216
|
+
continue;
|
|
217
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
218
|
+
if (!content.includes('proj-track'))
|
|
219
|
+
continue;
|
|
220
|
+
cleanConfig(configPath);
|
|
221
|
+
modified.push(configPath);
|
|
222
|
+
}
|
|
223
|
+
return modified;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Check if the shell hook is installed in any config file.
|
|
227
|
+
*/
|
|
228
|
+
export function isShellFunctionInstalled() {
|
|
229
|
+
const configs = getShellConfigs();
|
|
230
|
+
return configs.some(c => isInstalled(c));
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=shell-installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-installer.js","sourceRoot":"","sources":["../../src/utils/shell-installer.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "proj-track",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Auto-capture CLI command history per-project with zero terminal interference.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"proj-track": "dist/index.js",
|
|
9
|
+
"proj-track-logger": "dist/logger.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"test": "NODE_OPTIONS='--experimental-vm-modules' jest",
|
|
15
|
+
"test:watch": "NODE_OPTIONS='--experimental-vm-modules' jest --watch",
|
|
16
|
+
"lint": "tsc --noEmit",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"preuninstall": "node scripts/preuninstall.js || true",
|
|
19
|
+
"docs:dev": "vitepress dev docs",
|
|
20
|
+
"docs:build": "vitepress build docs",
|
|
21
|
+
"docs:preview": "vitepress preview docs"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"cli",
|
|
25
|
+
"command-history",
|
|
26
|
+
"project-tracker",
|
|
27
|
+
"terminal",
|
|
28
|
+
"developer-tools",
|
|
29
|
+
"shell-history",
|
|
30
|
+
"bash",
|
|
31
|
+
"zsh",
|
|
32
|
+
"auto-capture",
|
|
33
|
+
"prompt-command",
|
|
34
|
+
"devtools",
|
|
35
|
+
"command-logger",
|
|
36
|
+
"project-history",
|
|
37
|
+
"workflow",
|
|
38
|
+
"productivity",
|
|
39
|
+
"shell-hook",
|
|
40
|
+
"terminal-history",
|
|
41
|
+
"command-tracking",
|
|
42
|
+
"nodejs",
|
|
43
|
+
"typescript"
|
|
44
|
+
],
|
|
45
|
+
"author": {
|
|
46
|
+
"name": "Ali Raza",
|
|
47
|
+
"url": "https://github.com/Ali-Raza-Arain"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://Ali-Raza-Arain.github.io/proj-track/",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/Ali-Raza-Arain/proj-track.git"
|
|
53
|
+
},
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/Ali-Raza-Arain/proj-track/issues"
|
|
56
|
+
},
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"chalk": "^5.3.0",
|
|
60
|
+
"commander": "^12.1.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/jest": "^30.0.0",
|
|
64
|
+
"@types/node": "^22.0.0",
|
|
65
|
+
"jest": "^30.3.0",
|
|
66
|
+
"ts-jest": "^29.4.6",
|
|
67
|
+
"typescript": "^5.6.0",
|
|
68
|
+
"vitepress": "^1.6.4"
|
|
69
|
+
},
|
|
70
|
+
"files": [
|
|
71
|
+
"dist",
|
|
72
|
+
"src/hooks",
|
|
73
|
+
"scripts"
|
|
74
|
+
],
|
|
75
|
+
"engines": {
|
|
76
|
+
"node": ">=18.0.0"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pre-uninstall script for proj-track.
|
|
5
|
+
* Runs on `npm uninstall -g proj-track` (even with sudo).
|
|
6
|
+
*
|
|
7
|
+
* Handles the sudo case: when user runs `sudo npm uninstall -g`,
|
|
8
|
+
* HOME=/root but the real user's shell config is in /home/<user>.
|
|
9
|
+
* We use SUDO_USER to find the correct home directory.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
import path from 'node:path';
|
|
14
|
+
import { execSync } from 'node:child_process';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the real user's home directory, even when running under sudo.
|
|
18
|
+
*/
|
|
19
|
+
function getRealHome() {
|
|
20
|
+
const sudoUser = process.env.SUDO_USER;
|
|
21
|
+
|
|
22
|
+
if (sudoUser) {
|
|
23
|
+
// Running under sudo — resolve real user's home
|
|
24
|
+
try {
|
|
25
|
+
const home = execSync(`eval echo ~${sudoUser}`, { encoding: 'utf-8' }).trim();
|
|
26
|
+
if (home && fs.existsSync(home)) {
|
|
27
|
+
return home;
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
// Fall through
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Fallback: common Linux home path
|
|
34
|
+
const linuxHome = `/home/${sudoUser}`;
|
|
35
|
+
if (fs.existsSync(linuxHome)) {
|
|
36
|
+
return linuxHome;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Not sudo — use normal HOME
|
|
41
|
+
return process.env.HOME || process.env.USERPROFILE || '';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Remove all proj-track content from a shell config file.
|
|
46
|
+
*/
|
|
47
|
+
function cleanConfig(configPath) {
|
|
48
|
+
if (!fs.existsSync(configPath)) return false;
|
|
49
|
+
|
|
50
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
51
|
+
if (!content.includes('proj-track')) return false;
|
|
52
|
+
|
|
53
|
+
const lines = content.split('\n');
|
|
54
|
+
const cleaned = [];
|
|
55
|
+
let insideBlock = false;
|
|
56
|
+
|
|
57
|
+
for (const line of lines) {
|
|
58
|
+
if (line.includes('# --- proj-track') && line.includes('start ---')) {
|
|
59
|
+
insideBlock = true;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (line.includes('# --- proj-track') && line.includes('end ---')) {
|
|
63
|
+
insideBlock = false;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (insideBlock) continue;
|
|
67
|
+
cleaned.push(line);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Remove trailing blank lines
|
|
71
|
+
while (cleaned.length > 0 && cleaned[cleaned.length - 1].trim() === '') {
|
|
72
|
+
cleaned.pop();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
fs.writeFileSync(configPath, cleaned.join('\n') + '\n', 'utf-8');
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// --- Main ---
|
|
80
|
+
try {
|
|
81
|
+
const home = getRealHome();
|
|
82
|
+
if (!home) process.exit(0);
|
|
83
|
+
|
|
84
|
+
const configs = [
|
|
85
|
+
path.join(home, '.bashrc'),
|
|
86
|
+
path.join(home, '.zshrc'),
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
for (const configPath of configs) {
|
|
90
|
+
if (cleanConfig(configPath)) {
|
|
91
|
+
console.log(`proj-track: cleaned ${configPath}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} catch {
|
|
95
|
+
// Silent exit — never block npm uninstall
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# ============================================================
|
|
5
|
+
# Release Script for proj-track
|
|
6
|
+
# Usage: ./scripts/release.sh [patch|minor|major]
|
|
7
|
+
# Default: patch
|
|
8
|
+
# ============================================================
|
|
9
|
+
|
|
10
|
+
BUMP="${1:-patch}"
|
|
11
|
+
|
|
12
|
+
echo "==> Running lint..."
|
|
13
|
+
npm run lint
|
|
14
|
+
|
|
15
|
+
echo "==> Running tests with coverage..."
|
|
16
|
+
npm test -- --coverage
|
|
17
|
+
echo ""
|
|
18
|
+
|
|
19
|
+
echo "==> Building package..."
|
|
20
|
+
npm run build
|
|
21
|
+
|
|
22
|
+
echo "==> Building docs..."
|
|
23
|
+
npm run docs:build
|
|
24
|
+
|
|
25
|
+
echo "==> Bumping version ($BUMP)..."
|
|
26
|
+
NEW_VERSION=$(npm version "$BUMP" --no-git-tag-version | tr -d 'v')
|
|
27
|
+
echo " New version: $NEW_VERSION"
|
|
28
|
+
|
|
29
|
+
echo "==> Publishing to npm..."
|
|
30
|
+
npm publish
|
|
31
|
+
|
|
32
|
+
echo "==> Staging changes..."
|
|
33
|
+
git add package.json package-lock.json
|
|
34
|
+
|
|
35
|
+
echo "==> Committing..."
|
|
36
|
+
git commit -m "$NEW_VERSION"
|
|
37
|
+
|
|
38
|
+
echo "==> Creating annotated tag..."
|
|
39
|
+
git tag -a "v$NEW_VERSION" -m "v$NEW_VERSION"
|
|
40
|
+
|
|
41
|
+
echo "==> Pushing commit + tag..."
|
|
42
|
+
git push origin main --follow-tags
|
|
43
|
+
|
|
44
|
+
echo "==> Creating GitHub Release..."
|
|
45
|
+
gh release create "v$NEW_VERSION" \
|
|
46
|
+
--title "v$NEW_VERSION" \
|
|
47
|
+
--generate-notes
|
|
48
|
+
|
|
49
|
+
echo ""
|
|
50
|
+
echo "============================================"
|
|
51
|
+
echo " Released v$NEW_VERSION successfully!"
|
|
52
|
+
echo "============================================"
|
|
53
|
+
echo ""
|
|
54
|
+
echo "Post-release checklist:"
|
|
55
|
+
echo " 1. Update CHANGELOG.md with release details"
|
|
56
|
+
echo " 2. Verify Codecov badge updated (https://codecov.io/gh/Ali-Raza-Arain/proj-track)"
|
|
57
|
+
echo " 3. Verify docs deployed (https://Ali-Raza-Arain.github.io/proj-track/)"
|
|
58
|
+
echo " 4. Update GitHub repo 'About' description if needed"
|
|
59
|
+
echo ""
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# --- proj-track hook start ---
|
|
2
|
+
# AUTO-CAPTURE via PROMPT_COMMAND (NOT DEBUG trap - doesn't break arrow keys)
|
|
3
|
+
|
|
4
|
+
# Cleanup any previous installation from shell memory first
|
|
5
|
+
if declare -f __proj_track_capture >/dev/null 2>&1; then
|
|
6
|
+
# Remove old function from PROMPT_COMMAND
|
|
7
|
+
PROMPT_COMMAND="${PROMPT_COMMAND//__proj_track_capture;/}"
|
|
8
|
+
PROMPT_COMMAND="${PROMPT_COMMAND//__proj_track_capture/}"
|
|
9
|
+
unset -f __proj_track_capture 2>/dev/null
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# Store the original PROMPT_COMMAND so we don't clobber it
|
|
13
|
+
__proj_track_old_prompt="${PROMPT_COMMAND:-}"
|
|
14
|
+
|
|
15
|
+
__proj_track_capture() {
|
|
16
|
+
# Guard: if proj-track-logger is not installed, disable self
|
|
17
|
+
if ! command -v proj-track-logger >/dev/null 2>&1; then
|
|
18
|
+
return
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Get the last command from bash history (strip leading number + spaces)
|
|
22
|
+
local last_cmd
|
|
23
|
+
last_cmd=$(HISTTIMEFORMAT='' builtin history 1 | sed 's/^[ ]*[0-9]*[ ]*//')
|
|
24
|
+
|
|
25
|
+
# Skip empty
|
|
26
|
+
[ -z "$last_cmd" ] && return
|
|
27
|
+
|
|
28
|
+
# Skip proj-track's own commands (prevent self-tracking)
|
|
29
|
+
[[ "$last_cmd" =~ ^proj-track ]] && return
|
|
30
|
+
|
|
31
|
+
# Skip VS Code internal commands
|
|
32
|
+
[[ "$last_cmd" =~ ^__vsc ]] && return
|
|
33
|
+
[[ "$last_cmd" =~ ^__proj ]] && return
|
|
34
|
+
[[ "$last_cmd" =~ ^__git ]] && return
|
|
35
|
+
|
|
36
|
+
# Check if in a project directory (.git, package.json, or .proj-track.json)
|
|
37
|
+
if [ -d ".git" ] || [ -f "package.json" ] || [ -f ".proj-track.json" ]; then
|
|
38
|
+
# Check if permanently disabled (proj-track remove)
|
|
39
|
+
[ -f ".proj-track-disabled" ] && return
|
|
40
|
+
|
|
41
|
+
# Check if paused
|
|
42
|
+
[ -f ".proj-track.json.paused" ] && return
|
|
43
|
+
|
|
44
|
+
# Run logger in SUBSHELL with full suppression (NO job control messages)
|
|
45
|
+
(proj-track-logger "$last_cmd" >/dev/null 2>&1 &)
|
|
46
|
+
|
|
47
|
+
# Disown to prevent "[1]+ Done" messages
|
|
48
|
+
disown -a 2>/dev/null
|
|
49
|
+
fi
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Chain with existing PROMPT_COMMAND (don't clobber git prompt, etc.)
|
|
53
|
+
if [ -n "$__proj_track_old_prompt" ]; then
|
|
54
|
+
PROMPT_COMMAND="__proj_track_capture; ${__proj_track_old_prompt}"
|
|
55
|
+
else
|
|
56
|
+
PROMPT_COMMAND='__proj_track_capture'
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Convenience aliases (manual commands still available)
|
|
60
|
+
alias thistory='proj-track list 2>/dev/null'
|
|
61
|
+
alias trun='proj-track run'
|
|
62
|
+
alias tclear='proj-track clear'
|
|
63
|
+
alias tinit='proj-track init'
|
|
64
|
+
alias tremove='proj-track remove'
|
|
65
|
+
alias tpause='proj-track pause'
|
|
66
|
+
alias tresume='proj-track resume'
|
|
67
|
+
# --- proj-track hook end ---
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# --- proj-track hook start ---
|
|
2
|
+
# AUTO-CAPTURE via preexec hook (Zsh native, no DEBUG trap)
|
|
3
|
+
|
|
4
|
+
# Cleanup any previous installation from shell memory first
|
|
5
|
+
if typeset -f __proj_track_preexec >/dev/null 2>&1; then
|
|
6
|
+
add-zsh-hook -d preexec __proj_track_preexec 2>/dev/null
|
|
7
|
+
unfunction __proj_track_preexec 2>/dev/null
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
__proj_track_preexec() {
|
|
11
|
+
local cmd="$1"
|
|
12
|
+
|
|
13
|
+
# Guard: if proj-track-logger is not installed, disable self
|
|
14
|
+
if ! command -v proj-track-logger >/dev/null 2>&1; then
|
|
15
|
+
return
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Skip empty
|
|
19
|
+
[ -z "$cmd" ] && return
|
|
20
|
+
|
|
21
|
+
# Skip proj-track's own commands
|
|
22
|
+
[[ "$cmd" =~ ^proj-track ]] && return
|
|
23
|
+
|
|
24
|
+
# Skip VS Code internal commands
|
|
25
|
+
[[ "$cmd" =~ ^__vsc ]] && return
|
|
26
|
+
[[ "$cmd" =~ ^__proj ]] && return
|
|
27
|
+
[[ "$cmd" =~ ^__git ]] && return
|
|
28
|
+
|
|
29
|
+
# Check if in a project directory
|
|
30
|
+
if [ -d ".git" ] || [ -f "package.json" ] || [ -f ".proj-track.json" ]; then
|
|
31
|
+
# Check if permanently disabled (proj-track remove)
|
|
32
|
+
[ -f ".proj-track-disabled" ] && return
|
|
33
|
+
|
|
34
|
+
# Check if paused
|
|
35
|
+
[ -f ".proj-track.json.paused" ] && return
|
|
36
|
+
|
|
37
|
+
# Silent execution in subshell
|
|
38
|
+
(proj-track-logger "$cmd" >/dev/null 2>&1 &)
|
|
39
|
+
disown 2>/dev/null
|
|
40
|
+
fi
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
autoload -Uz add-zsh-hook
|
|
44
|
+
add-zsh-hook preexec __proj_track_preexec
|
|
45
|
+
|
|
46
|
+
# Convenience aliases
|
|
47
|
+
alias thistory='proj-track list 2>/dev/null'
|
|
48
|
+
alias trun='proj-track run'
|
|
49
|
+
alias tclear='proj-track clear'
|
|
50
|
+
alias tinit='proj-track init'
|
|
51
|
+
alias tremove='proj-track remove'
|
|
52
|
+
alias tpause='proj-track pause'
|
|
53
|
+
alias tresume='proj-track resume'
|
|
54
|
+
# --- proj-track hook end ---
|