opendoor-plugin 0.2.0 → 0.4.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 CHANGED
@@ -19,15 +19,33 @@ Full feature spec: [`docs/feature-doorstop-plugin.md`](docs/feature-doorstop-plu
19
19
 
20
20
  ## Status
21
21
 
22
- The plugin is fully wired and green, in two halves:
22
+ Requires **pi-web 1.202609.1 or newer** (browser plugin API v4 / server
23
+ plugin API v3). Tested through **pi-web 1.202610.8**, which remains
24
+ **additive** for this plugin — its browser v4/server v3 entries still load,
25
+ with once-per-plugin deprecation diagnostics expected (see **Rollout** below
26
+ for the upgrade order and the 1.202610.x sessiond-restart note). The Phase 3 pairing
27
+ on top of that migration (public session metadata + session-list row
28
+ labels, plan §2.1) stays on the same v4/v3 contracts. The package is one npm
29
+ package (`opendoor-plugin`) that ships a PI WEB plugin AND a Pi extension:
30
+ the plugin's browser/server halves below, plus the review-dispatch extension
31
+ that starts labeled review conversations (`/opendoor-review`, see **Review
32
+ dispatch (Pi extension)** below). The plugin loads on older hosts unchanged;
33
+ only the extension's dispatch bridge, the public metadata, and the row
34
+ labels need a 1.202610.x session daemon (see **Rollout**). The plugin is
35
+ fully wired and green:
23
36
 
24
- - **Browser entry** (`src/pi-web-plugin.ts`, apiVersion 2, name `Opendoor`)
37
+ - **Browser entry** (`src/browser/pi-web-plugin.ts`, apiVersion 4, name `Opendoor`)
25
38
  delegates to `createOpendoorBrowserContributions` in
26
- `src/doorstop-contributions.ts`, which contributes:
39
+ `src/browser/doorstop-contributions.ts`, which contributes:
27
40
 
28
- - **panel** `workspace.doorstop` (title **Requirements**, order 60) — the Lit
41
+ - **panel** `workspace.doorstop` (title **Requirements**, order 5 — deliberately
42
+ below the bundled Files panel's order 10, which answers every chat file link
43
+ unconditionally in the host's first-accepting-panel dispatch; this is what
44
+ makes the `fileOpenQuery` claim — chat links to doorstop item files open the
45
+ item's detail view in this panel instead of Files — reachable, at the cost
46
+ of the Requirements tab preceding Files) — the Lit
29
47
  body element `<pi-web-opendoor-panel-body>`, driven by the per-workspace
30
- controller registry (`src/doorstop-panel.ts`): five vertical sections —
48
+ controller registry (`src/browser/doorstop-panel.ts`): five vertical sections —
31
49
  `project-actions` (title, Items/Findings toggle, Refresh / Run validation
32
50
  / Publish HTML), `item-list` (filters row + item rows with state chips),
33
51
  `item-details` (links in/out, references, extended attributes,
@@ -40,9 +58,14 @@ The plugin is fully wired and green, in two halves:
40
58
  - **actions** `view.doorstop` (mod+7) and `workspace.refresh-doorstop`
41
59
  (mod+shift+d);
42
60
  - **label** `doorstop-status` — the informational requirement-health counts
43
- (async-cache idiom, feature spec §7.4).
61
+ (async-cache idiom, feature spec §7.4);
62
+ - **session-row label** `doorstop.review` — a compact indicator on session
63
+ rows carrying public `opendoor` metadata; clicking it reopens the
64
+ Requirements tab on the row's machine/workspace (works for unselected and
65
+ archived rows, no live Pi connection needed). See **Session metadata and
66
+ session-list row labels** below.
44
67
 
45
- - **Server entry** (`src/server-plugin.ts`, default export `PiWebServerPlugin`)
68
+ - **Server entry** (`src/server-plugin.ts`, apiVersion 3, default export `PiWebServerPlugin`)
46
69
  contributes a workspace provider that claims only projects whose root
47
70
  contains a `.doorstop.yml` (cheap `fs.access` probe — everything else stays
48
71
  with the bundled Git provider) and serves a six-operation backend:
@@ -57,24 +80,42 @@ The plugin is fully wired and green, in two halves:
57
80
  server-side (the browser never sends shell strings), and runs through the
58
81
  host's `execFile()` helper with `cwd` = the workspace path, timeouts
59
82
  clamped to 8.5 s (the review+git pipeline shares one deadline budget under
60
- the host's 10 s callback bound), and per-workspace run serialization.
83
+ the host's 10 s callback bound), and per-workspace run serialization. The
84
+ server entry permanently declares no `requires` and no `start()`: the
85
+ capability-driven `doorstop.ask-agent` dispatch it once carried was
86
+ unreachable by construction on a workspace-provider-contributing entry
87
+ (PI WEB rejects the provider-dependency capability cycle) and has been
88
+ retired. The review dispatch now runs in the Pi extension below.
89
+ - **Pi extension** (`src/pi-extension/opendoor-review.ts`, bundled to
90
+ `dist/pi-extension/index.js` and declared by `pi.extensions`) registers
91
+ `/opendoor-review <UID> [instruction…]`. It publishes the shipped public
92
+ `opendoor` session metadata (`{ schema: 1, op: "review", uids }`) and asks
93
+ PI WEB's own per-session dispatch bridge to start an independent
94
+ conversation in the same registered project — the same spawn semantics and
95
+ delegation restrictions as `spawn_session`, with model/thinking inherited
96
+ from the initiating conversation. Every outcome (started / refused / no
97
+ bridge) is reported as a message in the initiating conversation. This is
98
+ the pathway the panel's **Start review session** entry drives (see **Review
99
+ dispatch (Pi extension)** below).
61
100
 
62
- Dispatch (per action, in `src/doorstop-panel-elements.ts`): when the workspace
101
+ Dispatch (per action, in `src/browser/doorstop-panel-element.ts`): when the workspace
63
102
  is opendoor-owned with an active backend, the action sends a structured
64
- request via `context.backend.request("doorstop.run", …)` (the review-commit
103
+ request via `context.peer.request("doorstop.run", …)` (the review-commit
65
104
  flag rides along when the setting is enabled; the "Changes since review"
66
- section fetches via `context.backend.request("doorstop.item-baseline", …)`)
105
+ section fetches via `context.peer.request("doorstop.item-baseline", …)`)
67
106
  and the captured output appears in the panel's status bar (auto-expanded);
68
107
  the panel auto-rescans on completion. When the backend is absent (unpaired
69
108
  install, or a workspace the provider does not own), the action falls back to
70
109
  `terminal.runCommand()` with the same shell command, so output stays visible
71
110
  and auditable in the terminal.
72
111
 
73
- `doorstop.run` and `doorstop.item-baseline`) shared by both halves, plus the
74
- four git-action contracts (`doorstop.git-status`, `doorstop.git-stage`,
75
- `doorstop.git-unstage`, `doorstop.git-commit`), live in
76
- `src/doorstop-backend-contract.ts`. Later modules import these and must not
77
- redefine them.
112
+ The shared types + function-signature contracts live in
113
+ `src/doorstop-contract.ts`; the two backend operation contracts
114
+ (`doorstop.run` and `doorstop.item-baseline`) shared by both halves, plus
115
+ the four git-action contracts (`doorstop.git-status`, `doorstop.git-stage`,
116
+ `doorstop.git-unstage`, `doorstop.git-commit`), live in
117
+ `src/doorstop-backend-contract.ts`. Later modules import these and must not
118
+ redefine them.
78
119
 
