@decohere/create 0.0.1-dev.126 → 0.0.1-dev.15

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.
@@ -3,5 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- const _runner = require("./runner.js");
7
- (0, _runner.runInBuilder)(process.argv.slice(2));
6
+ const _nodepath = require("node:path");
7
+ const _commander = require("commander");
8
+ const _scaffold = require("./scaffold.js");
9
+ const program = new _commander.Command();
10
+ program.name("decohere").description("Scaffold a new Decohere project").argument("[directory]", "Target directory (default: current directory)", ".").option("-y, --yes", "Skip confirmation prompts").action(async (directory, opts)=>{
11
+ await (0, _scaffold.scaffold)((0, _nodepath.resolve)(directory), opts);
12
+ });
13
+ program.parse();
14
+
15
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvY2xpLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiO1xuaW1wb3J0IHsgc2NhZmZvbGQgfSBmcm9tIFwiLi9zY2FmZm9sZC5qc1wiO1xuXG5jb25zdCBwcm9ncmFtID0gbmV3IENvbW1hbmQoKTtcblxucHJvZ3JhbVxuXHQubmFtZShcImRlY29oZXJlXCIpXG5cdC5kZXNjcmlwdGlvbihcIlNjYWZmb2xkIGEgbmV3IERlY29oZXJlIHByb2plY3RcIilcblx0LmFyZ3VtZW50KFwiW2RpcmVjdG9yeV1cIiwgXCJUYXJnZXQgZGlyZWN0b3J5IChkZWZhdWx0OiBjdXJyZW50IGRpcmVjdG9yeSlcIiwgXCIuXCIpXG5cdC5vcHRpb24oXCIteSwgLS15ZXNcIiwgXCJTa2lwIGNvbmZpcm1hdGlvbiBwcm9tcHRzXCIpXG5cdC5hY3Rpb24oYXN5bmMgKGRpcmVjdG9yeTogc3RyaW5nLCBvcHRzOiB7IHllcz86IGJvb2xlYW4gfSkgPT4ge1xuXHRcdGF3YWl0IHNjYWZmb2xkKHJlc29sdmUoZGlyZWN0b3J5KSwgb3B0cyk7XG5cdH0pO1xuXG5wcm9ncmFtLnBhcnNlKCk7XG4iXSwibmFtZXMiOlsicHJvZ3JhbSIsIkNvbW1hbmQiLCJuYW1lIiwiZGVzY3JpcHRpb24iLCJhcmd1bWVudCIsIm9wdGlvbiIsImFjdGlvbiIsImRpcmVjdG9yeSIsIm9wdHMiLCJzY2FmZm9sZCIsInJlc29sdmUiLCJwYXJzZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7MEJBQ3dCOzJCQUNBOzBCQUNDO0FBRXpCLE1BQU1BLFVBQVUsSUFBSUMsa0JBQU87QUFFM0JELFFBQ0VFLElBQUksQ0FBQyxZQUNMQyxXQUFXLENBQUMsbUNBQ1pDLFFBQVEsQ0FBQyxlQUFlLGlEQUFpRCxLQUN6RUMsTUFBTSxDQUFDLGFBQWEsNkJBQ3BCQyxNQUFNLENBQUMsT0FBT0MsV0FBbUJDO0lBQ2pDLE1BQU1DLElBQUFBLGtCQUFRLEVBQUNDLElBQUFBLGlCQUFPLEVBQUNILFlBQVlDO0FBQ3BDO0FBRURSLFFBQVFXLEtBQUsifQ==
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "scaffold", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return scaffold;
9
+ }
10
+ });
11
+ const _nodefs = require("node:fs");
12
+ const _promises = require("node:fs/promises");
13
+ const _nodepath = require("node:path");
14
+ const _promises1 = require("node:readline/promises");
15
+ const _templates = require("./templates.js");
16
+ async function scaffold(targetDir, opts) {
17
+ const name = (0, _nodepath.basename)(targetDir);
18
+ if ((0, _nodefs.existsSync)(targetDir) && (0, _nodefs.readdirSync)(targetDir).length > 0 && !opts.yes) {
19
+ const rl = (0, _promises1.createInterface)({
20
+ input: process.stdin,
21
+ output: process.stdout
22
+ });
23
+ const answer = await rl.question(`Directory "${name}" is not empty. Continue? [y/N] `);
24
+ rl.close();
25
+ if (!answer.trim().toLowerCase().startsWith("y")) {
26
+ console.log("Aborted.");
27
+ process.exit(0);
28
+ }
29
+ }
30
+ await (0, _promises.mkdir)((0, _nodepath.join)(targetDir, "projects", "app", "src"), {
31
+ recursive: true
32
+ });
33
+ await Promise.all([
34
+ (0, _promises.writeFile)((0, _nodepath.join)(targetDir, "package.json"), (0, _templates.ROOT_PACKAGE_JSON)(name)),
35
+ (0, _promises.writeFile)((0, _nodepath.join)(targetDir, "tsconfig.json"), _templates.TSCONFIG),
36
+ (0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "app", "package.json"), (0, _templates.APP_PACKAGE_JSON)(name)),
37
+ (0, _promises.writeFile)((0, _nodepath.join)(targetDir, "projects", "app", "src", "main.ts"), _templates.MAIN_TS)
38
+ ]);
39
+ console.log(`\nScaffolded ${name}. Next steps:\n`);
40
+ if ((0, _nodepath.basename)(targetDir) !== targetDir) {
41
+ console.log(` cd ${name}`);
42
+ }
43
+ console.log(" pnpm install");
44
+ console.log(" pnpm build # forge build");
45
+ console.log(" pnpm dev # flux serve\n");
46
+ }
47
+
48
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvc2NhZmZvbGQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZGRpclN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHsgbWtkaXIsIHdyaXRlRmlsZSB9IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBiYXNlbmFtZSwgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGNyZWF0ZUludGVyZmFjZSB9IGZyb20gXCJub2RlOnJlYWRsaW5lL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBBUFBfUEFDS0FHRV9KU09OLCBNQUlOX1RTLCBST09UX1BBQ0tBR0VfSlNPTiwgVFNDT05GSUcgfSBmcm9tIFwiLi90ZW1wbGF0ZXMuanNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBTY2FmZm9sZE9wdGlvbnMge1xuXHR5ZXM/OiBib29sZWFuO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2NhZmZvbGQodGFyZ2V0RGlyOiBzdHJpbmcsIG9wdHM6IFNjYWZmb2xkT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuXHRjb25zdCBuYW1lID0gYmFzZW5hbWUodGFyZ2V0RGlyKTtcblxuXHRpZiAoZXhpc3RzU3luYyh0YXJnZXREaXIpICYmIHJlYWRkaXJTeW5jKHRhcmdldERpcikubGVuZ3RoID4gMCAmJiAhb3B0cy55ZXMpIHtcblx0XHRjb25zdCBybCA9IGNyZWF0ZUludGVyZmFjZSh7XG5cdFx0XHRpbnB1dDogcHJvY2Vzcy5zdGRpbixcblx0XHRcdG91dHB1dDogcHJvY2Vzcy5zdGRvdXQsXG5cdFx0fSk7XG5cdFx0Y29uc3QgYW5zd2VyID0gYXdhaXQgcmwucXVlc3Rpb24oYERpcmVjdG9yeSBcIiR7bmFtZX1cIiBpcyBub3QgZW1wdHkuIENvbnRpbnVlPyBbeS9OXSBgKTtcblx0XHRybC5jbG9zZSgpO1xuXHRcdGlmICghYW5zd2VyLnRyaW0oKS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoXCJ5XCIpKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkFib3J0ZWQuXCIpO1xuXHRcdFx0cHJvY2Vzcy5leGl0KDApO1xuXHRcdH1cblx0fVxuXG5cdGF3YWl0IG1rZGlyKGpvaW4odGFyZ2V0RGlyLCBcInByb2plY3RzXCIsIFwiYXBwXCIsIFwic3JjXCIpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuXHRhd2FpdCBQcm9taXNlLmFsbChbXG5cdFx0d3JpdGVGaWxlKGpvaW4odGFyZ2V0RGlyLCBcInBhY2thZ2UuanNvblwiKSwgUk9PVF9QQUNLQUdFX0pTT04obmFtZSkpLFxuXHRcdHdyaXRlRmlsZShqb2luKHRhcmdldERpciwgXCJ0c2NvbmZpZy5qc29uXCIpLCBUU0NPTkZJRyksXG5cdFx0d3JpdGVGaWxlKGpvaW4odGFyZ2V0RGlyLCBcInByb2plY3RzXCIsIFwiYXBwXCIsIFwicGFja2FnZS5qc29uXCIpLCBBUFBfUEFDS0FHRV9KU09OKG5hbWUpKSxcblx0XHR3cml0ZUZpbGUoam9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcHBcIiwgXCJzcmNcIiwgXCJtYWluLnRzXCIpLCBNQUlOX1RTKSxcblx0XSk7XG5cblx0Y29uc29sZS5sb2coYFxcblNjYWZmb2xkZWQgJHtuYW1lfS4gTmV4dCBzdGVwczpcXG5gKTtcblx0aWYgKGJhc2VuYW1lKHRhcmdldERpcikgIT09IHRhcmdldERpcikge1xuXHRcdGNvbnNvbGUubG9nKGAgIGNkICR7bmFtZX1gKTtcblx0fVxuXHRjb25zb2xlLmxvZyhcIiAgcG5wbSBpbnN0YWxsXCIpO1xuXHRjb25zb2xlLmxvZyhcIiAgcG5wbSBidWlsZCAgICAgIyBmb3JnZSBidWlsZFwiKTtcblx0Y29uc29sZS5sb2coXCIgIHBucG0gZGV2ICAgICAgICMgZmx1eCBzZXJ2ZVxcblwiKTtcbn1cbiJdLCJuYW1lcyI6WyJzY2FmZm9sZCIsInRhcmdldERpciIsIm9wdHMiLCJuYW1lIiwiYmFzZW5hbWUiLCJleGlzdHNTeW5jIiwicmVhZGRpclN5bmMiLCJsZW5ndGgiLCJ5ZXMiLCJybCIsImNyZWF0ZUludGVyZmFjZSIsImlucHV0IiwicHJvY2VzcyIsInN0ZGluIiwib3V0cHV0Iiwic3Rkb3V0IiwiYW5zd2VyIiwicXVlc3Rpb24iLCJjbG9zZSIsInRyaW0iLCJ0b0xvd2VyQ2FzZSIsInN0YXJ0c1dpdGgiLCJjb25zb2xlIiwibG9nIiwiZXhpdCIsIm1rZGlyIiwiam9pbiIsInJlY3Vyc2l2ZSIsIlByb21pc2UiLCJhbGwiLCJ3cml0ZUZpbGUiLCJST09UX1BBQ0tBR0VfSlNPTiIsIlRTQ09ORklHIiwiQVBQX1BBQ0tBR0VfSlNPTiIsIk1BSU5fVFMiXSwibWFwcGluZ3MiOiI7Ozs7K0JBVXNCQTs7O2VBQUFBOzs7d0JBVmtCOzBCQUNQOzBCQUNGOzJCQUNDOzJCQUN1QztBQU1oRSxlQUFlQSxTQUFTQyxTQUFpQixFQUFFQyxJQUFxQjtJQUN0RSxNQUFNQyxPQUFPQyxJQUFBQSxrQkFBUSxFQUFDSDtJQUV0QixJQUFJSSxJQUFBQSxrQkFBVSxFQUFDSixjQUFjSyxJQUFBQSxtQkFBVyxFQUFDTCxXQUFXTSxNQUFNLEdBQUcsS0FBSyxDQUFDTCxLQUFLTSxHQUFHLEVBQUU7UUFDNUUsTUFBTUMsS0FBS0MsSUFBQUEsMEJBQWUsRUFBQztZQUMxQkMsT0FBT0MsUUFBUUMsS0FBSztZQUNwQkMsUUFBUUYsUUFBUUcsTUFBTTtRQUN2QjtRQUNBLE1BQU1DLFNBQVMsTUFBTVAsR0FBR1EsUUFBUSxDQUFDLENBQUMsV0FBVyxFQUFFZCxLQUFLLGdDQUFnQyxDQUFDO1FBQ3JGTSxHQUFHUyxLQUFLO1FBQ1IsSUFBSSxDQUFDRixPQUFPRyxJQUFJLEdBQUdDLFdBQVcsR0FBR0MsVUFBVSxDQUFDLE1BQU07WUFDakRDLFFBQVFDLEdBQUcsQ0FBQztZQUNaWCxRQUFRWSxJQUFJLENBQUM7UUFDZDtJQUNEO0lBRUEsTUFBTUMsSUFBQUEsZUFBSyxFQUFDQyxJQUFBQSxjQUFJLEVBQUN6QixXQUFXLFlBQVksT0FBTyxRQUFRO1FBQUUwQixXQUFXO0lBQUs7SUFFekUsTUFBTUMsUUFBUUMsR0FBRyxDQUFDO1FBQ2pCQyxJQUFBQSxtQkFBUyxFQUFDSixJQUFBQSxjQUFJLEVBQUN6QixXQUFXLGlCQUFpQjhCLElBQUFBLDRCQUFpQixFQUFDNUI7UUFDN0QyQixJQUFBQSxtQkFBUyxFQUFDSixJQUFBQSxjQUFJLEVBQUN6QixXQUFXLGtCQUFrQitCLG1CQUFRO1FBQ3BERixJQUFBQSxtQkFBUyxFQUFDSixJQUFBQSxjQUFJLEVBQUN6QixXQUFXLFlBQVksT0FBTyxpQkFBaUJnQyxJQUFBQSwyQkFBZ0IsRUFBQzlCO1FBQy9FMkIsSUFBQUEsbUJBQVMsRUFBQ0osSUFBQUEsY0FBSSxFQUFDekIsV0FBVyxZQUFZLE9BQU8sT0FBTyxZQUFZaUMsa0JBQU87S0FDdkU7SUFFRFosUUFBUUMsR0FBRyxDQUFDLENBQUMsYUFBYSxFQUFFcEIsS0FBSyxlQUFlLENBQUM7SUFDakQsSUFBSUMsSUFBQUEsa0JBQVEsRUFBQ0gsZUFBZUEsV0FBVztRQUN0Q3FCLFFBQVFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRXBCLE1BQU07SUFDM0I7SUFDQW1CLFFBQVFDLEdBQUcsQ0FBQztJQUNaRCxRQUFRQyxHQUFHLENBQUM7SUFDWkQsUUFBUUMsR0FBRyxDQUFDO0FBQ2IifQ==
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get APP_PACKAGE_JSON () {
13
+ return APP_PACKAGE_JSON;
14
+ },
15
+ get MAIN_TS () {
16
+ return MAIN_TS;
17
+ },
18
+ get ROOT_PACKAGE_JSON () {
19
+ return ROOT_PACKAGE_JSON;
20
+ },
21
+ get TSCONFIG () {
22
+ return TSCONFIG;
23
+ }
24
+ });
25
+ function ROOT_PACKAGE_JSON(name) {
26
+ return JSON.stringify({
27
+ name,
28
+ version: "0.0.1",
29
+ type: "module",
30
+ scripts: {
31
+ build: "forge build",
32
+ "build:watch": "forge build --watch",
33
+ dev: "flux serve"
34
+ },
35
+ devDependencies: {
36
+ "@decohere/terminal": "0.0.1-dev.14",
37
+ typescript: "^6.0.3"
38
+ }
39
+ }, null, 2);
40
+ }
41
+ function APP_PACKAGE_JSON(name) {
42
+ return JSON.stringify({
43
+ name: `@${name}/app`,
44
+ version: "0.0.1",
45
+ type: "module",
46
+ main: "src/main.ts"
47
+ }, null, 2);
48
+ }
49
+ const TSCONFIG = JSON.stringify({
50
+ compilerOptions: {
51
+ target: "ES2022",
52
+ module: "NodeNext",
53
+ moduleResolution: "NodeNext",
54
+ strict: true,
55
+ skipLibCheck: true
56
+ },
57
+ include: [
58
+ "projects"
59
+ ]
60
+ }, null, 2);
61
+ const MAIN_TS = `console.log("Hello from Decohere!");
62
+ `;
63
+
64
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvdGVtcGxhdGVzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBST09UX1BBQ0tBR0VfSlNPTihuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRyZXR1cm4gSlNPTi5zdHJpbmdpZnkoXG5cdFx0e1xuXHRcdFx0bmFtZSxcblx0XHRcdHZlcnNpb246IFwiMC4wLjFcIixcblx0XHRcdHR5cGU6IFwibW9kdWxlXCIsXG5cdFx0XHRzY3JpcHRzOiB7XG5cdFx0XHRcdGJ1aWxkOiBcImZvcmdlIGJ1aWxkXCIsXG5cdFx0XHRcdFwiYnVpbGQ6d2F0Y2hcIjogXCJmb3JnZSBidWlsZCAtLXdhdGNoXCIsXG5cdFx0XHRcdGRldjogXCJmbHV4IHNlcnZlXCIsXG5cdFx0XHR9LFxuXHRcdFx0ZGV2RGVwZW5kZW5jaWVzOiB7XG5cdFx0XHRcdFwiQGRlY29oZXJlL3Rlcm1pbmFsXCI6IFwiMC4wLjEtZGV2LjE0XCIsXG5cdFx0XHRcdHR5cGVzY3JpcHQ6IFwiXjYuMC4zXCIsXG5cdFx0XHR9LFxuXHRcdH0sXG5cdFx0bnVsbCxcblx0XHQyLFxuXHQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gQVBQX1BBQ0tBR0VfSlNPTihuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRyZXR1cm4gSlNPTi5zdHJpbmdpZnkoXG5cdFx0e1xuXHRcdFx0bmFtZTogYEAke25hbWV9L2FwcGAsXG5cdFx0XHR2ZXJzaW9uOiBcIjAuMC4xXCIsXG5cdFx0XHR0eXBlOiBcIm1vZHVsZVwiLFxuXHRcdFx0bWFpbjogXCJzcmMvbWFpbi50c1wiLFxuXHRcdH0sXG5cdFx0bnVsbCxcblx0XHQyLFxuXHQpO1xufVxuXG5leHBvcnQgY29uc3QgVFNDT05GSUcgPSBKU09OLnN0cmluZ2lmeShcblx0e1xuXHRcdGNvbXBpbGVyT3B0aW9uczoge1xuXHRcdFx0dGFyZ2V0OiBcIkVTMjAyMlwiLFxuXHRcdFx0bW9kdWxlOiBcIk5vZGVOZXh0XCIsXG5cdFx0XHRtb2R1bGVSZXNvbHV0aW9uOiBcIk5vZGVOZXh0XCIsXG5cdFx0XHRzdHJpY3Q6IHRydWUsXG5cdFx0XHRza2lwTGliQ2hlY2s6IHRydWUsXG5cdFx0fSxcblx0XHRpbmNsdWRlOiBbXCJwcm9qZWN0c1wiXSxcblx0fSxcblx0bnVsbCxcblx0Mixcbik7XG5cbmV4cG9ydCBjb25zdCBNQUlOX1RTID0gYGNvbnNvbGUubG9nKFwiSGVsbG8gZnJvbSBEZWNvaGVyZSFcIik7XG5gO1xuIl0sIm5hbWVzIjpbIkFQUF9QQUNLQUdFX0pTT04iLCJNQUlOX1RTIiwiUk9PVF9QQUNLQUdFX0pTT04iLCJUU0NPTkZJRyIsIm5hbWUiLCJKU09OIiwic3RyaW5naWZ5IiwidmVyc2lvbiIsInR5cGUiLCJzY3JpcHRzIiwiYnVpbGQiLCJkZXYiLCJkZXZEZXBlbmRlbmNpZXMiLCJ0eXBlc2NyaXB0IiwibWFpbiIsImNvbXBpbGVyT3B0aW9ucyIsInRhcmdldCIsIm1vZHVsZSIsIm1vZHVsZVJlc29sdXRpb24iLCJzdHJpY3QiLCJza2lwTGliQ2hlY2siLCJpbmNsdWRlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztRQXFCZ0JBO2VBQUFBOztRQTRCSEM7ZUFBQUE7O1FBakRHQztlQUFBQTs7UUFrQ0hDO2VBQUFBOzs7QUFsQ04sU0FBU0Qsa0JBQWtCRSxJQUFZO0lBQzdDLE9BQU9DLEtBQUtDLFNBQVMsQ0FDcEI7UUFDQ0Y7UUFDQUcsU0FBUztRQUNUQyxNQUFNO1FBQ05DLFNBQVM7WUFDUkMsT0FBTztZQUNQLGVBQWU7WUFDZkMsS0FBSztRQUNOO1FBQ0FDLGlCQUFpQjtZQUNoQixzQkFBc0I7WUFDdEJDLFlBQVk7UUFDYjtJQUNELEdBQ0EsTUFDQTtBQUVGO0FBRU8sU0FBU2IsaUJBQWlCSSxJQUFZO0lBQzVDLE9BQU9DLEtBQUtDLFNBQVMsQ0FDcEI7UUFDQ0YsTUFBTSxDQUFDLENBQUMsRUFBRUEsS0FBSyxJQUFJLENBQUM7UUFDcEJHLFNBQVM7UUFDVEMsTUFBTTtRQUNOTSxNQUFNO0lBQ1AsR0FDQSxNQUNBO0FBRUY7QUFFTyxNQUFNWCxXQUFXRSxLQUFLQyxTQUFTLENBQ3JDO0lBQ0NTLGlCQUFpQjtRQUNoQkMsUUFBUTtRQUNSQyxRQUFRO1FBQ1JDLGtCQUFrQjtRQUNsQkMsUUFBUTtRQUNSQyxjQUFjO0lBQ2Y7SUFDQUMsU0FBUztRQUFDO0tBQVc7QUFDdEIsR0FDQSxNQUNBO0FBR00sTUFBTXBCLFVBQVUsQ0FBQztBQUN4QixDQUFDIn0=
package/es6/src/cli.js CHANGED
@@ -1,3 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { runInBuilder } from "./runner.js";
3
- runInBuilder(process.argv.slice(2));
2
+ import { resolve } from "node:path";
3
+ import { Command } from "commander";
4
+ import { scaffold } from "./scaffold.js";
5
+ const program = new Command();
6
+ program.name("decohere").description("Scaffold a new Decohere project").argument("[directory]", "Target directory (default: current directory)", ".").option("-y, --yes", "Skip confirmation prompts").action(async (directory, opts)=>{
7
+ await scaffold(resolve(directory), opts);
8
+ });
9
+ program.parse();
10
+
11
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvY2xpLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIiMhL3Vzci9iaW4vZW52IG5vZGVcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBDb21tYW5kIH0gZnJvbSBcImNvbW1hbmRlclwiO1xuaW1wb3J0IHsgc2NhZmZvbGQgfSBmcm9tIFwiLi9zY2FmZm9sZC5qc1wiO1xuXG5jb25zdCBwcm9ncmFtID0gbmV3IENvbW1hbmQoKTtcblxucHJvZ3JhbVxuXHQubmFtZShcImRlY29oZXJlXCIpXG5cdC5kZXNjcmlwdGlvbihcIlNjYWZmb2xkIGEgbmV3IERlY29oZXJlIHByb2plY3RcIilcblx0LmFyZ3VtZW50KFwiW2RpcmVjdG9yeV1cIiwgXCJUYXJnZXQgZGlyZWN0b3J5IChkZWZhdWx0OiBjdXJyZW50IGRpcmVjdG9yeSlcIiwgXCIuXCIpXG5cdC5vcHRpb24oXCIteSwgLS15ZXNcIiwgXCJTa2lwIGNvbmZpcm1hdGlvbiBwcm9tcHRzXCIpXG5cdC5hY3Rpb24oYXN5bmMgKGRpcmVjdG9yeTogc3RyaW5nLCBvcHRzOiB7IHllcz86IGJvb2xlYW4gfSkgPT4ge1xuXHRcdGF3YWl0IHNjYWZmb2xkKHJlc29sdmUoZGlyZWN0b3J5KSwgb3B0cyk7XG5cdH0pO1xuXG5wcm9ncmFtLnBhcnNlKCk7XG4iXSwibmFtZXMiOlsicmVzb2x2ZSIsIkNvbW1hbmQiLCJzY2FmZm9sZCIsInByb2dyYW0iLCJuYW1lIiwiZGVzY3JpcHRpb24iLCJhcmd1bWVudCIsIm9wdGlvbiIsImFjdGlvbiIsImRpcmVjdG9yeSIsIm9wdHMiLCJwYXJzZSJdLCJtYXBwaW5ncyI6IjtBQUNBLFNBQVNBLE9BQU8sUUFBUSxZQUFZO0FBQ3BDLFNBQVNDLE9BQU8sUUFBUSxZQUFZO0FBQ3BDLFNBQVNDLFFBQVEsUUFBUSxnQkFBZ0I7QUFFekMsTUFBTUMsVUFBVSxJQUFJRjtBQUVwQkUsUUFDRUMsSUFBSSxDQUFDLFlBQ0xDLFdBQVcsQ0FBQyxtQ0FDWkMsUUFBUSxDQUFDLGVBQWUsaURBQWlELEtBQ3pFQyxNQUFNLENBQUMsYUFBYSw2QkFDcEJDLE1BQU0sQ0FBQyxPQUFPQyxXQUFtQkM7SUFDakMsTUFBTVIsU0FBU0YsUUFBUVMsWUFBWUM7QUFDcEM7QUFFRFAsUUFBUVEsS0FBSyJ9
@@ -0,0 +1,38 @@
1
+ import { existsSync, readdirSync } from "node:fs";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import { basename, join } from "node:path";
4
+ import { createInterface } from "node:readline/promises";
5
+ import { APP_PACKAGE_JSON, MAIN_TS, ROOT_PACKAGE_JSON, TSCONFIG } from "./templates.js";
6
+ export async function scaffold(targetDir, opts) {
7
+ const name = basename(targetDir);
8
+ if (existsSync(targetDir) && readdirSync(targetDir).length > 0 && !opts.yes) {
9
+ const rl = createInterface({
10
+ input: process.stdin,
11
+ output: process.stdout
12
+ });
13
+ const answer = await rl.question(`Directory "${name}" is not empty. Continue? [y/N] `);
14
+ rl.close();
15
+ if (!answer.trim().toLowerCase().startsWith("y")) {
16
+ console.log("Aborted.");
17
+ process.exit(0);
18
+ }
19
+ }
20
+ await mkdir(join(targetDir, "projects", "app", "src"), {
21
+ recursive: true
22
+ });
23
+ await Promise.all([
24
+ writeFile(join(targetDir, "package.json"), ROOT_PACKAGE_JSON(name)),
25
+ writeFile(join(targetDir, "tsconfig.json"), TSCONFIG),
26
+ writeFile(join(targetDir, "projects", "app", "package.json"), APP_PACKAGE_JSON(name)),
27
+ writeFile(join(targetDir, "projects", "app", "src", "main.ts"), MAIN_TS)
28
+ ]);
29
+ console.log(`\nScaffolded ${name}. Next steps:\n`);
30
+ if (basename(targetDir) !== targetDir) {
31
+ console.log(` cd ${name}`);
32
+ }
33
+ console.log(" pnpm install");
34
+ console.log(" pnpm build # forge build");
35
+ console.log(" pnpm dev # flux serve\n");
36
+ }
37
+
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvc2NhZmZvbGQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZGRpclN5bmMgfSBmcm9tIFwibm9kZTpmc1wiO1xuaW1wb3J0IHsgbWtkaXIsIHdyaXRlRmlsZSB9IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBiYXNlbmFtZSwgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGNyZWF0ZUludGVyZmFjZSB9IGZyb20gXCJub2RlOnJlYWRsaW5lL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBBUFBfUEFDS0FHRV9KU09OLCBNQUlOX1RTLCBST09UX1BBQ0tBR0VfSlNPTiwgVFNDT05GSUcgfSBmcm9tIFwiLi90ZW1wbGF0ZXMuanNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBTY2FmZm9sZE9wdGlvbnMge1xuXHR5ZXM/OiBib29sZWFuO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2NhZmZvbGQodGFyZ2V0RGlyOiBzdHJpbmcsIG9wdHM6IFNjYWZmb2xkT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuXHRjb25zdCBuYW1lID0gYmFzZW5hbWUodGFyZ2V0RGlyKTtcblxuXHRpZiAoZXhpc3RzU3luYyh0YXJnZXREaXIpICYmIHJlYWRkaXJTeW5jKHRhcmdldERpcikubGVuZ3RoID4gMCAmJiAhb3B0cy55ZXMpIHtcblx0XHRjb25zdCBybCA9IGNyZWF0ZUludGVyZmFjZSh7XG5cdFx0XHRpbnB1dDogcHJvY2Vzcy5zdGRpbixcblx0XHRcdG91dHB1dDogcHJvY2Vzcy5zdGRvdXQsXG5cdFx0fSk7XG5cdFx0Y29uc3QgYW5zd2VyID0gYXdhaXQgcmwucXVlc3Rpb24oYERpcmVjdG9yeSBcIiR7bmFtZX1cIiBpcyBub3QgZW1wdHkuIENvbnRpbnVlPyBbeS9OXSBgKTtcblx0XHRybC5jbG9zZSgpO1xuXHRcdGlmICghYW5zd2VyLnRyaW0oKS50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoXCJ5XCIpKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkFib3J0ZWQuXCIpO1xuXHRcdFx0cHJvY2Vzcy5leGl0KDApO1xuXHRcdH1cblx0fVxuXG5cdGF3YWl0IG1rZGlyKGpvaW4odGFyZ2V0RGlyLCBcInByb2plY3RzXCIsIFwiYXBwXCIsIFwic3JjXCIpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuXHRhd2FpdCBQcm9taXNlLmFsbChbXG5cdFx0d3JpdGVGaWxlKGpvaW4odGFyZ2V0RGlyLCBcInBhY2thZ2UuanNvblwiKSwgUk9PVF9QQUNLQUdFX0pTT04obmFtZSkpLFxuXHRcdHdyaXRlRmlsZShqb2luKHRhcmdldERpciwgXCJ0c2NvbmZpZy5qc29uXCIpLCBUU0NPTkZJRyksXG5cdFx0d3JpdGVGaWxlKGpvaW4odGFyZ2V0RGlyLCBcInByb2plY3RzXCIsIFwiYXBwXCIsIFwicGFja2FnZS5qc29uXCIpLCBBUFBfUEFDS0FHRV9KU09OKG5hbWUpKSxcblx0XHR3cml0ZUZpbGUoam9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcHBcIiwgXCJzcmNcIiwgXCJtYWluLnRzXCIpLCBNQUlOX1RTKSxcblx0XSk7XG5cblx0Y29uc29sZS5sb2coYFxcblNjYWZmb2xkZWQgJHtuYW1lfS4gTmV4dCBzdGVwczpcXG5gKTtcblx0aWYgKGJhc2VuYW1lKHRhcmdldERpcikgIT09IHRhcmdldERpcikge1xuXHRcdGNvbnNvbGUubG9nKGAgIGNkICR7bmFtZX1gKTtcblx0fVxuXHRjb25zb2xlLmxvZyhcIiAgcG5wbSBpbnN0YWxsXCIpO1xuXHRjb25zb2xlLmxvZyhcIiAgcG5wbSBidWlsZCAgICAgIyBmb3JnZSBidWlsZFwiKTtcblx0Y29uc29sZS5sb2coXCIgIHBucG0gZGV2ICAgICAgICMgZmx1eCBzZXJ2ZVxcblwiKTtcbn1cbiJdLCJuYW1lcyI6WyJleGlzdHNTeW5jIiwicmVhZGRpclN5bmMiLCJta2RpciIsIndyaXRlRmlsZSIsImJhc2VuYW1lIiwiam9pbiIsImNyZWF0ZUludGVyZmFjZSIsIkFQUF9QQUNLQUdFX0pTT04iLCJNQUlOX1RTIiwiUk9PVF9QQUNLQUdFX0pTT04iLCJUU0NPTkZJRyIsInNjYWZmb2xkIiwidGFyZ2V0RGlyIiwib3B0cyIsIm5hbWUiLCJsZW5ndGgiLCJ5ZXMiLCJybCIsImlucHV0IiwicHJvY2VzcyIsInN0ZGluIiwib3V0cHV0Iiwic3Rkb3V0IiwiYW5zd2VyIiwicXVlc3Rpb24iLCJjbG9zZSIsInRyaW0iLCJ0b0xvd2VyQ2FzZSIsInN0YXJ0c1dpdGgiLCJjb25zb2xlIiwibG9nIiwiZXhpdCIsInJlY3Vyc2l2ZSIsIlByb21pc2UiLCJhbGwiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLFVBQVUsRUFBRUMsV0FBVyxRQUFRLFVBQVU7QUFDbEQsU0FBU0MsS0FBSyxFQUFFQyxTQUFTLFFBQVEsbUJBQW1CO0FBQ3BELFNBQVNDLFFBQVEsRUFBRUMsSUFBSSxRQUFRLFlBQVk7QUFDM0MsU0FBU0MsZUFBZSxRQUFRLHlCQUF5QjtBQUN6RCxTQUFTQyxnQkFBZ0IsRUFBRUMsT0FBTyxFQUFFQyxpQkFBaUIsRUFBRUMsUUFBUSxRQUFRLGlCQUFpQjtBQU14RixPQUFPLGVBQWVDLFNBQVNDLFNBQWlCLEVBQUVDLElBQXFCO0lBQ3RFLE1BQU1DLE9BQU9WLFNBQVNRO0lBRXRCLElBQUlaLFdBQVdZLGNBQWNYLFlBQVlXLFdBQVdHLE1BQU0sR0FBRyxLQUFLLENBQUNGLEtBQUtHLEdBQUcsRUFBRTtRQUM1RSxNQUFNQyxLQUFLWCxnQkFBZ0I7WUFDMUJZLE9BQU9DLFFBQVFDLEtBQUs7WUFDcEJDLFFBQVFGLFFBQVFHLE1BQU07UUFDdkI7UUFDQSxNQUFNQyxTQUFTLE1BQU1OLEdBQUdPLFFBQVEsQ0FBQyxDQUFDLFdBQVcsRUFBRVYsS0FBSyxnQ0FBZ0MsQ0FBQztRQUNyRkcsR0FBR1EsS0FBSztRQUNSLElBQUksQ0FBQ0YsT0FBT0csSUFBSSxHQUFHQyxXQUFXLEdBQUdDLFVBQVUsQ0FBQyxNQUFNO1lBQ2pEQyxRQUFRQyxHQUFHLENBQUM7WUFDWlgsUUFBUVksSUFBSSxDQUFDO1FBQ2Q7SUFDRDtJQUVBLE1BQU03QixNQUFNRyxLQUFLTyxXQUFXLFlBQVksT0FBTyxRQUFRO1FBQUVvQixXQUFXO0lBQUs7SUFFekUsTUFBTUMsUUFBUUMsR0FBRyxDQUFDO1FBQ2pCL0IsVUFBVUUsS0FBS08sV0FBVyxpQkFBaUJILGtCQUFrQks7UUFDN0RYLFVBQVVFLEtBQUtPLFdBQVcsa0JBQWtCRjtRQUM1Q1AsVUFBVUUsS0FBS08sV0FBVyxZQUFZLE9BQU8saUJBQWlCTCxpQkFBaUJPO1FBQy9FWCxVQUFVRSxLQUFLTyxXQUFXLFlBQVksT0FBTyxPQUFPLFlBQVlKO0tBQ2hFO0lBRURxQixRQUFRQyxHQUFHLENBQUMsQ0FBQyxhQUFhLEVBQUVoQixLQUFLLGVBQWUsQ0FBQztJQUNqRCxJQUFJVixTQUFTUSxlQUFlQSxXQUFXO1FBQ3RDaUIsUUFBUUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFaEIsTUFBTTtJQUMzQjtJQUNBZSxRQUFRQyxHQUFHLENBQUM7SUFDWkQsUUFBUUMsR0FBRyxDQUFDO0lBQ1pELFFBQVFDLEdBQUcsQ0FBQztBQUNiIn0=
@@ -0,0 +1,40 @@
1
+ export function ROOT_PACKAGE_JSON(name) {
2
+ return JSON.stringify({
3
+ name,
4
+ version: "0.0.1",
5
+ type: "module",
6
+ scripts: {
7
+ build: "forge build",
8
+ "build:watch": "forge build --watch",
9
+ dev: "flux serve"
10
+ },
11
+ devDependencies: {
12
+ "@decohere/terminal": "0.0.1-dev.14",
13
+ typescript: "^6.0.3"
14
+ }
15
+ }, null, 2);
16
+ }
17
+ export function APP_PACKAGE_JSON(name) {
18
+ return JSON.stringify({
19
+ name: `@${name}/app`,
20
+ version: "0.0.1",
21
+ type: "module",
22
+ main: "src/main.ts"
23
+ }, null, 2);
24
+ }
25
+ export const TSCONFIG = JSON.stringify({
26
+ compilerOptions: {
27
+ target: "ES2022",
28
+ module: "NodeNext",
29
+ moduleResolution: "NodeNext",
30
+ strict: true,
31
+ skipLibCheck: true
32
+ },
33
+ include: [
34
+ "projects"
35
+ ]
36
+ }, null, 2);
37
+ export const MAIN_TS = `console.log("Hello from Decohere!");
38
+ `;
39
+
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS9zcmMvdGVtcGxhdGVzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBmdW5jdGlvbiBST09UX1BBQ0tBR0VfSlNPTihuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRyZXR1cm4gSlNPTi5zdHJpbmdpZnkoXG5cdFx0e1xuXHRcdFx0bmFtZSxcblx0XHRcdHZlcnNpb246IFwiMC4wLjFcIixcblx0XHRcdHR5cGU6IFwibW9kdWxlXCIsXG5cdFx0XHRzY3JpcHRzOiB7XG5cdFx0XHRcdGJ1aWxkOiBcImZvcmdlIGJ1aWxkXCIsXG5cdFx0XHRcdFwiYnVpbGQ6d2F0Y2hcIjogXCJmb3JnZSBidWlsZCAtLXdhdGNoXCIsXG5cdFx0XHRcdGRldjogXCJmbHV4IHNlcnZlXCIsXG5cdFx0XHR9LFxuXHRcdFx0ZGV2RGVwZW5kZW5jaWVzOiB7XG5cdFx0XHRcdFwiQGRlY29oZXJlL3Rlcm1pbmFsXCI6IFwiMC4wLjEtZGV2LjE0XCIsXG5cdFx0XHRcdHR5cGVzY3JpcHQ6IFwiXjYuMC4zXCIsXG5cdFx0XHR9LFxuXHRcdH0sXG5cdFx0bnVsbCxcblx0XHQyLFxuXHQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gQVBQX1BBQ0tBR0VfSlNPTihuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRyZXR1cm4gSlNPTi5zdHJpbmdpZnkoXG5cdFx0e1xuXHRcdFx0bmFtZTogYEAke25hbWV9L2FwcGAsXG5cdFx0XHR2ZXJzaW9uOiBcIjAuMC4xXCIsXG5cdFx0XHR0eXBlOiBcIm1vZHVsZVwiLFxuXHRcdFx0bWFpbjogXCJzcmMvbWFpbi50c1wiLFxuXHRcdH0sXG5cdFx0bnVsbCxcblx0XHQyLFxuXHQpO1xufVxuXG5leHBvcnQgY29uc3QgVFNDT05GSUcgPSBKU09OLnN0cmluZ2lmeShcblx0e1xuXHRcdGNvbXBpbGVyT3B0aW9uczoge1xuXHRcdFx0dGFyZ2V0OiBcIkVTMjAyMlwiLFxuXHRcdFx0bW9kdWxlOiBcIk5vZGVOZXh0XCIsXG5cdFx0XHRtb2R1bGVSZXNvbHV0aW9uOiBcIk5vZGVOZXh0XCIsXG5cdFx0XHRzdHJpY3Q6IHRydWUsXG5cdFx0XHRza2lwTGliQ2hlY2s6IHRydWUsXG5cdFx0fSxcblx0XHRpbmNsdWRlOiBbXCJwcm9qZWN0c1wiXSxcblx0fSxcblx0bnVsbCxcblx0Mixcbik7XG5cbmV4cG9ydCBjb25zdCBNQUlOX1RTID0gYGNvbnNvbGUubG9nKFwiSGVsbG8gZnJvbSBEZWNvaGVyZSFcIik7XG5gO1xuIl0sIm5hbWVzIjpbIlJPT1RfUEFDS0FHRV9KU09OIiwibmFtZSIsIkpTT04iLCJzdHJpbmdpZnkiLCJ2ZXJzaW9uIiwidHlwZSIsInNjcmlwdHMiLCJidWlsZCIsImRldiIsImRldkRlcGVuZGVuY2llcyIsInR5cGVzY3JpcHQiLCJBUFBfUEFDS0FHRV9KU09OIiwibWFpbiIsIlRTQ09ORklHIiwiY29tcGlsZXJPcHRpb25zIiwidGFyZ2V0IiwibW9kdWxlIiwibW9kdWxlUmVzb2x1dGlvbiIsInN0cmljdCIsInNraXBMaWJDaGVjayIsImluY2x1ZGUiLCJNQUlOX1RTIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFNBQVNBLGtCQUFrQkMsSUFBWTtJQUM3QyxPQUFPQyxLQUFLQyxTQUFTLENBQ3BCO1FBQ0NGO1FBQ0FHLFNBQVM7UUFDVEMsTUFBTTtRQUNOQyxTQUFTO1lBQ1JDLE9BQU87WUFDUCxlQUFlO1lBQ2ZDLEtBQUs7UUFDTjtRQUNBQyxpQkFBaUI7WUFDaEIsc0JBQXNCO1lBQ3RCQyxZQUFZO1FBQ2I7SUFDRCxHQUNBLE1BQ0E7QUFFRjtBQUVBLE9BQU8sU0FBU0MsaUJBQWlCVixJQUFZO0lBQzVDLE9BQU9DLEtBQUtDLFNBQVMsQ0FDcEI7UUFDQ0YsTUFBTSxDQUFDLENBQUMsRUFBRUEsS0FBSyxJQUFJLENBQUM7UUFDcEJHLFNBQVM7UUFDVEMsTUFBTTtRQUNOTyxNQUFNO0lBQ1AsR0FDQSxNQUNBO0FBRUY7QUFFQSxPQUFPLE1BQU1DLFdBQVdYLEtBQUtDLFNBQVMsQ0FDckM7SUFDQ1csaUJBQWlCO1FBQ2hCQyxRQUFRO1FBQ1JDLFFBQVE7UUFDUkMsa0JBQWtCO1FBQ2xCQyxRQUFRO1FBQ1JDLGNBQWM7SUFDZjtJQUNBQyxTQUFTO1FBQUM7S0FBVztBQUN0QixHQUNBLE1BQ0EsR0FDQztBQUVGLE9BQU8sTUFBTUMsVUFBVSxDQUFDO0FBQ3hCLENBQUMsQ0FBQyJ9
package/package.json CHANGED
@@ -1,40 +1,27 @@
1
1
  {
2
2
  "name": "@decohere/create",
3
- "version": "0.0.1-dev.126",
4
- "description": "Download the Decohere scaffolder image and run it (npm create @decohere)",
3
+ "version": "0.0.1-dev.15",
4
+ "description": "Scaffold a new Decohere project — build with Forge, serve with Flux",
5
5
  "keywords": [
6
6
  "decohere",
7
7
  "create",
8
8
  "scaffold",
9
- "cli"
9
+ "cli",
10
+ "forge",
11
+ "flux",
12
+ "typescript"
10
13
  ],
11
- "homepage": "https://github.com/typesmiths/decohere/tree/main/projects/create#readme",
12
- "bugs": {
13
- "url": "https://github.com/typesmiths/decohere/issues"
14
- },
15
- "repository": {
16
- "type": "git",
17
- "url": "git+https://github.com/typesmiths/decohere.git",
18
- "directory": "projects/create"
19
- },
20
14
  "license": "ISC",
21
15
  "author": "Typesmiths",
22
16
  "type": "module",
23
- "exports": {
24
- ".": {
25
- "types": "./types/src/index.d.ts",
26
- "import": "./es6/src/index.js"
27
- }
28
- },
29
17
  "bin": {
30
18
  "create-decohere": "./es6/src/cli.js"
31
19
  },
32
20
  "scripts": {
33
21
  "test": "echo \"Error: no test specified\" && exit 1"
34
22
  },
35
- "dependencies": {},
36
- "devDependencies": {},
37
- "decohere": {
38
- "dockerImageRepository": "ghcr.io/typesmiths/decohere/create"
39
- }
23
+ "dependencies": {
24
+ "commander": "^13.1.0"
25
+ },
26
+ "devDependencies": {}
40
27
  }
