@foldspace_npm/harness 0.1.15 → 0.1.16

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/CLAUDE.md CHANGED
@@ -44,16 +44,23 @@ current CLI contract — risk, prerequisites, effects, next step.
44
44
  | **L2 · look up entities** | a search from the user's own words, showing rows |
45
45
 
46
46
  1. **Get the agent live first (L0) - with no actions.** Straight after
47
- orienting: `npm run build`, `npm run inject`, the human signs in to their
48
- app, then `npx foldspace attach --daemon`. An empty registry is valid. L0
49
- is `registration_ok` with the agent visible on their page - tell them to
50
- look at it and say hello to it. **Do not explore the app first**: no
47
+ orienting: `npm run build`, `npm run inject`, and one ask - *"A Chrome
48
+ window opened at <Product>'s login. Please log in there - I'll notice when
49
+ you're in."* Then `npx foldspace observe wait-login`: it returns the moment
50
+ they are in, so nobody has to type "I've logged in". Then
51
+ `npx foldspace attach --daemon`. An empty registry is valid. L0 is
52
+ `registration_ok` with the agent visible on their page: take
53
+ `npx foldspace observe screenshot`, send them the image, and tell them to
54
+ look at it and say hello to it. **From here on the agent stays on their
55
+ page** - you never detach to look at the app.
56
+ **Do not explore the app first**: no
51
57
  reading its bundle, no watching its traffic, no browsing its screens.
52
58
  Nothing about L0 needs any of it, and minutes of silent investigation
53
59
  before the human has seen anything is the wrong first impression.
54
60
  2. **Then offer experiences - from what you already have.** With the agent on
55
61
  their screen, offer three or four read-only experiences as a choice,
56
- recommended first. Sources: the conversation starters seeded at sign-up,
62
+ recommended first. Sources: the product's own menu (`npx foldspace observe
63
+ menu` takes a second and moves nothing), the conversation starters seeded at sign-up,
57
64
  `discover_actions`, and `docs/app-profile.md`. `discover_actions` gives
58
65
  candidates, not an inventory. Do not investigate the app to build this
59
66
  list. Order them cheapest first: the user's own data with no parameter
@@ -92,15 +99,35 @@ and asking are not the only options — **observing is, and it comes first**:
92
99
 
93
100
  1. **Already known** — `docs/app-profile.md`. A verified endpoint needs no
94
101
  browsing.
95
- 2. **You drive - once they have chosen an experience.** The agent is already
96
- attached from L0, and `attach` owns the debug port: `npx foldspace attach
97
- --stop` first. Then *you* go to the one screen that experience needs: read
98
- the app's bundle for API paths and watch the requests it makes
99
- (chrome-devtools MCP against the inject Chrome, or a page-context
100
- `fetch`). Attach again when you have the call. Read the auth method off a request
101
- the page already sent — bearer from `localStorage`, cookie, custom header.
102
- Delegate the watching to a read-only subagent so the traffic does not flood
103
- your context.
102
+ 2. **You look - once they have chosen an experience - with `foldspace
103
+ observe`.** It reads the test window they signed in to, it is read-only by
104
+ construction, and it works **while the agent stays attached**: do not
105
+ `attach --stop` to look. Write no browser-driving script of your own, and do
106
+ not reach for a separate DevTools server - one launched on its own opens a
107
+ different, signed-out Chrome and can never see the window they logged in to.
108
+
109
+ ```bash
110
+ npx foldspace observe menu # the product's own screens, by label and path
111
+ npx foldspace observe screen --click "<a label from menu>" --match "<three to five words for the data>"
112
+ npx foldspace observe read "<the GET path screen returned>" # GET only: status, field names and types, row count
113
+ npx foldspace observe auth # only if a read came back 401 or 403
114
+ npx foldspace observe styles # their font and colours, for the card
115
+ ```
116
+
117
+ `screen` reaches a screen the way a person does and returns at most eight
118
+ requests, ranked by your words - field names, value types and row counts,
119
+ **never values**. `read` confirms the one you picked. `auth` reports *where*
120
+ each header value comes from, never the value: do not go hunting through
121
+ storage, cookies or bundles yourself. One experience needs one screen; two
122
+ `screen` calls is normal, five means the experience is wrong for this
123
+ product - offer the next one.
124
+
125
+ **`observe` refuses what is not provably looking**, and a refusal is an
126
+ answer (**Safety**): it follows links, tabs and menu openers only - a plain
127
+ button can do anything, so use `--goto <path>` from `menu` instead; it will
128
+ not open a path that does something (`/logout`, `/…/delete`); and `read`
129
+ only goes to the app's own origin, a host configured for this project, or
130
+ an origin `screen` saw the page call.
104
131
  3. **Ask the human to perform the workflow** — only for what you cannot reach:
105
132
  an MFA step, a paywall, a screen that needs a record the account does not
106
133
  have, or anything that would write.
@@ -198,9 +225,8 @@ npx foldspace attach --daemon
198
225
  ```
