@cssints/devtools 0.2.0 → 0.3.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
@@ -33,6 +33,11 @@ docs/API.md, "Debugging: the devtools overlay"; the design in docs/research/devt
33
33
  (a `cssints` button and Alt+Shift+C). The first open loads both; a call shows as `file:line` and its source, with no link
34
34
  to an editor. The table has no path of the machine that built it. Sizes are logged by the build (this site: table 70 kB,
35
35
  overlay 190 kB, the entry +0.85 kB).
36
+ - **Readable classes, dev only.** The dev server adds `cs-<owner>[-<label>]` to each `cn(...)` and `cv({...})`:
37
+ `const logo = cn(...)` inside `function Landing()` gives `cs-Landing-logo`, at the top of `landing/page.ts`
38
+ `cs-page-logo`, `<div class={cn(...)}>` in `Button` `cs-Button`. The panel shows it first in its bar and in the hover
39
+ tag; the prompt's `Classes:` line lists it. It is not in the table, the sheet or the hashes, and a build has none.
40
+ docs/API.md, "Debugging: the devtools overlay".
36
41
  - **The data is the compiler's.** The table holds the sheet as the server renders it, each class's rule, plugin,
37
42
  tokens and sites, and the place of every call. The core parses the sheet; it never reads the page's CSSOM for
38
43
  cssints' rules.
@@ -54,15 +59,75 @@ cssints({ devtools: true, opencode: true });
54
59
  cssints({ devtools: true, opencode: { agent: "build", skills: ["cssints"] } });
