tap-the-sign 0.2.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/.claude-plugin/plugin.json +10 -0
- package/.codex-plugin/plugin.json +6 -0
- package/.cursor-plugin/plugin.json +13 -0
- package/LICENSE +21 -0
- package/README.md +160 -0
- package/commands/tap-the-sign-off.md +2 -0
- package/commands/tap-the-sign-on.md +2 -0
- package/commands/tap-the-sign-status.md +2 -0
- package/docs/REQUIREMENTS.md +99 -0
- package/hooks/hooks.claude.json +28 -0
- package/hooks/hooks.codex.json +28 -0
- package/hooks/hooks.cursor.json +18 -0
- package/hooks-bin/claude-arm.sh +6 -0
- package/hooks-bin/claude-stop.sh +6 -0
- package/hooks-bin/codex-arm.sh +6 -0
- package/hooks-bin/codex-stop.sh +6 -0
- package/hooks-bin/constants.mjs +33 -0
- package/hooks-bin/cursor-arm.sh +6 -0
- package/hooks-bin/cursor-stop.sh +6 -0
- package/hooks-bin/paths.mjs +101 -0
- package/hooks-bin/run-hook.mjs +175 -0
- package/hooks-bin/skill-check.mjs +70 -0
- package/hooks-bin/state.mjs +48 -0
- package/hooks-bin/tap-the-sign-env.sh +31 -0
- package/install.bun.sh +27 -0
- package/install.sh +28 -0
- package/package.json +52 -0
- package/scripts/sync-hooks-bin.mjs +20 -0
- package/src/cli.mjs +133 -0
- package/src/constants.mjs +33 -0
- package/src/hooks/runner.mjs +175 -0
- package/src/install-thermo.mjs +62 -0
- package/src/install.mjs +171 -0
- package/src/merge-config.mjs +95 -0
- package/src/paths.mjs +101 -0
- package/src/skill-check.mjs +70 -0
- package/src/state.mjs +48 -0
- package/src/uninstall.mjs +69 -0
package/src/state.mjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
PHASE_DONE,
|
|
5
|
+
PHASE_IDLE,
|
|
6
|
+
PHASE_PLANNING,
|
|
7
|
+
PHASE_PREFLIGHT,
|
|
8
|
+
} from './constants.mjs';
|
|
9
|
+
import { getStateDir } from './paths.mjs';
|
|
10
|
+
|
|
11
|
+
export function getSessionId(input) {
|
|
12
|
+
return (
|
|
13
|
+
input.conversation_id ??
|
|
14
|
+
input.session_id ??
|
|
15
|
+
input.parent_conversation_id ??
|
|
16
|
+
'unknown'
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function statePath(sessionId) {
|
|
21
|
+
const safe = sessionId.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
22
|
+
return path.join(getStateDir(), `${safe}.json`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function readState(sessionId) {
|
|
26
|
+
const file = statePath(sessionId);
|
|
27
|
+
if (!fs.existsSync(file)) {
|
|
28
|
+
return { phase: PHASE_IDLE };
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
32
|
+
} catch {
|
|
33
|
+
return { phase: PHASE_IDLE };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function writeState(sessionId, state) {
|
|
38
|
+
const dir = getStateDir();
|
|
39
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
40
|
+
fs.writeFileSync(statePath(sessionId), JSON.stringify(state, null, 2) + '\n');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function transitionPhase(sessionId, phase, extra = {}) {
|
|
44
|
+
const current = readState(sessionId);
|
|
45
|
+
writeState(sessionId, { ...current, phase, ...extra, updatedAt: new Date().toISOString() });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { PHASE_IDLE, PHASE_PLANNING, PHASE_PREFLIGHT, PHASE_DONE };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
readJsonFile,
|
|
5
|
+
stripTapTheSignFromClaudeHooks,
|
|
6
|
+
stripTapTheSignFromCursorHooks,
|
|
7
|
+
writeJsonFile,
|
|
8
|
+
} from './merge-config.mjs';
|
|
9
|
+
import { getConfigRoots, setInstallScope } from './paths.mjs';
|
|
10
|
+
|
|
11
|
+
function rmIfExists(p) {
|
|
12
|
+
if (fs.existsSync(p)) {
|
|
13
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const COMMAND_FILES = [
|
|
18
|
+
'tap-the-sign-on.md',
|
|
19
|
+
'tap-the-sign-off.md',
|
|
20
|
+
'tap-the-sign-status.md',
|
|
21
|
+
'plan-sandwich-on.md',
|
|
22
|
+
'plan-sandwich-off.md',
|
|
23
|
+
'plan-sandwich-status.md',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export function uninstall({
|
|
27
|
+
global = false,
|
|
28
|
+
projectRoot = null,
|
|
29
|
+
cursor = true,
|
|
30
|
+
claude = true,
|
|
31
|
+
codex = true,
|
|
32
|
+
} = {}) {
|
|
33
|
+
setInstallScope({ global, projectRoot });
|
|
34
|
+
const roots = getConfigRoots();
|
|
35
|
+
|
|
36
|
+
if (cursor) {
|
|
37
|
+
const existing = readJsonFile(roots.cursorHooksJson);
|
|
38
|
+
if (existing) {
|
|
39
|
+
writeJsonFile(roots.cursorHooksJson, stripTapTheSignFromCursorHooks(existing));
|
|
40
|
+
}
|
|
41
|
+
rmIfExists(roots.cursorHooksDir);
|
|
42
|
+
rmIfExists(path.join(roots.projectRoot, '.cursor', 'hooks', 'plan-sandwich'));
|
|
43
|
+
for (const cmd of COMMAND_FILES) {
|
|
44
|
+
const p = path.join(roots.cursorCommandsDir, cmd);
|
|
45
|
+
if (fs.existsSync(p)) fs.unlinkSync(p);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (claude) {
|
|
50
|
+
const existing = readJsonFile(roots.claudeSettings);
|
|
51
|
+
if (existing) {
|
|
52
|
+
writeJsonFile(roots.claudeSettings, {
|
|
53
|
+
...existing,
|
|
54
|
+
...stripTapTheSignFromClaudeHooks(existing),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (codex) {
|
|
60
|
+
const existing = readJsonFile(roots.codexHooksJson);
|
|
61
|
+
if (existing) {
|
|
62
|
+
writeJsonFile(roots.codexHooksJson, stripTapTheSignFromClaudeHooks(existing));
|
|
63
|
+
}
|
|
64
|
+
rmIfExists(roots.codexHooksDir);
|
|
65
|
+
rmIfExists(path.join(roots.projectRoot, '.codex', 'hooks', 'plan-sandwich'));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return roots;
|
|
69
|
+
}
|