acrylblends 1.1.0 → 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 +45 -1
- package/dist/index.js +1980 -27
- package/dist/index.js.map +1 -1
- package/docs/framework/agents/index.md +1 -1
- package/docs/framework/getting-started/desktop.md +23 -4
- package/docs/framework/guides/create-acrylblends.md +1 -1
- package/docs/framework/workshop/README.md +138 -152
- package/docs/framework/workshop/facilitator.md +69 -101
- 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-BFpULBCj.d.ts → audit-Bok_UNCn.d.ts} +26 -3
- package/lib/{client-modules-drj4mjhj.js → client-modules-Bkdr83jO.js} +1 -1
- package/lib/cordis/door.d.ts +42 -7
- package/lib/cordis/door.js +204 -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.js +1 -1
- package/lib/door/host.d.ts +2 -2
- package/lib/door/host.js +1 -1
- package/lib/door/page.d.ts +10 -1
- package/lib/door/page.js +46 -7
- 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-BwM6T2nG.js → snapshot-text-CXTnjxGx.js} +87 -7
- 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 +86 -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 +53 -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 +3 -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 +32 -4
- package/plugins/acryl-door/src/page/driver/snapshot.ts +5 -2
- package/plugins/acryl-door/src/page/index.ts +41 -2
- 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-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 +238 -26
- package/plugins/agent-panel/drivers.ts +7 -2
- package/plugins/agent-panel/headless.ts +5 -2
- package/plugins/agent-panel/index.ts +146 -57
- 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 +6 -0
- 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 +1 -1
- 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 +38 -19
- package/templates/agent/template.json +2 -0
- package/templates/agent/test/app.test.ts +45 -3
- 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/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/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/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;
|
|
@@ -142,10 +151,10 @@ declare class Door {
|
|
|
142
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. */
|
|
143
152
|
driveFor(windowId: string): () => void;
|
|
144
153
|
/** Run one verb. @throws DoorError or UiControlError. */
|
|
145
|
-
run(verb: string, args: unknown, signal: AbortSignal): Promise<VerbAnswer>;
|
|
154
|
+
run(verb: string, args: unknown, signal: AbortSignal, scope?: VerbScope): Promise<VerbAnswer>;
|
|
146
155
|
brief(): VerbAnswer;
|
|
147
|
-
look(input: Record<string, unknown>, signal: AbortSignal): Promise<UiSnapshot>;
|
|
148
|
-
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>;
|
|
149
158
|
/**
|
|
150
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.
|
|
151
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.
|
|
@@ -174,6 +183,8 @@ declare class Door {
|
|
|
174
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.
|
|
175
184
|
*/
|
|
176
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"];
|
|
177
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"];
|
|
178
189
|
type Verb = (typeof VERBS)[number];
|
|
179
190
|
/** The JSON Schema of a verb's arguments, as MCP lists it. */
|
|
@@ -229,6 +240,12 @@ interface DoorFile {
|
|
|
229
240
|
declare function doorFilePath(appRoot: string): string;
|
|
230
241
|
/** The connection file as written, or undefined when there is none or it does not parse. */
|
|
231
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;
|
|
232
249
|
//#endregion
|
|
233
250
|
//#region ../../plugins/acryl-door/src/host/operator-routes.d.ts
|
|
234
251
|
type CallResponse = {
|
|
@@ -259,12 +276,30 @@ interface Config {
|
|
|
259
276
|
* run it in production (a packaged desktop app whose user drives it with an agent) says so here; `ACRYL_DOOR=off` still wins.
|
|
260
277
|
*/
|
|
261
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;
|
|
262
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. */
|
|
263
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;
|
|
264
299
|
}
|
|
265
300
|
declare const Config: z<Config>;
|
|
266
301
|
/** The page of a path the app does not serve, development only: what is missing, a way back, and the door's script. */
|
|
267
302
|
declare function notFoundPage(path: string, scriptTag: string): string;
|
|
268
303
|
declare function apply(ctx: Context, rawConfig?: Config): void;
|
|
269
304
|
//#endregion
|
|
270
|
-
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",
|
|
@@ -625,19 +642,19 @@ var Door = class {
|
|
|
625
642
|
return this.deps.channel.driveFor(windowId);
|
|
626
643
|
}
|
|
627
644
|
/** Run one verb. @throws DoorError or UiControlError. */
|
|
628
|
-
async run(verb, args, signal) {
|
|
645
|
+
async run(verb, args, signal, scope = {}) {
|
|
629
646
|
const input = typeof args === "object" && args !== null && !Array.isArray(args) ? args : {};
|
|
630
647
|
switch (verb) {
|
|
631
648
|
case "brief": return this.brief();
|
|
632
649
|
case "look": {
|
|
633
|
-
const snapshot = await this.look(input, signal);
|
|
650
|
+
const snapshot = await this.look(input, signal, scope);
|
|
634
651
|
return {
|
|
635
652
|
value: snapshot,
|
|
636
653
|
text: renderSnapshot(snapshot, (cursor) => `run look --cursor ${String(cursor)}`)
|
|
637
654
|
};
|
|
638
655
|
}
|
|
639
656
|
case "act": {
|
|
640
|
-
const result = await this.act(input, signal);
|
|
657
|
+
const result = await this.act(input, signal, scope);
|
|
641
658
|
return {
|
|
642
659
|
value: result,
|
|
643
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`
|
|
@@ -694,33 +711,47 @@ var Door = class {
|
|
|
694
711
|
].join("\n")
|
|
695
712
|
};
|
|
696
713
|
}
|
|
697
|
-
look(input, signal) {
|
|
698
|
-
const { window, rest } = this.windowOf(input);
|
|
714
|
+
look(input, signal, scope = {}) {
|
|
715
|
+
const { window, rest } = this.windowOf(input, scope);
|
|
699
716
|
const request = this.parse({
|
|
700
717
|
...rest,
|
|
701
718
|
op: "snapshot"
|
|
702
719
|
});
|
|
703
|
-
return this.callPage("look", request, signal, window);
|
|
720
|
+
return this.callPage("look", request, signal, window, scope.page);
|
|
704
721
|
}
|
|
705
|
-
async act(input, signal) {
|
|
722
|
+
async act(input, signal, scope = {}) {
|
|
706
723
|
if (input.op === "snapshot") throw new DoorError("invalid", "use look to see the page");
|
|
707
|
-
const { window, rest } = this.windowOf(input);
|
|
724
|
+
const { window, rest } = this.windowOf(input, scope);
|
|
708
725
|
const request = this.parse(rest);
|
|
709
|
-
|
|
710
|
-
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);
|
|
711
732
|
let answer;
|
|
733
|
+
let left = moves;
|
|
712
734
|
try {
|
|
713
|
-
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;
|
|
714
737
|
} catch (cause) {
|
|
715
|
-
if (!(cause instanceof UiControlError && cause.code === "disconnected"))
|
|
738
|
+
if (!(cause instanceof UiControlError && cause.code === "disconnected")) {
|
|
739
|
+
stay.abort();
|
|
740
|
+
throw cause;
|
|
741
|
+
}
|
|
716
742
|
answer = {
|
|
717
743
|
ok: true,
|
|
718
|
-
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"
|
|
719
745
|
};
|
|
746
|
+
left = true;
|
|
747
|
+
}
|
|
748
|
+
if (!left) {
|
|
749
|
+
stay.abort();
|
|
750
|
+
return answer;
|
|
720
751
|
}
|
|
721
752
|
const came = await back;
|
|
722
|
-
if (came !== void 0) this.deps.channel.prefer(came);
|
|
723
|
-
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?`);
|
|
724
755
|
const landed = request.op === "navigate" ? await this.statusAt(request.path) : void 0;
|
|
725
756
|
return {
|
|
726
757
|
...answer,
|
|
@@ -735,7 +766,8 @@ var Door = class {
|
|
|
735
766
|
const base = this.deps.app.url;
|
|
736
767
|
if (base === void 0) return void 0;
|
|
737
768
|
try {
|
|
738
|
-
const
|
|
769
|
+
const target = underAppBase(this.deps.appBase ?? "", path);
|
|
770
|
+
const response = await fetch(new URL(target, base), {
|
|
739
771
|
headers: { accept: "text/html" },
|
|
740
772
|
signal: AbortSignal.timeout(3e3)
|
|
741
773
|
});
|
|
@@ -800,12 +832,13 @@ var Door = class {
|
|
|
800
832
|
}
|
|
801
833
|
}
|
|
802
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. */
|
|
803
|
-
windowOf(input) {
|
|
835
|
+
windowOf(input, scope = {}) {
|
|
804
836
|
const { window, ...rest } = input;
|
|
805
837
|
if (window === void 0) return {
|
|
806
838
|
window: void 0,
|
|
807
839
|
rest
|
|
808
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");
|
|
809
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");
|
|
810
843
|
return {
|
|
811
844
|
window,
|
|
@@ -820,12 +853,13 @@ var Door = class {
|
|
|
820
853
|
}
|
|
821
854
|
}
|
|
822
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. */
|
|
823
|
-
async callPage(verb, request, signal, window) {
|
|
856
|
+
async callPage(verb, request, signal, window, page) {
|
|
824
857
|
const approval = "token";
|
|
825
858
|
try {
|
|
826
859
|
const value = await this.deps.channel.call(request, {
|
|
827
860
|
signal,
|
|
828
861
|
...window === void 0 ? {} : { window },
|
|
862
|
+
...page === void 0 ? {} : { page },
|
|
829
863
|
...request.op === "wait" ? { timeoutMs: (request.timeoutMs ?? 3e3) + 5e3 } : {}
|
|
830
864
|
});
|
|
831
865
|
const target = "target" in value ? value.target : void 0;
|
|
@@ -862,7 +896,7 @@ var Door = class {
|
|
|
862
896
|
}
|
|
863
897
|
async plugin(run, mutates = true) {
|
|
864
898
|
const extensions = this.deps.extensions();
|
|
865
|
-
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");
|
|
866
900
|
const value = await run(extensions);
|
|
867
901
|
const unchanged = typeof value === "object" && value !== null && value.action === "unchanged";
|
|
868
902
|
if (mutates && !unchanged && this.deps.reloadOnChange !== false) await this.deps.channel.reloadAll();
|
|
@@ -914,8 +948,8 @@ var Door = class {
|
|
|
914
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
|
|
915
949
|
* client prints it.
|
|
916
950
|
*/
|
|
917
|
-
/** Register every
|
|
918
|
-
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) {
|
|
919
953
|
const running = new AbortController();
|
|
920
954
|
const removers = [];
|
|
921
955
|
const removeAll = () => {
|
|
@@ -923,12 +957,13 @@ function registerChatTools(tools, door) {
|
|
|
923
957
|
for (const remove of removers.splice(0).reverse()) remove();
|
|
924
958
|
};
|
|
925
959
|
try {
|
|
926
|
-
for (const verb of
|
|
960
|
+
for (const verb of verbs) removers.push(tools.register(chatToolName(verb), {
|
|
927
961
|
description: VERB_SPECS[verb].description,
|
|
928
962
|
parameters: VERB_SPECS[verb].arguments,
|
|
929
|
-
run: async (input) => {
|
|
963
|
+
run: async (input, options) => {
|
|
964
|
+
const signal = options?.signal === void 0 ? running.signal : AbortSignal.any([running.signal, options.signal]);
|
|
930
965
|
try {
|
|
931
|
-
return (await door.run(verb, input ?? {},
|
|
966
|
+
return (await door.run(verb, input ?? {}, signal, options?.page === void 0 ? {} : { page: options.page })).text;
|
|
932
967
|
} catch (cause) {
|
|
933
968
|
if (cause instanceof DoorError || cause instanceof UiControlError) throw new Error(`${cause.code}: ${cause.message}`, { cause });
|
|
934
969
|
throw cause;
|
|
@@ -997,10 +1032,14 @@ function alive(pid) {
|
|
|
997
1032
|
* Write this run's connection file, replacing a stale one.
|
|
998
1033
|
* @throws when another live process already serves this folder's door: two apps from one folder would race for one file.
|
|
999
1034
|
*/
|
|
1000
|
-
|
|
1001
|
-
|
|
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) {
|
|
1002
1037
|
const existing = readDoorFile(appRoot);
|
|
1003
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);
|
|
1004
1043
|
const file = doorFilePath(appRoot);
|
|
1005
1044
|
const temporary = join(dir, `${DOOR_FILE}.${String(process.pid)}.tmp`);
|
|
1006
1045
|
const content = {
|
|
@@ -1171,11 +1210,13 @@ const ownOrigin = async (c, next) => {
|
|
|
1171
1210
|
};
|
|
1172
1211
|
function pageSocketRoutes(channel, options) {
|
|
1173
1212
|
const heartbeatMs = options.heartbeatMs ?? 15e3;
|
|
1174
|
-
|
|
1213
|
+
const events = (c) => {
|
|
1175
1214
|
const windowId = c.req.query("window");
|
|
1176
1215
|
const focused = c.req.query("focused") === "1";
|
|
1177
1216
|
const shellQuery = Number(c.req.query("shell"));
|
|
1178
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;
|
|
1179
1220
|
let detach;
|
|
1180
1221
|
let beat;
|
|
1181
1222
|
return {
|
|
@@ -1199,7 +1240,7 @@ function pageSocketRoutes(channel, options) {
|
|
|
1199
1240
|
close: () => {
|
|
1200
1241
|
ws.close(1e3, "replaced");
|
|
1201
1242
|
}
|
|
1202
|
-
}, shellWindow);
|
|
1243
|
+
}, shellWindow, tab);
|
|
1203
1244
|
write({ e: "ready" });
|
|
1204
1245
|
beat = setInterval(() => {
|
|
1205
1246
|
try {
|
|
@@ -1223,7 +1264,12 @@ function pageSocketRoutes(channel, options) {
|
|
|
1223
1264
|
detach?.();
|
|
1224
1265
|
}
|
|
1225
1266
|
};
|
|
1226
|
-
}
|
|
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
|
+
});
|
|
1227
1273
|
}
|
|
1228
1274
|
/** The oldest Node the client runs on (the framework's own floor). */
|
|
1229
1275
|
const MIN_NODE = [22, 19];
|
|
@@ -1343,14 +1389,13 @@ function writeShims(root, target) {
|
|
|
1343
1389
|
*/
|
|
1344
1390
|
/** Stable Cordis plugin name, equal to the package name and the Loader row id. */
|
|
1345
1391
|
const name = "acryl-door";
|
|
1346
|
-
const inject = [
|
|
1347
|
-
"router",
|
|
1348
|
-
"appInstance",
|
|
1349
|
-
"nodeServer"
|
|
1350
|
-
];
|
|
1392
|
+
const inject = ["router", "appInstance"];
|
|
1351
1393
|
const Config = z.object({
|
|
1352
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."),
|
|
1353
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."),
|
|
1354
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.") })
|
|
1355
1400
|
});
|
|
1356
1401
|
/** The page module, served compiled from source by the app's own TypeScript. */
|
|
@@ -1382,25 +1427,51 @@ function notFoundPage(path, scriptTag) {
|
|
|
1382
1427
|
}
|
|
1383
1428
|
function apply(ctx, rawConfig = {}) {
|
|
1384
1429
|
const config = Config(rawConfig);
|
|
1385
|
-
|
|
1430
|
+
const pageOnly = config.pageOnly === true;
|
|
1431
|
+
if (process.env.ACRYL_DOOR === "off" || process.env.NODE_ENV === "production" && config.allowInProduction !== true && !pageOnly) return;
|
|
1386
1432
|
const app = ctx.get("appInstance");
|
|
1387
|
-
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
|
+
};
|
|
1388
1448
|
if (typeof app?.root !== "string") throw new Error("acryl-door: the appInstance service has no app folder (root)");
|
|
1389
1449
|
const reportError = (operation, cause) => {
|
|
1390
1450
|
ctx.logger?.error?.(`acryl-door: failed to ${operation}: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
1391
1451
|
};
|
|
1452
|
+
const address = { url: "" };
|
|
1453
|
+
if (!pageOnly) assertDoorIsFree(app.root);
|
|
1392
1454
|
const secret = newSecret();
|
|
1393
|
-
const channel = new UiChannel({
|
|
1455
|
+
const channel = new UiChannel({
|
|
1456
|
+
attachWaitMs: 2e3,
|
|
1457
|
+
requirePage: pageOnly
|
|
1458
|
+
});
|
|
1394
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, "") : "";
|
|
1395
1463
|
const door = new Door({
|
|
1396
1464
|
channel,
|
|
1397
1465
|
shell,
|
|
1398
|
-
audit
|
|
1466
|
+
audit,
|
|
1399
1467
|
app: {
|
|
1400
1468
|
name: app.name,
|
|
1401
1469
|
root: app.root,
|
|
1402
|
-
url
|
|
1470
|
+
get url() {
|
|
1471
|
+
return address.url;
|
|
1472
|
+
}
|
|
1403
1473
|
},
|
|
1474
|
+
...appBase === "" ? {} : { appBase },
|
|
1404
1475
|
extensions: () => ctx.get("extensions"),
|
|
1405
1476
|
tools: () => ctx.get("tools"),
|
|
1406
1477
|
expose: config.tools?.expose ?? [],
|
|
@@ -1412,8 +1483,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1412
1483
|
ctx.effect(() => () => {
|
|
1413
1484
|
shell.close();
|
|
1414
1485
|
}, "acryl-door: desktop shell channel");
|
|
1415
|
-
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
|
+
}));
|
|
1416
1490
|
const tag = `<script type="module" src="${DOOR_PREFIX}/page.js"><\/script>`;
|
|
1491
|
+
const meta = appBase === "" ? "" : `<meta name="acryl-app-base" content="${appBase}">`;
|
|
1417
1492
|
const addScript = async (c, next) => {
|
|
1418
1493
|
await next();
|
|
1419
1494
|
if (!(c.res.headers.get("content-type") ?? "").includes("text/html")) {
|
|
@@ -1423,11 +1498,12 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1423
1498
|
});
|
|
1424
1499
|
return;
|
|
1425
1500
|
}
|
|
1426
|
-
|
|
1501
|
+
let html = await c.res.text();
|
|
1427
1502
|
const headers = new Headers(c.res.headers);
|
|
1428
1503
|
headers.delete("content-length");
|
|
1429
|
-
|
|
1430
|
-
|
|
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, {
|
|
1431
1507
|
status: c.res.status,
|
|
1432
1508
|
headers
|
|
1433
1509
|
});
|
|
@@ -1435,31 +1511,99 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1435
1511
|
const router = ctx.router;
|
|
1436
1512
|
if (typeof router.wrap === "function") router.wrap(addScript);
|
|
1437
1513
|
else ctx.router.route("/", new Acryl().use("*", addScript));
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
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, {
|
|
1445
1574
|
prefix: DOOR_PREFIX,
|
|
1446
|
-
upgrade
|
|
1447
|
-
})
|
|
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
|
+
]));
|
|
1448
1582
|
ctx.inject(["tools"], (inner) => {
|
|
1449
|
-
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");
|
|
1450
1584
|
});
|
|
1451
1585
|
ctx.effect(function* () {
|
|
1452
1586
|
yield ctx.reflect.provide("door", door);
|
|
1453
|
-
|
|
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);
|
|
1454
1598
|
try {
|
|
1455
1599
|
writeShims(app.root, shimTarget());
|
|
1456
1600
|
} catch (cause) {
|
|
1457
1601
|
reportError("write .acryl/bin", cause);
|
|
1458
1602
|
}
|
|
1459
|
-
|
|
1603
|
+
return () => {
|
|
1460
1604
|
removeDoorFile(app.root, secret);
|
|
1461
1605
|
};
|
|
1462
|
-
}, "acryl-door:
|
|
1606
|
+
}, "acryl-door: .acryl/door.json and .acryl/bin/acryl");
|
|
1463
1607
|
}
|
|
1464
1608
|
//#endregion
|
|
1465
|
-
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
|