55
60
  ```
56
61
 
57
- With an element picked, the panel has a prompt box (Enter sends, Shift+Enter is a new line). The dev server starts a session
58
- on the running OpenCode V2 service (`Service.discover` of `@opencode/client`; the page never talks to it) in the nearest
59
- folder up from the Vite root that has a `.git`, with a prompt of `src/core/prompt.ts`: your instruction, the element (tag,
60
- DOM path, text, classes), the `css.*` calls that style it (`file:line` and the call's source), the winner of each property
61
- and what it beat, and the tokens it reads; every list is cut. The box then shows `running · <session id>`, and `completed`,
62
- `failed` or `interrupted`; with no service running it says so and keeps your text. The page and the server talk over the
63
- HMR channel (`cssints:devtools:ask`, `cssints:devtools:asked`), not a route. A build has none of it. The idea, and the
64
- calls to the V2 client, follow [brendonovich/vite-plugin-opencode](https://github.com/Brendonovich/vite-plugin-opencode)
65
- (MIT, Brendan Allan), which marks the markup with Babel and so needs no table; here the table is the context.
62
+ The panel has an OpenCode box whenever the option is on, picked element or not. It is pinned: at the bottom of the panel in
63
+ a left or right dock, at its right edge (20 rem wide, to the right of the inspection) in a top or bottom dock, and in the
64
+ detached window by the window's shape (wider than tall: the right edge); the inspection beside it scrolls, the box does not.
65
+ The box has a title row (`OpenCode`, and a dot with `connected` or `not connected`), the input (Enter sends, Shift+Enter is a
66
+ new line) and one status line:
67
+
68
+ - Not connected: how to connect. Start OpenCode (or `opencode serve --service`) and run `/cssints-devtools` in a session; the
69
+ dev server finds the running service by itself; a prompt without an attached session opens a new one in the repository
70
+ folder; `@opencode/client` must be in the app's devDependencies. When the server has its own message (the client is not
71
+ installed), it follows.
72
+ - Connected: `connected to <service address> · attached session <id> · <state>`, or `no session attached: a prompt starts a
73
+ new one`. The id is the session `/cssints-devtools` attached to this dev server (truncated; the full id is the title); the
74
+ state is `running`, `completed`, `failed` or `interrupted`.
75
+
76
+ The page asks the dev server whether a service is found (a probe: it looks, it creates no session) when the panel opens, when
77
+ the box gets focus and after a send that found none, so starting OpenCode later shows up without a reload.
78
+
79
+ ### The command `/cssints-devtools`
80
+
81
+ The box does not choose a session: an OpenCode command attaches the session it runs in to a dev server. The plugin is the
82
+ main entry of this package, so OpenCode loads it by the package name (checked on 2.0.27: it installs the package and finds
83
+ the entry; a package subpath, `@cssints/devtools/opencode`, is not loaded as a plugin):
84
+
85
+ ```jsonc
86
+ // opencode.jsonc of the repository of the app (or ~/.config/opencode/opencode.jsonc)
87
+ { "plugins": ["@cssints/devtools"] }
88
+ ```
89
+
90
+ Or, with the package installed in the app, a file of the repository (OpenCode loads the `.ts` files of `.opencode/plugins/`):
91
+
92
+ ```ts
93
+ // .opencode/plugins/cssints-devtools.ts
94
+ export { default } from "@cssints/devtools/opencode";
95
+ ```
96
+
97
+ Then, in an OpenCode session:
98
+
99
+ - `/cssints-devtools`: one dev server of this repository with `opencode` on runs: this session is attached to it. Several
100
+ run: they are listed (id, address, root) and none is attached. None: it says so.
101
+ - `/cssints-devtools <id or part of it>` picks one (the id is the Vite root relative to the repository, `/` as `-`, so
102
+ `docs` picks `apps-docs`); `/cssints-devtools off [id]` detaches this session (or that server).
103
+
104
+ Each outcome is a message in the session (`ctx.session.synthetic`, which also gives the model a turn to acknowledge it). The
105
+ prompts of an attached server's panel are sent to that session, which is not created again; a session that is gone makes the
106
+ send fail with a message that says to run `/cssints-devtools` again. The rendezvous is files, not a route (the ask channel is
107
+ the HMR socket, which Vite's token protects): `<repository>/node_modules/.cache/cssints-devtools/<id>.json` (`root`, `pid`,
108
+ `url`) is written by the dev server while it runs, and `<id>.session.json` by the command. A dev server that crashed leaves a
109
+ file with a dead pid, which the command ignores and removes. The plugin imports `cssints/devtools-link`, the module both
110
+ sides share.
111
+
112
+ Without an attached session, Enter starts a session on the running OpenCode V2 service (`Service.discover` of
113
+ `@opencode/client`; the page never talks to it) in the nearest folder up from the Vite root that has a `.git`. The prompt is built by `src/core/prompt.ts`:
114
+
115
+ - `App:` (added by the dev server, on top): the Vite root relative to the repository (`.` when it is the repository) and the
116
+ address the server listens on, as file paths in the prompt are relative to that root;
117
+ - your instruction, then `Page:` (path, query and hash, not the origin), `Title:` and `Display:` (viewport and pixel ratio,
118
+ the `class` and `data-*` attributes of `<html>`, `prefers-color-scheme` and `prefers-reduced-motion`; with an element, its
119
+ rendered size and position and whether it is hovered, focused or disabled);
120
+ - with an element picked: its tag, DOM path, text, classes, `id`, `role`, `aria-label`, `href`, `src`, `alt`, `type`, `name`,
121
+ `placeholder` and `title`, the `data-*` attributes of it and of its three nearest ancestors, the `css.*` calls that style it
122
+ (`file:line` and the call's source), the winner of each property and what it beat, and the tokens it reads. Never a `value`,
123
+ a cookie or storage.
124
+
125
+ Every list and value is cut, the server cuts the whole at 16,000 characters from the end (the `App:` line, the instruction
126
+ and the header come first and stay). With no service running the box says how to connect and keeps your text. The
127
+ page and the server talk over the HMR channel (`cssints:devtools:ask`, `asked`, `link`, `linked`), not a route. A build has
128
+ none of it. The idea, and the calls to the V2 client, follow
129
+ [brendonovich/vite-plugin-opencode](https://github.com/Brendonovich/vite-plugin-opencode) (MIT, Brendan Allan), which marks the
130
+ markup with Babel and so needs no table; here the table is the context.
66
131
 
67
132
  ## Layout
68
133
 
@@ -98,6 +163,7 @@ the calls to the V2 client. No code is copied. The overlay is built with [Solid]
98
163
  bun run test # test/core.mjs (the cascade on happy-dom: hover vs media, @container, @supports, @scope,
99
164
  # an unlayered rule, frame's kernel, within(), grouping), test/build.mjs (nothing in a build
100
165
  # without the option; with "build": the table, the lazy chunk, the loader's size; apps/docs/test/browser.mjs opens it in Chrome),
101
- # test/opencode.mjs (the dev server and a fake OpenCode service: the prompt as sent, the agent, the directory, the status, no service)
102
- bun run test:browsers # builds dist/overlay.js, then the demo in Chrome, Firefox and WebKit (test/browsers.mjs; each dock: the panel on its side, a pick beside it, a drag of the grip, the button after Esc, the dock and sizes after a reload; detach: the pop-up with the panel, a pick in the page followed live, the choice after a reload, closing re-docks, a blocked pop-up), then the prompt box in Chrome (test/ask-browser.mjs)
166
+ # test/opencode.mjs (the dev server and a fake OpenCode service: the prompt as sent, the agent, the directory, the status, no service; the link probe, with and without the service and the client; an attached session, a detached one, two dev servers, a session that is gone, stale files),
167
+ # test/opencode-plugin.mjs (the command on a fake plugin context: none, one, several, a pick, off, a stale pid)
168
+ bun run test:browsers # builds dist/overlay.js, then the demo in Chrome, Firefox and WebKit (test/browsers.mjs; each dock: the panel on its side, a pick beside it, a drag of the grip, the button after Esc, the dock and sizes after a reload; detach: the pop-up with the panel, a pick in the page followed live, the choice after a reload, closing re-docks, a blocked pop-up), then the OpenCode box in Chrome (test/ask-browser.mjs: with nothing picked, pinned in each dock and in the window, the connect text, a service started later found on focus, the attached session and its title; screenshots in test/out/)
103
169
  ```
