@sightmap/sightkick 0.4.0 → 0.6.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sightmap/sightkick",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "sightkick — compile a .sightkick/ tool layer + sightmap corpus into WebMCP tool IR, and install the sightkick agent skills (native binary, no Go toolchain required)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://sightmap.org",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@sightmap/sightkick-darwin-arm64": "0.
|
|
38
|
-
"@sightmap/sightkick-darwin-x64": "0.
|
|
39
|
-
"@sightmap/sightkick-linux-arm64": "0.
|
|
40
|
-
"@sightmap/sightkick-linux-x64": "0.
|
|
41
|
-
"@sightmap/sightkick-win32-arm64": "0.
|
|
42
|
-
"@sightmap/sightkick-win32-x64": "0.
|
|
37
|
+
"@sightmap/sightkick-darwin-arm64": "0.6.0",
|
|
38
|
+
"@sightmap/sightkick-darwin-x64": "0.6.0",
|
|
39
|
+
"@sightmap/sightkick-linux-arm64": "0.6.0",
|
|
40
|
+
"@sightmap/sightkick-linux-x64": "0.6.0",
|
|
41
|
+
"@sightmap/sightkick-win32-arm64": "0.6.0",
|
|
42
|
+
"@sightmap/sightkick-win32-x64": "0.6.0"
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -71,13 +71,16 @@ sets them (a conflict warns); `tools` and `journeys` accumulate. Most apps set
|
|
|
71
71
|
- name: add_task # required, unique
|
|
72
72
|
description: Add a task. # shown in getTools(); a result-shape hint is appended automatically
|
|
73
73
|
mode: live # live (default) drives the DOM; api is opt-in reads-only
|
|
74
|
-
ensure_view: Home # a corpus VIEW name
|
|
75
|
-
#
|
|
76
|
-
#
|
|
74
|
+
ensure_view: Home # OPTIONAL: a corpus VIEW name. Omit it and component
|
|
75
|
+
# names resolve against the WHOLE corpus (every view +
|
|
76
|
+
# globals). Set it to scope resolution to one view
|
|
77
|
+
# (+ globals) — disambiguating same-named components —
|
|
78
|
+
# AND to view-scope the tool at runtime (it then only
|
|
79
|
+
# registers on pages whose route matches).
|
|
77
80
|
params: # become the tool's input schema; referenced as {{name}}
|
|
78
81
|
- name: title
|
|
79
82
|
type: string # string | number | boolean | enum
|
|
80
|
-
required: true
|
|
83
|
+
required: true # false ⇒ optional: a step using {{title}} auto-skips when it's omitted
|
|
81
84
|
description: The task title.
|
|
82
85
|
# values: [A, B, C] # required when type: enum
|
|
83
86
|
guard: # optional idempotency guard — exactly one of present/absent
|
|
@@ -88,19 +91,27 @@ sets them (a conflict warns); `tools` and `journeys` accumulate. Most apps set
|
|
|
88
91
|
```
|
|
89
92
|
|
|
90
93
|
A `live` tool needs **at least one `step` or a `returns`**. `ensure_view` is
|
|
91
|
-
optional
|
|
92
|
-
|
|
94
|
+
genuinely **optional**: omit it and a tool resolves its component names against
|
|
95
|
+
the whole corpus (every view's components plus globals). Set it when you want to
|
|
96
|
+
**scope** resolution to a single view — to disambiguate a component name that
|
|
97
|
+
recurs across views — and to **route-scope** the tool so it only registers on
|
|
98
|
+
pages whose route matches. It is a scoping/routing hint, not a prerequisite for
|
|
99
|
+
resolution: a component validly declared on a view resolves with or without it.
|
|
93
100
|
|
|
94
101
|
### Steps (each is a single-key mapping: the op)
|
|
95
102
|
|
|
96
103
|
| Step | Body | Does |
|
|
97
104
|
|------|------|------|
|
|
98
105
|
| `fill` | `query`, `value` | Type `value` (supports `{{param}}`) into the matched input. |
|
|
99
|
-
| `click` | `query` | Click the matched element. |
|
|
106
|
+
| `click` | `query` | Click the matched element, the way a user does — it scrolls the target into view and hit-tests to the topmost element at its centre, so it drives custom widgets whose handler sits on an inner child (e.g. a custom-dropdown option). |
|
|
100
107
|
| `wait_for` | `query`, `timeout_ms` (default 5000) | Wait until the query matches — use after a mutating action to confirm the visible result. |
|
|
108
|
+
| `keypress` | `key` | Dispatch one discrete key (e.g. `Enter`) at whatever a preceding fill/click left focused — no query of its own. For a gate a fill's own per-character keys can't stand in for. |
|
|
101
109
|
| `navigate` | `view` | Client-navigate to a corpus **view** by name. |
|
|
102
110
|
| `goto` | `url` | Navigate to a URL template (`{{param}}` interpolated). |
|
|
103
111
|
|
|
112
|
+
Any step may also carry **`when: "{{param}}"`** — it is skipped when `when`
|
|
113
|
+
interpolates to empty. And a step **auto-skips** when any `{{param}}` it
|
|
114
|
+
interpolates is an *omitted optional* param (see [grouping](#grouping-optional-fields--custom-dropdowns)).
|
|
104
115
|
Reads are **not** steps — declare them with `returns`. A tool that ends with a
|
|
105
116
|
mutation should `wait_for` its own visible feedback before returning.
|
|
106
117
|
|
|
@@ -124,6 +135,51 @@ returns:
|
|
|
124
135
|
done: done
|
|
125
136
|
```
|
|
126
137
|
|
|
138
|
+
## Grouping, optional fields & custom dropdowns
|
|
139
|
+
|
|
140
|
+
**Group tools by meaning, not by field.** Prefer one tool per meaningful unit a
|
|
141
|
+
user or schema would name — a passenger, a date of birth, a contact block — with
|
|
142
|
+
**typed params** (`enum`/`number`/`string`) whose steps reference **named
|
|
143
|
+
components**. Avoid a generic "set any field by its on-screen label" tool: it
|
|
144
|
+
pushes label-guessing onto the agent, throws away the typed contract that is a
|
|
145
|
+
tool's whole value over raw DOM access, and forces brittle `Component[label*=…]`
|
|
146
|
+
matching that degrades into special-casing exactly when it hits a hard field. A
|
|
147
|
+
grouped tool freely mixes step ops — `fill` for text inputs, click-to-open +
|
|
148
|
+
click-the-option for custom dropdowns — since each field's interaction is authored
|
|
149
|
+
explicitly (so "can't generalize across input types" never arises).
|
|
150
|
+
|
|
151
|
+
**Optional fields → optional params + skippable steps.** Mark non-required params
|
|
152
|
+
`required: false`; a step **auto-skips** when a `{{param}}` it interpolates is
|
|
153
|
+
omitted (required params are guaranteed present by the input schema). *Omitted ≠
|
|
154
|
+
empty string* — an explicit `""` is a real value and does not skip. Use an explicit
|
|
155
|
+
`when: "{{param}}"` only for a step that gates on a param it doesn't otherwise
|
|
156
|
+
reference. This also lets a grouped tool double as a **partial setter**:
|
|
157
|
+
`set_passenger(firstName="Joel")` sets just that field.
|
|
158
|
+
|
|
159
|
+
**Custom dropdowns are two clicks, not a special op.** A `<select>`-like custom
|
|
160
|
+
widget (typically an ARIA `button[aria-haspopup=listbox]` + a `[role=option]`
|
|
161
|
+
list) is driven by `click`-ing the trigger to open, then `click`-ing the option —
|
|
162
|
+
the `click` step hits the option the way a user does. Map the trigger and the
|
|
163
|
+
options as corpus components so steps can address `GenderSelect` then
|
|
164
|
+
`GenderSelect Option[label="{{gender}}"]`. No keyboard, no bespoke `select_option`.
|
|
165
|
+
|
|
166
|
+
**Encode order for dependent fields.** When one field changes another's options
|
|
167
|
+
(e.g. country → state/phone), author the steps in order and `wait_for` the
|
|
168
|
+
dependent control before setting it:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
steps:
|
|
172
|
+
- click: { query: 'CountrySelect' }
|
|
173
|
+
- click: { query: 'CountrySelect Option[label="{{country}}"]' }
|
|
174
|
+
- wait_for: { query: 'StateSelect' } # the re-render has landed
|
|
175
|
+
- click: { query: 'StateSelect' }
|
|
176
|
+
- click: { query: 'StateSelect Option[label="{{state}}"]' }
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Reach for a generic `fill_field(field, value)` only** as an escape hatch for a
|
|
180
|
+
large, flat, independent block of homogeneous **text** inputs where typing and
|
|
181
|
+
ordering add nothing — and expect to special-case the structured fields anyway.
|
|
182
|
+
|
|
127
183
|
## Component queries (CSS-shaped, over corpus components)
|
|
128
184
|
|
|
129
185
|
- `Component` — by corpus component name.
|
|
@@ -216,20 +272,28 @@ journeys:
|
|
|
216
272
|
reason: confirm the task you just added
|
|
217
273
|
```
|
|
218
274
|
|
|
275
|
+
A journey's `description` isn't decoration — it's the one-line gloss `sightkick outline` prints
|
|
276
|
+
for that journey (see "Plan time" below), the thing a plan-time reader uses to decide "is this the
|
|
277
|
+
flow I want" before reading a single tool's detail. Write it for that reader: name the outcome, one
|
|
278
|
+
sentence, no jargon a first-time reader of this app wouldn't already have.
|
|
279
|
+
|
|
219
280
|
## Build & fix
|
|
220
281
|
|
|
221
282
|
```sh
|
|
222
283
|
sightkick build <APP_DIR> -o /tmp/x.ir.json # <APP_DIR> holds .sightkick/ + .sightmap/
|
|
223
284
|
sightkick build <APP_DIR> --verify # also checks returns extractors against captured
|
|
224
285
|
# view snapshots; warns on fields empty on every row
|
|
286
|
+
sightkick outline <APP_DIR> # read-back check: what a plan-time agent will see
|
|
225
287
|
```
|
|
226
288
|
|
|
227
289
|
The compiler is your validator. Common diagnostics and fixes:
|
|
228
290
|
|
|
229
|
-
- **unresolved component / property / view** — the name isn't in the corpus
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
291
|
+
- **unresolved component / property / view** — the name isn't in the corpus
|
|
292
|
+
(within the tool's scope: the whole corpus, or one view when `ensure_view` is
|
|
293
|
+
set). `build` prints candidates; fix the query, declare the component/property
|
|
294
|
+
in the corpus (sightmap-authoring), or drop/adjust `ensure_view` if it's
|
|
295
|
+
scoping the name out. Remember property refs resolve against the
|
|
296
|
+
**row/target** component.
|
|
233
297
|
- **`returns has both value and list`** — pick one.
|
|
234
298
|
- **`live tool needs at least one step or a returns`** — add a step or a read.
|
|
235
299
|
- **`unrecognized step op`** / **`not a single-key mapping`** — each step is one
|
|
@@ -240,3 +304,25 @@ The compiler is your validator. Common diagnostics and fixes:
|
|
|
240
304
|
For `--verify` you need a captured snapshot of the view (`sightmap capture` /
|
|
241
305
|
`snapshot` in the sightmap-browser skill). Once `build` is clean, run the tools
|
|
242
306
|
on a live page with the **sightkick-debug** skill.
|
|
307
|
+
|
|
308
|
+
`build` proves the tool layer compiles; `outline` shows what an agent will actually see when it
|
|
309
|
+
tries to use it. Read your new tool's one-liner in the output — if it doesn't identify what the
|
|
310
|
+
tool does on its own, that's an authoring gap (a description that assumes context an agent
|
|
311
|
+
resolving a scenario won't have), not an implementation gap `build` would ever catch.
|
|
312
|
+
|
|
313
|
+
## Plan time
|
|
314
|
+
|
|
315
|
+
Once the tool layer builds clean, a plan-time reader (an agent resolving a `.feature` scenario
|
|
316
|
+
into a plan, or you checking what one would see) never needs the full IR or the raw YAML — see
|
|
317
|
+
`docs/scenario-testing.md` §6/§6.1:
|
|
318
|
+
|
|
319
|
+
```sh
|
|
320
|
+
sightkick outline <APP_DIR> # journeys + every tool's one-liner
|
|
321
|
+
sightkick explain <APP_DIR> --journey add_and_review # full detail for that journey's tools
|
|
322
|
+
sightkick explain <APP_DIR> --view TaskList # or for a view's tools
|
|
323
|
+
sightkick explain <APP_DIR> add_task # or for named tools directly
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
`outline` is the orientation pass (~3 KB on a 16-tool corpus, about an eighth of the IR); `explain`
|
|
327
|
+
fills in description/params/`ensure_view`/returns for a selected subset. Neither carries `steps`,
|
|
328
|
+
`guard`, or a compiled query — that's runtime DOM-addressing detail, not plan-time information.
|
|
@@ -45,8 +45,11 @@ sightmap session, and persist-inject the runtime + tools:
|
|
|
45
45
|
```sh
|
|
46
46
|
sightkick browser <CORPUS_DIR>
|
|
47
47
|
# auto-opens the corpus's home-view URL (or pass --url URL)
|
|
48
|
-
# --webmcp expose the native document.modelContext
|
|
49
|
-
#
|
|
48
|
+
# --webmcp expose the native document.modelContext AND auto-load the
|
|
49
|
+
# bundled WebMCP inspector (+ sightmap's overlay) — open it
|
|
50
|
+
# from Chrome's side panel to drive the tools with Gemini
|
|
51
|
+
# --no-inspector with --webmcp, skip the inspector (native surface only)
|
|
52
|
+
# --extensions P load EXTRA unpacked extensions, merged with the above
|
|
50
53
|
# --profile/--cdp-port/--chrome-flag passed through to sightmap
|
|
51
54
|
# --no-start inject into an already-running session (e.g. after editing the corpus)
|
|
52
55
|
```
|
|
@@ -74,6 +77,11 @@ sightkick runtime -o /tmp/sightkick-runtime.js
|
|
|
74
77
|
sightkick build <CORPUS_DIR> -o /tmp/x.ir.json
|
|
75
78
|
```
|
|
76
79
|
|
|
80
|
+
To *read* the tool layer — what's in it, rather than injecting it — run `sightkick outline
|
|
81
|
+
<CORPUS_DIR>` (journeys + every tool's one-liner) or `explain` for full detail on a subset. Never
|
|
82
|
+
`cat` the IR file for this: roughly two thirds of it is compiled DOM-addressing detail
|
|
83
|
+
(`steps`/`guard`/`Query` trees) that's noise for a reader.
|
|
84
|
+
|
|
77
85
|
Rebuild the IR whenever the corpus/manifest changes. The runtime bundle is
|
|
78
86
|
embedded in the CLI, so re-emit it after upgrading `sightkick`.
|
|
79
87
|
|
|
@@ -94,11 +102,18 @@ sightmap browser start --detach --url <SITE_URL> --profile /tmp/sk-dbg
|
|
|
94
102
|
### Mode B — inspector/Gemini-driven (native WebMCP surface)
|
|
95
103
|
Turn on the blink flags so Chrome exposes the real `document.modelContext`, and
|
|
96
104
|
load the **WebMCP inspector** (a drive-with-Gemini sidebar). Our tools register on
|
|
97
|
-
the native surface, so the inspector reads them like any site's own.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
the native surface, so the inspector reads them like any site's own.
|
|
106
|
+
|
|
107
|
+
The easy path is `sightkick browser <CORPUS_DIR> --webmcp`: it flips the blink
|
|
108
|
+
flags **and** auto-loads the bundled inspector (plus sightmap's overlay). The
|
|
109
|
+
inspector is vendored from upstream
|
|
110
|
+
([`beaufortfrancois/model-context-tool-inspector`](https://github.com/beaufortfrancois/model-context-tool-inspector),
|
|
111
|
+
Apache-2.0) and embedded in the CLI, so nothing to install — open it from Chrome's
|
|
112
|
+
side panel. Add `--no-inspector` for the native surface without it.
|
|
113
|
+
|
|
114
|
+
To do it by hand instead (finer control, or a non-sightkick session), point
|
|
115
|
+
`<INSPECTOR_DIR>` at an unpacked copy of the inspector — the repo's
|
|
116
|
+
`vendor/webmcp-tool/unpacked` (see its `NOTES.md`) or a Chrome-Web-Store install:
|
|
102
117
|
|
|
103
118
|
```sh
|
|
104
119
|
sightmap browser start --detach --url <SITE_URL> --profile /tmp/sk-dbg \
|
|
@@ -136,6 +151,9 @@ sightmap browser eval "window.__t='RUN';document.modelContext.getTools().then(fu
|
|
|
136
151
|
sleep 1; sightmap browser eval "window.__t" # -> ["tool_a","tool_b",...]
|
|
137
152
|
```
|
|
138
153
|
|
|
154
|
+
That's the live, view-scoped names-only listing — the offline, whole-corpus equivalent is
|
|
155
|
+
`sightkick outline <CORPUS_DIR>`, which works with no browser session at all.
|
|
156
|
+
|
|
139
157
|
## 4. Drive the tools
|
|
140
158
|
|
|
141
159
|
### Mode A (agent/scripted): drive via `sightkick call`
|