@hachej/boring-workspace 0.1.54 → 0.1.56

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.
@@ -282,6 +282,63 @@ parses `/name args` only.
282
282
  `package.json#pi` block — Pi-sourced commands appear automatically. No
283
283
  harness changes required.
284
284
 
285
+ ### 4.8 Generic session attention badges
286
+
287
+ `WorkspaceAttention` is the generic way for plugins to say “this chat session
288
+ needs attention”. The workspace owns only the display and routing mechanics;
289
+ plugins own the domain semantics, surface UI, and bridge/API operations.
290
+
291
+ A plugin should use its own `reason` namespace and may attach a `sessionBadge`
292
+ for the session list:
293
+
294
+ ```ts
295
+ const { addBlocker, removeBlocker } = useWorkspaceAttention()
296
+
297
+ addBlocker({
298
+ id: `pr-review:${sessionId}:123`,
299
+ reason: "pr-review.review",
300
+ sessionId,
301
+ surfaceKind: "pr-review",
302
+ target: "review-123",
303
+ label: "Review PR #123 to continue",
304
+ sessionBadge: {
305
+ kind: "review",
306
+ label: "review",
307
+ tone: "warning",
308
+ priority: 20,
309
+ },
310
+ actions: [{ id: "open", label: "Open review" }],
311
+ })
312
+ ```
313
+
314
+ `sessionBadge.kind` is stable metadata for tests/styling
315
+ (`data-boring-badge="review"`). `label` is the short text rendered in the row.
316
+ `tone` is visual only; plugin code should not infer behavior from it. If several
317
+ plugins mark one session, the highest `priority` badge wins.
318
+
319
+ Composer blocker actions are plugin-defined. Workspace provides a convenience
320
+ for `id: "open"` when `surfaceKind` is present, and emits
321
+ `WORKSPACE_ATTENTION_ACTION_EVENT` for every action with `{ blockerId, actionId,
322
+ sessionId, blocker }`. The owning plugin should listen for its domain-specific
323
+ actions such as `approve`, `request-changes`, or `cancel`; workspace does not
324
+ assign semantics to those action ids.
325
+
326
+ Ask-user consumes this as an ask-user-specific attention type:
327
+
328
+ ```ts
329
+ reason: "ask-user.question"
330
+ sessionBadge: { kind: "question", label: "question", tone: "attention" }
331
+ ```
332
+
333
+ Other plugins should not reuse ask-user’s reason or badge kind unless they are
334
+ actually delegating to ask-user. For example, a PR review plugin should use
335
+ `reason: "pr-review.review"` and `kind: "review"` even if both are ultimately
336
+ “human input”.
337
+
338
+ Compatibility: old blockers with `reason: "waiting_for_user_input"` still render
339
+ a legacy `needs input` badge, but new plugins should provide `sessionBadge`
340
+ explicitly.
341
+
285
342
  ---
286
343
 
287
344
  ## 5. Key algorithms
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hachej/boring-workspace",
3
- "version": "0.1.54",
3
+ "version": "0.1.56",
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.",
@@ -34,6 +34,10 @@
34
34
  "types": "./dist/shared.d.ts",
35
35
  "import": "./dist/shared.js"
36
36
  },
37
+ "./bridge-client": {
38
+ "types": "./dist/bridge-client.d.ts",
39
+ "import": "./dist/bridge-client.js"
40
+ },
37
41
  "./app/front": {
38
42
  "types": "./dist/app-front.d.ts",
39
43
  "import": "./dist/app-front.js",
@@ -135,9 +139,9 @@
135
139
  "tailwind-merge": "^2.0.0",
136
140
  "zod": "^3.23.0",
137
141
  "zustand": "^5.0.0",
138
- "@hachej/boring-ui-kit": "0.1.54",
139
- "@hachej/boring-ui-plugin-cli": "0.1.54",
140
- "@hachej/boring-agent": "0.1.54"
142
+ "@hachej/boring-agent": "0.1.56",
143
+ "@hachej/boring-ui-kit": "0.1.56",
144
+ "@hachej/boring-ui-plugin-cli": "0.1.56"
141
145
  },
