opentakeoff-mcp 0.9.71 → 0.9.75

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.
Files changed (3) hide show
  1. package/README.md +31 -4
  2. package/dist/server-core.js +1048 -134
  3. package/package.json +4 -3
package/README.md CHANGED
@@ -38,6 +38,18 @@ native canvas, so every JSON tool and the text/metadata resources work
38
38
  everywhere; the sheet-image resource and the `view_sheet` tool say exactly
39
39
  what's missing where rendering isn't available.
40
40
 
41
+ ## One-Click is temporarily gated
42
+
43
+ `one_click` and `detect_rooms` are **not registered** on a default build while the flood
44
+ engine is re-validated against a wider plan corpus: `tools/list` never names them, the
45
+ initialize `instructions` say so and point at `measure_polygon`, and no other tool's
46
+ description sends an agent to a verb that is not there. A default build registers
47
+ **52 tools**. Everything else — sweeps, counts, `derive_base`, `derive_transitions`, the
48
+ exports — is unchanged. Set `OPENTAKEOFF_ONE_CLICK=1` in the server's environment to
49
+ register both verbs (54 tools); the parity, conformance and e2e tests run that way, and
50
+ `test/gate.test.ts` pins both surfaces. The rows and examples below that use `one_click`
51
+ describe the lifted build. Design note: [`docs/design/ONE_CLICK_GATE.md`](../docs/design/ONE_CLICK_GATE.md).
52
+
41
53
 
42
54
  The takeoff engine—One-Click Area, the scale model, conditions, totals—on
43
55
  **stdio for your MCP client**. An agent can open a plan, read the title block,
@@ -109,8 +121,8 @@ includes document text, shape vertices, or result payload content.
109
121
 
110
122
  ### Staged tool exposure (opt-in)
111
123
 
112
- By default every client gets all 47 tool schemas on `tools/list`—the flat
113
- contract every published client already expects. Forty-three descriptions is real
124
+ By default every client gets all 52 tool schemas on `tools/list`—the flat
125
+ contract every published client already expects. Fifty-two descriptions is real
114
126
  token weight for an agent session that may never touch half of them, so the
115
127
  server can instead stage the surface along the workflow it already teaches:
116
128
 
