@peekdev/cli 0.1.0-alpha.11 → 0.1.0-alpha.13
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 +25 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +57 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/lib/claude-skill.d.ts +54 -0
- package/dist/lib/claude-skill.d.ts.map +1 -0
- package/dist/lib/claude-skill.js +88 -0
- package/dist/lib/claude-skill.js.map +1 -0
- package/dist/skills/peek-skill.md +182 -0
- package/package.json +16 -2
package/README.md
CHANGED
|
@@ -77,6 +77,31 @@ Full data-handling policy: [`docs/peek/PRIVACY_POLICY.md`](https://github.com/Cu
|
|
|
77
77
|
|
|
78
78
|
If your client isn't auto-detected, `peek init` prints the JSON config you can paste manually. The MCP server speaks the standard stdio protocol (spec 2025-11-25 + 2025-03-26 back-compat).
|
|
79
79
|
|
|
80
|
+
### Claude Code skill
|
|
81
|
+
|
|
82
|
+
When Claude Code is among the configured clients (or `~/.claude.json` already exists), `peek init` also drops a SKILL.md into `~/.claude/skills/peek/`. Claude Code loads it on session start and uses it to decide *when* to reach for peek's MCP tools — investigating an error from a manual repro, generating a Playwright test from a session, querying DOM state at a past moment, etc.
|
|
83
|
+
|
|
84
|
+
The skill is idempotent on re-run (no-op when the on-disk content matches the bundled source). Skip the install with `peek init --skip-skill`. Want it without running `peek init`? See the curl-able recipe at [`docs/peek/distribution/claude-code-skill.md`](https://github.com/Cubenest/rrweb-stack/blob/main/docs/peek/distribution/claude-code-skill.md).
|
|
85
|
+
|
|
86
|
+
### Cursor — project-level recipe
|
|
87
|
+
|
|
88
|
+
`peek init` writes Cursor's MCP server entry to the global config at `~/.cursor/mcp.json` — every project opened in Cursor inherits it. If you'd rather scope peek to one project (a repo where peek captures matter but other repos on the same machine should not surface the tools), drop a `.cursor/mcp.json` into the workspace root:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"peek": {
|
|
94
|
+
"command": "npx",
|
|
95
|
+
"args": ["-y", "@peekdev/mcp"]
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Commit it or add it to `.gitignore` — Cursor reads either. Cursor's docs document the global file as "tools available everywhere" and the project file as "project-specific tools" (see [docs.cursor.com/context/mcp](https://cursor.com/docs/context/mcp) for current merge semantics).
|
|
102
|
+
|
|
103
|
+
This is the same block `peek init` writes to the global file, so the two configs are interchangeable. You still need the [Peek Chrome extension](https://chromewebstore.google.com/) installed and the native messaging host registered — run `peek init --skip-clients` if you want the host installed without touching any MCP config.
|
|
104
|
+
|
|
80
105
|
## Versioning & compatibility
|
|
81
106
|
|
|
82
107
|
Semantic Versioning. Currently `0.1.0-alpha.x` — pre-release; the CLI surface is stable in spirit but flags may rename. See [SUPPORTED.md](https://github.com/Cubenest/rrweb-stack/blob/main/SUPPORTED.md) for the compatibility matrix.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAsWA,+DAA+D;AAC/D,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAsC7D"}
|
package/dist/commands/init.js
CHANGED
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
// affirmatively opts in, so we call the installer directly with realSink).
|
|
8
8
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import { homedir } from 'node:os';
|
|
10
|
+
import { join } from 'node:path';
|
|
10
11
|
import { parseArgs } from 'node:util';
|
|
11
12
|
import { buildManifest, hostBinaryPath, installManifests, loadExtensionIds, realSink, resolveInstallTargets, } from '@peekdev/mcp/native-host';
|
|
13
|
+
import { installSkill } from '../lib/claude-skill.js';
|
|
12
14
|
import { chromeExtensionOrigin, extractDevId, validateChromeExtensionId, } from '../lib/extension-id.js';
|
|
13
15
|
import { atomicWriteFileSync } from '../lib/fs-atomic.js';
|
|
14
16
|
import { PEEK_BLOCK_SNIPPET, containsJsonComments, detectClients, hasPeekServer, mergePeekConfig, serializeConfig, } from '../lib/init-config.js';
|
|
@@ -75,7 +77,7 @@ async function configureClients(homeDir, cwd) {
|
|
|
75
77
|
})));
|
|
76
78
|
if (chosen.length === 0) {
|
|
77
79
|
process.stdout.write('No clients selected; skipping MCP config.\n');
|
|
78
|
-
return;
|
|
80
|
+
return [];
|
|
79
81
|
}
|
|
80
82
|
for (const client of chosen) {
|
|
81
83
|
const already = (() => {
|
|
@@ -106,6 +108,54 @@ async function configureClients(homeDir, cwd) {
|
|
|
106
108
|
process.stdout.write(` ✗ ${client.label}: ${client.configPath} — ${res.error}\n`);
|
|
107
109
|
}
|
|
108
110
|
}
|
|
111
|
+
return chosen;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Drop the peek Claude Code Skill (SKILL.md) into `~/.claude/skills/peek/`.
|
|
115
|
+
*
|
|
116
|
+
* The skill guides Claude Code on when to reach for peek's MCP tools — it's
|
|
117
|
+
* complementary to the `mcpServers.peek` block written by configureClients
|
|
118
|
+
* (the latter exposes the tools; the skill teaches Claude when to use them).
|
|
119
|
+
*
|
|
120
|
+
* Runs when Claude Code is among the just-configured clients OR already has
|
|
121
|
+
* `~/.claude.json` (i.e. the user has Claude Code installed regardless of
|
|
122
|
+
* whether they re-selected it in this run). Skipped via `--skip-skill`.
|
|
123
|
+
*
|
|
124
|
+
* Idempotent: re-running over an identical file is a no-op.
|
|
125
|
+
*/
|
|
126
|
+
function installClaudeSkill(homeDir, chosenClients) {
|
|
127
|
+
const claudeChosen = chosenClients.some((c) => c.id === 'claude-code');
|
|
128
|
+
const claudeConfigExists = existsSync(join(homeDir, '.claude.json'));
|
|
129
|
+
if (!claudeChosen && !claudeConfigExists) {
|
|
130
|
+
// No Claude Code on this machine + the user didn't ask to configure it.
|
|
131
|
+
// Don't write a skill for a tool they don't have.
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const result = installSkill(homeDir, {
|
|
135
|
+
fileExists: existsSync,
|
|
136
|
+
readFile: (p) => readFileSync(p, 'utf8'),
|
|
137
|
+
mkdir: (p) => mkdirSync(p, { recursive: true }),
|
|
138
|
+
writeFile: (p, c) => atomicWriteFileSync(p, c),
|
|
139
|
+
});
|
|
140
|
+
switch (result.status) {
|
|
141
|
+
case 'wrote':
|
|
142
|
+
process.stdout.write(` ✔ Wrote Claude Code skill: ${result.target}\n`);
|
|
143
|
+
break;
|
|
144
|
+
case 'updated':
|
|
145
|
+
process.stdout.write(` ✔ Refreshed Claude Code skill: ${result.target}\n`);
|
|
146
|
+
break;
|
|
147
|
+
case 'unchanged':
|
|
148
|
+
process.stdout.write(` · Claude Code skill already current: ${result.target}\n`);
|
|
149
|
+
break;
|
|
150
|
+
case 'source_missing':
|
|
151
|
+
// Should never happen in a published tarball — postbuild copies it in.
|
|
152
|
+
// If it does (e.g. broken local dev environment), say so but don't fail.
|
|
153
|
+
process.stdout.write(` ! Claude Code skill source missing at ${result.source}; skipped. (Reinstall @peekdev/cli.)\n`);
|
|
154
|
+
break;
|
|
155
|
+
case 'error':
|
|
156
|
+
process.stdout.write(` ✗ Claude Code skill: ${result.target} — ${result.error}\n`);
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
109
159
|
}
|
|
110
160
|
/**
|
|
111
161
|
* P-13 (2026-05-28 QA walk): read the first existing native-host manifest from
|
|
@@ -250,6 +300,7 @@ export async function runInit(argv) {
|
|
|
250
300
|
options: {
|
|
251
301
|
'skip-native-host': { type: 'boolean' },
|
|
252
302
|
'skip-clients': { type: 'boolean' },
|
|
303
|
+
'skip-skill': { type: 'boolean' },
|
|
253
304
|
},
|
|
254
305
|
allowPositionals: false,
|
|
255
306
|
});
|
|
@@ -257,8 +308,12 @@ export async function runInit(argv) {
|
|
|
257
308
|
const homeDir = homedir();
|
|
258
309
|
const cwd = process.cwd();
|
|
259
310
|
process.stdout.write('peek init — configure MCP clients + the native messaging host.\n\n');
|
|
311
|
+
let chosenClients = [];
|
|
260
312
|
if (!values['skip-clients']) {
|
|
261
|
-
await configureClients(homeDir, cwd);
|
|
313
|
+
chosenClients = await configureClients(homeDir, cwd);
|
|
314
|
+
}
|
|
315
|
+
if (!values['skip-skill']) {
|
|
316
|
+
installClaudeSkill(homeDir, chosenClients);
|
|
262
317
|
}
|
|
263
318
|
if (!values['skip-native-host']) {
|
|
264
319
|
if (SUPPORTED.includes(platform)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Where Claude Code looks for the peek skill on a user's machine. */
|
|
2
|
+
export declare function claudeSkillTargetPath(homeDir: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Path to the canonical skill content shipped in the installed npm tarball.
|
|
5
|
+
*
|
|
6
|
+
* After `pnpm build`, `scripts/postbuild.mjs` copies `skills/peek-skill.md`
|
|
7
|
+
* to `dist/skills/peek-skill.md`. This function resolves the path RELATIVE
|
|
8
|
+
* to the running JS so the same logic works for:
|
|
9
|
+
* - the published tarball: `<pkg>/dist/lib/claude-skill.js` →
|
|
10
|
+
* `<pkg>/dist/skills/peek-skill.md`
|
|
11
|
+
* - a local `pnpm --filter @peekdev/cli build` checkout: same shape, both
|
|
12
|
+
* under `dist/`.
|
|
13
|
+
*
|
|
14
|
+
* (When running via ts-node / vitest directly against the .ts source — i.e.
|
|
15
|
+
* during tests — this path resolves under `src/lib/`, which is NOT where the
|
|
16
|
+
* markdown lives. That's why tests inject their own `readFile` rather than
|
|
17
|
+
* exercising this resolver against the filesystem.)
|
|
18
|
+
*/
|
|
19
|
+
export declare function defaultSkillSourcePath(): string;
|
|
20
|
+
/** Side-effect dependencies. Tests inject mocks; the command shell uses node:fs. */
|
|
21
|
+
export interface SkillIO {
|
|
22
|
+
readonly readFile: (path: string) => string;
|
|
23
|
+
readonly writeFile: (path: string, content: string) => void;
|
|
24
|
+
readonly mkdir: (path: string) => void;
|
|
25
|
+
readonly fileExists: (path: string) => boolean;
|
|
26
|
+
}
|
|
27
|
+
export type InstallSkillOutcome = {
|
|
28
|
+
readonly status: 'wrote';
|
|
29
|
+
readonly target: string;
|
|
30
|
+
} | {
|
|
31
|
+
readonly status: 'updated';
|
|
32
|
+
readonly target: string;
|
|
33
|
+
} | {
|
|
34
|
+
readonly status: 'unchanged';
|
|
35
|
+
readonly target: string;
|
|
36
|
+
} | {
|
|
37
|
+
readonly status: 'source_missing';
|
|
38
|
+
readonly source: string;
|
|
39
|
+
} | {
|
|
40
|
+
readonly status: 'error';
|
|
41
|
+
readonly target: string;
|
|
42
|
+
readonly error: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Install (or refresh) the peek SKILL.md at `~/.claude/skills/peek/SKILL.md`.
|
|
46
|
+
*
|
|
47
|
+
* Idempotent — re-running over an identical file is a no-op (returns
|
|
48
|
+
* `unchanged`). Overwrites an out-of-date file in place (returns `updated`).
|
|
49
|
+
*
|
|
50
|
+
* Never deletes anything; never reads any user state other than the existing
|
|
51
|
+
* SKILL.md it would replace.
|
|
52
|
+
*/
|
|
53
|
+
export declare function installSkill(homeDir: string, io: SkillIO, sourcePath?: string): InstallSkillOutcome;
|
|
54
|
+
//# sourceMappingURL=claude-skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-skill.d.ts","sourceRoot":"","sources":["../../src/lib/claude-skill.ts"],"names":[],"mappings":"AAgBA,sEAAsE;AACtE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAG/C;AAED,oFAAoF;AACpF,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAChD;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElF;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,OAAO,EACX,UAAU,GAAE,MAAiC,GAC5C,mBAAmB,CAyCrB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Claude Code Skill installer. Writes a self-documenting SKILL.md into
|
|
2
|
+
// `~/.claude/skills/peek/SKILL.md` so Claude Code auto-loads it on session
|
|
3
|
+
// start and knows when to reach for peek's MCP tools.
|
|
4
|
+
//
|
|
5
|
+
// The canonical skill content lives at `packages/peek-cli/skills/peek-skill.md`
|
|
6
|
+
// in the repo. `scripts/postbuild.mjs` copies that folder into `dist/skills/`
|
|
7
|
+
// so the installed npm tarball can read it relative to the running JS via
|
|
8
|
+
// `defaultSkillSourcePath()` below.
|
|
9
|
+
//
|
|
10
|
+
// Plain-function shell — no command-line side effects in this module. Tests
|
|
11
|
+
// inject `readFile` + `writeFile` + `mkdir` to verify behavior without
|
|
12
|
+
// touching the real filesystem.
|
|
13
|
+
import { dirname, join } from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
/** Where Claude Code looks for the peek skill on a user's machine. */
|
|
16
|
+
export function claudeSkillTargetPath(homeDir) {
|
|
17
|
+
return join(homeDir, '.claude', 'skills', 'peek', 'SKILL.md');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Path to the canonical skill content shipped in the installed npm tarball.
|
|
21
|
+
*
|
|
22
|
+
* After `pnpm build`, `scripts/postbuild.mjs` copies `skills/peek-skill.md`
|
|
23
|
+
* to `dist/skills/peek-skill.md`. This function resolves the path RELATIVE
|
|
24
|
+
* to the running JS so the same logic works for:
|
|
25
|
+
* - the published tarball: `<pkg>/dist/lib/claude-skill.js` →
|
|
26
|
+
* `<pkg>/dist/skills/peek-skill.md`
|
|
27
|
+
* - a local `pnpm --filter @peekdev/cli build` checkout: same shape, both
|
|
28
|
+
* under `dist/`.
|
|
29
|
+
*
|
|
30
|
+
* (When running via ts-node / vitest directly against the .ts source — i.e.
|
|
31
|
+
* during tests — this path resolves under `src/lib/`, which is NOT where the
|
|
32
|
+
* markdown lives. That's why tests inject their own `readFile` rather than
|
|
33
|
+
* exercising this resolver against the filesystem.)
|
|
34
|
+
*/
|
|
35
|
+
export function defaultSkillSourcePath() {
|
|
36
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
37
|
+
return join(here, '..', 'skills', 'peek-skill.md');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Install (or refresh) the peek SKILL.md at `~/.claude/skills/peek/SKILL.md`.
|
|
41
|
+
*
|
|
42
|
+
* Idempotent — re-running over an identical file is a no-op (returns
|
|
43
|
+
* `unchanged`). Overwrites an out-of-date file in place (returns `updated`).
|
|
44
|
+
*
|
|
45
|
+
* Never deletes anything; never reads any user state other than the existing
|
|
46
|
+
* SKILL.md it would replace.
|
|
47
|
+
*/
|
|
48
|
+
export function installSkill(homeDir, io, sourcePath = defaultSkillSourcePath()) {
|
|
49
|
+
if (!io.fileExists(sourcePath)) {
|
|
50
|
+
return { status: 'source_missing', source: sourcePath };
|
|
51
|
+
}
|
|
52
|
+
let content;
|
|
53
|
+
try {
|
|
54
|
+
content = io.readFile(sourcePath);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
return {
|
|
58
|
+
status: 'error',
|
|
59
|
+
target: claudeSkillTargetPath(homeDir),
|
|
60
|
+
error: err instanceof Error ? err.message : String(err),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const target = claudeSkillTargetPath(homeDir);
|
|
64
|
+
const targetExists = io.fileExists(target);
|
|
65
|
+
if (targetExists) {
|
|
66
|
+
try {
|
|
67
|
+
if (io.readFile(target) === content) {
|
|
68
|
+
return { status: 'unchanged', target };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// unreadable existing file — fall through and overwrite it
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
io.mkdir(dirname(target));
|
|
77
|
+
io.writeFile(target, content);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
return {
|
|
81
|
+
status: 'error',
|
|
82
|
+
target,
|
|
83
|
+
error: err instanceof Error ? err.message : String(err),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return { status: targetExists ? 'updated' : 'wrote', target };
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=claude-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-skill.js","sourceRoot":"","sources":["../../src/lib/claude-skill.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,2EAA2E;AAC3E,sDAAsD;AACtD,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,0EAA0E;AAC1E,oCAAoC;AACpC,EAAE;AACF,4EAA4E;AAC5E,uEAAuE;AACvE,gCAAgC;AAEhC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,sEAAsE;AACtE,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,OAAO,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;AACrD,CAAC;AAiBD;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAe,EACf,EAAW,EACX,aAAqB,sBAAsB,EAAE;IAE7C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAC1D,CAAC;IAED,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,qBAAqB,CAAC,OAAO,CAAC;YACtC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,OAAO,EAAE,CAAC;gBACpC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;YACzC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;QAC7D,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1B,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,MAAM,EAAE,OAAO;YACf,MAAM;YACN,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: peek
|
|
3
|
+
description: Use when the user mentions a recent browser session, an error they just reproduced, "what was the user doing before X", DOM state at some past moment, or wants to turn a manual repro into a Playwright test. Peek exposes 10 MCP tools backed by a local SQLite store of rrweb-captured browser sessions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# peek — local browser-session inspection
|
|
7
|
+
|
|
8
|
+
Peek is an OSS browser companion for AI coding agents. A Chrome MV3
|
|
9
|
+
extension records masked rrweb sessions to a local SQLite store
|
|
10
|
+
(`~/.peek/sessions.db`); a stdio MCP server exposes 10 tools that let you
|
|
11
|
+
inspect those sessions and (with consent) drive the live browser.
|
|
12
|
+
|
|
13
|
+
Peek runs entirely on the user's machine. No telemetry, no cloud, no
|
|
14
|
+
account. If `~/.peek/sessions.db` is absent, peek isn't installed yet —
|
|
15
|
+
direct the user to `npx @peekdev/cli init` and stop.
|
|
16
|
+
|
|
17
|
+
## When to invoke
|
|
18
|
+
|
|
19
|
+
Reach for peek when the user mentions any of these:
|
|
20
|
+
|
|
21
|
+
- "what happened in my last session" / "show me my recent sessions"
|
|
22
|
+
- "investigate this error" alongside a manual repro they just performed
|
|
23
|
+
- "what was the user doing when X failed" / "what action triggered X"
|
|
24
|
+
- "what did the DOM look like when Y happened"
|
|
25
|
+
- "turn what I just did into a Playwright test"
|
|
26
|
+
- "click the foo button on this page" (write tools, with consent)
|
|
27
|
+
- "fill in this form on the page open in my browser" (write tools, with
|
|
28
|
+
consent)
|
|
29
|
+
|
|
30
|
+
Don't reach for peek when:
|
|
31
|
+
|
|
32
|
+
- The user is asking about production / remote / non-local data
|
|
33
|
+
- A test-runner integration is already in scope — use
|
|
34
|
+
`@tracelane/wdio` (or the upcoming `@tracelane/playwright-reporter`)
|
|
35
|
+
for test-failure capture instead
|
|
36
|
+
- The user wants live page introspection at the current moment with no
|
|
37
|
+
prior recording — peek is for *replaying* what was already captured,
|
|
38
|
+
not a live debugger
|
|
39
|
+
- The question is about static code, not runtime behavior
|
|
40
|
+
|
|
41
|
+
## The 10 tools
|
|
42
|
+
|
|
43
|
+
**Read tools (8) — work at permission Level 2+ for the origin:**
|
|
44
|
+
|
|
45
|
+
| Tool | When |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `list_recent_sessions` | Always the first call. Returns `[{ sessionId, origin, startedAt, endedAt, eventCount, ... }]` for the last N sessions. |
|
|
48
|
+
| `get_session_summary` | Narrative summary of one session — what the user did, top-level errors, key navigations. Start here after `list_recent_sessions` picks the target. |
|
|
49
|
+
| `get_session_console_errors` | All `console.error` / uncaught exceptions in the session, with timestamps. |
|
|
50
|
+
| `get_session_network_errors` | All ≥ 400 responses, with request URL, method, status, and (where deep-capture was enabled) redacted body. |
|
|
51
|
+
| `get_user_action_before_error` | Walks rrweb input events backward from a given timestamp; returns the last meaningful user action (click target, form input, navigation). Use right after spotting a console/network error. |
|
|
52
|
+
| `get_dom_snapshot` | Returns the DOM at a given timestamp as a serialized tree. Use to understand what was on screen when something happened. |
|
|
53
|
+
| `query_dom_history` | Given a CSS selector + sessionId, returns every snapshot where that element changed. Good for "when did this element appear/disappear/change text". |
|
|
54
|
+
| `generate_playwright_repro` | Turns a session (or a slice of one) into a runnable Playwright test stub. Selectors are best-effort from rrweb metadata; surface to the user for review before assuming they'll work. |
|
|
55
|
+
|
|
56
|
+
**Write tools (2) — escalating consent required:**
|
|
57
|
+
|
|
58
|
+
| Tool | When |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `request_authorization` | Ask the user to authorize a specific action against a specific origin. Always call this BEFORE `execute_action` if the action is destructive (form submission, navigation away from the current page, anything that mutates state). |
|
|
61
|
+
| `execute_action` | Performs a click / type / navigate in the user's live browser. Gated by the per-origin permission level — Level 3 covers safe reads, Level 4 covers actions with destructive-action consent, Level 5 is full automation. |
|
|
62
|
+
|
|
63
|
+
## Workflow
|
|
64
|
+
|
|
65
|
+
The shape of almost every peek conversation:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
1. list_recent_sessions
|
|
69
|
+
→ pick the sessionId the user means (usually the most recent;
|
|
70
|
+
prompt if ambiguous)
|
|
71
|
+
|
|
72
|
+
2. get_session_summary(sessionId)
|
|
73
|
+
→ understand what happened in plain language
|
|
74
|
+
|
|
75
|
+
3. Drill down based on the user's question:
|
|
76
|
+
- errors → get_session_console_errors / get_session_network_errors
|
|
77
|
+
- timing → get_user_action_before_error(sessionId, atTimestamp)
|
|
78
|
+
- DOM state → get_dom_snapshot(sessionId, atTimestamp)
|
|
79
|
+
- element history → query_dom_history(sessionId, selector)
|
|
80
|
+
- repro test → generate_playwright_repro(sessionId, fromTs, toTs)
|
|
81
|
+
|
|
82
|
+
4. (Optional, gated) write tools — only when the user explicitly asks
|
|
83
|
+
peek to *do* something in their browser:
|
|
84
|
+
- destructive? → request_authorization first, surface the prompt,
|
|
85
|
+
only then execute_action
|
|
86
|
+
- safe (read-only-equivalent click)? → execute_action with the
|
|
87
|
+
least-privilege scope
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Examples
|
|
91
|
+
|
|
92
|
+
### Investigating a 500 error from a manual repro
|
|
93
|
+
|
|
94
|
+
User: "I just got a 500 on the dashboard, what happened?"
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
1. list_recent_sessions
|
|
98
|
+
→ grab the most recent session for the dashboard origin
|
|
99
|
+
2. get_session_network_errors(sessionId)
|
|
100
|
+
→ find the 500: POST /api/save, body field "name" was empty
|
|
101
|
+
3. get_user_action_before_error(sessionId, errorTs)
|
|
102
|
+
→ user clicked "Save" with empty form
|
|
103
|
+
4. (optional) get_dom_snapshot(sessionId, errorTs - 100)
|
|
104
|
+
→ confirm the form state right before the click
|
|
105
|
+
5. Tell the user: "You submitted /api/save with an empty `name` field,
|
|
106
|
+
the server returned 500. The form's required-field validation didn't
|
|
107
|
+
fire. Want me to add a Playwright test for this?"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Generating a Playwright test from a manual repro
|
|
111
|
+
|
|
112
|
+
User: "Write a Playwright test for the bug I just reproduced."
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
1. list_recent_sessions
|
|
116
|
+
→ the most recent session
|
|
117
|
+
2. get_session_summary(sessionId)
|
|
118
|
+
→ confirm with the user: "I see you logged in, opened settings,
|
|
119
|
+
clicked Delete account, saw the confirmation dialog, and the
|
|
120
|
+
test fails when the dialog closes early — is this what you
|
|
121
|
+
want a test for?"
|
|
122
|
+
3. generate_playwright_repro(sessionId)
|
|
123
|
+
→ returns a test file stub
|
|
124
|
+
4. Show the user the stub; ask which selectors look fragile.
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Clicking a button on the user's live browser (consent flow)
|
|
128
|
+
|
|
129
|
+
User: "Click the Save button on the page I have open."
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
1. Identify the target origin from list_recent_sessions OR from context
|
|
133
|
+
2. request_authorization({
|
|
134
|
+
tool: 'execute_action',
|
|
135
|
+
origin: 'https://app.example.com',
|
|
136
|
+
action: 'click',
|
|
137
|
+
selector: '#save-button',
|
|
138
|
+
destructive: false,
|
|
139
|
+
})
|
|
140
|
+
→ surface the consent prompt to the user
|
|
141
|
+
3. If approved → execute_action with the same args
|
|
142
|
+
4. If declined → say so and stop. Do not retry.
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Permission model
|
|
146
|
+
|
|
147
|
+
Peek uses a five-level per-origin model. The state lives in
|
|
148
|
+
`~/.peek/permissions.json`; the user manages it via the extension's
|
|
149
|
+
side panel and `peek audit` (CLI).
|
|
150
|
+
|
|
151
|
+
- **Level 0** — no access (default for new origins)
|
|
152
|
+
- **Level 1** — list-only (sessionId + origin + timestamps; no event content)
|
|
153
|
+
- **Level 2** — read full session content (all 8 read tools usable)
|
|
154
|
+
- **Level 3** — read + safe actions (clicks, typing in inputs; no
|
|
155
|
+
navigation away, no form submission)
|
|
156
|
+
- **Level 4** — read + actions including destructive (with per-action
|
|
157
|
+
`request_authorization` consent)
|
|
158
|
+
- **Level 5** — automation (Level 4 actions without per-action consent;
|
|
159
|
+
rare, opt-in only)
|
|
160
|
+
|
|
161
|
+
If a tool returns `{ error: 'permission_denied', origin, currentLevel,
|
|
162
|
+
requiredLevel }`, tell the user how to escalate (via the side panel)
|
|
163
|
+
and stop. Don't retry, don't suggest workarounds.
|
|
164
|
+
|
|
165
|
+
## Safety floor
|
|
166
|
+
|
|
167
|
+
- Never invent sessions. If `list_recent_sessions` returns empty, say so
|
|
168
|
+
and suggest the user record a session via the extension.
|
|
169
|
+
- Never invent tool names. The 10 above are the entire surface.
|
|
170
|
+
- Selector results from `generate_playwright_repro` are derived from
|
|
171
|
+
rrweb event metadata. Surface them for review; don't claim a generated
|
|
172
|
+
test is production-ready without the user confirming.
|
|
173
|
+
- Destructive write actions (form submits, navigation off-page, deletes)
|
|
174
|
+
ALWAYS require a fresh `request_authorization` call. Never reuse a
|
|
175
|
+
prior authorization for a different action.
|
|
176
|
+
|
|
177
|
+
## See also
|
|
178
|
+
|
|
179
|
+
- npm: <https://www.npmjs.com/package/@peekdev/cli> · <https://www.npmjs.com/package/@peekdev/mcp>
|
|
180
|
+
- Source: <https://github.com/Cubenest/rrweb-stack>
|
|
181
|
+
- Docs: <https://cubenest.in/peek>
|
|
182
|
+
- Privacy policy: <https://github.com/Cubenest/rrweb-stack/blob/main/docs/peek/PRIVACY_POLICY.md>
|
package/package.json
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peekdev/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.13",
|
|
4
4
|
"description": "peek command-line tool. A thin read-mostly client of the native host's ~/.peek/sessions.db (ADR-0007): status, sessions list/show/export/delete, the `peek init` MCP-client wizard, and `peek audit log`.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"peek",
|
|
7
|
+
"mcp",
|
|
8
|
+
"model-context-protocol",
|
|
9
|
+
"browser",
|
|
10
|
+
"claude-code",
|
|
11
|
+
"cursor",
|
|
12
|
+
"ai-coding-agent",
|
|
13
|
+
"session-replay"
|
|
14
|
+
],
|
|
5
15
|
"license": "Apache-2.0",
|
|
16
|
+
"funding": {
|
|
17
|
+
"type": "github",
|
|
18
|
+
"url": "https://github.com/sponsors/harry-harish"
|
|
19
|
+
},
|
|
6
20
|
"type": "module",
|
|
7
21
|
"bin": {
|
|
8
22
|
"peek": "./dist/index.js"
|
|
@@ -22,7 +36,7 @@
|
|
|
22
36
|
],
|
|
23
37
|
"dependencies": {
|
|
24
38
|
"better-sqlite3": "^12.10.0",
|
|
25
|
-
"@peekdev/mcp": "0.1.0-alpha.
|
|
39
|
+
"@peekdev/mcp": "0.1.0-alpha.8"
|
|
26
40
|
},
|
|
27
41
|
"devDependencies": {
|
|
28
42
|
"@types/better-sqlite3": "^7.6.13",
|