create-mdan 0.5.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/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/cli-bin.d.ts +3 -0
- package/dist/cli-bin.d.ts.map +1 -0
- package/dist/cli-bin.js +7 -0
- package/dist/cli-bin.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +94 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
- package/template/bun/README.md +31 -0
- package/template/bun/index.mjs +63 -0
- package/template/bun/package.json +17 -0
- package/template/node/README.md +29 -0
- package/template/node/index.mjs +62 -0
- package/template/node/package.json +17 -0
- package/template/shared/app/client.ts +7 -0
- package/template/shared/app/index.md +17 -0
- package/template/shared/app/server.ts +51 -0
- package/template/shared/tsconfig.json +22 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MDAN
|
|
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
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# create-mdan
|
|
2
|
+
|
|
3
|
+
`create-mdan` scaffolds a minimal MDAN app.
|
|
4
|
+
|
|
5
|
+
Use it when you want the fastest path from a blank directory to a working MDAN app.
|
|
6
|
+
|
|
7
|
+
It supports both Node and Bun starters.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
Node starter:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm create mdan@latest agent-app
|
|
15
|
+
cd agent-app
|
|
16
|
+
npm install
|
|
17
|
+
npm start
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Bun starter:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bunx create-mdan agent-app
|
|
24
|
+
cd agent-app
|
|
25
|
+
bun install
|
|
26
|
+
bun start
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
You can override the generated runtime explicitly:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm create mdan@latest agent-app -- --runtime bun
|
|
33
|
+
bunx create-mdan agent-app --runtime node
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Defaults:
|
|
37
|
+
|
|
38
|
+
- `npm create` and `npx create-mdan` default to the Node starter
|
|
39
|
+
- `bunx create-mdan` defaults to the Bun starter
|
|
40
|
+
|
|
41
|
+
The generated app uses this small shape:
|
|
42
|
+
|
|
43
|
+
- `app/index.md`
|
|
44
|
+
- `app/server.ts`
|
|
45
|
+
- `app/client.ts`
|
|
46
|
+
- `index.mjs`
|
|
47
|
+
|
|
48
|
+
## Docs
|
|
49
|
+
|
|
50
|
+
- [Docs](https://docs.mdan.ai/)
|
|
51
|
+
- [Getting Started](https://docs.mdan.ai/getting-started)
|
|
52
|
+
- [Understanding MDAN](https://docs.mdan.ai/understanding-mdan)
|
|
53
|
+
- [Examples](https://docs.mdan.ai/examples)
|
|
54
|
+
- [SDK Overview](https://docs.mdan.ai/sdk)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-bin.d.ts","sourceRoot":"","sources":["../src/cli-bin.ts"],"names":[],"mappings":""}
|
package/dist/cli-bin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-bin.js","sourceRoot":"","sources":["../src/cli-bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC1C,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type StarterRuntime } from "./index.js";
|
|
2
|
+
export interface ParsedCliArgs {
|
|
3
|
+
targetArg: string | undefined;
|
|
4
|
+
runtime: StarterRuntime;
|
|
5
|
+
showHelp: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function detectDefaultRuntime(userAgent?: string): StarterRuntime;
|
|
8
|
+
export declare function parseCliArgs(argv: string[], userAgent?: string): ParsedCliArgs;
|
|
9
|
+
export declare function formatUsage(): string;
|
|
10
|
+
export declare function formatNextSteps(projectDir: string, runtime: StarterRuntime, targetArg?: string): string;
|
|
11
|
+
declare function main(argv: string[]): Promise<void>;
|
|
12
|
+
export { main };
|
|
13
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgD,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/F,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAMD,wBAAgB,oBAAoB,CAAC,SAAS,SAA0C,GAAG,cAAc,CAExG;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,SAA0C,GAAG,aAAa,CAkD/G;AAED,wBAAgB,WAAW,IAAI,MAAM,CAQpC;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,SAAa,GAAG,MAAM,CAa3G;AAMD,iBAAe,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBjD;AAED,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import packageJson from "../package.json" with { type: "json" };
|
|
3
|
+
import { scaffoldStarterProject, toCompatibleSdkRange } from "./index.js";
|
|
4
|
+
function isStarterRuntime(value) {
|
|
5
|
+
return value === "node" || value === "bun";
|
|
6
|
+
}
|
|
7
|
+
export function detectDefaultRuntime(userAgent = process.env.npm_config_user_agent ?? "") {
|
|
8
|
+
return /\bbun\/\d/i.test(userAgent) ? "bun" : "node";
|
|
9
|
+
}
|
|
10
|
+
export function parseCliArgs(argv, userAgent = process.env.npm_config_user_agent ?? "") {
|
|
11
|
+
let targetArg;
|
|
12
|
+
let runtime = detectDefaultRuntime(userAgent);
|
|
13
|
+
let showHelp = false;
|
|
14
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
15
|
+
const arg = argv[index];
|
|
16
|
+
if (!arg) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (arg === "--help" || arg === "-h") {
|
|
20
|
+
showHelp = true;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (arg === "--") {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (arg === "--runtime") {
|
|
27
|
+
const next = argv[index + 1];
|
|
28
|
+
if (!next || !isStarterRuntime(next)) {
|
|
29
|
+
throw new Error('Expected "--runtime" to be followed by "node" or "bun".');
|
|
30
|
+
}
|
|
31
|
+
runtime = next;
|
|
32
|
+
index += 1;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (arg.startsWith("--runtime=")) {
|
|
36
|
+
const value = arg.slice("--runtime=".length);
|
|
37
|
+
if (!isStarterRuntime(value)) {
|
|
38
|
+
throw new Error(`Unsupported runtime "${value}". Expected "node" or "bun".`);
|
|
39
|
+
}
|
|
40
|
+
runtime = value;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (arg.startsWith("-")) {
|
|
44
|
+
throw new Error(`Unknown option "${arg}".`);
|
|
45
|
+
}
|
|
46
|
+
if (targetArg) {
|
|
47
|
+
throw new Error(`Unexpected extra argument "${arg}".`);
|
|
48
|
+
}
|
|
49
|
+
targetArg = arg;
|
|
50
|
+
}
|
|
51
|
+
return { targetArg, runtime, showHelp };
|
|
52
|
+
}
|
|
53
|
+
export function formatUsage() {
|
|
54
|
+
return [
|
|
55
|
+
"Usage:",
|
|
56
|
+
" npm create mdan@latest <project-name>",
|
|
57
|
+
" npm create mdan@latest <project-name> -- --runtime bun",
|
|
58
|
+
" bunx create-mdan <project-name>",
|
|
59
|
+
" bunx create-mdan <project-name> --runtime node"
|
|
60
|
+
].join("\n");
|
|
61
|
+
}
|
|
62
|
+
export function formatNextSteps(projectDir, runtime, targetArg = projectDir) {
|
|
63
|
+
const installCommand = runtime === "bun" ? "bun install" : "npm install";
|
|
64
|
+
const startCommand = runtime === "bun" ? "bun start" : "npm start";
|
|
65
|
+
return [
|
|
66
|
+
`Created MDAN ${runtime} starter in ${projectDir}`,
|
|
67
|
+
"",
|
|
68
|
+
"Next steps:",
|
|
69
|
+
` cd ${targetArg}`,
|
|
70
|
+
"",
|
|
71
|
+
` ${installCommand}`,
|
|
72
|
+
` ${startCommand}`
|
|
73
|
+
].join("\n");
|
|
74
|
+
}
|
|
75
|
+
function printUsage() {
|
|
76
|
+
console.log(formatUsage());
|
|
77
|
+
}
|
|
78
|
+
async function main(argv) {
|
|
79
|
+
const { targetArg, runtime, showHelp } = parseCliArgs(argv);
|
|
80
|
+
if (!targetArg || showHelp) {
|
|
81
|
+
printUsage();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const targetDir = resolve(process.cwd(), targetArg);
|
|
85
|
+
const projectDir = await scaffoldStarterProject({
|
|
86
|
+
targetDir,
|
|
87
|
+
sdkVersion: toCompatibleSdkRange(packageJson.version),
|
|
88
|
+
runtime,
|
|
89
|
+
...(targetArg === "." ? {} : { projectName: targetArg })
|
|
90
|
+
});
|
|
91
|
+
console.log(formatNextSteps(projectDir, runtime, targetArg));
|
|
92
|
+
}
|
|
93
|
+
export { main };
|
|
94
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type StarterRuntime = "node" | "bun";
|
|
2
|
+
export interface ScaffoldStarterProjectOptions {
|
|
3
|
+
targetDir: string;
|
|
4
|
+
projectName?: string;
|
|
5
|
+
sdkVersion: string;
|
|
6
|
+
runtime?: StarterRuntime;
|
|
7
|
+
}
|
|
8
|
+
export declare function toCompatibleSdkRange(packageVersion: string): string;
|
|
9
|
+
export declare function scaffoldStarterProject(options: ScaffoldStarterProjectOptions, moduleUrl?: string): Promise<string>;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,KAAK,CAAC;AAE5C,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AASD,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAQnE;AAsDD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,EACtC,SAAS,SAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { cp, mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, join, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const TEMPLATE_PLACEHOLDERS = {
|
|
5
|
+
__PROJECT_NAME__: "",
|
|
6
|
+
__SDK_VERSION__: ""
|
|
7
|
+
};
|
|
8
|
+
const DEFAULT_RUNTIME = "node";
|
|
9
|
+
export function toCompatibleSdkRange(packageVersion) {
|
|
10
|
+
const match = packageVersion.match(/^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/);
|
|
11
|
+
if (!match) {
|
|
12
|
+
throw new Error(`Unsupported package version "${packageVersion}".`);
|
|
13
|
+
}
|
|
14
|
+
const [, major, minor] = match;
|
|
15
|
+
return `^${major}.${minor}.0`;
|
|
16
|
+
}
|
|
17
|
+
function templateRootsFromModule(moduleUrl, runtime) {
|
|
18
|
+
return [
|
|
19
|
+
resolve(fileURLToPath(new URL("../template/shared", moduleUrl))),
|
|
20
|
+
resolve(fileURLToPath(new URL(`../template/${runtime}`, moduleUrl)))
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
async function ensureEmptyTarget(targetDir) {
|
|
24
|
+
try {
|
|
25
|
+
const targetStat = await stat(targetDir);
|
|
26
|
+
if (!targetStat.isDirectory()) {
|
|
27
|
+
throw new Error(`Target path "${targetDir}" already exists and is not a directory.`);
|
|
28
|
+
}
|
|
29
|
+
const entries = await readdir(targetDir);
|
|
30
|
+
if (entries.length > 0) {
|
|
31
|
+
throw new Error(`Target directory "${targetDir}" must be empty.`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const code = error.code;
|
|
36
|
+
if (code === "ENOENT") {
|
|
37
|
+
await mkdir(targetDir, { recursive: true });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function replaceInFile(filePath, replacements) {
|
|
44
|
+
const original = await readFile(filePath, "utf8");
|
|
45
|
+
let next = original;
|
|
46
|
+
for (const [pattern, value] of Object.entries(replacements)) {
|
|
47
|
+
next = next.replaceAll(pattern, value);
|
|
48
|
+
}
|
|
49
|
+
if (next !== original) {
|
|
50
|
+
await writeFile(filePath, next, "utf8");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function walkFiles(root) {
|
|
54
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
55
|
+
const files = [];
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
const filePath = join(root, entry.name);
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
files.push(...(await walkFiles(filePath)));
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
files.push(filePath);
|
|
63
|
+
}
|
|
64
|
+
return files;
|
|
65
|
+
}
|
|
66
|
+
export async function scaffoldStarterProject(options, moduleUrl = import.meta.url) {
|
|
67
|
+
const runtime = options.runtime ?? DEFAULT_RUNTIME;
|
|
68
|
+
const templateRoots = templateRootsFromModule(moduleUrl, runtime);
|
|
69
|
+
const targetDir = resolve(options.targetDir);
|
|
70
|
+
const projectName = options.projectName?.trim() || basename(targetDir);
|
|
71
|
+
if (!projectName) {
|
|
72
|
+
throw new Error("Project name cannot be empty.");
|
|
73
|
+
}
|
|
74
|
+
await ensureEmptyTarget(targetDir);
|
|
75
|
+
for (const templateRoot of templateRoots) {
|
|
76
|
+
await cp(templateRoot, targetDir, { recursive: true });
|
|
77
|
+
}
|
|
78
|
+
const replacements = {
|
|
79
|
+
__PROJECT_NAME__: projectName,
|
|
80
|
+
__SDK_VERSION__: options.sdkVersion
|
|
81
|
+
};
|
|
82
|
+
const files = await walkFiles(targetDir);
|
|
83
|
+
await Promise.all(files.map((filePath) => replaceInFile(filePath, replacements)));
|
|
84
|
+
return targetDir;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-mdan",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Create a minimal MDAN app with npm create or bunx.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://docs.mdan.ai",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/mdan-ai/mdan/issues"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/mdan-ai/mdan.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mdan",
|
|
17
|
+
"create",
|
|
18
|
+
"scaffold",
|
|
19
|
+
"markdown",
|
|
20
|
+
"ai",
|
|
21
|
+
"agent",
|
|
22
|
+
"agentic",
|
|
23
|
+
"workflow",
|
|
24
|
+
"skills-app",
|
|
25
|
+
"agent-app",
|
|
26
|
+
"cli",
|
|
27
|
+
"bun"
|
|
28
|
+
],
|
|
29
|
+
"type": "module",
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"template/shared",
|
|
40
|
+
"template/node",
|
|
41
|
+
"template/bun"
|
|
42
|
+
],
|
|
43
|
+
"bin": {
|
|
44
|
+
"create-mdan": "./dist/cli-bin.js"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"prepack": "node ../scripts/sync-package-license.mjs",
|
|
48
|
+
"postpack": "node ../scripts/sync-package-license.mjs --cleanup"
|
|
49
|
+
},
|
|
50
|
+
"exports": {
|
|
51
|
+
".": {
|
|
52
|
+
"types": "./dist/index.d.ts",
|
|
53
|
+
"default": "./dist/index.js"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
This is a minimal MDAN starter for the Bun host.
|
|
4
|
+
|
|
5
|
+
## 30-Second Tour
|
|
6
|
+
|
|
7
|
+
- `app/index.md`
|
|
8
|
+
Defines the page source and interaction.
|
|
9
|
+
- `app/server.ts`
|
|
10
|
+
Owns state and action handlers.
|
|
11
|
+
- `app/client.ts`
|
|
12
|
+
Mounts the browser runtime.
|
|
13
|
+
- `index.mjs`
|
|
14
|
+
Starts the Bun host.
|
|
15
|
+
|
|
16
|
+
## Run It
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bun install
|
|
20
|
+
bun start
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This starter is Bun-native, so you can use it without installing Node.
|
|
24
|
+
|
|
25
|
+
Then open [http://127.0.0.1:3000/](http://127.0.0.1:3000/).
|
|
26
|
+
|
|
27
|
+
## First Things To Change
|
|
28
|
+
|
|
29
|
+
1. Edit `app/index.md`
|
|
30
|
+
2. Edit `app/server.ts`
|
|
31
|
+
3. Keep `app/client.ts` as-is, or replace it when you want to own the UI
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
import { createHost } from "@mdanai/sdk/server/bun";
|
|
6
|
+
|
|
7
|
+
import { createAppServer } from "./dist/server.js";
|
|
8
|
+
|
|
9
|
+
const port = Number(process.env.PORT || 3000);
|
|
10
|
+
const hostname = process.env.HOST || "127.0.0.1";
|
|
11
|
+
const projectRoot = fileURLToPath(new URL("./", import.meta.url));
|
|
12
|
+
const sourcePath = join(projectRoot, "app", "index.md");
|
|
13
|
+
const assetVersion = Date.now().toString(36);
|
|
14
|
+
|
|
15
|
+
function withVersion(path) {
|
|
16
|
+
return `${path}?v=${assetVersion}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const importMap = {
|
|
20
|
+
imports: {
|
|
21
|
+
"@mdanai/sdk/core": withVersion("/node_modules/@mdanai/sdk/dist/core/index.js"),
|
|
22
|
+
"@mdanai/sdk/web": withVersion("/node_modules/@mdanai/sdk/dist/web/index.js"),
|
|
23
|
+
"@mdanai/sdk/elements": withVersion("/node_modules/@mdanai/sdk/dist/elements/index.js"),
|
|
24
|
+
"lit": withVersion("/node_modules/lit/index.js"),
|
|
25
|
+
"lit-html": withVersion("/node_modules/lit-html/lit-html.js"),
|
|
26
|
+
"lit-html/is-server.js": withVersion("/node_modules/lit-html/is-server.js"),
|
|
27
|
+
"lit-element/lit-element.js": withVersion("/node_modules/lit-element/lit-element.js"),
|
|
28
|
+
"@lit/reactive-element": withVersion("/node_modules/@lit/reactive-element/reactive-element.js")
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function injectEnhancement(html) {
|
|
33
|
+
const enhancement = `
|
|
34
|
+
<script type="importmap">${JSON.stringify(importMap)}</script>
|
|
35
|
+
<script type="module">
|
|
36
|
+
import { mountApp } from "${withVersion("/app/client.js")}";
|
|
37
|
+
mountApp(document, window.fetch.bind(window));
|
|
38
|
+
</script>`;
|
|
39
|
+
|
|
40
|
+
return html.replace("</body>", `${enhancement}\n </body>`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const source = await readFile(sourcePath, "utf8");
|
|
44
|
+
const mdan = createAppServer({ source });
|
|
45
|
+
|
|
46
|
+
Bun.serve({
|
|
47
|
+
hostname,
|
|
48
|
+
port,
|
|
49
|
+
fetch: createHost(mdan, {
|
|
50
|
+
transformHtml: injectEnhancement,
|
|
51
|
+
staticFiles: {
|
|
52
|
+
"/app/client.js": join(projectRoot, "dist", "client.js")
|
|
53
|
+
},
|
|
54
|
+
staticMounts: [
|
|
55
|
+
{
|
|
56
|
+
urlPrefix: "/node_modules/",
|
|
57
|
+
directory: join(projectRoot, "node_modules")
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
})
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log(`MDAN starter running at http://${hostname}:${port}/`);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -p tsconfig.json",
|
|
8
|
+
"start": "tsc -p tsconfig.json && bun run index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@mdanai/sdk": "__SDK_VERSION__"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^24.6.0",
|
|
15
|
+
"typescript": "^5.9.3"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# __PROJECT_NAME__
|
|
2
|
+
|
|
3
|
+
This is a minimal MDAN starter for the Node host.
|
|
4
|
+
|
|
5
|
+
## 30-Second Tour
|
|
6
|
+
|
|
7
|
+
- `app/index.md`
|
|
8
|
+
Defines the page source and interaction.
|
|
9
|
+
- `app/server.ts`
|
|
10
|
+
Owns state and action handlers.
|
|
11
|
+
- `app/client.ts`
|
|
12
|
+
Mounts the browser runtime.
|
|
13
|
+
- `index.mjs`
|
|
14
|
+
Starts the Node host.
|
|
15
|
+
|
|
16
|
+
## Run It
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install
|
|
20
|
+
npm start
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then open [http://127.0.0.1:3000/](http://127.0.0.1:3000/).
|
|
24
|
+
|
|
25
|
+
## First Things To Change
|
|
26
|
+
|
|
27
|
+
1. Edit `app/index.md`
|
|
28
|
+
2. Edit `app/server.ts`
|
|
29
|
+
3. Keep `app/client.ts` as-is, or replace it when you want to own the UI
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import { createHost } from "@mdanai/sdk/server/node";
|
|
7
|
+
|
|
8
|
+
import { createAppServer } from "./dist/server.js";
|
|
9
|
+
|
|
10
|
+
const port = Number(process.env.PORT || 3000);
|
|
11
|
+
const projectRoot = fileURLToPath(new URL("./", import.meta.url));
|
|
12
|
+
const sourcePath = join(projectRoot, "app", "index.md");
|
|
13
|
+
const assetVersion = Date.now().toString(36);
|
|
14
|
+
|
|
15
|
+
function withVersion(path) {
|
|
16
|
+
return `${path}?v=${assetVersion}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const importMap = {
|
|
20
|
+
imports: {
|
|
21
|
+
"@mdanai/sdk/core": withVersion("/node_modules/@mdanai/sdk/dist/core/index.js"),
|
|
22
|
+
"@mdanai/sdk/web": withVersion("/node_modules/@mdanai/sdk/dist/web/index.js"),
|
|
23
|
+
"@mdanai/sdk/elements": withVersion("/node_modules/@mdanai/sdk/dist/elements/index.js"),
|
|
24
|
+
"lit": withVersion("/node_modules/lit/index.js"),
|
|
25
|
+
"lit-html": withVersion("/node_modules/lit-html/lit-html.js"),
|
|
26
|
+
"lit-html/is-server.js": withVersion("/node_modules/lit-html/is-server.js"),
|
|
27
|
+
"lit-element/lit-element.js": withVersion("/node_modules/lit-element/lit-element.js"),
|
|
28
|
+
"@lit/reactive-element": withVersion("/node_modules/@lit/reactive-element/reactive-element.js")
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function injectEnhancement(html) {
|
|
33
|
+
const enhancement = `
|
|
34
|
+
<script type="importmap">${JSON.stringify(importMap)}</script>
|
|
35
|
+
<script type="module">
|
|
36
|
+
import { mountApp } from "${withVersion("/app/client.js")}";
|
|
37
|
+
mountApp(document, window.fetch.bind(window));
|
|
38
|
+
</script>`;
|
|
39
|
+
|
|
40
|
+
return html.replace("</body>", `${enhancement}\n </body>`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const source = await readFile(sourcePath, "utf8");
|
|
44
|
+
const mdan = createAppServer({ source });
|
|
45
|
+
const server = http.createServer(
|
|
46
|
+
createHost(mdan, {
|
|
47
|
+
transformHtml: injectEnhancement,
|
|
48
|
+
staticFiles: {
|
|
49
|
+
"/app/client.js": join(projectRoot, "dist", "client.js")
|
|
50
|
+
},
|
|
51
|
+
staticMounts: [
|
|
52
|
+
{
|
|
53
|
+
urlPrefix: "/node_modules/",
|
|
54
|
+
directory: join(projectRoot, "node_modules")
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
server.listen(port, "127.0.0.1", () => {
|
|
61
|
+
console.log(`MDAN starter running at http://127.0.0.1:${port}/`);
|
|
62
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -p tsconfig.json",
|
|
8
|
+
"start": "tsc -p tsconfig.json && node index.mjs"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@mdanai/sdk": "__SDK_VERSION__"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^24.6.0",
|
|
15
|
+
"typescript": "^5.9.3"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { mountMdanElements } from "@mdanai/sdk/elements";
|
|
2
|
+
import { createHeadlessHost } from "@mdanai/sdk/web";
|
|
3
|
+
|
|
4
|
+
export function mountApp(root: HTMLElement, fetchImpl: typeof fetch): void {
|
|
5
|
+
const host = createHeadlessHost({ root, fetchImpl });
|
|
6
|
+
mountMdanElements({ root, host }).mount();
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Agent App"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Agent App
|
|
6
|
+
|
|
7
|
+
Use this starter as the smallest end-to-end MDAN app.
|
|
8
|
+
|
|
9
|
+
<!-- mdan:block main -->
|
|
10
|
+
|
|
11
|
+
```mdan
|
|
12
|
+
BLOCK main {
|
|
13
|
+
INPUT text required -> message
|
|
14
|
+
GET "/list" -> refresh label:"Refresh"
|
|
15
|
+
POST "/post" (message) -> submit label:"Submit"
|
|
16
|
+
}
|
|
17
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { composePage } from "@mdanai/sdk/core";
|
|
2
|
+
import { createHostedApp } from "@mdanai/sdk/server";
|
|
3
|
+
|
|
4
|
+
export interface CreateAppServerOptions {
|
|
5
|
+
source: string;
|
|
6
|
+
initialMessages?: string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function createAppServer(options: CreateAppServerOptions) {
|
|
10
|
+
const messages = [...(options.initialMessages ?? ["Welcome to MDAN"])];
|
|
11
|
+
|
|
12
|
+
function renderMainBlock(): string {
|
|
13
|
+
const count = `${messages.length} live ${messages.length === 1 ? "message" : "messages"}`;
|
|
14
|
+
return `## ${count}\n\n${messages.map((message) => `- ${message}`).join("\n")}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function renderPage() {
|
|
18
|
+
return composePage(options.source, {
|
|
19
|
+
blocks: {
|
|
20
|
+
main: renderMainBlock()
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return createHostedApp({
|
|
26
|
+
pages: {
|
|
27
|
+
"/": renderPage
|
|
28
|
+
},
|
|
29
|
+
actions: [
|
|
30
|
+
{
|
|
31
|
+
target: "/list",
|
|
32
|
+
methods: ["GET"],
|
|
33
|
+
routePath: "/",
|
|
34
|
+
blockName: "main",
|
|
35
|
+
handler: ({ block }) => block()
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
target: "/post",
|
|
39
|
+
methods: ["POST"],
|
|
40
|
+
routePath: "/",
|
|
41
|
+
blockName: "main",
|
|
42
|
+
handler: ({ inputs, block }) => {
|
|
43
|
+
if (inputs.message) {
|
|
44
|
+
messages.push(inputs.message);
|
|
45
|
+
}
|
|
46
|
+
return block();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"declarationMap": true,
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"noUncheckedIndexedAccess": true,
|
|
12
|
+
"exactOptionalPropertyTypes": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"resolveJsonModule": true,
|
|
16
|
+
"lib": ["ES2022", "DOM"],
|
|
17
|
+
"types": ["node"],
|
|
18
|
+
"rootDir": "./app",
|
|
19
|
+
"outDir": "./dist"
|
|
20
|
+
},
|
|
21
|
+
"include": ["app/**/*.ts"]
|
|
22
|
+
}
|