@mindees/cli 0.1.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 +31 -0
- package/README.md +70 -0
- package/dist/ai.d.ts +15 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +57 -0
- package/dist/ai.js.map +1 -0
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +94 -0
- package/dist/bin.js.map +1 -0
- package/dist/build.d.ts +37 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +97 -0
- package/dist/build.js.map +1 -0
- package/dist/cli.d.ts +32 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +194 -0
- package/dist/cli.js.map +1 -0
- package/dist/create-target.d.ts +36 -0
- package/dist/create-target.d.ts.map +1 -0
- package/dist/create-target.js +90 -0
- package/dist/create-target.js.map +1 -0
- package/dist/dev.d.ts +32 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +64 -0
- package/dist/dev.js.map +1 -0
- package/dist/doctor.d.ts +15 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +92 -0
- package/dist/doctor.js.map +1 -0
- package/dist/fs.d.ts +28 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +39 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/nl.d.ts +26 -0
- package/dist/nl.d.ts.map +1 -0
- package/dist/nl.js +49 -0
- package/dist/nl.js.map +1 -0
- package/dist/scaffold.d.ts +32 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +52 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/templates.d.ts +32 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +131 -0
- package/dist/templates.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/version.d.ts +17 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +18 -0
- package/dist/version.js.map +1 -0
- package/package.json +37 -0
package/dist/fs.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/fs.ts
|
|
2
|
+
/** An in-memory {@link FileSystem} for tests and dry runs. */
|
|
3
|
+
function createMemoryFileSystem(initial = {}) {
|
|
4
|
+
const files = new Map(Object.entries(initial));
|
|
5
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
6
|
+
const norm = (p) => p.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/\.\//g, "/").replace(/\/{2,}/g, "/").replace(/\/+$/, "");
|
|
7
|
+
return {
|
|
8
|
+
exists: (path) => {
|
|
9
|
+
const p = norm(path);
|
|
10
|
+
if (files.has(p) || dirs.has(p)) return true;
|
|
11
|
+
const prefix = `${p}/`;
|
|
12
|
+
for (const f of files.keys()) if (f.startsWith(prefix)) return true;
|
|
13
|
+
return false;
|
|
14
|
+
},
|
|
15
|
+
readFile: (path) => {
|
|
16
|
+
const p = norm(path);
|
|
17
|
+
const c = files.get(p);
|
|
18
|
+
if (c === void 0) throw new Error(`ENOENT: ${p}`);
|
|
19
|
+
return c;
|
|
20
|
+
},
|
|
21
|
+
writeFile: (path, contents) => {
|
|
22
|
+
files.set(norm(path), contents);
|
|
23
|
+
},
|
|
24
|
+
mkdir: (path) => {
|
|
25
|
+
dirs.add(norm(path));
|
|
26
|
+
},
|
|
27
|
+
readDir: (dir) => {
|
|
28
|
+
const prefix = dir === "" || dir === "." ? "" : `${norm(dir)}/`;
|
|
29
|
+
const out = [];
|
|
30
|
+
for (const f of files.keys()) if (prefix === "" || f.startsWith(prefix)) out.push(prefix === "" ? f : f.slice(prefix.length));
|
|
31
|
+
return out.sort();
|
|
32
|
+
},
|
|
33
|
+
snapshot: () => Object.fromEntries([...files.entries()].sort())
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { createMemoryFileSystem };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=fs.js.map
|
package/dist/fs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","names":[],"sources":["../src/fs.ts"],"sourcesContent":["/**\n * A tiny filesystem abstraction so CLI commands are testable without touching\n * the real disk. The `bin` layer supplies a `node:fs`-backed implementation; the\n * core (`scaffold`, `buildProject`) takes a {@link FileSystem}.\n *\n * @module\n */\n\n/** The minimal filesystem surface the CLI core needs. */\nexport interface FileSystem {\n /** True if a file or directory exists at `path`. */\n exists(path: string): boolean\n /** Read a UTF-8 file. Throws if missing. */\n readFile(path: string): string\n /** Write a UTF-8 file, creating parent directories as needed. */\n writeFile(path: string, contents: string): void\n /** Create a directory (and parents). No-op if it exists. */\n mkdir(path: string): void\n /** List files (recursively) under `dir`, returned as POSIX-relative paths. */\n readDir(dir: string): string[]\n}\n\n/** An in-memory {@link FileSystem} for tests and dry runs. */\nexport function createMemoryFileSystem(initial: Record<string, string> = {}): FileSystem & {\n /** Snapshot of all written files (path → contents). */\n snapshot(): Record<string, string>\n} {\n const files = new Map<string, string>(Object.entries(initial))\n const dirs = new Set<string>()\n\n // Normalize to POSIX separators, drop a leading `./`, collapse `//` and `/./`,\n // and strip a trailing slash — so `./dist/App.js` and `dist/App.js` are equal.\n const norm = (p: string) =>\n p\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\//, '')\n .replace(/\\/\\.\\//g, '/')\n .replace(/\\/{2,}/g, '/')\n .replace(/\\/+$/, '')\n\n return {\n exists: (path) => {\n const p = norm(path)\n if (files.has(p) || dirs.has(p)) return true\n // A path is a directory if any file lives under it.\n const prefix = `${p}/`\n for (const f of files.keys()) if (f.startsWith(prefix)) return true\n return false\n },\n readFile: (path) => {\n const p = norm(path)\n const c = files.get(p)\n if (c === undefined) throw new Error(`ENOENT: ${p}`)\n return c\n },\n writeFile: (path, contents) => {\n files.set(norm(path), contents)\n },\n mkdir: (path) => {\n dirs.add(norm(path))\n },\n readDir: (dir) => {\n const prefix = dir === '' || dir === '.' ? '' : `${norm(dir)}/`\n const out: string[] = []\n for (const f of files.keys()) {\n if (prefix === '' || f.startsWith(prefix)) {\n out.push(prefix === '' ? f : f.slice(prefix.length))\n }\n }\n return out.sort()\n },\n snapshot: () => Object.fromEntries([...files.entries()].sort()),\n }\n}\n"],"mappings":";;AAuBA,SAAgB,uBAAuB,UAAkC,CAAC,GAGxE;CACA,MAAM,QAAQ,IAAI,IAAoB,OAAO,QAAQ,OAAO,CAAC;CAC7D,MAAM,uBAAO,IAAI,IAAY;CAI7B,MAAM,QAAQ,MACZ,EACG,QAAQ,OAAO,GAAG,EAClB,QAAQ,SAAS,EAAE,EACnB,QAAQ,WAAW,GAAG,EACtB,QAAQ,WAAW,GAAG,EACtB,QAAQ,QAAQ,EAAE;CAEvB,OAAO;EACL,SAAS,SAAS;GAChB,MAAM,IAAI,KAAK,IAAI;GACnB,IAAI,MAAM,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,GAAG,OAAO;GAExC,MAAM,SAAS,GAAG,EAAE;GACpB,KAAK,MAAM,KAAK,MAAM,KAAK,GAAG,IAAI,EAAE,WAAW,MAAM,GAAG,OAAO;GAC/D,OAAO;EACT;EACA,WAAW,SAAS;GAClB,MAAM,IAAI,KAAK,IAAI;GACnB,MAAM,IAAI,MAAM,IAAI,CAAC;GACrB,IAAI,MAAM,KAAA,GAAW,MAAM,IAAI,MAAM,WAAW,GAAG;GACnD,OAAO;EACT;EACA,YAAY,MAAM,aAAa;GAC7B,MAAM,IAAI,KAAK,IAAI,GAAG,QAAQ;EAChC;EACA,QAAQ,SAAS;GACf,KAAK,IAAI,KAAK,IAAI,CAAC;EACrB;EACA,UAAU,QAAQ;GAChB,MAAM,SAAS,QAAQ,MAAM,QAAQ,MAAM,KAAK,GAAG,KAAK,GAAG,EAAE;GAC7D,MAAM,MAAgB,CAAC;GACvB,KAAK,MAAM,KAAK,MAAM,KAAK,GACzB,IAAI,WAAW,MAAM,EAAE,WAAW,MAAM,GACtC,IAAI,KAAK,WAAW,KAAK,IAAI,EAAE,MAAM,OAAO,MAAM,CAAC;GAGvD,OAAO,IAAI,KAAK;EAClB;EACA,gBAAgB,OAAO,YAAY,CAAC,GAAG,MAAM,QAAQ,CAAC,EAAE,KAAK,CAAC;CAChE;AACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { VERSION } from "./version.js";
|
|
2
|
+
import { CommandResult, DoctorCheck, DoctorStatus, EnvProbe, ExitCode, OutputLine, Writer } from "./types.js";
|
|
3
|
+
import { AiCommandContext, runAiCommand } from "./ai.js";
|
|
4
|
+
import { FileSystem, createMemoryFileSystem } from "./fs.js";
|
|
5
|
+
import { BuildOptions, BuildResult, buildProject } from "./build.js";
|
|
6
|
+
import { CliContext, runCli, runCliAsync } from "./cli.js";
|
|
7
|
+
import { CreateTarget, CreateTargetResult, quoteShellPath, resolveCreateTarget } from "./create-target.js";
|
|
8
|
+
import { DevOptions, DevSession, Watcher, startDev } from "./dev.js";
|
|
9
|
+
import { doctorSummary, renderDoctor, runDoctor } from "./doctor.js";
|
|
10
|
+
import { TemplatePick, naturalLanguageToTemplate } from "./nl.js";
|
|
11
|
+
import { ScaffoldOptions, ScaffoldResult, scaffold } from "./scaffold.js";
|
|
12
|
+
import { DEFAULT_TEMPLATE, TEMPLATES, Template, getTemplate, materialize, templateNames } from "./templates.js";
|
|
13
|
+
import { Maturity, NotImplementedError, PackageInfo, notImplemented } from "@mindees/core";
|
|
14
|
+
|
|
15
|
+
//#region src/index.d.ts
|
|
16
|
+
/** The npm package name. */
|
|
17
|
+
declare const name = "@mindees/cli";
|
|
18
|
+
/**
|
|
19
|
+
* Current maturity. The CLI core — dispatch, `create` (+ templates), `build`
|
|
20
|
+
* (via the compiler), `doctor`, `info`, and the dev rebuild orchestrator — is
|
|
21
|
+
* implemented and tested. The live dev-server HTTP/HMR transport is a developer
|
|
22
|
+
* preview; on-device NL→app generation is Phase 10 (today `--prompt` maps to a
|
|
23
|
+
* template deterministically).
|
|
24
|
+
*/
|
|
25
|
+
declare const maturity: Maturity;
|
|
26
|
+
/**
|
|
27
|
+
* Static identity + maturity metadata for this package. Frozen so the
|
|
28
|
+
* self-reported identity tooling introspects cannot be mutated at runtime,
|
|
29
|
+
* matching the `readonly` fields of {@link PackageInfo}.
|
|
30
|
+
*/
|
|
31
|
+
declare const info: PackageInfo;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { type AiCommandContext, type BuildOptions, type BuildResult, type CliContext, type CommandResult, type CreateTarget, type CreateTargetResult, DEFAULT_TEMPLATE, type DevOptions, type DevSession, type DoctorCheck, type DoctorStatus, type EnvProbe, type ExitCode, type FileSystem, type Maturity, NotImplementedError, type OutputLine, type PackageInfo, type ScaffoldOptions, type ScaffoldResult, TEMPLATES, type Template, type TemplatePick, VERSION, type Watcher, type Writer, buildProject, createMemoryFileSystem, doctorSummary, getTemplate, info, materialize, maturity, name, naturalLanguageToTemplate, notImplemented, quoteShellPath, renderDoctor, resolveCreateTarget, runAiCommand, runCli, runCliAsync, runDoctor, scaffold, startDev, templateNames };
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;;;AAuEA;AAAA,cAnBa,IAAA;AAmBuE;;;;;;;AAAA,cAPvE,QAAA,EAAU,QAAyB;;;;;;cAOnC,IAAA,EAAM,WAAiE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { VERSION } from "./version.js";
|
|
2
|
+
import { runAiCommand } from "./ai.js";
|
|
3
|
+
import { buildProject } from "./build.js";
|
|
4
|
+
import { quoteShellPath, resolveCreateTarget } from "./create-target.js";
|
|
5
|
+
import { doctorSummary, renderDoctor, runDoctor } from "./doctor.js";
|
|
6
|
+
import { DEFAULT_TEMPLATE, TEMPLATES, getTemplate, materialize, templateNames } from "./templates.js";
|
|
7
|
+
import { naturalLanguageToTemplate } from "./nl.js";
|
|
8
|
+
import { scaffold } from "./scaffold.js";
|
|
9
|
+
import { runCli, runCliAsync } from "./cli.js";
|
|
10
|
+
import { startDev } from "./dev.js";
|
|
11
|
+
import { createMemoryFileSystem } from "./fs.js";
|
|
12
|
+
import { NotImplementedError, notImplemented } from "@mindees/core";
|
|
13
|
+
//#region src/index.ts
|
|
14
|
+
/** The npm package name. */
|
|
15
|
+
const name = "@mindees/cli";
|
|
16
|
+
/**
|
|
17
|
+
* Current maturity. The CLI core — dispatch, `create` (+ templates), `build`
|
|
18
|
+
* (via the compiler), `doctor`, `info`, and the dev rebuild orchestrator — is
|
|
19
|
+
* implemented and tested. The live dev-server HTTP/HMR transport is a developer
|
|
20
|
+
* preview; on-device NL→app generation is Phase 10 (today `--prompt` maps to a
|
|
21
|
+
* template deterministically).
|
|
22
|
+
*/
|
|
23
|
+
const maturity = "experimental";
|
|
24
|
+
/**
|
|
25
|
+
* Static identity + maturity metadata for this package. Frozen so the
|
|
26
|
+
* self-reported identity tooling introspects cannot be mutated at runtime,
|
|
27
|
+
* matching the `readonly` fields of {@link PackageInfo}.
|
|
28
|
+
*/
|
|
29
|
+
const info = Object.freeze({
|
|
30
|
+
name,
|
|
31
|
+
version: VERSION,
|
|
32
|
+
maturity
|
|
33
|
+
});
|
|
34
|
+
//#endregion
|
|
35
|
+
export { DEFAULT_TEMPLATE, NotImplementedError, TEMPLATES, VERSION, buildProject, createMemoryFileSystem, doctorSummary, getTemplate, info, materialize, maturity, name, naturalLanguageToTemplate, notImplemented, quoteShellPath, renderDoctor, resolveCreateTarget, runAiCommand, runCli, runCliAsync, runDoctor, scaffold, startDev, templateNames };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { Maturity, PackageInfo } from '@mindees/core'\nimport { NotImplementedError, notImplemented } from '@mindees/core'\nimport { VERSION } from './version'\n\n/** AI command handler (used by `runCliAsync`; exposed for embedders). */\nexport { type AiCommandContext, runAiCommand } from './ai'\n/** Project build (via @mindees/compiler). */\nexport { type BuildOptions, type BuildResult, buildProject } from './build'\n/** CLI dispatch. `runCli` is synchronous; `runCliAsync` adds the async `ai` command. */\nexport { type CliContext, runCli, runCliAsync } from './cli'\n/** Create target path + package-name resolution. */\nexport {\n type CreateTarget,\n type CreateTargetResult,\n quoteShellPath,\n resolveCreateTarget,\n} from './create-target'\n/** Dev orchestrator (rebuild-on-change). */\nexport { type DevOptions, type DevSession, startDev, type Watcher } from './dev'\n/** Environment diagnostics. */\nexport { doctorSummary, renderDoctor, runDoctor } from './doctor'\n/** Filesystem abstraction. */\nexport { createMemoryFileSystem, type FileSystem } from './fs'\n/** Natural-language → template mapping (offline; AI is Phase 10). */\nexport { naturalLanguageToTemplate, type TemplatePick } from './nl'\n/** Scaffolding. */\nexport {\n type ScaffoldOptions,\n type ScaffoldResult,\n scaffold,\n} from './scaffold'\n/** Templates. */\nexport {\n DEFAULT_TEMPLATE,\n getTemplate,\n materialize,\n TEMPLATES,\n type Template,\n templateNames,\n} from './templates'\n/** Shared types. */\nexport type {\n CommandResult,\n DoctorCheck,\n DoctorStatus,\n EnvProbe,\n ExitCode,\n OutputLine,\n Writer,\n} from './types'\n\n/** The npm package name. */\nexport const name = '@mindees/cli'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport { VERSION }\n\n/**\n * Current maturity. The CLI core — dispatch, `create` (+ templates), `build`\n * (via the compiler), `doctor`, `info`, and the dev rebuild orchestrator — is\n * implemented and tested. The live dev-server HTTP/HMR transport is a developer\n * preview; on-device NL→app generation is Phase 10 (today `--prompt` maps to a\n * template deterministically).\n */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n\nexport type { Maturity, PackageInfo }\nexport { NotImplementedError, notImplemented }\n"],"mappings":";;;;;;;;;;;;;;AAoDA,MAAa,OAAO;;;;;;;;AAYpB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
|
package/dist/nl.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/nl.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Natural-language → template mapping for `mindees create --prompt "…"`.
|
|
4
|
+
*
|
|
5
|
+
* This is an **honest, deterministic, offline** keyword mapper — NOT AI codegen.
|
|
6
|
+
* Real natural-language app generation is a Phase 10 (`@mindees/ai` / Synapse)
|
|
7
|
+
* capability; until then, `--prompt` never blocks `create` and never pretends to
|
|
8
|
+
* understand more than it does: it picks the closest built-in template by
|
|
9
|
+
* keyword and explains why. The deterministic fallback is the `blank` template.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** The chosen template plus a short reason (shown to the user). */
|
|
14
|
+
interface TemplatePick {
|
|
15
|
+
template: string;
|
|
16
|
+
reason: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Map a free-text prompt to a built-in template by keyword. Deterministic and
|
|
20
|
+
* offline; defaults to {@link DEFAULT_TEMPLATE} when nothing matches. If a rule
|
|
21
|
+
* points at a template that doesn't exist, it's skipped (defensive).
|
|
22
|
+
*/
|
|
23
|
+
declare function naturalLanguageToTemplate(prompt: string): TemplatePick;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { TemplatePick, naturalLanguageToTemplate };
|
|
26
|
+
//# sourceMappingURL=nl.d.ts.map
|
package/dist/nl.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nl.d.ts","names":[],"sources":["../src/nl.ts"],"mappings":";;AAeA;;;;AAEQ;AAgBR;;;;AAAuE;;UAlBtD,YAAA;EACf,QAAA;EACA,MAAM;AAAA;;;;;;iBAgBQ,yBAAA,CAA0B,MAAA,WAAiB,YAAY"}
|
package/dist/nl.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DEFAULT_TEMPLATE, getTemplate } from "./templates.js";
|
|
2
|
+
//#region src/nl.ts
|
|
3
|
+
/**
|
|
4
|
+
* Natural-language → template mapping for `mindees create --prompt "…"`.
|
|
5
|
+
*
|
|
6
|
+
* This is an **honest, deterministic, offline** keyword mapper — NOT AI codegen.
|
|
7
|
+
* Real natural-language app generation is a Phase 10 (`@mindees/ai` / Synapse)
|
|
8
|
+
* capability; until then, `--prompt` never blocks `create` and never pretends to
|
|
9
|
+
* understand more than it does: it picks the closest built-in template by
|
|
10
|
+
* keyword and explains why. The deterministic fallback is the `blank` template.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
/** Keyword → template rules, checked in order. */
|
|
15
|
+
const RULES = [{
|
|
16
|
+
keywords: [
|
|
17
|
+
"counter",
|
|
18
|
+
"count",
|
|
19
|
+
"increment",
|
|
20
|
+
"button",
|
|
21
|
+
"click",
|
|
22
|
+
"reactive"
|
|
23
|
+
],
|
|
24
|
+
template: "counter"
|
|
25
|
+
}];
|
|
26
|
+
/**
|
|
27
|
+
* Map a free-text prompt to a built-in template by keyword. Deterministic and
|
|
28
|
+
* offline; defaults to {@link DEFAULT_TEMPLATE} when nothing matches. If a rule
|
|
29
|
+
* points at a template that doesn't exist, it's skipped (defensive).
|
|
30
|
+
*/
|
|
31
|
+
function naturalLanguageToTemplate(prompt) {
|
|
32
|
+
const text = prompt.toLowerCase();
|
|
33
|
+
for (const rule of RULES) {
|
|
34
|
+
if (!getTemplate(rule.template)) continue;
|
|
35
|
+
const hit = rule.keywords.find((k) => text.includes(k));
|
|
36
|
+
if (hit) return {
|
|
37
|
+
template: rule.template,
|
|
38
|
+
reason: `matched keyword "${hit}"`
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
template: DEFAULT_TEMPLATE,
|
|
43
|
+
reason: "no keyword matched; using the default template"
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { naturalLanguageToTemplate };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=nl.js.map
|
package/dist/nl.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nl.js","names":[],"sources":["../src/nl.ts"],"sourcesContent":["/**\n * Natural-language → template mapping for `mindees create --prompt \"…\"`.\n *\n * This is an **honest, deterministic, offline** keyword mapper — NOT AI codegen.\n * Real natural-language app generation is a Phase 10 (`@mindees/ai` / Synapse)\n * capability; until then, `--prompt` never blocks `create` and never pretends to\n * understand more than it does: it picks the closest built-in template by\n * keyword and explains why. The deterministic fallback is the `blank` template.\n *\n * @module\n */\n\nimport { DEFAULT_TEMPLATE, getTemplate } from './templates'\n\n/** The chosen template plus a short reason (shown to the user). */\nexport interface TemplatePick {\n template: string\n reason: string\n}\n\n/** Keyword → template rules, checked in order. */\nconst RULES: Array<{ keywords: string[]; template: string }> = [\n {\n keywords: ['counter', 'count', 'increment', 'button', 'click', 'reactive'],\n template: 'counter',\n },\n]\n\n/**\n * Map a free-text prompt to a built-in template by keyword. Deterministic and\n * offline; defaults to {@link DEFAULT_TEMPLATE} when nothing matches. If a rule\n * points at a template that doesn't exist, it's skipped (defensive).\n */\nexport function naturalLanguageToTemplate(prompt: string): TemplatePick {\n const text = prompt.toLowerCase()\n for (const rule of RULES) {\n if (!getTemplate(rule.template)) continue\n const hit = rule.keywords.find((k) => text.includes(k))\n if (hit) {\n return { template: rule.template, reason: `matched keyword \"${hit}\"` }\n }\n }\n return { template: DEFAULT_TEMPLATE, reason: 'no keyword matched; using the default template' }\n}\n"],"mappings":";;;;;;;;;;;;;;AAqBA,MAAM,QAAyD,CAC7D;CACE,UAAU;EAAC;EAAW;EAAS;EAAa;EAAU;EAAS;CAAU;CACzE,UAAU;AACZ,CACF;;;;;;AAOA,SAAgB,0BAA0B,QAA8B;CACtE,MAAM,OAAO,OAAO,YAAY;CAChC,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,CAAC,YAAY,KAAK,QAAQ,GAAG;EACjC,MAAM,MAAM,KAAK,SAAS,MAAM,MAAM,KAAK,SAAS,CAAC,CAAC;EACtD,IAAI,KACF,OAAO;GAAE,UAAU,KAAK;GAAU,QAAQ,oBAAoB,IAAI;EAAG;CAEzE;CACA,OAAO;EAAE,UAAU;EAAkB,QAAQ;CAAiD;AAChG"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { FileSystem } from "./fs.js";
|
|
2
|
+
|
|
3
|
+
//#region src/scaffold.d.ts
|
|
4
|
+
/** Options for {@link scaffold}. */
|
|
5
|
+
interface ScaffoldOptions {
|
|
6
|
+
/** App/directory name (also used to substitute `{{appName}}`). */
|
|
7
|
+
appName: string;
|
|
8
|
+
/** Target directory to write into. */
|
|
9
|
+
targetDir: string;
|
|
10
|
+
/** Template name. Defaults to `blank`. */
|
|
11
|
+
template?: string;
|
|
12
|
+
/** Overwrite a non-empty target directory. Default `false`. */
|
|
13
|
+
force?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** Outcome of a scaffold. */
|
|
16
|
+
interface ScaffoldResult {
|
|
17
|
+
ok: boolean;
|
|
18
|
+
/** Files written (relative to `targetDir`), sorted. */
|
|
19
|
+
written: string[];
|
|
20
|
+
/** Reason for failure, if `ok` is false. */
|
|
21
|
+
error?: string;
|
|
22
|
+
/** The resolved template name. */
|
|
23
|
+
template: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Scaffold a new project. Returns the list of files written, or an error if the
|
|
27
|
+
* template is unknown or the target is non-empty (without `force`).
|
|
28
|
+
*/
|
|
29
|
+
declare function scaffold(fs: FileSystem, options: ScaffoldOptions): ScaffoldResult;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { ScaffoldOptions, ScaffoldResult, scaffold };
|
|
32
|
+
//# sourceMappingURL=scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","names":[],"sources":["../src/scaffold.ts"],"mappings":";;;;UAciB,eAAA;EAQV;EANL,OAAA;EAU6B;EAR7B,SAAA;EAQ6B;EAN7B,QAAA;EASA;EAPA,KAAA;AAAA;;UAIe,cAAA;EACf,EAAA;EAasB;EAXtB,OAAA;EAW2B;EAT3B,KAAA;EASkE;EAPlE,QAAA;AAAA;;;;;iBAOc,QAAA,CAAS,EAAA,EAAI,UAAA,EAAY,OAAA,EAAS,eAAA,GAAkB,cAAA"}
|
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { DEFAULT_TEMPLATE, getTemplate, materialize, templateNames } from "./templates.js";
|
|
2
|
+
//#region src/scaffold.ts
|
|
3
|
+
/**
|
|
4
|
+
* Scaffold a new project. Returns the list of files written, or an error if the
|
|
5
|
+
* template is unknown or the target is non-empty (without `force`).
|
|
6
|
+
*/
|
|
7
|
+
function scaffold(fs, options) {
|
|
8
|
+
const { appName, targetDir, template = DEFAULT_TEMPLATE, force = false } = options;
|
|
9
|
+
const tpl = getTemplate(template);
|
|
10
|
+
if (!tpl) return {
|
|
11
|
+
ok: false,
|
|
12
|
+
written: [],
|
|
13
|
+
template,
|
|
14
|
+
error: `Unknown template "${template}". Available: ${templateNames().join(", ")}.`
|
|
15
|
+
};
|
|
16
|
+
if (fs.exists(targetDir)) {
|
|
17
|
+
let existing;
|
|
18
|
+
try {
|
|
19
|
+
existing = fs.readDir(targetDir);
|
|
20
|
+
} catch {
|
|
21
|
+
return {
|
|
22
|
+
ok: false,
|
|
23
|
+
written: [],
|
|
24
|
+
template,
|
|
25
|
+
error: `Target "${targetDir}" exists but could not be read (it may be a file or inaccessible).`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (!force && existing.length > 0) return {
|
|
29
|
+
ok: false,
|
|
30
|
+
written: [],
|
|
31
|
+
template,
|
|
32
|
+
error: `Target directory "${targetDir}" is not empty. Use --force to overwrite.`
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const files = materialize(tpl, appName);
|
|
36
|
+
const written = [];
|
|
37
|
+
fs.mkdir(targetDir);
|
|
38
|
+
for (const [rel, contents] of Object.entries(files)) {
|
|
39
|
+
fs.writeFile(`${targetDir}/${rel}`, contents);
|
|
40
|
+
written.push(rel);
|
|
41
|
+
}
|
|
42
|
+
written.sort();
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
written,
|
|
46
|
+
template
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { scaffold };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.js","names":[],"sources":["../src/scaffold.ts"],"sourcesContent":["/**\n * `scaffold` — write a template into a target directory.\n *\n * Pure over an injected {@link FileSystem}, so `create` and `create-mindees`\n * share one tested implementation. Refuses to overwrite a non-empty target\n * unless `force` is set.\n *\n * @module\n */\n\nimport type { FileSystem } from './fs'\nimport { DEFAULT_TEMPLATE, getTemplate, materialize, templateNames } from './templates'\n\n/** Options for {@link scaffold}. */\nexport interface ScaffoldOptions {\n /** App/directory name (also used to substitute `{{appName}}`). */\n appName: string\n /** Target directory to write into. */\n targetDir: string\n /** Template name. Defaults to `blank`. */\n template?: string\n /** Overwrite a non-empty target directory. Default `false`. */\n force?: boolean\n}\n\n/** Outcome of a scaffold. */\nexport interface ScaffoldResult {\n ok: boolean\n /** Files written (relative to `targetDir`), sorted. */\n written: string[]\n /** Reason for failure, if `ok` is false. */\n error?: string\n /** The resolved template name. */\n template: string\n}\n\n/**\n * Scaffold a new project. Returns the list of files written, or an error if the\n * template is unknown or the target is non-empty (without `force`).\n */\nexport function scaffold(fs: FileSystem, options: ScaffoldOptions): ScaffoldResult {\n const { appName, targetDir, template = DEFAULT_TEMPLATE, force = false } = options\n\n const tpl = getTemplate(template)\n if (!tpl) {\n return {\n ok: false,\n written: [],\n template,\n error: `Unknown template \"${template}\". Available: ${templateNames().join(', ')}.`,\n }\n }\n\n if (fs.exists(targetDir)) {\n let existing: string[]\n try {\n existing = fs.readDir(targetDir)\n } catch {\n // targetDir exists but could not be listed. The common cause is that it is a regular\n // FILE rather than a directory (readDir throws ENOTDIR), but it could also be a\n // permission error (EACCES) or another I/O failure — don't assert a specific cause we\n // didn't verify. Report it cleanly instead of letting the exception escape (the CLI\n // contract is \"never throws for expected failures\").\n return {\n ok: false,\n written: [],\n template,\n error: `Target \"${targetDir}\" exists but could not be read (it may be a file or inaccessible).`,\n }\n }\n if (!force && existing.length > 0) {\n return {\n ok: false,\n written: [],\n template,\n error: `Target directory \"${targetDir}\" is not empty. Use --force to overwrite.`,\n }\n }\n }\n\n const files = materialize(tpl, appName)\n const written: string[] = []\n fs.mkdir(targetDir)\n for (const [rel, contents] of Object.entries(files)) {\n fs.writeFile(`${targetDir}/${rel}`, contents)\n written.push(rel)\n }\n written.sort()\n return { ok: true, written, template }\n}\n"],"mappings":";;;;;;AAwCA,SAAgB,SAAS,IAAgB,SAA0C;CACjF,MAAM,EAAE,SAAS,WAAW,WAAW,kBAAkB,QAAQ,UAAU;CAE3E,MAAM,MAAM,YAAY,QAAQ;CAChC,IAAI,CAAC,KACH,OAAO;EACL,IAAI;EACJ,SAAS,CAAC;EACV;EACA,OAAO,qBAAqB,SAAS,gBAAgB,cAAc,EAAE,KAAK,IAAI,EAAE;CAClF;CAGF,IAAI,GAAG,OAAO,SAAS,GAAG;EACxB,IAAI;EACJ,IAAI;GACF,WAAW,GAAG,QAAQ,SAAS;EACjC,QAAQ;GAMN,OAAO;IACL,IAAI;IACJ,SAAS,CAAC;IACV;IACA,OAAO,WAAW,UAAU;GAC9B;EACF;EACA,IAAI,CAAC,SAAS,SAAS,SAAS,GAC9B,OAAO;GACL,IAAI;GACJ,SAAS,CAAC;GACV;GACA,OAAO,qBAAqB,UAAU;EACxC;CAEJ;CAEA,MAAM,QAAQ,YAAY,KAAK,OAAO;CACtC,MAAM,UAAoB,CAAC;CAC3B,GAAG,MAAM,SAAS;CAClB,KAAK,MAAM,CAAC,KAAK,aAAa,OAAO,QAAQ,KAAK,GAAG;EACnD,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,QAAQ;EAC5C,QAAQ,KAAK,GAAG;CAClB;CACA,QAAQ,KAAK;CACb,OAAO;EAAE,IAAI;EAAM;EAAS;CAAS;AACvC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/templates.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Project templates for `mindees create` / `create-mindees`.
|
|
4
|
+
*
|
|
5
|
+
* Templates are in-memory maps of relative path → file contents, so they're
|
|
6
|
+
* deterministic and need no on-disk fixtures. Each scaffolds a runnable
|
|
7
|
+
* MindeesNative app skeleton wired to the current `@mindees/*` packages.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/** A template: a name, a description, and its files (relative path → contents). */
|
|
12
|
+
interface Template {
|
|
13
|
+
name: string;
|
|
14
|
+
description: string;
|
|
15
|
+
files: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
/** All built-in templates, keyed by name. */
|
|
18
|
+
declare const TEMPLATES: Record<string, Template>;
|
|
19
|
+
/** The default template name used when none is specified. */
|
|
20
|
+
declare const DEFAULT_TEMPLATE = "blank";
|
|
21
|
+
/** Look up a template by name, or `undefined` if unknown. */
|
|
22
|
+
declare function getTemplate(name: string): Template | undefined;
|
|
23
|
+
/** Names of all available templates. */
|
|
24
|
+
declare function templateNames(): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Materialize a template's files for `appName`: substitutes the `{{appName}}`
|
|
27
|
+
* placeholder and returns a fresh path → contents map. Pure (no I/O).
|
|
28
|
+
*/
|
|
29
|
+
declare function materialize(template: Template, appName: string): Record<string, string>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { DEFAULT_TEMPLATE, TEMPLATES, Template, getTemplate, materialize, templateNames };
|
|
32
|
+
//# sourceMappingURL=templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","names":[],"sources":["../src/templates.ts"],"mappings":";;AAaA;;;;;;;;;UAAiB,QAAA;EACf,IAAA;EACA,WAAA;EACA,KAAA,EAAO,MAAM;AAAA;AAwHgC;AAAA,cAAlC,SAAA,EAAW,MAAM,SAAS,QAAA;;cAM1B,gBAAA;;iBAGG,WAAA,CAAY,IAAA,WAAe,QAAQ;AAAnD;AAAA,iBAKgB,aAAA;;;AALmC;AAKnD;iBAQgB,WAAA,CAAY,QAAA,EAAU,QAAA,EAAU,OAAA,WAAkB,MAAM"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { VERSION } from "./version.js";
|
|
2
|
+
//#region src/templates.ts
|
|
3
|
+
/**
|
|
4
|
+
* Project templates for `mindees create` / `create-mindees`.
|
|
5
|
+
*
|
|
6
|
+
* Templates are in-memory maps of relative path → file contents, so they're
|
|
7
|
+
* deterministic and need no on-disk fixtures. Each scaffolds a runnable
|
|
8
|
+
* MindeesNative app skeleton wired to the current `@mindees/*` packages.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Version pinned for scaffolded apps. Derives from the CLI's own
|
|
14
|
+
* {@link VERSION} (the single locked `@mindees/*` version line) so generated
|
|
15
|
+
* projects always pin the framework packages to the same release that
|
|
16
|
+
* scaffolded them, instead of a hardcoded literal.
|
|
17
|
+
*/
|
|
18
|
+
const PKG_VERSION = VERSION;
|
|
19
|
+
function appPackageJson(appName, extraDeps = {}) {
|
|
20
|
+
const deps = {
|
|
21
|
+
"@mindees/core": PKG_VERSION,
|
|
22
|
+
"@mindees/renderer": PKG_VERSION,
|
|
23
|
+
...extraDeps
|
|
24
|
+
};
|
|
25
|
+
return `${JSON.stringify({
|
|
26
|
+
name: appName,
|
|
27
|
+
version: "0.1.0",
|
|
28
|
+
private: true,
|
|
29
|
+
type: "module",
|
|
30
|
+
scripts: {
|
|
31
|
+
dev: "mindees dev",
|
|
32
|
+
build: "mindees build"
|
|
33
|
+
},
|
|
34
|
+
dependencies: deps,
|
|
35
|
+
devDependencies: { "@mindees/cli": PKG_VERSION }
|
|
36
|
+
}, null, 2)}\n`;
|
|
37
|
+
}
|
|
38
|
+
const GITIGNORE = "node_modules/\ndist/\n*.log\n";
|
|
39
|
+
const TSCONFIG = `${JSON.stringify({
|
|
40
|
+
compilerOptions: {
|
|
41
|
+
strict: true,
|
|
42
|
+
module: "esnext",
|
|
43
|
+
moduleResolution: "bundler",
|
|
44
|
+
target: "es2023",
|
|
45
|
+
jsx: "react",
|
|
46
|
+
jsxFactory: "createElement",
|
|
47
|
+
jsxFragmentFactory: "Fragment",
|
|
48
|
+
verbatimModuleSyntax: true
|
|
49
|
+
},
|
|
50
|
+
include: ["src"]
|
|
51
|
+
}, null, 2)}\n`;
|
|
52
|
+
/** All built-in templates, keyed by name. */
|
|
53
|
+
const TEMPLATES = {
|
|
54
|
+
blank: {
|
|
55
|
+
name: "blank",
|
|
56
|
+
description: "A minimal MindeesNative app (one screen).",
|
|
57
|
+
files: {
|
|
58
|
+
"package.json": appPackageJson("{{appName}}"),
|
|
59
|
+
".gitignore": GITIGNORE,
|
|
60
|
+
"tsconfig.json": TSCONFIG,
|
|
61
|
+
"README.md": `# {{appName}}\n\nA MindeesNative app. Start with \`mindees dev\`.\n`,
|
|
62
|
+
"src/App.tsx": `import { createElement } from '@mindees/core'
|
|
63
|
+
|
|
64
|
+
export function App() {
|
|
65
|
+
return (
|
|
66
|
+
<view>
|
|
67
|
+
<text>Hello from {{appName}} 👋</text>
|
|
68
|
+
</view>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
`,
|
|
72
|
+
"src/main.tsx": `import { createDomBackend, render } from '@mindees/renderer'
|
|
73
|
+
import { App } from './App'
|
|
74
|
+
|
|
75
|
+
const root = document.getElementById('app')
|
|
76
|
+
if (root) render(App, {}, createDomBackend(), root)
|
|
77
|
+
`
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
counter: {
|
|
81
|
+
name: "counter",
|
|
82
|
+
description: "A reactive counter — demonstrates signals + fine-grained updates.",
|
|
83
|
+
files: {
|
|
84
|
+
"package.json": appPackageJson("{{appName}}"),
|
|
85
|
+
".gitignore": GITIGNORE,
|
|
86
|
+
"tsconfig.json": TSCONFIG,
|
|
87
|
+
"README.md": `# {{appName}}\n\nA reactive counter built with MindeesNative signals.\n`,
|
|
88
|
+
"src/App.tsx": `import { createElement, signal } from '@mindees/core'
|
|
89
|
+
|
|
90
|
+
export function App() {
|
|
91
|
+
const count = signal(0)
|
|
92
|
+
return (
|
|
93
|
+
<view>
|
|
94
|
+
<text>{() => \`Count: \${count()}\`}</text>
|
|
95
|
+
<button onClick={() => count.set(count() + 1)}>Increment</button>
|
|
96
|
+
</view>
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
`,
|
|
100
|
+
"src/main.tsx": `import { createDomBackend, render } from '@mindees/renderer'
|
|
101
|
+
import { App } from './App'
|
|
102
|
+
|
|
103
|
+
const root = document.getElementById('app')
|
|
104
|
+
if (root) render(App, {}, createDomBackend(), root)
|
|
105
|
+
`
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
/** The default template name used when none is specified. */
|
|
110
|
+
const DEFAULT_TEMPLATE = "blank";
|
|
111
|
+
/** Look up a template by name, or `undefined` if unknown. */
|
|
112
|
+
function getTemplate(name) {
|
|
113
|
+
return TEMPLATES[name];
|
|
114
|
+
}
|
|
115
|
+
/** Names of all available templates. */
|
|
116
|
+
function templateNames() {
|
|
117
|
+
return Object.keys(TEMPLATES);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Materialize a template's files for `appName`: substitutes the `{{appName}}`
|
|
121
|
+
* placeholder and returns a fresh path → contents map. Pure (no I/O).
|
|
122
|
+
*/
|
|
123
|
+
function materialize(template, appName) {
|
|
124
|
+
const out = {};
|
|
125
|
+
for (const [path, contents] of Object.entries(template.files)) out[path] = contents.replaceAll("{{appName}}", appName);
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
//#endregion
|
|
129
|
+
export { DEFAULT_TEMPLATE, TEMPLATES, getTemplate, materialize, templateNames };
|
|
130
|
+
|
|
131
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","names":[],"sources":["../src/templates.ts"],"sourcesContent":["/**\n * Project templates for `mindees create` / `create-mindees`.\n *\n * Templates are in-memory maps of relative path → file contents, so they're\n * deterministic and need no on-disk fixtures. Each scaffolds a runnable\n * MindeesNative app skeleton wired to the current `@mindees/*` packages.\n *\n * @module\n */\n\nimport { VERSION } from './version'\n\n/** A template: a name, a description, and its files (relative path → contents). */\nexport interface Template {\n name: string\n description: string\n files: Record<string, string>\n}\n\n/**\n * Version pinned for scaffolded apps. Derives from the CLI's own\n * {@link VERSION} (the single locked `@mindees/*` version line) so generated\n * projects always pin the framework packages to the same release that\n * scaffolded them, instead of a hardcoded literal.\n */\nconst PKG_VERSION = VERSION\n\nfunction appPackageJson(appName: string, extraDeps: Record<string, string> = {}): string {\n const deps = {\n '@mindees/core': PKG_VERSION,\n '@mindees/renderer': PKG_VERSION,\n ...extraDeps,\n }\n // The `dev`/`build` scripts invoke the `mindees` binary, so the CLI must be a\n // (dev) dependency of the generated app — otherwise the commands only resolve\n // when the CLI happens to be installed globally.\n const devDeps = {\n '@mindees/cli': PKG_VERSION,\n }\n return `${JSON.stringify(\n {\n name: appName,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n dev: 'mindees dev',\n build: 'mindees build',\n },\n dependencies: deps,\n devDependencies: devDeps,\n },\n null,\n 2,\n )}\\n`\n}\n\nconst GITIGNORE = 'node_modules/\\ndist/\\n*.log\\n'\n\nconst TSCONFIG = `${JSON.stringify(\n {\n compilerOptions: {\n strict: true,\n module: 'esnext',\n moduleResolution: 'bundler',\n target: 'es2023',\n jsx: 'react',\n jsxFactory: 'createElement',\n jsxFragmentFactory: 'Fragment',\n verbatimModuleSyntax: true,\n },\n include: ['src'],\n },\n null,\n 2,\n)}\\n`\n\n/** The `blank` template: the minimal runnable app. */\nconst blank: Template = {\n name: 'blank',\n description: 'A minimal MindeesNative app (one screen).',\n files: {\n 'package.json': appPackageJson('{{appName}}'),\n '.gitignore': GITIGNORE,\n 'tsconfig.json': TSCONFIG,\n 'README.md': `# {{appName}}\\n\\nA MindeesNative app. Start with \\`mindees dev\\`.\\n`,\n 'src/App.tsx': `import { createElement } from '@mindees/core'\n\nexport function App() {\n return (\n <view>\n <text>Hello from {{appName}} 👋</text>\n </view>\n )\n}\n`,\n 'src/main.tsx': `import { createDomBackend, render } from '@mindees/renderer'\nimport { App } from './App'\n\nconst root = document.getElementById('app')\nif (root) render(App, {}, createDomBackend(), root)\n`,\n },\n}\n\n/** The `counter` template: shows fine-grained reactivity (signals). */\nconst counter: Template = {\n name: 'counter',\n description: 'A reactive counter — demonstrates signals + fine-grained updates.',\n files: {\n 'package.json': appPackageJson('{{appName}}'),\n '.gitignore': GITIGNORE,\n 'tsconfig.json': TSCONFIG,\n 'README.md': `# {{appName}}\\n\\nA reactive counter built with MindeesNative signals.\\n`,\n 'src/App.tsx': `import { createElement, signal } from '@mindees/core'\n\nexport function App() {\n const count = signal(0)\n return (\n <view>\n <text>{() => \\`Count: \\${count()}\\`}</text>\n <button onClick={() => count.set(count() + 1)}>Increment</button>\n </view>\n )\n}\n`,\n 'src/main.tsx': `import { createDomBackend, render } from '@mindees/renderer'\nimport { App } from './App'\n\nconst root = document.getElementById('app')\nif (root) render(App, {}, createDomBackend(), root)\n`,\n },\n}\n\n/** All built-in templates, keyed by name. */\nexport const TEMPLATES: Record<string, Template> = {\n blank,\n counter,\n}\n\n/** The default template name used when none is specified. */\nexport const DEFAULT_TEMPLATE = 'blank'\n\n/** Look up a template by name, or `undefined` if unknown. */\nexport function getTemplate(name: string): Template | undefined {\n return TEMPLATES[name]\n}\n\n/** Names of all available templates. */\nexport function templateNames(): string[] {\n return Object.keys(TEMPLATES)\n}\n\n/**\n * Materialize a template's files for `appName`: substitutes the `{{appName}}`\n * placeholder and returns a fresh path → contents map. Pure (no I/O).\n */\nexport function materialize(template: Template, appName: string): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [path, contents] of Object.entries(template.files)) {\n out[path] = contents.replaceAll('{{appName}}', appName)\n }\n return out\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,MAAM,cAAc;AAEpB,SAAS,eAAe,SAAiB,YAAoC,CAAC,GAAW;CACvF,MAAM,OAAO;EACX,iBAAiB;EACjB,qBAAqB;EACrB,GAAG;CACL;CAOA,OAAO,GAAG,KAAK,UACb;EACE,MAAM;EACN,SAAS;EACT,SAAS;EACT,MAAM;EACN,SAAS;GACP,KAAK;GACL,OAAO;EACT;EACA,cAAc;EACd,iBAAiB,EAbnB,gBAAgB,YAaS;CACzB,GACA,MACA,CACF,EAAE;AACJ;AAEA,MAAM,YAAY;AAElB,MAAM,WAAW,GAAG,KAAK,UACvB;CACE,iBAAiB;EACf,QAAQ;EACR,QAAQ;EACR,kBAAkB;EAClB,QAAQ;EACR,KAAK;EACL,YAAY;EACZ,oBAAoB;EACpB,sBAAsB;CACxB;CACA,SAAS,CAAC,KAAK;AACjB,GACA,MACA,CACF,EAAE;;AA6DF,MAAa,YAAsC;CACjD;EA1DA,MAAM;EACN,aAAa;EACb,OAAO;GACL,gBAAgB,eAAe,aAAa;GAC5C,cAAc;GACd,iBAAiB;GACjB,aAAa;GACb,eAAe;;;;;;;;;;GAUf,gBAAgB;;;;;;EAMlB;CAmCA;CACA;EA/BA,MAAM;EACN,aAAa;EACb,OAAO;GACL,gBAAgB,eAAe,aAAa;GAC5C,cAAc;GACd,iBAAiB;GACjB,aAAa;GACb,eAAe;;;;;;;;;;;;GAYf,gBAAgB;;;;;;EAMlB;CAMA;AACF;;AAGA,MAAa,mBAAmB;;AAGhC,SAAgB,YAAY,MAAoC;CAC9D,OAAO,UAAU;AACnB;;AAGA,SAAgB,gBAA0B;CACxC,OAAO,OAAO,KAAK,SAAS;AAC9B;;;;;AAMA,SAAgB,YAAY,UAAoB,SAAyC;CACvF,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,CAAC,MAAM,aAAa,OAAO,QAAQ,SAAS,KAAK,GAC1D,IAAI,QAAQ,SAAS,WAAW,eAAe,OAAO;CAExD,OAAO;AACT"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared types for Forge — the MindeesNative CLI (`mindees`).
|
|
4
|
+
*
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
/** Exit-code convention: 0 = success, non-zero = failure. */
|
|
8
|
+
type ExitCode = number;
|
|
9
|
+
/**
|
|
10
|
+
* A line of output, tagged by stream. The CLI core never writes to the console
|
|
11
|
+
* directly — it returns/streams `OutputLine`s so every command is testable.
|
|
12
|
+
*/
|
|
13
|
+
interface OutputLine {
|
|
14
|
+
stream: 'out' | 'err';
|
|
15
|
+
text: string;
|
|
16
|
+
}
|
|
17
|
+
/** A sink the CLI writes structured output to (console adapter in `bin`). */
|
|
18
|
+
type Writer = (line: OutputLine) => void;
|
|
19
|
+
/** The result of running a CLI command. */
|
|
20
|
+
interface CommandResult {
|
|
21
|
+
exitCode: ExitCode;
|
|
22
|
+
}
|
|
23
|
+
/** Severity of a {@link DoctorCheck}. */
|
|
24
|
+
type DoctorStatus = 'ok' | 'warn' | 'fail';
|
|
25
|
+
/** One environment check produced by `doctor`. */
|
|
26
|
+
interface DoctorCheck {
|
|
27
|
+
/** Short label, e.g. `"Node.js"`. */
|
|
28
|
+
name: string;
|
|
29
|
+
status: DoctorStatus;
|
|
30
|
+
/** What was found, e.g. `"v24.7.0"`. */
|
|
31
|
+
detail: string;
|
|
32
|
+
/** Actionable fix shown when `status` is `warn`/`fail`. */
|
|
33
|
+
fix?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A snapshot of the environment, injected into `doctor` so it is fully
|
|
37
|
+
* deterministic in tests (no real `process`/fs access in the core).
|
|
38
|
+
*/
|
|
39
|
+
interface EnvProbe {
|
|
40
|
+
/** Node version string, e.g. `process.version` → `"v24.7.0"`. */
|
|
41
|
+
nodeVersion: string;
|
|
42
|
+
/** Detected package manager + version, or `null` if none. */
|
|
43
|
+
packageManager: {
|
|
44
|
+
name: string;
|
|
45
|
+
version: string;
|
|
46
|
+
} | null;
|
|
47
|
+
/** Whether a `package.json` exists in the working directory. */
|
|
48
|
+
hasPackageJson: boolean;
|
|
49
|
+
/** Whether `node_modules` exists (deps installed). */
|
|
50
|
+
hasNodeModules: boolean;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { CommandResult, DoctorCheck, DoctorStatus, EnvProbe, ExitCode, OutputLine, Writer };
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;AAOA;;;;AAAoB;AAAA,KAAR,QAAA;;;;AAQN;UAFW,UAAA;EACf,MAAA;EACA,IAAI;AAAA;AAIgC;AAAA,KAA1B,MAAA,IAAU,IAAgB,EAAV,UAAU;;UAGrB,aAAA;EACf,QAAA,EAAU,QAAQ;AAAA;AAIpB;AAAA,KAAY,YAAA;;UAGK,WAAA;EAHO;EAKtB,IAAA;EACA,MAAA,EAAQ,YAAY;;EAEpB,MAAA;EAHA;EAKA,GAAA;AAAA;;;;AAAG;UAOY,QAAA;EAAQ;EAEvB,WAAA;EAFuB;EAIvB,cAAA;IAAkB,IAAA;IAAc,OAAA;EAAA;EAEhC;EAAA,cAAA;EAEc;EAAd,cAAA;AAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/version.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Single source of truth for the `@mindees/cli` package version.
|
|
4
|
+
*
|
|
5
|
+
* All `@mindees/*` packages share one locked version line (Changesets, fixed
|
|
6
|
+
* group). Keeping it in its own dependency-free module lets both the public
|
|
7
|
+
* package metadata ({@link index}) and the scaffolder's generated
|
|
8
|
+
* `package.json` ({@link templates}) pin to the same value without a circular
|
|
9
|
+
* import.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
14
|
+
declare const VERSION = "0.1.0";
|
|
15
|
+
//#endregion
|
|
16
|
+
export { VERSION };
|
|
17
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","names":[],"sources":["../src/version.ts"],"mappings":";;AAaA;;;;AAAoB;;;;;;;cAAP,OAAA"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/version.ts
|
|
2
|
+
/**
|
|
3
|
+
* Single source of truth for the `@mindees/cli` package version.
|
|
4
|
+
*
|
|
5
|
+
* All `@mindees/*` packages share one locked version line (Changesets, fixed
|
|
6
|
+
* group). Keeping it in its own dependency-free module lets both the public
|
|
7
|
+
* package metadata ({@link index}) and the scaffolder's generated
|
|
8
|
+
* `package.json` ({@link templates}) pin to the same value without a circular
|
|
9
|
+
* import.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
14
|
+
const VERSION = "0.1.0";
|
|
15
|
+
//#endregion
|
|
16
|
+
export { VERSION };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["/**\n * Single source of truth for the `@mindees/cli` package version.\n *\n * All `@mindees/*` packages share one locked version line (Changesets, fixed\n * group). Keeping it in its own dependency-free module lets both the public\n * package metadata ({@link index}) and the scaffolder's generated\n * `package.json` ({@link templates}) pin to the same value without a circular\n * import.\n *\n * @module\n */\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.1.0'\n"],"mappings":";;;;;;;;;;;;;AAaA,MAAa,UAAU"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mindees/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MindeesNative Forge — the `mindees` CLI: create, build (via the compiler), dev (rebuild orchestrator), doctor, info.",
|
|
5
|
+
"license": "MIT OR Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"bin": {
|
|
9
|
+
"mindees": "./dist/bin.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/mindees/mindees.git",
|
|
26
|
+
"directory": "packages/cli"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@mindees/core": "0.1.0",
|
|
30
|
+
"@mindees/compiler": "0.1.0",
|
|
31
|
+
"@mindees/ai": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsdown",
|
|
35
|
+
"typecheck": "tsc --noEmit"
|
|
36
|
+
}
|
|
37
|
+
}
|