@ahmednawaz/crank 0.1.2

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/.env.example ADDED
@@ -0,0 +1,53 @@
1
+ # Companion (browser ↔ local bridge)
2
+ CRANK_PORT=3344
3
+ CRANK_HOST=127.0.0.1
4
+ # Shared team passphrase — required for panel + MCP when set (share internally, never commit real value)
5
+ # CRANK_TEAM_TOKEN=Crank-xxxxxxxxxxxxxxxxxxxxxxxx
6
+ # App repo to search/write when Apply persists copy (defaults to crank package root).
7
+ # For a real product app: CRANK_PROJECT_ROOT=/path/to/your-app
8
+ # Or: npx crank /path/to/your-app
9
+ # CRANK_PROJECT_ROOT=
10
+
11
+ # Motive Glean Client API
12
+ GLEAN_BASE_URL=https://motive-prod-be.glean.com
13
+ GLEAN_API_KEY=
14
+ # Default: Robot Content Designer (UX string options)
15
+ GLEAN_AGENT_ID=a866095fd53b419ab08338e3559fb7aa
16
+ # Required only when using a global token:
17
+ # GLEAN_ACT_AS=you@motive.com
18
+ # When true, skip network and return deterministic stub variants
19
+ GLEAN_STUB=true
20
+ # Max copy options to request/parse (default 3; was 4, was 6)
21
+ # CRANK_GLEAN_OPTION_COUNT=3
22
+ # Prefer /agents/runs/stream (live token progress). Set false to force /runs/wait.
23
+ # Stream does not reduce total latency — both block ~1–2 min for Robot Content Designer.
24
+ # GLEAN_USE_STREAM=true
25
+ # GLEAN_STREAM_FIRST_BYTE_MS=12000
26
+ # GLEAN_WAIT_HEARTBEAT_MS=3500
27
+ # Overall cap for stream + /runs/wait (default 5 min; agent often 90–140s)
28
+ # GLEAN_AGENT_TIMEOUT_MS=300000
29
+
30
+ # MCP server
31
+ CRANK_MCP_MODE=stdio
32
+ # For Replit / remote agents, run HTTP mode and expose HTTPS:
33
+ # CRANK_MCP_MODE=http
34
+ # CRANK_MCP_HTTP_PORT=3345
35
+ # Optional shared secret for remote MCP clients (Replit custom headers)
36
+ CRANK_MCP_API_KEY=
37
+
38
+ # Companion URL the MCP server uses to talk to the selection store
39
+ CRANK_COMPANION_URL=http://127.0.0.1:3344
40
+ VIZPATCH_ROOT=/Users/ahmed.nawaz/Downloads/vizpatch
41
+
42
+ # Optional: one-click "Run fully automatic" (bookmarklet Agent → SDK/CLI)
43
+ # User key: Cursor Dashboard → Integrations / API Keys
44
+ # OR team service-account key: Team Settings → Service accounts
45
+ # Team Admin API keys are NOT supported.
46
+ # CURSOR_API_KEY=
47
+ # Runtime: local (default, edits files on this machine) or cloud (Cursor VM + GitHub clone)
48
+ # CURSOR_AGENT_RUNTIME=local
49
+ # Required for cloud when git has no origin remote:
50
+ # CURSOR_AGENT_REPO_URL=https://github.com/org/repo
51
+ # CURSOR_AGENT_STARTING_REF=main
52
+ # CURSOR_AGENT_MODEL=composer-2.5
53
+ # CURSOR_AGENT_AUTO_PR=false
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ # Crank
2
+
3
+ Internal Motive tool for **copy iteration on live UI panels**.
4
+
5
+ Select a `div` → send its text nodes to a **Glean** agent (skills/rules aware) → review 3–4 copy options → apply the chosen variant via **MCP** into whatever product the panel is running in.
6
+
7
+ This repo is a **sibling extract** of patterns from [Vizpatch](../vizpatch) (inspect/select, companion bridge, text apply). It is intentionally separate so Vizpatch stays CSS-focused and Crank stays copy-focused.
8
+
9
+ ---
10
+
11
+ ## Architecture
12
+
13
+ ```mermaid
14
+ flowchart LR
15
+ subgraph Browser
16
+ Page[Product page / panel]
17
+ BM[Crank bookmarklet]
18
+ Page --> BM
19
+ end
20
+
21
+ subgraph Local_or_Hosted["Local or hosted bridge"]
22
+ Comp[Companion :3344]
23
+ Store[(Selection store)]
24
+ GleanClient[Glean client]
25
+ Comp --> Store
26
+ Comp --> GleanClient
27
+ end
28
+
29
+ subgraph Agent_backends["Agent backends"]
30
+ Glean[Glean agent API]
31
+ Skills[skills/ rules]
32
+ GleanClient --> Glean
33
+ Skills -.-> Glean
34
+ end
35
+
36
+ subgraph MCP_clients["MCP clients"]
37
+ Cursor[Cursor / Claude Desktop]
38
+ Replit[Replit Agent]
39
+ MCP[Crank MCP server]
40
+ Cursor -->|stdio| MCP
41
+ Replit -->|HTTPS custom MCP| MCP
42
+ MCP -->|HTTP| Comp
43
+ end
44
+
45
+ BM -->|WS / HTTP selection| Comp
46
+ Comp -->|APPLY_VARIANT| BM
47
+ Glean -->|3–4 variants| Comp
48
+ ```
49
+
50
+ ### Flow
51
+
52
+ 1. **Select** — Bookmarklet hover/click picks a `div`, extracts text nodes (`path`, `role`, `text`), posts to companion `/api/selection`.
53
+ 2. **Propose** — Companion calls Glean (`glean-client.js`) with selection context. Stub returns deterministic variants when `GLEAN_STUB=true` (count = `CRANK_GLEAN_OPTION_COUNT`, default 3).
54
+ 3. **Review** — Variants appear in the bookmarklet panel and/or via MCP tool `propose_copy_variants`.
55
+ 4. **Apply** — Panel **Apply** (or MCP `apply_copy_variant`) updates live DOM **and** persists editable hardcoded literals via Vizpatch `text-writer`. **Preview** is DOM-only.
56
+ 5. **Agent handoff (same chat)** — Panel **Agent** queues structured pending changes for MCP pull and copies a short phrase (`Apply the pending Crank change`) to the clipboard. Paste that phrase in your **current** Cursor chat (or keep an agent session that already has the `crank-apply-changes` skill). The agent calls `crank_get_formatted_changes` → edits source → `crank_clear_changes`. Optional secondary: **Open new chat instead** uses a `cursor://…/prompt` deeplink (opens a *new* prefilled chat — not the same Composer).
57
+
58
+ **There is no silent push into the IDE chat panel.** Cursor has no public “append to current Composer” API. MCP is pull-only (the agent calls tools). Prompt deeplinks always require user confirm ([docs](https://cursor.com/docs/reference/deeplinks): “never trigger automatic execution”) and open a new chat. Community workarounds (`composer.newAgentChat` + clipboard paste) also start a new chat — Crank does not ship those as primary. A background run via Cursor SDK / CLI (`Agent.prompt`, `agent -p`) is a separate agent — not the Composer chat — and needs `CURSOR_API_KEY`.
59
+
60
+ ---
61
+
62
+ ## Quick start (one command — Retune-style)
63
+
64
+ From your **app repo root** (Replit, Cursor terminal, or Codespaces — no paths):
65
+
66
+ ```bash
67
+ npx crank setup # once: MCP config, skill, devDependency, Vite inject
68
+ npx crank # starts companion + dev + panel
69
+ ```
70
+
71
+ MCP config uses **`npx -y crank mcp`** (like Retune) — no absolute paths. After setup, `crank` is added to `devDependencies` so virtual environments resolve it automatically.
72
+
73
+ **Agent chat:** paste `Apply the pending Crank change` or ask the agent to run `npx crank`. The agent should call **`crank_get_environment`** first to learn which repo and URLs are active.
74
+
75
+ That automatically:
76
+
77
+ 1. **Detects** your app directory (`app/`, `client/`, `web/`, or repo root — same heuristics as Retune)
78
+ 2. **Inits** MCP for Cursor / VS Code / Claude + installs the skill
79
+ 3. **Starts** companion + `npm run dev` when a dev script exists
80
+ 4. **Writes** `.crank/runtime.json` with public URLs for the panel loader
81
+
82
+ | Environment | Agent MCP | Panel |
83
+ |-------------|-----------|-------|
84
+ | **Cursor / Claude / VS Code** | `npx crank mcp` (stdio) | Vite auto-inject or bookmarklet |
85
+ | **Replit Agent** | HTTPS `/mcp` from `crank_get_environment` | Webview + bookmarklet |
86
+
87
+ Stop local daemon: `npx crank stop`
88
+
89
+ ### Vizpatch reuse (UI + text dispatch)
90
+
91
+ Set `VIZPATCH_ROOT` (defaults to sibling `../vizpatch`). Crank reuses:
92
+
93
+ - **tool-ui CSS** — `/ui/vizpatch-ui.css`
94
+ - **control helpers** — `/ui/crank-ui-helpers.js` (buttons, fields, textareas)
95
+ - **hardcoded vs dynamic/bound** — `/ui/text-source.js` (`classifyTextSource`)
96
+ - **DOM preview** — Preview / Discard (`PREVIEW_TEXT_CHANGE`)
97
+ - **source save** — Save source (`SAVE_TEXT_CHANGE` → Vizpatch `text-writer.js`)
98
+ - Locked nodes show a badge + reason and cannot be edited in-panel
99
+
100
+ Useful variants:
101
+
102
+ ```bash
103
+ npx crank init # write configs only
104
+ npx crank start --daemon --no-open # durable companion
105
+ npx crank --dev # also runs npm run dev
106
+ npx crank --http-mcp # force remote MCP (Replit-style)
107
+ npx crank doctor # print detected environment
108
+ npx crank stop # stop daemon
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Manual companion-only start
114
+
115
+ ```bash
116
+ cd ~/Downloads/crank
117
+ cp .env.example .env # if needed
118
+ npm install
119
+ node bin/crank.js start --daemon --no-open
120
+ ```
121
+
122
+ Open `http://127.0.0.1:3344`, drag the **Crank** bookmarklet to the bookmarks bar, open any page, click the bookmarklet → **Select** → **Ask Glean**.
123
+
124
+ Stub demo without a browser (companion must be running):
125
+
126
+ ```bash
127
+ npm run demo
128
+ ```
129
+
130
+ ### MCP (Cursor / Claude Desktop)
131
+
132
+ Companion must be running. Add to MCP config:
133
+
134
+ ```json
135
+ {
136
+ "mcpServers": {
137
+ "crank": {
138
+ "command": "node",
139
+ "args": ["~/Downloads/crank/mcp-server/index.js"],
140
+ "env": {
141
+ "CRANK_COMPANION_URL": "http://127.0.0.1:3344",
142
+ "CRANK_MCP_MODE": "stdio"
143
+ }
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ Tools:
150
+
151
+ | Tool | Purpose |
152
+ |------|---------|
153
+ | `get_selected_copy` | Read active selection + text nodes |
154
+ | `propose_copy_variants` | Call Glean for 3–4 iterations |
155
+ | `apply_copy_variant` | DOM apply + source persist (set `persist:false` for preview) |
156
+ | `apply_custom_copy` | Apply agent-edited `nodes[]` (DOM) |
157
+ | `crank_get_formatted_changes` | Agent-ready markdown for pending Agent-button changes (Retune-style) |
158
+ | `crank_get_pending_changes` | Structured JSON diffs for pending changes |
159
+ | `crank_watch_changes` | Long-poll until pending changes appear |
160
+ | `crank_clear_changes` | Clear pending after apply |
161
+ | `crank_status` | Whether anything is queued |
162
+ | `get_pending_agent_prompt` | Legacy: read full queued prompt |
163
+ | `ack_pending_agent_prompt` | Legacy: clear pending after applying |
164
+ | `queue_agent_prompt` | Queue a variant for Cursor (same as **Agent**) |
165
+
166
+ ### MCP (HTTP / Replit)
167
+
168
+ ```bash
169
+ CRANK_MCP_MODE=http CRANK_MCP_HTTP_PORT=3345 npm run mcp:http
170
+ ```
171
+
172
+ Expose `https://…/mcp` (tunnel or hosted) and add as a **custom MCP server** in Replit Integrations. Optional auth: set `CRANK_MCP_API_KEY` and pass `X-API-Key` in Replit advanced headers.
173
+
174
+ ---
175
+
176
+ ## Glean integration
177
+
178
+ Uses Motive Client API against `https://motive-prod-be.glean.com`.
179
+
180
+ Default agent: **Robot Content Designer** (`a866095fd53b419ab08338e3559fb7aa`) — generates + scores UX string options.
181
+
182
+ Env vars (see `.env.example`; secrets live in `.env`, gitignored):
183
+
184
+ | Variable | Role |
185
+ |----------|------|
186
+ | `GLEAN_BASE_URL` | Instance backend, e.g. `https://motive-prod-be.glean.com` |
187
+ | `GLEAN_API_KEY` | Client API bearer token |
188
+ | `GLEAN_AGENT_ID` | Agent Builder id (default = Robot Content Designer) |
189
+ | `GLEAN_ACT_AS` | Optional; required for global tokens |
190
+ | `GLEAN_STUB` | `true` = local stub variants; `false` = live agent |
191
+ | `CRANK_GLEAN_OPTION_COUNT` | Max options to request/parse (default **3**; was 4, was 6) |
192
+ | `GLEAN_USE_STREAM` | `true` = live SSE progress (same latency as `/runs/wait`) |
193
+ | `GLEAN_AGENT_TIMEOUT_MS` | Overall cap (default 5 min) |
194
+
195
+ **Latency:** Robot Content Designer typically takes **1–2 minutes** end-to-end. Most of that is inherent agent runtime (~55–90s silent phase before tokens). Stream vs wait does not materially change total time — stream only adds live progress UI. Set `GLEAN_STUB=true` for instant local dev.
196
+
197
+ Live path: `POST /rest/api/v1/agents/runs/stream` (preferred) or `/runs/wait` with the agent’s form fields. Companion parses Option N / Heading / Body / CTA from the agent markdown into `variants[]` for the panel + MCP.
198
+
199
+ ---
200
+
201
+ ## Replit MCP conclusion
202
+
203
+ **Replit Agent can consume MCP natively** — no browser extension is required for MCP itself.
204
+
205
+ Findings (as of Dec 2025 / docs current through 2026):
206
+
207
+ - Replit Agent supports the Model Context Protocol as a **client**: curated one-click servers plus **custom remote MCP servers** by HTTPS URL ([Connect via MCP](https://docs.replit.com/build/connect-via-mcp), [changelog 2025-12-12](https://docs.replit.com/updates/2025/12/12/changelog)).
208
+ - Custom servers are added under Integrations → MCP Servers → **Add MCP server** with an HTTPS endpoint; optional custom headers (e.g. `X-API-Key`) for static tokens ([MCP list / auth](https://docs.replit.com/references/mcp/overview)).
209
+ - Traffic is scanned by Replit’s security layer before tools run.
210
+ - Replit needs a **network-reachable HTTPS** MCP endpoint. Local `stdio` MCP (Cursor-style) does **not** work for Replit. Host Crank MCP with `CRANK_MCP_MODE=http` behind HTTPS (or a tunnel).
211
+
212
+ **What still needs a browser-side hook in Replit:**
213
+
214
+ | Concern | Native MCP? | What you need |
215
+ |---------|-------------|----------------|
216
+ | Agent calling `get_selected_copy` / `apply_copy_variant` | Yes (remote HTTPS MCP) | Hosted `mcp-server` |
217
+ | User selecting a `div` inside a Replit webview/preview | No | Bookmarklet (or a small content-script extension) injected into that page, talking to companion |
218
+ | Companion selection store on laptop localhost | Not reachable from Replit cloud | Host companion + MCP together, or tunnel both |
219
+
220
+ **Bottom line:** Replit does **not** need an extension for MCP. It **does** need (1) a remote HTTPS Crank MCP, and (2) something in the page (bookmarklet/extension) to capture the selection — same as local Cursor workflows.
221
+
222
+ ---
223
+
224
+ ## Repo layout
225
+
226
+ ```text
227
+ crank/
228
+ ├── bin/crank.js # CLI: init, start --daemon, stop, status
229
+ ├── bookmarklet/ # Div picker + text extract + panel
230
+ ├── companion/ # Express + WebSocket bridge + Glean client
231
+ ├── mcp-server/ # MCP tools (stdio + HTTP)
232
+ ├── skills/ # Copy rules sent to / used by Glean
233
+ ├── scripts/demo-flow.js # Curl-less E2E stub demo
234
+ ├── .env.example
235
+ └── README.md
236
+ ```
237
+
238
+ ---
239
+
240
+ ## What was reused from Vizpatch vs new
241
+
242
+ | Area | Approach |
243
+ |------|----------|
244
+ | Element picker (highlight, click, Esc) | **Forked pattern** from `extension/content.js` / bookmarklet inspect |
245
+ | Companion Express + WS on fixed port | **Forked pattern** from `companion/server.js` (stripped CSS/sourcemap/VFS) |
246
+ | Text node write-back | **Simplified invent** — live DOM by path index; source-file `text-writer.js` not copied yet |
247
+ | Glean client + skills/ | **New** |
248
+ | MCP tool surface | **New** |
249
+ | tool-ui / CSS inspector chrome | **Not reused** (out of scope) |
250
+
251
+ ---
252
+
253
+ ## Key next steps (real Glean + product wiring)
254
+
255
+ 1. Drop real `GLEAN_API_KEY` / `GLEAN_AGENT_ID`; set `GLEAN_STUB=false`.
256
+ 2. Align request/response schema in `companion/glean-client.js` with the Motive Glean agent contract.
257
+ 3. Point Glean at `skills/` (or sync rules into Glean’s skill store).
258
+ 4. Optionally port Vizpatch `text-writer.js` for source-file persistence when the panel maps to a known project root.
259
+ 5. For Replit: deploy companion + MCP HTTP behind HTTPS; document the Integrations URL + `X-API-Key`.
260
+ 6. Harden MCP HTTP to the official Streamable HTTP transport if Replit’s client requires it beyond JSON-RPC `/mcp`.
261
+
262
+ ---
263
+
264
+ ## Status
265
+
266
+ Internal scaffold — runnable stubs. Not a production Motive service yet.