getobsrv 0.7.2 → 0.8.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 +34 -1
- package/bin/install-skill.js +113 -0
- package/bin/obsrv.js +8 -0
- package/out/cli/args.js +2 -0
- package/out/main/cli.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,6 +28,38 @@ Both panes stay in lock-step (scroll, navigation) and the 1x pane is fully inter
|
|
|
28
28
|
fit), and are shown at true physical size — usually a small, dense render on a
|
|
29
29
|
desktop monitor, exactly like the phone in your hand.
|
|
30
30
|
|
|
31
|
+
## Quickstart
|
|
32
|
+
|
|
33
|
+
**The desktop app** — download the DMG for your chip from
|
|
34
|
+
[Releases](https://github.com/vibesyemmy/obsrv/releases), drag Obsrv.app to
|
|
35
|
+
Applications, then clear the quarantine flag once (the build is not yet
|
|
36
|
+
notarised, so macOS falsely reports it as "damaged"):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
xattr -cr /Applications/Obsrv.app
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Open it and set your monitor's diagonal in Settings — that one number is what
|
|
43
|
+
makes the target pane render at true physical size.
|
|
44
|
+
|
|
45
|
+
**The CLI, and Claude Code / MCP clients:**
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm i -g getobsrv # or use npx -y getobsrv
|
|
49
|
+
obsrv install-skill # teach Claude Code when to use it
|
|
50
|
+
claude mcp add --scope user obsrv -- npx -y getobsrv mcp # give it the tools
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`install-skill` copies the [obsrv-screens skill](skills/obsrv-screens/SKILL.md)
|
|
54
|
+
into `~/.claude/skills/` (`--dest` for elsewhere, `--print` to pipe it into
|
|
55
|
+
another agent framework). The skill is what makes an agent reach for Obsrv on
|
|
56
|
+
its own when frontend work needs checking; the MCP registration is what gives
|
|
57
|
+
it the tools to do so. New sessions pick both up.
|
|
58
|
+
|
|
59
|
+
**Both together** — install the app *and* the tools, then flip **Agent control**
|
|
60
|
+
on in the app's toolbar: agent testing now drives the window you are watching
|
|
61
|
+
instead of rendering invisibly.
|
|
62
|
+
|
|
31
63
|
## Use
|
|
32
64
|
|
|
33
65
|
```bash
|
|
@@ -70,7 +102,8 @@ npx -y getobsrv diff http://localhost:5173 --preset laptop-768 --out-dir diffout
|
|
|
70
102
|
`npx -y getobsrv --help` (or `node bin/obsrv.js --help` in a checkout) lists every preset, profile and flag. Diff findings
|
|
71
103
|
are informational (exit 0); CI thresholds are the caller's job. A ready-made
|
|
72
104
|
Claude Code skill that wraps the loop (snap matrix → read the PNGs → diff →
|
|
73
|
-
fix → re-snap) lives at [skills/obsrv-screens/SKILL.md](skills/obsrv-screens/SKILL.md)
|
|
105
|
+
fix → re-snap) lives at [skills/obsrv-screens/SKILL.md](skills/obsrv-screens/SKILL.md);
|
|
106
|
+
`obsrv install-skill` copies it into `~/.claude/skills/` so agents find it.
|
|
74
107
|
|
|
75
108
|
### MCP server
|
|
76
109
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `obsrv install-skill` — copy the packaged Claude Code skill into the user's
|
|
3
|
+
// skills directory, so an agent picks up the snap → look → diff → fix loop
|
|
4
|
+
// without being told about it. Plain Node: no Electron, no build needed.
|
|
5
|
+
'use strict'
|
|
6
|
+
|
|
7
|
+
const { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } = require('node:fs')
|
|
8
|
+
const { homedir } = require('node:os')
|
|
9
|
+
const { join, resolve } = require('node:path')
|
|
10
|
+
|
|
11
|
+
const SKILL_NAME = 'obsrv-screens'
|
|
12
|
+
const source = join(__dirname, '..', 'skills', SKILL_NAME)
|
|
13
|
+
|
|
14
|
+
function usage() {
|
|
15
|
+
return `obsrv install-skill — install the ${SKILL_NAME} skill for Claude Code
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
obsrv install-skill [flags]
|
|
19
|
+
|
|
20
|
+
Flags:
|
|
21
|
+
--dest <dir> Skills directory to install into (default ~/.claude/skills).
|
|
22
|
+
--force Overwrite an existing, different copy.
|
|
23
|
+
--print Write SKILL.md to stdout instead of installing.
|
|
24
|
+
--help Show this message.
|
|
25
|
+
|
|
26
|
+
Installs to <dest>/${SKILL_NAME}/. New Claude Code sessions pick the skill up;
|
|
27
|
+
sessions already running need a restart.`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Copies a directory tree. Shallow enough for a skill (SKILL.md + optional references). */
|
|
31
|
+
function copyTree(from, to) {
|
|
32
|
+
mkdirSync(to, { recursive: true })
|
|
33
|
+
for (const entry of readdirSync(from)) {
|
|
34
|
+
const src = join(from, entry)
|
|
35
|
+
const dst = join(to, entry)
|
|
36
|
+
if (statSync(src).isDirectory()) copyTree(src, dst)
|
|
37
|
+
else copyFileSync(src, dst)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** True when every file in `from` exists in `to` with identical bytes. */
|
|
42
|
+
function sameTree(from, to) {
|
|
43
|
+
for (const entry of readdirSync(from)) {
|
|
44
|
+
const src = join(from, entry)
|
|
45
|
+
const dst = join(to, entry)
|
|
46
|
+
if (!existsSync(dst)) return false
|
|
47
|
+
if (statSync(src).isDirectory()) {
|
|
48
|
+
if (!statSync(dst).isDirectory() || !sameTree(src, dst)) return false
|
|
49
|
+
} else if (!readFileSync(src).equals(readFileSync(dst))) return false
|
|
50
|
+
}
|
|
51
|
+
return true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function main(argv) {
|
|
55
|
+
let dest = join(homedir(), '.claude', 'skills')
|
|
56
|
+
let force = false
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < argv.length; i++) {
|
|
59
|
+
const flag = argv[i]
|
|
60
|
+
if (flag === '--help' || flag === '-h') {
|
|
61
|
+
console.log(usage())
|
|
62
|
+
return 0
|
|
63
|
+
}
|
|
64
|
+
if (flag === '--print') {
|
|
65
|
+
process.stdout.write(readFileSync(join(source, 'SKILL.md'), 'utf8'))
|
|
66
|
+
return 0
|
|
67
|
+
}
|
|
68
|
+
if (flag === '--force') {
|
|
69
|
+
force = true
|
|
70
|
+
continue
|
|
71
|
+
}
|
|
72
|
+
if (flag === '--dest') {
|
|
73
|
+
const value = argv[++i]
|
|
74
|
+
if (!value) {
|
|
75
|
+
console.error('obsrv install-skill: --dest needs a directory')
|
|
76
|
+
return 2
|
|
77
|
+
}
|
|
78
|
+
dest = resolve(value)
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
console.error(`obsrv install-skill: unknown flag: ${flag}\n\n${usage()}`)
|
|
82
|
+
return 2
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!existsSync(source)) {
|
|
86
|
+
console.error(`obsrv install-skill: the packaged skill is missing (looked in ${source})`)
|
|
87
|
+
return 1
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const target = join(dest, SKILL_NAME)
|
|
91
|
+
if (existsSync(target)) {
|
|
92
|
+
if (sameTree(source, target)) {
|
|
93
|
+
console.error(`obsrv install-skill: already up to date at ${target}`)
|
|
94
|
+
return 0
|
|
95
|
+
}
|
|
96
|
+
if (!force) {
|
|
97
|
+
console.error(
|
|
98
|
+
`obsrv install-skill: ${target} exists and differs — pass --force to overwrite it, ` +
|
|
99
|
+
'or --dest to install elsewhere',
|
|
100
|
+
)
|
|
101
|
+
return 1
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
copyTree(source, target)
|
|
106
|
+
console.error(
|
|
107
|
+
`obsrv install-skill: installed to ${target}\n` +
|
|
108
|
+
'New Claude Code sessions will pick it up; restart any session already running.',
|
|
109
|
+
)
|
|
110
|
+
return 0
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
process.exit(main(process.argv.slice(2)))
|
package/bin/obsrv.js
CHANGED
|
@@ -20,6 +20,14 @@ if (process.argv[2] === 'mcp') {
|
|
|
20
20
|
return
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
// `obsrv install-skill` copies the packaged Claude Code skill into the user's
|
|
24
|
+
// skills directory. Also plain node — it never renders anything.
|
|
25
|
+
if (process.argv[2] === 'install-skill') {
|
|
26
|
+
process.argv.splice(2, 1)
|
|
27
|
+
require('./install-skill.js')
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
const cliEntry = join(__dirname, '..', 'out', 'main', 'cli.js')
|
|
24
32
|
if (!existsSync(cliEntry)) {
|
|
25
33
|
console.error('obsrv: out/main/cli.js is missing — run `npm run build` in the Obsrv repo first')
|
package/out/cli/args.js
CHANGED
|
@@ -22,6 +22,8 @@ function usage() {
|
|
|
22
22
|
Usage:
|
|
23
23
|
obsrv snap <url> [flags] Render <url> on a target screen; write a PNG, print JSON.
|
|
24
24
|
obsrv diff <url> [flags] Render <url> at 1x and against a 2x reference; print JSON metrics.
|
|
25
|
+
obsrv mcp Serve the MCP server on stdio (for Claude Code and other clients).
|
|
26
|
+
obsrv install-skill Install the obsrv-screens skill for Claude Code (--help for flags).
|
|
25
27
|
|
|
26
28
|
Shared flags:
|
|
27
29
|
--preset <id> Screen preset (default ${exports.DEFAULT_PRESET}):
|
package/out/main/cli.js
CHANGED
|
@@ -53,6 +53,8 @@ function usage() {
|
|
|
53
53
|
Usage:
|
|
54
54
|
obsrv snap <url> [flags] Render <url> on a target screen; write a PNG, print JSON.
|
|
55
55
|
obsrv diff <url> [flags] Render <url> at 1x and against a 2x reference; print JSON metrics.
|
|
56
|
+
obsrv mcp Serve the MCP server on stdio (for Claude Code and other clients).
|
|
57
|
+
obsrv install-skill Install the obsrv-screens skill for Claude Code (--help for flags).
|
|
56
58
|
|
|
57
59
|
Shared flags:
|
|
58
60
|
--preset <id> Screen preset (default ${DEFAULT_PRESET}):
|