@assemora/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 +202 -0
- package/README.md +272 -0
- package/bin.mjs +31 -0
- package/dist/args.d.ts +35 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +104 -0
- package/dist/args.js.map +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +11 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/agents.d.ts +50 -0
- package/dist/commands/agents.d.ts.map +1 -0
- package/dist/commands/agents.js +169 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/artifacts.d.ts +5 -0
- package/dist/commands/artifacts.d.ts.map +1 -0
- package/dist/commands/artifacts.js +126 -0
- package/dist/commands/artifacts.js.map +1 -0
- package/dist/commands/console.d.ts +25 -0
- package/dist/commands/console.d.ts.map +1 -0
- package/dist/commands/console.js +99 -0
- package/dist/commands/console.js.map +1 -0
- package/dist/commands/db.d.ts +48 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +585 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/index.d.ts +21 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +21 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/inspect.d.ts +8 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +280 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/make.d.ts +29 -0
- package/dist/commands/make.d.ts.map +1 -0
- package/dist/commands/make.js +393 -0
- package/dist/commands/make.js.map +1 -0
- package/dist/commands/mcp.d.ts +19 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +116 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/new.d.ts +20 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +83 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/run.d.ts +20 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +355 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/watchdog.d.ts +2 -0
- package/dist/commands/watchdog.d.ts.map +1 -0
- package/dist/commands/watchdog.js +74 -0
- package/dist/commands/watchdog.js.map +1 -0
- package/dist/config.d.ts +89 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +156 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +96 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +181 -0
- package/dist/output.js.map +1 -0
- package/dist/project.d.ts +44 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +102 -0
- package/dist/project.js.map +1 -0
- package/dist/registry.d.ts +48 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +74 -0
- package/dist/registry.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project's own application, booted once (ADR-0021).
|
|
3
|
+
*
|
|
4
|
+
* The CLI never constructs an application — it cannot, because it does not depend on
|
|
5
|
+
* a single feature package. It asks the config for one and boots it, and everything
|
|
6
|
+
* that needs an application comes through here so that `assemora console`, which
|
|
7
|
+
* asks many times, opens one database pool rather than one per question.
|
|
8
|
+
*
|
|
9
|
+
* Booting is the honest cost of describing the real application instead of parsing
|
|
10
|
+
* its source, which is the trade ADR-0021 accepted.
|
|
11
|
+
*/
|
|
12
|
+
import { type Application } from '@assemora/core';
|
|
13
|
+
import type { LoadedConfig } from './config.js';
|
|
14
|
+
/**
|
|
15
|
+
* An endpoint a client can speak to over something that is not HTTP.
|
|
16
|
+
*
|
|
17
|
+
* Declared structurally and nowhere else. `assemora mcp` drives it and the CLI still
|
|
18
|
+
* imports no feature package — it is handed the thing by the project's own config, the
|
|
19
|
+
* way it is handed the application (ADR-0021).
|
|
20
|
+
*/
|
|
21
|
+
export type McpEndpoint = {
|
|
22
|
+
handle(message: unknown, credential: {
|
|
23
|
+
readonly token: string;
|
|
24
|
+
}): Promise<unknown>;
|
|
25
|
+
};
|
|
26
|
+
/** What a config's `app()` turns out to have handed back. */
|
|
27
|
+
export type LoadedProject = {
|
|
28
|
+
readonly application: Application;
|
|
29
|
+
/** Present when the project assembled itself with `assemora()` and asked for MCP. */
|
|
30
|
+
readonly mcp: McpEndpoint | undefined;
|
|
31
|
+
};
|
|
32
|
+
/** Everything this config describes. The same one, however often it is asked for. */
|
|
33
|
+
export declare const loadProject: (loaded: LoadedConfig) => Promise<LoadedProject>;
|
|
34
|
+
/** The application this config describes. */
|
|
35
|
+
export declare const loadApplication: (loaded: LoadedConfig) => Promise<Application>;
|
|
36
|
+
/**
|
|
37
|
+
* Closes everything this process booted, newest first.
|
|
38
|
+
*
|
|
39
|
+
* `run()` calls it when a command returns, so a database pool never outlives the
|
|
40
|
+
* invocation that opened it. It is safe to call again — an application already
|
|
41
|
+
* stopped ignores a second `shutdown()`.
|
|
42
|
+
*/
|
|
43
|
+
export declare const shutdown: () => Promise<void>;
|
|
44
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,KAAK,WAAW,EAAsB,MAAM,gBAAgB,CAAA;AAErE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AA2B/C;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACnF,CAAA;AAED,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,qFAAqF;IACrF,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,SAAS,CAAA;CACtC,CAAA;AAkDD,qFAAqF;AACrF,eAAO,MAAM,WAAW,WAAY,YAAY,KAAG,OAAO,CAAC,aAAa,CAcvE,CAAA;AAED,6CAA6C;AAC7C,eAAO,MAAM,eAAe,WAAkB,YAAY,KAAG,OAAO,CAAC,WAAW,CACvC,CAAA;AAEzC;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,QAAa,OAAO,CAAC,IAAI,CAU7C,CAAA"}
|
package/dist/project.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project's own application, booted once (ADR-0021).
|
|
3
|
+
*
|
|
4
|
+
* The CLI never constructs an application — it cannot, because it does not depend on
|
|
5
|
+
* a single feature package. It asks the config for one and boots it, and everything
|
|
6
|
+
* that needs an application comes through here so that `assemora console`, which
|
|
7
|
+
* asks many times, opens one database pool rather than one per question.
|
|
8
|
+
*
|
|
9
|
+
* Booting is the honest cost of describing the real application instead of parsing
|
|
10
|
+
* its source, which is the trade ADR-0021 accepted.
|
|
11
|
+
*/
|
|
12
|
+
import { ConfigurationError } from '@assemora/core';
|
|
13
|
+
/**
|
|
14
|
+
* Keyed by config file rather than held as a single value.
|
|
15
|
+
*
|
|
16
|
+
* One process only ever runs one project, so the key is never observable to a user.
|
|
17
|
+
* It is observable to a test that drives two projects in a row, and the alternative
|
|
18
|
+
* there is the first project's application answering the second project's question.
|
|
19
|
+
*/
|
|
20
|
+
const booted = new Map();
|
|
21
|
+
const looksLikeApplication = (value) => {
|
|
22
|
+
if (typeof value !== 'object' || value === null)
|
|
23
|
+
return false;
|
|
24
|
+
const candidate = value;
|
|
25
|
+
return (typeof candidate.boot === 'function' &&
|
|
26
|
+
typeof candidate.shutdown === 'function' &&
|
|
27
|
+
typeof candidate.registry === 'object' &&
|
|
28
|
+
typeof candidate.commands === 'object' &&
|
|
29
|
+
typeof candidate.queries === 'object');
|
|
30
|
+
};
|
|
31
|
+
const looksLikeMcp = (value) => typeof value === 'object' &&
|
|
32
|
+
value !== null &&
|
|
33
|
+
typeof value.handle === 'function';
|
|
34
|
+
/**
|
|
35
|
+
* What `app()` returned, whichever of the two shapes it is.
|
|
36
|
+
*
|
|
37
|
+
* A config may hand back the application itself, or the thing `assemora()` built around
|
|
38
|
+
* one. The second is worth accepting: `app: () => createApp().app` is the line every
|
|
39
|
+
* starter carries, and the `.app` on the end is a wart — it throws away the half that
|
|
40
|
+
* knows about MCP, the server and the frontend, and it is easy to write and impossible
|
|
41
|
+
* to notice missing.
|
|
42
|
+
*/
|
|
43
|
+
const carrierOf = (created) => {
|
|
44
|
+
if (looksLikeApplication(created))
|
|
45
|
+
return { application: created, mcp: undefined };
|
|
46
|
+
if (typeof created !== 'object' || created === null)
|
|
47
|
+
return undefined;
|
|
48
|
+
const carrier = created;
|
|
49
|
+
if (!looksLikeApplication(carrier.app))
|
|
50
|
+
return undefined;
|
|
51
|
+
return {
|
|
52
|
+
application: carrier.app,
|
|
53
|
+
mcp: looksLikeMcp(carrier.mcp) ? carrier.mcp : undefined,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const bootOnce = async (loaded) => {
|
|
57
|
+
const project = carrierOf(await loaded.config.app());
|
|
58
|
+
if (project === undefined) {
|
|
59
|
+
throw new ConfigurationError(`${loaded.file}: "app" did not return an Assemora application. It must return what ` +
|
|
60
|
+
'createApplication() or assemora() produced, un-booted — not a server and not a ' +
|
|
61
|
+
'promise of nothing.');
|
|
62
|
+
}
|
|
63
|
+
// `boot()` refuses an application that is already running, and its message says so:
|
|
64
|
+
// an `app()` that boots on the developer's behalf is a mistake worth hearing about
|
|
65
|
+
// rather than one to paper over here.
|
|
66
|
+
await project.application.boot();
|
|
67
|
+
return project;
|
|
68
|
+
};
|
|
69
|
+
/** Everything this config describes. The same one, however often it is asked for. */
|
|
70
|
+
export const loadProject = (loaded) => {
|
|
71
|
+
const existing = booted.get(loaded.file);
|
|
72
|
+
if (existing !== undefined)
|
|
73
|
+
return existing;
|
|
74
|
+
const pending = bootOnce(loaded);
|
|
75
|
+
booted.set(loaded.file, pending);
|
|
76
|
+
// A boot that failed is not worth remembering — and attaching this handler is also
|
|
77
|
+
// what stops the rejection being reported as unhandled when nobody awaits it twice.
|
|
78
|
+
pending.catch(() => {
|
|
79
|
+
booted.delete(loaded.file);
|
|
80
|
+
});
|
|
81
|
+
return pending;
|
|
82
|
+
};
|
|
83
|
+
/** The application this config describes. */
|
|
84
|
+
export const loadApplication = async (loaded) => (await loadProject(loaded)).application;
|
|
85
|
+
/**
|
|
86
|
+
* Closes everything this process booted, newest first.
|
|
87
|
+
*
|
|
88
|
+
* `run()` calls it when a command returns, so a database pool never outlives the
|
|
89
|
+
* invocation that opened it. It is safe to call again — an application already
|
|
90
|
+
* stopped ignores a second `shutdown()`.
|
|
91
|
+
*/
|
|
92
|
+
export const shutdown = async () => {
|
|
93
|
+
const pending = [...booted.values()].reverse();
|
|
94
|
+
booted.clear();
|
|
95
|
+
for (const entry of pending) {
|
|
96
|
+
// An application that never finished booting has nothing to close, and its
|
|
97
|
+
// failure was already delivered to whoever asked for it.
|
|
98
|
+
const project = await entry.catch(() => undefined);
|
|
99
|
+
await project?.application.shutdown();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ParsedArgs } from './args.js';
|
|
2
|
+
/**
|
|
3
|
+
* `0` succeeded, `1` the command failed, `2` the invocation was wrong.
|
|
4
|
+
*
|
|
5
|
+
* The distinction matters to a script: `2` says the arguments were nonsense and
|
|
6
|
+
* retrying will not help, while `1` says the work was attempted and did not finish.
|
|
7
|
+
*/
|
|
8
|
+
export type CommandHandler = (input: {
|
|
9
|
+
readonly args: ParsedArgs;
|
|
10
|
+
readonly cwd: string;
|
|
11
|
+
}) => Promise<number>;
|
|
12
|
+
/** The groups of SPEC.md §77, in the order it lists them. */
|
|
13
|
+
export type CommandGroup = 'project' | 'run' | 'identity' | 'make' | 'database' | 'inspect' | 'artifacts' | 'console';
|
|
14
|
+
export type CliCommand = {
|
|
15
|
+
/** What is typed: `make:model`, `db:migrate`, `api:openapi`. */
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly group: CommandGroup;
|
|
18
|
+
/** One line, lower case, no full stop — it is printed in a column. */
|
|
19
|
+
readonly summary: string;
|
|
20
|
+
/** The whole invocation, starting with `assemora`. */
|
|
21
|
+
readonly usage: string;
|
|
22
|
+
readonly handler: CommandHandler;
|
|
23
|
+
};
|
|
24
|
+
/** Identity plus types, like `defineConfig` — the check happens where it is written. */
|
|
25
|
+
export declare const defineCommand: (command: CliCommand) => CliCommand;
|
|
26
|
+
export declare const COMMAND_GROUPS: readonly CommandGroup[];
|
|
27
|
+
/**
|
|
28
|
+
* Adds commands to the table.
|
|
29
|
+
*
|
|
30
|
+
* Order inside a group is the order they are registered in, which is the order
|
|
31
|
+
* SPEC.md §77 lists them — `dev, build, start`, not `build, dev, start`. Registering
|
|
32
|
+
* a name twice is a mistake in the CLI itself, so it throws where it happens rather
|
|
33
|
+
* than letting whichever module loaded last decide what `db:migrate` means.
|
|
34
|
+
*/
|
|
35
|
+
export declare const register: (...commands: readonly CliCommand[]) => void;
|
|
36
|
+
export declare const registeredCommands: () => readonly CliCommand[];
|
|
37
|
+
export declare const commandNamed: (name: string) => CliCommand | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* What `assemora` and `assemora --help` print.
|
|
40
|
+
*
|
|
41
|
+
* The list is grouped exactly as SPEC.md §77 groups it, because those groups are the
|
|
42
|
+
* four unrelated jobs the CLI does and reading it as one alphabetical run of
|
|
43
|
+
* twenty-two names tells nobody which is which.
|
|
44
|
+
*/
|
|
45
|
+
export declare const helpText: (commands?: readonly CliCommand[]) => string;
|
|
46
|
+
/** What `assemora <command> --help` prints. */
|
|
47
|
+
export declare const commandHelpText: (command: CliCommand) => string;
|
|
48
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;AAErB,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GACpB,SAAS,GACT,KAAK,GACL,UAAU,GACV,MAAM,GACN,UAAU,GACV,SAAS,GACT,WAAW,GACX,SAAS,CAAA;AAEb,MAAM,MAAM,UAAU,GAAG;IACvB,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAA;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;CACjC,CAAA;AAED,wFAAwF;AACxF,eAAO,MAAM,aAAa,YAAa,UAAU,KAAG,UAAqB,CAAA;AAazE,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EAAuC,CAAA;AAIzF;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,gBAAiB,SAAS,UAAU,EAAE,KAAG,IAQ7D,CAAA;AAED,eAAO,MAAM,kBAAkB,QAAO,SAAS,UAAU,EAAyB,CAAA;AAElF,eAAO,MAAM,YAAY,SAAU,MAAM,KAAG,UAAU,GAAG,SAA4B,CAAA;AAIrF;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,cAAc,SAAS,UAAU,EAAE,KAA0B,MAiCjF,CAAA;AAED,+CAA+C;AAC/C,eAAO,MAAM,eAAe,YAAa,UAAU,KAAG,MACW,CAAA"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command table (SPEC.md §77).
|
|
3
|
+
*
|
|
4
|
+
* Every command is a small function of `{ args, cwd }` returning an exit code, and
|
|
5
|
+
* that is the whole of what `run()` knows about it. The groups register themselves
|
|
6
|
+
* into the table below, so adding `assemora db:seed` is one `defineCommand` in the
|
|
7
|
+
* group that owns it and nothing anywhere else — including in the help, which is
|
|
8
|
+
* printed from the table rather than written out beside it.
|
|
9
|
+
*/
|
|
10
|
+
import { ConfigurationError } from '@assemora/core';
|
|
11
|
+
/** Identity plus types, like `defineConfig` — the check happens where it is written. */
|
|
12
|
+
export const defineCommand = (command) => command;
|
|
13
|
+
const GROUPS = [
|
|
14
|
+
{ group: 'project', title: 'Project' },
|
|
15
|
+
{ group: 'run', title: 'Run' },
|
|
16
|
+
{ group: 'identity', title: 'Identity' },
|
|
17
|
+
{ group: 'make', title: 'Generate' },
|
|
18
|
+
{ group: 'database', title: 'Database' },
|
|
19
|
+
{ group: 'inspect', title: 'Inspect' },
|
|
20
|
+
{ group: 'artifacts', title: 'Artifacts' },
|
|
21
|
+
{ group: 'console', title: 'Console' },
|
|
22
|
+
];
|
|
23
|
+
export const COMMAND_GROUPS = GROUPS.map((entry) => entry.group);
|
|
24
|
+
const table = new Map();
|
|
25
|
+
/**
|
|
26
|
+
* Adds commands to the table.
|
|
27
|
+
*
|
|
28
|
+
* Order inside a group is the order they are registered in, which is the order
|
|
29
|
+
* SPEC.md §77 lists them — `dev, build, start`, not `build, dev, start`. Registering
|
|
30
|
+
* a name twice is a mistake in the CLI itself, so it throws where it happens rather
|
|
31
|
+
* than letting whichever module loaded last decide what `db:migrate` means.
|
|
32
|
+
*/
|
|
33
|
+
export const register = (...commands) => {
|
|
34
|
+
for (const command of commands) {
|
|
35
|
+
if (table.has(command.name)) {
|
|
36
|
+
throw new ConfigurationError(`CLI command "${command.name}" is registered twice`);
|
|
37
|
+
}
|
|
38
|
+
table.set(command.name, command);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export const registeredCommands = () => [...table.values()];
|
|
42
|
+
export const commandNamed = (name) => table.get(name);
|
|
43
|
+
const pad = (text, width) => text.padEnd(width);
|
|
44
|
+
/**
|
|
45
|
+
* What `assemora` and `assemora --help` print.
|
|
46
|
+
*
|
|
47
|
+
* The list is grouped exactly as SPEC.md §77 groups it, because those groups are the
|
|
48
|
+
* four unrelated jobs the CLI does and reading it as one alphabetical run of
|
|
49
|
+
* twenty-two names tells nobody which is which.
|
|
50
|
+
*/
|
|
51
|
+
export const helpText = (commands = registeredCommands()) => {
|
|
52
|
+
const names = commands.map((command) => command.name.length);
|
|
53
|
+
const width = Math.max(...names, '-h, --help'.length) + 2;
|
|
54
|
+
const lines = [
|
|
55
|
+
'assemora — the command line for an Assemora project',
|
|
56
|
+
'',
|
|
57
|
+
'Usage',
|
|
58
|
+
' assemora <command> [options]',
|
|
59
|
+
];
|
|
60
|
+
for (const { group, title } of GROUPS) {
|
|
61
|
+
const members = commands.filter((command) => command.group === group);
|
|
62
|
+
if (members.length === 0)
|
|
63
|
+
continue;
|
|
64
|
+
lines.push('', title);
|
|
65
|
+
for (const command of members) {
|
|
66
|
+
lines.push(` ${pad(command.name, width)}${command.summary}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
lines.push('', 'Options', ` ${pad('-h, --help', width)}this help, or one command's usage`, ` ${pad('--version', width)}the CLI version`, ` ${pad('--debug', width)}print stack traces when something fails`, '', 'Flags follow the command: `assemora make:model Post --force`.');
|
|
70
|
+
return lines.join('\n');
|
|
71
|
+
};
|
|
72
|
+
/** What `assemora <command> --help` prints. */
|
|
73
|
+
export const commandHelpText = (command) => ['Usage', ` ${command.usage}`, '', command.summary].join('\n');
|
|
74
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@assemora/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Assemora CLI: generators, migrations, introspection",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/assemora/assemora.git",
|
|
12
|
+
"directory": "packages/cli"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"bin": {
|
|
23
|
+
"assemora": "./bin.mjs"
|
|
24
|
+
},
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"bin.mjs",
|
|
28
|
+
"dist",
|
|
29
|
+
"!dist/.tsbuildinfo"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@assemora/core": "0.1.0",
|
|
33
|
+
"@assemora/openapi": "0.1.0",
|
|
34
|
+
"@assemora/database": "0.1.0",
|
|
35
|
+
"@assemora/schema": "0.1.0",
|
|
36
|
+
"@assemora/database-postgres": "0.1.0",
|
|
37
|
+
"@assemora/data": "0.1.0",
|
|
38
|
+
"@assemora/sdk": "0.1.0",
|
|
39
|
+
"create-assemora": "0.1.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "24.13.3"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc -b tsconfig.build.json",
|
|
46
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
47
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
48
|
+
}
|
|
49
|
+
}
|