acrylblends 0.7.8 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +13 -5
- package/dist/index.js +72 -13
- package/dist/index.js.map +1 -1
- package/docs/framework/README.md +2 -2
- package/docs/framework/UPSTREAM.md +1 -1
- package/docs/framework/getting-started/basic.md +1 -2
- package/docs/framework/getting-started/desktop.md +1 -1
- package/docs/framework/guides/bring-your-own-tool.md +216 -0
- package/docs/framework/guides/create-acrylblends.md +5 -4
- package/docs/framework/guides/data.md +2 -1
- package/docs/framework/upstream.json +3 -3
- package/lib/node-server.js +1 -0
- package/package.json +1 -1
- package/plugins/acryl-db/plugin.json +6 -1
- package/plugins/acryl-db/src/conformance.ts +224 -0
- package/plugins/acryl-db/upstream.json +1 -1
- package/plugins/acryl-db-sqlite/plugin.json +4 -1
- package/plugins/acryl-db-sqlite/upstream.json +1 -1
- package/plugins/acryl-door/LICENSE +47 -0
- package/plugins/acryl-door/plugin.json +14 -0
- package/plugins/acryl-door/src/cli/acryl.ts +207 -0
- package/plugins/acryl-door/src/host/api.ts +9 -0
- package/plugins/acryl-door/src/host/audit.ts +64 -0
- package/plugins/acryl-door/src/host/channel.ts +142 -0
- package/plugins/acryl-door/src/host/chat-tools.ts +39 -0
- package/plugins/acryl-door/src/host/door-file.ts +94 -0
- package/plugins/acryl-door/src/host/door.ts +195 -0
- package/plugins/acryl-door/src/host/http.ts +80 -0
- package/plugins/acryl-door/src/host/mcp-routes.ts +83 -0
- package/plugins/acryl-door/src/host/operator-routes.ts +38 -0
- package/plugins/acryl-door/src/host/page-routes.ts +65 -0
- package/plugins/acryl-door/src/host/shim.ts +65 -0
- package/plugins/acryl-door/src/host/verbs.ts +109 -0
- package/plugins/acryl-door/src/index.ts +133 -0
- package/plugins/acryl-door/src/page/api.ts +9 -0
- package/plugins/acryl-door/src/page/channel.ts +135 -0
- package/plugins/acryl-door/src/page/driver/accessibility.ts +163 -0
- package/plugins/acryl-door/src/page/driver/actions.ts +186 -0
- package/plugins/acryl-door/src/page/driver/driver.ts +153 -0
- package/plugins/acryl-door/src/page/driver/ref-table.ts +78 -0
- package/plugins/acryl-door/src/page/driver/sensitivity.ts +49 -0
- package/plugins/acryl-door/src/page/driver/snapshot.ts +132 -0
- package/plugins/acryl-door/src/page/index.ts +40 -0
- package/plugins/acryl-door/src/page/indicator.ts +72 -0
- package/plugins/acryl-door/src/page/main.ts +7 -0
- package/plugins/acryl-door/src/page/protocol.ts +213 -0
- package/plugins/acryl-door/src/page/snapshot-text.ts +18 -0
- package/plugins/acryl-door/src/page/user-input.ts +24 -0
- package/plugins/acryl-door/upstream.json +28 -0
- package/plugins/acryl-inspect/upstream.json +1 -1
- package/plugins/acryl-kv/plugin.json +6 -1
- package/plugins/acryl-kv/src/conformance.ts +226 -0
- package/plugins/acryl-kv/upstream.json +1 -1
- package/plugins/acryl-kv-db/plugin.json +4 -1
- package/plugins/acryl-kv-db/upstream.json +1 -1
- package/plugins/acryl-kv-json/plugin.json +4 -1
- package/plugins/acryl-kv-json/upstream.json +1 -1
- package/plugins/acryl-node-server/src/adapter/listener.ts +5 -0
- package/plugins/acryl-node-server/upstream.json +2 -2
- package/plugins/acryl-router/src/service.ts +3 -0
- package/plugins/acryl-router/upstream.json +2 -2
- package/plugins/acryl-router-http/upstream.json +1 -1
- package/plugins/acryl-state/upstream.json +1 -1
- package/plugins/agent-panel/client/main.ts +159 -0
- package/plugins/agent-panel/index.ts +232 -0
- package/plugins/agent-panel/plugin.json +21 -0
- package/plugins/desktop/upstream.json +1 -1
- package/plugins/desktop-web/upstream.json +1 -1
- package/plugins/extensions/resolve.ts +16 -2
- package/plugins/tsconfig.json +6 -0
- package/shared/DEFAULTS.md +11 -6
- package/shared/SKILL.md +1 -1
- package/templates/agent/blend.yaml +3 -0
- package/templates/agent/src/app.ts +18 -2
- package/templates/agent/src/routes.ts +14 -1
- package/templates/agent/template.json +2 -1
- package/templates/agent/test/agent.test.ts +10 -4
- package/templates/agent/test/app.test.ts +29 -8
- package/templates/agent/test/builder.test.ts +34 -23
- package/templates/agent/test/model.test.ts +24 -19
- package/templates/blank/src/app.ts +25 -5
- package/templates/blank/test/app.test.ts +28 -9
- package/templates/chat/AGENTS.md +16 -0
- package/templates/chat/blend.yaml +32 -0
- package/templates/chat/gitignore +6 -0
- package/templates/chat/migrations/001-chat.sql +12 -0
- package/templates/chat/package.json +33 -0
- package/templates/chat/src/app.ts +107 -0
- package/templates/chat/src/chat-app.ts +101 -0
- package/templates/chat/src/client/chat.tsx +115 -0
- package/templates/chat/src/client/tsconfig.json +26 -0
- package/templates/chat/src/db.ts +43 -0
- package/templates/chat/src/door.ts +7 -0
- package/templates/chat/src/llm.ts +42 -0
- package/templates/chat/src/main.ts +28 -0
- package/templates/chat/src/page.tsx +40 -0
- package/templates/chat/src/routes.ts +15 -0
- package/templates/chat/src/runtime.ts +17 -0
- package/templates/chat/template.json +12 -0
- package/templates/chat/test/chat.test.ts +198 -0
- package/templates/chat/test/server.test.ts +78 -0
- package/templates/chat/tsconfig.json +20 -0
- package/templates/nodejs/AGENTS.md +9 -0
- package/templates/nodejs/blend.yaml +29 -0
- package/templates/nodejs/gitignore +3 -0
- package/templates/nodejs/package.json +30 -0
- package/templates/nodejs/src/app.ts +95 -0
- package/templates/nodejs/src/client/counter.tsx +12 -0
- package/templates/nodejs/src/client/tsconfig.json +26 -0
- package/templates/nodejs/src/door.ts +7 -0
- package/templates/nodejs/src/main.ts +25 -0
- package/templates/nodejs/src/page.tsx +29 -0
- package/templates/nodejs/src/routes.ts +40 -0
- package/templates/nodejs/template.json +11 -0
- package/templates/nodejs/test/app.test.ts +78 -0
- package/templates/nodejs/test/server.test.ts +83 -0
- package/templates/nodejs/tsconfig.json +20 -0
- package/templates/notes/AGENTS.md +26 -0
- package/templates/notes/blend.yaml +32 -0
- package/templates/notes/gitignore +6 -0
- package/templates/notes/migrations/001-notes.sql +18 -0
- package/templates/notes/package.json +33 -0
- package/templates/notes/src/app.ts +107 -0
- package/templates/notes/src/auth.ts +57 -0
- package/templates/notes/src/client/counter.tsx +21 -0
- package/templates/notes/src/client/tsconfig.json +26 -0
- package/templates/notes/src/db.ts +50 -0
- package/templates/notes/src/door.ts +7 -0
- package/templates/notes/src/main.ts +28 -0
- package/templates/notes/src/notes-app.ts +205 -0
- package/templates/notes/src/routes.ts +14 -0
- package/templates/notes/src/runtime.ts +17 -0
- package/templates/notes/src/schema.ts +38 -0
- package/templates/notes/src/views.tsx +136 -0
- package/templates/notes/template.json +12 -0
- package/templates/notes/test/notes.test.ts +280 -0
- package/templates/notes/test/server.test.ts +78 -0
- package/templates/notes/tsconfig.json +20 -0
- package/templates/todo/src/app.ts +27 -7
- package/templates/todo/test/todo.test.ts +47 -22
- package/templates/todo/upstream.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -18,8 +18,10 @@ interface Io {
|
|
|
18
18
|
interface AddOptions {
|
|
19
19
|
readonly names: readonly string[];
|
|
20
20
|
readonly directory: string | undefined;
|
|
21
|
+
/** Also copy the port's conformance suite (`src/conformance.ts`) and the `vitest` it runs on: what a provider of your own must pass. */
|
|
22
|
+
readonly suite: boolean;
|
|
21
23
|
}
|
|
22
|
-
/** Parse `add <plugin...> [--dir <app>]`. */
|
|
24
|
+
/** Parse `add <plugin...> [--dir <app>] [--suite]`. */
|
|
23
25
|
export declare function parseAddOptions(argv: readonly string[]): AddOptions;
|
|
24
26
|
/**
|
|
25
27
|
* Copy library plugins into an existing app, with the plugins they require, and add their npm packages to its package.json.
|
|
@@ -29,9 +31,11 @@ export declare function add(options: AddOptions, io: Io): Promise<number>;
|
|
|
29
31
|
/** `acrylblends plugins`: the library, one line per plugin. */
|
|
30
32
|
export declare function listPlugins(io: Io): number;
|
|
31
33
|
//#endregion
|
|
32
|
-
//#region src/
|
|
34
|
+
//#region src/version.d.ts
|
|
33
35
|
/** The version of this package. */
|
|
34
36
|
export declare const VERSION: string;
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/cli.d.ts
|
|
35
39
|
export declare const HELP: string;
|
|
36
40
|
/**
|
|
37
41
|
* Run the CLI and return the exit code: 0 done, 1 failed or refused, 2 a usage error. Never calls `process.exit`.
|
|
@@ -39,8 +43,8 @@ export declare const HELP: string;
|
|
|
39
43
|
export declare function runCli(argv: readonly string[], io?: Io): Promise<number>;
|
|
40
44
|
//#endregion
|
|
41
45
|
//#region src/templates.d.ts
|
|
42
|
-
/** The templates: a
|
|
43
|
-
export declare const TEMPLATES: readonly ["blank", "todo", "agent"];
|
|
46
|
+
/** The templates, all Cordis apps: a web app with a page and a client component (nodejs), a notes app and a chat app on the db port (notes, chat), a blank app on the router, a todo list on the router and state, and the blank app with the offline agent. */
|
|
47
|
+
export declare const TEMPLATES: readonly ["nodejs", "notes", "chat", "blank", "todo", "agent"];
|
|
44
48
|
type Template = (typeof TEMPLATES)[number];
|
|
45
49
|
export declare function isTemplate(value: string): value is Template;
|
|
46
50
|
/**
|
|
@@ -86,6 +90,10 @@ interface LibraryPlugin {
|
|
|
86
90
|
readonly scripts?: Readonly<Record<string, string>>;
|
|
87
91
|
/** Lines the app's `.gitignore` needs for this plugin (added when missing, if the app has a `.gitignore`). */
|
|
88
92
|
readonly gitignore?: readonly string[];
|
|
93
|
+
/** The port's conformance suite, a path inside the plugin: shipped in the package, but copied into an app only by `acrylblends add <plugin> --suite` (it needs vitest). */
|
|
94
|
+
readonly suite?: string;
|
|
95
|
+
/** `package.json` "imports" entries the app gets (`#acryl-kv`): a path below the plugins folder. A plugin of your own imports the port by that name, in tests and the type-check as well as when installed live. */
|
|
96
|
+
readonly imports?: Readonly<Record<string, string>>;
|
|
89
97
|
/** How to mount it, shown after `acrylblends add`. */
|
|
90
98
|
readonly mount?: string;
|
|
91
99
|
/**
|
|
@@ -118,7 +126,7 @@ export declare function nameFrom(directory: string): string;
|
|
|
118
126
|
/** Refuse a target that exists and is not an empty directory. A missing target is fine: it is created. */
|
|
119
127
|
export declare function assertTargetFree(target: string): void;
|
|
120
128
|
/**
|
|
121
|
-
* Copy a template into `target`, replacing `__APP_NAME__` with `name
|
|
129
|
+
* Copy a template into `target`, replacing `__APP_NAME__` with `name` and `__ACRYLBLENDS_RANGE__` with the range of this release. Checks the target before writing anything.
|
|
122
130
|
*
|
|
123
131
|
* @returns the copied files, relative to `target`
|
|
124
132
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -116,7 +116,7 @@ function copyPlugin(plugin, appDir, root = libraryRoot()) {
|
|
|
116
116
|
recursive: true,
|
|
117
117
|
filter: (path) => {
|
|
118
118
|
const inside = path.slice(source.length + 1);
|
|
119
|
-
return !(dirname(path) === source && LIBRARY_ONLY.has(inside)) && !isOmitted(inside, plugin.omit);
|
|
119
|
+
return !(dirname(path) === source && LIBRARY_ONLY.has(inside)) && !isOmitted(inside, plugin.omit) && inside.split(sep).join("/") !== plugin.suite;
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
if (!folder.legacy) recordLibraryCopy(folder.dir, plugin.name);
|
|
@@ -124,6 +124,10 @@ function copyPlugin(plugin, appDir, root = libraryRoot()) {
|
|
|
124
124
|
}
|
|
125
125
|
const relativeName = (appDir, path) => path.slice(appDir.length + 1).split(sep).join("/");
|
|
126
126
|
//#endregion
|
|
127
|
+
//#region src/version.ts
|
|
128
|
+
/** The version of this package. */
|
|
129
|
+
const VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
130
|
+
//#endregion
|
|
127
131
|
//#region src/project.ts
|
|
128
132
|
/** Thrown when the target directory exists and is not empty. Nothing has been written. */
|
|
129
133
|
var TargetNotEmptyError = class extends Error {
|
|
@@ -148,7 +152,7 @@ function assertTargetFree(target) {
|
|
|
148
152
|
if (!statSync(target).isDirectory() || readdirSync(target).length > 0) throw new TargetNotEmptyError(target);
|
|
149
153
|
}
|
|
150
154
|
/**
|
|
151
|
-
* Copy a template into `target`, replacing `__APP_NAME__` with `name
|
|
155
|
+
* Copy a template into `target`, replacing `__APP_NAME__` with `name` and `__ACRYLBLENDS_RANGE__` with the range of this release. Checks the target before writing anything.
|
|
152
156
|
*
|
|
153
157
|
* @returns the copied files, relative to `target`
|
|
154
158
|
*/
|
|
@@ -168,7 +172,7 @@ function copyTemplate(source, target, name) {
|
|
|
168
172
|
continue;
|
|
169
173
|
}
|
|
170
174
|
const text = readFileSync(sourcePath, "utf8");
|
|
171
|
-
if (text.includes("__APP_NAME__")) writeFileSync(targetPath, text.replaceAll("__APP_NAME__", name));
|
|
175
|
+
if (text.includes("__APP_NAME__") || text.includes("__ACRYLBLENDS_RANGE__")) writeFileSync(targetPath, text.replaceAll("__APP_NAME__", name).replaceAll("__ACRYLBLENDS_RANGE__", `^${VERSION}`));
|
|
172
176
|
else cpSync(sourcePath, targetPath);
|
|
173
177
|
written.push(`${prefix}${targetName}`);
|
|
174
178
|
}
|
|
@@ -214,6 +218,19 @@ function mergeDependencies(appDir, dependencies) {
|
|
|
214
218
|
writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
215
219
|
return added;
|
|
216
220
|
}
|
|
221
|
+
/** Add `package.json` "imports" entries (`#acryl-kv`: `./plugins/acryl-kv/src/index.ts`); an entry the app already has is kept. Returns the names added. */
|
|
222
|
+
function mergeImports(appDir, imports, pluginsDir) {
|
|
223
|
+
const file = join(appDir, "package.json");
|
|
224
|
+
const manifest = JSON.parse(readFileSync(file, "utf8"));
|
|
225
|
+
const current = manifest.imports ?? {};
|
|
226
|
+
const added = Object.keys(imports).filter((name) => !(name in current));
|
|
227
|
+
manifest.imports = {
|
|
228
|
+
...Object.fromEntries(Object.entries(imports).map(([name, path]) => [name, `./${pluginsDir}/${path}`])),
|
|
229
|
+
...current
|
|
230
|
+
};
|
|
231
|
+
writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
232
|
+
return added;
|
|
233
|
+
}
|
|
217
234
|
/** Declare a file as an opener in package.json (`"acryl": { "opener": [...] }`): the one place that may import a database provider. */
|
|
218
235
|
function mergeOpener(appDir, opener) {
|
|
219
236
|
const file = join(appDir, "package.json");
|
|
@@ -306,8 +323,11 @@ function copyFrameworkDocs(source, target) {
|
|
|
306
323
|
}
|
|
307
324
|
//#endregion
|
|
308
325
|
//#region src/templates.ts
|
|
309
|
-
/** The templates: a
|
|
326
|
+
/** The templates, all Cordis apps: a web app with a page and a client component (nodejs), a notes app and a chat app on the db port (notes, chat), a blank app on the router, a todo list on the router and state, and the blank app with the offline agent. */
|
|
310
327
|
const TEMPLATES = [
|
|
328
|
+
"nodejs",
|
|
329
|
+
"notes",
|
|
330
|
+
"chat",
|
|
311
331
|
"blank",
|
|
312
332
|
"todo",
|
|
313
333
|
"agent"
|
|
@@ -427,6 +447,7 @@ async function init(options, io) {
|
|
|
427
447
|
const plugins = closure([...readTemplatePlugins(templateDir(template)), ...options.desktop ? ["desktop"] : []], readLibrary());
|
|
428
448
|
for (const plugin of plugins) {
|
|
429
449
|
copyPlugin(plugin, directory);
|
|
450
|
+
if (plugin.imports) mergeImports(directory, plugin.imports, "plugins");
|
|
430
451
|
mergeDependencies(directory, plugin.dependencies);
|
|
431
452
|
mergeTooling(directory, plugin);
|
|
432
453
|
}
|
|
@@ -447,7 +468,7 @@ async function init(options, io) {
|
|
|
447
468
|
}
|
|
448
469
|
//#endregion
|
|
449
470
|
//#region src/add.ts
|
|
450
|
-
/** Parse `add <plugin...> [--dir <app>]`. */
|
|
471
|
+
/** Parse `add <plugin...> [--dir <app>] [--suite]`. */
|
|
451
472
|
function parseAddOptions(argv) {
|
|
452
473
|
let parsed;
|
|
453
474
|
try {
|
|
@@ -458,14 +479,18 @@ function parseAddOptions(argv) {
|
|
|
458
479
|
if (parsed.positionals.length === 0) throw new UsageError("add needs at least one plugin name (see \"acrylblends plugins\")");
|
|
459
480
|
return {
|
|
460
481
|
names: parsed.positionals,
|
|
461
|
-
directory: parsed.values.dir
|
|
482
|
+
directory: parsed.values.dir,
|
|
483
|
+
suite: parsed.values.suite === true
|
|
462
484
|
};
|
|
463
485
|
}
|
|
464
486
|
const parse$1 = (argv) => parseArgs({
|
|
465
487
|
args: [...argv],
|
|
466
488
|
allowPositionals: true,
|
|
467
489
|
strict: true,
|
|
468
|
-
options: {
|
|
490
|
+
options: {
|
|
491
|
+
dir: { type: "string" },
|
|
492
|
+
suite: { type: "boolean" }
|
|
493
|
+
}
|
|
469
494
|
});
|
|
470
495
|
const present = (appDir, name) => existsSync(join(pluginsFolder(appDir).dir, name));
|
|
471
496
|
/**
|
|
@@ -495,7 +520,7 @@ async function add(options, io) {
|
|
|
495
520
|
}
|
|
496
521
|
const names = options.names.filter((name) => !external.includes(name)).map((name) => name === "db" ? "acryl-db-sqlite" : name).map((name) => name === "kv" ? "acryl-kv-json" : name).map((name) => name === "desktop" && plain ? "desktop-web" : name);
|
|
497
522
|
if (names.length === 0) return 0;
|
|
498
|
-
const already = names.filter((name) => present(appDir, name));
|
|
523
|
+
const already = options.suite ? [] : names.filter((name) => present(appDir, name));
|
|
499
524
|
if (already.length > 0) {
|
|
500
525
|
io.stderr.write(`error: the app already has ${already.map((name) => `${relative(appDir, join(pluginsFolder(appDir).dir, name)).split(sep).join("/")}`).join(", ")}\n`);
|
|
501
526
|
return 1;
|
|
@@ -504,6 +529,7 @@ async function add(options, io) {
|
|
|
504
529
|
const addedDependencies = [];
|
|
505
530
|
for (const plugin of toCopy) {
|
|
506
531
|
copyPlugin(plugin, appDir);
|
|
532
|
+
if (plugin.imports) mergeImports(appDir, plugin.imports, relative(appDir, pluginsFolder(appDir).dir).split(sep).join("/"));
|
|
507
533
|
addedDependencies.push(...mergeDependencies(appDir, plugin.dependencies));
|
|
508
534
|
const tooling = mergeTooling(appDir, plugin);
|
|
509
535
|
appendGitignore(appDir, plugin.gitignore);
|
|
@@ -511,11 +537,45 @@ async function add(options, io) {
|
|
|
511
537
|
addedDependencies.push(...tooling.devDependencies);
|
|
512
538
|
if (tooling.scripts.length > 0) io.stdout.write(`new scripts: ${tooling.scripts.map((name) => `npm run ${name}`).join(", ")}\n`);
|
|
513
539
|
}
|
|
540
|
+
if (options.suite) {
|
|
541
|
+
const refused = copySuites(names, appDir, addedDependencies, io);
|
|
542
|
+
if (refused !== 0) return refused;
|
|
543
|
+
}
|
|
514
544
|
io.stdout.write(`added ${toCopy.map((plugin) => plugin.name).join(", ")} to ${appDir}\n`);
|
|
515
545
|
if (addedDependencies.length > 0) io.stdout.write(`new dependencies: ${addedDependencies.join(", ")} (run npm install)\n`);
|
|
516
546
|
for (const plugin of toCopy.filter((plugin) => names.includes(plugin.name))) io.stdout.write(`\n${plugin.name}: ${plugin.mount ?? `import it from '../plugins/${plugin.name}/index.ts' and mount it in src/app.ts`}\n`);
|
|
517
547
|
return 0;
|
|
518
548
|
}
|
|
549
|
+
/** The vitest the suites run on (the version this package is tested with). */
|
|
550
|
+
const SUITE_RUNNER = { vitest: "5.0.3" };
|
|
551
|
+
/**
|
|
552
|
+
* Copy the conformance suite of each named port next to its source (`plugins/<name>/src/conformance.ts`), and add `vitest` to the app's development
|
|
553
|
+
* dependencies. The suite is left out of a normal copy because an app that only uses a port has no use for it. Returns the exit code: 1 when a plugin has none.
|
|
554
|
+
*/
|
|
555
|
+
function copySuites(names, appDir, added, io) {
|
|
556
|
+
const copies = [];
|
|
557
|
+
const ports = [...new Set(names.map((name) => name.replace(/^(acryl-(?:kv|db))(?:-.*)?$/u, "$1")))];
|
|
558
|
+
const library = readLibrary();
|
|
559
|
+
for (const name of ports) {
|
|
560
|
+
const suite = library.get(name)?.suite;
|
|
561
|
+
const from = suite === void 0 ? "" : join(libraryRoot(), name, suite);
|
|
562
|
+
if (suite === void 0 || !existsSync(from)) {
|
|
563
|
+
io.stderr.write(`error: ${name} has no conformance suite (the ports db and kv do)\n`);
|
|
564
|
+
return 1;
|
|
565
|
+
}
|
|
566
|
+
copies.push({
|
|
567
|
+
from,
|
|
568
|
+
to: join(pluginsFolder(appDir).dir, name, suite)
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
for (const { from, to } of copies) {
|
|
572
|
+
mkdirSync(dirname(to), { recursive: true });
|
|
573
|
+
copyFileSync(from, to);
|
|
574
|
+
io.stdout.write(`added the conformance suite ${relative(appDir, to).split(sep).join("/")}\n`);
|
|
575
|
+
}
|
|
576
|
+
added.push(...mergeTooling(appDir, { devDependencies: SUITE_RUNNER }).devDependencies);
|
|
577
|
+
return 0;
|
|
578
|
+
}
|
|
519
579
|
const PLUGIN_NAME = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
520
580
|
/**
|
|
521
581
|
* Bring an external plugin folder (a package made with the builder's package_plugin, or any folder with an index.ts that exports a
|
|
@@ -911,14 +971,13 @@ async function kvImport(options, io) {
|
|
|
911
971
|
}
|
|
912
972
|
//#endregion
|
|
913
973
|
//#region src/cli.ts
|
|
914
|
-
/** The version of this package. */
|
|
915
|
-
const VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
916
974
|
const HELP = `acrylblends ${VERSION} - scaffold Cordis apps
|
|
917
975
|
|
|
918
976
|
Usage:
|
|
919
977
|
acrylblends init [dir] [options] Create a Cordis app in an empty or new directory
|
|
920
|
-
acrylblends add <plugin...> [--dir d] Copy library plugins (and what they require) into an app;
|
|
921
|
-
a folder path brings an external plugin into its plugins
|
|
978
|
+
acrylblends add <plugin...> [--dir d] [--suite] Copy library plugins (and what they require) into an app;
|
|
979
|
+
a folder path brings an external plugin into its plugins/;
|
|
980
|
+
--suite also copies the port's conformance suite and vitest (add kv --suite)
|
|
922
981
|
acrylblends plugins List the plugin library
|
|
923
982
|
acrylblends build-client [root] [out] Compile the client modules once for production (src/client to dist/client)
|
|
924
983
|
acrylblends kv import <kv.json> <db> Move a JSON-file kv store into the kv table of a SQLite database [--overwrite] [--table t] [--migrations dir]
|