slashdev 1.2.0 → 1.3.1
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.md +1 -1
- package/claude-skills/hormozi/SKILL.md +133 -0
- package/claude-skills/hormozi/references/core-four-leads.md +195 -0
- package/claude-skills/hormozi/references/critique-rubric.md +132 -0
- package/claude-skills/hormozi/references/enhancements.md +161 -0
- package/claude-skills/hormozi/references/examples.md +208 -0
- package/claude-skills/hormozi/references/grand-slam-offer.md +105 -0
- package/claude-skills/hormozi/references/lead-magnets.md +115 -0
- package/claude-skills/hormozi/references/problem-solution-stack.md +125 -0
- package/claude-skills/hormozi/references/value-equation.md +105 -0
- package/hooks/post-response.sh +62 -1
- package/hooks/prompt-submit.sh +42 -0
- package/package.json +1 -1
- package/src/commands/setup-internals.js +22 -0
- package/vendor/gstack/.env.example +0 -5
- package/vendor/gstack/autoplan/SKILL.md +0 -1116
- package/vendor/gstack/browse/SKILL.md +0 -538
- package/vendor/gstack/canary/SKILL.md +0 -587
- package/vendor/gstack/careful/SKILL.md +0 -59
- package/vendor/gstack/codex/SKILL.md +0 -862
- package/vendor/gstack/connect-chrome/SKILL.md +0 -549
- package/vendor/gstack/cso/ACKNOWLEDGEMENTS.md +0 -14
- package/vendor/gstack/cso/SKILL.md +0 -929
- package/vendor/gstack/design-consultation/SKILL.md +0 -962
- package/vendor/gstack/design-review/SKILL.md +0 -1314
- package/vendor/gstack/design-shotgun/SKILL.md +0 -730
- package/vendor/gstack/document-release/SKILL.md +0 -718
- package/vendor/gstack/freeze/SKILL.md +0 -82
- package/vendor/gstack/gstack-upgrade/SKILL.md +0 -232
- package/vendor/gstack/guard/SKILL.md +0 -82
- package/vendor/gstack/investigate/SKILL.md +0 -504
- package/vendor/gstack/land-and-deploy/SKILL.md +0 -1367
- package/vendor/gstack/office-hours/SKILL.md +0 -1317
- package/vendor/gstack/plan-ceo-review/SKILL.md +0 -1537
- package/vendor/gstack/plan-design-review/SKILL.md +0 -1227
- package/vendor/gstack/plan-eng-review/SKILL.md +0 -1120
- package/vendor/gstack/qa/SKILL.md +0 -1136
- package/vendor/gstack/qa/references/issue-taxonomy.md +0 -85
- package/vendor/gstack/qa/templates/qa-report-template.md +0 -126
- package/vendor/gstack/qa-only/SKILL.md +0 -726
- package/vendor/gstack/retro/SKILL.md +0 -1197
- package/vendor/gstack/review/SKILL.md +0 -1138
- package/vendor/gstack/review/TODOS-format.md +0 -62
- package/vendor/gstack/review/checklist.md +0 -220
- package/vendor/gstack/review/design-checklist.md +0 -132
- package/vendor/gstack/review/greptile-triage.md +0 -220
- package/vendor/gstack/setup-browser-cookies/SKILL.md +0 -348
- package/vendor/gstack/setup-deploy/SKILL.md +0 -528
- package/vendor/gstack/ship/SKILL.md +0 -1931
- package/vendor/gstack/unfreeze/SKILL.md +0 -40
package/hooks/post-response.sh
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const https = require('https');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const { execFileSync } = require('child_process');
|
|
6
7
|
|
|
7
8
|
// Debug log
|
|
8
9
|
const DEBUG_LOG = path.join(require('os').homedir(), '.slashdev', 'hook-debug.log');
|
|
@@ -181,6 +182,54 @@ try {
|
|
|
181
182
|
debug(`Conversation type derivation error: ${e.message}`);
|
|
182
183
|
}
|
|
183
184
|
|
|
185
|
+
// v2: was this typed by a person? Claude Code also records background-task
|
|
186
|
+
// notifications, messages from other sessions, skill loads and IDE
|
|
187
|
+
// context as user turns; headless runs (claude -p) are scripts.
|
|
188
|
+
let source = 'human';
|
|
189
|
+
try {
|
|
190
|
+
const head = lastPrompt.trimStart().slice(0, 80).toLowerCase();
|
|
191
|
+
const entrypoint = String(process.env.CLAUDE_CODE_ENTRYPOINT || '');
|
|
192
|
+
if (!lastPrompt.trim()) source = 'unknown';
|
|
193
|
+
else if (entrypoint.startsWith('sdk')) source = 'scripted';
|
|
194
|
+
else if (head.startsWith('<task-notification>')) source = 'task_notification';
|
|
195
|
+
else if (head.startsWith('another claude session sent')) source = 'session_message';
|
|
196
|
+
else if (head.startsWith('base directory for this skill')) source = 'skill';
|
|
197
|
+
else if (head.startsWith('<ide_') || head.startsWith('<system-reminder>')) source = 'ide_context';
|
|
198
|
+
} catch (e) {
|
|
199
|
+
debug(`Source classification error: ${e.message}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// v2: when the prompt was sent (stamped by prompt-submit.sh).
|
|
203
|
+
let promptSubmittedAt = null;
|
|
204
|
+
try {
|
|
205
|
+
const safeId = String(sessionId).replace(/[^A-Za-z0-9_-]/g, '');
|
|
206
|
+
const stamp = path.join(require('os').homedir(), '.slashdev', 'sessions', `${safeId}.json`);
|
|
207
|
+
if (safeId && fs.existsSync(stamp)) {
|
|
208
|
+
promptSubmittedAt = JSON.parse(fs.readFileSync(stamp, 'utf8')).submitted_at || null;
|
|
209
|
+
}
|
|
210
|
+
} catch (e) {
|
|
211
|
+
debug(`Prompt stamp read error: ${e.message}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// v2: repo, branch and commit, to tie a session to what it shipped.
|
|
215
|
+
// The remote URL is reduced to owner/repo so no credentials leave.
|
|
216
|
+
let repo = null;
|
|
217
|
+
let branch = null;
|
|
218
|
+
let commitSha = null;
|
|
219
|
+
try {
|
|
220
|
+
const cwd = hookData.cwd;
|
|
221
|
+
if (cwd && fs.existsSync(cwd)) {
|
|
222
|
+
const git = (args) => execFileSync('git', ['-C', cwd, ...args], { encoding: 'utf8', timeout: 1500, stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
223
|
+
branch = git(['rev-parse', '--abbrev-ref', 'HEAD']) || null;
|
|
224
|
+
commitSha = git(['rev-parse', 'HEAD']) || null;
|
|
225
|
+
const remote = git(['config', '--get', 'remote.origin.url']);
|
|
226
|
+
const m = remote.match(/[:/]([^/:]+\/[^/]+?)(?:\.git)?\/?$/);
|
|
227
|
+
repo = m ? m[1] : null;
|
|
228
|
+
}
|
|
229
|
+
} catch (e) {
|
|
230
|
+
// Not a git repo, or git missing: leave them null.
|
|
231
|
+
}
|
|
232
|
+
|
|
184
233
|
const payload = JSON.stringify({
|
|
185
234
|
engineer,
|
|
186
235
|
session_id: sessionId,
|
|
@@ -192,9 +241,21 @@ try {
|
|
|
192
241
|
conversation_type: conversationType,
|
|
193
242
|
model: model,
|
|
194
243
|
message_count: messageCount,
|
|
244
|
+
source,
|
|
245
|
+
prompt_submitted_at: promptSubmittedAt,
|
|
246
|
+
repo,
|
|
247
|
+
branch,
|
|
248
|
+
commit_sha: commitSha,
|
|
249
|
+
cli_version: config.packageVersion || null,
|
|
195
250
|
});
|
|
196
251
|
|
|
197
|
-
debug(`Sending: engineer=${engineer}, session=${sessionId.substring(0, 12)}, prompt_len=${lastPrompt.length}, response_len=${lastResponse.length}, tools=[${toolsUsed.join(',')}], skills=[${skillsUsed.join(',')}], project=${projectName}, type=${conversationType}, model=${model}, messages=${messageCount}`);
|
|
252
|
+
debug(`Sending: engineer=${engineer}, session=${sessionId.substring(0, 12)}, prompt_len=${lastPrompt.length}, response_len=${lastResponse.length}, source=${source}, submitted=${promptSubmittedAt}, repo=${repo}, branch=${branch}, tools=[${toolsUsed.join(',')}], skills=[${skillsUsed.join(',')}], project=${projectName}, type=${conversationType}, model=${model}, messages=${messageCount}`);
|
|
253
|
+
|
|
254
|
+
// Dry run (testing): log the payload, send nothing.
|
|
255
|
+
if (process.env.SLASHDEV_LOG_DRY === '1') {
|
|
256
|
+
debug(`DRY payload: ${payload}`);
|
|
257
|
+
process.exit(0);
|
|
258
|
+
}
|
|
198
259
|
|
|
199
260
|
// POST to API
|
|
200
261
|
const url = new URL('https://v1api.slashdev.io/api/logs');
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Claude Code UserPromptSubmit hook: note when a prompt was sent, so the Stop
|
|
4
|
+
// hook (post-response.sh) can log the time a person asked as well as the time
|
|
5
|
+
// Claude finished. Local only — no network, no output — and it never blocks
|
|
6
|
+
// a prompt: any error just exits 0.
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
let input = '';
|
|
14
|
+
process.stdin.setEncoding('utf8');
|
|
15
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
16
|
+
process.stdin.on('end', () => {
|
|
17
|
+
try {
|
|
18
|
+
const hookData = input ? JSON.parse(input) : {};
|
|
19
|
+
const sessionId = String(hookData.session_id || '').replace(/[^A-Za-z0-9_-]/g, '');
|
|
20
|
+
if (!sessionId) process.exit(0);
|
|
21
|
+
|
|
22
|
+
const dir = path.join(os.homedir(), '.slashdev', 'sessions');
|
|
23
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
24
|
+
fs.writeFileSync(
|
|
25
|
+
path.join(dir, `${sessionId}.json`),
|
|
26
|
+
JSON.stringify({ submitted_at: new Date().toISOString() })
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Housekeeping: drop stamps older than two days.
|
|
30
|
+
const cutoff = Date.now() - 2 * 24 * 60 * 60 * 1000;
|
|
31
|
+
for (const name of fs.readdirSync(dir)) {
|
|
32
|
+
try {
|
|
33
|
+
const file = path.join(dir, name);
|
|
34
|
+
if (fs.statSync(file).mtimeMs < cutoff) fs.unlinkSync(file);
|
|
35
|
+
} catch (_) { /* ignore */ }
|
|
36
|
+
}
|
|
37
|
+
} catch (_) { /* never block a prompt */ }
|
|
38
|
+
process.exit(0);
|
|
39
|
+
});
|
|
40
|
+
} catch (_) {
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -119,6 +119,28 @@ export function installHooks() {
|
|
|
119
119
|
settings.hooks.Stop = stopHooks;
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
// Register UserPromptSubmit hook: stamps when each prompt was sent, so the
|
|
123
|
+
// Stop hook can log it (local only, never blocks a prompt).
|
|
124
|
+
const submitCommand = join(CLAUDE_HOOKS_DIR, 'prompt-submit.sh');
|
|
125
|
+
if (existsSync(submitCommand)) {
|
|
126
|
+
const submitHooks = settings.hooks.UserPromptSubmit || [];
|
|
127
|
+
const submitRegistered = submitHooks.some(
|
|
128
|
+
(entry) => Array.isArray(entry.hooks) && entry.hooks.some((h) => h.command && h.command.includes('prompt-submit.sh'))
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (!submitRegistered) {
|
|
132
|
+
submitHooks.push({
|
|
133
|
+
hooks: [
|
|
134
|
+
{
|
|
135
|
+
type: 'command',
|
|
136
|
+
command: submitCommand,
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
settings.hooks.UserPromptSubmit = submitHooks;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
122
144
|
// Register PreToolUse hook for the install guard (Bash tool only).
|
|
123
145
|
const guardCommand = join(CLAUDE_HOOKS_DIR, 'pre-install-guard.sh');
|
|
124
146
|
if (existsSync(guardCommand)) {
|