@antelopejs/dms-ai 0.3.0 → 0.4.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 +64 -205
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle/skill-sources.d.ts +1 -1
- package/dist/lifecycle/skill-sources.js +29 -13
- package/dist/lifecycle/skill-sources.js.map +1 -1
- package/frontend-vue/app/chat/components/BlockPreviewCard.vue +172 -0
- package/frontend-vue/app/chat/components/BlockPreviewModal.vue +324 -0
- package/frontend-vue/app/chat/components/BlockPreviewThumb.vue +141 -0
- package/frontend-vue/app/chat/components/MessageList.vue +20 -0
- package/frontend-vue/app/chat/components/SketchFrame.vue +59 -0
- package/frontend-vue/app/chat/composables/conversation-events.ts +23 -1
- package/frontend-vue/app/chat/composables/useBlockPreviewComponent.ts +15 -0
- package/frontend-vue/app/chat/composables/useDashboardScheme.ts +42 -0
- package/frontend-vue/app/chat/constants/block-preview.ts +27 -0
- package/frontend-vue/app/chat/constants/conversation.ts +1 -0
- package/frontend-vue/app/chat/constants/protocol.ts +1 -0
- package/frontend-vue/app/chat/constants/sketch.ts +105 -0
- package/frontend-vue/app/chat/types/conversation.ts +11 -1
- package/frontend-vue/app/chat/types/protocol.ts +56 -0
- package/frontend-vue/app/chat/utils/block-preview.ts +145 -0
- package/frontend-vue/app/chat/utils/conversation-messages.ts +23 -1
- package/frontend-vue/app/chat/utils/render-items.ts +13 -2
- package/frontend-vue/app/chat/utils/sketch.ts +56 -0
- package/frontend-vue/app/chat/utils/tool-lexicon.ts +7 -0
- package/frontend-vue/i18n/locales/dms-ai-panel-en-GB.json +23 -1
- package/frontend-vue/i18n/locales/dms-ai-panel-fr-FR.json +23 -1
- package/frontend-vue/package.json +1 -1
- package/frontend-vue/tests/chat/block-preview.test.ts +448 -0
- package/package.json +20 -6
- package/sidecar/dist/constants/mcp.js +2 -0
- package/sidecar/dist/constants/mcp.js.map +1 -1
- package/sidecar/dist/constants/preview.d.ts +39 -0
- package/sidecar/dist/constants/preview.js +55 -0
- package/sidecar/dist/constants/preview.js.map +1 -0
- package/sidecar/dist/constants/tool-kinds.js +2 -0
- package/sidecar/dist/constants/tool-kinds.js.map +1 -1
- package/sidecar/dist/mcp/tool-definitions.js +5 -0
- package/sidecar/dist/mcp/tool-definitions.js.map +1 -1
- package/sidecar/dist/mcp/tools/preview-blocks.d.ts +65 -0
- package/sidecar/dist/mcp/tools/preview-blocks.js +176 -0
- package/sidecar/dist/mcp/tools/preview-blocks.js.map +1 -0
- package/sidecar/dist/mcp/types.d.ts +3 -0
- package/sidecar/dist/prompts/agent.d.ts +1 -1
- package/sidecar/dist/prompts/agent.js +3 -2
- package/sidecar/dist/prompts/agent.js.map +1 -1
- package/sidecar/dist/protocol/events.d.ts +313 -0
- package/sidecar/dist/protocol/events.js +9 -0
- package/sidecar/dist/protocol/events.js.map +1 -1
- package/sidecar/dist/protocol/preview.d.ts +130 -0
- package/sidecar/dist/protocol/preview.js +91 -0
- package/sidecar/dist/protocol/preview.js.map +1 -0
- package/sidecar/dist/server/chat-events.d.ts +3 -0
- package/sidecar/dist/server/chat-events.js +21 -0
- package/sidecar/dist/server/chat-events.js.map +1 -1
- package/sidecar/dist/server/ws.js +3 -1
- package/sidecar/dist/server/ws.js.map +1 -1
- package/sidecar/dist/state/types.d.ts +3 -1
- package/sidecar/dist/state/types.js +1 -0
- package/sidecar/dist/state/types.js.map +1 -1
- package/sidecar/package.json +1 -1
- package/skills/dms-ai/SKILL.md +30 -0
- package/skills/dms-ai-code-mode/SKILL.md +51 -0
- package/skills/dms-builder-safe/SKILL.md +9 -2
- package/skills/dms-builder-page/SKILL.md +0 -80
package/README.md
CHANGED
|
@@ -1,241 +1,100 @@
|
|
|
1
|
-
# @antelopejs/dms-ai
|
|
2
|
-
|
|
3
1
|
<div align="center">
|
|
4
|
-
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/badge/license-Apache--2.0-blue?style=for-the-badge&labelColor=000000"></a>
|
|
5
|
-
<a href="https://discord.gg/sjK28QHrA7"><img src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000" alt="Discord"></a>
|
|
6
|
-
<a href="https://antelopejs.com"><img src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000" alt="Documentation"></a>
|
|
7
|
-
</div>
|
|
8
2
|
|
|
9
|
-
|
|
10
|
-
runs a coding agent in a local sidecar that can inspect the loaded modules and their declared skills,
|
|
11
|
-
edit the host project, and stream activity back to the dashboard. The chat is a panel docked next to
|
|
12
|
-
the page, which shrinks to make room: it stays open across page navigations and reloads, follows the
|
|
13
|
-
dashboard's theme, and is toggled from the header or with Ctrl+Shift+K (⌘⇧K on macOS). In the
|
|
14
|
-
command palette (Ctrl+K, ⌘K on macOS), Tab switches to the assistant, which answers a question
|
|
15
|
-
read-only and hands the conversation over to the panel. Claude Code drives it by default; OpenAI's
|
|
16
|
-
Codex is selectable once its CLI is installed.
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
3
|
+
# @antelopejs/dms-ai
|
|
19
4
|
|
|
20
|
-
|
|
5
|
+
<a href="https://www.npmjs.com/package/@antelopejs/dms-ai"><img alt="npm" src="https://img.shields.io/npm/v/@antelopejs/dms-ai?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
6
|
+
<a href="./LICENSE"><img alt="License" src="https://img.shields.io/npm/l/@antelopejs/dms-ai?style=for-the-badge&labelColor=000000&color=000000"></a>
|
|
7
|
+
<a href="https://discord.gg/sjK28QHrA7"><img alt="Discord" src="https://img.shields.io/badge/Discord-18181B?logo=discord&style=for-the-badge&color=000000"></a>
|
|
8
|
+
<a href="https://dms.antelopejs.com/docs/modules/ai"><img alt="Documentation" src="https://img.shields.io/badge/Docs-18181B?style=for-the-badge&color=000000"></a>
|
|
21
9
|
|
|
22
|
-
|
|
23
|
-
ajs project modules add @antelopejs/dms-ai
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
The module starts its bundled sidecar with the project as its working directory. In development,
|
|
27
|
-
set `DMS_AI=0` before starting the backend to disable the sidecar. If
|
|
28
|
-
`@antelopejs/dms-builder` is installed, the assistant also exposes its builder integration.
|
|
29
|
-
|
|
30
|
-
The sidecar is a child process of the backend. A hot reload of the module keeps it running, unless
|
|
31
|
-
its build changed. Stopping the project stops it: Ctrl+C reaches it through the terminal's process
|
|
32
|
-
group, and `@antelopejs/core` 1.13.2 or later terminates it on shutdown (Linux only). A sidecar left
|
|
33
|
-
running by a backend that crashed or was killed is stopped when the next run starts; otherwise it
|
|
34
|
-
exits on its own after 15 idle minutes.
|
|
35
|
-
|
|
36
|
-
The assistant is a development tool, on purpose: the backend and the sidecar refuse to run with
|
|
37
|
-
`NODE_ENV=production`, and the chat is reserved to owners. Remote *development* is supported (see
|
|
38
|
-
below); a hosted use would be a separate product with its own design.
|
|
39
|
-
|
|
40
|
-
## Remote access
|
|
41
|
-
|
|
42
|
-
The sidecar only listens on `127.0.0.1`, and the browser never talks to it: everything goes through
|
|
43
|
-
the DMS frontend server, over the same HTTP relay as the rest of the dashboard. The assistant
|
|
44
|
-
therefore works wherever the dashboard does — another machine on the LAN, Tailscale, an SSH tunnel to
|
|
45
|
-
the frontend port, a reverse proxy or a gateway — and the sidecar's port and client credential stay on
|
|
46
|
-
the server.
|
|
47
|
-
|
|
48
|
-
| Route (owner only) | Purpose |
|
|
49
|
-
| ----------------------------------------- | --------------------------------------------------------------------------- |
|
|
50
|
-
| `GET /ai/channel/events` | The tab's one event stream: the sidecar frames for the dashboard and chat. |
|
|
51
|
-
| `POST /ai/channel/:connectionId/messages` | One client message, relayed to that stream's sidecar socket. |
|
|
52
|
-
|
|
53
|
-
Each stream is bridged to a single sidecar socket, which the dashboard identifies as the host (the
|
|
54
|
-
current page, the agent's navigation requests) and as the chat. The backend opens each socket with
|
|
55
|
-
an `actor` frame naming the signed-in user, which the sidecar records on change sets and undos; a
|
|
56
|
-
browser cannot send that frame, the backend drops it. Browsers keep at most six HTTP/1.1
|
|
57
|
-
connections per origin, and every dashboard tab already holds two long-lived ones for the DMS. The
|
|
58
|
-
assistant adds its stream only in the visible tab whose panel is open, which leaves two dashboard tabs
|
|
59
|
-
usable side by side; over HTTPS with HTTP/2 the limit goes away. Over plain HTTP on an address other
|
|
60
|
-
than `localhost`, start the frontend server with `DMS_COOKIE_SECURE=false`, or the browser drops the
|
|
61
|
-
`Secure` session cookie.
|
|
62
|
-
|
|
63
|
-
## Pages
|
|
64
|
-
|
|
65
|
-
The module adds an **Assistant** module to the dashboard (`/modules/ai`), owner-only, with five
|
|
66
|
-
pages. They are built from DMS blocks; a custom component is used only where no block draws the
|
|
67
|
-
screen. Every page, block and child carries `$dms_ai.*` metadata, so the role editor lists them with
|
|
68
|
-
translated names (English and French, in `frontend-vue/i18n/locales/dms-ai-pages-*.json`).
|
|
69
|
-
|
|
70
|
-
| Page | What it shows |
|
|
71
|
-
| -------- | --------------------------------------------------------------------------------------------------------------- |
|
|
72
|
-
| Overview | Period selector, a banner when the assistant needs you (offline with Restart, a failed turn, requests waiting), its status rows, four KPIs, the activity chart, how actions were allowed, the latest change sets with Undo / Redo, and the top tools. |
|
|
73
|
-
| Changes | Every turn that touched the project as a change set: its diff, Undo with a conflict preview, Redo. `?set=<id>` opens one. |
|
|
74
|
-
| Activity | The audit log: tabs (changed files, asked you, denied or blocked, failed), quick filters, a detail drawer per call (`?record=<id>`), and a CSV export. |
|
|
75
|
-
| Skills | The skills loaded into the agent as cards, a detail drawer per skill, and a warning when two skills share a name. |
|
|
76
|
-
| Settings | The defaults of new conversations, saved as you change them: agent, thinking, approval mode, what always asks, request timeout, scope, local skills, checkpoint retention; then the tokens used over 14 days. |
|
|
77
|
-
|
|
78
|
-
Every route below is owner-only. Lists and settings answer `503 { message }` while the sidecar is
|
|
79
|
-
down, so tables show their error state and a setting says "Not saved"; charts answer empty.
|
|
80
|
-
|
|
81
|
-
| Route | Purpose |
|
|
82
|
-
| ------------------------------------------------------ | -------------------------------------------------------------- |
|
|
83
|
-
| `GET /ai/status`, `POST /ai/sidecar/restart` | The assistant's live status (`offline` when it does not answer), and a restart. |
|
|
84
|
-
| `GET /ai/status/facts`, `/ai/status/banner` | The Overview's status rows (a `KeyValueList`) and its banner (`BannerContent`, or 204 when all is well). |
|
|
85
|
-
| `GET /ai/metrics/kpi/:metric`, `series`, `allowed`, `top-tools`, `usage`, `usage/summary` | The Overview's and Settings › Usage figures. |
|
|
86
|
-
| `GET /ai/activity`, `/ai/activity/:id`, `/ai/activity/export.csv` | The audit log as a source table, one call's detail, the CSV export. |
|
|
87
|
-
| `GET /ai/changes`, `/ai/changes/:id`, `/ai/changes/:id/undo-preview`, `/ai/changes/:id/undo-confirm` | Change sets, a set's diff, what Undo restores, and the dialog it asks in. |
|
|
88
|
-
| `POST /ai/changes/:id/undo`, `/ai/changes/:id/redo` | Undo (`{ includeLater? }`) and Redo, recorded with the signed-in user's name. |
|
|
89
|
-
| `GET /ai/skills/catalog`, `/ai/skills/conflicts` | The skills as table rows, and the banner about names several skills share (204 when none). |
|
|
90
|
-
| `GET` / `PUT /ai/settings` | The settings form; `PUT` takes the one field an instant save sends. |
|
|
91
|
-
|
|
92
|
-
## Model output in the dashboard
|
|
93
|
-
|
|
94
|
-
The chat renders model output inside the dashboard, next to the owner's session, and that output can
|
|
95
|
-
carry a prompt injection read from a file or a page. So nothing the agent writes is trusted as markup:
|
|
96
|
-
|
|
97
|
-
- Markdown is rendered with raw HTML off, then sanitized by a DOMPurify instance of the chat's own
|
|
98
|
-
(hooks do not leak to the dashboard's), against an allowlist: text formatting, lists, quotes, code,
|
|
99
|
-
tables and links, and no attribute but `href`, `title`, `target`, `rel` and `start` — no `style`,
|
|
100
|
-
`class`, `id` or event handler.
|
|
101
|
-
- Links only go to `http`, `https`, `mailto` or a page of the dashboard, never `javascript:` or
|
|
102
|
-
`data:`, and open in a new tab with `rel="noopener noreferrer"`.
|
|
103
|
-
- An image the model writes is shown as a link: loading it on its own could send what the agent read
|
|
104
|
-
to its address.
|
|
105
|
-
- The agent can only navigate the dashboard to one of its own pages.
|
|
106
|
-
|
|
107
|
-
## Sidecar
|
|
108
|
-
|
|
109
|
-
The sidecar is an agent server only: `/health`, the settings, metrics and skills routes the backend
|
|
110
|
-
proxies, the MCP endpoint of its agents, and one WebSocket endpoint, `/ws`, which only accepts the
|
|
111
|
-
client credential as a `Bearer` header. It serves no page or asset. Run by hand (`node
|
|
112
|
-
sidecar/dist/index.js --port 0 --root <dir>`), it keeps its standalone default for the backend
|
|
113
|
-
origin, which is how its tests drive it.
|
|
114
|
-
|
|
115
|
-
## Configuration
|
|
116
|
-
|
|
117
|
-
The key is optional. Left out, the sidecar keeps the default it uses when run standalone
|
|
118
|
-
(`http://localhost:5010`), which is the behaviour every existing project already has.
|
|
119
|
-
|
|
120
|
-
| Key | What it is |
|
|
121
|
-
| ------------ | ------------------------------------------------------------------------------ |
|
|
122
|
-
| `backendUrl` | Origin the sidecar calls the DMS backend on — its pages registry, logs and builder clients. |
|
|
123
|
-
|
|
124
|
-
The api module publishes the origin it actually reserved, so `backendUrl` should reference it rather
|
|
125
|
-
than repeat a port that may already be taken:
|
|
126
|
-
|
|
127
|
-
```typescript [antelope.config.ts]
|
|
128
|
-
export default defineConfig({
|
|
129
|
-
modules: {
|
|
130
|
-
"dms-ai": {
|
|
131
|
-
source: { type: "package", package: "@antelopejs/dms-ai" },
|
|
132
|
-
config: {
|
|
133
|
-
backendUrl: "${@api.API_LOCAL_BASE_URL}",
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
```
|
|
10
|
+
An AI development assistant inside the AntelopeJS DMS dashboard.
|
|
139
11
|
|
|
140
|
-
|
|
12
|
+
</div>
|
|
141
13
|
|
|
142
|
-
|
|
143
|
-
the same seam, so the chat, the tool calls, the permission prompts and the file-change animation
|
|
144
|
-
behave the same either way. `GET /settings` reports which ones this install can actually drive:
|
|
14
|
+

|
|
145
15
|
|
|
146
|
-
|
|
147
|
-
{ "provider": "claude", "providers": { "claude": { "available": true }, "codex": { "available": false, "reason": "Install @openai/codex, at the exact version dms-ai pins, to enable this provider." } } }
|
|
148
|
-
```
|
|
16
|
+
## What it does
|
|
149
17
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
18
|
+
- Docks a chat panel next to any page (`Ctrl` `Shift` `K`), with the page as context.
|
|
19
|
+
- Runs a coding agent (Claude Code by default, or OpenAI's Codex) in a local sidecar that reads the project, its loaded modules and their skills.
|
|
20
|
+
- Edits pages through the [Builder](https://github.com/AntelopeJS/dms-builder) in Safe mode, or writes code, then typechecks and shows the result live.
|
|
21
|
+
- Saves every turn that touches the project as a change set you can review, undo and redo.
|
|
22
|
+
- Adds an owner-only **Assistant** module: Overview, Changes, Activity, Skills and Settings.
|
|
154
23
|
|
|
155
|
-
|
|
156
|
-
in-agent context, its transcript is kept.
|
|
24
|
+
The assistant is a development tool: the backend and the sidecar refuse to run with `NODE_ENV=production`.
|
|
157
25
|
|
|
158
|
-
|
|
26
|
+
## Install
|
|
159
27
|
|
|
160
|
-
|
|
161
|
-
project only through the Builder tools. It holds whatever permission mode is selected:
|
|
28
|
+
Run the AntelopeJS CLI from the root of a project that already loads `@antelopejs/dms`:
|
|
162
29
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
`grep`, `git log`…) without asking. Reading, listing and searching stay available through
|
|
168
|
-
`Read`, `Glob` and `Grep`, allowed inside the workspace and asked outside it.
|
|
169
|
-
- On Codex, the sandbox stays read-only, without network, and every escalation is declined.
|
|
170
|
-
- Safe mode caps *Auto* at *Accept edits*: the sidecar stops approving prompts on its own, and the
|
|
171
|
-
Claude CLI never runs in `bypassPermissions`, so the prompts that remain (reads outside the
|
|
172
|
-
workspace, web access) still reach you.
|
|
30
|
+
```bash
|
|
31
|
+
ajs project modules add @antelopejs/dms-ai
|
|
32
|
+
ajs project modules add @antelopejs/dms-builder # recommended: enables Safe mode
|
|
33
|
+
```
|
|
173
34
|
|
|
174
|
-
|
|
175
|
-
turn on Codex, without discarding the conversation.
|
|
35
|
+
## Quick start
|
|
176
36
|
|
|
177
|
-
|
|
37
|
+
Point the sidecar at the origin the `api` module reserved:
|
|
178
38
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
39
|
+
```ts
|
|
40
|
+
// antelope.config.ts
|
|
41
|
+
"dms-ai": {
|
|
42
|
+
source: { type: "package", package: "@antelopejs/dms-ai" },
|
|
43
|
+
config: {
|
|
44
|
+
backendUrl: "${@api.API_LOCAL_BASE_URL}",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
```
|
|
182
48
|
|
|
183
|
-
|
|
184
|
-
pnpm add @openai/codex@0.154.0
|
|
185
|
-
```
|
|
49
|
+
Claude Code runs with its own credentials (its login, or `ANTHROPIC_API_KEY` in the backend's environment). Restart the backend, then the frontend, sign in as an owner and press `Ctrl` `Shift` `K` (`⌘` `⇧` `K` on macOS). Set `DMS_AI=0` to start the backend without the sidecar.
|
|
186
50
|
|
|
187
|
-
|
|
188
|
-
month. The sidecar ships protocol types generated from the pinned version and checks
|
|
189
|
-
`codex --version` against it at spawn, refusing to start on a mismatch rather than speaking a
|
|
190
|
-
protocol its types do not describe. The refusal names both versions, so an upgrade says what to
|
|
191
|
-
pin back to. To run a newer binary anyway — at the risk of a protocol its types do not
|
|
192
|
-
describe — set `DMS_AI_CODEX_ALLOW_VERSION_MISMATCH=1`; the drift is then logged once, at startup, instead of
|
|
193
|
-
blocking the provider.
|
|
51
|
+
## Compatibility
|
|
194
52
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
53
|
+
| Package | Version |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `@antelopejs/dms` | `>=0.9.0 <1.0.0` |
|
|
56
|
+
| `@antelopejs/interface-dms` | `>=0.7.0 <1.0.0` |
|
|
57
|
+
| `@antelopejs/dms-frontend` (renderer) | `>=0.6.0 <0.7.0` |
|
|
58
|
+
| `@antelopejs/dms-builder` (optional, Safe mode) | `>=0.4.0` |
|
|
200
59
|
|
|
201
|
-
|
|
60
|
+
On DMS 0.8, use `@antelopejs/dms-ai` 0.2.
|
|
202
61
|
|
|
203
|
-
|
|
204
|
-
sidecar records its pid so a previous run's orphans are killed at startup — through procfs on
|
|
205
|
-
Linux, `ps` on macOS and `taskkill /T` on Windows, which is also what takes the sandboxed children
|
|
206
|
-
of the app-server with it.
|
|
62
|
+
## Documentation
|
|
207
63
|
|
|
208
|
-
|
|
64
|
+
- [Introduction](https://dms.antelopejs.com/docs/modules/ai/introduction)
|
|
65
|
+
- [Installation](https://dms.antelopejs.com/docs/modules/ai/installation)
|
|
66
|
+
- [Configuration](https://dms.antelopejs.com/docs/modules/ai/configuration): agent providers, Codex, Safe mode, remote access
|
|
67
|
+
- [Usage](https://dms.antelopejs.com/docs/modules/ai/usage/chat)
|
|
68
|
+
- [Extending](https://dms.antelopejs.com/docs/modules/ai/extending)
|
|
69
|
+
- [FAQ](https://dms.antelopejs.com/docs/modules/ai/faq)
|
|
209
70
|
|
|
210
|
-
The
|
|
211
|
-
supplies authentication, shared state, Nuxt UI and the icons. The chat panel, `DmsAiChatPanel`, is a
|
|
212
|
-
docked side panel of the dashboard (`registerSidePanel`): the DMS renders it once for the whole app,
|
|
213
|
-
so it lives through Inertia navigations, and keeps its open state and width in a cookie. The command
|
|
214
|
-
palette's assistant mode answers with `DmsAiPaletteAnswer` (`registerCommandPaletteAssistant`). The
|
|
215
|
-
chat's code is under `frontend-vue/app/chat`. The renderer bundles the icons it finds in
|
|
216
|
-
`.vue` files, so an icon name belongs in the component that shows it.
|
|
71
|
+
The guide's sources live in [`docs/`](./docs). The package ships the `dms-ai`, `dms-builder-safe` and `dms-ai-code-mode` Claude Code skills in [`skills/`](./skills), declared under `antelopeJs.skills` and loaded into the assistant's agent.
|
|
217
72
|
|
|
218
|
-
##
|
|
73
|
+
## Contributing
|
|
219
74
|
|
|
220
|
-
|
|
75
|
+
Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a pull request.
|
|
221
76
|
|
|
222
77
|
```bash
|
|
223
78
|
pnpm install
|
|
224
79
|
pnpm --dir frontend-vue install
|
|
225
80
|
pnpm build
|
|
226
81
|
pnpm build:sidecar
|
|
82
|
+
pnpm dev # playground backend
|
|
83
|
+
pnpm frontend:dev # dashboard, in a second terminal
|
|
84
|
+
pnpm lint
|
|
227
85
|
pnpm test
|
|
86
|
+
pnpm test:node # every backend suite, after a single build
|
|
228
87
|
```
|
|
229
88
|
|
|
230
|
-
|
|
89
|
+
<details>
|
|
90
|
+
<summary>Repository notes</summary>
|
|
231
91
|
|
|
232
|
-
|
|
233
|
-
pnpm --dir frontend-vue build
|
|
234
|
-
pnpm
|
|
235
|
-
|
|
92
|
+
- The module registers `frontend-vue` through `AddFrontendModule` with the Vue 3 renderer. The chat panel, `DmsAiChatPanel`, is a docked side panel (`registerSidePanel`): the DMS renders it once for the whole app, so it lives through Inertia navigations and keeps its open state and width in a cookie. The command palette's assistant mode answers with `DmsAiPaletteAnswer` (`registerCommandPaletteAssistant`). The chat's code is under `frontend-vue/app/chat`. The renderer bundles the icons it finds in `.vue` files, so an icon name belongs in the component that shows it.
|
|
93
|
+
- To build and typecheck the Vue source, set `DMS_FRONTEND_WORKSPACE` to the absolute path of a generated Inertia workspace that includes this module, then run `pnpm --dir frontend-vue build` and `pnpm --dir frontend-vue typecheck`.
|
|
94
|
+
- `pnpm test:node` runs every backend suite after one build (`DMS_PREBUILT=1` skips the build when `dist/` is fresh, as in CI): `test:frontend-registration` (backend registration, sidecar inputs, `$dms_ai` keys in both locales), `test:routes` (the `/ai/*` routes against a stand-in sidecar) and `test:sidecar-lifecycle` (hot reload, restart, stale sidecar, Ctrl+C). The opt-in Codex acceptance suite runs with `CODEX_ACCEPTANCE=1 pnpm --dir sidecar test:acceptance`.
|
|
95
|
+
|
|
96
|
+
</details>
|
|
236
97
|
|
|
237
|
-
|
|
98
|
+
## License
|
|
238
99
|
|
|
239
|
-
|
|
240
|
-
`pnpm test:routes` drives the `/ai/*` routes against a stand-in sidecar: query translation, `503` while it is down, settings conversions, Undo stamping and the CSV export.
|
|
241
|
-
`pnpm test:sidecar-lifecycle` starts a stand-in sidecar to check that a hot reload keeps it, a restart replaces it, a sidecar left by an earlier run is stopped, and Ctrl+C on the backend stops it.
|
|
100
|
+
[Apache-2.0](./LICENSE)
|
package/dist/index.js
CHANGED
|
@@ -32,13 +32,14 @@ async function start() {
|
|
|
32
32
|
priority: frontend_module_1.FRONTEND_MODULE_PRIORITY,
|
|
33
33
|
backendProxies: [frontend_module_1.FRONTEND_BACKEND_PROXY],
|
|
34
34
|
});
|
|
35
|
+
const hostProjectRoot = process.cwd();
|
|
35
36
|
const [moduleRoots, skillDirs, builderEnabled] = await Promise.all([
|
|
36
37
|
(0, module_roots_1.collectModuleRoots)(),
|
|
37
|
-
(0, skill_sources_1.collectSkillSources)(),
|
|
38
|
+
(0, skill_sources_1.collectSkillSources)(hostProjectRoot),
|
|
38
39
|
(0, presence_1.isBuilderAvailable)(),
|
|
39
40
|
]);
|
|
40
41
|
void (0, spawn_sidecar_1.spawnSidecar)({
|
|
41
|
-
hostProjectRoot
|
|
42
|
+
hostProjectRoot,
|
|
42
43
|
...(0, config_1.getConfig)(),
|
|
43
44
|
moduleRoots,
|
|
44
45
|
skillDirs,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAoBA,8BAEC;AAED,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAoBA,8BAEC;AAED,sBA2BC;AAOD,0BAEC;AA5DD,0DAA6B;AAC7B,gEAA6D;AAC7D,yDAAmE;AACnE,iDAAwD;AACxD,kDAAsD;AACtD,qCAA6D;AAC7D,iEAKqC;AACrC,iDAAyD;AACzD,2DAA8D;AAC9D,6DAAgE;AAChE,6DAAyD;AACzD,qDAAuD;AACvD,mBAAiB;AACjB,oBAAkB;AAElB,SAAgB,SAAS,CAAC,MAAe;IACvC,IAAA,kBAAS,EAAC,IAAA,oBAAW,EAAC,MAAM,CAAC,CAAC,CAAC;AACjC,CAAC;AAEM,KAAK,UAAU,KAAK;IACzB,IAAA,4BAAe,GAAE,CAAC;IAClB,MAAM,IAAA,wBAAiB,EAAC;QACtB,IAAI,EAAE,sCAAoB;QAC1B,UAAU,EAAE,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,qCAAmB,CAAC;QACrD,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE;QACvC,QAAQ,EAAE,0CAAwB;QAClC,cAAc,EAAE,CAAC,wCAAsB,CAAC;KACzC,CAAC,CAAC;IAIH,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjE,IAAA,iCAAkB,GAAE;QACpB,IAAA,mCAAmB,EAAC,eAAe,CAAC;QACpC,IAAA,6BAAkB,GAAE;KACrB,CAAC,CAAC;IACH,KAAK,IAAA,4BAAY,EAAC;QAChB,eAAe;QACf,GAAG,IAAA,kBAAS,GAAE;QACd,WAAW;QACX,SAAS;QACT,cAAc;KACf,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,iBAAO,CAAC,KAAK,CAAC,GAAG,4BAAkB,gBAAgB,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC;AAOD,SAAgB,OAAO;IACrB,IAAA,0BAAe,GAAE,CAAC;AACpB,CAAC"}
|
|
@@ -13,6 +13,14 @@ const sidecar_1 = require("../constants/sidecar");
|
|
|
13
13
|
const PACKAGE_JSON_FILE = "package.json";
|
|
14
14
|
const NODE_MODULES_DIR = "node_modules";
|
|
15
15
|
const FALLBACK_PLUGIN_NAME = "skills";
|
|
16
|
+
const MODULE_DEPENDENCY_FIELDS = [
|
|
17
|
+
"dependencies",
|
|
18
|
+
"optionalDependencies",
|
|
19
|
+
];
|
|
20
|
+
const PROJECT_DEPENDENCY_FIELDS = [
|
|
21
|
+
...MODULE_DEPENDENCY_FIELDS,
|
|
22
|
+
"devDependencies",
|
|
23
|
+
];
|
|
16
24
|
function sanitizePluginName(name) {
|
|
17
25
|
const cleaned = name.toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
18
26
|
const trimmed = cleaned.replace(/^-+|-+$/g, "");
|
|
@@ -49,14 +57,11 @@ function skillSourcesFromPackage(pkg, baseDir, pluginName) {
|
|
|
49
57
|
dir: node_path_1.default.resolve(baseDir, rel),
|
|
50
58
|
}));
|
|
51
59
|
}
|
|
52
|
-
function listDependencyNames(pkg) {
|
|
60
|
+
function listDependencyNames(pkg, fields) {
|
|
53
61
|
if (pkg === null || typeof pkg !== "object")
|
|
54
62
|
return [];
|
|
55
63
|
const manifest = pkg;
|
|
56
|
-
return [
|
|
57
|
-
...Object.keys(manifest.dependencies ?? {}),
|
|
58
|
-
...Object.keys(manifest.optionalDependencies ?? {}),
|
|
59
|
-
];
|
|
64
|
+
return fields.flatMap((field) => Object.keys(manifest[field] ?? {}));
|
|
60
65
|
}
|
|
61
66
|
async function toRealDir(dir) {
|
|
62
67
|
try {
|
|
@@ -117,8 +122,8 @@ function scanDependencyOnce(dep, fromDir, scans) {
|
|
|
117
122
|
scans.set(dep, scan);
|
|
118
123
|
return scan;
|
|
119
124
|
}
|
|
120
|
-
async function readAllDependencySkillSources(localPath,
|
|
121
|
-
const nested = await Promise.all(
|
|
125
|
+
async function readAllDependencySkillSources(localPath, dependencies, scans) {
|
|
126
|
+
const nested = await Promise.all(dependencies.map((dep) => scanDependencyOnce(dep, localPath, scans)));
|
|
122
127
|
return nested.flat();
|
|
123
128
|
}
|
|
124
129
|
async function readModuleSkillSources(id, localPath, scans) {
|
|
@@ -131,9 +136,15 @@ async function readModuleSkillSources(id, localPath, scans) {
|
|
|
131
136
|
scans.set(moduleName, Promise.resolve([]));
|
|
132
137
|
}
|
|
133
138
|
const own = skillSourcesFromPackage(pkg, localPath, toPluginName(moduleName));
|
|
134
|
-
const fromDependencies = await readAllDependencySkillSources(localPath, pkg, scans);
|
|
139
|
+
const fromDependencies = await readAllDependencySkillSources(localPath, listDependencyNames(pkg, MODULE_DEPENDENCY_FIELDS), scans);
|
|
135
140
|
return [...own, ...fromDependencies];
|
|
136
141
|
}
|
|
142
|
+
async function readProjectSkillSources(projectRoot, scans) {
|
|
143
|
+
const pkg = await readPackageJson(projectRoot);
|
|
144
|
+
if (pkg === null)
|
|
145
|
+
return [];
|
|
146
|
+
return readAllDependencySkillSources(projectRoot, listDependencyNames(pkg, PROJECT_DEPENDENCY_FIELDS), scans);
|
|
147
|
+
}
|
|
137
148
|
function dedupeBy(sources, key, onDrop) {
|
|
138
149
|
const seen = new Set();
|
|
139
150
|
return sources.filter((source) => {
|
|
@@ -146,25 +157,30 @@ function dedupeBy(sources, key, onDrop) {
|
|
|
146
157
|
return true;
|
|
147
158
|
});
|
|
148
159
|
}
|
|
149
|
-
async function
|
|
160
|
+
async function readLoadedModulesSkillSources(scans) {
|
|
150
161
|
const ids = await (0, modules_1.ListModules)();
|
|
151
162
|
const infos = await Promise.all(ids.map((id) => (0, modules_1.GetModuleInfo)(id)
|
|
152
163
|
.then((i) => ({ id, i }))
|
|
153
164
|
.catch(() => null)));
|
|
154
|
-
const scans = new Map();
|
|
155
165
|
const nested = await Promise.all(infos.map((entry) => entry &&
|
|
156
166
|
typeof entry.i?.localPath === "string" &&
|
|
157
167
|
entry.i.localPath.length > 0
|
|
158
168
|
? readModuleSkillSources(entry.id, entry.i.localPath, scans)
|
|
159
169
|
: Promise.resolve([])));
|
|
160
|
-
|
|
170
|
+
return nested.flat();
|
|
171
|
+
}
|
|
172
|
+
async function gather(projectRoot) {
|
|
173
|
+
const scans = new Map();
|
|
174
|
+
const fromModules = await readLoadedModulesSkillSources(scans);
|
|
175
|
+
const fromProject = await readProjectSkillSources(projectRoot, scans);
|
|
176
|
+
const byDir = dedupeBy([...fromModules, ...fromProject], (source) => source.dir);
|
|
161
177
|
return dedupeBy(byDir, (source) => source.module, (dropped) => logging_1.Logging.Warn(`${sidecar_1.SIDECAR_LOG_PREFIX} skill dir ${dropped.dir} ignored: plugin name "${dropped.module}" already has a skill dir`));
|
|
162
178
|
}
|
|
163
|
-
async function collectSkillSources() {
|
|
179
|
+
async function collectSkillSources(projectRoot) {
|
|
164
180
|
try {
|
|
165
181
|
return await new Promise((resolve) => {
|
|
166
182
|
const timer = setTimeout(() => resolve([]), sidecar_1.MODULE_ROOTS_TIMEOUT_MS);
|
|
167
|
-
gather().then((v) => {
|
|
183
|
+
gather(projectRoot).then((v) => {
|
|
168
184
|
clearTimeout(timer);
|
|
169
185
|
resolve(v);
|
|
170
186
|
}, () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-sources.js","sourceRoot":"","sources":["../../src/lifecycle/skill-sources.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"skill-sources.js","sourceRoot":"","sources":["../../src/lifecycle/skill-sources.ts"],"names":[],"mappings":"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"}
|