@@ -0,0 +1,30 @@
1
+ import { attach as e, gitRoot as t, servers as n, sessionOf as r } from "cssints/devtools-link";
2
+ //#region src/opencode.ts
3
+ var i = "cssints-devtools", a = (e, t) => t.map((t) => {
4
+ let n = r(e, t.id);
5
+ return `- ${t.id} ${t.url} ${t.root}${n ? ` (session ${n})` : ""}`;
6
+ }).join("\n"), o = (t, o, s) => {
7
+ let c = n(t), [l = "", ...u] = s.trim().split(/\s+/), d = l === "off" ? u.join(" ") : l, f = d ? c.filter((e) => e.id.includes(d)) : c, p = f.filter((e) => e.id === d), m = p.length ? p : f;
8
+ if (l === "off") {
9
+ let n = m.filter((e) => d ? !0 : r(t, e.id) === o);
10
+ return n.forEach((n) => e(t, n.id)), n.length ? `Detached from ${n.map((e) => e.id).join(", ")}: its devtools panel starts a new session per prompt again.` : d ? `No running dev server matches "${d}".\n${a(t, c)}` : "This session is not attached to any dev server.";
11
+ }
12
+ if (!c.length) return `No cssints dev server with \`devtools: true, opencode: true\` runs in ${t}. Start one, then run /${i} again.`;
13
+ let [h, g] = m;
14
+ return h ? g ? `${m.length} dev servers run${d ? ` that match "${d}"` : ""}; none is attached. Run /${i} <id> to pick one:\n${a(t, m)}` : (e(t, h.id, o), `Attached this session (${o}) to the dev server ${h.id} (${h.url}, ${h.root}). The prompts of its devtools panel now go to this session. /${i} off detaches.`) : `No running dev server matches "${d}". Running:\n${a(t, c)}`;
15
+ }, s = {
16
+ id: "cssints.devtools",
17
+ setup(e) {
18
+ let n = t(e.location.directory);
19
+ return e.command.transform((t) => t.add({
20
+ name: i,
21
+ description: "Attach this session to the devtools of a cssints dev server (off detaches)",
22
+ execute: ({ sessionID: t, prompt: r }) => e.session.synthetic({
23
+ sessionID: t,
24
+ text: `${o(n, t, r.text)}\n\n(A notice from the /${i} command: acknowledge it in one short sentence and run no tools.)`
25
+ }).then(() => void 0)
26
+ })).then((e) => () => e.dispose());
27
+ }
28
+ };
29
+ //#endregion
30
+ export { i as COMMAND, s as default, o as run };