slait.dev 0.1.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 +149 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +22 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/hooks.d.ts +17 -0
- package/dist/commands/hooks.js +372 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +41 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/setup.d.ts +7 -0
- package/dist/commands/setup.js +85 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +29 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upload.d.ts +6 -0
- package/dist/commands/upload.js +75 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +62 -0
- package/dist/lib/api.js +92 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/claude-artifacts.d.ts +18 -0
- package/dist/lib/claude-artifacts.js +181 -0
- package/dist/lib/claude-artifacts.js.map +1 -0
- package/dist/lib/claude-hooks.d.ts +13 -0
- package/dist/lib/claude-hooks.js +87 -0
- package/dist/lib/claude-hooks.js.map +1 -0
- package/dist/lib/config.d.ts +10 -0
- package/dist/lib/config.js +52 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/cursor-artifacts.d.ts +13 -0
- package/dist/lib/cursor-artifacts.js +83 -0
- package/dist/lib/cursor-artifacts.js.map +1 -0
- package/dist/lib/cursor-hooks.d.ts +14 -0
- package/dist/lib/cursor-hooks.js +112 -0
- package/dist/lib/cursor-hooks.js.map +1 -0
- package/dist/lib/discover.d.ts +8 -0
- package/dist/lib/discover.js +65 -0
- package/dist/lib/discover.js.map +1 -0
- package/dist/lib/format.d.ts +17 -0
- package/dist/lib/format.js +134 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/project-link.d.ts +11 -0
- package/dist/lib/project-link.js +32 -0
- package/dist/lib/project-link.js.map +1 -0
- package/dist/lib/session-events.d.ts +8 -0
- package/dist/lib/session-events.js +44 -0
- package/dist/lib/session-events.js.map +1 -0
- package/dist/lib/state.d.ts +11 -0
- package/dist/lib/state.js +31 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/lib/transcript.d.ts +15 -0
- package/dist/lib/transcript.js +44 -0
- package/dist/lib/transcript.js.map +1 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Slait CLI
|
|
2
|
+
|
|
3
|
+
Automatically capture your Cursor and Claude sessions and stream them to the [Slait](https://slait.dev) dashboard for analysis.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g slait.dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run directly with `npx` (no install needed).
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
Get your API key from your [Slait dashboard profile](https://slait.dev), then run this in your project directory:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx slait.dev setup <your-api-key>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
That single command saves your key, links the project, and installs Cursor/Claude hooks. You're done — sessions appear on your dashboard automatically.
|
|
22
|
+
|
|
23
|
+
### Manual setup
|
|
24
|
+
|
|
25
|
+
If you prefer to run each step individually:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
slait config set-key <your-api-key>
|
|
29
|
+
cd /path/to/your/project
|
|
30
|
+
slait init
|
|
31
|
+
slait hooks install --cursor --claude
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## How It Works
|
|
35
|
+
|
|
36
|
+
Once hooks are installed, every Cursor or Claude session in your project is captured automatically:
|
|
37
|
+
|
|
38
|
+
- **Session starts** — a live session appears on your dashboard with a green "Live" badge
|
|
39
|
+
- **Each turn completes** — the transcript updates in real time on the dashboard
|
|
40
|
+
- **Session ends** — the full transcript is analyzed (9 AI skill modules scored 0–5) and results appear on the dashboard
|
|
41
|
+
|
|
42
|
+
No manual uploading required. No background processes. The CLI is stateless — Cursor/Claude hooks invoke it at the right moments.
|
|
43
|
+
|
|
44
|
+
## Commands
|
|
45
|
+
|
|
46
|
+
### `slait setup`
|
|
47
|
+
|
|
48
|
+
One-command setup that saves your API key, links the current project, and installs hooks.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx slait.dev setup <api-key> # Auto-detects Cursor/Claude and installs hooks
|
|
52
|
+
npx slait.dev setup <api-key> --cursor # Only install Cursor hooks
|
|
53
|
+
npx slait.dev setup <api-key> --claude # Only install Claude hooks
|
|
54
|
+
npx slait.dev setup <api-key> --name "App" # Custom project name
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### `slait config`
|
|
58
|
+
|
|
59
|
+
Manage CLI configuration stored in `~/.slait/config.json`.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
slait config set-key <api_key> # Save your API key
|
|
63
|
+
slait config set-url <url> # Set dashboard URL (default: https://slait.dev)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### `slait init`
|
|
67
|
+
|
|
68
|
+
Link the current directory to a Slait dashboard project. Creates a new project on the dashboard and stores the mapping locally.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
slait init # Uses directory name as project name
|
|
72
|
+
slait init --name "My App" # Custom project name
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `slait hooks`
|
|
76
|
+
|
|
77
|
+
Manage Cursor and Claude hooks for automatic session capture.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
slait hooks install --cursor # Install Cursor hooks (.cursor/hooks.json)
|
|
81
|
+
slait hooks install --claude # Install Claude hooks (.claude/settings.json)
|
|
82
|
+
slait hooks install --cursor --claude # Install both
|
|
83
|
+
|
|
84
|
+
slait hooks uninstall --cursor # Remove Cursor hooks
|
|
85
|
+
slait hooks uninstall --claude # Remove Claude hooks
|
|
86
|
+
|
|
87
|
+
slait hooks status # Show which hooks are installed
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### `slait upload`
|
|
91
|
+
|
|
92
|
+
Manually upload a transcript file for analysis. Useful for sessions that happened before hooks were installed.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
slait upload ./my-session.jsonl # Upload a specific file
|
|
96
|
+
slait upload --cursor --latest # Upload most recent Cursor transcript
|
|
97
|
+
slait upload --claude --latest # Upload most recent Claude transcript
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `slait status`
|
|
101
|
+
|
|
102
|
+
Show the current state of the CLI — API key, linked project, installed hooks.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
slait status
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Example output:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
Slait CLI Status
|
|
112
|
+
────────────────────────────────────────
|
|
113
|
+
API key: configured
|
|
114
|
+
Base URL: https://slait.dev
|
|
115
|
+
|
|
116
|
+
Project: my-app
|
|
117
|
+
Project ID: a266eb86-cd0f-41d7-b969-36d975b3f390
|
|
118
|
+
Dashboard: https://slait.dev/project/a266eb86-cd0f-41d7-b969-36d975b3f390
|
|
119
|
+
Linked at: 2026-03-07T01:29:07.974Z
|
|
120
|
+
|
|
121
|
+
Cursor hooks: installed
|
|
122
|
+
Claude hooks: not installed
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## FAQ
|
|
126
|
+
|
|
127
|
+
**Where is my API key?**
|
|
128
|
+
Go to your Slait dashboard profile page. There's a "Set up Slait CLI" section that shows your key with a copy button.
|
|
129
|
+
|
|
130
|
+
**Will it capture the session I'm currently in?**
|
|
131
|
+
No — hooks only fire for sessions that start after installation. You can manually upload the current session when it's done with `slait upload --cursor --latest`.
|
|
132
|
+
|
|
133
|
+
**What data is sent?**
|
|
134
|
+
The raw transcript (your prompts and AI responses) is sent to the Slait API for analysis. Analysis runs server-side — no API keys are needed on your machine besides the Slait API key.
|
|
135
|
+
|
|
136
|
+
**Can I use it in multiple projects?**
|
|
137
|
+
Yes. Run `npx slait.dev setup <api-key>` in each project directory. Each gets its own dashboard project.
|
|
138
|
+
|
|
139
|
+
**How do I unlink a project?**
|
|
140
|
+
Remove the link file:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
rm -rf ~/.slait/projects/
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Then run `slait init` again to re-link.
|
|
147
|
+
|
|
148
|
+
**Does it work with Cursor CLI (`agent`) mode?**
|
|
149
|
+
The `stop` hook does not fire in headless (`-p`) mode. It works fully in interactive Cursor sessions (both IDE and interactive CLI).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { readConfig, writeConfig } from "../lib/config.js";
|
|
2
|
+
export function runConfigSetKey(key) {
|
|
3
|
+
if (!key.trim()) {
|
|
4
|
+
console.error("Usage: slait config set-key <api_key>");
|
|
5
|
+
process.exit(1);
|
|
6
|
+
}
|
|
7
|
+
const config = readConfig();
|
|
8
|
+
config.api_key = key.trim();
|
|
9
|
+
writeConfig(config);
|
|
10
|
+
console.log("API key saved.");
|
|
11
|
+
}
|
|
12
|
+
export function runConfigSetUrl(url) {
|
|
13
|
+
if (!url.trim()) {
|
|
14
|
+
console.error("Usage: slait config set-url <url>");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
const config = readConfig();
|
|
18
|
+
config.base_url = url.trim().replace(/\/$/, "");
|
|
19
|
+
writeConfig(config);
|
|
20
|
+
console.log(`Base URL set to ${config.base_url}`);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE1D,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAA;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IAC3B,WAAW,CAAC,MAAM,CAAC,CAAA;IACnB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;AAC/B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAA;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,CAAC,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC/C,WAAW,CAAC,MAAM,CAAC,CAAA;IACnB,OAAO,CAAC,GAAG,CAAC,mBAAmB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;AACnD,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function runHooksInstall(opts: {
|
|
2
|
+
cursor?: boolean;
|
|
3
|
+
claude?: boolean;
|
|
4
|
+
}): void;
|
|
5
|
+
export declare function runHooksUninstall(opts: {
|
|
6
|
+
cursor?: boolean;
|
|
7
|
+
claude?: boolean;
|
|
8
|
+
}): void;
|
|
9
|
+
export declare function runHooksStatus(): void;
|
|
10
|
+
export declare function handleCursorSessionStart(): Promise<void>;
|
|
11
|
+
export declare function handleCursorStop(): Promise<void>;
|
|
12
|
+
export declare function handleCursorSessionEnd(): Promise<void>;
|
|
13
|
+
export declare function handleCursorAfterFileEdit(): Promise<void>;
|
|
14
|
+
export declare function handleCursorAfterShellExecution(): Promise<void>;
|
|
15
|
+
export declare function handleCursorPostToolUse(): Promise<void>;
|
|
16
|
+
export declare function handleCursorPostToolUseFailure(): Promise<void>;
|
|
17
|
+
export declare function handleClaudeStop(): Promise<void>;
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { installCursorHooks, uninstallCursorHooks, areCursorHooksInstalled } from "../lib/cursor-hooks.js";
|
|
4
|
+
import { installClaudeHooks, uninstallClaudeHooks, areClaudeHooksInstalled } from "../lib/claude-hooks.js";
|
|
5
|
+
import { requireApiKey, getBaseUrl } from "../lib/config.js";
|
|
6
|
+
import { getProjectLink } from "../lib/project-link.js";
|
|
7
|
+
import { loadSessionState, saveSessionState, removeSessionState } from "../lib/state.js";
|
|
8
|
+
import { resolveTranscriptPath } from "../lib/transcript.js";
|
|
9
|
+
import { cursorJsonlToChatLog, countTurns } from "../lib/format.js";
|
|
10
|
+
import { createSession, updateSession, analyze } from "../lib/api.js";
|
|
11
|
+
import { appendSessionEvent, readSessionEvents, deleteSessionEvents } from "../lib/session-events.js";
|
|
12
|
+
import { readCursorArtifacts } from "../lib/cursor-artifacts.js";
|
|
13
|
+
import { readClaudeArtifacts } from "../lib/claude-artifacts.js";
|
|
14
|
+
export function runHooksInstall(opts) {
|
|
15
|
+
const projectRoot = resolve(process.cwd());
|
|
16
|
+
let total = 0;
|
|
17
|
+
if (opts.cursor) {
|
|
18
|
+
const count = installCursorHooks(projectRoot);
|
|
19
|
+
if (count > 0) {
|
|
20
|
+
console.log(`Installed ${count} Cursor hook(s) in .cursor/hooks.json`);
|
|
21
|
+
total += count;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
console.log("Cursor hooks already installed.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (opts.claude) {
|
|
28
|
+
const count = installClaudeHooks(projectRoot);
|
|
29
|
+
if (count > 0) {
|
|
30
|
+
console.log(`Installed ${count} Claude hook(s) in .claude/settings.json`);
|
|
31
|
+
total += count;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log("Claude hooks already installed.");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!opts.cursor && !opts.claude) {
|
|
38
|
+
console.error("Specify --cursor, --claude, or both.");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
if (total > 0) {
|
|
42
|
+
console.log("\nHooks installed. Sessions will auto-upload when you work in this project.");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function runHooksUninstall(opts) {
|
|
46
|
+
const projectRoot = resolve(process.cwd());
|
|
47
|
+
if (opts.cursor) {
|
|
48
|
+
const removed = uninstallCursorHooks(projectRoot);
|
|
49
|
+
console.log(removed ? "Cursor hooks removed." : "No Cursor hooks found.");
|
|
50
|
+
}
|
|
51
|
+
if (opts.claude) {
|
|
52
|
+
const removed = uninstallClaudeHooks(projectRoot);
|
|
53
|
+
console.log(removed ? "Claude hooks removed." : "No Claude hooks found.");
|
|
54
|
+
}
|
|
55
|
+
if (!opts.cursor && !opts.claude) {
|
|
56
|
+
console.error("Specify --cursor, --claude, or both.");
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function runHooksStatus() {
|
|
61
|
+
const projectRoot = resolve(process.cwd());
|
|
62
|
+
const cursorInstalled = areCursorHooksInstalled(projectRoot);
|
|
63
|
+
const claudeInstalled = areClaudeHooksInstalled(projectRoot);
|
|
64
|
+
console.log(`Cursor hooks: ${cursorInstalled ? "installed" : "not installed"}`);
|
|
65
|
+
console.log(`Claude hooks: ${claudeInstalled ? "installed" : "not installed"}`);
|
|
66
|
+
}
|
|
67
|
+
function readStdinSync() {
|
|
68
|
+
try {
|
|
69
|
+
return readFileSync("/dev/stdin", "utf-8");
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return "{}";
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function parseHookPayload() {
|
|
76
|
+
const raw = readStdinSync();
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(raw);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return { conversation_id: "" };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function uniqueNonEmpty(values) {
|
|
85
|
+
return Array.from(new Set(values.filter((value) => Boolean(value && value.trim()))));
|
|
86
|
+
}
|
|
87
|
+
function loadStateFromPayload(payload) {
|
|
88
|
+
const keys = uniqueNonEmpty([payload.conversation_id, payload.session_id]);
|
|
89
|
+
for (const key of keys) {
|
|
90
|
+
const state = loadSessionState(key);
|
|
91
|
+
if (state)
|
|
92
|
+
return { key, state };
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
function removeStatesForPayload(payload, state) {
|
|
97
|
+
const keys = uniqueNonEmpty([state.conversationId, payload.conversation_id, payload.session_id]);
|
|
98
|
+
for (const key of keys)
|
|
99
|
+
removeSessionState(key);
|
|
100
|
+
}
|
|
101
|
+
function resolveCursorTranscriptPath(state, payload) {
|
|
102
|
+
const ids = uniqueNonEmpty([state.conversationId, payload.conversation_id, payload.session_id]);
|
|
103
|
+
for (const id of ids) {
|
|
104
|
+
const path = resolveTranscriptPath(state.workspacePath, id);
|
|
105
|
+
if (path)
|
|
106
|
+
return path;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
function collectArtifacts(source, workspacePath, rawTranscript) {
|
|
111
|
+
try {
|
|
112
|
+
if (source === "cursor") {
|
|
113
|
+
const artifacts = readCursorArtifacts(workspacePath);
|
|
114
|
+
const configMetadata = {
|
|
115
|
+
plansUsed: Object.keys(artifacts).filter((k) => k.startsWith("Cursor Plan")),
|
|
116
|
+
rulesUsed: Object.keys(artifacts).filter((k) => k.startsWith("Cursor Rule") || k === "AGENTS.md" || k === ".cursorrules"),
|
|
117
|
+
};
|
|
118
|
+
return { supplementaryFiles: artifacts, configMetadata };
|
|
119
|
+
}
|
|
120
|
+
const { supplementaryFiles, configMetadata: claudeMeta } = readClaudeArtifacts(workspacePath, rawTranscript);
|
|
121
|
+
return {
|
|
122
|
+
supplementaryFiles,
|
|
123
|
+
configMetadata: {
|
|
124
|
+
claudeMdPresent: claudeMeta.claudeMdPresent,
|
|
125
|
+
skillsUsed: claudeMeta.skillsUsed,
|
|
126
|
+
pluginsUsed: claudeMeta.pluginsUsed,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return { supplementaryFiles: {}, configMetadata: {} };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export async function handleCursorSessionStart() {
|
|
135
|
+
const payload = parseHookPayload();
|
|
136
|
+
const conversationId = payload.conversation_id || payload.session_id;
|
|
137
|
+
if (!conversationId)
|
|
138
|
+
return;
|
|
139
|
+
const apiKey = requireApiKey();
|
|
140
|
+
const workspacePath = payload.workspace_roots?.[0] ?? process.cwd();
|
|
141
|
+
const link = getProjectLink(resolve(workspacePath));
|
|
142
|
+
if (!link) {
|
|
143
|
+
// Project not linked -- silently skip
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
const { id } = await createSession(apiKey, {
|
|
148
|
+
projectId: link.projectId,
|
|
149
|
+
source: "cursor",
|
|
150
|
+
status: "in_progress",
|
|
151
|
+
sessionLabel: conversationId,
|
|
152
|
+
});
|
|
153
|
+
const now = new Date().toISOString();
|
|
154
|
+
const state = {
|
|
155
|
+
conversationId,
|
|
156
|
+
dashboardSessionId: id,
|
|
157
|
+
projectId: link.projectId,
|
|
158
|
+
source: "cursor",
|
|
159
|
+
workspacePath,
|
|
160
|
+
startedAt: now,
|
|
161
|
+
};
|
|
162
|
+
saveSessionState(state);
|
|
163
|
+
// Save aliases so later hook events can resolve the same dashboard session
|
|
164
|
+
for (const alias of uniqueNonEmpty([payload.conversation_id, payload.session_id])) {
|
|
165
|
+
if (alias !== conversationId) {
|
|
166
|
+
saveSessionState({ ...state, conversationId: alias });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
appendSessionEvent(conversationId, {
|
|
170
|
+
hook: "sessionStart",
|
|
171
|
+
ts: now,
|
|
172
|
+
conversation_id: conversationId,
|
|
173
|
+
session_id: payload.session_id,
|
|
174
|
+
workspace_roots: payload.workspace_roots,
|
|
175
|
+
is_background_agent: payload.is_background_agent,
|
|
176
|
+
composer_mode: payload.composer_mode,
|
|
177
|
+
model: payload.model,
|
|
178
|
+
cursor_version: payload.cursor_version,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Hook failures should be silent to not disrupt the user's workflow
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export async function handleCursorStop() {
|
|
186
|
+
const payload = parseHookPayload();
|
|
187
|
+
const loaded = loadStateFromPayload(payload);
|
|
188
|
+
if (!loaded)
|
|
189
|
+
return;
|
|
190
|
+
const { state } = loaded;
|
|
191
|
+
const conversationId = state.conversationId;
|
|
192
|
+
appendSessionEvent(conversationId, {
|
|
193
|
+
hook: "stop",
|
|
194
|
+
ts: new Date().toISOString(),
|
|
195
|
+
generation_id: payload.generation_id,
|
|
196
|
+
status: payload.status,
|
|
197
|
+
loop_count: payload.loop_count,
|
|
198
|
+
model: payload.model,
|
|
199
|
+
});
|
|
200
|
+
const apiKey = requireApiKey();
|
|
201
|
+
try {
|
|
202
|
+
const transcriptPath = resolveCursorTranscriptPath(state, payload);
|
|
203
|
+
if (!transcriptPath)
|
|
204
|
+
return;
|
|
205
|
+
const raw = readFileSync(transcriptPath, "utf-8");
|
|
206
|
+
const chatLog = cursorJsonlToChatLog(raw);
|
|
207
|
+
const turnCount = countTurns(chatLog);
|
|
208
|
+
const sessionEvents = readSessionEvents(conversationId);
|
|
209
|
+
await updateSession(apiKey, state.dashboardSessionId, {
|
|
210
|
+
rawLog: chatLog,
|
|
211
|
+
turnCount,
|
|
212
|
+
sessionEvents,
|
|
213
|
+
});
|
|
214
|
+
// In some environments sessionEnd may not fire reliably.
|
|
215
|
+
// If stop indicates completion, finalize analysis here as a fallback.
|
|
216
|
+
const finalStatus = (payload.final_status ?? payload.status ?? "").toLowerCase();
|
|
217
|
+
if (finalStatus === "complete" || finalStatus === "completed" || finalStatus === "session_end") {
|
|
218
|
+
const { supplementaryFiles, configMetadata } = collectArtifacts(state.source, state.workspacePath, raw);
|
|
219
|
+
const analysis = await analyze(chatLog, apiKey, supplementaryFiles, configMetadata);
|
|
220
|
+
await updateSession(apiKey, state.dashboardSessionId, {
|
|
221
|
+
rawLog: chatLog,
|
|
222
|
+
turnCount,
|
|
223
|
+
status: "complete",
|
|
224
|
+
analysis,
|
|
225
|
+
sessionEvents,
|
|
226
|
+
supplementaryFiles,
|
|
227
|
+
configMetadata,
|
|
228
|
+
durationMs: payload.duration_ms,
|
|
229
|
+
endReason: payload.final_status ?? payload.status,
|
|
230
|
+
errorMessage: payload.error_message,
|
|
231
|
+
});
|
|
232
|
+
deleteSessionEvents(conversationId);
|
|
233
|
+
removeStatesForPayload(payload, state);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Silent failure
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
export async function handleCursorSessionEnd() {
|
|
241
|
+
const payload = parseHookPayload();
|
|
242
|
+
const loaded = loadStateFromPayload(payload);
|
|
243
|
+
if (!loaded)
|
|
244
|
+
return;
|
|
245
|
+
const { state } = loaded;
|
|
246
|
+
const conversationId = state.conversationId;
|
|
247
|
+
appendSessionEvent(conversationId, {
|
|
248
|
+
hook: "sessionEnd",
|
|
249
|
+
ts: new Date().toISOString(),
|
|
250
|
+
reason: payload.reason,
|
|
251
|
+
duration_ms: payload.duration_ms,
|
|
252
|
+
final_status: payload.final_status,
|
|
253
|
+
error_message: payload.error_message,
|
|
254
|
+
is_background_agent: payload.is_background_agent,
|
|
255
|
+
});
|
|
256
|
+
const apiKey = requireApiKey();
|
|
257
|
+
try {
|
|
258
|
+
const transcriptPath = resolveCursorTranscriptPath(state, payload);
|
|
259
|
+
if (!transcriptPath) {
|
|
260
|
+
deleteSessionEvents(conversationId);
|
|
261
|
+
removeStatesForPayload(payload, state);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const raw = readFileSync(transcriptPath, "utf-8");
|
|
265
|
+
const chatLog = cursorJsonlToChatLog(raw);
|
|
266
|
+
if (!chatLog || chatLog.length < 50) {
|
|
267
|
+
deleteSessionEvents(conversationId);
|
|
268
|
+
removeStatesForPayload(payload, state);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const turnCount = countTurns(chatLog);
|
|
272
|
+
const sessionEvents = readSessionEvents(conversationId);
|
|
273
|
+
const { supplementaryFiles, configMetadata } = collectArtifacts(state.source, state.workspacePath, raw);
|
|
274
|
+
// Run full analysis with supplementary files
|
|
275
|
+
const analysis = await analyze(chatLog, apiKey, supplementaryFiles, configMetadata);
|
|
276
|
+
// Update session with final analysis + events + outcome + artifacts
|
|
277
|
+
await updateSession(apiKey, state.dashboardSessionId, {
|
|
278
|
+
rawLog: chatLog,
|
|
279
|
+
turnCount,
|
|
280
|
+
status: "complete",
|
|
281
|
+
analysis,
|
|
282
|
+
sessionEvents,
|
|
283
|
+
supplementaryFiles,
|
|
284
|
+
configMetadata,
|
|
285
|
+
durationMs: payload.duration_ms,
|
|
286
|
+
endReason: payload.reason ?? payload.final_status,
|
|
287
|
+
errorMessage: payload.error_message,
|
|
288
|
+
});
|
|
289
|
+
const baseUrl = getBaseUrl();
|
|
290
|
+
console.error(`Session analyzed -> ${baseUrl}/session/${state.dashboardSessionId}`);
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
console.error(`[slait] Session analysis failed: ${err.message}`);
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
deleteSessionEvents(conversationId);
|
|
297
|
+
removeStatesForPayload(payload, state);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// ── Behavioral data hooks (fire-and-forget, append to event log only) ────
|
|
301
|
+
const MAX_TOOL_OUTPUT_BYTES = 50_000;
|
|
302
|
+
function truncateToolOutput(output) {
|
|
303
|
+
if (!output || output.length <= MAX_TOOL_OUTPUT_BYTES)
|
|
304
|
+
return output;
|
|
305
|
+
return output.slice(0, MAX_TOOL_OUTPUT_BYTES) + "…[truncated]";
|
|
306
|
+
}
|
|
307
|
+
export async function handleCursorAfterFileEdit() {
|
|
308
|
+
const payload = parseHookPayload();
|
|
309
|
+
const loaded = loadStateFromPayload(payload);
|
|
310
|
+
if (!loaded)
|
|
311
|
+
return;
|
|
312
|
+
appendSessionEvent(loaded.state.conversationId, {
|
|
313
|
+
hook: "afterFileEdit",
|
|
314
|
+
ts: new Date().toISOString(),
|
|
315
|
+
generation_id: payload.generation_id,
|
|
316
|
+
file_path: payload.file_path,
|
|
317
|
+
edits: payload.edits,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
export async function handleCursorAfterShellExecution() {
|
|
321
|
+
const payload = parseHookPayload();
|
|
322
|
+
const loaded = loadStateFromPayload(payload);
|
|
323
|
+
if (!loaded)
|
|
324
|
+
return;
|
|
325
|
+
appendSessionEvent(loaded.state.conversationId, {
|
|
326
|
+
hook: "afterShellExecution",
|
|
327
|
+
ts: new Date().toISOString(),
|
|
328
|
+
generation_id: payload.generation_id,
|
|
329
|
+
command: payload.command,
|
|
330
|
+
duration: payload.duration,
|
|
331
|
+
sandbox: payload.sandbox,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
export async function handleCursorPostToolUse() {
|
|
335
|
+
const payload = parseHookPayload();
|
|
336
|
+
const loaded = loadStateFromPayload(payload);
|
|
337
|
+
if (!loaded)
|
|
338
|
+
return;
|
|
339
|
+
appendSessionEvent(loaded.state.conversationId, {
|
|
340
|
+
hook: "postToolUse",
|
|
341
|
+
ts: new Date().toISOString(),
|
|
342
|
+
generation_id: payload.generation_id,
|
|
343
|
+
tool_name: payload.tool_name,
|
|
344
|
+
tool_input: payload.tool_input,
|
|
345
|
+
tool_output: truncateToolOutput(payload.tool_output),
|
|
346
|
+
tool_use_id: payload.tool_use_id,
|
|
347
|
+
cwd: payload.cwd,
|
|
348
|
+
duration: payload.duration,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
export async function handleCursorPostToolUseFailure() {
|
|
352
|
+
const payload = parseHookPayload();
|
|
353
|
+
const loaded = loadStateFromPayload(payload);
|
|
354
|
+
if (!loaded)
|
|
355
|
+
return;
|
|
356
|
+
appendSessionEvent(loaded.state.conversationId, {
|
|
357
|
+
hook: "postToolUseFailure",
|
|
358
|
+
ts: new Date().toISOString(),
|
|
359
|
+
generation_id: payload.generation_id,
|
|
360
|
+
tool_name: payload.tool_name,
|
|
361
|
+
tool_input: payload.tool_input,
|
|
362
|
+
tool_output: truncateToolOutput(payload.tool_output),
|
|
363
|
+
tool_use_id: payload.tool_use_id,
|
|
364
|
+
cwd: payload.cwd,
|
|
365
|
+
duration: payload.duration,
|
|
366
|
+
error_message: payload.error_message,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
export async function handleClaudeStop() {
|
|
370
|
+
await handleCursorStop();
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
2
|
+
import { basename } from "path";
|
|
3
|
+
import { requireApiKey, getBaseUrl } from "../lib/config.js";
|
|
4
|
+
import { getProjectLink, saveProjectLink } from "../lib/project-link.js";
|
|
5
|
+
import { createProject } from "../lib/api.js";
|
|
6
|
+
export async function runInit(opts) {
|
|
7
|
+
const apiKey = requireApiKey();
|
|
8
|
+
const cwd = resolve(process.cwd());
|
|
9
|
+
const existing = getProjectLink(cwd);
|
|
10
|
+
if (existing) {
|
|
11
|
+
const baseUrl = getBaseUrl();
|
|
12
|
+
console.log(`Already linked to project "${existing.projectName}"`);
|
|
13
|
+
console.log(` Dashboard: ${baseUrl}/project/${existing.projectId}`);
|
|
14
|
+
console.log(` Linked at: ${existing.linkedAt}`);
|
|
15
|
+
console.log(`\nTo re-link, delete ~/.slait/projects/ and run slait init again.`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const projectName = opts.name?.trim() || basename(cwd);
|
|
19
|
+
const source = "cursor";
|
|
20
|
+
console.log(`Linking "${projectName}" to Slait dashboard...`);
|
|
21
|
+
try {
|
|
22
|
+
const { id } = await createProject(apiKey, projectName, source);
|
|
23
|
+
const link = {
|
|
24
|
+
projectId: id,
|
|
25
|
+
projectName,
|
|
26
|
+
localPath: cwd,
|
|
27
|
+
source,
|
|
28
|
+
linkedAt: new Date().toISOString(),
|
|
29
|
+
};
|
|
30
|
+
saveProjectLink(link);
|
|
31
|
+
const baseUrl = getBaseUrl();
|
|
32
|
+
console.log(`Project linked successfully!`);
|
|
33
|
+
console.log(` Dashboard: ${baseUrl}/project/${id}`);
|
|
34
|
+
console.log(`\nNext: run 'slait hooks install --cursor' to enable live tracking.`);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.error(`Failed to create project: ${err.message}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAoB,MAAM,wBAAwB,CAAA;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAE7C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAuB;IACnD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAA;IAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA;IAClC,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;IAEpC,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;QAC5B,OAAO,CAAC,GAAG,CAAC,8BAA8B,QAAQ,CAAC,WAAW,GAAG,CAAC,CAAA;QAClE,OAAO,CAAC,GAAG,CAAC,gBAAgB,OAAO,YAAY,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAA;QACpE,OAAO,CAAC,GAAG,CAAC,gBAAgB,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;QAChD,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAA;QAChF,OAAM;IACR,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAA;IACtD,MAAM,MAAM,GAAG,QAAiB,CAAA;IAEhC,OAAO,CAAC,GAAG,CAAC,YAAY,WAAW,yBAAyB,CAAC,CAAA;IAE7D,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;QAE/D,MAAM,IAAI,GAAgB;YACxB,SAAS,EAAE,EAAE;YACb,WAAW;YACX,SAAS,EAAE,GAAG;YACd,MAAM;YACN,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACnC,CAAA;QACD,eAAe,CAAC,IAAI,CAAC,CAAA;QAErB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;QAC5B,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;QAC3C,OAAO,CAAC,GAAG,CAAC,gBAAgB,OAAO,YAAY,EAAE,EAAE,CAAC,CAAA;QACpD,OAAO,CAAC,GAAG,CAAC,qEAAqE,CAAC,CAAA;IACpF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,6BAA8B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;QACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC"}
|