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.
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "tap-the-sign",
3
+ "description": "Auto thermo sign-off after Plan mode plans. Requires thermo-nuclear-code-quality-review skill.",
4
+ "version": "0.2.0",
5
+ "author": {
6
+ "name": "tap-the-sign"
7
+ },
8
+ "hooks": "./hooks/hooks.claude.json",
9
+ "commands": "./commands/"
10
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "tap-the-sign",
3
+ "description": "Auto thermo sign-off after Plan mode (permission_mode plan). Requires thermo-nuclear-code-quality-review skill.",
4
+ "version": "0.2.0",
5
+ "hooks": "./hooks/hooks.codex.json"
6
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "tap-the-sign",
3
+ "displayName": "Tap the Sign",
4
+ "version": "0.2.0",
5
+ "description": "Auto thermo sign-off after Plan mode plans. Requires thermo-nuclear-code-quality-review skill.",
6
+ "author": {
7
+ "name": "tap-the-sign"
8
+ },
9
+ "license": "MIT",
10
+ "keywords": ["plan-mode", "hooks", "thermonuclear", "code-quality", "tap-the-sign"],
11
+ "hooks": "./hooks/hooks.cursor.json",
12
+ "commands": "./commands/"
13
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 tap-the-sign contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # Tap the Sign
2
+
3
+ Auto **thermo sign-off** on your plan before you build.
4
+
5
+ After Plan mode drafts a plan, tap-the-sign auto-sends a thermonuclear review follow-up and updates the plan with a **Thermonuclear pre-flight** section. Post-plan only — no pre-plan injection.
6
+
7
+ tap-the-sign is a standalone hook add-on. It does **not** bundle the thermonuclear review rubric — install [`thermo-nuclear-code-quality-review`](https://github.com/cursor/plugins/tree/main/cursor-team-kit/skills/thermo-nuclear-code-quality-review) separately.
8
+
9
+ ## What it does
10
+
11
+ 1. You enable the hook and submit a task in **Plan mode**.
12
+ 2. When the plan draft finishes, the hook auto-sends this follow-up:
13
+
14
+ ```text
15
+ @thermo-nuclear-code-quality-review
16
+
17
+ Read and apply the full rubric from the thermo-nuclear-code-quality-review skill
18
+ (code judo, 1k-line rule, spaghetti growth, HIGH/MID/LOW bar) to **this plan**
19
+ (not a diff yet).
20
+
21
+ Will this pass the next thermonuclear code review with no new items (especially HIGH or MID)?
22
+ Did you find all the code judo opportunities?
23
+ What changes would you make to improve confidence to high that this plan would pass
24
+ thermonuclear code review cleanly?
25
+ Include a **Thermonuclear pre-flight** section with this assessment in the plan.
26
+ Be careful to not introduce any blocker higher than LOW and checking three times
27
+ (three separate passes) for code judo opportunities.
28
+ On Pass 3: Thermo-nuclear subagent on final diff; zero HIGH/MID.
29
+ ```
30
+
31
+ 3. After the plan is updated with the pre-flight section, the hook stops (no infinite loop).
32
+
33
+ If the thermo skill is missing, planning still works; the auto follow-up is **skipped** with a warning in the Hooks output channel.
34
+
35
+ ## Quick start
36
+
37
+ ```bash
38
+ npx tap-the-sign install && npx tap-the-sign install-thermo && npx tap-the-sign on
39
+ npx tap-the-sign doctor
40
+ ```
41
+
42
+ **Bun:**
43
+
44
+ ```bash
45
+ bunx tap-the-sign install && bunx tap-the-sign install-thermo && bunx tap-the-sign on
46
+ ```
47
+
48
+ Use Plan mode in Cursor, Claude Code, or Codex.
49
+
50
+ ## Install paths
51
+
52
+ ### 1. npm / npx
53
+
54
+ ```bash
55
+ npx tap-the-sign install # all IDEs, project-local
56
+ npx tap-the-sign install --global # user-global (~/.cursor, ~/.claude, ~/.codex)
57
+ npx tap-the-sign install-thermo # skill only (recommended)
58
+ npx tap-the-sign install --no-codex # subset of IDEs
59
+ ```
60
+
61
+ ### 2. Bun / bunx
62
+
63
+ ```bash
64
+ bunx tap-the-sign install
65
+ bunx tap-the-sign install-thermo
66
+ bunx tap-the-sign on
67
+ ```
68
+
69
+ From a repo clone:
70
+
71
+ ```bash
72
+ git clone https://github.com/your-org/tap-the-sign.git
73
+ cd tap-the-sign
74
+ ./install.bun.sh
75
+ bun src/cli.mjs install-thermo && bun src/cli.mjs on
76
+ ```
77
+
78
+ Hook scripts prefer **Bun** at runtime when `bun` is on `PATH`, otherwise Node 18+.
79
+
80
+ ### 3. Git plugin (IDE-native)
81
+
82
+ | IDE | Install |
83
+ |-----|---------|
84
+ | **Cursor** | `/add-plugin your-org/tap-the-sign` |
85
+ | **Claude Code** | `/plugin marketplace add …` then `/plugin install tap-the-sign@…` |
86
+ | **Codex** | Install plugin; trust hooks via `/hooks` |
87
+
88
+ Then run `tap-the-sign on` (or `/tap-the-sign-on` in Cursor). Plugins ship wiring, not default-on.
89
+
90
+ **Thermo skill:** `tap-the-sign install-thermo` or `/add-plugin cursor-team-kit` (full plugin + subagent for Pass 3).
91
+
92
+ ### 4. curl / install.sh
93
+
94
+ ```bash
95
+ curl -fsSL https://raw.githubusercontent.com/your-org/tap-the-sign/main/install.sh | bash
96
+ # then:
97
+ npx tap-the-sign install-thermo && npx tap-the-sign on
98
+ ```
99
+
100
+ Or clone and run `./install.sh` (uses Bun if installed, else Node).
101
+
102
+ ## Thermo skill
103
+
104
+ **Recommended (skill only):**
105
+
106
+ ```bash
107
+ tap-the-sign install-thermo
108
+ # equivalent:
109
+ npx skills add cursor/plugins --skill thermo-nuclear-code-quality-review \
110
+ -a cursor -a claude-code -a codex --copy -y
111
+ ```
112
+
113
+ **Full plugin (includes thermo subagent for Pass 3):**
114
+
115
+ ```text
116
+ /add-plugin cursor-team-kit
117
+ ```
118
+
119
+ `install-thermo` installs the rubric (`SKILL.md`). The auto follow-up invokes the skill via `@thermo-nuclear-code-quality-review`. Pass 3 subagent requires `/add-plugin cursor-team-kit`.
120
+
121
+ ## Toggle
122
+
123
+ | Command | Action |
124
+ |---------|--------|
125
+ | `tap-the-sign on` | Enable hook |
126
+ | `tap-the-sign off` | Disable hook |
127
+ | `tap-the-sign status` | Show hook + skill status |
128
+ | `tap-the-sign doctor` | Fail if thermo skill missing |
129
+ | `tap-the-sign doctor --fix` | Run `install-thermo` if skill missing |
130
+ | `tap-the-sign install-thermo` | Install thermo skill via `npx skills add` |
131
+
132
+ **Cursor slash commands:** `/tap-the-sign-on`, `/tap-the-sign-off`, `/tap-the-sign-status`
133
+
134
+ ## Requirements
135
+
136
+ See [docs/REQUIREMENTS.md](docs/REQUIREMENTS.md).
137
+
138
+ - **Required for auto follow-up:** `thermo-nuclear-code-quality-review` skill
139
+ - **Local IDE only** — Cursor Cloud Agents do not run `stop` / `beforeSubmitPrompt` hooks
140
+ - **Codex:** review and trust hooks in `/hooks` after install
141
+
142
+ ## Plan mode detection
143
+
144
+ | IDE | Field |
145
+ |-----|-------|
146
+ | Cursor | `composer_mode === "plan"` |
147
+ | Claude Code | `permission_mode === "plan"` |
148
+ | Codex | `permission_mode === "plan"` |
149
+
150
+ ## Uninstall
151
+
152
+ ```bash
153
+ tap-the-sign uninstall
154
+ ```
155
+
156
+ Also removes legacy `plan-sandwich` hook entries if present.
157
+
158
+ ## License
159
+
160
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,2 @@
1
+ <!-- TAP_THE_SIGN_DISABLE -->
2
+ Disable the tap-the-sign hook.
@@ -0,0 +1,2 @@
1
+ <!-- TAP_THE_SIGN_ENABLE -->
2
+ Enable the tap-the-sign hook (auto thermo sign-off after Plan mode plans).
@@ -0,0 +1,2 @@
1
+ <!-- TAP_THE_SIGN_STATUS -->
2
+ Show tap-the-sign hook and thermo skill status.
@@ -0,0 +1,99 @@
1
+ # Requirements
2
+
3
+ ## Thermo skill (required for auto pre-flight)
4
+
5
+ tap-the-sign **references** but does **not** include the thermonuclear review rubric.
6
+
7
+ Install **`thermo-nuclear-code-quality-review`** separately.
8
+
9
+ ### Recommended: skill only
10
+
11
+ ```bash
12
+ tap-the-sign install-thermo
13
+ ```
14
+
15
+ This runs:
16
+
17
+ ```bash
18
+ npx skills add cursor/plugins \
19
+ --skill thermo-nuclear-code-quality-review \
20
+ -a cursor -a claude-code -a codex \
21
+ --copy \
22
+ -y
23
+ ```
24
+
25
+ ### Alternative: full cursor-team-kit plugin
26
+
27
+ ```text
28
+ /add-plugin cursor-team-kit
29
+ ```
30
+
31
+ Includes the thermo subagent used for Pass 3 in the auto follow-up. `install-thermo` installs the rubric only.
32
+
33
+ The hook follow-up invokes the skill via:
34
+
35
+ ```text
36
+ @thermo-nuclear-code-quality-review
37
+ ```
38
+
39
+ and instructs the agent to apply the full skill rubric to the plan.
40
+
41
+ Verify installation:
42
+
43
+ ```bash
44
+ tap-the-sign doctor
45
+ ```
46
+
47
+ ### If the skill is missing
48
+
49
+ | Step | Behavior |
50
+ |------|----------|
51
+ | Plan mode submit | Allowed — hook arms normally |
52
+ | Post-plan follow-up | **Skipped** — warning on stderr / systemMessage |
53
+ | `tap-the-sign doctor` | Exits non-zero with install instructions |
54
+ | `tap-the-sign doctor --fix` | Attempts `install-thermo` |
55
+
56
+ ## Runtime
57
+
58
+ - **Node.js 18+** or **Bun 1+** (CLI, hook scripts, and install)
59
+ - Hooks use Bun automatically when `bun` is on `PATH`, otherwise Node
60
+ - **Local agent session** (not Cursor Cloud Agents for this hook)
61
+
62
+ ## IDE hook support
63
+
64
+ | Hook event | Cursor | Claude Code | Codex |
65
+ |------------|--------|-------------|-------|
66
+ | Prompt submit (arm) | `beforeSubmitPrompt` | `UserPromptSubmit` | `UserPromptSubmit` |
67
+ | Post-plan follow-up | `stop` → `followup_message` | `Stop` → `decision: block` | `Stop` → `decision: block` |
68
+
69
+ ## Installed files (project-local default)
70
+
71
+ ```text
72
+ .cursor/hooks/tap-the-sign/ # hook scripts + runtime
73
+ .cursor/hooks.json # merged entries (tagged _tapTheSign)
74
+ .cursor/commands/tap-the-sign-*.md
75
+ .claude/settings.json # merged hooks
76
+ .codex/hooks.json
77
+ .codex/hooks/tap-the-sign/
78
+ .tap-the-sign/enabled # toggle flag (create with tap-the-sign on)
79
+ .tap-the-sign/state/ # per-session state (gitignored)
80
+ ```
81
+
82
+ ## Optional: global install
83
+
84
+ ```bash
85
+ tap-the-sign install --global
86
+ tap-the-sign install-thermo --global
87
+ tap-the-sign on --global
88
+ ```
89
+
90
+ Uses `~/.cursor/`, `~/.claude/`, `~/.codex/`, and `~/.config/tap-the-sign/`.
91
+
92
+ ## Skill discovery paths
93
+
94
+ `tap-the-sign doctor` searches for `thermo-nuclear-code-quality-review/SKILL.md` under:
95
+
96
+ - Project: `.agents/skills/`, `.cursor/skills/`, `.claude/skills/`
97
+ - Global: `~/.cursor/skills/`, `~/.codex/skills/`, `~/.cursor/plugins/` (and cache)
98
+
99
+ These cover `npx skills add` installs and cursor-team-kit plugin cache.
@@ -0,0 +1,28 @@
1
+ {
2
+ "hooks": {
3
+ "UserPromptSubmit": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "_tapTheSign": true,
8
+ "type": "command",
9
+ "command": "${CLAUDE_PLUGIN_ROOT}/hooks-bin/claude-arm.sh",
10
+ "timeout": 30
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "Stop": [
16
+ {
17
+ "hooks": [
18
+ {
19
+ "_tapTheSign": true,
20
+ "type": "command",
21
+ "command": "${CLAUDE_PLUGIN_ROOT}/hooks-bin/claude-stop.sh",
22
+ "timeout": 30
23
+ }
24
+ ]
25
+ }
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "hooks": {
3
+ "UserPromptSubmit": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "_tapTheSign": true,
8
+ "type": "command",
9
+ "command": "${PLUGIN_ROOT}/hooks-bin/codex-arm.sh",
10
+ "timeout": 30
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "Stop": [
16
+ {
17
+ "hooks": [
18
+ {
19
+ "_tapTheSign": true,
20
+ "type": "command",
21
+ "command": "${PLUGIN_ROOT}/hooks-bin/codex-stop.sh",
22
+ "timeout": 30
23
+ }
24
+ ]
25
+ }
26
+ ]
27
+ }
28
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "beforeSubmitPrompt": [
5
+ {
6
+ "_tapTheSign": true,
7
+ "command": "${CURSOR_PLUGIN_ROOT}/hooks-bin/cursor-arm.sh"
8
+ }
9
+ ],
10
+ "stop": [
11
+ {
12
+ "_tapTheSign": true,
13
+ "command": "${CURSOR_PLUGIN_ROOT}/hooks-bin/cursor-stop.sh",
14
+ "loop_limit": 1
15
+ }
16
+ ]
17
+ }
18
+ }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ # shellcheck source=/dev/null
5
+ source "$HOOKS_DIR/tap-the-sign-env.sh"
6
+ exec "${TAP_THE_SIGN_RUNTIME:-node}" "$HOOKS_DIR/run-hook.mjs" --event arm --host claude
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ # shellcheck source=/dev/null
5
+ source "$HOOKS_DIR/tap-the-sign-env.sh"
6
+ exec "${TAP_THE_SIGN_RUNTIME:-node}" "$HOOKS_DIR/run-hook.mjs" --event stop --host claude
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ # shellcheck source=/dev/null
5
+ source "$HOOKS_DIR/tap-the-sign-env.sh"
6
+ exec "${TAP_THE_SIGN_RUNTIME:-node}" "$HOOKS_DIR/run-hook.mjs" --event arm --host codex
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ # shellcheck source=/dev/null
5
+ source "$HOOKS_DIR/tap-the-sign-env.sh"
6
+ exec "${TAP_THE_SIGN_RUNTIME:-node}" "$HOOKS_DIR/run-hook.mjs" --event stop --host codex
@@ -0,0 +1,33 @@
1
+ export const SKILL_NAME = 'thermo-nuclear-code-quality-review';
2
+
3
+ export const SENTINEL_ENABLE = '<!-- TAP_THE_SIGN_ENABLE -->';
4
+ export const SENTINEL_DISABLE = '<!-- TAP_THE_SIGN_DISABLE -->';
5
+ export const SENTINEL_STATUS = '<!-- TAP_THE_SIGN_STATUS -->';
6
+
7
+ export const PHASE_IDLE = 'idle';
8
+ export const PHASE_PLANNING = 'planning';
9
+ export const PHASE_PREFLIGHT = 'preflight';
10
+ export const PHASE_DONE = 'done';
11
+
12
+ export const TAP_THE_SIGN_MARKER = '_tapTheSign';
13
+ export const LEGACY_MARKERS = ['_planSandwich', TAP_THE_SIGN_MARKER];
14
+
15
+ export const FOLLOW_UP_MESSAGE = `@thermo-nuclear-code-quality-review
16
+
17
+ Read and apply the full rubric from the thermo-nuclear-code-quality-review skill
18
+ (code judo, 1k-line rule, spaghetti growth, HIGH/MID/LOW bar) to **this plan**
19
+ (not a diff yet).
20
+
21
+ Will this pass the next thermonuclear code review with no new items (especially HIGH or MID)?
22
+ Did you find all the code judo opportunities?
23
+ What changes would you make to improve confidence to high that this plan would pass
24
+ thermonuclear code review cleanly?
25
+ Include a **Thermonuclear pre-flight** section with this assessment in the plan.
26
+ Be careful to not introduce any blocker higher than LOW and checking three times
27
+ (three separate passes) for code judo opportunities.
28
+ On Pass 3: Thermo-nuclear subagent on final diff; zero HIGH/MID.`;
29
+
30
+ export const SKILL_MISSING_WARNING =
31
+ 'tap-the-sign: thermo-nuclear-code-quality-review skill not found. ' +
32
+ 'Run: tap-the-sign install-thermo (or /add-plugin cursor-team-kit). ' +
33
+ 'Skipping auto pre-flight follow-up.';
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ # shellcheck source=/dev/null
5
+ source "$HOOKS_DIR/tap-the-sign-env.sh"
6
+ exec "${TAP_THE_SIGN_RUNTIME:-node}" "$HOOKS_DIR/run-hook.mjs" --event arm --host cursor
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ # shellcheck source=/dev/null
5
+ source "$HOOKS_DIR/tap-the-sign-env.sh"
6
+ exec "${TAP_THE_SIGN_RUNTIME:-node}" "$HOOKS_DIR/run-hook.mjs" --event stop --host cursor
@@ -0,0 +1,101 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ export const PACKAGE_ROOT = path.resolve(__dirname, '..');
8
+
9
+ let installScope = { global: false, projectRoot: null };
10
+
11
+ function initScopeFromEnv() {
12
+ if (process.env.TAP_THE_SIGN_GLOBAL === '1' || process.env.PLAN_SANDWICH_GLOBAL === '1') {
13
+ installScope = { global: true, projectRoot: os.homedir() };
14
+ return;
15
+ }
16
+ const projectRoot =
17
+ process.env.TAP_THE_SIGN_PROJECT_ROOT ?? process.env.PLAN_SANDWICH_PROJECT_ROOT;
18
+ if (projectRoot) {
19
+ installScope = { global: false, projectRoot };
20
+ }
21
+ }
22
+
23
+ initScopeFromEnv();
24
+
25
+ export function setInstallScope({ global = false, projectRoot = null } = {}) {
26
+ installScope = {
27
+ global,
28
+ projectRoot: projectRoot ?? findProjectRoot(process.cwd()),
29
+ };
30
+ }
31
+
32
+ export function getInstallScope() {
33
+ return { ...installScope };
34
+ }
35
+
36
+ export function findProjectRoot(startDir) {
37
+ let dir = path.resolve(startDir);
38
+ const root = path.parse(dir).root;
39
+ while (dir !== root) {
40
+ if (
41
+ fs.existsSync(path.join(dir, '.git')) ||
42
+ fs.existsSync(path.join(dir, '.cursor')) ||
43
+ fs.existsSync(path.join(dir, 'package.json'))
44
+ ) {
45
+ return dir;
46
+ }
47
+ dir = path.dirname(dir);
48
+ }
49
+ return path.resolve(startDir);
50
+ }
51
+
52
+ export function getProjectRoot() {
53
+ return installScope.projectRoot ?? findProjectRoot(process.cwd());
54
+ }
55
+
56
+ export function getConfigRoots() {
57
+ if (installScope.global) {
58
+ const home = os.homedir();
59
+ return {
60
+ projectRoot: home,
61
+ cursorHooksDir: path.join(home, '.cursor', 'hooks', 'tap-the-sign'),
62
+ cursorHooksJson: path.join(home, '.cursor', 'hooks.json'),
63
+ cursorCommandsDir: path.join(home, '.cursor', 'commands'),
64
+ claudeSettings: path.join(home, '.claude', 'settings.json'),
65
+ codexHooksDir: path.join(home, '.codex', 'hooks', 'tap-the-sign'),
66
+ codexHooksJson: path.join(home, '.codex', 'hooks.json'),
67
+ tapTheSignDir: path.join(home, '.config', 'tap-the-sign'),
68
+ global: true,
69
+ };
70
+ }
71
+
72
+ const projectRoot = getProjectRoot();
73
+ return {
74
+ projectRoot,
75
+ cursorHooksDir: path.join(projectRoot, '.cursor', 'hooks', 'tap-the-sign'),
76
+ cursorHooksJson: path.join(projectRoot, '.cursor', 'hooks.json'),
77
+ cursorCommandsDir: path.join(projectRoot, '.cursor', 'commands'),
78
+ claudeSettings: path.join(projectRoot, '.claude', 'settings.json'),
79
+ codexHooksDir: path.join(projectRoot, '.codex', 'hooks', 'tap-the-sign'),
80
+ codexHooksJson: path.join(projectRoot, '.codex', 'hooks.json'),
81
+ tapTheSignDir: path.join(projectRoot, '.tap-the-sign'),
82
+ global: false,
83
+ };
84
+ }
85
+
86
+ export function getEnabledPath() {
87
+ return path.join(getConfigRoots().tapTheSignDir, 'enabled');
88
+ }
89
+
90
+ export function getStateDir() {
91
+ return path.join(getConfigRoots().tapTheSignDir, 'state');
92
+ }
93
+
94
+ export function resolveInstalledRunner() {
95
+ const roots = getConfigRoots();
96
+ const runner = path.join(roots.cursorHooksDir, 'run-hook.mjs');
97
+ if (fs.existsSync(runner)) {
98
+ return runner;
99
+ }
100
+ return path.join(PACKAGE_ROOT, 'src', 'hooks', 'runner.mjs');
101
+ }