@@ -0,0 +1,4 @@
1
+ export interface ScaffoldOptions {
2
+ yes?: boolean;
3
+ }
4
+ export declare function scaffold(targetDir: string, opts: ScaffoldOptions): Promise<void>;
@@ -0,0 +1,4 @@
1
+ export declare function ROOT_PACKAGE_JSON(name: string): string;
2
+ export declare function APP_PACKAGE_JSON(name: string): string;
3
+ export declare const TSCONFIG: string;
4
+ export declare const MAIN_TS = "console.log(\"Hello from Decohere!\");\n";
package/LICENSE DELETED
@@ -1,15 +0,0 @@
1
- ISC License
2
-
3
- Copyright (c) 2025-2026 Typesmiths
4
-
5
- Permission to use, copy, modify, and/or distribute this software for any
6
- purpose with or without fee is hereby granted, provided that the above
7
- copyright notice and this permission notice appear in all copies.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md DELETED
@@ -1,254 +0,0 @@
1
- # @decohere/create
2
-
3
- Scaffold a new Decohere project — built with Forge, served with Flux.
4
-
5
- Docker is required on the host. `@decohere/create` only pulls `ghcr.io/typesmiths/decohere/create` and runs `@decohere/scaffold` inside it (including the Auth0 CLI). It does not install the scaffolder libraries on the host.
6
-
7
- ## Usage
8
-
9
- `npm create` already says “create”, so the first token is the kind (`webapi`), not `create` again. The launcher forwards `decohere create webapi …` into the builder image.
10
-
11
- This run prompts for database, auth, Postman, and whether to install:
12
-
13
- ```bash
14
- npm create @decohere@dev webapi -d my-app
15
- # or
16
- npx @decohere/create@dev webapi -d my-app
17
- # or, once `@decohere/cli` is installed:
18
- decohere create webapi -d my-app
19
- ```
20
-
21
- To skip prompts, pass every answer up front (`-y` means “install deps, don’t ask”):
22
-
23
- ```bash
24
- npm create @decohere@dev -- webapi -d my-app --database postgres/typeorm --auth none --postman local -y
25
- ```
26
-
27
- Target directory is `webapi`'s optional argument or `-d` (default `.`). `npm create` treats `-d` as its own loglevel flag and forwards `my-app` as a positional — that form is supported. Extra create flags still need `--` after `npm create`.
28
-
29
- The first token after the package must be a command (`webapi`); a bare directory name is an unknown command.
30
-
31
- The scaffolded Dev Container asks **y/N** (TTY only) before npm auth and optional codebase RAG MCP (semantic search). Decline or run without a TTY to skip. Credentials are written under the project `.cursor/` directory (gitignored).
32
-
33
- ## Commands
34
-
35
- ### `webapi`
36
-
37
- Scaffolds a full web API using `@decohere/http` (HTTP), `@decohere/crucible` (DI), `@decohere/config` (configuration) and Scribe (logging), plus a Dev Container workspace.
38
-
39
- ```bash
40
- npx @decohere/create webapi -d my-app
41
- npx @decohere/create webapi -d my-app --name billing
42
- npx @decohere/create webapi -d my-app --name api --name billing
43
- ```
44
-
45
- Generated structure (default `--name api`):
46
-
47
- ```
48
- my-app/
49
- package.json # build / start / start:<name> / dev
50
- .github/
51
- actions/setup-node-pnpm/
52
- workflows/
53
- ci.yml # lint ∥ test (+ build and package on default branch)
54
- publish.yml # forge publish (skips private); no docker push by default
55
- tsconfig.json
56
- biome.json
57
- .env
58
- config/
59
- config.yaml
60
- config.dev.yaml
61
- .devcontainer/
62
- projects/
63
- api/ # or projects/<name> when --name is set
64
- package.json # private: true (app, not an npm package)
65
- Dockerfile # copies .package/ (written by `forge package`)
66
- .dockerignore
67
- src/
68
- main.ts
69
- sample.config.ts
70
- sample.service.ts
71
- controllers/
72
- hello.controller.ts
73
- ```
74
-
75
- Every API gets its own `projects/<name>/Dockerfile`; that folder is the Docker build context. The Dockerfile copies `.package/`, which `forge package` writes (see below).
76
-
77
- The app Dev Container is a thin `FROM ghcr.io/typesmiths/decohere/devcontainer:<version>` (pinned to the scaffolder version). Shared layers (bash history, pnpm, `gh`, js-debug bootloader fix) update via `docker pull` / Dev Container rebuild — Compose mounts and lifecycle scripts stay in the app repo. Rebuild with pull after upgrading `@decohere/create`.
78
-
79
- #### Scripts
80
-
81
- | Script | Command | When |
82
- |---|---|---|
83
- | `build` | `forge build --configuration release` | CI, Nixpacks |
84
- | `package` / `package:<name>` | release build, then `forge package` (all APIs, or that one) | Before `docker build` |
85
- | `start` | `node dist/release/projects/<first>/es6/src/main.js` | Production default API (`pnpm start`) |
86
- | `start:<name>` | same path for that API | Deploy that API (`pnpm run start:billing`) |
87
- | `dev` | `flux serve --env-file-if-exists .env` (plus `--project @<app>/<first>` when named) | Local HMR for the first API; loads `.env` if present |
88
- | `dev:<name>` | `PORT=<3000+n> flux serve --env-file-if-exists .env --project @<app>/<name>` | Local HMR for that API |
89
- | `lint:check` / `typecheck` / `test` | biome / forge typecheck / vitest | CI |
90
-
91
- #### Multiple APIs / add later
92
-
93
- ```bash
94
- decohere add api billing
95
- # empty machine / npm create still maps `webapi add`:
96
- npx @decohere/create webapi add billing -d my-app
97
- ```
98
-
99
- Adds `projects/billing`, `start:billing` / `package:billing` / `dev:billing`, and `projects/billing/Dockerfile`. Does not rewrite the first API or workspace files like `biome.json`.
100
-
101
- Each API is a separate deploy: package it (`pnpm run package:billing`) and build the image from its folder (`docker build projects/billing`), or set the start command to `pnpm run start:billing`. Workspace `config/` is shared; each API still has its own named datasource and `{PREFIX}_DB_*` env (host/port default to the Compose Postgres).
102
-
103
- ### `auth0`
104
-
105
- The Auth0 CLI lives in the create image. Host tokens are stored in `~/.config/auth0` (always bind-mounted). Use this after a project exists, when a token expires, or when the Postman SPA needs to be created/updated.
106
-
107
- ```bash
108
- # Device/URL login — open the printed URL in your browser
109
- npx @decohere/create auth0 login
110
-
111
- # Update the Auth0 API + Postman SPA for this workspace (run from the project, or pass -d)
112
- npx @decohere/create auth0 configure
113
- npx @decohere/create auth0 configure -d my-app
114
-
115
- # Same commands once `@decohere/cli` is installed:
116
- decohere auth0 login
117
- decohere auth0 configure
118
- ```
119
-
120
- `configure` does **not** rewrite application source. It scans `projects/*/src` for `@Authorize("action", "Subject")`, adds those permissions to the Auth0 API (keeping any already on the API), assigns them to `AUTH0_ADMIN_USER_SUB` when set, and updates Postman token `scope`.
121
-
122
- #### Keep Auth0 in sync with controllers
123
-
124
- `@Authorize("read", "Invoice")` becomes Auth0 API permission `read:Invoice`. After adding a controller:
125
-
126
- ```bash
127
- npx @decohere/create auth0 configure
128
- ```
129
-
130
- Then in Postman, Authorization → Get New Access Token so the token includes the new permissions.
131
-
132
- #### Deploy (Railway / Fly / Nixpacks)
133
-
134
- The production image does not install or build anything: it copies `.package/`, the folder `forge package` writes inside the API project (the API's compiled code, the workspace libraries it imports, and a plain `node_modules` of the third-party packages it uses, with no symlinks). Run `pnpm run package` (or `package:<name>`) first, then `docker build projects/<name>`.
135
-
136
- 1. **CI builds the image (preferred):** run `pnpm run package`, then `pnpm exec forge docker --configuration release --push`. Private `@decohere/*` packages need npm auth only in that package step, never in the image build.
137
- 2. **Hosts that build from a git clone** (Railway, Fly) do not have `.package/`, because it is build output. Build the image in CI and deploy it, or run the package step before `docker build`.
138
- 3. **Nixpacks (no Dockerfile):** conventional `build` / `start` scripts — install → build → start.
139
-
140
- Commit `pnpm-lock.yaml` after the first install.
141
-
142
- **Registry push (optional):** CI does not run `forge docker --push` by default. For Cloud Run / K8s, add `pnpm run package` and that step to `publish.yml` after configuring GHCR.
143
-
144
- **Conventions:** `"private": true` → skip npm publish; presence of a Dockerfile → dockerizable; non-private packages under `projects/` → `forge publish`.
145
-
146
- #### Database (`--database`)
147
-
148
- | Value | Effect |
149
- |---|---|
150
- | `none` | No database |
151
- | `postgres/typeorm` | One Compose Postgres **instance**; each API owns a named database + `{PREFIX}_DB_*` env |
152
-
153
- ```bash
154
- npx @decohere/create webapi -d my-app --database postgres/typeorm
155
- npx @decohere/create webapi -d my-app --name api --name billing --database postgres/typeorm
156
- ```
157
-
158
- `config.yaml` lists one datasource per API (`name: billing` → `withTypeOrm({ name: "billing" })`). Locally they share host `postgres` port `5432`. Point `BILLING_DB_HOST` / `BILLING_DB_PORT` at another server to split later. `webapi add billing --database postgres/typeorm` appends a datasource; TypeORM bootstrap `CREATE DATABASE`s it on first run.
159
-
160
- #### Health probes
161
-
162
- Scaffolded APIs call `.withHealth()` so these routes are available **without auth**:
163
-
164
- | Route | Purpose | Status |
165
- |---|---|---|
166
- | `GET /health` | Liveness — process is up | Always `200` `{ "status": "ok" }` |
167
- | `GET /ready` | Readiness — dependencies OK | `200` when checks pass; `503` when a check fails |
168
-
169
- With `--database postgres/typeorm`, readiness runs `SELECT 1` against each TypeORM datasource. Use `/ready` for load balancers and orchestrators.
170
-
171
- #### Auth (`--auth`)
172
-
173
- | Value | Effect |
174
- |---|---|
175
- | `none` | No auth |
176
- | `auth0` | Auth0 JWT protection; with Postgres also scaffolds a local User profile |
177
-
178
- ```bash
179
- npx @decohere/create webapi -d my-app --auth auth0
180
- ```
181
-
182
- With Auth0 + Postgres, customize authorization in `projects/<api>/src/auth/ability.factory.ts`:
183
- override `defineAbilitiesFor` for product CASL rules, and `mapPrincipal` for IdP claim mapping
184
- (including the `AUTH0_ADMIN_USER_SUB` admin bootstrap). `@decohere/http`'s default already maps
185
- `admin` → `manage`/`all` and `action:Subject` scopes.
186
-
187
- #### Postman (`--postman`)
188
-
189
- | Value | Effect |
190
- |---|---|
191
- | `none` | Skip Postman |
192
- | `local` | Local View collection + environment under `postman/` |
193
- | `api` | Create collection/environment in a Postman cloud workspace |
194
-
195
- ```bash
196
- npx @decohere/create webapi -d my-app --postman local
197
- ```
198
-
199
- ## Options
200
-
201
- | Option | Scope | Description |
202
- |---|---|---|
203
- | `[directory]` / `-d <directory>` | `webapi` / global | Target directory (positional wins; default `.`) |
204
- | `--name <slug>` | `webapi` | API directory under `projects/` (repeatable; default `api`) |
205
- | `add api <name>` | `decohere add api` / `npx @decohere/create webapi add` | Add an API to an existing Decohere workspace |
206
- | `auth0 login` | `decohere auth0` / `npx @decohere/create auth0` | Device/URL login; persist tokens in `~/.config/auth0` |
207
- | `auth0 configure` | `decohere auth0` / `npx @decohere/create auth0` | Update Auth0 API + Postman SPA for an existing workspace |
208
- | `--database <provider>` | `webapi` / `add` | `none` \| `postgres/typeorm` |
209
- | `--auth <provider>` | `webapi` / `add` | `none` \| `auth0` |
210
- | `--postman <provider>` | `webapi` / `add` | `none` \| `local` \| `api` |
211
- | `-y, --yes` | `webapi` / `add` | Install dependencies without prompting |
212
- | `--install <mode>` | `webapi` / `add` | `ask` (default) \| `yes` \| `no` |
213
-
214
- ## Next steps
215
-
216
- After scaffolding:
217
-
218
- ```bash
219
- cd my-app
220
- code . # open in VS Code / Dev Container
221
- pnpm build # forge release build
222
- pnpm start # run compiled API (production)
223
- pnpm dev # Flux HMR (development)
224
- ```
225
-
226
- ## Troubleshooting
227
-
228
- ### GHCR pull fails with `403 Forbidden`
229
-
230
- If scaffolding fails with an error like:
231
-
232
- ```text
233
- failed to resolve reference "ghcr.io/typesmiths/decohere/create:<version>": ... 403 Forbidden
234
- ```
235
-
236
- your GitHub token likely does not include the `read:packages` scope.
237
-
238
- 1. Create or use a token with at least `read:packages`.
239
- 2. If the package is private/internal, also include `repo`.
240
- 3. Re-login to GHCR and retry.
241
-
242
- ```bash
243
- export GH_TOKEN=YOUR_PAT_WITH_READ_PACKAGES
244
- echo "$GH_TOKEN" | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin
245
- docker pull ghcr.io/typesmiths/decohere/create:<version>
246
- ```
247
-
248
- You can verify scopes with:
249
-
250
- ```bash
251
- gh auth status -t
252
- ```
253
-
254
- If you still get `403` after adding `read:packages`, ask an org admin to grant your user/team access to the `typesmiths/decohere/create` package.
@@ -1,26 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get containerArgvFromHost () {
13
- return _resolvelaunch.containerArgvFromHost;
14
- },
15
- get resolveLaunch () {
16
- return _resolvelaunch.resolveLaunch;
17
- },
18
- get runInBuilder () {
19
- return _runner.runInBuilder;
20
- },
21
- get toProductArgv () {
22
- return _resolvelaunch.toProductArgv;
23
- }
24
- });
25
- const _resolvelaunch = require("./resolve-launch.js");
26
- const _runner = require("./runner.js");
@@ -1,100 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get containerArgvFromHost () {
13
- return containerArgvFromHost;
14
- },
15
- get resolveLaunch () {
16
- return resolveLaunch;
17
- },
18
- get toProductArgv () {
19
- return toProductArgv;
20
- }
21
- });
22
- const _nodepath = require("node:path");
23
- const HOST_FLAGS_WITH_VALUE = new Set([
24
- "--config-file",
25
- "--log-level"
26
- ]);
27
- function toProductArgv(tokens) {
28
- if (tokens[0] === "webapi" && tokens[1] === "add") {
29
- return [
30
- "add",
31
- "api",
32
- ...tokens.slice(2)
33
- ];
34
- }
35
- if (tokens[0] === "webapi") {
36
- return [
37
- "create",
38
- "webapi",
39
- ...tokens.slice(1)
40
- ];
41
- }
42
- return tokens;
43
- }
44
- function containerArgvFromHost(argv) {
45
- const user = argv[0]?.includes("node") || argv[0]?.endsWith("node") ? argv.slice(2) : argv;
46
- const stripped = [];
47
- for(let i = 0; i < user.length; i++){
48
- const arg = user[i];
49
- if (arg != null && HOST_FLAGS_WITH_VALUE.has(arg)) {
50
- i++;
51
- continue;
52
- }
53
- if (arg != null) stripped.push(arg);
54
- }
55
- return toProductArgv(stripped);
56
- }
57
- function resolveLaunch(argv, cwd = process.cwd()) {
58
- if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h" || argv[0] === "--version")) {
59
- return {
60
- targetDir: cwd,
61
- containerArgv: argv,
62
- projectName: (0, _nodepath.basename)(cwd),
63
- kind: "scaffold"
64
- };
65
- }
66
- let directoryFlag;
67
- const withoutD = [];
68
- for(let i = 0; i < argv.length; i++){
69
- const arg = argv[i];
70
- if (arg === "-d") {
71
- directoryFlag = argv[i + 1];
72
- i++;
73
- continue;
74
- }
75
- if (arg != null) withoutD.push(arg);
76
- }
77
- const product = toProductArgv(withoutD);
78
- const isAdd = product[0] === "add";
79
- let positional;
80
- let withoutPositional = product;
81
- if (!isAdd && product[0] === "create" && product[1] === "webapi" && product[2] != null && !product[2].startsWith("-")) {
82
- positional = product[2];
83
- withoutPositional = [
84
- product[0],
85
- product[1],
86
- ...product.slice(3)
87
- ];
88
- }
89
- const targetDir = (0, _nodepath.resolve)(cwd, positional?.trim() || directoryFlag?.trim() || ".");
90
- return {
91
- targetDir,
92
- containerArgv: [
93
- ...withoutPositional,
94
- "-d",
95
- "."
96
- ],
97
- projectName: (0, _nodepath.basename)(targetDir),
98
- kind: product[0] === "auth0" ? "auth0" : "scaffold"
99
- };
100
- }
@@ -1,105 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- Object.defineProperty(exports, "runInBuilder", {
6
- enumerable: true,
7
- get: function() {
8
- return runInBuilder;
9
- }
10
- });
11
- const _nodechild_process = require("node:child_process");
12
- const _nodefs = require("node:fs");
13
- const _nodeos = require("node:os");
14
- const _nodepath = require("node:path");
15
- const _resolvelaunch = require("./resolve-launch.js");
16
- const _version = require("./version.js");
17
- const BUILDER_IMAGE = `${_version.CREATE_IMAGE_REPOSITORY}:${_version.CREATE_VERSION}`;
18
- function runInBuilder(argv) {
19
- const { targetDir, containerArgv, projectName, kind } = (0, _resolvelaunch.resolveLaunch)(argv);
20
- (0, _nodefs.mkdirSync)(targetDir, {
21
- recursive: true
22
- });
23
- if (kind === "scaffold") {
24
- (0, _nodefs.mkdirSync)((0, _nodepath.resolve)(targetDir, ".devcontainer", "npm-auth"), {
25
- recursive: true
26
- });
27
- }
28
- try {
29
- (0, _nodechild_process.execFileSync)("docker", [
30
- "info"
31
- ], {
32
- stdio: "pipe"
33
- });
34
- } catch {
35
- console.error("\n Docker is required to scaffold a Decohere project.\n" + " Install Docker Desktop: https://www.docker.com/products/docker-desktop\n");
36
- process.exit(1);
37
- }
38
- const hostUid = process.getuid?.();
39
- const hostGid = process.getgid?.() ?? hostUid;
40
- const runAsHostUser = hostUid != null && hostGid != null;
41
- const npmCacheDir = (0, _nodepath.resolve)((0, _nodeos.homedir)(), ".cache/decohere-create/npm");
42
- (0, _nodefs.mkdirSync)(npmCacheDir, {
43
- recursive: true
44
- });
45
- const builderHome = "/tmp/decohere-create-home";
46
- const volumes = [
47
- "-v",
48
- `${targetDir}:/workspace`,
49
- "-v",
50
- `${npmCacheDir}:/npm-cache`
51
- ];
52
- const envArgs = [
53
- "-e",
54
- "DECOHERE_BUILDER=1",
55
- "-e",
56
- `DECOHERE_PROJECT_NAME=${projectName}`,
57
- "-e",
58
- "NPM_CONFIG_CACHE=/npm-cache",
59
- "-e",
60
- "NPM_CONFIG_PREFER_OFFLINE=true",
61
- "-e",
62
- `HOME=${builderHome}`
63
- ];
64
- const npmrcPath = (0, _nodepath.resolve)((0, _nodeos.homedir)(), ".npmrc");
65
- if ((0, _nodefs.existsSync)(npmrcPath)) {
66
- volumes.push("-v", `${npmrcPath}:/tmp/host-npmrc:ro`);
67
- envArgs.push("-e", "NPM_CONFIG_USERCONFIG=/tmp/host-npmrc");
68
- }
69
- const auth0ConfigDir = (0, _nodepath.resolve)((0, _nodeos.homedir)(), ".config/auth0");
70
- (0, _nodefs.mkdirSync)(auth0ConfigDir, {
71
- recursive: true
72
- });
73
- volumes.push("-v", `${auth0ConfigDir}:${builderHome}/.config/auth0`);
74
- const userArgs = [];
75
- if (runAsHostUser) {
76
- userArgs.push("--user", `${hostUid}:${hostGid}`);
77
- } else if (hostUid != null) {
78
- envArgs.push("-e", `HOST_UID=${hostUid}`);
79
- if (hostGid != null) envArgs.push("-e", `HOST_GID=${hostGid}`);
80
- }
81
- console.log(kind === "auth0" ? " Running Auth0 CLI in the scaffolder image...\n" : " Running scaffolding in a sandboxed container...\n");
82
- const ttyFlags = process.stdin.isTTY ? [
83
- "-it"
84
- ] : [
85
- "-i"
86
- ];
87
- const result = (0, _nodechild_process.spawnSync)("docker", [
88
- "run",
89
- "--rm",
90
- ...ttyFlags,
91
- ...userArgs,
92
- ...volumes,
93
- ...envArgs,
94
- "-w",
95
- "/workspace",
96
- BUILDER_IMAGE,
97
- ...containerArgv
98
- ], {
99
- stdio: "inherit"
100
- });
101
- if (result.status === 0 && kind === "scaffold") {
102
- console.log(`\n Scaffold complete!\n\n Open your project:\n\n code ${targetDir}\n`);
103
- }
104
- process.exit(result.status ?? 0);
105
- }
@@ -1,48 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get CREATE_IMAGE_REPOSITORY () {
13
- return CREATE_IMAGE_REPOSITORY;
14
- },
15
- get CREATE_VERSION () {
16
- return CREATE_VERSION;
17
- }
18
- });
19
- const _nodemodule = require("node:module");
20
- const _nodepath = require("node:path");
21
- const _nodeurl = require("node:url");
22
- const _require = (0, _nodemodule.createRequire)(require("url").pathToFileURL(__filename).toString());
23
- const DEFAULT_CREATE_VERSION = "0.0.1-dev";
24
- const DEFAULT_CREATE_IMAGE_REPOSITORY = "ghcr.io/typesmiths/decohere/create";
25
- function resolveCreateMetadata() {
26
- let dir = (0, _nodepath.dirname)((0, _nodeurl.fileURLToPath)(require("url").pathToFileURL(__filename).toString()));
27
- for(let i = 0; i < 5; i++){
28
- try {
29
- const pkg = _require((0, _nodepath.join)(dir, "package.json"));
30
- if (pkg.name === "@decohere/create") {
31
- return {
32
- version: pkg.version ?? DEFAULT_CREATE_VERSION,
33
- imageRepository: pkg.decohere?.dockerImageRepository ?? DEFAULT_CREATE_IMAGE_REPOSITORY
34
- };
35
- }
36
- } catch {}
37
- const parent = (0, _nodepath.dirname)(dir);
38
- if (parent === dir) break;
39
- dir = parent;
40
- }
41
- return {
42
- version: DEFAULT_CREATE_VERSION,
43
- imageRepository: DEFAULT_CREATE_IMAGE_REPOSITORY
44
- };
45
- }
46
- const createMetadata = resolveCreateMetadata();
47
- const CREATE_VERSION = createMetadata.version;
48
- const CREATE_IMAGE_REPOSITORY = createMetadata.imageRepository;
package/es6/src/index.js DELETED
@@ -1,2 +0,0 @@
1
- export { containerArgvFromHost, resolveLaunch, toProductArgv } from "./resolve-launch.js";
2
- export { runInBuilder } from "./runner.js";
@@ -1,87 +0,0 @@
1
- import { basename, resolve } from "node:path";
2
- const HOST_FLAGS_WITH_VALUE = new Set([
3
- "--config-file",
4
- "--log-level"
5
- ]);
6
- /**
7
- * Map host / npm-create argv onto the product CLI (`create webapi` / `add api`).
8
- * `npm create @decohere webapi` already says “create”, so we prepend `create`
9
- * rather than making users type `create create webapi`.
10
- */ export function toProductArgv(tokens) {
11
- if (tokens[0] === "webapi" && tokens[1] === "add") {
12
- return [
13
- "add",
14
- "api",
15
- ...tokens.slice(2)
16
- ];
17
- }
18
- if (tokens[0] === "webapi") {
19
- return [
20
- "create",
21
- "webapi",
22
- ...tokens.slice(1)
23
- ];
24
- }
25
- return tokens;
26
- }
27
- export function containerArgvFromHost(argv) {
28
- const user = argv[0]?.includes("node") || argv[0]?.endsWith("node") ? argv.slice(2) : argv;
29
- const stripped = [];
30
- for(let i = 0; i < user.length; i++){
31
- const arg = user[i];
32
- if (arg != null && HOST_FLAGS_WITH_VALUE.has(arg)) {
33
- i++;
34
- continue;
35
- }
36
- if (arg != null) stripped.push(arg);
37
- }
38
- return toProductArgv(stripped);
39
- }
40
- /**
41
- * Host argv → directory to mount and argv for the in-image `decohere` entrypoint.
42
- * Positional `webapi my-app` / `create webapi my-app` wins over `-d` (npm treats `-d`
43
- * as its own loglevel).
44
- */ export function resolveLaunch(argv, cwd = process.cwd()) {
45
- if (argv.length === 1 && (argv[0] === "--help" || argv[0] === "-h" || argv[0] === "--version")) {
46
- return {
47
- targetDir: cwd,
48
- containerArgv: argv,
49
- projectName: basename(cwd),
50
- kind: "scaffold"
51
- };
52
- }
53
- let directoryFlag;
54
- const withoutD = [];
55
- for(let i = 0; i < argv.length; i++){
56
- const arg = argv[i];
57
- if (arg === "-d") {
58
- directoryFlag = argv[i + 1];
59
- i++;
60
- continue;
61
- }
62
- if (arg != null) withoutD.push(arg);
63
- }
64
- const product = toProductArgv(withoutD);
65
- const isAdd = product[0] === "add";
66
- let positional;
67
- let withoutPositional = product;
68
- if (!isAdd && product[0] === "create" && product[1] === "webapi" && product[2] != null && !product[2].startsWith("-")) {
69
- positional = product[2];
70
- withoutPositional = [
71
- product[0],
72
- product[1],
73
- ...product.slice(3)
74
- ];
75
- }
76
- const targetDir = resolve(cwd, positional?.trim() || directoryFlag?.trim() || ".");
77
- return {
78
- targetDir,
79
- containerArgv: [
80
- ...withoutPositional,
81
- "-d",
82
- "."
83
- ],
84
- projectName: basename(targetDir),
85
- kind: product[0] === "auth0" ? "auth0" : "scaffold"
86
- };
87
- }
package/es6/src/runner.js DELETED
@@ -1,98 +0,0 @@
1
- import { execFileSync, spawnSync } from "node:child_process";
2
- import { existsSync, mkdirSync } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { resolve } from "node:path";
5
- import { resolveLaunch } from "./resolve-launch.js";
6
- import { CREATE_IMAGE_REPOSITORY, CREATE_VERSION } from "./version.js";
7
- const BUILDER_IMAGE = `${CREATE_IMAGE_REPOSITORY}:${CREATE_VERSION}`;
8
- /**
9
- * Pull/run the Decohere scaffolder image. Host `@decohere/create` does not load
10
- * the `@decohere/scaffold` dependency tree — that lives in the image only.
11
- */ export function runInBuilder(argv) {
12
- const { targetDir, containerArgv, projectName, kind } = resolveLaunch(argv);
13
- mkdirSync(targetDir, {
14
- recursive: true
15
- });
16
- if (kind === "scaffold") {
17
- mkdirSync(resolve(targetDir, ".devcontainer", "npm-auth"), {
18
- recursive: true
19
- });
20
- }
21
- try {
22
- execFileSync("docker", [
23
- "info"
24
- ], {
25
- stdio: "pipe"
26
- });
27
- } catch {
28
- console.error("\n Docker is required to scaffold a Decohere project.\n" + " Install Docker Desktop: https://www.docker.com/products/docker-desktop\n");
29
- process.exit(1);
30
- }
31
- const hostUid = process.getuid?.();
32
- const hostGid = process.getgid?.() ?? hostUid;
33
- const runAsHostUser = hostUid != null && hostGid != null;
34
- const npmCacheDir = resolve(homedir(), ".cache/decohere-create/npm");
35
- mkdirSync(npmCacheDir, {
36
- recursive: true
37
- });
38
- const builderHome = "/tmp/decohere-create-home";
39
- const volumes = [
40
- "-v",
41
- `${targetDir}:/workspace`,
42
- "-v",
43
- `${npmCacheDir}:/npm-cache`
44
- ];
45
- const envArgs = [
46
- "-e",
47
- "DECOHERE_BUILDER=1",
48
- "-e",
49
- `DECOHERE_PROJECT_NAME=${projectName}`,
50
- "-e",
51
- "NPM_CONFIG_CACHE=/npm-cache",
52
- "-e",
53
- "NPM_CONFIG_PREFER_OFFLINE=true",
54
- "-e",
55
- `HOME=${builderHome}`
56
- ];
57
- const npmrcPath = resolve(homedir(), ".npmrc");
58
- if (existsSync(npmrcPath)) {
59
- volumes.push("-v", `${npmrcPath}:/tmp/host-npmrc:ro`);
60
- envArgs.push("-e", "NPM_CONFIG_USERCONFIG=/tmp/host-npmrc");
61
- }
62
- const auth0ConfigDir = resolve(homedir(), ".config/auth0");
63
- mkdirSync(auth0ConfigDir, {
64
- recursive: true
65
- });
66
- volumes.push("-v", `${auth0ConfigDir}:${builderHome}/.config/auth0`);
67
- const userArgs = [];
68
- if (runAsHostUser) {
69
- userArgs.push("--user", `${hostUid}:${hostGid}`);
70
- } else if (hostUid != null) {
71
- envArgs.push("-e", `HOST_UID=${hostUid}`);
72
- if (hostGid != null) envArgs.push("-e", `HOST_GID=${hostGid}`);
73
- }
74
- console.log(kind === "auth0" ? " Running Auth0 CLI in the scaffolder image...\n" : " Running scaffolding in a sandboxed container...\n");
75
- const ttyFlags = process.stdin.isTTY ? [
76
- "-it"
77
- ] : [
78
- "-i"
79
- ];
80
- const result = spawnSync("docker", [
81
- "run",
82
- "--rm",
83
- ...ttyFlags,
84
- ...userArgs,
85
- ...volumes,
86
- ...envArgs,
87
- "-w",
88
- "/workspace",
89
- BUILDER_IMAGE,
90
- ...containerArgv
91
- ], {
92
- stdio: "inherit"
93
- });
94
- if (result.status === 0 && kind === "scaffold") {
95
- console.log(`\n Scaffold complete!\n\n Open your project:\n\n code ${targetDir}\n`);
96
- }
97
- process.exit(result.status ?? 0);
98
- }
@@ -1,30 +0,0 @@
1
- import { createRequire } from "node:module";
2
- import { dirname, join } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- const _require = createRequire(import.meta.url);
5
- const DEFAULT_CREATE_VERSION = "0.0.1-dev";
6
- const DEFAULT_CREATE_IMAGE_REPOSITORY = "ghcr.io/typesmiths/decohere/create";
7
- function resolveCreateMetadata() {
8
- let dir = dirname(fileURLToPath(import.meta.url));
9
- for(let i = 0; i < 5; i++){
10
- try {
11
- const pkg = _require(join(dir, "package.json"));
12
- if (pkg.name === "@decohere/create") {
13
- return {
14
- version: pkg.version ?? DEFAULT_CREATE_VERSION,
15
- imageRepository: pkg.decohere?.dockerImageRepository ?? DEFAULT_CREATE_IMAGE_REPOSITORY
16
- };
17
- }
18
- } catch {}
19
- const parent = dirname(dir);
20
- if (parent === dir) break;
21
- dir = parent;
22
- }
23
- return {
24
- version: DEFAULT_CREATE_VERSION,
25
- imageRepository: DEFAULT_CREATE_IMAGE_REPOSITORY
26
- };
27
- }
28
- const createMetadata = resolveCreateMetadata();
29
- export const CREATE_VERSION = createMetadata.version;
30
- export const CREATE_IMAGE_REPOSITORY = createMetadata.imageRepository;
@@ -1,177 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Vendor `@decohere/scaffold` for the builder image: resolve `@decohere/*` from
4
- * dist/release via `file:` (not `overrides`), `npm install --install-links`,
5
- * then tar the installed tree including `node_modules`. `--install-links`
6
- * materializes `file:` packages (and their deps) instead of leaving symlinks
7
- * whose nested installs live outside the packed directory.
8
- */
9
- import { spawnSync } from "node:child_process";
10
- import { readdirSync, readFileSync, writeFileSync } from "node:fs";
11
- import { dirname, join, relative, resolve } from "node:path";
12
- import { fileURLToPath } from "node:url";
13
-
14
- /**
15
- * @typedef {{ name: string, dir: string }} WorkspacePackage
16
- */
17
-
18
- /**
19
- * @param {string} rootDir
20
- * @returns {WorkspacePackage[]}
21
- */
22
- export function collectWorkspacePackages(rootDir) {
23
- /** @type {WorkspacePackage[]} */
24
- const found = [];
25
- const walk = (dir) => {
26
- let entries;
27
- try {
28
- entries = readdirSync(dir, { withFileTypes: true });
29
- } catch {
30
- return;
31
- }
32
- for (const entry of entries) {
33
- if (entry.name === "node_modules" || entry.name === ".git") continue;
34
- const path = join(dir, entry.name);
35
- if (entry.isDirectory()) {
36
- walk(path);
37
- continue;
38
- }
39
- if (entry.name !== "package.json") continue;
40
- const pkg = JSON.parse(readFileSync(path, "utf8"));
41
- if (typeof pkg.name === "string" && pkg.name.startsWith("@decohere/")) {
42
- found.push({ name: pkg.name, dir });
43
- }
44
- }
45
- };
46
- walk(rootDir);
47
- return found;
48
- }
49
-
50
- /**
51
- * @param {string} fromDir
52
- * @param {string} pkgDir
53
- */
54
- export function fileSpec(fromDir, pkgDir) {
55
- let rel = relative(fromDir, pkgDir) || ".";
56
- rel = rel.replaceAll("\\", "/");
57
- if (!rel.startsWith(".")) rel = `./${rel}`;
58
- return `file:${rel}`;
59
- }
60
-
61
- /**
62
- * Rewrite `@decohere/*` dependency specs to local `file:` paths.
63
- * Must mutate `dependencies` (not `overrides`) — npm throws EOVERRIDE when an
64
- * override conflicts with a direct dependency.
65
- *
66
- * @param {Record<string, unknown>} pkg
67
- * @param {string} fromDir
68
- * @param {WorkspacePackage[]} packages
69
- */
70
- export function rewriteDecohereDepsToFile(pkg, fromDir, packages) {
71
- const byName = new Map(packages.map((item) => [item.name, item.dir]));
72
- const from = resolve(fromDir);
73
- const rewrite = (deps) => {
74
- if (deps == null || typeof deps !== "object" || Array.isArray(deps)) return deps;
75
- const next = { .../** @type {Record<string, unknown>} */ (deps) };
76
- for (const name of Object.keys(next)) {
77
- const dir = byName.get(name);
78
- if (dir == null || resolve(dir) === from) continue;
79
- next[name] = fileSpec(fromDir, dir);
80
- }
81
- return next;
82
- };
83
- return {
84
- ...pkg,
85
- dependencies: rewrite(pkg.dependencies),
86
- optionalDependencies: rewrite(pkg.optionalDependencies),
87
- };
88
- }
89
-
90
- function writeJson(path, value) {
91
- writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
92
- }
93
-
94
- function runNpm(cwd, args) {
95
- const result = spawnSync("npm", args, { cwd, encoding: "utf8" });
96
- if (result.status !== 0) {
97
- throw new Error(
98
- `npm ${args.join(" ")} failed (exit ${result.status}):\n${result.stderr}${result.stdout}`,
99
- );
100
- }
101
- return result.stdout.trim();
102
- }
103
-
104
- function packInstalledTree(outDir, dest) {
105
- const result = spawnSync(
106
- "tar",
107
- ["--create", "--gzip", "--dereference", "--file", dest, "-C", outDir, "."],
108
- { encoding: "utf8" },
109
- );
110
- if (result.status !== 0) {
111
- throw new Error(`tar failed (exit ${result.status}):\n${result.stderr}${result.stdout}`);
112
- }
113
- }
114
-
115
- export function packBuilderTgz(options) {
116
- const outDir = resolve(options.outDir);
117
- const workspaceOut = resolve(options.workspaceOut);
118
- const dest = resolve(options.dest);
119
- const packageJsonPath = join(outDir, "package.json");
120
- const packages = collectWorkspacePackages(workspaceOut);
121
- const originals = packages.map((pkg) => {
122
- const path = join(pkg.dir, "package.json");
123
- return { path, original: JSON.parse(readFileSync(path, "utf8")) };
124
- });
125
- const createOriginal = originals.find((entry) => entry.path === packageJsonPath)?.original;
126
- if (createOriginal == null) {
127
- throw new Error(`No @decohere package.json at ${packageJsonPath}`);
128
- }
129
-
130
- try {
131
- for (const { path, original } of originals) {
132
- writeJson(path, rewriteDecohereDepsToFile(original, dirname(path), packages));
133
- }
134
- runNpm(outDir, ["install", "--omit=dev", "--ignore-scripts", "--install-links"]);
135
- } finally {
136
- for (const { path, original } of originals) {
137
- writeJson(path, original);
138
- }
139
- }
140
-
141
- packInstalledTree(outDir, dest);
142
- return dest;
143
- }
144
-
145
- function parseArgs(argv) {
146
- /** @type {Record<string, string>} */
147
- const parsed = {};
148
- for (let i = 0; i < argv.length; i++) {
149
- const arg = argv[i];
150
- if (arg == null || !arg.startsWith("--")) continue;
151
- const key = arg.slice(2);
152
- const value = argv[i + 1];
153
- if (value == null || value.startsWith("--")) {
154
- throw new Error(`Missing value for --${key}`);
155
- }
156
- parsed[key] = value;
157
- i++;
158
- }
159
- return parsed;
160
- }
161
-
162
- function main() {
163
- const args = parseArgs(process.argv.slice(2));
164
- const outDir = args["out-dir"];
165
- const workspaceOut = args["workspace-out"];
166
- const dest = args.dest;
167
- if (outDir == null || workspaceOut == null || dest == null) {
168
- throw new Error(
169
- "Usage: pack-builder-tgz.mjs --out-dir <dir> --workspace-out <dir> --dest <create.tgz>",
170
- );
171
- }
172
- packBuilderTgz({ outDir, workspaceOut, dest });
173
- }
174
-
175
- if (process.argv[1] != null && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
176
- main();
177
- }
@@ -1,3 +0,0 @@
1
- export type { LaunchKind, LaunchPlan } from "./resolve-launch.js";
2
- export { containerArgvFromHost, resolveLaunch, toProductArgv } from "./resolve-launch.js";
3
- export { runInBuilder } from "./runner.js";
@@ -1,20 +0,0 @@
1
- export type LaunchKind = "scaffold" | "auth0";
2
- export type LaunchPlan = {
3
- targetDir: string;
4
- containerArgv: string[];
5
- projectName: string;
6
- kind: LaunchKind;
7
- };
8
- /**
9
- * Map host / npm-create argv onto the product CLI (`create webapi` / `add api`).
10
- * `npm create @decohere webapi` already says “create”, so we prepend `create`
11
- * rather than making users type `create create webapi`.
12
- */
13
- export declare function toProductArgv(tokens: string[]): string[];
14
- export declare function containerArgvFromHost(argv: string[]): string[];
15
- /**
16
- * Host argv → directory to mount and argv for the in-image `decohere` entrypoint.
17
- * Positional `webapi my-app` / `create webapi my-app` wins over `-d` (npm treats `-d`
18
- * as its own loglevel).
19
- */
20
- export declare function resolveLaunch(argv: string[], cwd?: string): LaunchPlan;
@@ -1,5 +0,0 @@
1
- /**
2
- * Pull/run the Decohere scaffolder image. Host `@decohere/create` does not load
3
- * the `@decohere/scaffold` dependency tree — that lives in the image only.
4
- */
5
- export declare function runInBuilder(argv: string[]): never;
@@ -1,2 +0,0 @@
1
- export declare const CREATE_VERSION: string;
2
- export declare const CREATE_IMAGE_REPOSITORY: string;