79
120
  ## Workspace settings (`.pi-web/opendoor.json`)
80
121
 
@@ -92,6 +133,7 @@ bundled workspace-tasks plugin. The *server* entry's host-scoped knobs
92
133
  "version": 1,
93
134
  "publish": { "target": "./public" },
94
135
  "discovery": { "excludedDirectories": ["published", "vendor"] },
136
+ "showAdditionalAttribute": ["text", "component"],
95
137
  "commitAfterReview": false
96
138
  }
97
139
  ```
@@ -104,6 +146,18 @@ bundled workspace-tasks plugin. The *server* entry's host-scoped knobs
104
146
  - `discovery.excludedDirectories` — additional directory names the
105
147
  `.doorstop.yml` walk never enters (merged with the built-in
106
148
  `.git`/`node_modules` skips, max 16 names).
149
+ - `showAdditionalAttribute` — array of attribute NAMES rendered in every
150
+ item-list row as `key: value` (values jsonish-quoted, joined with ` · `, in
151
+ the configured order). Entries may be any extended attribute key; an
152
+ attribute an item does not have is skipped for that row, and no unconfigured
153
+ attribute ever appears. The modeled `text` is special-cased: instead of a
154
+ `text: "…"` pair in the attribute column, the item body renders raw and
155
+ unquoted on its own indented second line below the row, clamped to two lines
156
+ with an ellipsis (the full body lives in the detail pane); it is skipped when
157
+ the item body is empty. Default `[]` leaves today's rows unchanged. Invalid
158
+ entries are dropped with a warning each, duplicates are deduplicated, the
159
+ list is capped at 16 names, and unknown keys are accepted (they simply match
160
+ nothing).
107
161
  - `commitAfterReview` — opt-in boolean (default `false`): when enabled on a
108
162
  paired workspace, the **Review** action's `doorstop review <uid>` is
109
163
  followed by a pathspec-limited git commit of the item file with the
@@ -150,12 +204,13 @@ bottom:
150
204
  all** button, and the **Git commit** control (message input + button); see
151
205
  **Git actions** below.
152
206
  2. **`item-list`** — a filters row (document chips, state filter, search)
153
- above the item rows.
207
+ above the item rows; each row shows its level, UID, excerpt, any attributes
208
+ configured through `showAdditionalAttribute`, and its state chips.
154
209
  3. **`item-details`** — the selected item's full detail pane (unchanged).
155
210
  4. **`item-action-palette`** — the item actions (**Review**, **Clear suspect
156
- links**, **Edit**, **Unlink**/**Link** + target UID inputs, **Ask agent**
157
- menu), moved out of the detail pane so the row spans the panel at the same
158
- height as the center-panel chat prompt footer. A muted "Select an item…"
211
+ links**, **Link** + target UID input, **Ask agent** menu), moved out of
212
+ the detail pane so the row spans the panel at the same height as the
213
+ center-panel chat prompt footer. A muted "Select an item…"
159
214
  placeholder keeps the palette at constant height while nothing is
160
215
  selected; the palette is hidden in the Findings view.
161
216
  5. **`status-bar`** — the run status row (badge, duration, **Dismiss**),
@@ -258,7 +313,18 @@ bottom:
258
313
  expanded status bar body.
259
314
  - **Ask the agent** menu: inserts ready-made prompts (explain, fix suspect
260
315
  links, draft child requirement, review readiness) into the session prompt
261
- editor using the item's paths and state (feature spec §7.3).
316
+ editor using the item's paths and state (feature spec §7.3). **Start
317
+ review session** composes `/opendoor-review <UID>` plus the item context
318
+ into that same editor and needs no paired backend: sending it lets the
319
+ opendoor Pi extension start an independent review conversation whose list
320
+ row carries a **`firstUid +n` label** that reopens the Requirements tab on
321
+ the row's workspace — including for unselected and archived rows and with
322
+ no live Pi connection — landing on the item detail pane. After the insert
323
+ the panel's status bar shows a quiet `ok` **review dispatch** run row.
324
+ Without the extension installed the inserted text is still a
325
+ self-sufficient review instruction, so the review happens in the current
326
+ conversation; a refused dispatch is reported in the chat by the extension.
327
+ See **Session metadata and session-list row labels** in the feature spec.
262
328
  - Fingerprints and the requirement state are recomputed in the browser from
263
329
  the YAML files; everything mutating goes through the visible `doorstop`
264
330
  CLI — paired, headlessly via the server entry (output captured in the
@@ -274,12 +340,27 @@ npm test # vitest (unit tests under src/**/*.test.ts)
274
340
  npm run test:coverage # v8 coverage report
275
341
  npm run typecheck # tsc --noEmit (strict)
276
342
  npm run build # esbuild: dist/browser/pi-web-plugin.js + dist/server-plugin.js
277
- # (+ verbatim package.json manifest copy into dist/)
343
+ # + dist/pi-extension/index.js, then the dist-root
344
+ # package.json plugin manifest (see the build script header)
278
345
  npm run dev # watch mode build
279
346
  ```
