@hachej/boring-workspace 0.1.31 → 0.1.33

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.
@@ -10,8 +10,8 @@ architecture, see the repo-level
10
10
  Use the workspace-local CLI from inside the agent/runtime workspace:
11
11
 
12
12
  ```bash
13
- boring-ui scaffold-plugin <name>
14
- boring-ui verify-plugin <name>
13
+ boring-ui-plugin scaffold <name>
14
+ boring-ui-plugin verify <name>
15
15
  ```
16
16
 
17
17
  Default shape:
@@ -29,8 +29,9 @@ backend registration.
29
29
 
30
30
  ## App/internal publishable package plugin
31
31
 
32
- Use [`packages/cli/templates/plugin`](../../../packages/cli/templates/plugin/) as the reference
33
- shape when building a trusted package composed by an app shell:
32
+ Run `boring-ui-plugin create <name> --path plugins` for the trusted package
33
+ shape composed by an app shell. The command uses
34
+ [`packages/plugin-cli/templates/plugin`](../../../packages/plugin-cli/templates/plugin/) as its reference:
34
35
 
35
36
  ```txt
36
37
  plugins/<name>/
@@ -27,7 +27,7 @@ For future generated/hosted runtime-plugin architecture, see the repo-level
27
27
  | Term | Definition |
28
28
  | --- | --- |
29
29
  | **App/internal plugin** | Trusted package composed by the app at boot. May export `boring.server`, Fastify routes, agent tools, providers, catalogs, and domain APIs. Server changes require restart/redeploy. |
30
- | **Runtime/generated plugin** | Workspace-local plugin under `.pi/extensions/<id>/`, usually produced by `boring-ui scaffold-plugin`. It is hot-loaded for front/Pi resources, but must not rely on dynamic backend routes. |
30
+ | **Runtime/generated plugin** | Workspace-local plugin under `.pi/extensions/<id>/`, usually produced by `boring-ui-plugin scaffold`. It is hot-loaded for front/Pi resources, but must not rely on dynamic backend routes. |
31
31
  | **Boring plugin package** | Node package with `package.json#boring` and/or `package.json#pi`. App-default packages are declared in `package.json#boring.defaultPluginPackages` or passed to `createWorkspaceAgentServer`. |
32
32
  | **Boring front factory** | Default export of `boring.front`: `(api: BoringFrontAPI) => void | Promise<void>`. Usually created with `definePlugin({ ... })`. |
33
33
  | **Workspace server plugin** | Trusted boot-time server contribution returned by `defineServerPlugin({ ... })` or a compatible object. May include routes, tools, system prompt, Pi resources, and provisioning. |
@@ -57,8 +57,8 @@ For future generated/hosted runtime-plugin architecture, see the repo-level
57
57
  1. Agent/user runs the workspace-local CLI:
58
58
 
59
59
  ```bash
60
- boring-ui scaffold-plugin <name>
61
- boring-ui verify-plugin <name>
60
+ boring-ui-plugin scaffold <name>
61
+ boring-ui-plugin verify <name>
62
62
  ```
63
63
 
64
64
  2. The plugin lives under `.pi/extensions/<name>/`.
@@ -234,11 +234,11 @@ write/read `.error` state, and keep their previous live UI where possible.
234
234
  Generated plugin authoring uses the provisioned workspace-local CLI:
235
235
 
236
236
  ```bash
237
- boring-ui scaffold-plugin <name>
238
- boring-ui verify-plugin <name>
237
+ boring-ui-plugin scaffold <name>
238
+ boring-ui-plugin verify <name>
239
239
  ```
240
240
 
241
- Do not teach agents to copy `packages/cli/templates/plugin` for generated runtime
241
+ Do not teach agents to copy `packages/plugin-cli/templates/plugin` for generated runtime
242
242
  plugins. That template is an app/internal publishable package example.
243
243
 
244
244
  ### 4.7 `pluginHotReload`
@@ -10,7 +10,7 @@ fork of the manifest.
10
10
 
11
11
  ### Plugin authoring — already unified
12
12
 