199
226
 
200
227
  `inject` launches an isolated Chrome profile and records its debug port; it
201
- loads nothing. In a first session `attach` comes straight after sign-in (L0);
202
- to observe afterwards, `attach --stop`, use chrome-devtools MCP against the
203
- same Chrome, then attach again. `attach` prepares the page and loads the local
228
+ loads nothing. In a first session `attach` comes straight after sign-in (L0),
229
+ and `foldspace observe` reads the same window while it runs. `attach` prepares the page and loads the local
204
230
  `dist/index.js` over CDP. Coding agents use `--daemon` so the tool returns after
205
231
  `[lifecycle] inspect_registration:…`. An empty local registry is valid; `npm run
206
232
  build` is still required so `dist/index.js` exists.
@@ -212,8 +238,9 @@ SDK without the configured agent.
212
238
 
213
239
  `inspect_registration:registration_ok` is the signal. On `registration_mismatch`
214
240
  read `npx foldspace help attach --json` and map `missingActionNames`,
215
- `unexpectedActionNames`, `diagnosticError`. While attach runs it owns the debug
216
- port `attach --stop` before using chrome-devtools MCP again.
241
+ `unexpectedActionNames`, `diagnosticError`. A running attach keeps the actions
242
+ it loaded: after a rebuild, `attach --stop` and attach again to load the new
243
+ ones. That is the only reason to stop it.
217
244
 
218
245
  Prove a named action through the visible agent: after the human talks to the
219
246
  copilot, read the daemon log for `[actions]` SDK callback and local
package/README.md CHANGED
@@ -190,8 +190,8 @@ Use `foldspace help attach` for mode requirements, effects, and safety options.
190
190
  Coding agents should run `foldspace attach --daemon` so the invoking tool
191
191
  returns after `[lifecycle] inspect_registration:…`. Foreground attach remains
192
192
  the default for humans watching the terminal. `attach --status` and
193
- `attach --stop` inspect and tear down a daemon. Observe customer-app network
194
- traffic after `inject` and before attach; attach owns the debug port.
193
+ `attach --stop` inspect and tear down a daemon. Look at the customer's app with
194
+ `foldspace observe`: it reads the same window, read-only, while attach runs.
195
195
 
196
196
  ### Verify actions through the agent
197
197
 
package/bin/attach.mjs CHANGED
@@ -43,6 +43,7 @@ import {
43
43
  shouldFulfillActionRequest,
44
44
  } from "../src/attach-preflight.mjs";
45
45
  import { serializeDiagnostic } from "../src/diagnostics.mjs";
46
+ import { recordEvent } from "../src/session-events.mjs";
46
47
  import {
47
48
  ERROR_CODES,
48
49
  createLifecycleResult,
@@ -699,6 +700,8 @@ async function prepare(ws, sessionId, url) {
699
700
 
700
701
  {
701
702
  const verification = await verifyPreparedPage(ws, sessionId);
703
+ // For scoring a session: the moment the customer could first see their agent.
704
+ if (verification.ok) recordEvent(root, "agent_visible", { mode: attachMode });
702
705
  logLifecycle(
703
706
  createLifecycleResult({
704
707
  operation: "inspect_registration",
@@ -952,7 +955,7 @@ console.log(`Test: ${noTestMode ? "OFF — conversations WILL appear in the das
952
955
  console.log(`Hosts: ${hostPatterns.join(", ")}`);
953
956
  console.log(`Serving: ${path.relative(root, bundlePath)}`);
954
957
  console.log(
955
- `CDP: this process owns the debug port. Detach before using chrome-devtools MCP against the same Chrome.\n`,
958
+ `CDP: attached. \`foldspace observe\` reads this same window while attach runs; stop attach only to load rebuilt actions.\n`,
956
959
  );
957
960
 
958
961
  function printSessionSummary() {
package/bin/inject.mjs CHANGED
@@ -11,6 +11,7 @@
11
11
  * npm run inject -- --url https://app.other.com --product ABC123 --agent other-agent
12
12
  * npm run inject -- --print # resolve target only, don't launch
13
13
  */
14
+ import { recordEvent } from "../src/session-events.mjs";
14
15
  import fs from "fs";
15
16
  import path from "path";
16
17
  import os from "os";
@@ -279,6 +280,8 @@ fs.writeFileSync(
279
280
  ),
280
281
  );
281
282
 
283
+ recordEvent(root, "chrome_opened", { url: startUrl });
284
+
282
285
  // --- theme -------------------------------------------------------------
283
286
  //
284
287
  // Chrome 151 ignores --load-extension, so load the optional cosmetic theme