@ranger-testing/ranger-cli 1.1.6 → 2.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 +47 -45
- package/build/cli.js +671 -291
- package/build/cli.js.map +1 -1
- package/build/commands/addEnv.js +1 -1
- package/build/commands/addEnv.js.map +1 -1
- package/build/commands/authEncrypt.js +5 -10
- package/build/commands/authEncrypt.js.map +1 -1
- package/build/commands/clean.js +1 -1
- package/build/commands/clean.js.map +1 -1
- package/build/commands/config.js +9 -15
- package/build/commands/config.js.map +1 -1
- package/build/commands/env.js +10 -13
- package/build/commands/env.js.map +1 -1
- package/build/commands/feature.js +138 -67
- package/build/commands/feature.js.map +1 -1
- package/build/commands/hook.js +9 -4
- package/build/commands/hook.js.map +1 -1
- package/build/commands/hooks/autoPrompt.js +32 -0
- package/build/commands/hooks/autoPrompt.js.map +1 -0
- package/build/commands/hooks/disable.js +8 -5
- package/build/commands/hooks/disable.js.map +1 -1
- package/build/commands/hooks/enable.js +16 -9
- package/build/commands/hooks/enable.js.map +1 -1
- package/build/commands/hooks/exitPlanMode.js +10 -10
- package/build/commands/hooks/exitPlanMode.js.map +1 -1
- package/build/commands/hooks/index.js +1 -0
- package/build/commands/hooks/index.js.map +1 -1
- package/build/commands/hooks/output.js +20 -2
- package/build/commands/hooks/output.js.map +1 -1
- package/build/commands/hooks/planReminder.js +9 -9
- package/build/commands/hooks/planReminder.js.map +1 -1
- package/build/commands/hooks/planStart.js +6 -6
- package/build/commands/hooks/planStart.js.map +1 -1
- package/build/commands/hooks/postEdit.js +6 -6
- package/build/commands/hooks/postEdit.js.map +1 -1
- package/build/commands/hooks/preCompact.js +5 -5
- package/build/commands/hooks/preCompact.js.map +1 -1
- package/build/commands/hooks/sessionEnd.js +8 -4
- package/build/commands/hooks/sessionEnd.js.map +1 -1
- package/build/commands/hooks/sessionStart.js +41 -25
- package/build/commands/hooks/sessionStart.js.map +1 -1
- package/build/commands/hooks/stopHook.js +30 -6
- package/build/commands/hooks/stopHook.js.map +1 -1
- package/build/commands/index.js +1 -2
- package/build/commands/index.js.map +1 -1
- package/build/commands/login.js +2 -5
- package/build/commands/login.js.map +1 -1
- package/build/commands/setupCi.js +189 -0
- package/build/commands/setupCi.js.map +1 -0
- package/build/commands/skillup.js +16 -68
- package/build/commands/skillup.js.map +1 -1
- package/build/commands/start.js +1 -1
- package/build/commands/start.js.map +1 -1
- package/build/commands/status.js +14 -13
- package/build/commands/status.js.map +1 -1
- package/build/commands/update.js +34 -5
- package/build/commands/update.js.map +1 -1
- package/build/commands/updateEnv.js +1 -1
- package/build/commands/updateEnv.js.map +1 -1
- package/build/commands/useEnv.js +1 -1
- package/build/commands/useEnv.js.map +1 -1
- package/build/commands/utils/activeProfile.js +76 -0
- package/build/commands/utils/activeProfile.js.map +1 -0
- package/build/commands/utils/browserSessionsApi.js +1 -1
- package/build/commands/utils/browserSessionsApi.js.map +1 -1
- package/build/commands/utils/desirePathLog.js +39 -34
- package/build/commands/utils/desirePathLog.js.map +1 -1
- package/build/commands/utils/deviceAuth.js +53 -5
- package/build/commands/utils/deviceAuth.js.map +1 -1
- package/build/commands/utils/environment.js +11 -12
- package/build/commands/utils/environment.js.map +1 -1
- package/build/commands/utils/featureApi.js +49 -46
- package/build/commands/utils/featureApi.js.map +1 -1
- package/build/commands/utils/featureReportGenerator.js +6 -6
- package/build/commands/utils/featureReportGenerator.js.map +1 -1
- package/build/commands/utils/keychain.js +1 -1
- package/build/commands/utils/localAgentInstallationsApi.js +1 -1
- package/build/commands/utils/profileMessages.js +8 -0
- package/build/commands/utils/profileMessages.js.map +1 -0
- package/build/commands/utils/profileSetupBanner.js +167 -0
- package/build/commands/utils/profileSetupBanner.js.map +1 -0
- package/build/commands/utils/retry.js +25 -0
- package/build/commands/utils/retry.js.map +1 -0
- package/build/commands/utils/sessionCache.js +17 -0
- package/build/commands/utils/sessionCache.js.map +1 -1
- package/build/commands/utils/settings.js +23 -2
- package/build/commands/utils/settings.js.map +1 -1
- package/build/commands/utils/skills.js +1 -1
- package/build/commands/utils/telemetry.js +254 -0
- package/build/commands/utils/telemetry.js.map +1 -0
- package/build/commands/utils/userApi.js +4 -4
- package/build/commands/utils/userApi.js.map +1 -1
- package/build/commands/verifyFeature.js +678 -407
- package/build/commands/verifyFeature.js.map +1 -1
- package/build/commands/verifyInBrowser.js +1 -1
- package/build/commands/verifyInBrowser.js.map +1 -1
- package/build/skills/ranger/SKILL.md +65 -64
- package/build/skills/ranger/create.md +31 -31
- package/build/skills/ranger/feedback.md +25 -17
- package/build/skills/ranger/start.md +37 -37
- package/build/skills/ranger/verify.md +59 -55
- package/package.json +1 -1
- package/scripts/postinstall.js +1 -1
- package/build/commands/dataMcpServer.js +0 -1
- package/build/commands/dataMcpServer.js.map +0 -1
- package/build/commands/utils/cliSecret.js +0 -1
- package/build/commands/utils/cliSecret.js.map +0 -1
- package/build/skills/bug-bash.md +0 -329
- package/build/skills/e2e-test-recommender.md +0 -168
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { disableSession, disableBranch, getCurrentBranch, } from '../utils/sessionCache.js';
|
|
2
2
|
import { printBlock } from './output.js';
|
|
3
3
|
/**
|
|
4
|
-
* Disable hook - disables Ranger hooks for
|
|
4
|
+
* Disable hook - disables Ranger hooks for the current session and current branch.
|
|
5
|
+
* Session ID is resolved from the optional parameter (OpenCode --session-id),
|
|
6
|
+
* falling back to CLAUDE_SESSION_ID env var (Claude Code).
|
|
5
7
|
*/
|
|
6
|
-
export async function disable() {
|
|
7
|
-
const sessionId = process.env.CLAUDE_SESSION_ID || '';
|
|
8
|
+
export async function disable(sessionIdOverride) {
|
|
9
|
+
const sessionId = sessionIdOverride || process.env.CLAUDE_SESSION_ID || '';
|
|
8
10
|
if (!sessionId) {
|
|
9
|
-
console.error('Error:
|
|
11
|
+
console.error('Error: No session ID available.');
|
|
12
|
+
console.error('Provide --session-id or ensure CLAUDE_SESSION_ID is set.');
|
|
10
13
|
process.exit(1);
|
|
11
14
|
}
|
|
12
15
|
// Disable hooks for this session
|
|
@@ -23,7 +26,7 @@ The user has expressly disabled Ranger hooks for this session${branch && branch
|
|
|
23
26
|
**IMPORTANT INSTRUCTIONS:**
|
|
24
27
|
- Do NOT use the /ranger skill
|
|
25
28
|
- Do NOT use any \`ranger\` CLI commands
|
|
26
|
-
- Proceed with your task without tracking
|
|
29
|
+
- Proceed with your task without tracking feature reviews using the Ranger CLI
|
|
27
30
|
|
|
28
31
|
To re-enable Ranger, run \`/ranger:enable\`.`);
|
|
29
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"disable.js","sourceRoot":"","sources":["../../../src/commands/hooks/disable.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,cAAc,EACd,aAAa,EACb,gBAAgB,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC
|
|
1
|
+
{"version":3,"file":"disable.js","sourceRoot":"","sources":["../../../src/commands/hooks/disable.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,cAAc,EACd,aAAa,EACb,gBAAgB,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,iBAA0B;IACpD,MAAM,SAAS,GAAG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAE3E,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACjD,OAAO,CAAC,KAAK,CACT,0DAA0D,CAC7D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,iCAAiC;IACjC,cAAc,CAAC,SAAS,CAAC,CAAC;IAE1B,wDAAwD;IACxD,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,IAAI,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACrD,aAAa,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAED,UAAU,CAAC;;+DAEgD,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE;;;;;;;6CAOrG,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -4,13 +4,15 @@ import { getRangerSkillContent } from '../utils/skillContent.js';
|
|
|
4
4
|
import { printBlock } from './output.js';
|
|
5
5
|
import { update } from '../update.js';
|
|
6
6
|
/**
|
|
7
|
-
* Enable hook - enables Ranger hooks for
|
|
7
|
+
* Enable hook - enables Ranger hooks for the current session.
|
|
8
|
+
* Session ID is resolved from the optional parameter (OpenCode --session-id),
|
|
9
|
+
* falling back to CLAUDE_SESSION_ID env var (Claude Code).
|
|
8
10
|
*/
|
|
9
|
-
export async function enable() {
|
|
10
|
-
const sessionId = process.env.CLAUDE_SESSION_ID || '';
|
|
11
|
+
export async function enable(sessionIdOverride) {
|
|
12
|
+
const sessionId = sessionIdOverride || process.env.CLAUDE_SESSION_ID || '';
|
|
11
13
|
if (!sessionId) {
|
|
12
|
-
console.error('Error:
|
|
13
|
-
console.error('
|
|
14
|
+
console.error('Error: No session ID available.');
|
|
15
|
+
console.error('Provide --session-id or ensure CLAUDE_SESSION_ID is set.');
|
|
14
16
|
process.exit(1);
|
|
15
17
|
}
|
|
16
18
|
// Check if CLI is configured (has token)
|
|
@@ -22,13 +24,18 @@ The Ranger CLI is not configured. To get started:
|
|
|
22
24
|
|
|
23
25
|
1. Install: \`npm install -g @ranger-testing/ranger-cli\`
|
|
24
26
|
2. Get token: https://dashboard.ranger.net/cli
|
|
25
|
-
3. Initialize: \`ranger
|
|
27
|
+
3. Initialize: \`ranger setup [token]\`
|
|
26
28
|
|
|
27
29
|
Restart your Claude Code session after setup.`);
|
|
28
30
|
return;
|
|
29
31
|
}
|
|
30
32
|
// Run ranger update to ensure CLI and skills are up to date
|
|
31
|
-
|
|
33
|
+
try {
|
|
34
|
+
await update();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Non-fatal — don't block hook enablement if update check fails
|
|
38
|
+
}
|
|
32
39
|
// Enable hooks for this session (and auto-enable branch if not on main)
|
|
33
40
|
enableSession(sessionId);
|
|
34
41
|
const branch = getCurrentBranch();
|
|
@@ -45,7 +52,7 @@ ${skillContent}
|
|
|
45
52
|
|
|
46
53
|
## Quick Reference
|
|
47
54
|
|
|
48
|
-
**In plan mode:** Include Ranger Feature Specification at end of plan.
|
|
49
|
-
**Not in plan mode:** Run \`ranger
|
|
55
|
+
**In plan mode:** Include Ranger Feature Review Specification at end of plan.
|
|
56
|
+
**Not in plan mode:** Run \`ranger create\` FIRST, then verify with \`ranger go\`.`);
|
|
50
57
|
}
|
|
51
58
|
//# sourceMappingURL=enable.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enable.js","sourceRoot":"","sources":["../../../src/commands/hooks/enable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC
|
|
1
|
+
{"version":3,"file":"enable.js","sourceRoot":"","sources":["../../../src/commands/hooks/enable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,iBAA0B;IACnD,MAAM,SAAS,GAAG,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAE3E,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACjD,OAAO,CAAC,KAAK,CACT,0DAA0D,CAC7D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,yCAAyC;IACzC,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,UAAU,CAAC;;;;;;;;8CAQ2B,CAAC,CAAC;QACxC,OAAO;IACX,CAAC;IAED,4DAA4D;IAC5D,IAAI,CAAC;QACD,MAAM,MAAM,EAAE,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACL,gEAAgE;IACpE,CAAC;IAED,wEAAwE;IACxE,aAAa,CAAC,SAAS,CAAC,CAAC;IAEzB,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,MAAM,UAAU,GACZ,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,QAAQ;QAC9C,CAAC,CAAC,iBAAiB,MAAM,8EAA8E;QACvG,CAAC,CAAC,EAAE,CAAC;IAEb,0BAA0B;IAC1B,MAAM,YAAY,GAAG,qBAAqB,EAAE,CAAC;IAE7C,UAAU,CAAC,mBAAmB,UAAU;;;;EAI1C,YAAY;;;;;mFAKqE,CAAC,CAAC;AACrF,CAAC"}
|
|
@@ -3,32 +3,32 @@ import { printBlock, getEnabledSessionId } from './output.js';
|
|
|
3
3
|
* PermissionRequest hook handler for ExitPlanMode
|
|
4
4
|
*
|
|
5
5
|
* This command is invoked when Claude requests permission to exit plan mode.
|
|
6
|
-
* It reminds Claude to create a Ranger feature to track the work.
|
|
6
|
+
* It reminds Claude to create a Ranger feature review to track the work.
|
|
7
7
|
*/
|
|
8
|
-
export async function exitPlanMode() {
|
|
9
|
-
const sessionId = await getEnabledSessionId();
|
|
8
|
+
export async function exitPlanMode(sessionIdOverride) {
|
|
9
|
+
const sessionId = await getEnabledSessionId(sessionIdOverride);
|
|
10
10
|
if (!sessionId) {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
-
printBlock(`=== RANGER: CREATE FEATURE NOW ===
|
|
13
|
+
printBlock(`=== RANGER: CREATE FEATURE REVIEW NOW ===
|
|
14
14
|
|
|
15
15
|
You are about to exit plan mode. If your plan includes UI changes:
|
|
16
16
|
|
|
17
|
-
**ACTION REQUIRED:** Create the Ranger feature using
|
|
17
|
+
**ACTION REQUIRED:** Create the Ranger feature review using scenarios from your Ranger Feature Review Specification:
|
|
18
18
|
|
|
19
19
|
\`\`\`
|
|
20
|
-
ranger
|
|
20
|
+
ranger create "<Feature Review Name from plan>" \\
|
|
21
21
|
-d "<Description from plan>" \\
|
|
22
|
-
-c "<
|
|
23
|
-
-c "<
|
|
22
|
+
-c "<Scenario 1 from plan>" \\
|
|
23
|
+
-c "<Scenario 2 from plan>"
|
|
24
24
|
\`\`\`
|
|
25
25
|
|
|
26
|
-
**REMINDER:**
|
|
26
|
+
**REMINDER:** Scenarios must be E2E user flows, NOT implementation tasks.
|
|
27
27
|
|
|
28
28
|
**Good:** "User can log in with valid credentials and see dashboard"
|
|
29
29
|
**Bad:** "Add form validation" or "API returns 200"
|
|
30
30
|
|
|
31
|
-
If you did NOT include a Ranger Feature Specification in your plan, go back and add one before proceeding. See /ranger and create.md for guidance.
|
|
31
|
+
If you did NOT include a Ranger Feature Review Specification in your plan, go back and add one before proceeding. See /ranger and create.md for guidance.
|
|
32
32
|
|
|
33
33
|
=== END ===`);
|
|
34
34
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exitPlanMode.js","sourceRoot":"","sources":["../../../src/commands/hooks/exitPlanMode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;
|
|
1
|
+
{"version":3,"file":"exitPlanMode.js","sourceRoot":"","sources":["../../../src/commands/hooks/exitPlanMode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,iBAA0B;IACzD,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO;IACX,CAAC;IAED,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;YAoBH,CAAC,CAAC;AACd,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/hooks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -29,8 +29,14 @@ export async function readHookInput() {
|
|
|
29
29
|
* Read hook input and check if session is enabled.
|
|
30
30
|
* Returns session_id if enabled, null otherwise.
|
|
31
31
|
* Use this as the standard guard at the start of most hooks.
|
|
32
|
+
*
|
|
33
|
+
* When sessionIdOverride is provided (e.g. from --session-id flag for
|
|
34
|
+
* non-Claude integrations like OpenCode), stdin is not read.
|
|
32
35
|
*/
|
|
33
|
-
export async function getEnabledSessionId() {
|
|
36
|
+
export async function getEnabledSessionId(sessionIdOverride) {
|
|
37
|
+
if (sessionIdOverride) {
|
|
38
|
+
return isSessionEnabled(sessionIdOverride) ? sessionIdOverride : null;
|
|
39
|
+
}
|
|
34
40
|
const input = await readHookInput();
|
|
35
41
|
const sessionId = input?.session_id;
|
|
36
42
|
if (!sessionId || !isSessionEnabled(sessionId)) {
|
|
@@ -41,8 +47,20 @@ export async function getEnabledSessionId() {
|
|
|
41
47
|
/**
|
|
42
48
|
* Read hook input and return full context for hooks that need more data.
|
|
43
49
|
* Returns null if session not enabled.
|
|
50
|
+
*
|
|
51
|
+
* When sessionIdOverride is provided, stdin is not read and a synthetic
|
|
52
|
+
* HookInput is used (no permission_mode or other stdin-only fields).
|
|
44
53
|
*/
|
|
45
|
-
export async function getEnabledHookContext() {
|
|
54
|
+
export async function getEnabledHookContext(sessionIdOverride) {
|
|
55
|
+
if (sessionIdOverride) {
|
|
56
|
+
if (!isSessionEnabled(sessionIdOverride)) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
sessionId: sessionIdOverride,
|
|
61
|
+
input: { session_id: sessionIdOverride },
|
|
62
|
+
};
|
|
63
|
+
}
|
|
46
64
|
const input = await readHookInput();
|
|
47
65
|
const sessionId = input?.session_id;
|
|
48
66
|
if (!sessionId || !isSessionEnabled(sessionId)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/commands/hooks/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAWD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IAC/B,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACtC,KAAK,IAAI,KAAK,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAc,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/commands/hooks/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAWD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IAC/B,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACtC,KAAK,IAAI,KAAK,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAc,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACrC,iBAA0B;IAE1B,IAAI,iBAAiB,EAAE,CAAC;QACpB,OAAO,gBAAgB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,KAAK,EAAE,UAAU,CAAC;IAEpC,IAAI,CAAC,SAAS,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,SAAS,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACvC,iBAA0B;IAK1B,IAAI,iBAAiB,EAAE,CAAC;QACpB,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO;YACH,SAAS,EAAE,iBAAiB;YAC5B,KAAK,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE;SAC3C,CAAC;IACN,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;IACpC,MAAM,SAAS,GAAG,KAAK,EAAE,UAAU,CAAC;IAEpC,IAAI,CAAC,SAAS,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -6,8 +6,8 @@ import { shouldShowPlanReminder } from '../utils/sessionCache.js';
|
|
|
6
6
|
* This command is invoked on UserPromptSubmit, SubagentStop, and PostToolUse.
|
|
7
7
|
* It checks if in plan mode and shows the Ranger reminder (max once per 5 mins per session).
|
|
8
8
|
*/
|
|
9
|
-
export async function planReminder() {
|
|
10
|
-
const ctx = await getEnabledHookContext();
|
|
9
|
+
export async function planReminder(sessionIdOverride) {
|
|
10
|
+
const ctx = await getEnabledHookContext(sessionIdOverride);
|
|
11
11
|
if (!ctx) {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
@@ -24,22 +24,22 @@ export async function planReminder() {
|
|
|
24
24
|
If this plan involves ANY UI changes, you MUST:
|
|
25
25
|
|
|
26
26
|
1. **READ /ranger skill NOW** - specifically the create.md instructions
|
|
27
|
-
2. **Add a Ranger Feature Specification** to the end of your plan
|
|
27
|
+
2. **Add a Ranger Feature Review Specification** to the end of your plan
|
|
28
28
|
|
|
29
|
-
DO NOT write
|
|
30
|
-
|
|
29
|
+
DO NOT write scenarios without reading create.md first.
|
|
30
|
+
Scenarios are E2E test flows, NOT implementation tasks.
|
|
31
31
|
|
|
32
32
|
Your plan must end with:
|
|
33
33
|
\`\`\`
|
|
34
|
-
### Ranger Feature Specification (create this first with \`ranger
|
|
35
|
-
Feature Name: <name>
|
|
34
|
+
### Ranger Feature Review Specification (create this first with \`ranger create\`)
|
|
35
|
+
Feature Review Name: <name>
|
|
36
36
|
Description: <description>
|
|
37
|
-
|
|
37
|
+
Scenarios:
|
|
38
38
|
1. <E2E user flow that can be verified in browser>
|
|
39
39
|
2. <another E2E user flow if needed>
|
|
40
40
|
\`\`\`
|
|
41
41
|
|
|
42
|
-
Then run: \`ranger
|
|
42
|
+
Then run: \`ranger create "<name>" -d "<desc>" -c "<scenario1>" -c "<scenario2>"\`
|
|
43
43
|
|
|
44
44
|
=== END ===`);
|
|
45
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planReminder.js","sourceRoot":"","sources":["../../../src/commands/hooks/planReminder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;
|
|
1
|
+
{"version":3,"file":"planReminder.js","sourceRoot":"","sources":["../../../src/commands/hooks/planReminder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,iBAA0B;IACzD,MAAM,GAAG,GAAG,MAAM,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;IAC3D,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO;IACX,CAAC;IAED,yBAAyB;IACzB,IAAI,GAAG,CAAC,KAAK,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;QACvC,OAAO;IACX,CAAC;IAED,kEAAkE;IAClE,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,OAAO;IACX,CAAC;IAED,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;YAsBH,CAAC,CAAC;AACd,CAAC"}
|
|
@@ -3,10 +3,10 @@ import { printBlock, getEnabledSessionId } from './output.js';
|
|
|
3
3
|
* SubagentStart hook handler for Plan mode
|
|
4
4
|
*
|
|
5
5
|
* This command is invoked when Claude enters plan mode (Plan subagent starts).
|
|
6
|
-
* It reminds Claude to include Ranger
|
|
6
|
+
* It reminds Claude to include Ranger scenarios as part of the planning process.
|
|
7
7
|
*/
|
|
8
|
-
export async function planStart() {
|
|
9
|
-
const sessionId = await getEnabledSessionId();
|
|
8
|
+
export async function planStart(sessionIdOverride) {
|
|
9
|
+
const sessionId = await getEnabledSessionId(sessionIdOverride);
|
|
10
10
|
if (!sessionId) {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
@@ -15,15 +15,15 @@ export async function planStart() {
|
|
|
15
15
|
If this plan involves UI changes, you MUST:
|
|
16
16
|
|
|
17
17
|
1. **READ /ranger skill** - specifically create.md
|
|
18
|
-
2. **Add a Ranger Feature Specification** at the end of your plan
|
|
18
|
+
2. **Add a Ranger Feature Review Specification** at the end of your plan
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Scenarios are E2E test flows, NOT implementation tasks.
|
|
21
21
|
|
|
22
22
|
**Good:** "User can log in with valid credentials and see dashboard"
|
|
23
23
|
**Bad:** "Add form validation" or "Button is visible"
|
|
24
24
|
|
|
25
25
|
After planning, run:
|
|
26
|
-
\`ranger
|
|
26
|
+
\`ranger create "<name>" -d "<desc>" -c "<E2E flow 1>" -c "<E2E flow 2>"\`
|
|
27
27
|
|
|
28
28
|
=== END ===`);
|
|
29
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planStart.js","sourceRoot":"","sources":["../../../src/commands/hooks/planStart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;
|
|
1
|
+
{"version":3,"file":"planStart.js","sourceRoot":"","sources":["../../../src/commands/hooks/planStart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,iBAA0B;IACtD,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO;IACX,CAAC;IAED,UAAU,CAAC;;;;;;;;;;;;;;;YAeH,CAAC,CAAC;AACd,CAAC"}
|
|
@@ -5,10 +5,10 @@ import { getEnabledSessionId } from './output.js';
|
|
|
5
5
|
* PostToolUse (Write/Edit) hook handler for Claude Code plugin
|
|
6
6
|
*
|
|
7
7
|
* This command is invoked automatically after Write or Edit tools are used.
|
|
8
|
-
* If the session isn't registered with a Ranger feature, prompts to use /ranger.
|
|
8
|
+
* If the session isn't registered with a Ranger feature review, prompts to use /ranger.
|
|
9
9
|
*/
|
|
10
|
-
export async function postEdit() {
|
|
11
|
-
const sessionId = await getEnabledSessionId();
|
|
10
|
+
export async function postEdit(sessionIdOverride) {
|
|
11
|
+
const sessionId = await getEnabledSessionId(sessionIdOverride);
|
|
12
12
|
if (!sessionId) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
@@ -21,11 +21,11 @@ export async function postEdit() {
|
|
|
21
21
|
// Check if this session is already registered
|
|
22
22
|
const existingEntry = getSessionEntry(sessionId);
|
|
23
23
|
if (existingEntry) {
|
|
24
|
-
// Already registered - remind about adding
|
|
24
|
+
// Already registered - remind about adding scenarios if scope expanded
|
|
25
25
|
const response = {
|
|
26
26
|
hookSpecificOutput: {
|
|
27
27
|
hookEventName: 'PostToolUse',
|
|
28
|
-
additionalContext: `RANGER: If this change expands the scope of the active feature, you may need to add a
|
|
28
|
+
additionalContext: `RANGER: If this change expands the scope of the active feature review, you may need to add a scenario. See Workflow 1 in /ranger. If you decide to add a scenario, you MUST read Workflow 1 IN DETAIL first.`,
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
31
|
console.log(JSON.stringify(response));
|
|
@@ -35,7 +35,7 @@ export async function postEdit() {
|
|
|
35
35
|
const response = {
|
|
36
36
|
hookSpecificOutput: {
|
|
37
37
|
hookEventName: 'PostToolUse',
|
|
38
|
-
additionalContext: `RANGER: If this is for a UI feature, you MUST use /ranger to either create a new feature or resume an existing one.`,
|
|
38
|
+
additionalContext: `RANGER: If this is for a UI feature, you MUST use /ranger to either create a new feature review or resume an existing one.`,
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
41
|
console.log(JSON.stringify(response));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postEdit.js","sourceRoot":"","sources":["../../../src/commands/hooks/postEdit.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,eAAe,EACf,oBAAoB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;
|
|
1
|
+
{"version":3,"file":"postEdit.js","sourceRoot":"","sources":["../../../src/commands/hooks/postEdit.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,eAAe,EACf,oBAAoB,GACvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,iBAA0B;IACrD,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO;IACX,CAAC;IAED,sFAAsF;IACtF,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAEhC,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO;IACX,CAAC;IAED,8CAA8C;IAC9C,MAAM,aAAa,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACjD,IAAI,aAAa,EAAE,CAAC;QAChB,uEAAuE;QACvE,MAAM,QAAQ,GAAG;YACb,kBAAkB,EAAE;gBAChB,aAAa,EAAE,aAAa;gBAC5B,iBAAiB,EAAE,8MAA8M;aACpO;SACJ,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtC,OAAO;IACX,CAAC;IAED,qDAAqD;IACrD,MAAM,QAAQ,GAAG;QACb,kBAAkB,EAAE;YAChB,aAAa,EAAE,aAAa;YAC5B,iBAAiB,EAAE,4HAA4H;SAClJ;KACJ,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -4,10 +4,10 @@ import { printBlock, getEnabledSessionId } from './output.js';
|
|
|
4
4
|
* PreCompact hook handler for Claude Code plugin
|
|
5
5
|
*
|
|
6
6
|
* This command is invoked automatically before Claude Code compacts the conversation.
|
|
7
|
-
* It reminds Claude to preserve Ranger Feature Specification in the compaction summary.
|
|
7
|
+
* It reminds Claude to preserve Ranger Feature Review Specification in the compaction summary.
|
|
8
8
|
*/
|
|
9
|
-
export async function preCompact() {
|
|
10
|
-
const sessionId = await getEnabledSessionId();
|
|
9
|
+
export async function preCompact(sessionIdOverride) {
|
|
10
|
+
const sessionId = await getEnabledSessionId(sessionIdOverride);
|
|
11
11
|
if (!sessionId) {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
@@ -19,9 +19,9 @@ export async function preCompact() {
|
|
|
19
19
|
}
|
|
20
20
|
printBlock(`=== RANGER: PRESERVE IN COMPACTION ===
|
|
21
21
|
|
|
22
|
-
If you created a plan with a **Ranger Feature Specification**, you MUST preserve it in the compaction summary.
|
|
22
|
+
If you created a plan with a **Ranger Feature Review Specification**, you MUST preserve it in the compaction summary.
|
|
23
23
|
|
|
24
|
-
The specification contains
|
|
24
|
+
The specification contains scenarios that will be used with \`ranger create\`.`);
|
|
25
25
|
}
|
|
26
26
|
catch {
|
|
27
27
|
// Silently fail - don't interrupt compaction
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preCompact.js","sourceRoot":"","sources":["../../../src/commands/hooks/preCompact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;
|
|
1
|
+
{"version":3,"file":"preCompact.js","sourceRoot":"","sources":["../../../src/commands/hooks/preCompact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,iBAA0B;IACvD,MAAM,SAAS,GAAG,MAAM,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO;IACX,CAAC;IAED,IAAI,CAAC;QACD,gCAAgC;QAChC,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO;QACX,CAAC;QAED,UAAU,CAAC;;;;+EAI4D,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACL,6CAA6C;IACjD,CAAC;AACL,CAAC"}
|
|
@@ -6,10 +6,14 @@ import { readHookInput } from './output.js';
|
|
|
6
6
|
* This command is invoked when a Claude Code session ends.
|
|
7
7
|
* If reason is 'clear' and session was enabled, records timestamp for auto-enable.
|
|
8
8
|
*/
|
|
9
|
-
export async function sessionEnd() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
export async function sessionEnd(sessionIdOverride) {
|
|
10
|
+
let sessionId = sessionIdOverride;
|
|
11
|
+
let reason;
|
|
12
|
+
if (!sessionIdOverride) {
|
|
13
|
+
const input = await readHookInput();
|
|
14
|
+
sessionId = input?.session_id;
|
|
15
|
+
reason = input?.reason;
|
|
16
|
+
}
|
|
13
17
|
if (!sessionId) {
|
|
14
18
|
return;
|
|
15
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionEnd.js","sourceRoot":"","sources":["../../../src/commands/hooks/sessionEnd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;
|
|
1
|
+
{"version":3,"file":"sessionEnd.js","sourceRoot":"","sources":["../../../src/commands/hooks/sessionEnd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,iBAA0B;IACvD,IAAI,SAAS,GAAG,iBAAiB,CAAC;IAClC,IAAI,MAA0B,CAAC;IAE/B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;QACpC,SAAS,GAAG,KAAK,EAAE,UAAU,CAAC;QAC9B,MAAM,GAAG,KAAK,EAAE,MAA4B,CAAC;IACjD,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO;IACX,CAAC;IAED,oEAAoE;IACpE,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACrB,2BAA2B,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;AACL,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { appendFile } from 'fs/promises';
|
|
2
2
|
import { initBranchTracking, shouldAutoEnableAfterClear, autoEnableAfterClear, isSessionEnabled, getCurrentBranch, } from '../utils/sessionCache.js';
|
|
3
|
+
import { createTelemetryCollector } from '../utils/telemetry.js';
|
|
3
4
|
const RANGER_AUTO_ENABLED_PROMPT = `=================================================================
|
|
4
5
|
🚨 RANGER IS ACTIVE 🚨
|
|
5
6
|
=================================================================
|
|
@@ -8,13 +9,13 @@ This session has Ranger ENABLED. Before doing ANYTHING else:
|
|
|
8
9
|
|
|
9
10
|
1. **READ the /ranger skill FIRST** - Run the skill to understand the required workflow for UI features
|
|
10
11
|
|
|
11
|
-
2. **Check for existing
|
|
12
|
+
2. **Check for existing feature reviews** - Run \`ranger list\` to see if there's an in-progress feature review to resume
|
|
12
13
|
|
|
13
14
|
3. **For ANY UI work**: You MUST either:
|
|
14
|
-
- Resume an existing feature: \`ranger
|
|
15
|
-
- Create a new feature: \`ranger
|
|
15
|
+
- Resume an existing feature review: \`ranger resume <id>\`
|
|
16
|
+
- Create a new feature review: \`ranger create "<name>" -d "<desc>" -c "<scenario>"\`
|
|
16
17
|
|
|
17
|
-
4. **If resuming a feature with reviewer comments**: Run \`ranger
|
|
18
|
+
4. **If resuming a feature review with reviewer comments**: Run \`ranger get-review\` to see what reviewers want fixed before making code changes
|
|
18
19
|
|
|
19
20
|
=================================================================`;
|
|
20
21
|
/**
|
|
@@ -25,30 +26,32 @@ This session has Ranger ENABLED. Before doing ANYTHING else:
|
|
|
25
26
|
*
|
|
26
27
|
* Note: The skill prompt is now shown by the enable hook when user runs /enable.
|
|
27
28
|
*/
|
|
28
|
-
export async function sessionStart() {
|
|
29
|
-
|
|
30
|
-
let input = '';
|
|
31
|
-
for await (const chunk of process.stdin) {
|
|
32
|
-
input += chunk;
|
|
33
|
-
}
|
|
34
|
-
let sessionId = '';
|
|
29
|
+
export async function sessionStart(sessionIdOverride) {
|
|
30
|
+
let sessionId = sessionIdOverride || '';
|
|
35
31
|
let source;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Ignore parse errors
|
|
43
|
-
}
|
|
44
|
-
// Export CLAUDE_SESSION_ID to env file if available
|
|
45
|
-
const envFile = process.env.CLAUDE_ENV_FILE;
|
|
46
|
-
if (envFile && sessionId) {
|
|
32
|
+
if (!sessionIdOverride) {
|
|
33
|
+
// Claude Code path: read JSON input from stdin to get session_id and source
|
|
34
|
+
let input = '';
|
|
35
|
+
for await (const chunk of process.stdin) {
|
|
36
|
+
input += chunk;
|
|
37
|
+
}
|
|
47
38
|
try {
|
|
48
|
-
|
|
39
|
+
const data = JSON.parse(input);
|
|
40
|
+
sessionId = data['session_id'] || '';
|
|
41
|
+
source = data['source'];
|
|
49
42
|
}
|
|
50
43
|
catch {
|
|
51
|
-
// Ignore errors
|
|
44
|
+
// Ignore parse errors
|
|
45
|
+
}
|
|
46
|
+
// Export CLAUDE_SESSION_ID to env file if available (Claude Code only)
|
|
47
|
+
const envFile = process.env.CLAUDE_ENV_FILE;
|
|
48
|
+
if (envFile && sessionId) {
|
|
49
|
+
try {
|
|
50
|
+
await appendFile(envFile, `export CLAUDE_SESSION_ID="${sessionId}"\n`);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Ignore errors writing to env file
|
|
54
|
+
}
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
57
|
if (sessionId) {
|
|
@@ -58,8 +61,21 @@ export async function sessionStart() {
|
|
|
58
61
|
}
|
|
59
62
|
// Initialize branch tracking - auto-enable session if branch is already enabled
|
|
60
63
|
initBranchTracking(sessionId);
|
|
64
|
+
const enabled = isSessionEnabled(sessionId);
|
|
65
|
+
// Telemetry: log session start with enabled status
|
|
66
|
+
try {
|
|
67
|
+
const telemetry = createTelemetryCollector('hook:session-start');
|
|
68
|
+
await telemetry.trackCommandStart({
|
|
69
|
+
sessionId,
|
|
70
|
+
hooksEnabled: enabled,
|
|
71
|
+
});
|
|
72
|
+
await telemetry.trackCommandEnd('success');
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Telemetry must never throw
|
|
76
|
+
}
|
|
61
77
|
// If session is now enabled (via branch or clear), output strong prompting
|
|
62
|
-
if (
|
|
78
|
+
if (enabled) {
|
|
63
79
|
const branch = getCurrentBranch();
|
|
64
80
|
const branchInfo = branch && branch !== 'main' && branch !== 'master'
|
|
65
81
|
? ` (Branch: ${branch})`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionStart.js","sourceRoot":"","sources":["../../../src/commands/hooks/sessionStart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACH,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"sessionStart.js","sourceRoot":"","sources":["../../../src/commands/hooks/sessionStart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACH,kBAAkB,EAClB,0BAA0B,EAC1B,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;kEAgB+B,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,iBAA0B;IACzD,IAAI,SAAS,GAAG,iBAAiB,IAAI,EAAE,CAAC;IACxC,IAAI,MAA0B,CAAC;IAE/B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACrB,4EAA4E;QAC5E,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACtC,KAAK,IAAI,KAAK,CAAC;QACnB,CAAC;QAED,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC/B,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;YACrC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACL,sBAAsB;QAC1B,CAAC;QAED,uEAAuE;QACvE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;QAC5C,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC;gBACD,MAAM,UAAU,CACZ,OAAO,EACP,6BAA6B,SAAS,KAAK,CAC9C,CAAC;YACN,CAAC;YAAC,MAAM,CAAC;gBACL,oCAAoC;YACxC,CAAC;QACL,CAAC;IACL,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACZ,mFAAmF;QACnF,IAAI,0BAA0B,CAAC,MAAM,CAAC,EAAE,CAAC;YACrC,oBAAoB,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;QAED,gFAAgF;QAChF,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAE9B,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;QAE5C,mDAAmD;QACnD,IAAI,CAAC;YACD,MAAM,SAAS,GAAG,wBAAwB,CAAC,oBAAoB,CAAC,CAAC;YACjE,MAAM,SAAS,CAAC,iBAAiB,CAAC;gBAC9B,SAAS;gBACT,YAAY,EAAE,OAAO;aACxB,CAAC,CAAC;YACH,MAAM,SAAS,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACL,6BAA6B;QACjC,CAAC;QAED,2EAA2E;QAC3E,IAAI,OAAO,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;YAClC,MAAM,UAAU,GACZ,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,QAAQ;gBAC9C,CAAC,CAAC,aAAa,MAAM,GAAG;gBACxB,CAAC,CAAC,EAAE,CAAC;YAEb,MAAM,QAAQ,GAAG;gBACb,kBAAkB,EAAE;oBAChB,aAAa,EAAE,cAAc;oBAC7B,iBAAiB,EAAE,0BAA0B,GAAG,UAAU;iBAC7D;aACJ,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1C,CAAC;IACL,CAAC;AACL,CAAC"}
|
|
@@ -2,53 +2,77 @@ import { getToken } from '../utils/keychain.js';
|
|
|
2
2
|
import { getFeature, concludeSession } from '../utils/featureApi.js';
|
|
3
3
|
import { getSessionEntry } from '../utils/sessionCache.js';
|
|
4
4
|
import { getEnabledSessionId } from './output.js';
|
|
5
|
+
import { createTelemetryCollector } from '../utils/telemetry.js';
|
|
5
6
|
/**
|
|
6
7
|
* Stop hook handler
|
|
7
8
|
*
|
|
8
|
-
* Only blocks stop for Claude sessions that have registered with a Ranger feature.
|
|
9
|
-
* Attempts to conclude the feature session before allowing stop.
|
|
9
|
+
* Only blocks stop for Claude sessions that have registered with a Ranger feature review.
|
|
10
|
+
* Attempts to conclude the feature review session before allowing stop.
|
|
10
11
|
*/
|
|
11
|
-
export async function stopHook() {
|
|
12
|
-
const sessionId = await getEnabledSessionId();
|
|
12
|
+
export async function stopHook(sessionIdOverride) {
|
|
13
|
+
const sessionId = await getEnabledSessionId(sessionIdOverride);
|
|
14
|
+
let stopAllowed = true;
|
|
13
15
|
if (!sessionId) {
|
|
16
|
+
await trackStop(sessionId, false, stopAllowed);
|
|
14
17
|
return;
|
|
15
18
|
}
|
|
16
19
|
try {
|
|
17
|
-
// Check if this Claude session is registered with a Ranger feature
|
|
20
|
+
// Check if this Claude session is registered with a Ranger feature review
|
|
18
21
|
const sessionEntry = getSessionEntry(sessionId);
|
|
19
22
|
if (!sessionEntry) {
|
|
20
23
|
// Not a Ranger session - allow stop
|
|
24
|
+
await trackStop(sessionId, true, stopAllowed);
|
|
21
25
|
return;
|
|
22
26
|
}
|
|
23
27
|
const token = await getToken();
|
|
24
28
|
if (!token) {
|
|
25
29
|
// No token configured - allow stop
|
|
30
|
+
await trackStop(sessionId, true, stopAllowed);
|
|
26
31
|
return;
|
|
27
32
|
}
|
|
28
33
|
// Get the feature
|
|
29
34
|
const feature = await getFeature(sessionEntry.featureId);
|
|
30
35
|
// If there's no current session, allow stop
|
|
31
36
|
if (!feature.currentSessionId) {
|
|
37
|
+
await trackStop(sessionId, true, stopAllowed);
|
|
32
38
|
return;
|
|
33
39
|
}
|
|
34
40
|
// Try to conclude the session
|
|
35
41
|
try {
|
|
36
42
|
await concludeSession(feature.id, feature.currentSessionId);
|
|
43
|
+
await trackStop(sessionId, true, stopAllowed);
|
|
37
44
|
return;
|
|
38
45
|
}
|
|
39
46
|
catch (err) {
|
|
40
47
|
// Failed to conclude - block with error message
|
|
48
|
+
stopAllowed = false;
|
|
41
49
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
42
50
|
const output = {
|
|
43
51
|
decision: 'block',
|
|
44
|
-
reason: `Failed to conclude Ranger feature session for "${feature.name}":\n\n${errorMessage}\n\
|
|
52
|
+
reason: `Failed to conclude Ranger feature review session for "${feature.name}":\n\n${errorMessage}\n\nThis is most likely due to pending scenarios that need to be verified. Please resolve the issue or resume later with:\n ranger resume`,
|
|
45
53
|
};
|
|
46
54
|
console.log(JSON.stringify(output));
|
|
55
|
+
await trackStop(sessionId, true, stopAllowed);
|
|
47
56
|
}
|
|
48
57
|
}
|
|
49
58
|
catch {
|
|
50
59
|
// On any error fetching feature, allow stop (fail open)
|
|
60
|
+
await trackStop(sessionId, true, stopAllowed);
|
|
51
61
|
return;
|
|
52
62
|
}
|
|
53
63
|
}
|
|
64
|
+
async function trackStop(sessionId, hooksEnabled, stopAllowed) {
|
|
65
|
+
try {
|
|
66
|
+
const telemetry = createTelemetryCollector('hook:stop');
|
|
67
|
+
await telemetry.trackCommandStart({
|
|
68
|
+
sessionId: sessionId ?? undefined,
|
|
69
|
+
hooksEnabled,
|
|
70
|
+
stopAllowed,
|
|
71
|
+
});
|
|
72
|
+
await telemetry.trackCommandEnd('success');
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Telemetry must never throw
|
|
76
|
+
}
|
|
77
|
+
}
|
|
54
78
|
//# sourceMappingURL=stopHook.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stopHook.js","sourceRoot":"","sources":["../../../src/commands/hooks/stopHook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"stopHook.js","sourceRoot":"","sources":["../../../src/commands/hooks/stopHook.ts"],"names":[],"mappings":"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"}
|