@skaile/forge-app 0.0.0-stage → 1.0.1
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/CHANGELOG.md +13 -0
- package/LICENSE +21 -0
- package/README.md +100 -2
- package/assets/css/forge-app.css +9 -0
- package/nuxt.config.ts +14 -0
- package/package.json +50 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.1
|
|
4
|
+
|
|
5
|
+
- Dependency `@skaile/forge-app-actions` widened to `^0.4.0 || ^0.5.0`. The layer only registers its Nuxt module, which 0.5.0 did not change. Before, a host on forge-app-actions 0.5.0 got a second, nested 0.4.x copy, and the layer registered that one. Hosts that resolve 0.5.0 get its breaking changes: the Workspaces capability bridge (`clientCapabilityBridge`, `capabilityRegistry`, `routeCapabilityInvocation`, …) is no longer a Nuxt server auto-import or a `/server` export; import it from `@skaile/forge-app-actions/server/workspaces`.
|
|
6
|
+
|
|
7
|
+
## 1.0.0
|
|
8
|
+
|
|
9
|
+
Initial release: an optional Nuxt layer for Skaile forge apps.
|
|
10
|
+
|
|
11
|
+
- `extends: ['@skaile/forge-app']` registers `modules: ['@nuxt/ui', '@skaile/forge-app-actions']` in that order.
|
|
12
|
+
- One shared stylesheet (`@import "tailwindcss"; @import "@nuxt/ui"; @import "@skaile/brand/nuxt-ui.css";`) registered once. Capability stylesheets stay in their own modules.
|
|
13
|
+
- No HTTP or MCP action endpoint, no principal or deps resolver, no settings or provider route, no editor or chat wiring: hosts add each feature explicitly.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matthias Ortegro
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,101 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @skaile/forge-app
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An optional Nuxt layer for Skaile forge apps. It saves the same three lines of setup in every host and nothing else.
|
|
4
|
+
|
|
5
|
+
## What the layer gives you
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
// nuxt.config.ts
|
|
9
|
+
export default defineNuxtConfig({
|
|
10
|
+
extends: ['@skaile/forge-app'],
|
|
11
|
+
})
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- `modules: ['@nuxt/ui', '@skaile/forge-app-actions']`, in that order (the actions module refuses to load unless Nuxt UI came first). Hosts keep their own `modules`; entries are merged, the layer's first.
|
|
15
|
+
- One stylesheet, registered once:
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
@import "tailwindcss";
|
|
19
|
+
@import "@nuxt/ui";
|
|
20
|
+
@import "@skaile/brand/nuxt-ui.css";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The brand bridge comes after Nuxt UI on purpose (equal specificity, source order decides). Capability stylesheets (editor, chat, inbox) stay in the modules that own them.
|
|
24
|
+
|
|
25
|
+
Install:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
bun add @skaile/forge-app @nuxt/ui nuxt tailwindcss
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Peers: `nuxt ^4`, `@nuxt/ui ^4.11`, `tailwindcss ^4`. Dependencies: `@skaile/forge-app-actions ^0.4.0 || ^0.5.0`, `@skaile/brand ^0.7.0`. Wrap the root in `<UApp>` as Nuxt UI requires.
|
|
32
|
+
|
|
33
|
+
## What the layer does not do
|
|
34
|
+
|
|
35
|
+
No HTTP or MCP action endpoint, no principal or deps resolver, no settings or provider route, no annotation or editor authorization, no chat handler, no central dependency list. Identity, grants and per-feature permission checks stay in the host. Compose chat with `createAiSdkChatHandler` yourself; the layer has no wrapper for it. Express/Vite apps do not use this layer; they use the framework-neutral packages directly.
|
|
36
|
+
|
|
37
|
+
## What hosts add explicitly
|
|
38
|
+
|
|
39
|
+
Each feature is opt-in in the host's own `nuxt.config.ts`.
|
|
40
|
+
|
|
41
|
+
**HTTP actions** (typed client, `forge-actions` CLI). Deny by default until your hook allows:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
export default defineNuxtConfig({
|
|
45
|
+
extends: ['@skaile/forge-app'],
|
|
46
|
+
forgeAppActions: { http: { route: '/api/actions' } },
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// server/plugins/actions-auth.ts
|
|
52
|
+
export default defineNitroPlugin((nitro) => {
|
|
53
|
+
nitro.hooks.hook('forge-app-actions:http:authorize', async (decision) => {
|
|
54
|
+
// decision: { event, bearer, allowed, principal?, deps? }
|
|
55
|
+
// Cookie sessions: do the same-origin check here.
|
|
56
|
+
decision.allowed = await isAllowed(decision.event, decision.bearer)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**MCP** (serves the `llm`-audience actions):
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
forgeAppActions: { mcp: { route: '/mcp', name: 'my-app' } },
|
|
65
|
+
// plus a Nitro hook on 'forge-app-actions:mcp:authorize' that sets decision.allowed
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Provider settings** (installed after `@nuxt/ui`, provides `<ForgeProvidersPanel>`):
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
extends: ['@skaile/forge-app'],
|
|
72
|
+
modules: ['@skaile/forge-settings/nuxt'],
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Settings storage, scopes and permissions stay in the host; see `@skaile/forge-settings`.
|
|
76
|
+
|
|
77
|
+
**Editor** (chat-free by default; the sidebar lives at `@skaile/forge-editor/ai/vue/chat` and needs `@skaile/forge-chat`):
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
extends: ['@skaile/forge-app'],
|
|
81
|
+
modules: ['@skaile/forge-editor/nuxt'],
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A plain editor host installs no settings storage and no agent runtime.
|
|
85
|
+
|
|
86
|
+
## Proof
|
|
87
|
+
|
|
88
|
+
`scripts/packed-consumer.mjs` packs the layer with `npm pack`, installs the tarball into a throwaway Nuxt app under `.scratch/packed-consumer/` (gitignored), runs `nuxi build`, boots `.output/server/index.mjs` on a free port and checks:
|
|
89
|
+
|
|
90
|
+
- Nuxt UI registered before `@skaile/forge-app-actions`; the packed layer is the extended layer; the stylesheet is registered once
|
|
91
|
+
- no HTTP/MCP options set; `GET/POST /api/actions` and `/mcp` answer 404
|
|
92
|
+
- the brand bridge is in the built CSS once, after Nuxt UI's defaults
|
|
93
|
+
- a second variant adds `@skaile/forge-editor` (and its Nuxt module): the build output and dependency tree contain no `@skaile/forge-settings`, `@skaile/forge-agent-runtime`, `@skaile/forge-common`, `@skaile/workspaces` or `@skaile/forge-chat`
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
node scripts/packed-consumer.mjs # both variants (~40s, needs registry access)
|
|
97
|
+
node scripts/packed-consumer.mjs base # layer only
|
|
98
|
+
node scripts/packed-consumer.mjs editor # layer + @skaile/forge-editor
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Exit 0 only when every check prints `PASS`. Unit tests (`bun run test`) cover the layer config itself.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @skaile/forge-app shared stylesheet, registered once by the layer.
|
|
3
|
+
* Order matters: the brand bridge must come after "@nuxt/ui" (equal
|
|
4
|
+
* specificity, source order decides). Capability stylesheets (chat, editor,
|
|
5
|
+
* inbox) stay in the modules that own them.
|
|
6
|
+
*/
|
|
7
|
+
@import "tailwindcss";
|
|
8
|
+
@import "@nuxt/ui";
|
|
9
|
+
@import "@skaile/brand/nuxt-ui.css";
|
package/nuxt.config.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { defineNuxtConfig } from "nuxt/config";
|
|
3
|
+
|
|
4
|
+
// Optional layer: `extends: ['@skaile/forge-app']`.
|
|
5
|
+
//
|
|
6
|
+
// - `@nuxt/ui` MUST precede `@skaile/forge-app-actions` (the actions module
|
|
7
|
+
// refuses to load otherwise and renders Nuxt UI primitives).
|
|
8
|
+
// - `forgeAppActions` is deliberately left unset: no HTTP or MCP endpoint, no
|
|
9
|
+
// principal/deps resolver. Hosts opt in per feature.
|
|
10
|
+
// - No dependency list, no settings/provider route, no chat or editor wiring.
|
|
11
|
+
export default defineNuxtConfig({
|
|
12
|
+
modules: ["@nuxt/ui", "@skaile/forge-app-actions"],
|
|
13
|
+
css: [fileURLToPath(new URL("./assets/css/forge-app.css", import.meta.url))],
|
|
14
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skaile/forge-app",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Optional Nuxt layer for Skaile forge apps: Nuxt UI, @skaile/forge-app-actions and the shared Tailwind + brand stylesheet, registered once. Adds no routes, resolvers or permissions.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"packageManager": "bun@1.3.9",
|
|
7
|
+
"main": "./nuxt.config.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"nuxt.config.ts",
|
|
10
|
+
"assets",
|
|
11
|
+
"README.md",
|
|
12
|
+
"CHANGELOG.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/skaile-ai/forge-app.git"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "bun x --bun vitest run",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"proof:packed": "node scripts/packed-consumer.mjs",
|
|
27
|
+
"check": "bun run format && bun run lint",
|
|
28
|
+
"format": "biome format --write nuxt.config.ts tests scripts",
|
|
29
|
+
"lint": "biome lint --fix --unsafe nuxt.config.ts tests scripts"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@skaile/brand": "^0.7.0",
|
|
33
|
+
"@skaile/forge-app-actions": "^0.4.0 || ^0.5.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@nuxt/ui": "^4.11.1",
|
|
37
|
+
"nuxt": "^4.0.0",
|
|
38
|
+
"tailwindcss": "^4.0.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@biomejs/biome": "^2.4.9",
|
|
42
|
+
"@nuxt/ui": "^4.11.1",
|
|
43
|
+
"@types/node": "^22.0.0",
|
|
44
|
+
"nuxt": "^4.0.0",
|
|
45
|
+
"tailwindcss": "^4.0.0",
|
|
46
|
+
"typescript": "^5.0.0",
|
|
47
|
+
"vitest": "^3.2.0"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=20"
|
|
51
|
+
}
|
|
52
|
+
}
|