@@ -136,8 +148,8 @@ reads the tool list once. ([#230](https://github.com/Kentucky-ai/opentakeoff/iss
136
148
  | `load_plan` | Open a plan PDF from disk. Default replaces the whole session; **`merge: true` ADDS the document to the working set** (#152)—plans + schedule + addenda as one takeoff, sheet graph spanning the whole set, marked set covering every worked sheet. Returns per-sheet dims, title-block `sheet_number`, and the detected drawn scale where present. |
137
149
  | `sheet_info` | One sheet's dims, vector segment count, scale status, detected suggestion, committed shape count. |
138
150
  | `set_scale` | Set a sheet's scale—exactly one of `label`, `upp`, `calibrate {p1, p2, feet}`, `use_detected`. **Lands unconfirmed** (`confirmed: false`) until a human confirms in the canvas—see Scale rules. |
139
- | `one_click` | One-Click Area at (x, y): the sealed flood engine bounded by the plan linework, traced, vertices snapped—the SAME feet-true arguments the canvas passes at a click (gap sealing up to a door width, door-swing wedge inclusion, the half-foot minimum-passage rule), so an MCP trace and a canvas click at one seed measure the same square footage (pinned against the bench corpus goldens in `test/parity.test.ts`). Every trace carries the engine's account of itself: `confidence` 0–1 with `confidence_factors` naming each deduction (`gap_sealed_px`, `door_wedges`, `min_pass_delta`, …)—a review prioritizer, never a verification; a low score is a `view_sheet {overlay: true}` audit prompt, not a fact. On a SCANNED sheet (no usable linework) the flood falls back automatically to the rendered pixels—same engine as the canvas—with `raster_traced` disclosed on the reply and on the shape's origin (#154). Pass `condition` to commit (the full account stamps `origin` centrally at the commit); `role: "deduct"` subtracts. |
140
- | `detect_rooms` | Batch One-Click: reads every room-number label off the sheet's text layer and floods each—one call instead of `read_sheet_text` + reasoning + N `one_click` calls, through the SAME sealed engine per room (confidence + the engine account ride each room and its committed origin). Only cleanly-traced rooms come back; everything skipped is counted and reasoned in `withheld` (degenerate / duplicate / implausible / unresolved), never dropped silently. To commit: `assign_from_schedule: true` routes each room through its OWN room-finish schedule row and commits under the FLOOR finish that row states (rooms the schedule can't answer for return in `unresolved[]` with reasons and re-seedable coordinates); or pass `condition` to commit every room under one stated tag. |
151
+ | `one_click` | **Temporarily gated — not registered unless `OPENTAKEOFF_ONE_CLICK=1`.** One-Click Area at (x, y): the sealed flood engine bounded by the plan linework, traced, vertices snapped—the SAME feet-true arguments the canvas passes at a click (gap sealing up to a door width, door-swing wedge inclusion, the half-foot minimum-passage rule), so an MCP trace and a canvas click at one seed measure the same square footage (pinned against the bench corpus goldens in `test/parity.test.ts`). Every trace carries the engine's account of itself: `confidence` 0–1 with `confidence_factors` naming each deduction (`gap_sealed_px`, `door_wedges`, `min_pass_delta`, …)—a review prioritizer, never a verification; a low score is a `view_sheet {overlay: true}` audit prompt, not a fact. On a SCANNED sheet (no usable linework) the flood falls back automatically to the rendered pixels—same engine as the canvas—with `raster_traced` disclosed on the reply and on the shape's origin (#154). Pass `condition` to commit (the full account stamps `origin` centrally at the commit); `role: "deduct"` subtracts. |
152
+ | `detect_rooms` | **Temporarily gated — not registered unless `OPENTAKEOFF_ONE_CLICK=1`.** Batch One-Click: reads every room-number label off the sheet's text layer and floods each—one call instead of `read_sheet_text` + reasoning + N `one_click` calls, through the SAME sealed engine per room (confidence + the engine account ride each room and its committed origin). Only cleanly-traced rooms come back; everything skipped is counted and reasoned in `withheld` (degenerate / duplicate / implausible / unresolved), never dropped silently. To commit: `assign_from_schedule: true` routes each room through its OWN room-finish schedule row and commits under the FLOOR finish that row states (rooms the schedule can't answer for return in `unresolved[]` with reasons and re-seedable coordinates); or pass `condition` to commit every room under one stated tag. |
141
153
  | `measure_polygon` | Area + perimeter of a polygon you supply (min 3 verts). Requires scale. |
142
154
  | `cut_out` | **A real hole in a committed floor shape** (#206), reconciled the way the canvas cuts one (#137)—the same `lib/cutout.js` boolean subtract, one module, so a headless session and the app can never disagree about what a hole holds. The parent keeps its outer ring + `verts_norm_holes`, its `computed` nets for real (N cuts compose, overlap never double-deducts, a hole ADDS perimeter), and the deduct carries `cuts_shape_id` so report/legend read the reconciled number. Refuses a ring not FULLY inside the parent (the canvas's edge-clip is a canvas affordance; over the wire it's refusal-over-guessing) and a cut that would erase or split the parent. One undo step restores parent and hole together; `delete_shape` on the deduct reverts the cut too (multi-cut parents rebuild from the chain's pristine snapshot minus survivors—the canvas's own delete semantics, ported as the spec). |
143
155
  | `measure_line` | Length of an open polyline (min 2 points). Requires scale. |
@@ -150,6 +162,13 @@ reads the tool list once. ([#230](https://github.com/Kentucky-ai/opentakeoff/iss
150
162
  | `takeoff_summary` | Per-condition totals + grand totals, computed by the Report's rules. |
151
163
  | `export_takeoff` | The full `opentakeoff.takeoff_canvas.v1` payload—exactly what the app autosaves. Inline, and to disk with `path` (see **Writing to disk** below). |
152
164
  | `delete_shape` | Remove a committed shape by id. |
165
+ | `propose_takeoff` | **Open a named batch** (#365). Every shape you commit from here on attaches to it (`origin.proposal_id`, stamped centrally at the commit—hand traces, sweeps, derives, `cut_out` alike), so the estimator sees ONE Accept pill for the batch instead of one per shape. `label` is what they read on the pill, `rationale` is what decided the batch; both required. Commits nothing itself. |
166
+ | `revise_proposal` | Replace **every still-pending shape** in a batch with a new set, as one journal step. All-or-nothing: validated (sheet, scale, vertex minimum, a height for `surface_area`) before the first pending shape is removed, the error naming the entry. Accepted shapes are ink and stay. One `undo_last` puts the previous batch back. |
167
+ | `withdraw_proposal` | Remove a batch's pending shapes in one step; the record stays marked withdrawn, accepted shapes stay (the reply counts them). `undo_last` restores the whole batch. |
168
+ | `propose_condition_edit` | **Propose** a condition change instead of making it: a diff—new `finish_tag` (rename), `waste_pct`, `multiplier`, `height_ft`, `roll_setup`—held pending until the estimator accepts from the panel. Nothing changes until then: `takeoff_summary` and `export_report` compute from the current values and carry the diff beside them. Only differing fields are recorded; a no-op or a rename onto a taken tag is refused; one pending diff per condition (proposing again replaces it). `rationale` required. |
169
+ | `withdraw_condition_edit` | Drop a pending condition-edit diff without touching the condition. |
170
+ | `scope_duplicates` | **Two conditions claiming the same floor, as a list** (#366): every pair of committed floor shapes on one sheet whose EXACT polygon intersection exceeds `min_fraction` of the smaller (default 0.05), with the shared SF, each side's condition, label and review state, and a `look` region for `view_sheet {overlay: true}`. Different conditions = a collision (the floor is counted twice downstream); the same condition = a double trace, returned in `duplicates`. `shared_floor_sf` is Σ areas − union over the compared set, counted once per cell — the number `takeoff_summary` always carries. Deducts and runs are not claims; unscaled sheets and degenerate rings are `unmeasured`, never zero. Read-only. |
171
+ | `scope_merge` | **Resolve one collision**: given the pair and the winner, the loser gives up the shared floor — trimmed to its remainder (exact boolean difference, quantities re-measured) or deleted when the overlap is near-total (≥ 98% of the loser). One journal step; `undo_last` restores the loser verbatim. With `winner` omitted the reviewed shape wins; refuses when neither is reviewed (it does not guess), when both are (the estimator's call in the canvas), always when the loser is ink, when the trim would split the loser, and when the loser carries reconciled cutouts. |
153
172
  | `edit_shape` | **Revise** a committed shape instead of redoing it: new `verts`, a different `condition`, a different `role`, a `label` (the room it belongs to—what per-room reporting groups by; `""` clears it), or any combination—quantities recomputed from the result. Refuses shapes a human affirmed. |
154
173
  | `edit_materials` | Add/remove/patch supporting-materials rows on a condition—the coverage-rate lines (adhesive at N sf/gal, grout at N lf/bag, …) that turn a measured quantity into an order quantity, matching the canvas's Supporting Materials panel. `basis` is `area` \| `linear` \| `count` \| **`seam_lf`**—the last is the *figured* roll-layout seam length a weld rod or seam tape is bought by (set `roll_setup` on the condition first; without one it reads 0, because nothing has decided how that floor gets cut). `condition` mints on first touch, like `one_click`/`measure_polygon`. No review gate (materials rows are quantity config, not traced geometry)—edits directly, reversible with `undo_last`. |
155
174
  | `edit_condition` | Set a condition's **waste %**, **×N multiplier**, **height_ft** (the H knob `measure_surface` quantifies against), and **roll_setup** (the roll-goods opt-in: seams figured, cuts packed, the reply echoes the order—cuts, `order_lf`, rolls, `order_qty`—and `export_report`'s `roll_goods` block carries the same rows; `null` opts out)—the knobs that turn measured quantities into order quantities. Resolves an **existing** finish tag or errors—a typo must not mint an empty condition. No review gate; one `undo_last` step restores the knobs verbatim. |
@@ -398,3 +417,11 @@ npm run build
398
417
  node scripts/build-smithery-mcpb.mjs
399
418
  smithery mcp publish dist-smithery/opentakeoff-mcp.mcpb -n Kentucky-ai/opentakeoff
400
419
  ```
420
+
421
+ ## Calibration and review correctness (0.9.72)
422
+
423
+ `set_scale` recomputes existing dimensional quantities from geometry, including holes and cutout restore snapshots. Changing an existing calibration records one `undo_last` step that restores the scale, its confirmation/source, and the prior quantities together. Initial calibration of an unmeasured sheet adds no undo step. Counts retain their stored values. A sheet containing human-reviewed dimensional measurements refuses recalibration over MCP, consistent with the existing reviewed-shape edit rules; recalibrate it in the canvas and import the updated takeoff into a fresh session.
424
+
425
+ `import_takeoff` refuses new dimensional shapes when their source calibration differs from the session's calibration, or is missing while the session has one. The error names the sheet and scales; no session state changes. Align calibrations and re-export, or load a fresh session to adopt the export's calibration. Counts and duplicate IDs are exempt. An existing calibration is preserved even in an untraced session.
426
+
427
+ New agent measurements, including `measure_polygon` and `measure_line`, explicitly carry `origin.reviewed: false`. Legacy agent records without the flag are normalized on import and browser reload. Explicit prior human approval is preserved. No new review gate is introduced.