@aotter/mantle 0.1.4 → 0.1.5-alpha.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/README.md +16 -16
- package/dist/cli/generate-cloudflare.d.ts +7 -0
- package/dist/cli/generate-cloudflare.d.ts.map +1 -0
- package/dist/cli/generate-cloudflare.js +123 -0
- package/dist/cli/generate-cloudflare.js.map +1 -0
- package/dist/cli/generate-project.d.ts +25 -0
- package/dist/cli/generate-project.d.ts.map +1 -0
- package/dist/cli/generate-project.js +282 -0
- package/dist/cli/generate-project.js.map +1 -0
- package/dist/cli/generate-sites.d.ts +8 -0
- package/dist/cli/generate-sites.d.ts.map +1 -0
- package/dist/cli/generate-sites.js +273 -0
- package/dist/cli/generate-sites.js.map +1 -0
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +121 -10
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +10 -10
- package/docs/adr/0021-retire-starter-scaffolding.md +1 -1
- package/docs/adr/0026-progressive-generate.md +36 -0
- package/docs/adr/0027-scheduled-procedure-triggers.md +31 -0
- package/docs/adr/0028-schema-ttl-expiry.md +33 -0
- package/docs/adr/README.md +5 -2
- package/docs/agent-prompts.md +40 -78
- package/docs/examples/host-chatgpt-sites/README.md +1 -1
- package/docs/examples/host-chatgpt-sites/drizzle/0004_mantle.sql +10 -0
- package/docs/examples/host-chatgpt-sites/drizzle/0005_mantle.sql +24 -0
- package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +1 -1
- package/docs/examples/host-chatgpt-sites/drizzle/meta/mantle-state.json +60 -0
- package/docs/examples/host-chatgpt-sites/package.json +1 -1
- package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +42 -8
- package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +9 -6
- package/docs/examples/host-local-admin-otp/package.json +2 -2
- package/docs/examples/host-minimal-worker/package.json +2 -2
- package/docs/handbook/chatgpt-sites/generated-app.md +84 -0
- package/docs/handbook/chatgpt-sites/index.md +21 -11
- package/docs/handbook/cloudflare/authentication.md +19 -2
- package/docs/handbook/cloudflare/bindings.md +4 -11
- package/docs/handbook/cloudflare/conventional-worker.md +7 -3
- package/docs/handbook/cloudflare/deploy-and-operate.md +1 -1
- package/docs/handbook/concepts/runtime-and-adapters.md +7 -0
- package/docs/handbook/guides/agent-setup.md +3 -3
- package/docs/handbook/navigation.json +3 -2
- package/docs/handbook/reference/diagnostics.md +5 -0
- package/docs/handbook/reference/procedure.md +52 -1
- package/docs/handbook/reference/schema.md +27 -1
- package/docs/handbook/reference/surface.md +3 -3
- package/docs/handbook/reference/trigger.md +21 -1
- package/docs/handbook/releases/index.md +55 -0
- package/docs/handbook/start/overview.md +5 -2
- package/docs/handbook/start/project-and-cli.md +103 -119
- package/docs/handbook/start/quickstart-admin.md +6 -4
- package/docs/handbook/start/quickstart-worker.md +17 -8
- package/docs/skills/develop/SKILL.md +14 -6
- package/docs/skills/integrate/SKILL.md +60 -0
- package/package.json +18 -17
- package/skills/README.md +3 -1
- package/skills/develop/SKILL.md +14 -6
- package/skills/install/SKILL.md +100 -137
- package/skills/integrate/SKILL.md +60 -0
- package/templates/chatgpt-sites/auth.ts +66 -0
- package/templates/chatgpt-sites/build.mjs +14 -0
- package/templates/chatgpt-sites/env.ts +1 -0
- package/templates/chatgpt-sites/mcp.ts +48 -0
- package/templates/chatgpt-sites/public-mcp.ts +29 -0
- package/templates/chatgpt-sites/smoke-local.mjs +20 -0
package/README.md
CHANGED
|
@@ -9,19 +9,18 @@ where agents write config and the runtime carries the complexity.
|
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
An agent can install the small bootstrap skill:
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
15
|
npx skills add aotter/mantle
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
For a new application, resolve one published stable version and install it
|
|
19
|
+
exactly. `mantle generate` will declare matching selected packages:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
npm
|
|
23
|
-
|
|
24
|
-
pnpm add @aotter/mantle
|
|
22
|
+
MANTLE_VERSION=$(npm view @aotter/mantle@latest version)
|
|
23
|
+
npm install --save-exact "@aotter/mantle@$MANTLE_VERSION"
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
## What's inside
|
|
@@ -67,11 +66,13 @@ pnpm exec mantle-harness indexes --require-public
|
|
|
67
66
|
pnpm exec mantle-harness http --base-url http://127.0.0.1:8787 --route page=/en/example
|
|
68
67
|
```
|
|
69
68
|
|
|
70
|
-
`mantle generate`
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
`mantle generate --host cf` or `--host chatgpt-sites` assembles a new blank
|
|
70
|
+
app with Spec, Runtime, API, MCP, Admin and Web by default. Use `--features`
|
|
71
|
+
to select a smaller set, including host-free Spec-only. The first run declares
|
|
72
|
+
matching optional dependencies; install them, then rerun. In an existing
|
|
73
|
+
direct-authored app, `generate` keeps its compile behavior: validate
|
|
74
|
+
`./manifests/` and write `.mantle/generated/mantle.ts`. Selected Admin syncs
|
|
75
|
+
its prebuilt SPA to `public/_mantle/admin/`. Generation does not deploy.
|
|
75
76
|
The same pure emitter is available from `@aotter/mantle/codegen` when a host
|
|
76
77
|
wants to own parsing and filesystem IO. TypeScript-authored manifests can pass
|
|
77
78
|
their already-compiled `plan` directly:
|
|
@@ -104,11 +105,10 @@ does not cache or retry. Dynamic and platform hosts can keep their own lifecycle
|
|
|
104
105
|
use generated `bindMantle(runtime)`, or skip code generation and call
|
|
105
106
|
`runtime.executeView({ view: "published-notes" })` directly.
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
an application or a visitor home page.
|
|
108
|
+
Start with [Project layout and CLI](docs/handbook/start/project-and-cli.md).
|
|
109
|
+
The [local Admin OTP](docs/handbook/start/quickstart-admin.md) tutorial remains
|
|
110
|
+
for apps that own their Worker entry. Generated apps start with an editable
|
|
111
|
+
blank home and no invented business Schema.
|
|
112
112
|
|
|
113
113
|
`mantle skills` copies every skill the installed package marks
|
|
114
114
|
`projection: project` in its front matter into matching
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ProjectSelection } from "./generate-project.js";
|
|
2
|
+
/** Prepare all paths before the caller commits any project files. */
|
|
3
|
+
export declare function prepareCloudflare(root: string, output: string, selection: ProjectSelection, fresh: boolean): Promise<{
|
|
4
|
+
readonly stale: boolean;
|
|
5
|
+
readonly commit: () => Promise<void>;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=generate-cloudflare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-cloudflare.d.ts","sourceRoot":"","sources":["../../src/cli/generate-cloudflare.ts"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAInF,qEAAqE;AACrE,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAC1H,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC,CAAC,CAuFD"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { appendFile, lstat, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { assertInsideProject } from "./generate-project.js";
|
|
4
|
+
/** Prepare all paths before the caller commits any project files. */
|
|
5
|
+
export async function prepareCloudflare(root, output, selection, fresh) {
|
|
6
|
+
const selected = (feature) => selection.features.includes(feature);
|
|
7
|
+
const name = basename(root).toLowerCase().replace(/[^a-z0-9-]/g, "-")
|
|
8
|
+
.replace(/^-+|-+$/g, "").slice(0, 63).replace(/-+$/g, "") || "mantle-app";
|
|
9
|
+
const worker = resolve(root, output, "worker.ts");
|
|
10
|
+
const fromIndex = importPath(join(root, "src/index.ts"), worker);
|
|
11
|
+
const toHandlers = importPath(worker, join(root, "src/handlers.ts"));
|
|
12
|
+
const toHome = importPath(worker, join(root, "src/home.ts"));
|
|
13
|
+
if (!selected("admin")) {
|
|
14
|
+
const adminAssets = join(root, "public/_mantle/admin");
|
|
15
|
+
await assertInsideProject(root, adminAssets);
|
|
16
|
+
const present = await lstat(adminAssets).then(() => true, (error) => {
|
|
17
|
+
if (error.code === "ENOENT")
|
|
18
|
+
return false;
|
|
19
|
+
throw error;
|
|
20
|
+
});
|
|
21
|
+
if (present)
|
|
22
|
+
throw new Error("Unselected Admin assets already exist; remove them deliberately before generating this reduced composition.");
|
|
23
|
+
}
|
|
24
|
+
const files = [
|
|
25
|
+
{ path: worker, content: workerSource(selection, toHandlers, toHome), owned: true },
|
|
26
|
+
{ path: "src/index.ts", content: `export { default } from "${fromIndex}";\n`, owned: false },
|
|
27
|
+
{ path: "src/handlers.ts", content: 'import type { AnyHandler } from "@aotter/mantle/runtime";\n\nexport const handlers: Record<string, AnyHandler> = {};\n', owned: false },
|
|
28
|
+
{ path: "tsconfig.json", content: `${JSON.stringify({ compilerOptions: {
|
|
29
|
+
target: "ES2022", module: "NodeNext", moduleResolution: "NodeNext", strict: true,
|
|
30
|
+
noEmit: true, skipLibCheck: true, types: ["@cloudflare/workers-types"],
|
|
31
|
+
}, include: ["src/**/*.ts", `${relative(root, resolve(root, output)).split(sep).join("/") || "."}/**/*.ts`] }, null, 2)}\n`, owned: false },
|
|
32
|
+
];
|
|
33
|
+
const wrangler = await Promise.all(["wrangler.jsonc", "wrangler.json", "wrangler.toml"].map(async (path) => ({
|
|
34
|
+
path, text: await readFile(join(root, path), "utf8").catch((error) => {
|
|
35
|
+
if (error.code === "ENOENT")
|
|
36
|
+
return null;
|
|
37
|
+
throw error;
|
|
38
|
+
}),
|
|
39
|
+
})));
|
|
40
|
+
const presentWrangler = wrangler.filter((file) => file.text !== null);
|
|
41
|
+
if (presentWrangler.length > 1)
|
|
42
|
+
throw new Error(`Multiple Wrangler configs found: ${presentWrangler.map((file) => file.path).join(", ")}. Choose one before generating.`);
|
|
43
|
+
const existingWrangler = presentWrangler[0];
|
|
44
|
+
if (!existingWrangler) {
|
|
45
|
+
files.push({ path: "wrangler.jsonc", content: `${JSON.stringify({
|
|
46
|
+
$schema: "node_modules/wrangler/config-schema.json", name, main: "src/index.ts",
|
|
47
|
+
compatibility_date: "2026-09-08", compatibility_flags: ["nodejs_compat", "global_fetch_strictly_public"],
|
|
48
|
+
...(selected("admin") ? { assets: { directory: "./public", binding: "ASSETS" } } : {}),
|
|
49
|
+
d1_databases: [{ binding: "DB", database_name: name }],
|
|
50
|
+
}, null, 2)}\n`, owned: false });
|
|
51
|
+
}
|
|
52
|
+
if (selected("admin"))
|
|
53
|
+
files.push({ path: ".dev.vars.example", content: "# Copy to .dev.vars for local Admin OTP. Never deploy these values.\nMANTLE_AUTH_MODE=local-otp\nPUBLIC_ORIGIN=http://127.0.0.1:8787\nADMIN_EMAIL=you@example.com\nBETTER_AUTH_SECRET=replace-with-a-random-32-byte-secret\n", owned: false });
|
|
54
|
+
if (selected("web"))
|
|
55
|
+
files.push({
|
|
56
|
+
path: "src/home.ts", owned: false,
|
|
57
|
+
content: 'export function home(): Response {\n return new Response(`<!doctype html><html lang="en"><meta charset="utf-8"><title>Mantle</title><body><main></main></body></html>`, { headers: { "content-type": "text/html; charset=utf-8" } });\n}\n',
|
|
58
|
+
});
|
|
59
|
+
const ignorePath = join(root, ".gitignore");
|
|
60
|
+
await assertInsideProject(root, ignorePath);
|
|
61
|
+
const gitignore = await readFile(ignorePath, "utf8").catch((error) => {
|
|
62
|
+
if (error.code === "ENOENT")
|
|
63
|
+
return null;
|
|
64
|
+
throw error;
|
|
65
|
+
});
|
|
66
|
+
const ignoreMissing = !gitignore?.split(/\r?\n/).includes(".dev.vars");
|
|
67
|
+
let stale = ignoreMissing;
|
|
68
|
+
const writes = [];
|
|
69
|
+
for (const file of files) {
|
|
70
|
+
const path = resolve(root, file.path);
|
|
71
|
+
await assertInsideProject(root, path);
|
|
72
|
+
const current = await readFile(path, "utf8").catch((error) => {
|
|
73
|
+
if (error.code === "ENOENT")
|
|
74
|
+
return null;
|
|
75
|
+
throw error;
|
|
76
|
+
});
|
|
77
|
+
if (current !== null && file.owned && !current.startsWith("// Generated by `mantle generate`")) {
|
|
78
|
+
throw new Error(`Generated output would replace a user-owned file: ${path}`);
|
|
79
|
+
}
|
|
80
|
+
if ((current === null && (file.owned || fresh || ["src/index.ts", "src/handlers.ts", "src/home.ts", "tsconfig.json", "wrangler.jsonc"].includes(file.path))) ||
|
|
81
|
+
(file.owned && current !== file.content)) {
|
|
82
|
+
stale = true;
|
|
83
|
+
writes.push(file);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
stale,
|
|
88
|
+
commit: async () => {
|
|
89
|
+
for (const file of writes) {
|
|
90
|
+
const path = resolve(root, file.path);
|
|
91
|
+
await mkdir(dirname(path), { recursive: true });
|
|
92
|
+
await writeFile(path, file.content, { flag: file.owned ? "w" : "wx" });
|
|
93
|
+
}
|
|
94
|
+
if (ignoreMissing) {
|
|
95
|
+
if (gitignore === null)
|
|
96
|
+
await writeFile(ignorePath, "node_modules/\n.wrangler/\n.dev.vars\n", { flag: "wx" });
|
|
97
|
+
else
|
|
98
|
+
await appendFile(ignorePath, `${gitignore.endsWith("\n") ? "" : "\n"}.dev.vars\n`);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function workerSource(selection, toHandlers, toHome) {
|
|
104
|
+
const has = (feature) => selection.features.includes(feature);
|
|
105
|
+
const auth = has("admin");
|
|
106
|
+
return `// Generated by \`mantle generate\`. Edit src/home.ts and src/handlers.ts instead.\n` +
|
|
107
|
+
`import { createMantleWorker${auth ? ", createAuth, createConventionalAuth, ConsoleEmailSender" : ""}, type MantleCloudflareEnv } from "@aotter/mantle/cloudflare";\n` +
|
|
108
|
+
`import { plan } from "./mantle.js";\n` +
|
|
109
|
+
`import { handlers } from "${toHandlers}";\n` +
|
|
110
|
+
(has("web") ? `import { home } from "${toHome}";\n` : "") +
|
|
111
|
+
`\ntype Env = MantleCloudflareEnv & { readonly ADMIN_EMAIL?: string };\n` +
|
|
112
|
+
(auth ? `const sender = new ConsoleEmailSender();\n` : "") +
|
|
113
|
+
`\nexport default createMantleWorker<Env>({\n plan,\n handlers,\n` +
|
|
114
|
+
` surfaces: { api: ${has("api")}, mcp: ${has("mcp")}, admin: ${has("admin")} },\n` +
|
|
115
|
+
(has("web") ? ` frontend: () => home(),\n` : "") +
|
|
116
|
+
(auth ? ` auth: (env) => {\n if (env.MANTLE_AUTH_MODE !== "local-otp") return createConventionalAuth(env);\n const origin = env.PUBLIC_ORIGIN;\n let local = false;\n try { const url = new URL(origin ?? ""); local = url.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname); } catch { /* fail closed */ }\n if (!origin || !local || !env.ADMIN_EMAIL || !env.BETTER_AUTH_SECRET) return createConventionalAuth(env);\n return createAuth({\n database: env.DB, baseURL: origin, secret: env.BETTER_AUTH_SECRET,\n methods: [{ kind: "email-otp", sender }],\n bootstrapOwner: { match: "email", value: env.ADMIN_EMAIL },\n oauthProvider: {\n loginPage: "/admin/sign-in", consentPage: "/oauth/consent",\n scopes: ["mcp"], mcpResource: \`\${origin.replace(/\\/+$/, "")}/mcp\`,\n allowDynamicClientRegistration: true, allowUnauthenticatedClientRegistration: true,\n clientRegistrationDefaultScopes: ["mcp"], clientRegistrationAllowedScopes: ["mcp"],\n },\n });\n },\n` : "") +
|
|
117
|
+
`});\n`;
|
|
118
|
+
}
|
|
119
|
+
function importPath(from, to) {
|
|
120
|
+
const path = relative(dirname(from), to).split(sep).join("/").replace(/\.ts$/, ".js");
|
|
121
|
+
return path.startsWith(".") ? path : `./${path}`;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=generate-cloudflare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-cloudflare.js","sourceRoot":"","sources":["../../src/cli/generate-cloudflare.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const FEATURES: readonly ["spec", "runtime", "api", "mcp", "admin", "web"];
|
|
2
|
+
export type Feature = typeof FEATURES[number];
|
|
3
|
+
export type Host = "cf" | "chatgpt-sites";
|
|
4
|
+
export interface ProjectSelection {
|
|
5
|
+
readonly version: 1;
|
|
6
|
+
readonly host: Host | null;
|
|
7
|
+
readonly features: readonly Feature[];
|
|
8
|
+
readonly output?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ProjectOptions {
|
|
11
|
+
readonly root: string;
|
|
12
|
+
readonly host?: string;
|
|
13
|
+
readonly features?: string;
|
|
14
|
+
readonly check: boolean;
|
|
15
|
+
readonly output: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ProjectDecision {
|
|
18
|
+
readonly mode: "legacy" | "project";
|
|
19
|
+
readonly selection?: ProjectSelection;
|
|
20
|
+
readonly incomplete: boolean;
|
|
21
|
+
readonly commit?: () => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare function prepareProject(options: ProjectOptions): Promise<ProjectDecision>;
|
|
24
|
+
export declare function assertInsideProject(root: string, path: string): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=generate-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-project.d.ts","sourceRoot":"","sources":["../../src/cli/generate-project.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,QAAQ,4DAA6D,CAAC;AACnF,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC9C,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG,eAAe,CAAC;AAC1C,MAAM,WAAW,gBAAgB;IAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;AACtJ,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AACD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAcD,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAiHtF;AAmFD,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBnF"}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { lstat, mkdir, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { stderr, stdin, stdout } from "node:process";
|
|
5
|
+
import { createInterface } from "node:readline/promises";
|
|
6
|
+
import { prepareCloudflare } from "./generate-cloudflare.js";
|
|
7
|
+
export const FEATURES = ["spec", "runtime", "api", "mcp", "admin", "web"];
|
|
8
|
+
const CONFIG = "mantle.config.json";
|
|
9
|
+
const FULL = FEATURES;
|
|
10
|
+
const DEPENDS = {
|
|
11
|
+
spec: [], runtime: ["spec"], api: ["runtime"], mcp: ["runtime"], admin: ["runtime", "api", "mcp"], web: ["runtime"],
|
|
12
|
+
};
|
|
13
|
+
const BOOTSTRAP = new Set([
|
|
14
|
+
".git", ".gitignore", ".agent", ".agents", ".claude", ".codex", ".cursor", ".gemini", ".opencode", ".windsurf",
|
|
15
|
+
".vscode", ".idea", ".skills", "skills", "node_modules", "package.json",
|
|
16
|
+
"package-lock.json", "pnpm-lock.yaml", "yarn.lock", "bun.lock", "bun.lockb", "skills-lock.json", "README.md", "AGENTS.md",
|
|
17
|
+
".DS_Store", ".npmrc", ".yarnrc.yml", ".yarn", ".nvmrc", "CLAUDE.md", "LICENSE", ".editorconfig",
|
|
18
|
+
]);
|
|
19
|
+
export async function prepareProject(options) {
|
|
20
|
+
const root = await realpath(options.root);
|
|
21
|
+
const configPath = join(root, CONFIG);
|
|
22
|
+
const saved = await readFile(configPath, "utf8").catch((error) => {
|
|
23
|
+
if (error.code === "ENOENT")
|
|
24
|
+
return null;
|
|
25
|
+
throw error;
|
|
26
|
+
});
|
|
27
|
+
const evidence = (await readdir(root)).filter((name) => !BOOTSTRAP.has(name) && name !== CONFIG);
|
|
28
|
+
if (saved === null && evidence.length) {
|
|
29
|
+
if (options.host || options.features)
|
|
30
|
+
throw new Error(`Existing application (${evidence.join(", ")}) uses direct authoring; generate a new application separately or integrate Mantle with the installed integration skill.`);
|
|
31
|
+
stdout.write(`Legacy compile mode: existing application files ${evidence.join(", ")}.\n`);
|
|
32
|
+
return { mode: "legacy", incomplete: false };
|
|
33
|
+
}
|
|
34
|
+
const selection = saved !== null ? parseSelection(saved) : await chooseSelection(options);
|
|
35
|
+
if (saved !== null && options.output !== ".mantle/generated" && options.output !== (selection.output ?? ".mantle/generated")) {
|
|
36
|
+
throw new Error("Changing a saved generated output directory is not supported; use the saved output path.");
|
|
37
|
+
}
|
|
38
|
+
if (saved !== null && (options.host !== undefined || options.features !== undefined)) {
|
|
39
|
+
const requested = await chooseSelection(options, selection);
|
|
40
|
+
if (JSON.stringify(requested) !== JSON.stringify(selection)) {
|
|
41
|
+
throw new Error("Changing a saved host or feature list is not supported in v1; plan a deliberate application migration.");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
stdout.write(`Generated project mode: ${selection.host ?? "host-free"}; features ${selection.features.join(", ")}${saved !== null ? " (saved)" : " (new)"}.\n`);
|
|
45
|
+
const packagePath = join(root, "package.json");
|
|
46
|
+
const existingPackage = await readFile(packagePath, "utf8").catch((error) => {
|
|
47
|
+
if (error.code === "ENOENT")
|
|
48
|
+
return null;
|
|
49
|
+
throw error;
|
|
50
|
+
});
|
|
51
|
+
const pkg = existingPackage ? JSON.parse(existingPackage) : {
|
|
52
|
+
name: basename(root).toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/^[._-]+/, "") || "app", private: true, type: "module",
|
|
53
|
+
};
|
|
54
|
+
if (!pkg || typeof pkg !== "object" || Array.isArray(pkg) ||
|
|
55
|
+
[pkg.dependencies, pkg.devDependencies, pkg.scripts].some((value) => value !== undefined &&
|
|
56
|
+
(!value || typeof value !== "object" || Array.isArray(value)))) {
|
|
57
|
+
throw new Error("package.json must contain an object with object-valued dependencies and scripts.");
|
|
58
|
+
}
|
|
59
|
+
if (pkg.type !== undefined && pkg.type !== "module") {
|
|
60
|
+
throw new Error("Generated applications require package.json type=module; preserve CommonJS applications in legacy compile mode.");
|
|
61
|
+
}
|
|
62
|
+
const addModuleType = pkg.type === undefined;
|
|
63
|
+
const version = JSON.parse(await readFile(new URL("../../package.json", import.meta.url), "utf8")).version;
|
|
64
|
+
const required = requiredPackages(selection, version);
|
|
65
|
+
const dependencies = { ...(pkg.dependencies ?? {}) };
|
|
66
|
+
const devDependencies = { ...(pkg.devDependencies ?? {}) };
|
|
67
|
+
let packageChanged = existingPackage === null || addModuleType;
|
|
68
|
+
for (const [name, expected] of Object.entries(required)) {
|
|
69
|
+
const actual = dependencies[name] ?? devDependencies[name];
|
|
70
|
+
if (actual && name.startsWith("@aotter/") && actual !== expected) {
|
|
71
|
+
throw new Error(`package.json declares ${name}@${actual}; expected exact ${expected}. Review this conflict before generating.`);
|
|
72
|
+
}
|
|
73
|
+
if (!actual) {
|
|
74
|
+
if (["wrangler", "typescript", "@cloudflare/workers-types", "esbuild"].includes(name))
|
|
75
|
+
devDependencies[name] = expected;
|
|
76
|
+
else
|
|
77
|
+
dependencies[name] = expected;
|
|
78
|
+
packageChanged = true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const scripts = { ...(pkg.scripts ?? {}) };
|
|
82
|
+
const requiredScripts = { generate: "mantle generate", "generate:check": "mantle generate --check",
|
|
83
|
+
...(selection.host === "cf" ? { dev: "wrangler dev --local --ip 127.0.0.1 --port 8787", deploy: "wrangler deploy", typecheck: "tsc --noEmit", build: "mantle generate && tsc --noEmit" } : {}),
|
|
84
|
+
...(selection.host === "chatgpt-sites" ? { dev: "wrangler dev --local --ip 127.0.0.1 --port 4174", typecheck: "tsc --noEmit", build: "node scripts/build.mjs",
|
|
85
|
+
...(selection.features.includes("admin") ? { "smoke:local": "node scripts/smoke-local.mjs" } : {}) } : {}) };
|
|
86
|
+
for (const [name, expected] of Object.entries(requiredScripts)) {
|
|
87
|
+
if (scripts[name] && scripts[name] !== expected) {
|
|
88
|
+
if (name === "generate" || name === "generate:check")
|
|
89
|
+
throw new Error(`package.json scripts.${name} conflicts with generated command ${expected}.`);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!scripts[name]) {
|
|
93
|
+
scripts[name] = expected;
|
|
94
|
+
packageChanged = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const lockfiles = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lock", "bun.lockb"].filter((name) => existsSync(join(root, name)));
|
|
98
|
+
if (lockfiles.length > 1)
|
|
99
|
+
throw new Error(`Multiple package-manager lockfiles found: ${lockfiles.join(", ")}. Choose one before generating.`);
|
|
100
|
+
await assertInsideProject(root, packagePath);
|
|
101
|
+
await assertInsideProject(root, configPath);
|
|
102
|
+
const outputDir = selection.output ?? options.output;
|
|
103
|
+
const output = resolve(root, outputDir, "mantle.ts");
|
|
104
|
+
await assertInsideProject(root, output);
|
|
105
|
+
const existingOutput = await readFile(output, "utf8").catch((error) => {
|
|
106
|
+
if (error.code === "ENOENT")
|
|
107
|
+
return null;
|
|
108
|
+
throw error;
|
|
109
|
+
});
|
|
110
|
+
if (existingOutput !== null && !existingOutput.startsWith("// Generated by `mantle generate`")) {
|
|
111
|
+
throw new Error(`Generated output would replace a user-owned file: ${output}`);
|
|
112
|
+
}
|
|
113
|
+
if (selection.features.includes("admin")) {
|
|
114
|
+
const admin = resolve(root, "public/_mantle/admin");
|
|
115
|
+
await assertInsideProject(root, admin);
|
|
116
|
+
if (saved === null && existsSync(admin)) {
|
|
117
|
+
throw new Error(`Admin asset target already exists and cannot be verified as generated: ${admin}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const cloudflare = selection.host === "cf" ? await prepareCloudflare(root, outputDir, selection, saved === null) : null;
|
|
121
|
+
const nextPackage = packageChanged ? `${JSON.stringify({ ...pkg, type: "module", scripts, dependencies,
|
|
122
|
+
...(Object.keys(devDependencies).length ? { devDependencies } : {}),
|
|
123
|
+
}, null, 2)}\n` : existingPackage;
|
|
124
|
+
const nextConfig = `${JSON.stringify(selection, null, 2)}\n`;
|
|
125
|
+
const drift = saved === null || existingPackage !== nextPackage || Boolean(cloudflare?.stale);
|
|
126
|
+
if (options.check) {
|
|
127
|
+
if (drift)
|
|
128
|
+
stderr.write("Project config or package declarations are stale.\n");
|
|
129
|
+
const missing = missingPackages(root, required);
|
|
130
|
+
if (missing.length)
|
|
131
|
+
stderr.write(`Selected packages are missing or mismatched: ${missing.join(", ")}.\n`);
|
|
132
|
+
return { mode: "project", selection, incomplete: drift || missing.length > 0 };
|
|
133
|
+
}
|
|
134
|
+
const missing = missingPackages(root, required);
|
|
135
|
+
const install = lockfiles[0] === "pnpm-lock.yaml" ? "pnpm install" : lockfiles[0] === "yarn.lock" ? "yarn install" : lockfiles[0]?.startsWith("bun") ? "bun install" : "npm install";
|
|
136
|
+
return {
|
|
137
|
+
mode: "project", selection, incomplete: missing.length > 0,
|
|
138
|
+
commit: async () => {
|
|
139
|
+
if (existingPackage !== nextPackage)
|
|
140
|
+
await atomicWrite(packagePath, nextPackage);
|
|
141
|
+
if (saved === null)
|
|
142
|
+
await atomicWrite(configPath, nextConfig);
|
|
143
|
+
await cloudflare?.commit();
|
|
144
|
+
if (missing.length)
|
|
145
|
+
stdout.write(`Install selected packages with ${install}, then run mantle generate again. Missing or mismatched: ${missing.join(", ")}.\n`);
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function chooseSelection(options, saved) {
|
|
150
|
+
const selected = options.features === undefined ? saved?.features ?? FULL : options.features.split(",").map((value) => value.trim());
|
|
151
|
+
if (!selected.length || selected.some((value) => !FEATURES.includes(value))) {
|
|
152
|
+
throw new Error(`--features accepts only ${FEATURES.join(", ")}; got ${options.features ?? ""}.`);
|
|
153
|
+
}
|
|
154
|
+
const closure = new Set();
|
|
155
|
+
const add = (feature) => { for (const dep of DEPENDS[feature])
|
|
156
|
+
add(dep); closure.add(feature); };
|
|
157
|
+
for (const feature of selected)
|
|
158
|
+
add(feature);
|
|
159
|
+
const features = FEATURES.filter((feature) => closure.has(feature));
|
|
160
|
+
let host = options.host ?? (features.length === 1 ? null : saved?.host ?? null);
|
|
161
|
+
if (host && host !== "cf" && host !== "chatgpt-sites")
|
|
162
|
+
throw new Error(`--host must be cf or chatgpt-sites; got ${host}.`);
|
|
163
|
+
if (features.some((feature) => feature !== "spec") && !host) {
|
|
164
|
+
if (options.check || !stdin.isTTY)
|
|
165
|
+
throw new Error("Host required for selected features; pass --host cf or --host chatgpt-sites.");
|
|
166
|
+
const prompt = createInterface({ input: stdin, output: stdout });
|
|
167
|
+
try {
|
|
168
|
+
host = (await prompt.question("Host (cf/chatgpt-sites): ")).trim();
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
prompt.close();
|
|
172
|
+
}
|
|
173
|
+
if (host !== "cf" && host !== "chatgpt-sites")
|
|
174
|
+
throw new Error("Host must be cf or chatgpt-sites.");
|
|
175
|
+
}
|
|
176
|
+
if (features.length === 1 && host)
|
|
177
|
+
throw new Error("Spec-only generation is host-free; omit --host.");
|
|
178
|
+
return { version: 1, host: host, features,
|
|
179
|
+
...(options.output !== ".mantle/generated" ? { output: options.output } : saved?.output ? { output: saved.output } : {}) };
|
|
180
|
+
}
|
|
181
|
+
function parseSelection(source) {
|
|
182
|
+
const value = JSON.parse(source);
|
|
183
|
+
if (!value || value.version !== 1 || !Array.isArray(value.features) ||
|
|
184
|
+
value.features.some((feature) => !FEATURES.includes(feature)) ||
|
|
185
|
+
(value.host !== null && value.host !== "cf" && value.host !== "chatgpt-sites") ||
|
|
186
|
+
(value.output !== undefined && (typeof value.output !== "string" || !value.output.trim()))) {
|
|
187
|
+
throw new Error("Invalid mantle.config.json selection.");
|
|
188
|
+
}
|
|
189
|
+
const selected = new Set(value.features);
|
|
190
|
+
if (!selected.has("spec") || value.features.length !== selected.size ||
|
|
191
|
+
FEATURES.filter((feature) => selected.has(feature)).join(",") !== value.features.join(",") ||
|
|
192
|
+
value.features.some((feature) => DEPENDS[feature].some((dependency) => !selected.has(dependency))) ||
|
|
193
|
+
(value.features.length === 1) !== (value.host === null)) {
|
|
194
|
+
throw new Error("mantle.config.json has an invalid feature closure or host.");
|
|
195
|
+
}
|
|
196
|
+
return { version: 1, host: value.host, features: value.features,
|
|
197
|
+
...(value.output ? { output: value.output } : {}) };
|
|
198
|
+
}
|
|
199
|
+
function requiredPackages(selection, version) {
|
|
200
|
+
const required = { "@aotter/mantle": version, zod: "^4.5.0" };
|
|
201
|
+
if (selection.host)
|
|
202
|
+
required["@aotter/mantle-cloudflare"] = version;
|
|
203
|
+
if (selection.features.includes("admin")) {
|
|
204
|
+
required["@aotter/mantle-admin"] = version;
|
|
205
|
+
required["@aotter/mantle-admin-ui"] = version;
|
|
206
|
+
}
|
|
207
|
+
if (selection.features.includes("web"))
|
|
208
|
+
required["@aotter/mantle-web"] = version;
|
|
209
|
+
if (selection.host) {
|
|
210
|
+
// The current Cloudflare adapter declares these peers even in reduced compositions.
|
|
211
|
+
required["better-auth"] = "1.7.2";
|
|
212
|
+
required["hono"] = "^4.12.0";
|
|
213
|
+
required["aws4fetch"] = "^1.0.20";
|
|
214
|
+
}
|
|
215
|
+
if (selection.host === "cf" && selection.features.includes("admin"))
|
|
216
|
+
required["@aotter/mantle-auth"] = version;
|
|
217
|
+
if (selection.host === "cf" || selection.host === "chatgpt-sites") {
|
|
218
|
+
required.wrangler = "4.129.0";
|
|
219
|
+
required.typescript = "^6.0.3";
|
|
220
|
+
required["@cloudflare/workers-types"] = "5.20260904.1";
|
|
221
|
+
}
|
|
222
|
+
if (selection.host === "chatgpt-sites")
|
|
223
|
+
required.esbuild = "^0.28.0";
|
|
224
|
+
return required;
|
|
225
|
+
}
|
|
226
|
+
function missingPackages(root, required) {
|
|
227
|
+
return Object.entries(required).filter(([name, expected]) => {
|
|
228
|
+
let path = null;
|
|
229
|
+
for (let parent = root;; parent = dirname(parent)) {
|
|
230
|
+
const candidate = join(parent, "node_modules", name, "package.json");
|
|
231
|
+
if (existsSync(candidate)) {
|
|
232
|
+
path = candidate;
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
if (dirname(parent) === parent)
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
if (!path)
|
|
239
|
+
return true;
|
|
240
|
+
if (!name.startsWith("@aotter/"))
|
|
241
|
+
return false;
|
|
242
|
+
try {
|
|
243
|
+
return JSON.parse(readFileSync(path, "utf8")).version !== expected;
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
}).map(([name]) => name);
|
|
249
|
+
}
|
|
250
|
+
export async function assertInsideProject(root, path) {
|
|
251
|
+
const project = await realpath(root);
|
|
252
|
+
let parent = resolve(path);
|
|
253
|
+
while (true) {
|
|
254
|
+
try {
|
|
255
|
+
if ((await lstat(parent)).isSymbolicLink())
|
|
256
|
+
throw new Error(`Generated path uses a symlink: ${parent}`);
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
if (error.code !== "ENOENT")
|
|
261
|
+
throw error;
|
|
262
|
+
parent = dirname(parent);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const target = await realpath(parent);
|
|
266
|
+
const difference = relative(project, target);
|
|
267
|
+
if (difference === ".." || difference.startsWith(`..${sep}`) || resolve(path) === project) {
|
|
268
|
+
throw new Error(`Generated path escapes project: ${path}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async function atomicWrite(path, value) {
|
|
272
|
+
await mkdir(dirname(path), { recursive: true });
|
|
273
|
+
const temporary = `${path}.${process.pid}.tmp`;
|
|
274
|
+
try {
|
|
275
|
+
await writeFile(temporary, value, { flag: "wx" });
|
|
276
|
+
await rename(temporary, path);
|
|
277
|
+
}
|
|
278
|
+
finally {
|
|
279
|
+
await rm(temporary, { force: true });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=generate-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-project.js","sourceRoot":"","sources":["../../src/cli/generate-project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SchemaManifest } from "@aotter/mantle-spec";
|
|
2
|
+
import { type ProjectSelection } from "./generate-project.js";
|
|
3
|
+
export declare function prepareSites(root: string, output: string, selection: ProjectSelection, schemas: readonly SchemaManifest[], check: boolean, reviewUniqueIndexes?: boolean): Promise<{
|
|
4
|
+
readonly stale: boolean;
|
|
5
|
+
readonly report?: string;
|
|
6
|
+
readonly commit: () => Promise<void>;
|
|
7
|
+
}>;
|
|
8
|
+
//# sourceMappingURL=generate-sites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-sites.d.ts","sourceRoot":"","sources":["../../src/cli/generate-sites.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAWnF,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,EAAE,SAAS,cAAc,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,mBAAmB,UAAQ,GAAG,OAAO,CAAC;IACtL,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC,CAAC,CAqFD"}
|