acrylblends 1.0.10 → 1.2.0
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 +9 -0
- package/dist/index.d.ts +60 -2
- package/dist/index.js +1992 -33
- package/dist/index.js.map +1 -1
- package/docs/framework/agents/index.md +1 -1
- package/docs/framework/api/summary.md +1 -1
- package/docs/framework/getting-started/desktop.md +23 -4
- package/docs/framework/guides/create-acrylblends.md +1 -1
- package/docs/framework/guides/production.md +20 -0
- package/docs/framework/workshop/README.md +174 -285
- package/docs/framework/workshop/facilitator.md +81 -90
- package/legacy/README.md +9 -0
- package/legacy/agent/157ce3db1112/src/app.ts +98 -0
- package/legacy/agent/157ce3db1112/src/routes.ts +63 -0
- package/legacy/agent/24c681a00fca/src/app.ts +160 -0
- package/legacy/agent/24c681a00fca/src/routes.ts +83 -0
- package/legacy/agent/2e790da977b2/src/app.ts +98 -0
- package/legacy/agent/2e790da977b2/src/routes.ts +63 -0
- package/legacy/agent/6307045545dc/src/app.ts +168 -0
- package/legacy/agent/6307045545dc/src/routes.ts +83 -0
- package/legacy/agent/6a5fb9c15c53/src/app.ts +158 -0
- package/legacy/agent/6a5fb9c15c53/src/routes.ts +83 -0
- package/legacy/agent/71fb54a5a942/src/app.ts +111 -0
- package/legacy/agent/71fb54a5a942/src/routes.ts +63 -0
- package/legacy/agent/74ece148269c/src/app.ts +168 -0
- package/legacy/agent/74ece148269c/src/routes.ts +93 -0
- package/legacy/agent/855359304707/src/app.ts +168 -0
- package/legacy/agent/855359304707/src/routes.ts +126 -0
- package/legacy/agent/b5ef3c786ae4/src/app.ts +127 -0
- package/legacy/agent/b5ef3c786ae4/src/routes.ts +76 -0
- package/legacy/agent/c2f30958043b/src/app.ts +98 -0
- package/legacy/agent/c2f30958043b/src/routes.ts +53 -0
- package/legacy/blank/5a91c558af22/src/routes.ts +18 -0
- package/legacy/blank/9c650cf52bf3/src/routes.ts +14 -0
- package/legacy/blank/aea589283445/src/routes.ts +16 -0
- package/legacy/blank/b2cbb759c889/src/routes.ts +16 -0
- package/legacy/blank/d6d371c9a65e/src/routes.ts +18 -0
- package/legacy/chat/7076cc821e2c/src/app.ts +72 -0
- package/legacy/chat/7076cc821e2c/src/routes.ts +13 -0
- package/legacy/chat/7dbe6d5170df/src/app.ts +107 -0
- package/legacy/chat/7dbe6d5170df/src/routes.ts +19 -0
- package/legacy/chat/a9a9ab44c58e/src/app.ts +107 -0
- package/legacy/chat/a9a9ab44c58e/src/routes.ts +15 -0
- package/legacy/chat/f20ad9a51b06/src/app.ts +106 -0
- package/legacy/chat/f20ad9a51b06/src/routes.ts +15 -0
- package/legacy/layouts.json +524 -0
- package/legacy/nodejs/1d477f37aaf4/src/app.ts +92 -0
- package/legacy/nodejs/1d477f37aaf4/src/routes.ts +40 -0
- package/legacy/nodejs/b1bd9462496c/src/app.ts +61 -0
- package/legacy/nodejs/b1bd9462496c/src/routes.ts +37 -0
- package/legacy/nodejs/d5bab75076ef/src/app.ts +95 -0
- package/legacy/nodejs/d5bab75076ef/src/routes.ts +40 -0
- package/legacy/notes/4edc36949c15/src/app.ts +107 -0
- package/legacy/notes/4edc36949c15/src/routes.ts +14 -0
- package/legacy/notes/6cab2d09747c/src/app.ts +72 -0
- package/legacy/notes/6cab2d09747c/src/routes.ts +12 -0
- package/legacy/notes/7ca2dfed623a/src/app.ts +106 -0
- package/legacy/notes/7ca2dfed623a/src/routes.ts +14 -0
- package/legacy/todo/02e613b3625c/src/app.ts +71 -0
- package/legacy/todo/02e613b3625c/src/todo.ts +123 -0
- package/legacy/todo/45694a8d9e15/src/app.ts +71 -0
- package/legacy/todo/45694a8d9e15/src/todo.ts +96 -0
- package/legacy/todo/5923d3a6099f/src/app.ts +71 -0
- package/legacy/todo/5923d3a6099f/src/todo.ts +125 -0
- package/legacy/todo/849a18d66dc1/src/app.ts +91 -0
- package/legacy/todo/849a18d66dc1/src/todo.ts +125 -0
- package/legacy/todo/8e64211312f3/src/app.ts +71 -0
- package/legacy/todo/8e64211312f3/src/todo.ts +125 -0
- package/legacy/todo/b79078a87565/src/app.ts +71 -0
- package/legacy/todo/b79078a87565/src/todo.ts +125 -0
- package/lib/{audit-Dw-siYTp.d.ts → audit-Bok_UNCn.d.ts} +41 -6
- package/lib/{client-modules-drj4mjhj.js → client-modules-Bkdr83jO.js} +1 -1
- package/lib/cordis/door.d.ts +44 -7
- package/lib/cordis/door.js +214 -60
- package/lib/cordis/inspect.js +1 -1
- package/lib/cordis/node-server.d.ts +101 -3
- package/lib/cordis/node-server.js +3 -3
- package/lib/cordis/router-http.d.ts +7 -1
- package/lib/cordis/router-http.js +44 -3
- package/lib/cordis/router.d.ts +1 -1
- package/lib/cordis/router.js +1 -1
- package/lib/cordis/state.d.ts +3 -2
- package/lib/cordis/state.js +371 -7
- package/lib/door/host.d.ts +2 -2
- package/lib/door/host.js +1 -1
- package/lib/door/page.d.ts +20 -1
- package/lib/door/page.js +75 -14
- package/lib/door/protocol.d.ts +1 -1
- package/lib/drivers.d.ts +10 -1
- package/lib/{index-DMOtA-NJ.d.ts → index-DGq7H0lb.d.ts} +11 -1
- package/lib/node-server.d.ts +7 -1
- package/lib/node-server.js +2 -2
- package/lib/{protocol-a2aqrp2X.d.ts → protocol-BeIYCgTo.d.ts} +4 -0
- package/lib/{snapshot-text-BfEbEOjA.js → snapshot-text-CXTnjxGx.js} +121 -9
- package/lib/src-CtkIX_Gg.js +427 -0
- package/lib/{src-BTBm4OPD.js → src-iBJ2ysV9.js} +77 -14
- package/lib/{test-websocket-BLeEvybj.js → test-websocket-CQOSvBth.js} +17 -7
- package/lib/{test-websocket-DyeS50Tr.d.ts → test-websocket-GUTAkFQT.d.ts} +3 -1
- package/package.json +2 -1
- package/plugins/acryl-door/src/host/channel.ts +124 -9
- package/plugins/acryl-door/src/host/chat-tools.ts +8 -6
- package/plugins/acryl-door/src/host/door-file.ts +7 -2
- package/plugins/acryl-door/src/host/door.ts +58 -23
- package/plugins/acryl-door/src/host/page-routes.ts +3 -1
- package/plugins/acryl-door/src/host/page-socket.ts +18 -8
- package/plugins/acryl-door/src/host/verbs.ts +3 -0
- package/plugins/acryl-door/src/index.ts +166 -29
- package/plugins/acryl-door/src/page/base.ts +32 -0
- package/plugins/acryl-door/src/page/channel.ts +11 -1
- package/plugins/acryl-door/src/page/driver/accessibility.ts +11 -0
- package/plugins/acryl-door/src/page/driver/actions.ts +4 -0
- package/plugins/acryl-door/src/page/driver/driver.ts +49 -7
- package/plugins/acryl-door/src/page/driver/snapshot.ts +5 -2
- package/plugins/acryl-door/src/page/index.ts +46 -2
- package/plugins/acryl-door/src/page/indicator.ts +14 -6
- package/plugins/acryl-door/src/page/outline.ts +56 -0
- package/plugins/acryl-door/src/page/protocol.ts +4 -0
- package/plugins/acryl-door/src/page/snapshot-text.ts +2 -1
- package/plugins/acryl-node-server/src/adapter/listener.ts +4 -0
- package/plugins/acryl-node-server/src/adapter/raw.ts +18 -0
- package/plugins/acryl-node-server/src/adapter/websocket.ts +15 -9
- package/plugins/acryl-node-server/src/client-modules.ts +7 -1
- package/plugins/acryl-node-server/src/index.ts +304 -16
- package/plugins/acryl-node-server/src/upgrade-hub.ts +2 -2
- package/plugins/acryl-page/plugin.json +12 -0
- package/plugins/acryl-page/src/index.ts +163 -0
- package/plugins/acryl-router/src/service.ts +77 -14
- package/plugins/acryl-router-http/src/index.ts +15 -1
- package/plugins/acryl-router-http/src/serve.ts +31 -0
- package/plugins/acryl-state/plugin.json +4 -3
- package/plugins/acryl-state/src/client-source.ts +244 -0
- package/plugins/acryl-state/src/service.ts +33 -6
- package/plugins/acryl-state/src/socket.ts +96 -0
- package/plugins/acryl-web-server/plugin.json +14 -0
- package/plugins/acryl-web-server/src/index.ts +164 -0
- package/plugins/agent/agent.ts +38 -7
- package/plugins/agent/index.ts +1 -1
- package/plugins/agent/model.ts +10 -2
- package/plugins/agent/tools.ts +9 -3
- package/plugins/agent-panel/client/describe.ts +57 -0
- package/plugins/agent-panel/client/driver-pick.ts +22 -0
- package/plugins/agent-panel/client/frame.ts +51 -0
- package/plugins/agent-panel/client/main.ts +343 -81
- package/plugins/agent-panel/drivers.ts +7 -2
- package/plugins/agent-panel/headless.ts +5 -2
- package/plugins/agent-panel/index.ts +187 -61
- package/plugins/agent-panel/mount.ts +27 -0
- package/plugins/agent-panel/visitors.ts +231 -0
- package/plugins/desktop/frame.ts +231 -0
- package/plugins/desktop/launch.ts +44 -9
- package/plugins/desktop/main.ts +100 -32
- package/plugins/desktop/window.ts +21 -4
- package/plugins/driver-pty/client/terminal.ts +4 -1
- package/plugins/driver-pty/index.ts +38 -11
- package/plugins/driver-pty/spawn.ts +38 -0
- package/plugins/driver-pty/terminal.ts +2 -0
- package/plugins/extensions/index.ts +26 -1
- package/plugins/extensions/resolve.ts +13 -0
- package/plugins/feedback/client.d.ts +22 -0
- package/plugins/feedback/client.js +471 -0
- package/plugins/feedback/index.ts +143 -0
- package/plugins/feedback/plugin.json +11 -0
- package/plugins/feedback/store.ts +307 -0
- package/plugins/home/index.ts +122 -0
- package/plugins/home/plugin.json +11 -0
- package/plugins/instance/index.ts +12 -3
- package/plugins/manifest/app-plugins.ts +86 -0
- package/plugins/manifest/index.ts +12 -2
- package/plugins/manifest/snapshot.ts +275 -0
- package/plugins/openai/index.ts +64 -5
- package/plugins/openai/prompt.ts +23 -0
- package/shared/AGENTS.core.md +36 -16
- package/shared/skills/acryl-add-ui/SKILL.md +19 -0
- package/shared/skills/acryl-app/SKILL.md +13 -0
- package/shared/skills/acryl-build-plugin/SKILL.md +22 -0
- package/shared/skills/acryl-change-plugin/SKILL.md +14 -0
- package/shared/skills/acryl-diagnose-plugin/SKILL.md +13 -0
- package/shared/skills/acryl-fix-plugin/SKILL.md +13 -0
- package/shared/skills/acryl-remove-plugin/SKILL.md +12 -0
- package/shared/skills/acryl-share-plugin/SKILL.md +16 -0
- package/shared/skills/cordis-plugin/SKILL.md +26 -0
- package/templates/agent/AGENTS.md +4 -2
- package/templates/agent/blend.yaml +4 -0
- package/templates/agent/gitignore +1 -0
- package/templates/agent/package.json +1 -0
- package/templates/agent/src/app.ts +150 -33
- package/templates/agent/src/frame.ts +17 -0
- package/templates/agent/src/main.ts +5 -3
- package/templates/agent/src/routes.ts +73 -21
- package/templates/agent/template.json +2 -0
- package/templates/agent/test/app.test.ts +83 -5
- package/templates/blank/AGENTS.md +3 -2
- package/templates/blank/blend.yaml +11 -0
- package/templates/blank/gitignore +1 -0
- package/templates/blank/package.json +1 -0
- package/templates/blank/src/app.ts +100 -29
- package/templates/blank/src/door.ts +7 -0
- package/templates/blank/src/first-page.ts +5 -0
- package/templates/blank/src/frame.ts +17 -0
- package/templates/blank/src/routes.ts +65 -8
- package/templates/blank/template.json +14 -1
- package/templates/blank/test/app.test.ts +103 -16
- package/templates/chat/blend.yaml +2 -1
- package/templates/chat/gitignore +1 -0
- package/templates/chat/package.json +1 -0
- package/templates/chat/src/app.ts +72 -22
- package/templates/chat/src/chat-app.ts +11 -2
- package/templates/chat/src/client/chat.tsx +4 -2
- package/templates/chat/src/frame.ts +17 -0
- package/templates/chat/src/main.ts +1 -6
- package/templates/chat/src/page.tsx +6 -4
- package/templates/chat/src/routes.ts +14 -4
- package/templates/chat/src/runtime.ts +9 -3
- package/templates/chat/template.json +3 -1
- package/templates/chat/test/chat.test.ts +46 -1
- package/templates/chat/test/server.test.ts +17 -3
- package/templates/nodejs/blend.yaml +2 -1
- package/templates/nodejs/gitignore +1 -0
- package/templates/nodejs/package.json +1 -0
- package/templates/nodejs/src/app.ts +76 -21
- package/templates/nodejs/src/frame.ts +17 -0
- package/templates/nodejs/src/main.ts +1 -6
- package/templates/nodejs/src/page.tsx +3 -3
- package/templates/nodejs/src/routes.ts +32 -13
- package/templates/nodejs/template.json +3 -1
- package/templates/nodejs/test/app.test.ts +38 -3
- package/templates/nodejs/test/server.test.ts +17 -3
- package/templates/notes/blend.yaml +2 -1
- package/templates/notes/gitignore +1 -0
- package/templates/notes/package.json +1 -0
- package/templates/notes/src/app.ts +72 -22
- package/templates/notes/src/frame.ts +17 -0
- package/templates/notes/src/main.ts +1 -6
- package/templates/notes/src/notes-app.ts +24 -17
- package/templates/notes/src/routes.ts +11 -4
- package/templates/notes/src/runtime.ts +9 -3
- package/templates/notes/src/views.tsx +26 -17
- package/templates/notes/template.json +3 -1
- package/templates/notes/test/notes.test.ts +39 -1
- package/templates/notes/test/server.test.ts +17 -3
- package/templates/todo/blend.yaml +3 -0
- package/templates/todo/gitignore +1 -0
- package/templates/todo/package.json +1 -0
- package/templates/todo/src/app.ts +81 -27
- package/templates/todo/src/door.ts +7 -0
- package/templates/todo/src/frame.ts +17 -0
- package/templates/todo/src/page.ts +13 -6
- package/templates/todo/src/todo.ts +18 -6
- package/templates/todo/template.json +11 -1
- package/templates/todo/test/todo.test.ts +67 -9
- package/lib/src-LX0E4ec4.js +0 -117
- package/shared/SKILL.md +0 -14
package/lib/cordis/door.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { f as UiActionResult, y as UiSnapshot } from "../protocol-
|
|
2
|
-
import { i as UiChannel, r as PageStream, t as AuditLog } from "../audit-
|
|
1
|
+
import { f as UiActionResult, y as UiSnapshot } from "../protocol-BeIYCgTo.js";
|
|
2
|
+
import { i as UiChannel, r as PageStream, t as AuditLog } from "../audit-Bok_UNCn.js";
|
|
3
3
|
import { Context } from "@deepseek-ai/cordis";
|
|
4
4
|
import z from "@deepseek-ai/schemastery";
|
|
5
5
|
|
|
@@ -102,7 +102,10 @@ interface ToolsPort {
|
|
|
102
102
|
register(name: string, tool: {
|
|
103
103
|
readonly description: string;
|
|
104
104
|
readonly parameters?: Readonly<Record<string, unknown>>;
|
|
105
|
-
run(input: unknown
|
|
105
|
+
run(input: unknown, options?: {
|
|
106
|
+
signal?: AbortSignal;
|
|
107
|
+
page?: string;
|
|
108
|
+
}): unknown;
|
|
106
109
|
}): () => void;
|
|
107
110
|
list(): ReadonlyArray<{
|
|
108
111
|
readonly name: string;
|
|
@@ -121,6 +124,8 @@ interface DoorDeps {
|
|
|
121
124
|
readonly root: string;
|
|
122
125
|
readonly url?: string | undefined;
|
|
123
126
|
};
|
|
127
|
+
/** The prefix the app's pages answer under (the frame's canvas, `/app`); absent on the app's own server, at the root. */
|
|
128
|
+
readonly appBase?: string | undefined;
|
|
124
129
|
/** Read at each call: the services may come and go while the door runs. */
|
|
125
130
|
readonly extensions: () => ExtensionsPort | undefined;
|
|
126
131
|
readonly tools: () => ToolsPort | undefined;
|
|
@@ -131,6 +136,10 @@ interface DoorDeps {
|
|
|
131
136
|
/** How long a reload or a move may take before the new page has connected again (tests shorten it). Default 15 s. */
|
|
132
137
|
readonly pageBackMs?: number;
|
|
133
138
|
}
|
|
139
|
+
/** Who a verb runs for: `page`, the door's id of the page a run was asked from; its look and act go to that page alone (followed into its tab), never to another one. */
|
|
140
|
+
interface VerbScope {
|
|
141
|
+
readonly page?: string;
|
|
142
|
+
}
|
|
134
143
|
/** What one verb answered: the value for `--json` and programs, the text for an agent reading a terminal. */
|
|
135
144
|
interface VerbAnswer {
|
|
136
145
|
readonly value: unknown;
|
|
@@ -139,11 +148,13 @@ interface VerbAnswer {
|
|
|
139
148
|
declare class Door {
|
|
140
149
|
private readonly deps;
|
|
141
150
|
constructor(deps: DoorDeps);
|
|
151
|
+
/** A run asked for from the panel of this page is going: its verbs that name no window are for that page. @returns the function to call when the run ends. */
|
|
152
|
+
driveFor(windowId: string): () => void;
|
|
142
153
|
/** Run one verb. @throws DoorError or UiControlError. */
|
|
143
|
-
run(verb: string, args: unknown, signal: AbortSignal): Promise<VerbAnswer>;
|
|
154
|
+
run(verb: string, args: unknown, signal: AbortSignal, scope?: VerbScope): Promise<VerbAnswer>;
|
|
144
155
|
brief(): VerbAnswer;
|
|
145
|
-
look(input: Record<string, unknown>, signal: AbortSignal): Promise<UiSnapshot>;
|
|
146
|
-
act(input: Record<string, unknown>, signal: AbortSignal): Promise<UiActionResult>;
|
|
156
|
+
look(input: Record<string, unknown>, signal: AbortSignal, scope?: VerbScope): Promise<UiSnapshot>;
|
|
157
|
+
act(input: Record<string, unknown>, signal: AbortSignal, scope?: VerbScope): Promise<UiActionResult>;
|
|
147
158
|
/**
|
|
148
159
|
* What the app answers at a path the page was sent to, so an agent that mistyped one is told ("404 at /nope") and not left to find out from a page it did not expect.
|
|
149
160
|
* A second GET of the same path (a page is read-only); nothing when the app has no address or does not answer in time.
|
|
@@ -172,6 +183,8 @@ declare class Door {
|
|
|
172
183
|
* MCP (`tools/list`) and the built-in chat (the `tools` registry). A verb added here is in all three, or the comparison test fails.
|
|
173
184
|
*/
|
|
174
185
|
/** Every verb, in the order `brief` lists them. */
|
|
186
|
+
/** The verbs that only use the page: what a page-only door (a production assistant) offers. */
|
|
187
|
+
declare const PAGE_VERBS: readonly ["look", "act"];
|
|
175
188
|
declare const VERBS: readonly ["brief", "look", "act", "plugin-list", "plugin-add", "plugin-remove", "plugin-reload", "tool-list", "tool-call", "window-list", "window-open", "window-focus", "window-close", "window-resize", "menu-list", "menu-click"];
|
|
176
189
|
type Verb = (typeof VERBS)[number];
|
|
177
190
|
/** The JSON Schema of a verb's arguments, as MCP lists it. */
|
|
@@ -227,6 +240,12 @@ interface DoorFile {
|
|
|
227
240
|
declare function doorFilePath(appRoot: string): string;
|
|
228
241
|
/** The connection file as written, or undefined when there is none or it does not parse. */
|
|
229
242
|
declare function readDoorFile(appRoot: string): DoorFile | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Write this run's connection file, replacing a stale one.
|
|
245
|
+
* @throws when another live process already serves this folder's door: two apps from one folder would race for one file.
|
|
246
|
+
*/
|
|
247
|
+
/** @throws when another live process already serves this folder's door: two apps from one folder would race for one file. */
|
|
248
|
+
declare function assertDoorIsFree(appRoot: string): void;
|
|
230
249
|
//#endregion
|
|
231
250
|
//#region ../../plugins/acryl-door/src/host/operator-routes.d.ts
|
|
232
251
|
type CallResponse = {
|
|
@@ -257,12 +276,30 @@ interface Config {
|
|
|
257
276
|
* run it in production (a packaged desktop app whose user drives it with an agent) says so here; `ACRYL_DOOR=off` still wins.
|
|
258
277
|
*/
|
|
259
278
|
allowInProduction?: boolean;
|
|
279
|
+
/**
|
|
280
|
+
* Page only, for a production assistant: the page channel and two chat tools, `door_look` and `door_act`, and nothing else - no operator routes, no MCP, no desktop
|
|
281
|
+
* shell channel, no `.acryl/` file, no plugin, tool or window verbs. The app's agent can then use the page for a visitor and cannot change the app. Runs in production
|
|
282
|
+
* without `allowInProduction`; `ACRYL_DOOR=off` still wins.
|
|
283
|
+
*/
|
|
284
|
+
pageOnly?: boolean;
|
|
260
285
|
/** Reload the open pages after a live plugin change, so an agent that built a feature sees it on the page it has open. Default: true. */
|
|
261
286
|
reloadOnChange?: boolean;
|
|
287
|
+
/**
|
|
288
|
+
* Put the page script in the host's own index page (DSH's web UI) too, so an agent can drive that UI. Default: true. A host whose index is a frame
|
|
289
|
+
* around the app (the ACRYL Blends frame, whose centre shows the app's page) turns it off: the door then drives the app's page in the canvas, and an
|
|
290
|
+
* agent's `act navigate` or a reload after a plugin change never takes the person's tab out of the frame.
|
|
291
|
+
*/
|
|
292
|
+
hostIndex?: boolean;
|
|
293
|
+
/**
|
|
294
|
+
* The host prefix the app's pages are served under (the frame's canvas, `/app`); absent on the app's own server, where they are at the root. The
|
|
295
|
+
* door puts it on every page as `<meta name="acryl-app-base">`, and `act navigate` with an app path goes under it: a page the app serves at
|
|
296
|
+
* `/board` is reached at `/app/board` in the frame and at `/board` in production, and the same verb works in both.
|
|
297
|
+
*/
|
|
298
|
+
appBase?: string;
|
|
262
299
|
}
|
|
263
300
|
declare const Config: z<Config>;
|
|
264
301
|
/** The page of a path the app does not serve, development only: what is missing, a way back, and the door's script. */
|
|
265
302
|
declare function notFoundPage(path: string, scriptTag: string): string;
|
|
266
303
|
declare function apply(ctx: Context, rawConfig?: Config): void;
|
|
267
304
|
//#endregion
|
|
268
|
-
export { type CallResponse, Config, DOOR_PREFIX, Door, DoorError, type DoorFile, STATE_DIR, VERBS, VERB_SPECS, type Verb, type VerbAnswer, type VerbSpec, apply, chatToolName, doorFilePath, inject, mcpTools, name, notFoundPage, readDoorFile };
|
|
305
|
+
export { type CallResponse, Config, DOOR_PREFIX, Door, DoorError, type DoorFile, PAGE_VERBS, STATE_DIR, VERBS, VERB_SPECS, type Verb, type VerbAnswer, type VerbSpec, apply, assertDoorIsFree, chatToolName, doorFilePath, inject, mcpTools, name, notFoundPage, readDoorFile };
|
package/lib/cordis/door.js
CHANGED
|
@@ -2,16 +2,31 @@ import { t as Acryl } from "../app-CQcGWjrk.js";
|
|
|
2
2
|
import { r as streamSSE } from "../streaming-BlDaph8U.js";
|
|
3
3
|
import { r as loopbackAuthority } from "../loopback-only-BbasoF7R.js";
|
|
4
4
|
import "../helpers-BEjcdbgw.js";
|
|
5
|
-
import { n as clientModules } from "../client-modules-
|
|
5
|
+
import { n as clientModules } from "../client-modules-Bkdr83jO.js";
|
|
6
6
|
import { a as MAX_WAIT_MS, d as parseChannelToHost, l as UiControlError, p as parseUiRequest, r as MAX_SNAPSHOT_NODES, u as WINDOW_ID } from "../protocol-CQ_if7Dg.js";
|
|
7
|
-
import { a as INVALID_JSON, c as operatorOnly, d as AuditLog, f as auditPath, i as DOOR_PREFIX, l as privateApi, o as error, p as UiChannel, r as pageChannelRoutes, s as jsonBody, t as renderSnapshot, u as readJson } from "../snapshot-text-
|
|
8
|
-
import "../src-
|
|
7
|
+
import { a as INVALID_JSON, c as operatorOnly, d as AuditLog, f as auditPath, i as DOOR_PREFIX, l as privateApi, o as error, p as UiChannel, r as pageChannelRoutes, s as jsonBody, t as renderSnapshot, u as readJson } from "../snapshot-text-CXTnjxGx.js";
|
|
8
|
+
import "../src-iBJ2ysV9.js";
|
|
9
9
|
import "../middleware-BfG_fp8P.js";
|
|
10
10
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
11
11
|
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
12
12
|
import z from "@deepseek-ai/schemastery";
|
|
13
13
|
import { randomBytes } from "node:crypto";
|
|
14
14
|
import { spawnSync } from "node:child_process";
|
|
15
|
+
//#region ../../plugins/acryl-door/src/page/base.ts
|
|
16
|
+
/**
|
|
17
|
+
* `path` (an app path, optionally with a query) under `base`: '/board' under '/app' is '/app/board'; the app's root is the base itself, so '/' is
|
|
18
|
+
* '/app' (its mount) and not '/app/'; without a base, the path as written.
|
|
19
|
+
*/
|
|
20
|
+
function underAppBase(base, path) {
|
|
21
|
+
if (base === "") return path;
|
|
22
|
+
const at = path.search(/[?#]/u);
|
|
23
|
+
const route = at === -1 ? path : path.slice(0, at);
|
|
24
|
+
const rest = at === -1 ? "" : path.slice(at);
|
|
25
|
+
if (route === base || route.startsWith(`${base}/`)) return path;
|
|
26
|
+
if (route === "/" || route === "") return `${base}${rest}`;
|
|
27
|
+
return `${base}${route.startsWith("/") ? "" : "/"}${route}${rest}`;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
15
30
|
//#region ../../plugins/acryl-door/src/shell/protocol.ts
|
|
16
31
|
var ShellError = class extends Error {
|
|
17
32
|
code;
|
|
@@ -283,6 +298,8 @@ function shellRoutes(prefix, secret, channel, heartbeatMs = SHELL_HEARTBEAT_MS)
|
|
|
283
298
|
* MCP (`tools/list`) and the built-in chat (the `tools` registry). A verb added here is in all three, or the comparison test fails.
|
|
284
299
|
*/
|
|
285
300
|
/** Every verb, in the order `brief` lists them. */
|
|
301
|
+
/** The verbs that only use the page: what a page-only door (a production assistant) offers. */
|
|
302
|
+
const PAGE_VERBS = ["look", "act"];
|
|
286
303
|
const VERBS = [
|
|
287
304
|
"brief",
|
|
288
305
|
"look",
|
|
@@ -620,20 +637,24 @@ var Door = class {
|
|
|
620
637
|
constructor(deps) {
|
|
621
638
|
this.deps = deps;
|
|
622
639
|
}
|
|
640
|
+
/** A run asked for from the panel of this page is going: its verbs that name no window are for that page. @returns the function to call when the run ends. */
|
|
641
|
+
driveFor(windowId) {
|
|
642
|
+
return this.deps.channel.driveFor(windowId);
|
|
643
|
+
}
|
|
623
644
|
/** Run one verb. @throws DoorError or UiControlError. */
|
|
624
|
-
async run(verb, args, signal) {
|
|
645
|
+
async run(verb, args, signal, scope = {}) {
|
|
625
646
|
const input = typeof args === "object" && args !== null && !Array.isArray(args) ? args : {};
|
|
626
647
|
switch (verb) {
|
|
627
648
|
case "brief": return this.brief();
|
|
628
649
|
case "look": {
|
|
629
|
-
const snapshot = await this.look(input, signal);
|
|
650
|
+
const snapshot = await this.look(input, signal, scope);
|
|
630
651
|
return {
|
|
631
652
|
value: snapshot,
|
|
632
653
|
text: renderSnapshot(snapshot, (cursor) => `run look --cursor ${String(cursor)}`)
|
|
633
654
|
};
|
|
634
655
|
}
|
|
635
656
|
case "act": {
|
|
636
|
-
const result = await this.act(input, signal);
|
|
657
|
+
const result = await this.act(input, signal, scope);
|
|
637
658
|
return {
|
|
638
659
|
value: result,
|
|
639
660
|
text: `done${result.target === void 0 ? "" : `: ${result.target.role} "${result.target.name}"`}${result.detail === void 0 ? "" : ` (${result.detail})`}; look again before the next act`
|
|
@@ -690,33 +711,47 @@ var Door = class {
|
|
|
690
711
|
].join("\n")
|
|
691
712
|
};
|
|
692
713
|
}
|
|
693
|
-
look(input, signal) {
|
|
694
|
-
const { window, rest } = this.windowOf(input);
|
|
714
|
+
look(input, signal, scope = {}) {
|
|
715
|
+
const { window, rest } = this.windowOf(input, scope);
|
|
695
716
|
const request = this.parse({
|
|
696
717
|
...rest,
|
|
697
718
|
op: "snapshot"
|
|
698
719
|
});
|
|
699
|
-
return this.callPage("look", request, signal, window);
|
|
720
|
+
return this.callPage("look", request, signal, window, scope.page);
|
|
700
721
|
}
|
|
701
|
-
async act(input, signal) {
|
|
722
|
+
async act(input, signal, scope = {}) {
|
|
702
723
|
if (input.op === "snapshot") throw new DoorError("invalid", "use look to see the page");
|
|
703
|
-
const { window, rest } = this.windowOf(input);
|
|
724
|
+
const { window, rest } = this.windowOf(input, scope);
|
|
704
725
|
const request = this.parse(rest);
|
|
705
|
-
|
|
706
|
-
const
|
|
726
|
+
const page = scope.page;
|
|
727
|
+
const moves = request.op === "reload" || request.op === "navigate";
|
|
728
|
+
if (!moves && request.op !== "click" && request.op !== "press" && request.op !== "type") return await this.callPage(`act ${String(input.op)}`, request, signal, window, page);
|
|
729
|
+
const backMs = this.deps.pageBackMs ?? PAGE_BACK_MS;
|
|
730
|
+
const stay = new AbortController();
|
|
731
|
+
const back = page === void 0 ? this.deps.channel.expectNewPage(backMs, stay.signal) : this.deps.channel.expectPageBack(page, backMs, stay.signal);
|
|
707
732
|
let answer;
|
|
733
|
+
let left = moves;
|
|
708
734
|
try {
|
|
709
|
-
answer = await this.callPage(`act ${request.op}`, request, signal, window);
|
|
735
|
+
answer = await this.callPage(`act ${request.op}`, request, signal, window, page);
|
|
736
|
+
left ||= answer.leaving === true;
|
|
710
737
|
} catch (cause) {
|
|
711
|
-
if (!(cause instanceof UiControlError && cause.code === "disconnected"))
|
|
738
|
+
if (!(cause instanceof UiControlError && cause.code === "disconnected")) {
|
|
739
|
+
stay.abort();
|
|
740
|
+
throw cause;
|
|
741
|
+
}
|
|
712
742
|
answer = {
|
|
713
743
|
ok: true,
|
|
714
|
-
detail: request.op === "reload" ? "reloading" : `going to ${request.path}`
|
|
744
|
+
detail: request.op === "reload" ? "reloading" : request.op === "navigate" ? `going to ${request.path}` : "the page is going to another address"
|
|
715
745
|
};
|
|
746
|
+
left = true;
|
|
747
|
+
}
|
|
748
|
+
if (!left) {
|
|
749
|
+
stay.abort();
|
|
750
|
+
return answer;
|
|
716
751
|
}
|
|
717
752
|
const came = await back;
|
|
718
|
-
if (came !== void 0) this.deps.channel.prefer(came);
|
|
719
|
-
if (came === void 0) throw new UiControlError("timeout", request.op === "reload" ? "the page did not come back after the reload" : `the page did not come back after going to ${request.path}: is there a page at that path, and does it load the door's script?`);
|
|
753
|
+
if (came !== void 0 && page === void 0) this.deps.channel.prefer(came);
|
|
754
|
+
if (came === void 0) throw new UiControlError("timeout", request.op === "reload" ? "the page did not come back after the reload" : request.op === "navigate" ? `the page did not come back after going to ${request.path}: is there a page at that path, and does it load the door's script?` : `the ${request.op} took the page to another address, and no page came back: does the page there load the door's script?`);
|
|
720
755
|
const landed = request.op === "navigate" ? await this.statusAt(request.path) : void 0;
|
|
721
756
|
return {
|
|
722
757
|
...answer,
|
|
@@ -731,7 +766,8 @@ var Door = class {
|
|
|
731
766
|
const base = this.deps.app.url;
|
|
732
767
|
if (base === void 0) return void 0;
|
|
733
768
|
try {
|
|
734
|
-
const
|
|
769
|
+
const target = underAppBase(this.deps.appBase ?? "", path);
|
|
770
|
+
const response = await fetch(new URL(target, base), {
|
|
735
771
|
headers: { accept: "text/html" },
|
|
736
772
|
signal: AbortSignal.timeout(3e3)
|
|
737
773
|
});
|
|
@@ -796,12 +832,13 @@ var Door = class {
|
|
|
796
832
|
}
|
|
797
833
|
}
|
|
798
834
|
/** `window` on look and act: the desktop window (the number `window list` prints) whose page the call is for; without it, the page used last. */
|
|
799
|
-
windowOf(input) {
|
|
835
|
+
windowOf(input, scope = {}) {
|
|
800
836
|
const { window, ...rest } = input;
|
|
801
837
|
if (window === void 0) return {
|
|
802
838
|
window: void 0,
|
|
803
839
|
rest
|
|
804
840
|
};
|
|
841
|
+
if (scope.page !== void 0) throw new DoorError("invalid", "this run drives only the page it was asked from; window does not apply");
|
|
805
842
|
if (typeof window !== "number" || !Number.isSafeInteger(window) || window < 1) throw new DoorError("invalid", "window must be the number `window list` prints for the window");
|
|
806
843
|
return {
|
|
807
844
|
window,
|
|
@@ -816,12 +853,13 @@ var Door = class {
|
|
|
816
853
|
}
|
|
817
854
|
}
|
|
818
855
|
/** Run one call on the page and record it. The audit holds which control was touched and how it ended, never what was typed. */
|
|
819
|
-
async callPage(verb, request, signal, window) {
|
|
856
|
+
async callPage(verb, request, signal, window, page) {
|
|
820
857
|
const approval = "token";
|
|
821
858
|
try {
|
|
822
859
|
const value = await this.deps.channel.call(request, {
|
|
823
860
|
signal,
|
|
824
861
|
...window === void 0 ? {} : { window },
|
|
862
|
+
...page === void 0 ? {} : { page },
|
|
825
863
|
...request.op === "wait" ? { timeoutMs: (request.timeoutMs ?? 3e3) + 5e3 } : {}
|
|
826
864
|
});
|
|
827
865
|
const target = "target" in value ? value.target : void 0;
|
|
@@ -858,7 +896,7 @@ var Door = class {
|
|
|
858
896
|
}
|
|
859
897
|
async plugin(run, mutates = true) {
|
|
860
898
|
const extensions = this.deps.extensions();
|
|
861
|
-
if (extensions === void 0) throw new DoorError("unavailable", "this
|
|
899
|
+
if (extensions === void 0) throw new DoorError("unavailable", "this door has no extensions plugin to drive. In ACRYL's frame none is needed: a saved change in src/ or plugins/ reloads the app by itself, so do not restart it. Elsewhere, the app has no way to install plugins while it runs");
|
|
862
900
|
const value = await run(extensions);
|
|
863
901
|
const unchanged = typeof value === "object" && value !== null && value.action === "unchanged";
|
|
864
902
|
if (mutates && !unchanged && this.deps.reloadOnChange !== false) await this.deps.channel.reloadAll();
|
|
@@ -910,8 +948,8 @@ var Door = class {
|
|
|
910
948
|
* `door_<verb>`. A tool answers the verb's text, what an agent reads in a terminal; a failed verb throws with its code, as the operator
|
|
911
949
|
* client prints it.
|
|
912
950
|
*/
|
|
913
|
-
/** Register every
|
|
914
|
-
function registerChatTools(tools, door) {
|
|
951
|
+
/** Register the verbs (default: every one). @returns the function that removes them all; it also aborts the calls still running. */
|
|
952
|
+
function registerChatTools(tools, door, verbs = VERBS) {
|
|
915
953
|
const running = new AbortController();
|
|
916
954
|
const removers = [];
|
|
917
955
|
const removeAll = () => {
|
|
@@ -919,12 +957,13 @@ function registerChatTools(tools, door) {
|
|
|
919
957
|
for (const remove of removers.splice(0).reverse()) remove();
|
|
920
958
|
};
|
|
921
959
|
try {
|
|
922
|
-
for (const verb of
|
|
960
|
+
for (const verb of verbs) removers.push(tools.register(chatToolName(verb), {
|
|
923
961
|
description: VERB_SPECS[verb].description,
|
|
924
962
|
parameters: VERB_SPECS[verb].arguments,
|
|
925
|
-
run: async (input) => {
|
|
963
|
+
run: async (input, options) => {
|
|
964
|
+
const signal = options?.signal === void 0 ? running.signal : AbortSignal.any([running.signal, options.signal]);
|
|
926
965
|
try {
|
|
927
|
-
return (await door.run(verb, input ?? {},
|
|
966
|
+
return (await door.run(verb, input ?? {}, signal, options?.page === void 0 ? {} : { page: options.page })).text;
|
|
928
967
|
} catch (cause) {
|
|
929
968
|
if (cause instanceof DoorError || cause instanceof UiControlError) throw new Error(`${cause.code}: ${cause.message}`, { cause });
|
|
930
969
|
throw cause;
|
|
@@ -993,10 +1032,14 @@ function alive(pid) {
|
|
|
993
1032
|
* Write this run's connection file, replacing a stale one.
|
|
994
1033
|
* @throws when another live process already serves this folder's door: two apps from one folder would race for one file.
|
|
995
1034
|
*/
|
|
996
|
-
|
|
997
|
-
|
|
1035
|
+
/** @throws when another live process already serves this folder's door: two apps from one folder would race for one file. */
|
|
1036
|
+
function assertDoorIsFree(appRoot) {
|
|
998
1037
|
const existing = readDoorFile(appRoot);
|
|
999
1038
|
if (existing !== void 0 && existing.pid !== process.pid && alive(existing.pid)) throw new Error(`acryl-door: another process (pid ${String(existing.pid)}) serves the door of ${appRoot}; stop it first`);
|
|
1039
|
+
}
|
|
1040
|
+
function writeDoorFile(appRoot, url, secret) {
|
|
1041
|
+
const dir = ensureStateDir(appRoot);
|
|
1042
|
+
assertDoorIsFree(appRoot);
|
|
1000
1043
|
const file = doorFilePath(appRoot);
|
|
1001
1044
|
const temporary = join(dir, `${DOOR_FILE}.${String(process.pid)}.tmp`);
|
|
1002
1045
|
const content = {
|
|
@@ -1167,11 +1210,13 @@ const ownOrigin = async (c, next) => {
|
|
|
1167
1210
|
};
|
|
1168
1211
|
function pageSocketRoutes(channel, options) {
|
|
1169
1212
|
const heartbeatMs = options.heartbeatMs ?? 15e3;
|
|
1170
|
-
|
|
1213
|
+
const events = (c) => {
|
|
1171
1214
|
const windowId = c.req.query("window");
|
|
1172
1215
|
const focused = c.req.query("focused") === "1";
|
|
1173
1216
|
const shellQuery = Number(c.req.query("shell"));
|
|
1174
1217
|
const shellWindow = Number.isSafeInteger(shellQuery) && shellQuery > 0 ? shellQuery : void 0;
|
|
1218
|
+
const tabQuery = c.req.query("tab");
|
|
1219
|
+
const tab = tabQuery !== void 0 && WINDOW_ID.test(tabQuery) ? tabQuery : void 0;
|
|
1175
1220
|
let detach;
|
|
1176
1221
|
let beat;
|
|
1177
1222
|
return {
|
|
@@ -1186,10 +1231,16 @@ function pageSocketRoutes(channel, options) {
|
|
|
1186
1231
|
d: data
|
|
1187
1232
|
});
|
|
1188
1233
|
},
|
|
1234
|
+
notify: (event, data) => {
|
|
1235
|
+
write({
|
|
1236
|
+
e: event,
|
|
1237
|
+
d: data
|
|
1238
|
+
});
|
|
1239
|
+
},
|
|
1189
1240
|
close: () => {
|
|
1190
1241
|
ws.close(1e3, "replaced");
|
|
1191
1242
|
}
|
|
1192
|
-
}, shellWindow);
|
|
1243
|
+
}, shellWindow, tab);
|
|
1193
1244
|
write({ e: "ready" });
|
|
1194
1245
|
beat = setInterval(() => {
|
|
1195
1246
|
try {
|
|
@@ -1213,7 +1264,12 @@ function pageSocketRoutes(channel, options) {
|
|
|
1213
1264
|
detach?.();
|
|
1214
1265
|
}
|
|
1215
1266
|
};
|
|
1216
|
-
}
|
|
1267
|
+
};
|
|
1268
|
+
return new Acryl().get(`${options.prefix}/channel/ws`, ownOrigin, async (c, next) => {
|
|
1269
|
+
const allow = options.upgrade();
|
|
1270
|
+
if (allow === void 0) return c.json(error("the page channel is not ready yet"), 503);
|
|
1271
|
+
return allow(events, { textOnly: true })(c, next);
|
|
1272
|
+
});
|
|
1217
1273
|
}
|
|
1218
1274
|
/** The oldest Node the client runs on (the framework's own floor). */
|
|
1219
1275
|
const MIN_NODE = [22, 19];
|
|
@@ -1333,14 +1389,13 @@ function writeShims(root, target) {
|
|
|
1333
1389
|
*/
|
|
1334
1390
|
/** Stable Cordis plugin name, equal to the package name and the Loader row id. */
|
|
1335
1391
|
const name = "acryl-door";
|
|
1336
|
-
const inject = [
|
|
1337
|
-
"router",
|
|
1338
|
-
"appInstance",
|
|
1339
|
-
"nodeServer"
|
|
1340
|
-
];
|
|
1392
|
+
const inject = ["router", "appInstance"];
|
|
1341
1393
|
const Config = z.object({
|
|
1342
1394
|
allowInProduction: z.boolean().default(false).description("Run in production too (NODE_ENV=production); ACRYL_DOOR=off still turns it off."),
|
|
1395
|
+
pageOnly: z.boolean().default(false).description("Only the page and the look and act chat tools (a production assistant); runs in production."),
|
|
1343
1396
|
reloadOnChange: z.boolean().default(true).description("Reload the open pages after a plugin was added, removed or reloaded while the app runs."),
|
|
1397
|
+
hostIndex: z.boolean().default(true).description("Put the page script in the host's own index page too; off when that index is a frame around the app."),
|
|
1398
|
+
appBase: z.string().default("").description("The prefix the app pages are served under (the frame canvas), without a trailing slash; empty at the root."),
|
|
1344
1399
|
tools: z.object({ expose: z.array(z.string().pattern(/^(?!door_)[A-Za-z][A-Za-z0-9_-]{0,63}$/u)).description("App tools (from the tools registry) the door offers; none by default.") })
|
|
1345
1400
|
});
|
|
1346
1401
|
/** The page module, served compiled from source by the app's own TypeScript. */
|
|
@@ -1372,25 +1427,51 @@ function notFoundPage(path, scriptTag) {
|
|
|
1372
1427
|
}
|
|
1373
1428
|
function apply(ctx, rawConfig = {}) {
|
|
1374
1429
|
const config = Config(rawConfig);
|
|
1375
|
-
|
|
1430
|
+
const pageOnly = config.pageOnly === true;
|
|
1431
|
+
if (process.env.ACRYL_DOOR === "off" || process.env.NODE_ENV === "production" && config.allowInProduction !== true && !pageOnly) return;
|
|
1376
1432
|
const app = ctx.get("appInstance");
|
|
1377
|
-
const
|
|
1433
|
+
const carrier = () => {
|
|
1434
|
+
const web = ctx.get("acrylWeb");
|
|
1435
|
+
if (web !== void 0) return web;
|
|
1436
|
+
const node = ctx.get("nodeServer");
|
|
1437
|
+
if (typeof node?.url !== "string") return void 0;
|
|
1438
|
+
try {
|
|
1439
|
+
const parsed = new URL(node.url);
|
|
1440
|
+
return {
|
|
1441
|
+
host: parsed.hostname,
|
|
1442
|
+
port: Number(parsed.port)
|
|
1443
|
+
};
|
|
1444
|
+
} catch {
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1378
1448
|
if (typeof app?.root !== "string") throw new Error("acryl-door: the appInstance service has no app folder (root)");
|
|
1379
1449
|
const reportError = (operation, cause) => {
|
|
1380
1450
|
ctx.logger?.error?.(`acryl-door: failed to ${operation}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
1381
1451
|
};
|
|
1452
|
+
const address = { url: "" };
|
|
1453
|
+
if (!pageOnly) assertDoorIsFree(app.root);
|
|
1382
1454
|
const secret = newSecret();
|
|
1383
|
-
const channel = new UiChannel({
|
|
1455
|
+
const channel = new UiChannel({
|
|
1456
|
+
attachWaitMs: 2e3,
|
|
1457
|
+
requirePage: pageOnly
|
|
1458
|
+
});
|
|
1384
1459
|
const shell = new ShellChannel();
|
|
1460
|
+
const audit = new AuditLog(auditPath(stateDir(app.root)));
|
|
1461
|
+
const rawBase = typeof config.appBase === "string" ? config.appBase.trim() : "";
|
|
1462
|
+
const appBase = rawBase.startsWith("/") && rawBase !== "/" ? rawBase.replace(/\/+$/u, "") : "";
|
|
1385
1463
|
const door = new Door({
|
|
1386
1464
|
channel,
|
|
1387
1465
|
shell,
|
|
1388
|
-
audit
|
|
1466
|
+
audit,
|
|
1389
1467
|
app: {
|
|
1390
1468
|
name: app.name,
|
|
1391
1469
|
root: app.root,
|
|
1392
|
-
url
|
|
1470
|
+
get url() {
|
|
1471
|
+
return address.url;
|
|
1472
|
+
}
|
|
1393
1473
|
},
|
|
1474
|
+
...appBase === "" ? {} : { appBase },
|
|
1394
1475
|
extensions: () => ctx.get("extensions"),
|
|
1395
1476
|
tools: () => ctx.get("tools"),
|
|
1396
1477
|
expose: config.tools?.expose ?? [],
|
|
@@ -1402,8 +1483,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1402
1483
|
ctx.effect(() => () => {
|
|
1403
1484
|
shell.close();
|
|
1404
1485
|
}, "acryl-door: desktop shell channel");
|
|
1405
|
-
const pageModule = new Acryl().get(`${DOOR_PREFIX}/page.js`, (c) => c.body(`import '${DOOR_PREFIX}/page/main.ts'\n`, 200, { "content-type": "text/javascript; charset=utf-8" })).route(`${DOOR_PREFIX}/page`, clientModules({
|
|
1486
|
+
const pageModule = new Acryl().get(`${DOOR_PREFIX}/page.js`, (c) => c.body(`import '${DOOR_PREFIX}/page/main.ts'\n`, 200, { "content-type": "text/javascript; charset=utf-8" })).route(`${DOOR_PREFIX}/page`, clientModules({
|
|
1487
|
+
root: PAGE_DIR,
|
|
1488
|
+
mount: `${DOOR_PREFIX}/page`
|
|
1489
|
+
}));
|
|
1406
1490
|
const tag = `<script type="module" src="${DOOR_PREFIX}/page.js"><\/script>`;
|
|
1491
|
+
const meta = appBase === "" ? "" : `<meta name="acryl-app-base" content="${appBase}">`;
|
|
1407
1492
|
const addScript = async (c, next) => {
|
|
1408
1493
|
await next();
|
|
1409
1494
|
if (!(c.res.headers.get("content-type") ?? "").includes("text/html")) {
|
|
@@ -1413,11 +1498,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1413
1498
|
});
|
|
1414
1499
|
return;
|
|
1415
1500
|
}
|
|
1416
|
-
|
|
1501
|
+
let html = await c.res.text();
|
|
1417
1502
|
const headers = new Headers(c.res.headers);
|
|
1418
1503
|
headers.delete("content-length");
|
|
1419
|
-
|
|
1420
|
-
|
|
1504
|
+
if (meta !== "" && !html.includes("name=\"acryl-app-base\"")) html = html.includes("</head>") ? html.replace("</head>", `${meta}</head>`) : meta + html;
|
|
1505
|
+
if (!html.includes(`/api/acryl-door/page.js`)) html = html.includes("</body>") ? html.replace("</body>", `${tag}</body>`) : html + tag;
|
|
1506
|
+
c.res = new Response(html, {
|
|
1421
1507
|
status: c.res.status,
|
|
1422
1508
|
headers
|
|
1423
1509
|
});
|
|
@@ -1425,31 +1511,99 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1425
1511
|
const router = ctx.router;
|
|
1426
1512
|
if (typeof router.wrap === "function") router.wrap(addScript);
|
|
1427
1513
|
else ctx.router.route("/", new Acryl().use("*", addScript));
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1514
|
+
if (config.hostIndex !== false) ctx.inject(["webServer"], (inner) => {
|
|
1515
|
+
inner.effect(() => {
|
|
1516
|
+
const taps = inner.get("webServer");
|
|
1517
|
+
if (typeof taps?.tapIndex !== "function") return () => {};
|
|
1518
|
+
return taps.tapIndex((html) => {
|
|
1519
|
+
if (html.includes(`/api/acryl-door/page.js`)) return html;
|
|
1520
|
+
return html.includes("</body>") ? html.replace("</body>", `${tag}</body>`) : html + tag;
|
|
1521
|
+
});
|
|
1522
|
+
}, "acryl-door: the page script in the host index");
|
|
1523
|
+
});
|
|
1524
|
+
let pageUpgrade;
|
|
1525
|
+
let nodeUpgrade;
|
|
1526
|
+
const endNodeOwner = () => {
|
|
1527
|
+
if (pageUpgrade === nodeUpgrade) pageUpgrade = void 0;
|
|
1528
|
+
nodeUpgrade = void 0;
|
|
1529
|
+
};
|
|
1530
|
+
const nodeFallback = () => {
|
|
1531
|
+
if (ctx.get("routerHttp") !== void 0 || nodeUpgrade !== void 0) return;
|
|
1532
|
+
try {
|
|
1533
|
+
const allow = ctx.get("nodeServer")?.upgrades?.();
|
|
1534
|
+
if (allow !== void 0) {
|
|
1535
|
+
nodeUpgrade = allow;
|
|
1536
|
+
pageUpgrade = allow;
|
|
1537
|
+
}
|
|
1538
|
+
} catch (cause) {
|
|
1539
|
+
reportError("open the page channel over a WebSocket (the pages use the event stream)", cause);
|
|
1540
|
+
}
|
|
1541
|
+
};
|
|
1542
|
+
ctx.inject(["routerHttp"], (inner) => {
|
|
1543
|
+
endNodeOwner();
|
|
1544
|
+
const http = inner.get("routerHttp");
|
|
1545
|
+
try {
|
|
1546
|
+
const allow = http?.upgrades?.();
|
|
1547
|
+
if (allow === void 0 || http === void 0 || typeof http.mount !== "function") return;
|
|
1548
|
+
pageUpgrade = allow;
|
|
1549
|
+
const remove = http.mount(DOOR_PREFIX, { upgrade: [`${DOOR_PREFIX}/channel/ws`] });
|
|
1550
|
+
inner.effect(() => () => {
|
|
1551
|
+
remove();
|
|
1552
|
+
if (pageUpgrade === allow) pageUpgrade = void 0;
|
|
1553
|
+
nodeFallback();
|
|
1554
|
+
}, "acryl-door: the page socket via routerHttp");
|
|
1555
|
+
} catch (cause) {
|
|
1556
|
+
reportError("open the page channel over a WebSocket (the pages use the event stream)", cause);
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
ctx.inject(["nodeServer"], (inner) => {
|
|
1560
|
+
inner.effect(() => {
|
|
1561
|
+
nodeFallback();
|
|
1562
|
+
const onService = inner.on;
|
|
1563
|
+
const off = onService("internal/service", () => {
|
|
1564
|
+
if (ctx.get("routerHttp") !== void 0) endNodeOwner();
|
|
1565
|
+
else nodeFallback();
|
|
1566
|
+
});
|
|
1567
|
+
return () => {
|
|
1568
|
+
off();
|
|
1569
|
+
endNodeOwner();
|
|
1570
|
+
};
|
|
1571
|
+
}, "acryl-door: the page socket on the node server");
|
|
1572
|
+
});
|
|
1573
|
+
ctx.router.route("/", pageSocketRoutes(channel, {
|
|
1435
1574
|
prefix: DOOR_PREFIX,
|
|
1436
|
-
upgrade
|
|
1437
|
-
})
|
|
1575
|
+
upgrade: () => pageUpgrade
|
|
1576
|
+
}));
|
|
1577
|
+
ctx.router.route("/", privateApi(DOOR_PREFIX, pageModule, pageChannelRoutes(channel, { prefix: DOOR_PREFIX }), ...pageOnly ? [] : [
|
|
1578
|
+
shellRoutes(DOOR_PREFIX, secret, shell),
|
|
1579
|
+
operatorRoutes(DOOR_PREFIX, secret, door, reportError),
|
|
1580
|
+
mcpRoutes(DOOR_PREFIX, secret, door, reportError)
|
|
1581
|
+
]));
|
|
1438
1582
|
ctx.inject(["tools"], (inner) => {
|
|
1439
|
-
inner.effect(() => registerChatTools(inner.get("tools"), door), "acryl-door: the verbs in the tools registry");
|
|
1583
|
+
inner.effect(() => registerChatTools(inner.get("tools"), door, pageOnly ? PAGE_VERBS : VERBS), "acryl-door: the verbs in the tools registry");
|
|
1440
1584
|
});
|
|
1441
1585
|
ctx.effect(function* () {
|
|
1442
1586
|
yield ctx.reflect.provide("door", door);
|
|
1443
|
-
|
|
1587
|
+
}, "acryl-door: the door service");
|
|
1588
|
+
if (pageOnly) return;
|
|
1589
|
+
ctx.effect(async () => {
|
|
1590
|
+
let bound = carrier();
|
|
1591
|
+
for (let at = 0; at < 500 && (bound === void 0 || !(bound.port > 0)); at += 1) {
|
|
1592
|
+
await new Promise((done) => setTimeout(done, 10));
|
|
1593
|
+
bound = carrier();
|
|
1594
|
+
}
|
|
1595
|
+
if (bound === void 0) throw new Error("acryl-door: no carrier bound the app (neither acrylWeb nor nodeServer answered)");
|
|
1596
|
+
address.url = loopbackUrl(`http://${bound.host}:${String(bound.port)}`);
|
|
1597
|
+
writeDoorFile(app.root, address.url, secret);
|
|
1444
1598
|
try {
|
|
1445
1599
|
writeShims(app.root, shimTarget());
|
|
1446
1600
|
} catch (cause) {
|
|
1447
1601
|
reportError("write .acryl/bin", cause);
|
|
1448
1602
|
}
|
|
1449
|
-
|
|
1603
|
+
return () => {
|
|
1450
1604
|
removeDoorFile(app.root, secret);
|
|
1451
1605
|
};
|
|
1452
|
-
}, "acryl-door:
|
|
1606
|
+
}, "acryl-door: .acryl/door.json and .acryl/bin/acryl");
|
|
1453
1607
|
}
|
|
1454
1608
|
//#endregion
|
|
1455
|
-
export { Config, DOOR_PREFIX, Door, DoorError, STATE_DIR, VERBS, VERB_SPECS, apply, chatToolName, doorFilePath, inject, mcpTools, name, notFoundPage, readDoorFile };
|
|
1609
|
+
export { Config, DOOR_PREFIX, Door, DoorError, PAGE_VERBS, STATE_DIR, VERBS, VERB_SPECS, apply, assertDoorIsFree, chatToolName, doorFilePath, inject, mcpTools, name, notFoundPage, readDoorFile };
|
package/lib/cordis/inspect.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as Acryl } from "../app-CQcGWjrk.js";
|
|
2
2
|
import { i as loopbackOnly } from "../loopback-only-BbasoF7R.js";
|
|
3
|
-
import "../src-
|
|
3
|
+
import "../src-iBJ2ysV9.js";
|
|
4
4
|
import "../middleware-BfG_fp8P.js";
|
|
5
5
|
import { Service } from "@deepseek-ai/cordis";
|
|
6
6
|
//#region ../../plugins/acryl-inspect/src/report.ts
|