@design-twin/dtwin 0.1.0-alpha.0 → 0.1.1

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
@@ -7,13 +7,31 @@ The plugin's hidden UI iframe is a WebSocket **client**; these processes are the
7
7
  (`127.0.0.1:8787`). Nothing touches the internet. See `../ARCHITECTURE.md` for the full design.
8
8
 
9
9
  ## Install (once)
10
- The `designtwin` package is not on npm; install it from a clone:
10
+ It needs [Bun](https://bun.sh/install) ≥ 1.4.2 (`engines.bun`) on your PATH; Node is not supported. Install Bun
11
+ first (`curl -fsSL https://bun.sh/install | bash`, or `powershell -c "irm bun.sh/install.ps1 | iex"` on Windows), then
12
+ the package, `@design-twin/dtwin`, from npm:
13
+ ```
14
+ bun add -g @design-twin/dtwin # puts `dtwin` in ~/.bun/bin (on your PATH via the Bun installer)
15
+ ```
16
+ `npm i -g @design-twin/dtwin` installs the same thing, but `dtwin` still runs on Bun: without Bun on PATH it stops at
17
+ `env: bun: No such file or directory`. The package also carries the built Figma plugin (`figma-plugin/manifest.json`
18
+ inside it — `dtwin init` prints the full path to import) and the design-to-code bundles the MCP server's
19
+ `design_get_component` / `design_drift_lint` load (`layer/`).
20
+
21
+ Or with Homebrew (macOS, Linux), which installs Bun for you and keeps both up to date with `brew upgrade`:
22
+ ```
23
+ brew install its-magdy/tap/dtwin
24
+ ```
25
+ The formula installs the same npm package into Homebrew's prefix; every release updates it. Paths `dtwin init` writes
26
+ (the `.mcp.json` server entry, the plugin manifest it prints) are spelt through `$(brew --prefix)/opt/dtwin/…`, which
27
+ survives an upgrade — not the versioned `Cellar/dtwin/<version>/` folder the next `brew upgrade` deletes.
28
+
29
+ Or from a clone (to work on the code):
11
30
  ```
12
31
  git clone https://github.com/its-magdy/design-twin.git && cd design-twin
13
32
  bun install # @modelcontextprotocol/sdk (+ zod), for every workspace
14
33
  cd bridge && bun link # puts `dtwin` in ~/.bun/bin (on your PATH); nothing to build
15
34
  ```
16
- It needs [Bun](https://bun.sh/install) ≥ 1.4.2 (`engines.bun`); Node is not supported.
17
35
  Or skip the link and run `bun --no-install --no-env-file /path/to/design-twin/bridge/src/figma-pull.ts` wherever
18
36
  this README says `dtwin` (those two flags are what the bin's shebang adds: without them, Bun loads the `.env` of the
19
37
  project you run it in and may fetch a missing package from the registry).
@@ -34,7 +52,7 @@ validated against them and exits rather than binding a port nothing could ever r
34
52
  **Languages:** the whole bridge is **TypeScript** (ESM) under `src/` — `figma-pull.ts` (read CLI),
35
53
  `server-core.ts` (WS core), `figma-mcp.ts` (MCP server), and the modules they share. From a checkout,
36
54
  Bun runs it directly with **zero build** (`bun bridge/src/figma-pull.ts …`, `bun bridge/src/figma-mcp.ts`), and the
37
- package ships the same TypeScript: its `dtwin` bin — what `bun link` puts on your PATH — is `src/figma-pull.ts`,
55
+ package ships the same TypeScript: its `dtwin` bin — what `bun add -g` or `bun link` puts on your PATH — is `src/figma-pull.ts`,
38
56
  whose shebang is `#!/usr/bin/env -S bun --no-install --no-env-file` (so a `.env` or a missing package in the
39
57
  project you run it from can neither change its environment nor make Bun fetch a module from the registry;
40
58
  `env -S` needs GNU coreutils ≥ 8.30 or a BSD/macOS `env` — on BusyBox, call `bun --no-install --no-env-file` on
@@ -801,13 +819,38 @@ execution**, unlike some community servers; a `fill` / `color` must be a hex col
801
819
  `#rrggbb` or `#rrggbbaa` with the `#`, never a name like `red` — and anything else is refused (by the
802
820
  schema here, and by the plugin for a write from another client) instead of painted as a wrong colour; `dryRun: true` returns a preview of what each op would
803
821
  create or overwrite without touching the file — there is no undo from the MCP side, so preview anything
804
- that overwrites; refused outright when the file is in read-only Dev Mode), and two that read the export already on disk and
822
+ that overwrites; refused outright when the file is in read-only Dev Mode — and **refused unless the designer has
823
+ ticked "Allow edits"** in the plugin window, see below), and two that read the export already on disk and
805
824
  need no Figma connection — `design_get_component` (one component's variant node trees) and
806
825
  `design_drift_lint` (the component map vs the export; see below). The frame-walking export tools accept opt-in read flags
807
826
  `css` / `measurements` / `pluginData` / `motion` / `sharedData`; `figma_export_design_system` doesn't
808
827
  take them (it never walks a node — see below) but DOES take `variantVisuals`, since the component
809
828
  catalog it builds is exactly what that flag enriches.
810
829
 
830
+ ### "Allow edits" — the plugin changes nothing until the designer opts in
831
+ The plugin window has an **Allow edits** checkbox, **off by default**. While it is off the plugin only reads:
832
+ every `figma_write` batch is refused whole, before any op runs, and the tool returns this error (nothing in the
833
+ file changed):
834
+
835
+ > Edits are off in the Design Twin plugin — tick 'Allow edits' in the plugin window, then retry. Nothing in the file was changed.
836
+
837
+ That is not something an agent can fix. **Ask the user to tick "Allow edits" in the Design Twin plugin window,
838
+ then retry the same call.** The plugin's main thread holds the setting and checks it on every write; nothing on
839
+ the bridge side can turn it on.
840
+
841
+ - **Dry run still works while it is off.** `dryRun: true` previews the batch as before and adds `editsAllowed`
842
+ (read from the plugin's `whoami`): `false` → a real write would be refused right now (the preview also carries
843
+ `wouldRefuse` with the sentence above); `true` → it would be applied; `null` → unknown (no plugin connected,
844
+ several connected with no `client`, or a plugin built before the opt-in). Check it before asking the user to
845
+ review a preview, so the request to tick the box comes in the same breath.
846
+ - **The setting is per user, for every file.** It is saved in Figma's `clientStorage`, which is already scoped
847
+ to one user and this plugin. It is not per file: the plugin cannot reliably name a file (`fileKey` is only for
848
+ private plugins, and file names repeat), and a per-file flag stored in the document would itself be an edit.
849
+ Untick it when you are done.
850
+ - **No write is silent.** Each applied batch (and each refused one) shows a Figma toast and a line in the plugin
851
+ window, e.g. "Design Twin applied 3 edits to this file."
852
+ - `dtwin whoami` prints the state (`edits: off — …` / `edits: ALLOWED — …`) and `editsAllowed` is in its JSON.
853
+
811
854
  ### `writeToDisk` — the export path that doesn't go through the context window
812
855
  Every export tool takes `writeToDisk: true` (plus an optional `outDir`). It writes the export through
813
856
  the same `write-out.ts` the CLI uses — same layout, by construction — and returns a **compact index**