@shaferllc/keel 0.83.4 → 0.83.6
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/AGENTS.md +5 -4
- package/README.md +23 -15
- package/dist/accounts/provider.js +12 -2
- package/dist/billing/provider.js +12 -2
- package/dist/mcp/cloud.d.ts +2 -1
- package/dist/mcp/cloud.js +117 -8
- package/dist/mcp/server.js +4 -2
- package/dist/teams/provider.js +12 -2
- package/docs/ai-manifest.json +8 -1
- package/docs/ai.md +22 -11
- package/docs/changelog.md +21 -0
- package/docs/from-install-to-deploy.md +186 -0
- package/docs/getting-started.md +19 -27
- package/docs/starter-kits.md +2 -1
- package/llms-full.txt +344 -147
- package/llms.txt +1 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -5,10 +5,11 @@ house framework for Node.js — or an app built on it. Humans: this is also a fa
|
|
|
5
5
|
orientation. For prose guides see [`docs/`](./docs); for a machine-readable
|
|
6
6
|
surface, run the [MCP server](#mcp-server-recommended).
|
|
7
7
|
|
|
8
|
-
> **The fastest path:**
|
|
9
|
-
> `
|
|
10
|
-
>
|
|
11
|
-
>
|
|
8
|
+
> **The fastest path:** follow
|
|
9
|
+
> [`docs/from-install-to-deploy.md`](./docs/from-install-to-deploy.md)
|
|
10
|
+
> (create-keeljs → local → Cloudflare or optional Keel Cloud). For deep
|
|
11
|
+
> lookups, connect the MCP server and call `keel_overview`, then
|
|
12
|
+
> `keel_search_docs` / `keel_search_api`.
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
package/README.md
CHANGED
|
@@ -61,19 +61,29 @@ export class HomeController {
|
|
|
61
61
|
- **Thin and legible.** The whole framework is a few hundred lines in
|
|
62
62
|
`src/core/`. No magic you can't read.
|
|
63
63
|
|
|
64
|
-
## Two
|
|
64
|
+
## Two pieces: the framework and your app
|
|
65
65
|
|
|
66
|
-
Keel is
|
|
67
|
-
|
|
66
|
+
Keel is a **library** you install. New apps come from the generator (templates
|
|
67
|
+
ship inside the package so they cannot lag the framework):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm create keeljs@latest my-app
|
|
71
|
+
cd my-app && npm install && npm run dev
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
End-to-end (local → Cloudflare or optional Keel Cloud):
|
|
75
|
+
[From install to deploy](./docs/from-install-to-deploy.md).
|
|
68
76
|
|
|
69
77
|
| Repo | Role |
|
|
70
78
|
|------|------|
|
|
71
79
|
| [`shaferllc/keel`](https://github.com/shaferllc/keel) (this repo) | The framework. Published as `@shaferllc/keel`. |
|
|
72
|
-
|
|
|
80
|
+
| Your app (via `create-keeljs`) | Routes, models, views — depends on `@shaferllc/keel`. |
|
|
73
81
|
|
|
74
82
|
## Install in your app
|
|
75
83
|
|
|
76
84
|
```bash
|
|
85
|
+
npm create keeljs@latest my-app
|
|
86
|
+
# or, into an existing project:
|
|
77
87
|
npm install @shaferllc/keel
|
|
78
88
|
```
|
|
79
89
|
|
|
@@ -81,24 +91,20 @@ npm install @shaferllc/keel
|
|
|
81
91
|
import { Application, Router, config } from "@shaferllc/keel/core";
|
|
82
92
|
```
|
|
83
93
|
|
|
84
|
-
Or clone the [starter app](https://github.com/shaferllc/keel-app) and start
|
|
85
|
-
from a working skeleton.
|
|
86
|
-
|
|
87
94
|
## Hack on the framework itself
|
|
88
95
|
|
|
89
96
|
```bash
|
|
90
97
|
git clone https://github.com/shaferllc/keel.git
|
|
91
98
|
cd keel
|
|
92
99
|
npm install
|
|
93
|
-
npm test
|
|
94
|
-
npm run typecheck
|
|
95
|
-
npm run build
|
|
96
|
-
npm run verify:release
|
|
100
|
+
npm test
|
|
101
|
+
npm run typecheck
|
|
102
|
+
npm run build
|
|
103
|
+
npm run verify:release
|
|
97
104
|
```
|
|
98
105
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
at your checkout (`"@shaferllc/keel": "file:../keel"`).
|
|
106
|
+
Point a generated kit at your checkout with
|
|
107
|
+
`"@shaferllc/keel": "file:../keel"` while developing.
|
|
102
108
|
|
|
103
109
|
## The console
|
|
104
110
|
|
|
@@ -192,7 +198,9 @@ See [docs/architecture.md](./docs/architecture.md) for the full picture.
|
|
|
192
198
|
|
|
193
199
|
| Guide | What it covers |
|
|
194
200
|
|-------|----------------|
|
|
195
|
-
| [Getting Started](./docs/getting-started.md) |
|
|
201
|
+
| [Getting Started](./docs/getting-started.md) | First route, controller, view, config |
|
|
202
|
+
| [From install to deploy](./docs/from-install-to-deploy.md) | create-keeljs → local → Cloudflare or Keel Cloud |
|
|
203
|
+
| [Starter kits](./docs/starter-kits.md) | Presets (`minimal` / `api` / `app` / `saas`) |
|
|
196
204
|
| [The Service Container](./docs/container.md) | Binding and resolving services, DI |
|
|
197
205
|
| [Service Providers](./docs/providers.md) | Plugin system: register/boot lifecycle, options |
|
|
198
206
|
| [Configuration](./docs/configuration.md) | `config/*.ts`, dot-notation, `env()` |
|
|
@@ -15,7 +15,17 @@ import { defaultConfig, resolveConfig } from "./config.js";
|
|
|
15
15
|
import { accountsMigration } from "./migration.js";
|
|
16
16
|
import { registerAccountsRoutes } from "./routes.js";
|
|
17
17
|
import { setAccountStore, tableStore } from "./store.js";
|
|
18
|
-
|
|
18
|
+
function packageDir() {
|
|
19
|
+
try {
|
|
20
|
+
const url = import.meta.url;
|
|
21
|
+
if (!url)
|
|
22
|
+
return ".";
|
|
23
|
+
return dirname(fileURLToPath(url));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return ".";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
19
29
|
export class AccountsServiceProvider extends PackageProvider {
|
|
20
30
|
name = "accounts";
|
|
21
31
|
config;
|
|
@@ -24,7 +34,7 @@ export class AccountsServiceProvider extends PackageProvider {
|
|
|
24
34
|
this.config = resolveConfig();
|
|
25
35
|
setAccountStore(tableStore(this.config.userTable));
|
|
26
36
|
this.migrations([accountsMigration(this.config.userTable)]);
|
|
27
|
-
this.publishes({ [join(
|
|
37
|
+
this.publishes({ [join(packageDir(), "accounts.config.stub")]: "config/accounts.ts" }, "accounts-config");
|
|
28
38
|
}
|
|
29
39
|
boot() {
|
|
30
40
|
if (!this.config.routes.enabled)
|
package/dist/billing/provider.js
CHANGED
|
@@ -17,7 +17,17 @@ import { BillingManager, setBilling } from "./manager.js";
|
|
|
17
17
|
import { registerDefaultGateways } from "./drivers/index.js";
|
|
18
18
|
import { billingMigration } from "./migration.js";
|
|
19
19
|
import { registerBillingRoutes } from "./routes.js";
|
|
20
|
-
|
|
20
|
+
function packageDir() {
|
|
21
|
+
try {
|
|
22
|
+
const url = import.meta.url;
|
|
23
|
+
if (!url)
|
|
24
|
+
return ".";
|
|
25
|
+
return dirname(fileURLToPath(url));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return ".";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
21
31
|
export class BillingServiceProvider extends PackageProvider {
|
|
22
32
|
name = "billing";
|
|
23
33
|
config;
|
|
@@ -31,7 +41,7 @@ export class BillingServiceProvider extends PackageProvider {
|
|
|
31
41
|
this.app.instance(BillingManager, this.manager);
|
|
32
42
|
// Default billable table is `users`.
|
|
33
43
|
this.migrations([billingMigration("users")]);
|
|
34
|
-
this.publishes({ [join(
|
|
44
|
+
this.publishes({ [join(packageDir(), "billing.config.stub")]: "config/billing.ts" }, "billing-config");
|
|
35
45
|
}
|
|
36
46
|
boot() {
|
|
37
47
|
this.routes((r) => registerBillingRoutes(r, this.config.webhook.path));
|
package/dist/mcp/cloud.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Keel Cloud MCP tools — registered only when KEEL_CLOUD_TOKEN is set.
|
|
3
3
|
*
|
|
4
4
|
* Talks to a Keel Cloud control plane over HTTP (Bearer token). Agents use these
|
|
5
|
-
* to create sites, preview/publish,
|
|
5
|
+
* to create sites, preview/publish, manage secrets/domains/billing, and export
|
|
6
|
+
* without leaving the IDE.
|
|
6
7
|
*/
|
|
7
8
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
9
|
/** Register Cloud tools on an existing MCP server when a Cloud token is present. */
|
package/dist/mcp/cloud.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Keel Cloud MCP tools — registered only when KEEL_CLOUD_TOKEN is set.
|
|
3
3
|
*
|
|
4
4
|
* Talks to a Keel Cloud control plane over HTTP (Bearer token). Agents use these
|
|
5
|
-
* to create sites, preview/publish,
|
|
5
|
+
* to create sites, preview/publish, manage secrets/domains/billing, and export
|
|
6
|
+
* without leaving the IDE.
|
|
6
7
|
*/
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
const PRESETS = ["minimal", "api", "app", "saas"];
|
|
@@ -42,18 +43,49 @@ function jsonText(data, isError = false) {
|
|
|
42
43
|
...(isError ? { isError: true } : {}),
|
|
43
44
|
};
|
|
44
45
|
}
|
|
46
|
+
function requireConfirm(confirm, action) {
|
|
47
|
+
if (confirm)
|
|
48
|
+
return null;
|
|
49
|
+
return jsonText({
|
|
50
|
+
error: `${action} requires confirm=true. Ask the user to confirm before calling again.`,
|
|
51
|
+
}, true);
|
|
52
|
+
}
|
|
45
53
|
/** Register Cloud tools on an existing MCP server when a Cloud token is present. */
|
|
46
54
|
export function registerCloudTools(server) {
|
|
47
55
|
if (!cloudConfig())
|
|
48
56
|
return false;
|
|
49
57
|
server.registerTool("keel_cloud_me", {
|
|
50
58
|
title: "Keel Cloud — who am I",
|
|
51
|
-
description: "Return the Keel Cloud user authenticated by KEEL_CLOUD_TOKEN.",
|
|
59
|
+
description: "Return the Keel Cloud user authenticated by KEEL_CLOUD_TOKEN (plan, site_limit, team_id). Token binds to the user's first team.",
|
|
52
60
|
inputSchema: {},
|
|
53
61
|
}, async () => {
|
|
54
62
|
const res = await cloudFetch("/api/v1/me");
|
|
55
63
|
return jsonText(res.body, !res.ok);
|
|
56
64
|
});
|
|
65
|
+
server.registerTool("keel_cloud_billing", {
|
|
66
|
+
title: "Keel Cloud — billing status",
|
|
67
|
+
description: "Current team plan (free|pro), site limits, custom-domain eligibility, and whether the caller is the owner.",
|
|
68
|
+
inputSchema: {},
|
|
69
|
+
}, async () => {
|
|
70
|
+
const res = await cloudFetch("/api/v1/billing");
|
|
71
|
+
return jsonText(res.body, !res.ok);
|
|
72
|
+
});
|
|
73
|
+
server.registerTool("keel_cloud_billing_checkout", {
|
|
74
|
+
title: "Keel Cloud — Stripe checkout URL",
|
|
75
|
+
description: "Create a Stripe Checkout session for Keel Cloud Pro (owner only). Return the url for the user to open — do not scrape cards.",
|
|
76
|
+
inputSchema: {},
|
|
77
|
+
}, async () => {
|
|
78
|
+
const res = await cloudFetch("/api/v1/billing/checkout", { method: "POST", body: "{}" });
|
|
79
|
+
return jsonText(res.body, !res.ok);
|
|
80
|
+
});
|
|
81
|
+
server.registerTool("keel_cloud_billing_portal", {
|
|
82
|
+
title: "Keel Cloud — Stripe customer portal URL",
|
|
83
|
+
description: "Open the Stripe customer portal URL for the team (owner only) to update card / cancel. Return the url for the user.",
|
|
84
|
+
inputSchema: {},
|
|
85
|
+
}, async () => {
|
|
86
|
+
const res = await cloudFetch("/api/v1/billing/portal", { method: "POST", body: "{}" });
|
|
87
|
+
return jsonText(res.body, !res.ok);
|
|
88
|
+
});
|
|
57
89
|
server.registerTool("keel_cloud_list_sites", {
|
|
58
90
|
title: "Keel Cloud — list sites",
|
|
59
91
|
description: "List sites on the current Keel Cloud team. Includes storage_path for local editing and hostnames.",
|
|
@@ -64,7 +96,7 @@ export function registerCloudTools(server) {
|
|
|
64
96
|
});
|
|
65
97
|
server.registerTool("keel_cloud_get_site", {
|
|
66
98
|
title: "Keel Cloud — get site",
|
|
67
|
-
description: "Fetch one Keel Cloud site by id (paths, hostnames, status).",
|
|
99
|
+
description: "Fetch one Keel Cloud site by id (paths, hostnames, status, git).",
|
|
68
100
|
inputSchema: {
|
|
69
101
|
site_id: z.number().int().describe("Site id from keel_cloud_list_sites"),
|
|
70
102
|
},
|
|
@@ -86,6 +118,36 @@ export function registerCloudTools(server) {
|
|
|
86
118
|
});
|
|
87
119
|
return jsonText(res.body, !res.ok);
|
|
88
120
|
});
|
|
121
|
+
server.registerTool("keel_cloud_delete_site", {
|
|
122
|
+
title: "Keel Cloud — soft-delete site",
|
|
123
|
+
description: "Soft-delete a site (detaches hostnames; recoverable within retention). Requires confirm=true.",
|
|
124
|
+
inputSchema: {
|
|
125
|
+
site_id: z.number().int().describe("Site id"),
|
|
126
|
+
confirm: z.boolean().describe("Must be true — ask the user before setting this"),
|
|
127
|
+
},
|
|
128
|
+
}, async ({ site_id, confirm }) => {
|
|
129
|
+
const blocked = requireConfirm(confirm, "Delete");
|
|
130
|
+
if (blocked)
|
|
131
|
+
return blocked;
|
|
132
|
+
const res = await cloudFetch(`/api/v1/sites/${site_id}/delete`, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
body: JSON.stringify({ confirm: true }),
|
|
135
|
+
});
|
|
136
|
+
return jsonText(res.body, !res.ok);
|
|
137
|
+
});
|
|
138
|
+
server.registerTool("keel_cloud_restore_site", {
|
|
139
|
+
title: "Keel Cloud — restore soft-deleted site",
|
|
140
|
+
description: "Restore a soft-deleted site within the retention window. Redeploy to reattach hostnames.",
|
|
141
|
+
inputSchema: {
|
|
142
|
+
site_id: z.number().int().describe("Site id"),
|
|
143
|
+
},
|
|
144
|
+
}, async ({ site_id }) => {
|
|
145
|
+
const res = await cloudFetch(`/api/v1/sites/${site_id}/restore`, {
|
|
146
|
+
method: "POST",
|
|
147
|
+
body: "{}",
|
|
148
|
+
});
|
|
149
|
+
return jsonText(res.body, !res.ok);
|
|
150
|
+
});
|
|
89
151
|
server.registerTool("keel_cloud_preview", {
|
|
90
152
|
title: "Keel Cloud — deploy preview",
|
|
91
153
|
description: "Deploy the site's preview Worker (and attach preview hostname when Cloudflare is configured). Safe to call freely while iterating.",
|
|
@@ -106,11 +168,9 @@ export function registerCloudTools(server) {
|
|
|
106
168
|
.describe("Must be true to publish — ask the user before setting this"),
|
|
107
169
|
},
|
|
108
170
|
}, async ({ site_id, confirm }) => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}, true);
|
|
113
|
-
}
|
|
171
|
+
const blocked = requireConfirm(confirm, "Publish");
|
|
172
|
+
if (blocked)
|
|
173
|
+
return blocked;
|
|
114
174
|
const res = await cloudFetch(`/api/v1/sites/${site_id}/publish`, {
|
|
115
175
|
method: "POST",
|
|
116
176
|
body: JSON.stringify({ confirm: true }),
|
|
@@ -127,6 +187,16 @@ export function registerCloudTools(server) {
|
|
|
127
187
|
const res = await cloudFetch(`/api/v1/sites/${site_id}/deploys`);
|
|
128
188
|
return jsonText(res.body, !res.ok);
|
|
129
189
|
});
|
|
190
|
+
server.registerTool("keel_cloud_list_secrets", {
|
|
191
|
+
title: "Keel Cloud — list secret keys",
|
|
192
|
+
description: "List vault key names for a site (values are never returned).",
|
|
193
|
+
inputSchema: {
|
|
194
|
+
site_id: z.number().int().describe("Site id"),
|
|
195
|
+
},
|
|
196
|
+
}, async ({ site_id }) => {
|
|
197
|
+
const res = await cloudFetch(`/api/v1/sites/${site_id}/secrets`);
|
|
198
|
+
return jsonText(res.body, !res.ok);
|
|
199
|
+
});
|
|
130
200
|
server.registerTool("keel_cloud_set_secret", {
|
|
131
201
|
title: "Keel Cloud — set secret",
|
|
132
202
|
description: "Store a secret in the site vault (never in git). Injected into the Worker on the next preview/publish.",
|
|
@@ -142,6 +212,45 @@ export function registerCloudTools(server) {
|
|
|
142
212
|
});
|
|
143
213
|
return jsonText(res.body, !res.ok);
|
|
144
214
|
});
|
|
215
|
+
server.registerTool("keel_cloud_delete_secret", {
|
|
216
|
+
title: "Keel Cloud — delete secret",
|
|
217
|
+
description: "Remove a secret key from the site vault.",
|
|
218
|
+
inputSchema: {
|
|
219
|
+
site_id: z.number().int().describe("Site id"),
|
|
220
|
+
key: z.string().min(1).describe("Secret key to remove"),
|
|
221
|
+
},
|
|
222
|
+
}, async ({ site_id, key }) => {
|
|
223
|
+
const res = await cloudFetch(`/api/v1/sites/${site_id}/secrets?key=${encodeURIComponent(key)}`, { method: "DELETE" });
|
|
224
|
+
return jsonText(res.body, !res.ok);
|
|
225
|
+
});
|
|
226
|
+
server.registerTool("keel_cloud_set_custom_domain", {
|
|
227
|
+
title: "Keel Cloud — set custom domain",
|
|
228
|
+
description: "Set a Pro custom hostname (CNAME instructions returned). Optionally attach=true to verify DNS and attach to the production Worker.",
|
|
229
|
+
inputSchema: {
|
|
230
|
+
site_id: z.number().int().describe("Site id"),
|
|
231
|
+
hostname: z.string().min(1).describe("Customer hostname, e.g. app.example.com"),
|
|
232
|
+
attach: z
|
|
233
|
+
.boolean()
|
|
234
|
+
.optional()
|
|
235
|
+
.describe("If true, verify DNS and attach Workers Custom Domain now"),
|
|
236
|
+
},
|
|
237
|
+
}, async ({ site_id, hostname, attach }) => {
|
|
238
|
+
const res = await cloudFetch(`/api/v1/sites/${site_id}/custom-domain`, {
|
|
239
|
+
method: "PUT",
|
|
240
|
+
body: JSON.stringify({ hostname, attach: Boolean(attach) }),
|
|
241
|
+
});
|
|
242
|
+
return jsonText(res.body, !res.ok);
|
|
243
|
+
});
|
|
244
|
+
server.registerTool("keel_cloud_clear_custom_domain", {
|
|
245
|
+
title: "Keel Cloud — clear custom domain",
|
|
246
|
+
description: "Detach and clear the site's custom hostname (Pro).",
|
|
247
|
+
inputSchema: {
|
|
248
|
+
site_id: z.number().int().describe("Site id"),
|
|
249
|
+
},
|
|
250
|
+
}, async ({ site_id }) => {
|
|
251
|
+
const res = await cloudFetch(`/api/v1/sites/${site_id}/custom-domain`, { method: "DELETE" });
|
|
252
|
+
return jsonText(res.body, !res.ok);
|
|
253
|
+
});
|
|
145
254
|
server.registerTool("keel_cloud_export", {
|
|
146
255
|
title: "Keel Cloud — export manifest",
|
|
147
256
|
description: "Return the site's export manifest (paths, hostnames, Keel version, SQL dump URLs). Use storage_path / git_url for code; use keel_cloud_export_sql for data.",
|
package/dist/mcp/server.js
CHANGED
|
@@ -190,12 +190,14 @@ export async function createServer() {
|
|
|
190
190
|
? [
|
|
191
191
|
"",
|
|
192
192
|
"## Keel Cloud (token detected)",
|
|
193
|
-
"Cloud tools are enabled.
|
|
193
|
+
"Cloud tools are enabled. Token binds to the user's first team.",
|
|
194
|
+
"Typical loop:",
|
|
194
195
|
"1. keel_cloud_create_site { name, preset }",
|
|
195
196
|
"2. Edit files at the returned storage_path (real Keel app)",
|
|
196
197
|
"3. keel_cloud_preview { site_id }",
|
|
197
198
|
"4. keel_cloud_publish { site_id, confirm: true } after user approval",
|
|
198
|
-
"Also:
|
|
199
|
+
"Also: me, billing(+checkout/portal), list/get/delete/restore sites,",
|
|
200
|
+
"secrets (list/set/delete), custom domain (set/clear), deploys, export(+sql).",
|
|
199
201
|
]
|
|
200
202
|
: []),
|
|
201
203
|
].join("\n");
|
package/dist/teams/provider.js
CHANGED
|
@@ -14,7 +14,17 @@ import { dirname, join } from "node:path";
|
|
|
14
14
|
import { PackageProvider } from "../core/package.js";
|
|
15
15
|
import { defaultConfig, resolveConfig } from "./config.js";
|
|
16
16
|
import { teamsMigration } from "./migration.js";
|
|
17
|
-
|
|
17
|
+
function packageDir() {
|
|
18
|
+
try {
|
|
19
|
+
const url = import.meta.url;
|
|
20
|
+
if (!url)
|
|
21
|
+
return ".";
|
|
22
|
+
return dirname(fileURLToPath(url));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return ".";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
18
28
|
export class TeamsServiceProvider extends PackageProvider {
|
|
19
29
|
name = "teams";
|
|
20
30
|
config;
|
|
@@ -22,6 +32,6 @@ export class TeamsServiceProvider extends PackageProvider {
|
|
|
22
32
|
this.mergeConfig("teams", defaultConfig);
|
|
23
33
|
this.config = resolveConfig();
|
|
24
34
|
this.migrations([teamsMigration(this.config.userTable)]);
|
|
25
|
-
this.publishes({ [join(
|
|
35
|
+
this.publishes({ [join(packageDir(), "teams.config.stub")]: "config/teams.ts" }, "teams-config");
|
|
26
36
|
}
|
|
27
37
|
}
|
package/docs/ai-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaferllc/keel",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.6",
|
|
4
4
|
"description": "The house framework for Node.js — a service container, providers, routing, JSX views, and a code-generating console.",
|
|
5
5
|
"repo": "https://github.com/shaferllc/keel",
|
|
6
6
|
"generated": "run `npm run build:ai` to regenerate",
|
|
@@ -159,6 +159,13 @@
|
|
|
159
159
|
"path": "docs/factories.md",
|
|
160
160
|
"example": "docs/examples/factories.ts"
|
|
161
161
|
},
|
|
162
|
+
{
|
|
163
|
+
"slug": "from-install-to-deploy",
|
|
164
|
+
"title": "From install to deploy",
|
|
165
|
+
"summary": "One path from zero to a live Keel app — locally, on Cloudflare yourself, or on Keel Cloud with an AI agent.",
|
|
166
|
+
"path": "docs/from-install-to-deploy.md",
|
|
167
|
+
"example": null
|
|
168
|
+
},
|
|
162
169
|
{
|
|
163
170
|
"slug": "gates",
|
|
164
171
|
"title": "Gates",
|
package/docs/ai.md
CHANGED
|
@@ -5,8 +5,9 @@ AI-facing surface: an MCP server, machine-readable docs (`llms.txt` /
|
|
|
5
5
|
`llms-full.txt`), an agent playbook (`AGENTS.md`), and code generators an agent
|
|
6
6
|
can drive directly.
|
|
7
7
|
|
|
8
|
-
If you only read one thing:
|
|
9
|
-
|
|
8
|
+
If you only read one thing: follow
|
|
9
|
+
[From install to deploy](./from-install-to-deploy.md), then point your agent at
|
|
10
|
+
the [MCP server](#the-mcp-server) and have it call `keel_overview` first.
|
|
10
11
|
|
|
11
12
|
## Why this exists
|
|
12
13
|
|
|
@@ -62,18 +63,23 @@ package, so it always matches your installed version.
|
|
|
62
63
|
| `keel_scaffold` | Generate a controller/provider/middleware/factory/seeder/job/notification/transformer stub. Returns code + target path — it does **not** write to disk. |
|
|
63
64
|
|
|
64
65
|
When `KEEL_CLOUD_TOKEN` (and optional `KEEL_CLOUD_URL`) is set, Cloud tools are
|
|
65
|
-
also registered
|
|
66
|
+
also registered. Create a token at `/tokens` on the control plane — the plaintext
|
|
67
|
+
looks like `keel_<selector>.<verifier>`.
|
|
66
68
|
|
|
67
69
|
| Tool | What it does |
|
|
68
70
|
|------|--------------|
|
|
69
|
-
| `keel_cloud_me` | Authenticated Cloud user |
|
|
70
|
-
| `
|
|
71
|
+
| `keel_cloud_me` | Authenticated Cloud user (plan, site limit, team) |
|
|
72
|
+
| `keel_cloud_billing` | Team plan / limits / owner flag |
|
|
73
|
+
| `keel_cloud_billing_checkout` / `_portal` | Stripe Checkout or Customer Portal URL (owner) |
|
|
74
|
+
| `keel_cloud_list_sites` / `keel_cloud_get_site` | List or fetch a site (`storage_path`, hostnames, git) |
|
|
71
75
|
| `keel_cloud_create_site` | Create from preset (`minimal` \| `api` \| `app` \| `saas`) |
|
|
76
|
+
| `keel_cloud_delete_site` / `keel_cloud_restore_site` | Soft-delete (confirm) / restore |
|
|
72
77
|
| `keel_cloud_preview` | Deploy preview Worker |
|
|
73
78
|
| `keel_cloud_publish` | Publish production — requires `confirm: true` |
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
79
|
+
| `keel_cloud_deploys` | Deploy history + logs |
|
|
80
|
+
| `keel_cloud_list_secrets` / `keel_cloud_set_secret` / `keel_cloud_delete_secret` | Vault keys (values never returned) |
|
|
81
|
+
| `keel_cloud_set_custom_domain` / `keel_cloud_clear_custom_domain` | Pro custom hostname (+ optional attach) |
|
|
82
|
+
| `keel_cloud_export` / `keel_cloud_export_sql` | Export manifest / portable `.sql` dump |
|
|
77
83
|
|
|
78
84
|
```json
|
|
79
85
|
{
|
|
@@ -82,7 +88,7 @@ also registered:
|
|
|
82
88
|
"command": "npx",
|
|
83
89
|
"args": ["-y", "keel-mcp"],
|
|
84
90
|
"env": {
|
|
85
|
-
"KEEL_CLOUD_TOKEN": "
|
|
91
|
+
"KEEL_CLOUD_TOKEN": "keel_….…",
|
|
86
92
|
"KEEL_CLOUD_URL": "https://app.keeljs.cloud"
|
|
87
93
|
}
|
|
88
94
|
}
|
|
@@ -90,6 +96,8 @@ also registered:
|
|
|
90
96
|
}
|
|
91
97
|
```
|
|
92
98
|
|
|
99
|
+
The token binds to the user's **first team**. Switch teams in the dashboard before
|
|
100
|
+
minting a token if you need a different team context.
|
|
93
101
|
### Resources
|
|
94
102
|
|
|
95
103
|
- `keel://overview` — the same orientation text as `keel_overview`
|
|
@@ -108,8 +116,11 @@ also registered:
|
|
|
108
116
|
|
|
109
117
|
1. `keel_cloud_create_site { name: "Acme", preset: "app" }`
|
|
110
118
|
2. Edit the returned `storage_path` (real Keel app + git)
|
|
111
|
-
3. `
|
|
112
|
-
4. `
|
|
119
|
+
3. `keel_cloud_set_secret` for env the Worker needs
|
|
120
|
+
4. `keel_cloud_preview { site_id }`
|
|
121
|
+
5. `keel_cloud_publish { site_id, confirm: true }` after the user approves
|
|
122
|
+
6. Optional Pro: `keel_cloud_set_custom_domain { hostname, attach: true }`
|
|
123
|
+
7. Escape hatch anytime: `keel_cloud_export` + `keel_cloud_export_sql`
|
|
113
124
|
|
|
114
125
|
## `llms.txt` and `llms-full.txt`
|
|
115
126
|
|
package/docs/changelog.md
CHANGED
|
@@ -4,6 +4,27 @@ All notable changes to Keel are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project aims to
|
|
5
5
|
adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.83.6] — 2026-07-13
|
|
8
|
+
|
|
9
|
+
### Documentation
|
|
10
|
+
|
|
11
|
+
- **[From install to deploy](./docs/from-install-to-deploy.md)** — end-to-end
|
|
12
|
+
guide: `create-keeljs` → local dev → Cloudflare self-deploy → optional Keel
|
|
13
|
+
Cloud + MCP. Getting Started and the README now lead with the generator.
|
|
14
|
+
|
|
15
|
+
[0.83.6]: https://github.com/shaferllc/keel/releases/tag/v0.83.6
|
|
16
|
+
|
|
17
|
+
## [0.83.5] — 2026-07-13
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Full Keel Cloud MCP surface** — billing status/checkout/portal, soft-delete
|
|
22
|
+
and restore sites, list/delete secrets, set/clear custom domains. Documented in
|
|
23
|
+
[Building with AI](./docs/ai.md). Pairs with expanded `/api/v1` routes on Keel
|
|
24
|
+
Cloud.
|
|
25
|
+
|
|
26
|
+
[0.83.5]: https://github.com/shaferllc/keel/releases/tag/v0.83.5
|
|
27
|
+
|
|
7
28
|
## [0.83.4] — 2026-07-13
|
|
8
29
|
|
|
9
30
|
### Added
|