letmeknow-cli 0.4.1 → 0.4.3
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 +37 -128
- package/SKILL.md +49 -113
- package/bin/letmeknow.js +9 -286
- package/bin/relay.js +440 -0
- package/bin/remote.js +299 -0
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -1,175 +1,84 @@
|
|
|
1
1
|
# LetMeKnow
|
|
2
2
|
|
|
3
|
-
LetMeKnow gives
|
|
3
|
+
LetMeKnow gives an agent-managed folder a public, live Vite preview. The CLI runs Vite in middleware mode and makes only an outbound WebSocket connection to the relay; it does not listen on a network port.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Start
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Node 22 or newer is required.
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npx letmeknow-cli
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
The deployed service is used by default. Set `LETMEKNOW_URL` for local development:
|
|
7
|
+
Node.js 22.12 or newer is required.
|
|
16
8
|
|
|
17
9
|
```bash
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
stdin contains one compact JSON command per line. stdout contains one JSON event per line. Diagnostics go to stderr.
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npx letmeknow-cli --skill
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
prints the agent instructions without connecting.
|
|
28
|
-
|
|
29
|
-
## Example
|
|
30
|
-
|
|
31
|
-
Open a session:
|
|
32
|
-
|
|
33
|
-
```json
|
|
34
|
-
{"type":"open","id":"open-1"}
|
|
10
|
+
npx letmeknow-cli ./workspace
|
|
35
11
|
```
|
|
36
12
|
|
|
37
|
-
The CLI
|
|
13
|
+
The CLI prints JSON lines to stdout. The first line contains the public preview URL:
|
|
38
14
|
|
|
39
15
|
```json
|
|
40
|
-
{"type":"
|
|
16
|
+
{"type":"ready","url":"https://0123456789abcdef0123.letmeknow.dev/"}
|
|
41
17
|
```
|
|
42
18
|
|
|
43
|
-
|
|
19
|
+
Open that URL in one browser. The directory defaults to the current working directory. Set `LETMEKNOW_URL` to use another compatible relay:
|
|
44
20
|
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
A connected browser receives the render immediately. The acknowledgement contains its revision:
|
|
50
|
-
|
|
51
|
-
```json
|
|
52
|
-
{"type":"ack","id":"render-1","render_id":"b87438c2-4f1c-44bd-9875-6cc64370b8aa"}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Submitting the form produces one normalized action:
|
|
56
|
-
|
|
57
|
-
```json
|
|
58
|
-
{"type":"action","id":"2ee81a6b-1035-40a7-a90d-c1e02f426baa","render_id":"b87438c2-4f1c-44bd-9875-6cc64370b8aa","action_id":"search","form_id":"search","target_id":"results","trigger":{"id":null,"name":null,"value":null},"values":{"customer":"Acme Ltd"}}
|
|
21
|
+
```bash
|
|
22
|
+
LETMEKNOW_URL=https://letmeknow.dev npx letmeknow-cli ./workspace
|
|
59
23
|
```
|
|
60
24
|
|
|
61
|
-
|
|
25
|
+
There are no `--host` or `--port` options because the CLI intentionally has no listening network socket. Diagnostics go to stderr. `--skill` prints the agent instructions without starting a session.
|
|
62
26
|
|
|
63
|
-
|
|
64
|
-
{"type":"response","id":"response-1","request_id":"2ee81a6b-1035-40a7-a90d-c1e02f426baa","body":"<table><tr><th>Invoice</th><th>Amount</th></tr><tr><td>INV-42</td><td>$800</td></tr></table>"}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
The browser inserts the fragment into `#results`. Without `data-lmk-target`, the response replaces the whole workspace.
|
|
27
|
+
## File workflow
|
|
68
28
|
|
|
69
|
-
|
|
29
|
+
The CLI does not receive file commands. The agent reads and writes the directory directly. Keep a normal Vite entry point such as `index.html`; JavaScript, CSS, images, and other Vite-supported files can be requested through the relay.
|
|
70
30
|
|
|
71
|
-
|
|
31
|
+
When a watched file changes, the browser receives an update. HTML changes replace the current document body without a page reload and preserve form values, focus, selection, and scroll position. CSS links are refreshed without navigating. Changes to a different HTML route do not disturb the current page.
|
|
72
32
|
|
|
73
|
-
|
|
33
|
+
An optional element can display submission status:
|
|
74
34
|
|
|
75
35
|
```html
|
|
76
|
-
<
|
|
77
|
-
<label>Comment<textarea name="comment"></textarea></label>
|
|
78
|
-
<button name="decision" value="approve" formaction="approve">Approve</button>
|
|
79
|
-
<button name="decision" value="reject" formaction="reject">Reject</button>
|
|
80
|
-
</form>
|
|
36
|
+
<p data-letmeknow-status aria-live="polite"></p>
|
|
81
37
|
```
|
|
82
38
|
|
|
83
|
-
|
|
39
|
+
## Form submissions
|
|
84
40
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
A button can invoke an action without a form:
|
|
41
|
+
Forms are submitted without navigation. GET and POST forms are sent through the relay to the CLI, which prints each submission as one JSON line on stdout. The agent can read that line and edit the folder in response.
|
|
88
42
|
|
|
89
43
|
```html
|
|
90
|
-
<
|
|
44
|
+
<form id="decision" action="/decide" method="post">
|
|
45
|
+
<label>Comment <textarea name="comment"></textarea></label>
|
|
46
|
+
<button name="decision" value="approve">Approve</button>
|
|
47
|
+
<button name="decision" value="reject">Reject</button>
|
|
48
|
+
</form>
|
|
91
49
|
```
|
|
92
50
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
### Targeted updates
|
|
96
|
-
|
|
97
|
-
`data-lmk-target` accepts one bare element ID. All updates use `innerHTML`. There are no alternate swap modes or selector targets. The default target is `lmk-view`, the whole workspace.
|
|
98
|
-
|
|
99
|
-
Typing, focusing, expanding `<details>`, validation, scrolling, and other local browser behavior produce no agent events.
|
|
100
|
-
|
|
101
|
-
## CSS
|
|
102
|
-
|
|
103
|
-
`render` accepts page CSS in its `css` field. A `response` may include `css` to replace it; omitting `css` preserves it.
|
|
104
|
-
|
|
105
|
-
Modern CSS is supported, including grid, flexbox, media queries, variables, transitions, and print styles. External stylesheets, `@import`, scripts, inline handlers, and inline `style` attributes are blocked. Local assets work in HTML and CSS.
|
|
106
|
-
|
|
107
|
-
## One browser client
|
|
108
|
-
|
|
109
|
-
At most one browser is active for a session. The first browser receives a private credential stored in that tab's `sessionStorage`.
|
|
110
|
-
|
|
111
|
-
- Reloads and reconnects reuse the credential.
|
|
112
|
-
- A competing browser triggers at most one liveness probe every five seconds.
|
|
113
|
-
- If the active browser answers, the claimant sees “This session is open elsewhere.”
|
|
114
|
-
- After a disconnect, the previous credential has a five-second exclusive reconnect period.
|
|
115
|
-
- After five seconds, either the old browser or a new claimant may connect; first connection wins.
|
|
116
|
-
- Laptop sleep does not invalidate the credential.
|
|
117
|
-
|
|
118
|
-
The server sends a connecting browser one canonical snapshot of the current HTML, CSS, render ID, and pending actions. It does not replay user actions. The browser restores same-tab drafts from `sessionStorage`; drafts do not transfer to another browser.
|
|
119
|
-
|
|
120
|
-
The server keeps committed page state and assets for the producer session. A full `render` replaces the page and clears old pending actions. A targeted response updates the canonical page. Browser disconnect alone does not delete state.
|
|
121
|
-
|
|
122
|
-
## Assets
|
|
123
|
-
|
|
124
|
-
`put` stores or replaces passive resources only under `/assets/`:
|
|
51
|
+
Submitting `Approve` prints an event like:
|
|
125
52
|
|
|
126
53
|
```json
|
|
127
|
-
{"type":"
|
|
54
|
+
{"type":"submit","id":"…","method":"POST","action":"/decide","form_id":"decision","trigger":{"id":null,"name":"decision","value":"approve"},"values":{"comment":"Looks good","decision":"approve"}}
|
|
128
55
|
```
|
|
129
56
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
```html
|
|
133
|
-
<img src="assets/logo.png" alt="Company logo">
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Assets answer only `GET` and `HEAD`. Each body is limited to 1 MiB. A session accepts 100 assets and 10 MiB decoded asset data. There is no `delete`; assets disappear with the session.
|
|
137
|
-
|
|
138
|
-
## Protocol
|
|
139
|
-
|
|
140
|
-
Commands:
|
|
57
|
+
Repeated field names become arrays. Native browser validation still runs before a submission is sent. File inputs and cross-origin form actions are not supported. Forms can use a submitter's standard `formaction`, `formmethod`, and `name`/`value` attributes.
|
|
141
58
|
|
|
142
|
-
|
|
143
|
-
- `render`: replace the committed HTML and CSS and push it to the browser.
|
|
144
|
-
- `put`: store an asset under `/assets/`.
|
|
145
|
-
- `response`: resolve one pending action with HTML and optional CSS.
|
|
146
|
-
- `close`: destroy the session immediately.
|
|
59
|
+
The event ID identifies the submission. It is not a request/response handle: update the files and let the live preview show the result.
|
|
147
60
|
|
|
148
|
-
|
|
61
|
+
## Security
|
|
149
62
|
|
|
150
|
-
|
|
151
|
-
- `action`: normalized form or standalone-button action.
|
|
152
|
-
- `ack`: command completion.
|
|
153
|
-
- `error`: invalid command or protocol state.
|
|
154
|
-
- `closing`: explicit session destruction.
|
|
63
|
+
The preview URL is a bearer capability. The relay receives the served files and submitted values. Do not put secrets in the preview folder or submit credentials unless that is intentional. The folder is trusted executable code from the browser's perspective.
|
|
155
64
|
|
|
156
|
-
|
|
65
|
+
The CLI's Vite configuration is disabled and its filesystem access is limited to the selected folder. The CLI itself still requires an outbound network connection to the relay. It does not accept inbound browser connections.
|
|
157
66
|
|
|
158
|
-
|
|
67
|
+
## Hosted compatibility
|
|
159
68
|
|
|
160
|
-
|
|
69
|
+
Existing clients using the older command protocol can still connect explicitly without a folder:
|
|
161
70
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
If the producer disconnects, the current page remains visible, drafts are preserved, and actions are disabled. The CLI can reconnect for ten minutes. Browser traffic does not extend that grace. `close` or producer-grace expiry deletes page state, credentials, pending actions, and assets.
|
|
71
|
+
```bash
|
|
72
|
+
LETMEKNOW_URL=https://letmeknow.dev npx letmeknow-cli
|
|
73
|
+
```
|
|
167
74
|
|
|
168
75
|
## Development
|
|
169
76
|
|
|
170
77
|
```bash
|
|
171
78
|
npm install
|
|
172
|
-
npm run dev
|
|
173
79
|
npm test
|
|
80
|
+
npm run dev
|
|
174
81
|
npm run deploy
|
|
175
82
|
```
|
|
83
|
+
|
|
84
|
+
`npm run dev` and `npm run deploy` operate the Cloudflare relay.
|
package/SKILL.md
CHANGED
|
@@ -1,164 +1,100 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: letmeknow
|
|
3
|
-
description:
|
|
3
|
+
description: Give a human a live public preview of an agent-managed folder and receive browser form submissions as JSON lines.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# LetMeKnow
|
|
7
7
|
|
|
8
|
-
Use LetMeKnow when one human needs a temporary
|
|
8
|
+
Use LetMeKnow when one human needs to inspect or interact with a temporary page, report, dashboard, approval form, quiz, table, or status view. The agent owns the files in a folder. The CLI runs Vite in middleware mode, connects to the public relay over an outbound WebSocket, and reports browser submissions on stdout.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
The CLI does **not** listen on a local network port.
|
|
11
11
|
|
|
12
12
|
## Start
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Run the CLI as a long-lived child process with the folder you will edit:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
npx letmeknow-cli
|
|
17
|
+
npx letmeknow-cli ./workspace
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Node.js 22.12 or newer is required. Read stdout and stderr separately. Stdout is JSONL; the first event is:
|
|
21
21
|
|
|
22
22
|
```json
|
|
23
|
-
{"type":"
|
|
23
|
+
{"type":"ready","url":"https://0123456789abcdef0123.letmeknow.dev/"}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Open the public URL for the human. The directory defaults to the current working directory. Set `LETMEKNOW_URL` to use another compatible relay. There are no host or port options: the CLI intentionally has no listening socket.
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
{"type":"session","id":"open-1","url":"https://0123456789abcdef0123.letmeknow.dev/","expires_after_disconnect":600}
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
The URL immediately serves a shell with a waiting message. One browser may use it at a time.
|
|
33
|
-
|
|
34
|
-
## Render HTML and CSS
|
|
35
|
-
|
|
36
|
-
```json
|
|
37
|
-
{"type":"render","id":"render-1","body":"<h1>Search invoices</h1><form id=\"search\" action=\"search\" method=\"post\" data-lmk-target=\"results\"><label>Customer<input name=\"customer\" required></label><button>Search</button></form><section id=\"results\"><p>Enter a customer.</p></section>","css":"#results { margin-top: 2rem; }"}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
A connected browser receives the render immediately. Wait for its acknowledgement and retain the `render_id`:
|
|
41
|
-
|
|
42
|
-
```json
|
|
43
|
-
{"type":"ack","id":"render-1","render_id":"b87438c2-4f1c-44bd-9875-6cc64370b8aa"}
|
|
44
|
-
```
|
|
28
|
+
Do not send file commands to stdin. Read and write the folder directly. Keep the process running while the human uses the page.
|
|
45
29
|
|
|
46
|
-
|
|
30
|
+
## Build the page
|
|
47
31
|
|
|
48
|
-
|
|
32
|
+
Create an ordinary Vite page in the folder, usually `index.html`, plus any CSS, JavaScript, images, or other assets it needs. Use semantic HTML and accessible labels, headings, sections, tables, and controls.
|
|
49
33
|
|
|
50
|
-
|
|
34
|
+
The relay is live:
|
|
51
35
|
|
|
52
|
-
|
|
36
|
+
- HTML changes update the current document body without a full page reload.
|
|
37
|
+
- Existing form values, focus, text selection, and scroll position are restored after an HTML update.
|
|
38
|
+
- CSS links are refreshed without navigating.
|
|
39
|
+
- Changes to another HTML route do not replace the current route.
|
|
53
40
|
|
|
54
|
-
|
|
41
|
+
An optional status element gives the human feedback after a form submission:
|
|
55
42
|
|
|
56
43
|
```html
|
|
57
|
-
<
|
|
58
|
-
<label>Reason<textarea name="reason" required></textarea></label>
|
|
59
|
-
<button name="decision" value="approve" formaction="approve">Approve</button>
|
|
60
|
-
<button name="decision" value="reject" formaction="reject">Reject</button>
|
|
61
|
-
</form>
|
|
44
|
+
<p data-letmeknow-status aria-live="polite"></p>
|
|
62
45
|
```
|
|
63
46
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- Use `method="post"`.
|
|
67
|
-
- Give each form a stable, unique `id`.
|
|
68
|
-
- Give controls meaningful `name` values.
|
|
69
|
-
- Use an action identifier containing letters, digits, `.`, `_`, `:`, or `-`.
|
|
70
|
-
- A submit button's standard `formaction` may override the form action.
|
|
71
|
-
- Native `required`, input types, ranges, and patterns validate locally.
|
|
47
|
+
## Receive form submissions
|
|
72
48
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
## Standalone actions
|
|
49
|
+
GET and POST forms are intercepted before navigation and sent through the relay to the CLI. Read stdout for a `submit` event:
|
|
76
50
|
|
|
77
51
|
```html
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
</button>
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Use standalone actions for refresh, retry, cancel, generate, inspect, load-more, and export. Their events have `form_id: null`, empty `values`, and the button's optional `id`, `name`, and `value` in `trigger`.
|
|
84
|
-
|
|
85
|
-
## Whole and partial updates
|
|
86
|
-
|
|
87
|
-
Responses replace the whole workspace by default. To update a region, put `data-lmk-target="element-id"` on the form or action button:
|
|
88
|
-
|
|
89
|
-
```html
|
|
90
|
-
<form id="search" action="search" method="post" data-lmk-target="results">
|
|
91
|
-
<input name="query">
|
|
92
|
-
<button>Search</button>
|
|
52
|
+
<form id="search" action="/search" method="post">
|
|
53
|
+
<label>Query <input name="query" required></label>
|
|
54
|
+
<button name="scope" value="all">Search all</button>
|
|
93
55
|
</form>
|
|
94
|
-
<section id="results"></section>
|
|
95
56
|
```
|
|
96
57
|
|
|
97
|
-
The
|
|
98
|
-
|
|
99
|
-
## Handle actions
|
|
58
|
+
The event is:
|
|
100
59
|
|
|
101
60
|
```json
|
|
102
|
-
{"type":"
|
|
61
|
+
{"type":"submit","id":"…","method":"POST","action":"/search","form_id":"search","trigger":{"id":null,"name":"scope","value":"all"},"values":{"query":"quarterly report","scope":"all"}}
|
|
103
62
|
```
|
|
104
63
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
- `id` to respond to this exact action.
|
|
108
|
-
- `render_id` to identify the page revision that produced it.
|
|
109
|
-
- `action_id` for user intent.
|
|
110
|
-
- `form_id` and `target_id` for context.
|
|
111
|
-
- `trigger` for the clicked button.
|
|
112
|
-
- `values` for the submitted form snapshot.
|
|
113
|
-
|
|
114
|
-
Validate actions and values. Treat values as untrusted and HTML-escape reflected text.
|
|
115
|
-
|
|
116
|
-
Respond with HTML for the target contents:
|
|
117
|
-
|
|
118
|
-
```json
|
|
119
|
-
{"type":"response","id":"response-1","request_id":"2ee81a6b-1035-40a7-a90d-c1e02f426baa","body":"<table><tr><th>Invoice</th><th>Amount</th></tr><tr><td>INV-42</td><td>$800</td></tr></table>"}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
A response may include `css` to replace the page CSS. Omitting it preserves the existing CSS:
|
|
123
|
-
|
|
124
|
-
```json
|
|
125
|
-
{"type":"response","id":"response-2","request_id":"event-2","body":"<h1 class=\"success\">Approved</h1>","css":".success { color: green; }"}
|
|
126
|
-
```
|
|
64
|
+
Rules:
|
|
127
65
|
|
|
128
|
-
|
|
66
|
+
- Give interactive forms a stable, meaningful `id`.
|
|
67
|
+
- Give controls meaningful `name` values.
|
|
68
|
+
- Use normal relative or same-origin actions.
|
|
69
|
+
- Use `formaction` and `formmethod` on submitters when different buttons have different intents.
|
|
70
|
+
- Native `required`, input types, ranges, and patterns validate in the browser before the event is sent.
|
|
71
|
+
- Repeated names become string arrays.
|
|
72
|
+
- File inputs and cross-origin actions are not supported.
|
|
129
73
|
|
|
130
|
-
|
|
74
|
+
The event ID identifies the submission. There is no response packet. Validate its values, edit the files, and let the live preview show the result. Do not write JSON commands to stdin.
|
|
131
75
|
|
|
132
|
-
|
|
76
|
+
## Example response workflow
|
|
133
77
|
|
|
134
|
-
|
|
78
|
+
1. Render the initial state in `index.html`.
|
|
79
|
+
2. Wait for a `submit` event on stdout.
|
|
80
|
+
3. Validate its `values` and `action`.
|
|
81
|
+
4. Rewrite the relevant HTML or data file in the workspace.
|
|
82
|
+
5. The browser updates in place through the relay.
|
|
135
83
|
|
|
136
|
-
|
|
84
|
+
Escape untrusted values before placing them in HTML. Treat browser input as untrusted even though the folder is local to the agent.
|
|
137
85
|
|
|
138
|
-
##
|
|
86
|
+
## Security
|
|
139
87
|
|
|
140
|
-
|
|
141
|
-
{"type":"put","id":"logo","path":"/assets/logo.png","content_type":"image/png","encoding":"base64","body":"iVBORw0KGgo..."}
|
|
142
|
-
```
|
|
88
|
+
The public URL is a bearer capability. The relay receives the served files and submitted values. Do not put secrets in the preview folder or submit credentials unless that is intentional. The folder is trusted executable code from the browser's perspective.
|
|
143
89
|
|
|
144
|
-
|
|
90
|
+
The CLI disables Vite config discovery and limits filesystem access to the selected folder. It makes outbound relay connections only; it does not accept inbound browser connections.
|
|
145
91
|
|
|
146
|
-
|
|
147
|
-
<img src="assets/logo.png" alt="Company logo">
|
|
148
|
-
```
|
|
92
|
+
## Stop
|
|
149
93
|
|
|
150
|
-
|
|
94
|
+
Send `SIGINT` or `SIGTERM` to stop the CLI. The relay session expires after producer disconnect. `--skill` prints these instructions without starting a session.
|
|
151
95
|
|
|
152
|
-
|
|
96
|
+
Existing clients using the older hosted command protocol can still connect explicitly without a folder:
|
|
153
97
|
|
|
154
|
-
```
|
|
155
|
-
|
|
98
|
+
```bash
|
|
99
|
+
LETMEKNOW_URL=https://letmeknow.dev npx letmeknow-cli
|
|
156
100
|
```
|
|
157
|
-
|
|
158
|
-
Wait for `ack` and `closing`. Closing stdin only disconnects the producer.
|
|
159
|
-
|
|
160
|
-
If the producer disconnects, the page remains visible, drafts remain, and actions are disabled. The CLI has ten minutes to reconnect. Browser traffic does not extend that period. Explicit close or expiry deletes HTML, CSS, credentials, actions, and assets.
|
|
161
|
-
|
|
162
|
-
Limits: 1 MiB per HTML, CSS, asset, or action body; 100 assets; 10 MiB decoded asset storage; and 32 pending actions.
|
|
163
|
-
|
|
164
|
-
Treat the URL as a bearer secret. Never expose either private reconnect credential.
|