@hachej/boring-workspace 0.1.41 → 0.1.43
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 +26 -261
- package/dist/{FileTree-CdvCFi6P.js → FileTree-CVsvICGP.js} +1 -1
- package/dist/{MarkdownEditor-D6W7J3qC.js → MarkdownEditor-BvaGmzWP.js} +1 -1
- package/dist/{WorkspaceLoadingState-BdtTzpsu.js → WorkspaceLoadingState-yp4vNmrT.js} +1 -1
- package/dist/{WorkspaceProvider-B6P8ANTL.js → WorkspaceProvider-DkZAxsYo.js} +2896 -2791
- package/dist/app-front.d.ts +8 -1
- package/dist/app-front.js +486 -478
- package/dist/app-server.d.ts +16 -5
- package/dist/app-server.js +26 -16
- package/dist/server.js +6 -6
- package/dist/testing.js +1 -1
- package/dist/workspace.js +5 -5
- package/docs/INTERFACES.md +1 -1
- package/docs/PLUGIN_STRUCTURE.md +3 -3
- package/docs/PLUGIN_SYSTEM.md +46 -4
- package/docs/README.md +85 -22
- package/package.json +4 -4
- /package/docs/plans/{ASK_USER_QUESTIONS_PLUGIN_SPEC.md → archive/ASK_USER_QUESTIONS_PLUGIN_SPEC.md} +0 -0
- /package/docs/plans/{FULL_PAGE_PANEL_ROUTE_SPEC.md → archive/FULL_PAGE_PANEL_ROUTE_SPEC.md} +0 -0
- /package/docs/plans/{GENERIC_EXPLORER_PLUGIN_PLAN.md → archive/GENERIC_EXPLORER_PLUGIN_PLAN.md} +0 -0
- /package/docs/plans/{PANE_TO_AGENT_CHAT_ACTIONS_SPEC.md → archive/PANE_TO_AGENT_CHAT_ACTIONS_SPEC.md} +0 -0
- /package/docs/plans/{PLUGIN_OUTPUTS_ISOLATION_PLAN.md → archive/PLUGIN_OUTPUTS_ISOLATION_PLAN.md} +0 -0
- /package/docs/plans/{README.md → archive/README.md} +0 -0
- /package/docs/plans/{UI_BRIDGE_OWNERSHIP_REFACTOR.md → archive/UI_BRIDGE_OWNERSHIP_REFACTOR.md} +0 -0
package/dist/app-server.d.ts
CHANGED
|
@@ -116,10 +116,11 @@ interface CreateWorkspaceAgentServerOptions extends WorkspaceAgentCreateOptions,
|
|
|
116
116
|
/**
|
|
117
117
|
* Install and advertise the boring plugin-authoring runtime.
|
|
118
118
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
119
|
+
* This option is ignored when `externalPlugins` is false. Keep it off for
|
|
120
|
+
* production/hosted workspaces unless a plugin-editing experience is
|
|
121
|
+
* explicitly enabled. Remote sandboxes can support authoring, but the CLI
|
|
122
|
+
* should be provisioned only for that activated editing mode, not for every
|
|
123
|
+
* normal workspace boot.
|
|
123
124
|
*
|
|
124
125
|
* Defaults to true for local/standalone strong-filesystem runtimes and false
|
|
125
126
|
* for remote/best-effort runtimes. Core/full-app may choose a stricter
|
|
@@ -128,6 +129,14 @@ interface CreateWorkspaceAgentServerOptions extends WorkspaceAgentCreateOptions,
|
|
|
128
129
|
installPluginAuthoring?: boolean;
|
|
129
130
|
/** Optional host-owned front-target override for boring plugin list/event payloads. */
|
|
130
131
|
boringPluginFrontTargetResolver?: BoringPluginFrontTargetResolver;
|
|
132
|
+
/**
|
|
133
|
+
* Single public-mode switch for user/global external plugins. When false,
|
|
134
|
+
* the server disables .pi/~/.pi/Pi-settings discovery, authoring CLI/prompt
|
|
135
|
+
* provisioning, plugin diagnostics, and external hot-reload resources. App/
|
|
136
|
+
* internal plugins from explicit `plugins`, `defaultPluginPackages`, and
|
|
137
|
+
* `additionalBoringPluginDirs` continue to work.
|
|
138
|
+
*/
|
|
139
|
+
externalPlugins?: boolean;
|
|
131
140
|
}
|
|
132
141
|
declare const PLUGIN_AUTHORING_PROVISIONING_IDS: Set<string>;
|
|
133
142
|
declare function omitPluginAuthoringProvisioning(plugins: WorkspaceRuntimeProvisioningInput[]): WorkspaceRuntimeProvisioningInput[];
|
|
@@ -145,7 +154,9 @@ interface CollectWorkspaceAgentServerPluginsOptions extends Pick<ServerBootstrap
|
|
|
145
154
|
/** Whether to include built-in boring plugin-authoring provisioning/prompt resources. */
|
|
146
155
|
installPluginAuthoring?: boolean;
|
|
147
156
|
}
|
|
148
|
-
declare function buildWorkspaceContextPrompt(
|
|
157
|
+
declare function buildWorkspaceContextPrompt(options?: {
|
|
158
|
+
pluginAuthoringEnabled?: boolean;
|
|
159
|
+
}): string;
|
|
149
160
|
declare function collectWorkspaceAgentServerPlugins(opts?: CollectWorkspaceAgentServerPluginsOptions): WorkspaceAgentServerPluginCollection;
|
|
150
161
|
declare function provisionWorkspaceAgentServer(opts: {
|
|
151
162
|
workspaceRoot: string;
|
package/dist/app-server.js
CHANGED
|
@@ -1070,7 +1070,7 @@ var BoringPluginAssetManager = class {
|
|
|
1070
1070
|
additionalSkillPaths: [...new Set(plugins.flatMap((plugin) => plugin.skillPaths ?? []).map(skillPathForPiLoader))],
|
|
1071
1071
|
packages: compactPiPackages(normalizeBoringPluginPiPackages(plugins)),
|
|
1072
1072
|
extensionPaths: plugins.flatMap((plugin) => plugin.extensionPaths ?? []),
|
|
1073
|
-
...prompts.length > 0 ? { systemPromptAppend: `# Loaded
|
|
1073
|
+
...prompts.length > 0 ? { systemPromptAppend: `# Loaded app-provided context
|
|
1074
1074
|
|
|
1075
1075
|
${prompts.join("\n\n")}` } : {}
|
|
1076
1076
|
};
|
|
@@ -1824,7 +1824,7 @@ async function runtimeBackendGateway(app, opts) {
|
|
|
1824
1824
|
function aggregatePluginPrompts(manager) {
|
|
1825
1825
|
const prompts = manager.list().map((plugin) => plugin.pi?.systemPrompt?.trim()).filter((prompt) => Boolean(prompt));
|
|
1826
1826
|
if (prompts.length === 0) return void 0;
|
|
1827
|
-
return `# Loaded
|
|
1827
|
+
return `# Loaded app-provided context
|
|
1828
1828
|
|
|
1829
1829
|
${prompts.join("\n\n")}`;
|
|
1830
1830
|
}
|
|
@@ -2182,14 +2182,14 @@ function createExecUiTool(uiBridge, opts = {}) {
|
|
|
2182
2182
|
" params:{seriesId:'GDPC1'}}}",
|
|
2183
2183
|
"",
|
|
2184
2184
|
" openSurface params: { kind: string, target: string, meta?: object }",
|
|
2185
|
-
" \u2014 Open
|
|
2186
|
-
" surface resolver registry. Use this when
|
|
2185
|
+
" \u2014 Open an app-owned target through the workspace",
|
|
2186
|
+
" surface resolver registry. Use this when the app",
|
|
2187
2187
|
" defines the mapping from domain target to panel",
|
|
2188
2188
|
" component, for example a catalog row.",
|
|
2189
2189
|
" Example: {kind:'openSurface', params:{",
|
|
2190
|
-
" kind:'
|
|
2190
|
+
" kind:'catalog.open-row',",
|
|
2191
2191
|
" target:'orders_daily',",
|
|
2192
|
-
" meta:{catalogId:'
|
|
2192
|
+
" meta:{catalogId:'data-catalog'}}}",
|
|
2193
2193
|
"",
|
|
2194
2194
|
" closePanel params: { id: string }",
|
|
2195
2195
|
" closeWorkbenchLeftPane params: {}",
|
|
@@ -2721,13 +2721,18 @@ function resolveBoringPiSkillPaths(workspaceRoot) {
|
|
|
2721
2721
|
const skillFile = join7(root, "skills", "boring-plugin-authoring", "SKILL.md");
|
|
2722
2722
|
return existsSync7(skillFile) ? [skillFile] : [];
|
|
2723
2723
|
}
|
|
2724
|
-
function buildWorkspaceContextPrompt() {
|
|
2724
|
+
function buildWorkspaceContextPrompt(options = {}) {
|
|
2725
2725
|
return [
|
|
2726
2726
|
"## Workspace",
|
|
2727
2727
|
"- Root: `$BORING_AGENT_WORKSPACE_ROOT` (exported into every bash invocation)",
|
|
2728
|
-
"- Generated plugin skills: `$BORING_AGENT_WORKSPACE_ROOT/.boring-agent/skills/` \u2014 readable with normal file tools",
|
|
2729
2728
|
"- User workspace skills: `$BORING_AGENT_WORKSPACE_ROOT/.agents/skills/`",
|
|
2730
|
-
|
|
2729
|
+
...options.pluginAuthoringEnabled ? [
|
|
2730
|
+
"- Generated plugin skills: `$BORING_AGENT_WORKSPACE_ROOT/.boring-agent/skills/` \u2014 readable with normal file tools",
|
|
2731
|
+
"- Runtime CLIs (`boring-ui-plugin`, `bm`, `python`, `pip`, `uv`) come from `.boring-agent/node`, `.boring-agent/venv`, and `.boring-agent/sdk/uv` and are already on PATH"
|
|
2732
|
+
] : [
|
|
2733
|
+
"- Runtime CLIs (`bm`, `python`, `pip`, `uv`) come from `.boring-agent/node`, `.boring-agent/venv`, and `.boring-agent/sdk/uv` when provisioned",
|
|
2734
|
+
"- This public app does not expose Boring plugin creation or installation. If asked about Boring plugins, do not explain how to create/install them; say that this app does not expose that feature and continue with normal workspace tasks."
|
|
2735
|
+
]
|
|
2731
2736
|
].join("\n");
|
|
2732
2737
|
}
|
|
2733
2738
|
function collectWorkspaceAgentServerPlugins(opts = {}) {
|
|
@@ -2821,7 +2826,7 @@ function readPiSettingsBoringPluginSources(settingsPath, workspaceId) {
|
|
|
2821
2826
|
}))
|
|
2822
2827
|
);
|
|
2823
2828
|
}
|
|
2824
|
-
function collectBoringPluginSources(workspaceRoot, pluginCollection, additionalPluginDirs = []) {
|
|
2829
|
+
function collectBoringPluginSources(workspaceRoot, pluginCollection, additionalPluginDirs = [], externalPluginsEnabled = true) {
|
|
2825
2830
|
const extensionPaths = pluginCollection.agentOptions.pi?.extensionPaths ?? [];
|
|
2826
2831
|
const pluginRoots = extensionPaths.flatMap((path) => {
|
|
2827
2832
|
try {
|
|
@@ -2830,13 +2835,16 @@ function collectBoringPluginSources(workspaceRoot, pluginCollection, additionalP
|
|
|
2830
2835
|
return [];
|
|
2831
2836
|
}
|
|
2832
2837
|
});
|
|
2833
|
-
|
|
2838
|
+
const externalSources = externalPluginsEnabled ? [
|
|
2834
2839
|
{ rootDir: join7(workspaceRoot, ".pi", "extensions"), kind: "external", workspaceId: workspaceRoot },
|
|
2835
2840
|
{ rootDir: join7(workspaceRoot, ".pi", "npm"), kind: "external", workspaceId: workspaceRoot },
|
|
2836
2841
|
{ rootDir: join7(workspaceRoot, ".pi", "git"), kind: "external", workspaceId: workspaceRoot },
|
|
2837
2842
|
{ rootDir: join7(homedir(), ".pi", "agent", "extensions"), kind: "external" },
|
|
2838
2843
|
...readPiSettingsBoringPluginSources(join7(workspaceRoot, ".pi", "settings.json"), workspaceRoot),
|
|
2839
|
-
...readPiSettingsBoringPluginSources(join7(homedir(), ".pi", "agent", "settings.json"))
|
|
2844
|
+
...readPiSettingsBoringPluginSources(join7(homedir(), ".pi", "agent", "settings.json"))
|
|
2845
|
+
] : [];
|
|
2846
|
+
return uniquePluginSources([
|
|
2847
|
+
...externalSources,
|
|
2840
2848
|
...pluginRoots.map((rootDir) => ({ rootDir, kind: "internal" })),
|
|
2841
2849
|
...additionalPluginDirs.map((entry) => typeof entry === "string" ? { rootDir: entry, kind: "internal" } : entry)
|
|
2842
2850
|
]);
|
|
@@ -2886,7 +2894,7 @@ function readWorkspacePluginPackageRuntimePlugins(pluginDirs) {
|
|
|
2886
2894
|
function aggregatePluginSystemPromptsFromScan(scan) {
|
|
2887
2895
|
const prompts = scan.plugins.map((plugin) => plugin.pi?.systemPrompt?.trim()).filter((prompt) => Boolean(prompt));
|
|
2888
2896
|
if (prompts.length === 0) return void 0;
|
|
2889
|
-
return `# Loaded
|
|
2897
|
+
return `# Loaded app-provided context
|
|
2890
2898
|
|
|
2891
2899
|
${prompts.join("\n\n")}`;
|
|
2892
2900
|
}
|
|
@@ -2919,6 +2927,7 @@ async function createWorkspaceAgentServer(opts = {}) {
|
|
|
2919
2927
|
const modeAdapter = opts.runtimeModeAdapter ?? resolveMode(resolvedMode);
|
|
2920
2928
|
const workspaceFsCapability = modeAdapter.workspaceFsCapability ?? "best-effort";
|
|
2921
2929
|
const validateUiPaths = opts.validateUiPaths ?? workspaceFsCapability === "strong";
|
|
2930
|
+
const externalPluginsEnabled = opts.externalPlugins !== false;
|
|
2922
2931
|
const uiTools = createWorkspaceUiTools(bridge, {
|
|
2923
2932
|
workspaceRoot: validateUiPaths ? workspaceRoot : void 0
|
|
2924
2933
|
});
|
|
@@ -2936,7 +2945,7 @@ async function createWorkspaceAgentServer(opts = {}) {
|
|
|
2936
2945
|
const resolvedPlugins = await Promise.all(
|
|
2937
2946
|
allPluginEntries.map((entry) => resolveOnePluginEntry(entry, ctx))
|
|
2938
2947
|
);
|
|
2939
|
-
const pluginAuthoringEnabled = (opts.installPluginAuthoring ?? workspaceFsCapability === "strong") && !(opts.excludeDefaults ?? []).includes("boring-ui-plugin-cli-package");
|
|
2948
|
+
const pluginAuthoringEnabled = externalPluginsEnabled && (opts.installPluginAuthoring ?? workspaceFsCapability === "strong") && !(opts.excludeDefaults ?? []).includes("boring-ui-plugin-cli-package");
|
|
2940
2949
|
const pluginCollection = collectWorkspaceAgentServerPlugins({
|
|
2941
2950
|
...opts,
|
|
2942
2951
|
plugins: resolvedPlugins,
|
|
@@ -2956,7 +2965,7 @@ async function createWorkspaceAgentServer(opts = {}) {
|
|
|
2956
2965
|
const refreshBoringPluginDirs = () => {
|
|
2957
2966
|
const next = uniquePluginSources([
|
|
2958
2967
|
...defaultPluginPackagePaths.map((rootDir) => ({ rootDir, kind: "internal" })),
|
|
2959
|
-
...collectBoringPluginSources(workspaceRoot, pluginCollection, opts.additionalBoringPluginDirs)
|
|
2968
|
+
...collectBoringPluginSources(workspaceRoot, pluginCollection, opts.additionalBoringPluginDirs, externalPluginsEnabled)
|
|
2960
2969
|
]);
|
|
2961
2970
|
boringPluginDirs.splice(0, boringPluginDirs.length, ...next);
|
|
2962
2971
|
return boringPluginDirs;
|
|
@@ -3022,13 +3031,14 @@ async function createWorkspaceAgentServer(opts = {}) {
|
|
|
3022
3031
|
...opts,
|
|
3023
3032
|
mode: resolvedMode,
|
|
3024
3033
|
workspaceRoot,
|
|
3034
|
+
externalPlugins: externalPluginsEnabled,
|
|
3025
3035
|
extraTools: [
|
|
3026
3036
|
...opts.extraTools ?? [],
|
|
3027
3037
|
...uiTools,
|
|
3028
3038
|
...pluginCollection.agentOptions.extraTools ?? []
|
|
3029
3039
|
],
|
|
3030
3040
|
systemPromptAppend: [
|
|
3031
|
-
workspaceFsCapability === "strong" ? buildWorkspaceContextPrompt() : void 0,
|
|
3041
|
+
workspaceFsCapability === "strong" ? buildWorkspaceContextPrompt({ pluginAuthoringEnabled }) : void 0,
|
|
3032
3042
|
// `boring-ui-plugin` resolves via PATH from the provisioned workspace
|
|
3033
3043
|
// runtime. It is the slim setup component for agent-authored plugins;
|
|
3034
3044
|
// do not route plugin authoring through the full human-facing CLI.
|
package/dist/server.js
CHANGED
|
@@ -508,14 +508,14 @@ function createExecUiTool(uiBridge, opts = {}) {
|
|
|
508
508
|
" params:{seriesId:'GDPC1'}}}",
|
|
509
509
|
"",
|
|
510
510
|
" openSurface params: { kind: string, target: string, meta?: object }",
|
|
511
|
-
" \u2014 Open
|
|
512
|
-
" surface resolver registry. Use this when
|
|
511
|
+
" \u2014 Open an app-owned target through the workspace",
|
|
512
|
+
" surface resolver registry. Use this when the app",
|
|
513
513
|
" defines the mapping from domain target to panel",
|
|
514
514
|
" component, for example a catalog row.",
|
|
515
515
|
" Example: {kind:'openSurface', params:{",
|
|
516
|
-
" kind:'
|
|
516
|
+
" kind:'catalog.open-row',",
|
|
517
517
|
" target:'orders_daily',",
|
|
518
|
-
" meta:{catalogId:'
|
|
518
|
+
" meta:{catalogId:'data-catalog'}}}",
|
|
519
519
|
"",
|
|
520
520
|
" closePanel params: { id: string }",
|
|
521
521
|
" closeWorkbenchLeftPane params: {}",
|
|
@@ -1700,7 +1700,7 @@ var BoringPluginAssetManager = class {
|
|
|
1700
1700
|
additionalSkillPaths: [...new Set(plugins.flatMap((plugin) => plugin.skillPaths ?? []).map(skillPathForPiLoader))],
|
|
1701
1701
|
packages: compactPiPackages(normalizeBoringPluginPiPackages(plugins)),
|
|
1702
1702
|
extensionPaths: plugins.flatMap((plugin) => plugin.extensionPaths ?? []),
|
|
1703
|
-
...prompts.length > 0 ? { systemPromptAppend: `# Loaded
|
|
1703
|
+
...prompts.length > 0 ? { systemPromptAppend: `# Loaded app-provided context
|
|
1704
1704
|
|
|
1705
1705
|
${prompts.join("\n\n")}` } : {}
|
|
1706
1706
|
};
|
|
@@ -1968,7 +1968,7 @@ async function boringPluginRoutes(app, opts) {
|
|
|
1968
1968
|
function aggregatePluginPrompts(manager) {
|
|
1969
1969
|
const prompts = manager.list().map((plugin) => plugin.pi?.systemPrompt?.trim()).filter((prompt) => Boolean(prompt));
|
|
1970
1970
|
if (prompts.length === 0) return void 0;
|
|
1971
|
-
return `# Loaded
|
|
1971
|
+
return `# Loaded app-provided context
|
|
1972
1972
|
|
|
1973
1973
|
${prompts.join("\n\n")}`;
|
|
1974
1974
|
}
|
package/dist/testing.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as Ba } from "react/jsx-runtime";
|
|
2
2
|
import * as Pa from "react";
|
|
3
3
|
import { createElement as is, useMemo as wn, useLayoutEffect as us, isValidElement as ss, cloneElement as ds, useSyncExternalStore as Gi } from "react";
|
|
4
|
-
import { h as cs, q as fs, o as ps } from "./WorkspaceProvider-
|
|
4
|
+
import { h as cs, q as fs, o as ps } from "./WorkspaceProvider-DkZAxsYo.js";
|
|
5
5
|
import { d as ms } from "./panel-DnvDNQac.js";
|
|
6
6
|
import * as bs from "react-dom/test-utils";
|
|
7
7
|
import ka from "react-dom";
|
package/dist/workspace.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
var V = Object.defineProperty;
|
|
2
2
|
var X = (e, t, r) => t in e ? V(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
|
|
3
3
|
var T = (e, t, r) => X(e, typeof t != "symbol" ? t + "" : t, r);
|
|
4
|
-
import { u as K, p as Q, a as Y, b as Z, D as ee } from "./WorkspaceProvider-
|
|
5
|
-
import { A as Je, C as Ge, c as Ve, d as Xe, e as Qe, F as Ye, f as Ze, M as et, g as tt, P as rt, h as at, i as nt, j as st, k as ot, R as it, S as lt, l as ct, m as dt, T as ut, U as pt, W as ft, n as mt, o as ht, q as gt, r as bt, s as yt, t as vt, v as xt, w as kt, x as wt, y as Pt, z as St, B as Ct, E as Nt, G as Et, H as Rt, I as Tt, J as It, K as Ot, L as Ft, N as Lt, O as Mt, Q as Bt, V as Wt, X as Dt, Y as Kt, Z as $t, _ as jt, $ as zt, a0 as Ht, a1 as Ut, a2 as _t, a3 as qt, a4 as At, a5 as Jt, a6 as Gt, a7 as Vt, a8 as Xt, a9 as Qt, aa as Yt, ab as Zt, ac as er, ad as tr, ae as rr, af as ar, ag as nr, ah as sr, ai as or, aj as ir, ak as lr, al as cr, am as dr, an as ur, ao as pr, ap as fr, aq as mr, ar as hr, as as gr } from "./WorkspaceProvider-
|
|
4
|
+
import { u as K, p as Q, a as Y, b as Z, D as ee } from "./WorkspaceProvider-DkZAxsYo.js";
|
|
5
|
+
import { A as Je, C as Ge, c as Ve, d as Xe, e as Qe, F as Ye, f as Ze, M as et, g as tt, P as rt, h as at, i as nt, j as st, k as ot, R as it, S as lt, l as ct, m as dt, T as ut, U as pt, W as ft, n as mt, o as ht, q as gt, r as bt, s as yt, t as vt, v as xt, w as kt, x as wt, y as Pt, z as St, B as Ct, E as Nt, G as Et, H as Rt, I as Tt, J as It, K as Ot, L as Ft, N as Lt, O as Mt, Q as Bt, V as Wt, X as Dt, Y as Kt, Z as $t, _ as jt, $ as zt, a0 as Ht, a1 as Ut, a2 as _t, a3 as qt, a4 as At, a5 as Jt, a6 as Gt, a7 as Vt, a8 as Xt, a9 as Qt, aa as Yt, ab as Zt, ac as er, ad as tr, ae as rr, af as ar, ag as nr, ah as sr, ai as or, aj as ir, ak as lr, al as cr, am as dr, an as ur, ao as pr, ap as fr, aq as mr, ar as hr, as as gr } from "./WorkspaceProvider-DkZAxsYo.js";
|
|
6
6
|
import { c as C } from "./utils-B6yFEsav.js";
|
|
7
|
-
import { C as yr, T as vr, W as xr, b as kr } from "./WorkspaceLoadingState-
|
|
7
|
+
import { C as yr, T as vr, W as xr, b as kr } from "./WorkspaceLoadingState-yp4vNmrT.js";
|
|
8
8
|
import { jsx as a, jsxs as g, Fragment as te } from "react/jsx-runtime";
|
|
9
9
|
import { Button as P, Sheet as re, SheetContent as ae, SheetHeader as ne, SheetTitle as se, SheetDescription as oe, EmptyState as ie, Kbd as I, ErrorState as le, IconButton as O } from "@hachej/boring-ui-kit";
|
|
10
10
|
import { Toaster as Pr, dismissToast as Sr, toast as Cr } from "@hachej/boring-ui-kit";
|
|
11
11
|
import { useSyncExternalStore as $, useState as N, useEffect as k, useRef as S, useCallback as b, useMemo as w, Suspense as ce, Component as de } from "react";
|
|
12
12
|
import { C as Er, c as Rr } from "./CodeEditor-DQqOn4xz.js";
|
|
13
|
-
import { FileTree as Ir } from "./FileTree-
|
|
14
|
-
import { MarkdownEditor as Fr } from "./MarkdownEditor-
|
|
13
|
+
import { FileTree as Ir } from "./FileTree-CVsvICGP.js";
|
|
14
|
+
import { MarkdownEditor as Fr } from "./MarkdownEditor-BvaGmzWP.js";
|
|
15
15
|
import { MenuIcon as ue, PanelLeftOpenIcon as pe, PanelLeftCloseIcon as fe, PinIcon as me, CheckIcon as he, CopyIcon as ge } from "lucide-react";
|
|
16
16
|
import { d as Mr } from "./panel-DnvDNQac.js";
|
|
17
17
|
function We() {
|
package/docs/INTERFACES.md
CHANGED
package/docs/PLUGIN_STRUCTURE.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Plugin Structure
|
|
2
2
|
|
|
3
3
|
Canonical quick reference for boring-ui plugin layouts. For the full current
|
|
4
|
-
contract, see [`PLUGIN_SYSTEM.md`](./PLUGIN_SYSTEM.md). For
|
|
5
|
-
architecture, see the repo-level
|
|
6
|
-
[`docs/runtime-plugin-v2-hot-reload-plan.md`](../../../docs/runtime-plugin-v2-hot-reload-plan.md).
|
|
4
|
+
contract, see [`PLUGIN_SYSTEM.md`](./PLUGIN_SYSTEM.md). For the historical
|
|
5
|
+
hosted/runtime architecture exploration, see the archived repo-level
|
|
6
|
+
[`docs/plans/archive/runtime-plugin-v2-hot-reload-plan.md`](../../../docs/plans/archive/runtime-plugin-v2-hot-reload-plan.md).
|
|
7
7
|
|
|
8
8
|
## Generated/runtime plugin
|
|
9
9
|
|
package/docs/PLUGIN_SYSTEM.md
CHANGED
|
@@ -6,8 +6,9 @@ example `PLUGIN_SYSTEM.md §4.5`), so keep headings stable when editing.
|
|
|
6
6
|
|
|
7
7
|
This document describes the implementation as it exists now. Historical
|
|
8
8
|
implementation plans live under `packages/workspace/docs/plans/archive/`.
|
|
9
|
-
For
|
|
10
|
-
|
|
9
|
+
For the historical generated/hosted runtime-plugin architecture exploration,
|
|
10
|
+
see the archived repo-level
|
|
11
|
+
`docs/plans/archive/runtime-plugin-v2-hot-reload-plan.md`.
|
|
11
12
|
|
|
12
13
|
## Contents
|
|
13
14
|
|
|
@@ -27,7 +28,7 @@ For future generated/hosted runtime-plugin architecture, see the repo-level
|
|
|
27
28
|
| Term | Definition |
|
|
28
29
|
| --- | --- |
|
|
29
30
|
| **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-plugin scaffold`. It is hot-loaded for front/Pi resources, but must not rely on dynamic backend routes. |
|
|
31
|
+
| **Runtime/generated plugin** | Workspace-local plugin under `.pi/extensions/<id>/`, usually produced by `boring-ui-plugin scaffold`. Also called an **external** plugin in trust-model terms. It is hot-loaded for front/Pi resources, but must not rely on dynamic backend routes. |
|
|
31
32
|
| **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
33
|
| **Boring front factory** | Default export of `boring.front`: `(api: BoringFrontAPI) => void | Promise<void>`. Usually created with `definePlugin({ ... })`. |
|
|
33
34
|
| **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. |
|
|
@@ -35,6 +36,25 @@ For future generated/hosted runtime-plugin architecture, see the repo-level
|
|
|
35
36
|
| **Revision** | Per-plugin monotonic integer. It bumps on signature changes and is appended to browser front imports for cache busting. |
|
|
36
37
|
| **Surface resolver** | Front contribution that maps a typed request such as `open-path` to a panel id/title/params. File opens should route through this path. |
|
|
37
38
|
|
|
39
|
+
### 1.1 Trust model (internal vs external)
|
|
40
|
+
|
|
41
|
+
The two tiers differ by **provenance and trust**, not just lifecycle:
|
|
42
|
+
|
|
43
|
+
| | App/internal plugin | Runtime/generated ("external") plugin |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| Provenance | App-owned package, composed at boot | Workspace-local `.pi/extensions/`, often agent-generated |
|
|
46
|
+
| Trust | Trusted app module | Trusted **only** as local developer/workspace code |
|
|
47
|
+
| Front | Native React in the host tree | Native React (local trusted context) |
|
|
48
|
+
| Server/routes/tools | Full power: Fastify routes, static `agentTools`, providers, domain APIs | Route-free; no `boring.server`; backend work goes through Pi tools |
|
|
49
|
+
| Reload | Restart/redeploy | `/reload` hot-swaps front + Pi resources |
|
|
50
|
+
|
|
51
|
+
Plugin tools' `execute()` run in the **host Node process and bypass the
|
|
52
|
+
sandbox by design**; plugin loading is local-mode-only (skipped under
|
|
53
|
+
`vercel-sandbox`). Hosted/marketplace plugins — untrusted external code that
|
|
54
|
+
would need iframe fronts and sandbox-proxied tools — are **not implemented**;
|
|
55
|
+
that provenance/permission model is a future phase (see §7 and the archived
|
|
56
|
+
repo-level `docs/plans/archive/runtime-plugin-trust-modes-plan.md`).
|
|
57
|
+
|
|
38
58
|
---
|
|
39
59
|
|
|
40
60
|
## 2. End-to-end behaviour
|
|
@@ -241,6 +261,27 @@ boring-ui-plugin verify <name>
|
|
|
241
261
|
Do not teach agents to copy `packages/plugin-cli/templates/plugin` for generated runtime
|
|
242
262
|
plugins. That template is an app/internal publishable package example.
|
|
243
263
|
|
|
264
|
+
### 4.7 Chat slash commands
|
|
265
|
+
|
|
266
|
+
Plugins can contribute **chat `/slash` commands** — a separate surface from the
|
|
267
|
+
command-palette `commands` output. There is no `!` bang-command; the composer
|
|
268
|
+
parses `/name args` only.
|
|
269
|
+
|
|
270
|
+
- **Front registry** (`packages/agent/src/front/slashCommands/registry.ts`):
|
|
271
|
+
`SlashCommand { name, description, kind?, source?, sourcePlugin?, handler }`.
|
|
272
|
+
`kind: 'local'` runs in the browser; `kind: 'skill'` is forwarded to the Pi
|
|
273
|
+
agent as `skill: <name>\n\n<args>`. The chat composer (`PiChatPanel`)
|
|
274
|
+
intercepts `/` input before it reaches the harness.
|
|
275
|
+
- **Server commands** are listed from the harness via
|
|
276
|
+
`GET /api/v1/agent/commands` (consumed by `useServerCommands`) and executed
|
|
277
|
+
via `POST /api/v1/agent/commands/execute` — this route **bypasses the
|
|
278
|
+
harness chat loop**; Pi executes the command natively. `source`
|
|
279
|
+
(`extension`/`prompt`/`skill`) and `sourcePlugin` tag where a command came
|
|
280
|
+
from in the picker.
|
|
281
|
+
- **How a plugin contributes one**: ship a Pi extension/prompt/skill in its
|
|
282
|
+
`package.json#pi` block — Pi-sourced commands appear automatically. No
|
|
283
|
+
harness changes required.
|
|
284
|
+
|
|
244
285
|
---
|
|
245
286
|
|
|
246
287
|
## 5. Key algorithms
|
|
@@ -327,7 +368,8 @@ while capturing the front factory.
|
|
|
327
368
|
plugin RPC for purity.
|
|
328
369
|
- Dynamic provider/binding trees for runtime hot-loaded plugins in this PR.
|
|
329
370
|
- Marketplace signing/provenance/permissions. Those belong to the next runtime
|
|
330
|
-
plugin architecture phase.
|
|
371
|
+
plugin architecture phase. Promotion (external → internal) is designed as an
|
|
372
|
+
explicit admin action with pinned provenance + restart — not implemented yet.
|
|
331
373
|
|
|
332
374
|
---
|
|
333
375
|
|
package/docs/README.md
CHANGED
|
@@ -1,24 +1,87 @@
|
|
|
1
1
|
# Workspace Docs
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- `
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
3
|
+
`@hachej/boring-workspace` is the workspace UI, layout, plugin, and bridge layer
|
|
4
|
+
for boring-ui apps. It composes chat, files, catalogs, editors, and app-specific
|
|
5
|
+
panes into an IDE-style workbench. The app shell owns auth, routing, persistence,
|
|
6
|
+
and the concrete chat component; the workspace owns the layout runtime, the
|
|
7
|
+
plugin registries, and the typed agent-to-browser bridge.
|
|
8
|
+
|
|
9
|
+
This folder holds the current normative docs. Read this index first, then jump to
|
|
10
|
+
the doc that matches your task.
|
|
11
|
+
|
|
12
|
+
## Architecture at a glance
|
|
13
|
+
|
|
14
|
+
- **Layout runtime** — Dockview-based panes (`IdeLayout`, `ChatLayout`,
|
|
15
|
+
`ResponsiveDockviewShell`) mounted by `WorkspaceProvider`. Panels open in the
|
|
16
|
+
center/right/bottom; left-tabs stay docked in the sidebar.
|
|
17
|
+
- **Plugin host** — `WorkspaceProvider` runs `bootstrap(plugins)` to populate the
|
|
18
|
+
panel, command, catalog, and surface-resolver registries. Lazy panel factories
|
|
19
|
+
are auto-wrapped in `React.lazy + Suspense + ErrorBoundary`.
|
|
20
|
+
- **UI bridge** — Agents/servers post `UiCommand` values (`src/shared/ui-bridge.ts`);
|
|
21
|
+
the front-end dispatches them against the workspace runtime over SSE with an
|
|
22
|
+
HTTP poll fallback.
|
|
23
|
+
- **Surface resolvers** — Decouple agent "open X" requests from concrete panel
|
|
24
|
+
ids. A `SurfaceOpenRequest { kind, target, meta }` is resolved by plugin
|
|
25
|
+
surface resolvers into panel openings (`src/shared/types/surface.ts`).
|
|
26
|
+
- **Two plugin tiers** — App/internal package plugins (trusted, boot-time, may add
|
|
27
|
+
routes/agent tools/Pi resources) and runtime/generated `.pi/extensions` plugins
|
|
28
|
+
(a.k.a. *external* plugins: hot-reloaded for front/Pi, route-free, and loaded
|
|
29
|
+
only in local/direct-style host runtime contexts — not `vercel-sandbox`). See
|
|
30
|
+
`PLUGIN_SYSTEM.md` §1.1 for the trust model.
|
|
31
|
+
|
|
32
|
+
## Key abstractions
|
|
33
|
+
|
|
34
|
+
| Abstraction | Where | What it is |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| `WorkspaceProvider` | `src/front/provider` | Root provider; boots plugins, layout, bridge. |
|
|
37
|
+
| `definePlugin()` | `@hachej/boring-workspace/plugin` | Declarative front plugin: panels, leftTabs, commands, catalogs, bindings, providers, surfaceResolvers. |
|
|
38
|
+
| `defineServerPlugin()` | `@hachej/boring-workspace/server` | Trusted boot-time server plugin: routes, agent tools, system prompt, Pi packages, provisioning. |
|
|
39
|
+
| `PaneProps<T>` | `src/shared/types/panel.ts` | Props every panel/left-tab component receives (`params`, `api`, `containerApi`). |
|
|
40
|
+
| `UiCommand` / `UiBridge` | `src/shared/ui-bridge.ts` | Typed agent→browser command contract. |
|
|
41
|
+
| `SurfaceOpenRequest` | `src/shared/types/surface.ts` | Domain open request resolved to a panel. |
|
|
42
|
+
| `BoringPluginAssetManager` | `src/server/agentPlugins` | Scans plugin dirs, hashes signatures, emits load/unload/error events, backs `/api/v1/agent-plugins`. |
|
|
43
|
+
|
|
44
|
+
## Architectural decisions
|
|
45
|
+
|
|
46
|
+
- **App shell owns auth/routing/persistence/chat; workspace owns chrome.** Keeps
|
|
47
|
+
the workspace package reusable and the chat component injected, not hardcoded.
|
|
48
|
+
- **Front/shared workspace code does not value-import `@hachej/boring-agent`.** The
|
|
49
|
+
dependency is inverted via the injected `chatPanel`, so the workbench builds and
|
|
50
|
+
ships without the agent package. Only `src/app/*` composition may import
|
|
51
|
+
documented agent server APIs.
|
|
52
|
+
- **Agents open domain targets through `openSurface`, not `openPanel`.** Surface
|
|
53
|
+
resolvers map requests to panels so workspace chrome never hardcodes plugin
|
|
54
|
+
panel ids or domain rules. Use `openPanel` only when the caller intentionally
|
|
55
|
+
names a concrete panel.
|
|
56
|
+
- **Plugin data APIs live under the owning plugin.** There is no shared
|
|
57
|
+
`front/data` compatibility layer; e.g. the filesystem client/hooks/events are
|
|
58
|
+
plugin-owned (`src/plugins/filesystemPlugin/front/data`).
|
|
59
|
+
- **Generated runtime plugins stay route-free; server changes are boot-time only.**
|
|
60
|
+
`/reload` refreshes front/Pi resources and tolerates per-plugin failures, but
|
|
61
|
+
does not hot-wire Fastify routes or agent tools. Server-file drift surfaces a
|
|
62
|
+
`requiresRestart` warning.
|
|
63
|
+
- **Chat-first boot.** `WorkspaceAgentFront` mounts immediately while readiness
|
|
64
|
+
warms in the background; workbench surfaces are locally gated by warmup state.
|
|
65
|
+
- **Style isolation.** Workspace owns public `--boring-*` tokens and Tailwind base
|
|
66
|
+
reset; agent consumes them under `[data-boring-agent]`. See
|
|
67
|
+
[`docs/TAILWIND-V4-STYLE-ISOLATION.md`](../../../docs/TAILWIND-V4-STYLE-ISOLATION.md).
|
|
68
|
+
|
|
69
|
+
## Docs
|
|
70
|
+
|
|
71
|
+
Authoring:
|
|
72
|
+
- [`PLUGIN_STRUCTURE.md`](./PLUGIN_STRUCTURE.md) — quick layout guide for
|
|
73
|
+
generated/runtime plugins vs app/internal publishable package plugins.
|
|
74
|
+
- [`PLUGIN_SYSTEM.md`](./PLUGIN_SYSTEM.md) — normative spec for the plugin/agent
|
|
75
|
+
layer: manifest fields, front + server authoring API, hot-reload coverage,
|
|
76
|
+
and key algorithms. Code and tests cite it as `Per PLUGIN_SYSTEM.md §X`, so its
|
|
77
|
+
section numbering is stable.
|
|
78
|
+
|
|
79
|
+
Boundaries / contracts:
|
|
80
|
+
- [`INTERFACES.md`](./INTERFACES.md) — package boundaries, core contracts, and
|
|
81
|
+
ownership rules across `src/front`, `src/server`, `src/shared`, `src/plugins`,
|
|
82
|
+
and `src/app`.
|
|
83
|
+
|
|
84
|
+
History:
|
|
85
|
+
- [`plans/archive/`](./plans/archive/) — superseded implementation plans and specs
|
|
86
|
+
kept for historical context. Not normative; current behavior is described in the
|
|
87
|
+
docs above and verified against source.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-workspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
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.",
|
|
@@ -135,9 +135,9 @@
|
|
|
135
135
|
"tailwind-merge": "^2.0.0",
|
|
136
136
|
"zod": "^3.23.0",
|
|
137
137
|
"zustand": "^5.0.0",
|
|
138
|
-
"@hachej/boring-
|
|
139
|
-
"@hachej/boring-
|
|
140
|
-
"@hachej/boring-ui-
|
|
138
|
+
"@hachej/boring-ui-kit": "0.1.43",
|
|
139
|
+
"@hachej/boring-agent": "0.1.43",
|
|
140
|
+
"@hachej/boring-ui-plugin-cli": "0.1.43"
|
|
141
141
|
},
|
|
142
142
|
"devDependencies": {
|
|
143
143
|
"@tailwindcss/postcss": "^4.0.0",
|
/package/docs/plans/{ASK_USER_QUESTIONS_PLUGIN_SPEC.md → archive/ASK_USER_QUESTIONS_PLUGIN_SPEC.md}
RENAMED
|
File without changes
|
|
File without changes
|
/package/docs/plans/{GENERIC_EXPLORER_PLUGIN_PLAN.md → archive/GENERIC_EXPLORER_PLUGIN_PLAN.md}
RENAMED
|
File without changes
|
|
File without changes
|
/package/docs/plans/{PLUGIN_OUTPUTS_ISOLATION_PLAN.md → archive/PLUGIN_OUTPUTS_ISOLATION_PLAN.md}
RENAMED
|
File without changes
|
|
File without changes
|
/package/docs/plans/{UI_BRIDGE_OWNERSHIP_REFACTOR.md → archive/UI_BRIDGE_OWNERSHIP_REFACTOR.md}
RENAMED
|
File without changes
|