@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/LICENSE
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# License
|
|
2
|
+
|
|
3
|
+
MindeesNative is dual-licensed under either of:
|
|
4
|
+
|
|
5
|
+
- **Apache License, Version 2.0** ([LICENSE-APACHE](./LICENSE-APACHE) or
|
|
6
|
+
<https://www.apache.org/licenses/LICENSE-2.0>)
|
|
7
|
+
- **MIT license** ([LICENSE-MIT](./LICENSE-MIT) or
|
|
8
|
+
<https://opensource.org/licenses/MIT>)
|
|
9
|
+
|
|
10
|
+
at your option.
|
|
11
|
+
|
|
12
|
+
This `MIT OR Apache-2.0` dual-license is the same model used by the Rust
|
|
13
|
+
ecosystem and many modern open-source projects. It gives downstream users
|
|
14
|
+
maximum flexibility: the MIT option is short and permissive, while the Apache
|
|
15
|
+
option adds an explicit patent grant.
|
|
16
|
+
|
|
17
|
+
## SPDX identifier
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
SPDX-License-Identifier: MIT OR Apache-2.0
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Contribution
|
|
24
|
+
|
|
25
|
+
Unless you explicitly state otherwise, any contribution intentionally
|
|
26
|
+
submitted for inclusion in the work by you, as defined in the Apache-2.0
|
|
27
|
+
license, shall be dual-licensed as above, without any additional terms or
|
|
28
|
+
conditions.
|
|
29
|
+
|
|
30
|
+
Contributions are accepted under the **Developer Certificate of Origin (DCO)**.
|
|
31
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for details on signing off your commits.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @mindees/cli
|
|
2
|
+
|
|
3
|
+
**Forge** โ the `mindees` command-line interface. Scaffold apps, type-check +
|
|
4
|
+
build them with the Mindees Compiler, and diagnose your environment. Zero
|
|
5
|
+
third-party dependencies (built on `node:util` `parseArgs`).
|
|
6
|
+
|
|
7
|
+
> **Status: ๐งช Experimental (Phase 5).** `create`, `build`, `doctor`, `info`,
|
|
8
|
+
> and the dev **rebuild orchestrator** are implemented and tested. The live
|
|
9
|
+
> dev-server **HTTP/HMR transport** is a developer preview. On-device NLโapp
|
|
10
|
+
> generation is Phase 10 โ today `--prompt` maps to a template deterministically.
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
mindees create <name-or-path> [--template blank|counter] [--prompt "..."] [--force]
|
|
16
|
+
mindees build [--out-dir <dir>] [--no-source-map]
|
|
17
|
+
mindees doctor # diagnose Node / package manager / project / deps
|
|
18
|
+
mindees info # CLI + environment info
|
|
19
|
+
mindees dev # rebuild-on-change (developer preview)
|
|
20
|
+
mindees help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
$ mindees create my-app --template counter
|
|
25
|
+
Created "my-app" from the counter template (6 files).
|
|
26
|
+
Next: cd "my-app" && pnpm install && mindees dev
|
|
27
|
+
|
|
28
|
+
$ mindees build
|
|
29
|
+
Built 3 module(s); flattened 4/9 elements.
|
|
30
|
+
|
|
31
|
+
$ mindees doctor
|
|
32
|
+
โ Node.js: v24.7.0
|
|
33
|
+
โ Package manager: pnpm 11.5.0
|
|
34
|
+
! Dependencies: node_modules missing
|
|
35
|
+
โ Install dependencies: `pnpm install` (or `npm exec --yes --package=pnpm@11.5.0 -- pnpm install` if the pnpm shim is unavailable).
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Design: a testable core, a thin shell
|
|
39
|
+
|
|
40
|
+
Every command is a **pure function** of injected capabilities โ a `FileSystem`,
|
|
41
|
+
an `EnvProbe`, and a `Writer` โ so the entire CLI is deterministic in tests. The
|
|
42
|
+
`mindees` executable (`bin`) is a thin adapter that wires real `node:fs` /
|
|
43
|
+
`process` into `runCli`. Highlights:
|
|
44
|
+
|
|
45
|
+
- **`scaffold`** โ writes a template through the injected FS (templates are
|
|
46
|
+
in-memory; no on-disk fixtures). Refuses a non-empty target without `--force`.
|
|
47
|
+
- **`resolveCreateTarget`** โ normalizes simple names, relative paths, and
|
|
48
|
+
absolute Windows/POSIX paths into a target directory plus npm-safe package
|
|
49
|
+
name, so path separators never leak into generated `package.json` files.
|
|
50
|
+
- **`buildProject`** โ compiles `src/**` via `@mindees/compiler` (the type-check
|
|
51
|
+
gate + emit), writing `dist/` and a `routes.manifest.json` when `src/routes/`
|
|
52
|
+
exists. Genuine type errors fail the build; isolation-only diagnostics
|
|
53
|
+
(unresolved cross-module imports, missing ambient JSX types) are reported as
|
|
54
|
+
warnings (full project-graph checking is future work).
|
|
55
|
+
- **`runDoctor`** โ environment checks with actionable fixes, over an injected
|
|
56
|
+
`EnvProbe`.
|
|
57
|
+
- **`startDev`** โ the rebuild orchestrator: builds once, rebuilds on each
|
|
58
|
+
`Watcher` change, tracks build count + last result. The watcher and HMR
|
|
59
|
+
transport are injected (the live server is the preview layer).
|
|
60
|
+
|
|
61
|
+
## Library API
|
|
62
|
+
|
|
63
|
+
Forge's internals are exported so other tooling (and `create-mindees`) can reuse
|
|
64
|
+
them: `runCli`, `scaffold`, `buildProject`, `startDev`, `runDoctor`,
|
|
65
|
+
`resolveCreateTarget`, `createMemoryFileSystem`, `TEMPLATES`,
|
|
66
|
+
`naturalLanguageToTemplate`, and their types.
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
`MIT OR Apache-2.0`
|
package/dist/ai.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CommandResult, Writer } from "./types.js";
|
|
2
|
+
import { AiBackend } from "@mindees/ai";
|
|
3
|
+
|
|
4
|
+
//#region src/ai.d.ts
|
|
5
|
+
/** What `runAiCommand` needs (injected for testability). */
|
|
6
|
+
interface AiCommandContext {
|
|
7
|
+
write: Writer;
|
|
8
|
+
/** The AI backend; absent when no `MINDEES_AI_*` env is configured. */
|
|
9
|
+
backend?: AiBackend;
|
|
10
|
+
}
|
|
11
|
+
/** Run an `ai` subcommand. Async because it talks to a model. */
|
|
12
|
+
declare function runAiCommand(args: readonly string[], ctx: AiCommandContext): Promise<CommandResult>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { AiCommandContext, runAiCommand };
|
|
15
|
+
//# sourceMappingURL=ai.d.ts.map
|
package/dist/ai.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai.d.ts","names":[],"sources":["../src/ai.ts"],"mappings":";;;;;UAeiB,gBAAA;EACf,KAAA,EAAO,MAAA;EAwBa;EAtBpB,OAAA,GAAU,SAAS;AAAA;;iBAsBC,YAAA,CACpB,IAAA,qBACA,GAAA,EAAK,gBAAA,GACJ,OAAA,CAAQ,aAAA"}
|
package/dist/ai.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { explainError, formatExplanation } from "@mindees/ai/devtools";
|
|
2
|
+
//#region src/ai.ts
|
|
3
|
+
const AI_HELP = `mindees ai โ dev-time AI helpers
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
mindees ai explain <error message...> Explain an error and suggest fixes
|
|
7
|
+
|
|
8
|
+
Configure a backend with environment variables:
|
|
9
|
+
MINDEES_AI_BASE_URL e.g. https://api.openai.com/v1
|
|
10
|
+
MINDEES_AI_MODEL e.g. gpt-4o-mini
|
|
11
|
+
MINDEES_AI_API_KEY your key
|
|
12
|
+
MINDEES_AI_ADAPTER openai (default) | anthropic`;
|
|
13
|
+
function out(write, text) {
|
|
14
|
+
write({
|
|
15
|
+
stream: "out",
|
|
16
|
+
text
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function err(write, text) {
|
|
20
|
+
write({
|
|
21
|
+
stream: "err",
|
|
22
|
+
text
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/** Run an `ai` subcommand. Async because it talks to a model. */
|
|
26
|
+
async function runAiCommand(args, ctx) {
|
|
27
|
+
const [sub, ...rest] = args;
|
|
28
|
+
if (!sub || sub === "help" || sub === "--help" || sub === "-h") {
|
|
29
|
+
out(ctx.write, AI_HELP);
|
|
30
|
+
return { exitCode: 0 };
|
|
31
|
+
}
|
|
32
|
+
if (sub !== "explain") {
|
|
33
|
+
err(ctx.write, `Unknown ai command "${sub}". Try \`mindees ai explain <error>\`.`);
|
|
34
|
+
return { exitCode: 1 };
|
|
35
|
+
}
|
|
36
|
+
const message = rest.join(" ").trim();
|
|
37
|
+
if (!message) {
|
|
38
|
+
err(ctx.write, "ai explain: provide an error message. Usage: mindees ai explain <error>");
|
|
39
|
+
return { exitCode: 1 };
|
|
40
|
+
}
|
|
41
|
+
if (!ctx.backend) {
|
|
42
|
+
err(ctx.write, "No AI backend configured. Set MINDEES_AI_BASE_URL and MINDEES_AI_MODEL (and MINDEES_AI_API_KEY if your provider needs one).");
|
|
43
|
+
return { exitCode: 1 };
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const explanation = await explainError(ctx.backend, { message });
|
|
47
|
+
out(ctx.write, formatExplanation(explanation));
|
|
48
|
+
return { exitCode: 0 };
|
|
49
|
+
} catch (e) {
|
|
50
|
+
err(ctx.write, `ai explain failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
51
|
+
return { exitCode: 1 };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { runAiCommand };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=ai.js.map
|
package/dist/ai.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai.js","names":[],"sources":["../src/ai.ts"],"sourcesContent":["/**\n * `mindees ai` โ dev-time AI helpers. Currently `ai explain <error>`, which runs Synapse's\n * {@link explainError} (from `@mindees/ai/devtools`) over an injected backend and prints a\n * structured explanation. Like every command, it's a pure function of injected capabilities\n * (the backend + writer), so it's deterministically testable with the mock backend; the real\n * `bin` wires a server backend from environment variables.\n *\n * @module\n */\n\nimport type { AiBackend } from '@mindees/ai'\nimport { explainError, formatExplanation } from '@mindees/ai/devtools'\nimport type { CommandResult, Writer } from './types'\n\n/** What `runAiCommand` needs (injected for testability). */\nexport interface AiCommandContext {\n write: Writer\n /** The AI backend; absent when no `MINDEES_AI_*` env is configured. */\n backend?: AiBackend\n}\n\nconst AI_HELP = `mindees ai โ dev-time AI helpers\n\nUsage:\n mindees ai explain <error message...> Explain an error and suggest fixes\n\nConfigure a backend with environment variables:\n MINDEES_AI_BASE_URL e.g. https://api.openai.com/v1\n MINDEES_AI_MODEL e.g. gpt-4o-mini\n MINDEES_AI_API_KEY your key\n MINDEES_AI_ADAPTER openai (default) | anthropic`\n\nfunction out(write: Writer, text: string): void {\n write({ stream: 'out', text })\n}\nfunction err(write: Writer, text: string): void {\n write({ stream: 'err', text })\n}\n\n/** Run an `ai` subcommand. Async because it talks to a model. */\nexport async function runAiCommand(\n args: readonly string[],\n ctx: AiCommandContext,\n): Promise<CommandResult> {\n const [sub, ...rest] = args\n\n if (!sub || sub === 'help' || sub === '--help' || sub === '-h') {\n out(ctx.write, AI_HELP)\n return { exitCode: 0 }\n }\n if (sub !== 'explain') {\n err(ctx.write, `Unknown ai command \"${sub}\". Try \\`mindees ai explain <error>\\`.`)\n return { exitCode: 1 }\n }\n\n const message = rest.join(' ').trim()\n if (!message) {\n err(ctx.write, 'ai explain: provide an error message. Usage: mindees ai explain <error>')\n return { exitCode: 1 }\n }\n if (!ctx.backend) {\n err(\n ctx.write,\n 'No AI backend configured. Set MINDEES_AI_BASE_URL and MINDEES_AI_MODEL (and MINDEES_AI_API_KEY if your provider needs one).',\n )\n return { exitCode: 1 }\n }\n\n try {\n const explanation = await explainError(ctx.backend, { message })\n out(ctx.write, formatExplanation(explanation))\n return { exitCode: 0 }\n } catch (e) {\n err(ctx.write, `ai explain failed: ${e instanceof Error ? e.message : String(e)}`)\n return { exitCode: 1 }\n }\n}\n"],"mappings":";;AAqBA,MAAM,UAAU;;;;;;;;;;AAWhB,SAAS,IAAI,OAAe,MAAoB;CAC9C,MAAM;EAAE,QAAQ;EAAO;CAAK,CAAC;AAC/B;AACA,SAAS,IAAI,OAAe,MAAoB;CAC9C,MAAM;EAAE,QAAQ;EAAO;CAAK,CAAC;AAC/B;;AAGA,eAAsB,aACpB,MACA,KACwB;CACxB,MAAM,CAAC,KAAK,GAAG,QAAQ;CAEvB,IAAI,CAAC,OAAO,QAAQ,UAAU,QAAQ,YAAY,QAAQ,MAAM;EAC9D,IAAI,IAAI,OAAO,OAAO;EACtB,OAAO,EAAE,UAAU,EAAE;CACvB;CACA,IAAI,QAAQ,WAAW;EACrB,IAAI,IAAI,OAAO,uBAAuB,IAAI,uCAAuC;EACjF,OAAO,EAAE,UAAU,EAAE;CACvB;CAEA,MAAM,UAAU,KAAK,KAAK,GAAG,EAAE,KAAK;CACpC,IAAI,CAAC,SAAS;EACZ,IAAI,IAAI,OAAO,yEAAyE;EACxF,OAAO,EAAE,UAAU,EAAE;CACvB;CACA,IAAI,CAAC,IAAI,SAAS;EAChB,IACE,IAAI,OACJ,6HACF;EACA,OAAO,EAAE,UAAU,EAAE;CACvB;CAEA,IAAI;EACF,MAAM,cAAc,MAAM,aAAa,IAAI,SAAS,EAAE,QAAQ,CAAC;EAC/D,IAAI,IAAI,OAAO,kBAAkB,WAAW,CAAC;EAC7C,OAAO,EAAE,UAAU,EAAE;CACvB,SAAS,GAAG;EACV,IAAI,IAAI,OAAO,sBAAsB,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,GAAG;EACjF,OAAO,EAAE,UAAU,EAAE;CACvB;AACF"}
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { VERSION } from "./version.js";
|
|
3
|
+
import { runCliAsync } from "./cli.js";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join, relative, sep } from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { createServerBackend } from "@mindees/ai/server";
|
|
8
|
+
//#region src/bin.ts
|
|
9
|
+
/**
|
|
10
|
+
* The `mindees` executable โ a thin adapter that wires real Node capabilities
|
|
11
|
+
* (filesystem, environment probe, stdout/stderr, AI backend) into the tested
|
|
12
|
+
* {@link runCliAsync} core. All logic lives in the core; this file only does I/O wiring.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
/** A `node:fs`-backed {@link FileSystem}. */
|
|
17
|
+
function nodeFileSystem() {
|
|
18
|
+
return {
|
|
19
|
+
exists: (path) => existsSync(path),
|
|
20
|
+
readFile: (path) => readFileSync(path, "utf8"),
|
|
21
|
+
writeFile: (path, contents) => {
|
|
22
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
23
|
+
writeFileSync(path, contents, "utf8");
|
|
24
|
+
},
|
|
25
|
+
mkdir: (path) => {
|
|
26
|
+
mkdirSync(path, { recursive: true });
|
|
27
|
+
},
|
|
28
|
+
readDir: (dir) => {
|
|
29
|
+
const walk = (current, acc) => {
|
|
30
|
+
if (!existsSync(current)) return acc;
|
|
31
|
+
for (const entry of readdirSync(current)) {
|
|
32
|
+
const full = join(current, entry);
|
|
33
|
+
if (statSync(full).isDirectory()) walk(full, acc);
|
|
34
|
+
else acc.push(relative(dir, full).split(sep).join("/"));
|
|
35
|
+
}
|
|
36
|
+
return acc;
|
|
37
|
+
};
|
|
38
|
+
return walk(dir, []).sort();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** Probe the real environment for `doctor`/`info`. */
|
|
43
|
+
function probeEnv(cwd) {
|
|
44
|
+
const pmMatch = (process.env.npm_config_user_agent ?? "").match(/^(\w+)\/(\S+)/);
|
|
45
|
+
return {
|
|
46
|
+
nodeVersion: process.version,
|
|
47
|
+
packageManager: pmMatch?.[1] && pmMatch[2] ? {
|
|
48
|
+
name: pmMatch[1],
|
|
49
|
+
version: pmMatch[2]
|
|
50
|
+
} : null,
|
|
51
|
+
hasPackageJson: existsSync(join(cwd, "package.json")),
|
|
52
|
+
hasNodeModules: existsSync(join(cwd, "node_modules"))
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Build a server AI backend from `MINDEES_AI_*` env, or `undefined` if not configured. */
|
|
56
|
+
function aiBackendFromEnv() {
|
|
57
|
+
const baseUrl = process.env.MINDEES_AI_BASE_URL;
|
|
58
|
+
const model = process.env.MINDEES_AI_MODEL;
|
|
59
|
+
if (!baseUrl || !model) return void 0;
|
|
60
|
+
const adapterEnv = process.env.MINDEES_AI_ADAPTER;
|
|
61
|
+
if (adapterEnv && adapterEnv !== "openai" && adapterEnv !== "anthropic") {
|
|
62
|
+
process.stderr.write(`mindees: unknown MINDEES_AI_ADAPTER "${adapterEnv}" (expected "openai" or "anthropic"); AI backend not configured.\n`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const adapter = adapterEnv === "anthropic" ? "anthropic" : "openai";
|
|
66
|
+
return createServerBackend({
|
|
67
|
+
fetch: globalThis.fetch,
|
|
68
|
+
baseUrl,
|
|
69
|
+
model,
|
|
70
|
+
adapter,
|
|
71
|
+
...process.env.MINDEES_AI_API_KEY ? { apiKey: process.env.MINDEES_AI_API_KEY } : {}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async function main() {
|
|
75
|
+
const cwd = process.cwd();
|
|
76
|
+
const write = (line) => {
|
|
77
|
+
(line.stream === "err" ? process.stderr : process.stdout).write(`${line.text}\n`);
|
|
78
|
+
};
|
|
79
|
+
const backend = aiBackendFromEnv();
|
|
80
|
+
const ctx = {
|
|
81
|
+
fs: nodeFileSystem(),
|
|
82
|
+
env: probeEnv(cwd),
|
|
83
|
+
cwd,
|
|
84
|
+
version: VERSION,
|
|
85
|
+
write,
|
|
86
|
+
...backend ? { aiBackend: backend } : {}
|
|
87
|
+
};
|
|
88
|
+
const { exitCode } = await runCliAsync(process.argv.slice(2), ctx);
|
|
89
|
+
process.exitCode = exitCode;
|
|
90
|
+
}
|
|
91
|
+
main();
|
|
92
|
+
//#endregion
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","names":[],"sources":["../src/bin.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * The `mindees` executable โ a thin adapter that wires real Node capabilities\n * (filesystem, environment probe, stdout/stderr, AI backend) into the tested\n * {@link runCliAsync} core. All logic lives in the core; this file only does I/O wiring.\n *\n * @module\n */\n\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'\nimport { dirname, join, relative, sep } from 'node:path'\nimport process from 'node:process'\nimport type { AiBackend } from '@mindees/ai'\nimport { type AdapterName, createServerBackend, type FetchLike } from '@mindees/ai/server'\nimport { type CliContext, runCliAsync } from './cli'\nimport type { FileSystem } from './fs'\nimport { VERSION } from './index'\nimport type { EnvProbe, OutputLine } from './types'\n\n/** A `node:fs`-backed {@link FileSystem}. */\nfunction nodeFileSystem(): FileSystem {\n return {\n exists: (path) => existsSync(path),\n readFile: (path) => readFileSync(path, 'utf8'),\n writeFile: (path, contents) => {\n mkdirSync(dirname(path), { recursive: true })\n writeFileSync(path, contents, 'utf8')\n },\n mkdir: (path) => {\n mkdirSync(path, { recursive: true })\n },\n readDir: (dir) => {\n const walk = (current: string, acc: string[]): string[] => {\n if (!existsSync(current)) return acc\n for (const entry of readdirSync(current)) {\n const full = join(current, entry)\n if (statSync(full).isDirectory()) walk(full, acc)\n else acc.push(relative(dir, full).split(sep).join('/'))\n }\n return acc\n }\n return walk(dir, []).sort()\n },\n }\n}\n\n/** Probe the real environment for `doctor`/`info`. */\nfunction probeEnv(cwd: string): EnvProbe {\n const pmSpec = process.env.npm_config_user_agent ?? ''\n // user agent looks like \"pnpm/11.5.0 npm/? node/v24 ...\".\n const pmMatch = pmSpec.match(/^(\\w+)\\/(\\S+)/)\n return {\n nodeVersion: process.version,\n packageManager: pmMatch?.[1] && pmMatch[2] ? { name: pmMatch[1], version: pmMatch[2] } : null,\n hasPackageJson: existsSync(join(cwd, 'package.json')),\n hasNodeModules: existsSync(join(cwd, 'node_modules')),\n }\n}\n\n/** Build a server AI backend from `MINDEES_AI_*` env, or `undefined` if not configured. */\nfunction aiBackendFromEnv(): AiBackend | undefined {\n const baseUrl = process.env.MINDEES_AI_BASE_URL\n const model = process.env.MINDEES_AI_MODEL\n if (!baseUrl || !model) return undefined\n // Fail loud on a mistyped adapter rather than silently defaulting to openai (which would\n // build the wrong auth headers and yield confusing HTTP errors). Empty/unset โ openai.\n const adapterEnv = process.env.MINDEES_AI_ADAPTER\n if (adapterEnv && adapterEnv !== 'openai' && adapterEnv !== 'anthropic') {\n process.stderr.write(\n `mindees: unknown MINDEES_AI_ADAPTER \"${adapterEnv}\" (expected \"openai\" or \"anthropic\"); AI backend not configured.\\n`,\n )\n return undefined\n }\n const adapter: AdapterName = adapterEnv === 'anthropic' ? 'anthropic' : 'openai'\n return createServerBackend({\n // The global `fetch` is structurally compatible at runtime; the minimal FetchLike\n // intentionally avoids the DOM lib, so cast rather than pull in those types.\n fetch: globalThis.fetch as unknown as FetchLike,\n baseUrl,\n model,\n adapter,\n ...(process.env.MINDEES_AI_API_KEY ? { apiKey: process.env.MINDEES_AI_API_KEY } : {}),\n })\n}\n\nasync function main(): Promise<void> {\n const cwd = process.cwd()\n const write = (line: OutputLine): void => {\n const stream = line.stream === 'err' ? process.stderr : process.stdout\n stream.write(`${line.text}\\n`)\n }\n const backend = aiBackendFromEnv()\n const ctx: CliContext = {\n fs: nodeFileSystem(),\n env: probeEnv(cwd),\n cwd,\n version: VERSION,\n write,\n ...(backend ? { aiBackend: backend } : {}),\n }\n const { exitCode } = await runCliAsync(process.argv.slice(2), ctx)\n process.exitCode = exitCode\n}\n\nmain()\n"],"mappings":";;;;;;;;;;;;;;;;AAqBA,SAAS,iBAA6B;CACpC,OAAO;EACL,SAAS,SAAS,WAAW,IAAI;EACjC,WAAW,SAAS,aAAa,MAAM,MAAM;EAC7C,YAAY,MAAM,aAAa;GAC7B,UAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;GAC5C,cAAc,MAAM,UAAU,MAAM;EACtC;EACA,QAAQ,SAAS;GACf,UAAU,MAAM,EAAE,WAAW,KAAK,CAAC;EACrC;EACA,UAAU,QAAQ;GAChB,MAAM,QAAQ,SAAiB,QAA4B;IACzD,IAAI,CAAC,WAAW,OAAO,GAAG,OAAO;IACjC,KAAK,MAAM,SAAS,YAAY,OAAO,GAAG;KACxC,MAAM,OAAO,KAAK,SAAS,KAAK;KAChC,IAAI,SAAS,IAAI,EAAE,YAAY,GAAG,KAAK,MAAM,GAAG;UAC3C,IAAI,KAAK,SAAS,KAAK,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;IACxD;IACA,OAAO;GACT;GACA,OAAO,KAAK,KAAK,CAAC,CAAC,EAAE,KAAK;EAC5B;CACF;AACF;;AAGA,SAAS,SAAS,KAAuB;CAGvC,MAAM,WAFS,QAAQ,IAAI,yBAAyB,IAE7B,MAAM,eAAe;CAC5C,OAAO;EACL,aAAa,QAAQ;EACrB,gBAAgB,UAAU,MAAM,QAAQ,KAAK;GAAE,MAAM,QAAQ;GAAI,SAAS,QAAQ;EAAG,IAAI;EACzF,gBAAgB,WAAW,KAAK,KAAK,cAAc,CAAC;EACpD,gBAAgB,WAAW,KAAK,KAAK,cAAc,CAAC;CACtD;AACF;;AAGA,SAAS,mBAA0C;CACjD,MAAM,UAAU,QAAQ,IAAI;CAC5B,MAAM,QAAQ,QAAQ,IAAI;CAC1B,IAAI,CAAC,WAAW,CAAC,OAAO,OAAO,KAAA;CAG/B,MAAM,aAAa,QAAQ,IAAI;CAC/B,IAAI,cAAc,eAAe,YAAY,eAAe,aAAa;EACvE,QAAQ,OAAO,MACb,wCAAwC,WAAW,mEACrD;EACA;CACF;CACA,MAAM,UAAuB,eAAe,cAAc,cAAc;CACxE,OAAO,oBAAoB;EAGzB,OAAO,WAAW;EAClB;EACA;EACA;EACA,GAAI,QAAQ,IAAI,qBAAqB,EAAE,QAAQ,QAAQ,IAAI,mBAAmB,IAAI,CAAC;CACrF,CAAC;AACH;AAEA,eAAe,OAAsB;CACnC,MAAM,MAAM,QAAQ,IAAI;CACxB,MAAM,SAAS,SAA2B;EAExC,CADe,KAAK,WAAW,QAAQ,QAAQ,SAAS,QAAQ,QACzD,MAAM,GAAG,KAAK,KAAK,GAAG;CAC/B;CACA,MAAM,UAAU,iBAAiB;CACjC,MAAM,MAAkB;EACtB,IAAI,eAAe;EACnB,KAAK,SAAS,GAAG;EACjB;EACA,SAAS;EACT;EACA,GAAI,UAAU,EAAE,WAAW,QAAQ,IAAI,CAAC;CAC1C;CACA,MAAM,EAAE,aAAa,MAAM,YAAY,QAAQ,KAAK,MAAM,CAAC,GAAG,GAAG;CACjE,QAAQ,WAAW;AACrB;AAEA,KAAK"}
|
package/dist/build.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { FileSystem } from "./fs.js";
|
|
2
|
+
import { Diagnostic, buildRouteManifest } from "@mindees/compiler";
|
|
3
|
+
|
|
4
|
+
//#region src/build.d.ts
|
|
5
|
+
/** Options for {@link buildProject}. */
|
|
6
|
+
interface BuildOptions {
|
|
7
|
+
/** Project root (contains `src/`). Default `"."`. */
|
|
8
|
+
root?: string;
|
|
9
|
+
/** Output directory. Default `"dist"`. */
|
|
10
|
+
outDir?: string;
|
|
11
|
+
/** Emit source maps. Default `true`. */
|
|
12
|
+
sourceMap?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Result of a project build. */
|
|
15
|
+
interface BuildResult {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
/** Source files compiled (relative paths), sorted. */
|
|
18
|
+
compiled: string[];
|
|
19
|
+
/** All diagnostics across modules (errors fail the build). */
|
|
20
|
+
diagnostics: Diagnostic[];
|
|
21
|
+
/** Route manifest, if `src/routes/` existed. */
|
|
22
|
+
routes?: ReturnType<typeof buildRouteManifest>;
|
|
23
|
+
/** Optimizer totals across all modules. */
|
|
24
|
+
stats: {
|
|
25
|
+
flattenedNodes: number;
|
|
26
|
+
totalElements: number;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build the project at `root`. Compiles every `src/**\/*.{ts,tsx}` (except
|
|
31
|
+
* `.d.ts`) and writes outputs to `outDir`. Stops emitting a module on type
|
|
32
|
+
* errors but collects diagnostics from all modules so the report is complete.
|
|
33
|
+
*/
|
|
34
|
+
declare function buildProject(fs: FileSystem, options?: BuildOptions): BuildResult;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { BuildOptions, BuildResult, buildProject };
|
|
37
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","names":[],"sources":["../src/build.ts"],"mappings":";;;;AA6CA;AAAA,UAViB,YAAA;;EAEf,IAAA;EAe2B;EAb3B,MAAA;EAamB;EAXnB,SAAA;AAAA;;UAIe,WAAA;EACf,EAAA;EAMA;EAJA,QAAA;EAI2B;EAF3B,WAAA,EAAa,UAAA;EAIJ;EAFT,MAAA,GAAS,UAAA,QAAkB,kBAAA;EAEmB;EAA9C,KAAA;IAAS,cAAA;IAAwB,aAAA;EAAA;AAAA;;;;;;iBAWnB,YAAA,CAAa,EAAA,EAAI,UAAA,EAAY,OAAA,GAAS,YAAA,GAAoB,WAAA"}
|
package/dist/build.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { buildRouteManifest, compile, typecheck } from "@mindees/compiler";
|
|
2
|
+
//#region src/build.ts
|
|
3
|
+
/**
|
|
4
|
+
* `buildProject` โ compile a project's sources with the Mindees Compiler.
|
|
5
|
+
*
|
|
6
|
+
* Walks `src/**` via an injected {@link FileSystem}, runs each TS/TSX module
|
|
7
|
+
* through `@mindees/compiler`'s `typecheck` gate and then `compile` (emit),
|
|
8
|
+
* writes the JS (and source map) to `dist/`, and โ if a `src/routes/` dir
|
|
9
|
+
* exists โ emits a per-route manifest. Returns structured results so the CLI can
|
|
10
|
+
* report diagnostics and fail the build on type errors.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Diagnostic codes that are artifacts of type-checking a module **in isolation**
|
|
16
|
+
* (without the project's dependency graph or ambient JSX types), not real app
|
|
17
|
+
* errors. If any ever reaches the build it is **downgraded to a warning** rather
|
|
18
|
+
* than failing the build:
|
|
19
|
+
*
|
|
20
|
+
* - `TS2307` โ "Cannot find module 'โฆ'": imports aren't resolved in single-module mode.
|
|
21
|
+
* - `TS7026` โ "no interface 'JSX.IntrinsicElements'": the framework's JSX env
|
|
22
|
+
* types aren't loaded in isolation.
|
|
23
|
+
*
|
|
24
|
+
* In practice the compiler's single-module gate already **filters** these upstream
|
|
25
|
+
* (it drops unresolved-import codes and injects ambient JSX types), so they
|
|
26
|
+
* normally don't appear here at all โ this set is a defensive backstop in case a
|
|
27
|
+
* future gate surfaces them. Genuine type errors (e.g. `TS2322` not-assignable)
|
|
28
|
+
* are untouched and still fail the build. A full project-graph type-check is
|
|
29
|
+
* future work (see ROADMAP).
|
|
30
|
+
*/
|
|
31
|
+
const ISOLATION_NOISE = new Set(["TS2307", "TS7026"]);
|
|
32
|
+
const COMPILABLE = /\.(tsx|ts)$/;
|
|
33
|
+
const DECLARATION = /\.d\.ts$/;
|
|
34
|
+
/**
|
|
35
|
+
* Build the project at `root`. Compiles every `src/**\/*.{ts,tsx}` (except
|
|
36
|
+
* `.d.ts`) and writes outputs to `outDir`. Stops emitting a module on type
|
|
37
|
+
* errors but collects diagnostics from all modules so the report is complete.
|
|
38
|
+
*/
|
|
39
|
+
function buildProject(fs, options = {}) {
|
|
40
|
+
const { root = ".", outDir = "dist", sourceMap = true } = options;
|
|
41
|
+
const srcDir = root === "." ? "src" : `${root}/src`;
|
|
42
|
+
const diagnostics = [];
|
|
43
|
+
const compiled = [];
|
|
44
|
+
const stats = {
|
|
45
|
+
flattenedNodes: 0,
|
|
46
|
+
totalElements: 0
|
|
47
|
+
};
|
|
48
|
+
const entries = fs.exists(srcDir) ? fs.readDir(srcDir) : [];
|
|
49
|
+
for (const rel of entries) {
|
|
50
|
+
if (!COMPILABLE.test(rel) || DECLARATION.test(rel)) continue;
|
|
51
|
+
const srcPath = `${srcDir}/${rel}`;
|
|
52
|
+
const source = fs.readFile(srcPath);
|
|
53
|
+
const moduleDiags = typecheck(source, rel).map((d) => d.severity === "error" && ISOLATION_NOISE.has(d.code) ? {
|
|
54
|
+
...d,
|
|
55
|
+
severity: "warning"
|
|
56
|
+
} : d);
|
|
57
|
+
diagnostics.push(...moduleDiags);
|
|
58
|
+
if (!moduleDiags.some((d) => d.severity === "error")) {
|
|
59
|
+
const emitted = compile(source, {
|
|
60
|
+
fileName: rel,
|
|
61
|
+
sourceMap
|
|
62
|
+
});
|
|
63
|
+
stats.flattenedNodes += emitted.stats.flattenedNodes;
|
|
64
|
+
stats.totalElements += emitted.stats.totalElements;
|
|
65
|
+
const outPath = `${outDir}/${rel.replace(COMPILABLE, ".js")}`;
|
|
66
|
+
fs.writeFile(outPath, emitted.code);
|
|
67
|
+
if (emitted.map) fs.writeFile(`${outPath}.map`, emitted.map);
|
|
68
|
+
compiled.push(rel);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
let routes;
|
|
72
|
+
const routesDir = `${srcDir}/routes`;
|
|
73
|
+
if (fs.exists(routesDir)) try {
|
|
74
|
+
routes = buildRouteManifest(fs.readDir(routesDir));
|
|
75
|
+
fs.writeFile(`${outDir}/routes.manifest.json`, `${JSON.stringify(routes, null, 2)}\n`);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
diagnostics.push({
|
|
78
|
+
severity: "error",
|
|
79
|
+
code: "MDC_ROUTES",
|
|
80
|
+
message: e instanceof Error ? e.message : String(e),
|
|
81
|
+
file: routesDir
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
compiled.sort();
|
|
85
|
+
const result = {
|
|
86
|
+
ok: !diagnostics.some((d) => d.severity === "error"),
|
|
87
|
+
compiled,
|
|
88
|
+
diagnostics,
|
|
89
|
+
stats
|
|
90
|
+
};
|
|
91
|
+
if (routes) result.routes = routes;
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { buildProject };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","names":[],"sources":["../src/build.ts"],"sourcesContent":["/**\n * `buildProject` โ compile a project's sources with the Mindees Compiler.\n *\n * Walks `src/**` via an injected {@link FileSystem}, runs each TS/TSX module\n * through `@mindees/compiler`'s `typecheck` gate and then `compile` (emit),\n * writes the JS (and source map) to `dist/`, and โ if a `src/routes/` dir\n * exists โ emits a per-route manifest. Returns structured results so the CLI can\n * report diagnostics and fail the build on type errors.\n *\n * @module\n */\n\nimport { buildRouteManifest, compile, type Diagnostic, typecheck } from '@mindees/compiler'\nimport type { FileSystem } from './fs'\n\n/**\n * Diagnostic codes that are artifacts of type-checking a module **in isolation**\n * (without the project's dependency graph or ambient JSX types), not real app\n * errors. If any ever reaches the build it is **downgraded to a warning** rather\n * than failing the build:\n *\n * - `TS2307` โ \"Cannot find module 'โฆ'\": imports aren't resolved in single-module mode.\n * - `TS7026` โ \"no interface 'JSX.IntrinsicElements'\": the framework's JSX env\n * types aren't loaded in isolation.\n *\n * In practice the compiler's single-module gate already **filters** these upstream\n * (it drops unresolved-import codes and injects ambient JSX types), so they\n * normally don't appear here at all โ this set is a defensive backstop in case a\n * future gate surfaces them. Genuine type errors (e.g. `TS2322` not-assignable)\n * are untouched and still fail the build. A full project-graph type-check is\n * future work (see ROADMAP).\n */\nconst ISOLATION_NOISE = new Set(['TS2307', 'TS7026'])\n\n/** Options for {@link buildProject}. */\nexport interface BuildOptions {\n /** Project root (contains `src/`). Default `\".\"`. */\n root?: string\n /** Output directory. Default `\"dist\"`. */\n outDir?: string\n /** Emit source maps. Default `true`. */\n sourceMap?: boolean\n}\n\n/** Result of a project build. */\nexport interface BuildResult {\n ok: boolean\n /** Source files compiled (relative paths), sorted. */\n compiled: string[]\n /** All diagnostics across modules (errors fail the build). */\n diagnostics: Diagnostic[]\n /** Route manifest, if `src/routes/` existed. */\n routes?: ReturnType<typeof buildRouteManifest>\n /** Optimizer totals across all modules. */\n stats: { flattenedNodes: number; totalElements: number }\n}\n\nconst COMPILABLE = /\\.(tsx|ts)$/\nconst DECLARATION = /\\.d\\.ts$/\n\n/**\n * Build the project at `root`. Compiles every `src/**\\/*.{ts,tsx}` (except\n * `.d.ts`) and writes outputs to `outDir`. Stops emitting a module on type\n * errors but collects diagnostics from all modules so the report is complete.\n */\nexport function buildProject(fs: FileSystem, options: BuildOptions = {}): BuildResult {\n const { root = '.', outDir = 'dist', sourceMap = true } = options\n const srcDir = root === '.' ? 'src' : `${root}/src`\n\n const diagnostics: Diagnostic[] = []\n const compiled: string[] = []\n const stats = { flattenedNodes: 0, totalElements: 0 }\n\n const entries = fs.exists(srcDir) ? fs.readDir(srcDir) : []\n for (const rel of entries) {\n if (!COMPILABLE.test(rel) || DECLARATION.test(rel)) continue\n const srcPath = `${srcDir}/${rel}`\n const source = fs.readFile(srcPath)\n\n // Type-check for diagnostics, but downgrade isolation-only noise to warnings\n // so a normal app (with cross-module imports + JSX) still builds. Genuine\n // type errors remain errors and fail the build below.\n const moduleDiags = typecheck(source, rel).map((d) =>\n d.severity === 'error' && ISOLATION_NOISE.has(d.code)\n ? { ...d, severity: 'warning' as const }\n : d,\n )\n diagnostics.push(...moduleDiags)\n\n // Emit only if this module has no real (post-downgrade) error.\n const moduleHasError = moduleDiags.some((d) => d.severity === 'error')\n if (!moduleHasError) {\n const emitted = compile(source, { fileName: rel, sourceMap })\n stats.flattenedNodes += emitted.stats.flattenedNodes\n stats.totalElements += emitted.stats.totalElements\n const outPath = `${outDir}/${rel.replace(COMPILABLE, '.js')}`\n fs.writeFile(outPath, emitted.code)\n if (emitted.map) fs.writeFile(`${outPath}.map`, emitted.map)\n compiled.push(rel)\n }\n }\n\n // Per-route manifest, if a routes dir is present. buildRouteManifest THROWS on\n // a malformed routes dir (duplicate route path, or a non-terminal catch-all) โ\n // ordinary user misconfigurations that `mindees build` exists to report. Turn\n // them into a build diagnostic + failing result so the CLI prints a clean error\n // and exits non-zero, honoring runCli's \"never throws for expected failures\"\n // contract instead of crashing with a raw stack trace.\n let routes: BuildResult['routes']\n const routesDir = `${srcDir}/routes`\n if (fs.exists(routesDir)) {\n try {\n routes = buildRouteManifest(fs.readDir(routesDir))\n fs.writeFile(`${outDir}/routes.manifest.json`, `${JSON.stringify(routes, null, 2)}\\n`)\n } catch (e) {\n diagnostics.push({\n severity: 'error',\n code: 'MDC_ROUTES',\n message: e instanceof Error ? e.message : String(e),\n file: routesDir,\n })\n }\n }\n\n compiled.sort()\n const ok = !diagnostics.some((d) => d.severity === 'error')\n const result: BuildResult = { ok, compiled, diagnostics, stats }\n if (routes) result.routes = routes\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,kBAAkB,IAAI,IAAI,CAAC,UAAU,QAAQ,CAAC;AAyBpD,MAAM,aAAa;AACnB,MAAM,cAAc;;;;;;AAOpB,SAAgB,aAAa,IAAgB,UAAwB,CAAC,GAAgB;CACpF,MAAM,EAAE,OAAO,KAAK,SAAS,QAAQ,YAAY,SAAS;CAC1D,MAAM,SAAS,SAAS,MAAM,QAAQ,GAAG,KAAK;CAE9C,MAAM,cAA4B,CAAC;CACnC,MAAM,WAAqB,CAAC;CAC5B,MAAM,QAAQ;EAAE,gBAAgB;EAAG,eAAe;CAAE;CAEpD,MAAM,UAAU,GAAG,OAAO,MAAM,IAAI,GAAG,QAAQ,MAAM,IAAI,CAAC;CAC1D,KAAK,MAAM,OAAO,SAAS;EACzB,IAAI,CAAC,WAAW,KAAK,GAAG,KAAK,YAAY,KAAK,GAAG,GAAG;EACpD,MAAM,UAAU,GAAG,OAAO,GAAG;EAC7B,MAAM,SAAS,GAAG,SAAS,OAAO;EAKlC,MAAM,cAAc,UAAU,QAAQ,GAAG,EAAE,KAAK,MAC9C,EAAE,aAAa,WAAW,gBAAgB,IAAI,EAAE,IAAI,IAChD;GAAE,GAAG;GAAG,UAAU;EAAmB,IACrC,CACN;EACA,YAAY,KAAK,GAAG,WAAW;EAI/B,IAAI,CADmB,YAAY,MAAM,MAAM,EAAE,aAAa,OAC5C,GAAG;GACnB,MAAM,UAAU,QAAQ,QAAQ;IAAE,UAAU;IAAK;GAAU,CAAC;GAC5D,MAAM,kBAAkB,QAAQ,MAAM;GACtC,MAAM,iBAAiB,QAAQ,MAAM;GACrC,MAAM,UAAU,GAAG,OAAO,GAAG,IAAI,QAAQ,YAAY,KAAK;GAC1D,GAAG,UAAU,SAAS,QAAQ,IAAI;GAClC,IAAI,QAAQ,KAAK,GAAG,UAAU,GAAG,QAAQ,OAAO,QAAQ,GAAG;GAC3D,SAAS,KAAK,GAAG;EACnB;CACF;CAQA,IAAI;CACJ,MAAM,YAAY,GAAG,OAAO;CAC5B,IAAI,GAAG,OAAO,SAAS,GACrB,IAAI;EACF,SAAS,mBAAmB,GAAG,QAAQ,SAAS,CAAC;EACjD,GAAG,UAAU,GAAG,OAAO,wBAAwB,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,GAAG;CACvF,SAAS,GAAG;EACV,YAAY,KAAK;GACf,UAAU;GACV,MAAM;GACN,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;GAClD,MAAM;EACR,CAAC;CACH;CAGF,SAAS,KAAK;CAEd,MAAM,SAAsB;EAAE,IAAA,CADlB,YAAY,MAAM,MAAM,EAAE,aAAa,OAAO;EACxB;EAAU;EAAa;CAAM;CAC/D,IAAI,QAAQ,OAAO,SAAS;CAC5B,OAAO;AACT"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CommandResult, EnvProbe, Writer } from "./types.js";
|
|
2
|
+
import { FileSystem } from "./fs.js";
|
|
3
|
+
import { AiBackend } from "@mindees/ai";
|
|
4
|
+
|
|
5
|
+
//#region src/cli.d.ts
|
|
6
|
+
/** Everything the CLI needs from the outside world (injected for testability). */
|
|
7
|
+
interface CliContext {
|
|
8
|
+
fs: FileSystem;
|
|
9
|
+
env: EnvProbe;
|
|
10
|
+
/** Working directory (where `create` writes, what `build` reads). */
|
|
11
|
+
cwd: string;
|
|
12
|
+
/** CLI version string (from package metadata). */
|
|
13
|
+
version: string;
|
|
14
|
+
/** Output sink. */
|
|
15
|
+
write: Writer;
|
|
16
|
+
/** AI backend for `ai` commands (wired from `MINDEES_AI_*` env in `bin`). */
|
|
17
|
+
aiBackend?: AiBackend;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Run the CLI. Returns a {@link CommandResult} with the process exit code.
|
|
21
|
+
* Never throws for expected failures โ it reports them and returns non-zero.
|
|
22
|
+
*/
|
|
23
|
+
declare function runCli(argv: readonly string[], ctx: CliContext): CommandResult;
|
|
24
|
+
/**
|
|
25
|
+
* The async CLI entry. Handles the model-calling `ai` command (which is asynchronous) and
|
|
26
|
+
* delegates every synchronous command to {@link runCli}. The `bin` calls this; tests can call
|
|
27
|
+
* either (sync commands stay testable through `runCli`).
|
|
28
|
+
*/
|
|
29
|
+
declare function runCliAsync(argv: readonly string[], ctx: CliContext): Promise<CommandResult>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { CliContext, runCli, runCliAsync };
|
|
32
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","names":[],"sources":["../src/cli.ts"],"mappings":";;;;;;UAwBiB,UAAA;EACf,EAAA,EAAI,UAAA;EACJ,GAAA,EAAK,QAAA;EAAA;EAEL,GAAA;EAEA;EAAA,OAAA;EAEO;EAAP,KAAA,EAAO,MAAA;EAEK;EAAZ,SAAA,GAAY,SAAA;AAAA;AAqCd;;;;AAAA,iBAAgB,MAAA,CAAO,IAAA,qBAAyB,GAAA,EAAK,UAAA,GAAa,aAAa;;;;;AAAA;iBAmC/D,WAAA,CAAY,IAAA,qBAAyB,GAAA,EAAK,UAAA,GAAa,OAAA,CAAQ,aAAA"}
|