@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.4.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.4.0",
38
- "@sightmap/sightkick-darwin-x64": "0.4.0",
39
- "@sightmap/sightkick-linux-arm64": "0.4.0",
40
- "@sightmap/sightkick-linux-x64": "0.4.0",
41
- "@sightmap/sightkick-win32-arm64": "0.4.0",
42
- "@sightmap/sightkick-win32-x64": "0.4.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 scopes component resolution to that
75
- # view (+ globals) AND view-scopes the tool at runtime
76
- # (it only registers on pages whose route matches)
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 but recommended it both disambiguates component names and controls
92
- which page the tool appears on.
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 (for
230
- that view). `build` prints candidates; fix the query, or declare the
231
- component/property in the corpus (sightmap-authoring). Remember property refs
232
- resolve against the **row/target** component.
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 (adds the blink flags)
49
- # --extensions P load an unpacked extension (e.g. a WebMCP inspector)
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. The inspector
98
- isn't shipped with the CLI — use the vendored copy in the sightkick repo
99
- (`vendor/webmcp-tool/unpacked`, whose `NOTES.md` explains the flag/CfT-version
100
- rationale) or install it from the Chrome Web Store. Point `<INSPECTOR_DIR>` at its
101
- unpacked directory:
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`