142
146
  "devDependencies": {
143
147
  "@tailwindcss/postcss": "^4.0.0",
@@ -1,198 +0,0 @@
1
- import { B as BoringPackageBoringField, a as BoringPackagePiField } from './manifest-C2vVgH_e.js';
2
- import { PiPackageSource, PluginSkillSource, ProvisionWorkspaceRuntimeOptions } from '@hachej/boring-agent/server';
3
- import { FastifyPluginAsync } from 'fastify';
4
- import { A as AgentTool } from './agent-tool-CB0RQyx9.js';
5
- import { U as UiBridge } from './ui-bridge-LeBuZqfA.js';
6
-
7
- type BoringPluginNativeFrontTargetTrust$1 = "local-trusted-native";
8
- /**
9
- * Host-owned runtime import target for a plugin front entry.
10
- *
11
- * Only the trusted native/browser-module case exists today. Future
12
- * target kinds (iframe/artifact/...) can extend the union without
13
- * rewriting list/event payload shapes.
14
- */
15
- interface BoringPluginNativeFrontTarget$1 {
16
- kind: "native";
17
- entryUrl: string;
18
- revision: number;
19
- trust: BoringPluginNativeFrontTargetTrust$1;
20
- }
21
- /**
22
- * Plugin front served as a plain browser module URL — the Vite-dev transport
23
- * (`/@fs/...`). Hosts running a Vite dev server let Vite transform the entry;
24
- * the CLI's runtime host mints `native` targets instead.
25
- */
26
- interface BoringPluginModuleUrlFrontTarget {
27
- kind: "module-url";
28
- entryUrl: string;
29
- revision: number;
30
- }
31
- type BoringPluginFrontTarget$1 = BoringPluginNativeFrontTarget$1 | BoringPluginModuleUrlFrontTarget;
32
- type BoringPluginEvent$1 = {
33
- type: "boring.plugin.load";
34
- id: string;
35
- boring: BoringPackageBoringField;
36
- version: string;
37
- revision: number;
38
- frontTarget?: BoringPluginFrontTarget$1;
39
- } | {
40
- type: "boring.plugin.unload";
41
- id: string;
42
- revision: number;
43
- } | {
44
- type: "boring.plugin.error";
45
- id: string;
46
- revision: number;
47
- message: string;
48
- };
49
- interface BoringPluginListEntry$1 {
50
- id: string;
51
- boring: BoringPackageBoringField;
52
- pi?: BoringPackagePiField;
53
- version: string;
54
- revision: number;
55
- frontTarget?: BoringPluginFrontTarget$1;
56
- }
57
-
58
- type BoringPluginSourceKind = "internal" | "external";
59
- interface BoringPluginSource {
60
- rootDir: string;
61
- kind: BoringPluginSourceKind;
62
- workspaceId?: string;
63
- /**
64
- * True when the user explicitly registered this directory as a plugin
65
- * source (e.g. a `packages` entry in Pi settings.json). Registered
66
- * sources that are missing, lack a package.json, or carry no plugin
67
- * metadata surface as preflight errors instead of being silently
68
- * skipped the way speculative scan roots are.
69
- */
70
- registered?: boolean;
71
- }
72
- type BoringPluginSourceInput = string | BoringPluginSource;
73
- interface BoringServerPluginManifest {
74
- id: string;
75
- rootDir: string;
76
- version: string;
77
- boring: BoringPackageBoringField;
78
- /** True when package.json explicitly declares a boring manifest. Pi-only packages remain valid Pi resources but are not listed as Boring plugins. */
79
- hasBoring: boolean;
80
- pi?: BoringPackagePiField;
81
- frontPath?: string;
82
- /** Legacy Vite-dev browser import fallback (`/@fs/...`). */
83
- frontUrl?: string;
84
- serverPath?: string;
85
- extensionPaths?: string[];
86
- skillPaths?: string[];
87
- source: BoringPluginSource;
88
- }
89
- type BoringPluginNativeFrontTargetTrust = BoringPluginNativeFrontTargetTrust$1;
90
- type BoringPluginNativeFrontTarget = BoringPluginNativeFrontTarget$1;
91
- type BoringPluginFrontTarget = BoringPluginFrontTarget$1;
92
- type BoringPluginListEntry = BoringPluginListEntry$1;
93
- interface BoringPluginFrontTargetResolverContext {
94
- revision: number;
95
- /** Plugin-root-relative front entry path normalized for URL-like consumers. */
96
- frontEntrySubpath: string;
97
- }
98
- type BoringPluginFrontTargetResolver = (plugin: BoringServerPluginManifest, context: BoringPluginFrontTargetResolverContext) => BoringPluginFrontTarget | undefined;
99
- /**
100
- * Surfaces whose changes the hot-reload pipeline can't re-load mid-
101
- * session — set when a plugin's load DID succeed but a sub-surface
102
- * (the agent-tools registry, Fastify routes) carries stale code from
103
- * the previous revision. The /reload caller (chat UI, verify-plugin,
104
- * etc.) should surface a "restart needed for X" warning.
105
- *
106
- * - `'routes'`: a `WorkspaceServerPlugin.routes` function changed. The
107
- * workspace's Fastify instance can't unregister + re-register routes
108
- * mid-flight; the previous routes stay live until next boot.
109
- * - `'agentTools'`: a `WorkspaceServerPlugin.agentTools` array changed.
110
- * The current Pi session still has the old tool list; new sessions
111
- * get the new list.
112
- * - Multiple surfaces: order is deterministic (`routes` before
113
- * `agentTools`) so subscribers can format consistently.
114
- */
115
- type PluginRestartSurface = "routes" | "agentTools";
116
- type BoringPluginEvent = (Extract<BoringPluginEvent$1, {
117
- type: "boring.plugin.load";
118
- }> & {
119
- /**
120
- * Non-empty when the plugin loaded but one or more server-side
121
- * surfaces still hold pre-load code. UI consumers should render
122
- * a "restart needed: <surfaces>" hint. Empty/omitted = fully
123
- * live.
124
- */
125
- requiresRestart?: PluginRestartSurface[];
126
- }) | Extract<BoringPluginEvent$1, {
127
- type: "boring.plugin.unload";
128
- }> | Extract<BoringPluginEvent$1, {
129
- type: "boring.plugin.error";
130
- }>;
131
-
132
- type WorkspaceRuntimeProvisioning = NonNullable<ProvisionWorkspaceRuntimeOptions["plugins"][number]["provisioning"]>;
133
- interface WorkspaceServerPluginAsset {
134
- /** Stable asset name within this plugin, e.g. "sdk" or "workspace-template". */
135
- name: string;
136
- /** Source directory or file owned by the plugin. Relative strings are resolved by the app integration. */
137
- source: string | URL;
138
- /** Optional runtime target path within this plugin's asset namespace. Defaults to name. */
139
- target?: string;
140
- }
141
- interface WorkspaceServerPlugin {
142
- id: string;
143
- label?: string;
144
- /**
145
- * Native Pi package sources required by this workspace integration.
146
- * Workspace declares them; @hachej/boring-agent applies them through Pi's native
147
- * resource loader without asking Pi packages to export Boring adapters.
148
- */
149
- piPackages?: PiPackageSource[];
150
- /**
151
- * Native pi extension entrypoints contributed by this plugin.
152
- * Passed to DefaultResourceLoader.additionalExtensionPaths so pi owns jiti
153
- * loading and ctx.reload() re-imports fresh source.
154
- */
155
- extensionPaths?: string[];
156
- systemPrompt?: string;
157
- skills?: PluginSkillSource[];
158
- agentTools?: AgentTool[];
159
- provisioning?: WorkspaceRuntimeProvisioning;
160
- /** Static filesystem assets this plugin needs in production/serverless bundles. */
161
- assets?: WorkspaceServerPluginAsset[];
162
- routes?: FastifyPluginAsync;
163
- /** UI state keys owned by this plugin that browser state PUTs must not overwrite. */
164
- preservedUiStateKeys?: string[];
165
- }
166
- declare function validateServerPlugin(plugin: WorkspaceServerPlugin): void;
167
- declare function defineServerPlugin<T extends WorkspaceServerPlugin>(plugin: T): T;
168
-
169
- interface ServerBootstrapOptions {
170
- plugins?: WorkspaceServerPlugin[];
171
- defaults?: WorkspaceServerPlugin[];
172
- excludeDefaults?: string[];
173
- }
174
- type WorkspaceRuntimeProvisioningInput = ProvisionWorkspaceRuntimeOptions["plugins"][number];
175
- type WorkspaceProvisioningContribution = {
176
- id: string;
177
- provisioning: NonNullable<WorkspaceRuntimeProvisioningInput["provisioning"]>;
178
- };
179
- type WorkspaceRouteContribution = {
180
- id: string;
181
- routes: FastifyPluginAsync;
182
- };
183
- interface ServerBootstrapResult {
184
- registered: string[];
185
- systemPromptAppend: string;
186
- piPackages: PiPackageSource[];
187
- extensionPaths: string[];
188
- agentTools: AgentTool[];
189
- runtimePlugins: WorkspaceRuntimeProvisioningInput[];
190
- provisioningContributions: WorkspaceProvisioningContribution[];
191
- routeContributions: WorkspaceRouteContribution[];
192
- preservedUiStateKeys: string[];
193
- }
194
- declare function bootstrapServer(options: ServerBootstrapOptions): ServerBootstrapResult;
195
-
196
- declare function createInMemoryBridge(): UiBridge;
197
-
198
- export { type BoringPluginSourceInput as B, type PluginRestartSurface as P, type ServerBootstrapOptions as S, type WorkspaceServerPlugin as W, type BoringPluginFrontTargetResolver as a, type WorkspaceProvisioningContribution as b, type WorkspaceRouteContribution as c, createInMemoryBridge as d, type WorkspaceRuntimeProvisioningInput as e, type WorkspaceServerPluginAsset as f, type BoringServerPluginManifest as g, type BoringPluginListEntry as h, type BoringPluginFrontTarget as i, type BoringPluginSource as j, type BoringPluginEvent as k, type BoringPluginFrontTargetResolverContext as l, type BoringPluginNativeFrontTarget as m, type BoringPluginNativeFrontTargetTrust as n, type BoringPluginSourceKind as o, type ServerBootstrapResult as p, bootstrapServer as q, defineServerPlugin as r, validateServerPlugin as v };