13
- `packages/cli/templates/plugin/` codifies one shape, locked in by PR #40
13
+ `packages/plugin-cli/templates/plugin/` codifies one shape, locked in by PR #40
14
14
  (`refactor/plugin-template`) and the `/boring-plugin-build` skill:
15
15
 
16
16
  ```
@@ -356,7 +356,7 @@ The `/boring-plugin-build` skill needs three additions:
356
356
  extension path (`src/agent/index.ts` + `pi.extensions` manifest field)
357
357
  for tools that want full hot reload.
358
358
 
359
- The template (`packages/cli/templates/plugin/`) stays as-is for L0/L1; an optional
359
+ The template (`packages/plugin-cli/templates/plugin/`) stays as-is for L0/L1; an optional
360
360
  `agent/index.ts` example can be added later when L2 migration of any
361
361
  shipped plugin proves the pattern.
362
362
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-workspace",
3
- "version": "0.1.31",
3
+ "version": "0.1.33",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Workspace UI, plugin, and bridge package for composing chat, files, catalogs, editors, and app-specific panes.",
@@ -130,8 +130,8 @@
130
130
  "tailwind-merge": "^2.0.0",
131
131
  "zod": "^3.23.0",
132
132
  "zustand": "^5.0.0",
133
- "@hachej/boring-agent": "0.1.31",
134
- "@hachej/boring-ui-kit": "0.1.31"
133
+ "@hachej/boring-agent": "0.1.33",
134
+ "@hachej/boring-ui-kit": "0.1.33"
135
135
  },
136
136
  "devDependencies": {
137
137
  "@tailwindcss/postcss": "^4.0.0",
@@ -1,266 +0,0 @@
1
- import { jsx as u, jsxs as C } from "react/jsx-runtime";
2
- import { useRef as I, useEffect as y, useMemo as A, useCallback as k, createContext as _, useContext as z } from "react";
3
- import { Tree as K } from "react-arborist";
4
- import { FolderOpenIcon as S, FolderIcon as J, ChevronRightIcon as Q, Loader2Icon as U } from "lucide-react";
5
- import { K as X } from "./WorkspaceProvider-0V-2x7AH.js";
6
- import { Input as Y } from "@hachej/boring-ui-kit";
7
- import { c as x } from "./utils-B6yFEsav.js";
8
- import { createDragDropManager as Z } from "dnd-core";
9
- import { HTML5Backend as $ } from "react-dnd-html5-backend";
10
- const F = Symbol.for("@hachej/boring-workspace/file-tree-dnd-manager");
11
- function E() {
12
- const r = globalThis;
13
- return r[F] ?? (r[F] = Z(
14
- $,
15
- typeof window > "u" ? void 0 : window
16
- )), r[F];
17
- }
18
- const M = /* @__PURE__ */ new Set(), P = _({
19
- onContextMenu: void 0,
20
- editing: null,
21
- pendingPaths: M,
22
- onSubmitEdit: void 0,
23
- onCancelEdit: void 0
24
- });
25
- function G({
26
- initialValue: r,
27
- onSubmit: p,
28
- onCancel: h,
29
- isDraft: f
30
- }) {
31
- const t = I(null), i = I(!1);
32
- y(() => {
33
- const e = t.current;
34
- if (e)
35
- if (e.focus(), !f && r.includes(".")) {
36
- const o = r.lastIndexOf(".");
37
- e.setSelectionRange(0, o);
38
- } else
39
- e.select();
40
- }, [r, f]);
41
- const d = () => {
42
- var o;
43
- if (i.current) return;
44
- i.current = !0;
45
- const e = ((o = t.current) == null ? void 0 : o.value.trim()) ?? "";
46
- !e || e === r ? h() : p(e);
47
- };
48
- return /* @__PURE__ */ u(
49
- Y,
50
- {
51
- ref: t,
52
- type: "text",
53
- defaultValue: r,
54
- "data-testid": "file-tree-edit-input",
55
- "aria-label": f ? "Name" : "Rename",
56
- onPointerDown: (e) => e.stopPropagation(),
57
- onClick: (e) => e.stopPropagation(),
58
- onKeyDown: (e) => {
59
- e.stopPropagation(), e.key === "Enter" ? (e.preventDefault(), d()) : e.key === "Escape" && (e.preventDefault(), i.current = !0, h());
60
- },
61
- onBlur: d,
62
- className: "h-5 min-w-0 flex-1 rounded-sm border-[color:var(--accent)]/60 px-1 text-[13px] leading-[1.2] focus-visible:ring-[color:var(--accent)]"
63
- }
64
- );
65
- }
66
- function H({ node: r, style: p, dragHandle: h }) {
67
- const { onContextMenu: f, editing: t, pendingPaths: i, onSubmitEdit: d, onCancelEdit: e } = z(P), o = r.data, m = o.kind === "dir", l = (t == null ? void 0 : t.path) === o.path, b = i.has(o.path), w = m ? r.isOpen ? S : J : X(o.name || "untitled");
68
- return /* @__PURE__ */ C(
69
- "div",
70
- {
71
- ref: h,
72
- style: p,
73
- className: x(
74
- "group relative mx-1 flex items-center gap-1.5 rounded-md px-2 py-0.5 text-[13px] leading-[1.4] cursor-pointer select-none text-foreground",
75
- "transition-colors duration-150 ease-[cubic-bezier(0.22,1,0.36,1)]",
76
- !l && "hover:bg-foreground/[0.04]",
77
- r.isSelected && !l && "bg-[oklch(from_var(--accent)_l_c_h/0.10)] text-foreground font-medium",
78
- r.willReceiveDrop && "bg-foreground/5 outline outline-1 outline-border"
79
- ),
80
- onClick: (s) => {
81
- l || (s.stopPropagation(), m ? r.toggle() : (r.select(), r.activate()));
82
- },
83
- onContextMenu: (s) => {
84
- l || o.isDraft || (s.preventDefault(), s.stopPropagation(), f == null || f(s, o));
85
- },
86
- children: [
87
- m ? /* @__PURE__ */ u(
88
- Q,
89
- {
90
- className: x(
91
- "h-3 w-3 shrink-0 text-muted-foreground/70 transition-transform duration-150 ease-[cubic-bezier(0.22,1,0.36,1)]",
92
- r.isOpen && "rotate-90"
93
- ),
94
- strokeWidth: 2
95
- }
96
- ) : /* @__PURE__ */ u("span", { className: "w-3 shrink-0" }),
97
- /* @__PURE__ */ u(
98
- w,
99
- {
100
- className: x(
101
- "h-4 w-4 shrink-0",
102
- r.isSelected ? "text-[color:var(--accent)]" : "text-muted-foreground/80"
103
- ),
104
- strokeWidth: 1.5
105
- }
106
- ),
107
- l ? /* @__PURE__ */ u(
108
- G,
109
- {
110
- initialValue: (t == null ? void 0 : t.initialValue) ?? o.name ?? "",
111
- isDraft: !!(t != null && t.isDraft),
112
- onSubmit: (s) => d == null ? void 0 : d(o.path, s),
113
- onCancel: () => e == null ? void 0 : e()
114
- }
115
- ) : /* @__PURE__ */ u(
116
- "span",
117
- {
118
- className: x(
119
- "truncate",
120
- b && "text-muted-foreground italic"
121
- ),
122
- children: o.name
123
- }
124
- ),
125
- b && !l && /* @__PURE__ */ u(
126
- U,
127
- {
128
- "data-testid": "file-tree-pending-spinner",
129
- "aria-label": "Pending",
130
- className: "ml-auto h-3 w-3 shrink-0 animate-spin text-muted-foreground/70",
131
- strokeWidth: 2
132
- }
133
- )
134
- ]
135
- }
136
- );
137
- }
138
- function ce({
139
- files: r,
140
- selectedPath: p,
141
- searchQuery: h,
142
- height: f = 400,
143
- editing: t,
144
- revealPath: i,
145
- pendingPaths: d,
146
- onSelect: e,
147
- onExpand: o,
148
- onCollapse: m,
149
- onContextMenu: l,
150
- onSubmitEdit: b,
151
- onCancelEdit: w,
152
- onRevealHandled: s,
153
- onDragDrop: T,
154
- className: D
155
- }) {
156
- const v = I(null);
157
- y(() => {
158
- if (!(t != null && t.isDraft)) return;
159
- const n = requestAnimationFrame(() => {
160
- var a;
161
- (a = v.current) == null || a.scrollTo(t.path);
162
- });
163
- return () => cancelAnimationFrame(n);
164
- }, [t == null ? void 0 : t.isDraft, t == null ? void 0 : t.path]), y(() => {
165
- if (!i) return;
166
- let n = 0;
167
- const a = requestAnimationFrame(() => {
168
- const c = v.current;
169
- if (!c) return;
170
- c.openParents(i);
171
- const N = c.get(i);
172
- N && (N.isInternal && N.open(), n = requestAnimationFrame(() => {
173
- var g;
174
- (g = v.current) == null || g.scrollTo(i), s == null || s(i);
175
- }));
176
- });
177
- return () => {
178
- cancelAnimationFrame(a), cancelAnimationFrame(n);
179
- };
180
- }, [r, s, i]);
181
- const O = A(
182
- () => p || void 0,
183
- [p]
184
- ), R = k(
185
- (n) => {
186
- n.data.kind === "file" && (e == null || e(n.data.path));
187
- },
188
- [e]
189
- ), W = k(
190
- (n) => {
191
- var c;
192
- const a = (c = v.current) == null ? void 0 : c.get(n);
193
- a && (a.isOpen ? o == null || o(a.data.path) : m == null || m(a.data.path));
194
- },
195
- [o, m]
196
- ), j = k(
197
- (n) => {
198
- if (!T) return;
199
- const a = !n.parentNode || n.parentNode.isRoot, c = a ? "." : n.parentNode.data.path;
200
- if (!(!a && n.parentNode.data.kind !== "dir"))
201
- for (const N of n.dragNodes) {
202
- const g = N.data.path;
203
- if (c === g || c !== "." && c.startsWith(g + "/")) return;
204
- T(g, c);
205
- }
206
- },
207
- [T]
208
- ), L = k(
209
- (n) => {
210
- if (!n.parentNode || n.parentNode.isRoot) return !1;
211
- if (n.parentNode.data.kind !== "dir") return !0;
212
- for (const a of n.dragNodes)
213
- if (n.parentNode.data.path === a.data.path || n.parentNode.data.path.startsWith(a.data.path + "/")) return !0;
214
- return !1;
215
- },
216
- []
217
- ), q = k(
218
- (n, a) => n.data.name.toLowerCase().includes(a.toLowerCase()),
219
- []
220
- ), B = A(
221
- () => ({
222
- onContextMenu: l,
223
- editing: t ?? null,
224
- pendingPaths: d ?? M,
225
- onSubmitEdit: b,
226
- onCancelEdit: w
227
- }),
228
- [l, t, d, b, w]
229
- );
230
- return r.length === 0 ? /* @__PURE__ */ u(
231
- "div",
232
- {
233
- className: x(
234
- "flex h-full items-center justify-center text-sm text-muted-foreground",
235
- D
236
- ),
237
- children: "No files"
238
- }
239
- ) : /* @__PURE__ */ u(P.Provider, { value: B, children: /* @__PURE__ */ u("div", { "data-boring-workspace-part": "file-tree", className: x("file-tree", D), children: /* @__PURE__ */ u(
240
- K,
241
- {
242
- ref: v,
243
- data: r,
244
- idAccessor: "path",
245
- childrenAccessor: "children",
246
- openByDefault: !1,
247
- width: "100%",
248
- height: f,
249
- rowHeight: 26,
250
- indent: 14,
251
- selection: O,
252
- searchTerm: h ?? "",
253
- searchMatch: q,
254
- onActivate: R,
255
- onToggle: W,
256
- onMove: j,
257
- disableDrop: L,
258
- disableEdit: !0,
259
- dndManager: E(),
260
- children: H
261
- }
262
- ) }) });
263
- }
264
- export {
265
- ce as FileTree
266
- };