280
347
 
281
348
  ## Installing the plugin locally (id `opendoor`)
282
349
 
350
+ The package carries two independently enabled halves: the **PI WEB plugin**
351
+ (browser + server entries) and the **Pi extension** (`/opendoor-review`).
352
+ The repository-root `package.json` is the npm-package-root manifest, so both
353
+ halves come from ONE install through **Settings → Pi packages** (npm name,
354
+ git/URL, or a local package source). The `ln -s dist` route below remains
355
+ available for plugin-only development.
356
+
357
+ ### PI WEB plugin (browser + server entries)
358
+
359
+ Install the package once — **Settings → Pi packages** with source
360
+ `opendoor-plugin` (or this repository's path / git URL) — then enable
361
+ **Opendoor** under **Settings → PI WEB plugins**. For a plugin-only local
362
+ build the symlink route still works:
363
+
283
364
  ```sh
284
365
  npm run build
285
366
  ln -s "$(pwd)/dist" ~/.pi-web/plugins/opendoor
@@ -298,3 +379,54 @@ The manifest should list an `opendoor` plugin entry **with a
298
379
  `backendRevision`** (signing the paired server module). If `backendRevision`
299
380
  is missing, the server module failed to load — check the sessiond log; the
300
381
  plugin still works fully via the terminal fallback.
382
+
383
+ ### Review dispatch (Pi extension)
384
+
385
+ Installing the package is what loads the extension; enabling the PI WEB
386
+ plugin is a separate decision. After installing or updating the package on a
387
+ machine, run `/reload` in each idle conversation so the `/opendoor-review`
388
+ command is registered there (an ordinary Pi-resource change — no provider
389
+ restart involved). The extension needs PI WEB **1.202610.x** for the
390
+ session-dispatch bridge; on an older host it reports "requires PI WEB's
391
+ session dispatch bridge" in the conversation and starts nothing. The panel's
392
+ **Start review session** entry needs no paired backend — it only composes the
393
+ command into the prompt editor.
394
+
395
+ ## Rollout (pi-web 1.202609.1)
396
+
397
+ pi-web 1.202609.1 is a **hard break** for plugins — there is no
398
+ compatibility shim in either direction: a v4/v3 host rejects v2/v1 plugin
399
+ modules, and a v2/v1 host rejects the migrated v4/v3 modules. Upgrade the
400
+ opendoor package and pi-web **together**, then restart
401
+ `pi-web-sessiond.service` and reload the PI WEB page. During the transition
402
+ the opendoor panel is **entirely absent** (both plugin entries rejected), not
403
+ degraded. Federated gateways/targets must be upgraded in lockstep.
404
+
405
+ ### pi-web 1.202610.3 (and later 1.202610.x)
406
+
407
+ Unlike 1.202609.1, release **1.202610.3** is **additive** for opendoor: the
408
+ untouched v4/v3 plugin keeps loading on a v1.202610.3 host, with a
409
+ once-per-plugin deprecation diagnostic (no removal date). No source changes
410
+ were needed — the only mindful adaptation was a no-op `navigate` stub in the
411
+ test fixtures (`src/test-fixtures.ts`, `src/browser/pi-web-plugin.test.ts`),
412
+ because 1.202610.x made `navigate` a required member of
413
+ `PluginRuntimeContext` / `WorkspacePanelContext`.
414
+
415
+ Host upgrade order for 1.202610.x: refresh the pi-web checkout, then
416
+ **manually restart `pi-web-sessiond.service`** — a UI/API autoreload alone
417
+ is **not sufficient** (the release touched the session-serving paths
418
+ heavily). The restart interrupts active sessions and terminals; reload the
419
+ PI WEB page afterwards and confirm the manifest shows the opendoor entry
420
+ with a `backendRevision`.
421
+
422
+ #### Review dispatch and session-row labels (1.202610.x floor)
423
+
424
+ The **Start review session** dispatch and the session-list row labels require
425
+ a **1.202610.x** session daemon: that release introduced the public session
426
+ metadata, the session-list label contribution, and the per-session dispatch
427
+ bridge the extension emits on. The opendoor **server** entry declares no
428
+ capabilities and loads across the whole supported range. `opendoor-plugin`
429
+ **0.4.0** is the first release carrying the extension. Restart
430
+ `pi-web-sessiond.service` once to load the server-side change, then run
431
+ `/reload` in each idle conversation to load the extension's
432
+ `/opendoor-review` command; the browser side only needs a page reload.