@mondaydotcomorg/z2h-cli 0.1.0 → 0.1.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/commands/__tests__/create-workspace.test.d.ts +2 -0
- package/dist/commands/__tests__/create-workspace.test.d.ts.map +1 -0
- package/dist/commands/__tests__/create.test.d.ts +2 -0
- package/dist/commands/__tests__/create.test.d.ts.map +1 -0
- package/dist/commands/create-workspace.d.ts +5 -0
- package/dist/commands/create-workspace.d.ts.map +1 -0
- package/dist/commands/create-workspace.js +80 -0
- package/dist/commands/create.d.ts +7 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +97 -0
- package/dist/constants.d.ts +1 -14
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +11 -34
- package/dist/esm/commands/__tests__/create-workspace.test.d.ts +2 -0
- package/dist/esm/commands/__tests__/create-workspace.test.d.ts.map +1 -0
- package/dist/esm/commands/__tests__/create.test.d.ts +2 -0
- package/dist/esm/commands/__tests__/create.test.d.ts.map +1 -0
- package/dist/esm/commands/create-workspace.d.ts +5 -0
- package/dist/esm/commands/create-workspace.d.ts.map +1 -0
- package/dist/esm/commands/create-workspace.mjs +74 -0
- package/dist/esm/commands/create.d.ts +7 -0
- package/dist/esm/commands/create.d.ts.map +1 -0
- package/dist/esm/commands/create.mjs +91 -0
- package/dist/esm/constants.d.ts +1 -14
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.mjs +11 -32
- package/dist/esm/index.mjs +28 -0
- package/dist/esm/shadow/__tests__/consumer-pkg.test.d.ts +2 -0
- package/dist/esm/shadow/__tests__/consumer-pkg.test.d.ts.map +1 -0
- package/dist/esm/shadow/__tests__/merge-package-json.test.d.ts +2 -0
- package/dist/esm/shadow/__tests__/merge-package-json.test.d.ts.map +1 -0
- package/dist/esm/shadow/consumer-pkg.d.ts +5 -15
- package/dist/esm/shadow/consumer-pkg.d.ts.map +1 -1
- package/dist/esm/shadow/consumer-pkg.mjs +11 -72
- package/dist/esm/shadow/merge-package-json.d.ts +10 -4
- package/dist/esm/shadow/merge-package-json.d.ts.map +1 -1
- package/dist/esm/shadow/merge-package-json.mjs +12 -11
- package/dist/esm/shadow/sync.mjs +2 -2
- package/dist/esm/templates/app/claude-settings.mjs +10 -0
- package/dist/esm/types.d.ts +0 -1
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/util/__tests__/templates.test.d.ts +2 -0
- package/dist/esm/util/__tests__/templates.test.d.ts.map +1 -0
- package/dist/esm/util/__tests__/workspace-templates-shipped.test.d.ts +2 -0
- package/dist/esm/util/__tests__/workspace-templates-shipped.test.d.ts.map +1 -0
- package/dist/esm/util/__tests__/workspace.test.d.ts +2 -0
- package/dist/esm/util/__tests__/workspace.test.d.ts.map +1 -0
- package/dist/esm/util/s3/upload.mjs +1 -1
- package/dist/esm/util/templates.d.ts +22 -0
- package/dist/esm/util/templates.d.ts.map +1 -0
- package/dist/esm/util/templates.mjs +36 -0
- package/dist/esm/util/workspace.d.ts +20 -0
- package/dist/esm/util/workspace.d.ts.map +1 -0
- package/dist/esm/util/workspace.mjs +46 -0
- package/dist/index.js +28 -0
- package/dist/shadow/__tests__/consumer-pkg.test.d.ts +2 -0
- package/dist/shadow/__tests__/consumer-pkg.test.d.ts.map +1 -0
- package/dist/shadow/__tests__/merge-package-json.test.d.ts +2 -0
- package/dist/shadow/__tests__/merge-package-json.test.d.ts.map +1 -0
- package/dist/shadow/consumer-pkg.d.ts +5 -15
- package/dist/shadow/consumer-pkg.d.ts.map +1 -1
- package/dist/shadow/consumer-pkg.js +10 -72
- package/dist/shadow/merge-package-json.d.ts +10 -4
- package/dist/shadow/merge-package-json.d.ts.map +1 -1
- package/dist/shadow/merge-package-json.js +11 -10
- package/dist/shadow/sync.js +2 -2
- package/dist/templates/app/claude-settings.js +13 -0
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/util/__tests__/templates.test.d.ts +2 -0
- package/dist/util/__tests__/templates.test.d.ts.map +1 -0
- package/dist/util/__tests__/workspace-templates-shipped.test.d.ts +2 -0
- package/dist/util/__tests__/workspace-templates-shipped.test.d.ts.map +1 -0
- package/dist/util/__tests__/workspace.test.d.ts +2 -0
- package/dist/util/__tests__/workspace.test.d.ts.map +1 -0
- package/dist/util/s3/upload.js +1 -1
- package/dist/util/templates.d.ts +22 -0
- package/dist/util/templates.d.ts.map +1 -0
- package/dist/util/templates.js +45 -0
- package/dist/util/workspace.d.ts +20 -0
- package/dist/util/workspace.d.ts.map +1 -0
- package/dist/util/workspace.js +57 -0
- package/package.json +5 -3
- package/src/commands/__tests__/create-workspace.test.ts +78 -0
- package/src/commands/__tests__/create.test.ts +111 -0
- package/src/commands/create-workspace.ts +85 -0
- package/src/commands/create.ts +113 -0
- package/src/constants.ts +11 -34
- package/src/index.ts +28 -0
- package/src/shadow/__tests__/consumer-pkg.test.ts +56 -0
- package/src/shadow/__tests__/merge-package-json.test.ts +44 -0
- package/src/shadow/consumer-pkg.ts +10 -88
- package/src/shadow/merge-package-json.ts +12 -11
- package/src/shadow/sync.ts +2 -2
- package/src/templates/app/CLAUDE.md +72 -0
- package/src/templates/app/claude-settings.json +7 -0
- package/src/templates/app/default-index.tsx.tmpl +21 -0
- package/src/templates/app/gitignore +4 -0
- package/src/templates/app/html-index.tsx.tmpl +21 -0
- package/src/templates/app/package.json.tmpl +13 -0
- package/src/templates/workspace/README.md +39 -0
- package/src/templates/workspace/gitignore +23 -0
- package/src/templates/workspace/npmrc +3 -0
- package/src/templates/workspace/nvmrc +1 -0
- package/src/templates/workspace/package.json.tmpl +23 -0
- package/src/templates/workspace/yarn-releases/yarn-4.5.1.cjs +934 -0
- package/src/templates/workspace/yarnrc.yml +7 -0
- package/src/types.ts +4 -1
- package/src/util/__tests__/templates.test.ts +27 -0
- package/src/util/__tests__/workspace-templates-shipped.test.ts +35 -0
- package/src/util/__tests__/workspace.test.ts +65 -0
- package/src/util/s3/upload.ts +1 -1
- package/src/util/templates.ts +37 -0
- package/src/util/workspace.ts +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-workspace.test.d.ts","sourceRoot":"","sources":["../../../src/commands/__tests__/create-workspace.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.test.d.ts","sourceRoot":"","sources":["../../../src/commands/__tests__/create.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiBD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDxF"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const promises = require('node:fs/promises');
|
|
5
|
+
const fsExtra = require('fs-extra');
|
|
6
|
+
const execa = require('execa');
|
|
7
|
+
const util_logger = require('../util/logger.js');
|
|
8
|
+
const util_workspace = require('../util/workspace.js');
|
|
9
|
+
const util_templates = require('../util/templates.js');
|
|
10
|
+
|
|
11
|
+
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
12
|
+
|
|
13
|
+
const path__default = /*#__PURE__*/_interopDefault(path);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Read the current z2h-cli version from its own package.json — the version
|
|
17
|
+
* that gets pinned into the workspace's devDependencies. That way the
|
|
18
|
+
* workspace's `@mondaydotcomorg/z2h-cli` always matches the version that
|
|
19
|
+
* bootstrapped it.
|
|
20
|
+
*/
|
|
21
|
+
async function readCurrentCliVersion() {
|
|
22
|
+
// util/templates.ts already locates `<package-root>/src/templates`. The
|
|
23
|
+
// package's own package.json sits two levels above templates/.
|
|
24
|
+
const templatesDir = util_templates.getTemplatesDir();
|
|
25
|
+
const pkgPath = path__default.default.resolve(templatesDir, '..', '..', 'package.json');
|
|
26
|
+
const pkg = (await fsExtra.readJson(pkgPath));
|
|
27
|
+
return `^${pkg.version}`;
|
|
28
|
+
}
|
|
29
|
+
async function createWorkspaceCommand(opts) {
|
|
30
|
+
if (opts.json) {
|
|
31
|
+
util_logger.setOutputMode('json');
|
|
32
|
+
}
|
|
33
|
+
const home = util_workspace.getWorkspaceHome();
|
|
34
|
+
const templatesDir = util_templates.getTemplatesDir();
|
|
35
|
+
const wsTemplatesDir = path__default.default.join(templatesDir, 'workspace');
|
|
36
|
+
// Refuse non-empty target.
|
|
37
|
+
if (await fsExtra.pathExists(home)) {
|
|
38
|
+
const entries = await fsExtra.readdir(home);
|
|
39
|
+
if (entries.length > 0) {
|
|
40
|
+
throw new Error(`${home} is non-empty. Wipe it before running create-workspace.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
await fsExtra.ensureDir(home);
|
|
45
|
+
}
|
|
46
|
+
const [cliVersion, pkgRaw] = await Promise.all([
|
|
47
|
+
readCurrentCliVersion(),
|
|
48
|
+
promises.readFile(path__default.default.join(wsTemplatesDir, 'package.json.tmpl'), 'utf8'),
|
|
49
|
+
]);
|
|
50
|
+
// Sources have plain names (gitignore, yarnrc.yml, nvmrc, npmrc) so they
|
|
51
|
+
// aren't interpreted as the active config files of *this* package; we
|
|
52
|
+
// rename to dotfiles at the destination.
|
|
53
|
+
//
|
|
54
|
+
// Yarn berry ships inline at .yarn/releases/. The workspace's .yarnrc.yml
|
|
55
|
+
// sets `yarnPath` to point here, so any `yarn` invocation (system classic
|
|
56
|
+
// or otherwise) reads the rc, delegates to this binary, and runs as 4.5.1
|
|
57
|
+
// — no corepack, no global pin needed. Mirrors how bigbrain-z2h ships its
|
|
58
|
+
// own yarn release.
|
|
59
|
+
await Promise.all([
|
|
60
|
+
fsExtra.writeFile(path__default.default.join(home, 'package.json'), util_templates.renderTemplate(pkgRaw, { __Z2H_CLI_VERSION__: cliVersion })),
|
|
61
|
+
fsExtra.copy(path__default.default.join(wsTemplatesDir, 'gitignore'), path__default.default.join(home, '.gitignore')),
|
|
62
|
+
fsExtra.copy(path__default.default.join(wsTemplatesDir, 'yarnrc.yml'), path__default.default.join(home, '.yarnrc.yml')),
|
|
63
|
+
fsExtra.copy(path__default.default.join(wsTemplatesDir, 'nvmrc'), path__default.default.join(home, '.nvmrc')),
|
|
64
|
+
fsExtra.copy(path__default.default.join(wsTemplatesDir, 'npmrc'), path__default.default.join(home, '.npmrc')),
|
|
65
|
+
fsExtra.copy(path__default.default.join(wsTemplatesDir, 'README.md'), path__default.default.join(home, 'README.md')),
|
|
66
|
+
fsExtra.copy(path__default.default.join(wsTemplatesDir, 'yarn-releases', 'yarn-4.5.1.cjs'), path__default.default.join(home, '.yarn', 'releases', 'yarn-4.5.1.cjs')),
|
|
67
|
+
]);
|
|
68
|
+
util_logger.info(`bootstrapping workspace at ${home}`);
|
|
69
|
+
await execa.execa('yarn', ['install'], {
|
|
70
|
+
cwd: home,
|
|
71
|
+
stdio: 'inherit',
|
|
72
|
+
});
|
|
73
|
+
util_logger.output(`[z2h-cli] workspace ready at ${home}`, {
|
|
74
|
+
ok: true,
|
|
75
|
+
workspace: home,
|
|
76
|
+
z2hCliVersion: cliVersion,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
exports.createWorkspaceCommand = createWorkspaceCommand;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA0BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EvF"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const promises = require('node:fs/promises');
|
|
5
|
+
const fsExtra = require('fs-extra');
|
|
6
|
+
const execa = require('execa');
|
|
7
|
+
const util_logger = require('../util/logger.js');
|
|
8
|
+
const util_workspace = require('../util/workspace.js');
|
|
9
|
+
const util_templates = require('../util/templates.js');
|
|
10
|
+
|
|
11
|
+
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
12
|
+
|
|
13
|
+
const path__default = /*#__PURE__*/_interopDefault(path);
|
|
14
|
+
|
|
15
|
+
const APP_NAME_RE = /^[a-z][a-z0-9-]{1,49}$/;
|
|
16
|
+
/**
|
|
17
|
+
* Convert kebab-case to PascalCase. `demo-app` → `DemoApp`.
|
|
18
|
+
*/
|
|
19
|
+
function pascalCase(input) {
|
|
20
|
+
return input
|
|
21
|
+
.split('-')
|
|
22
|
+
.filter(Boolean)
|
|
23
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
24
|
+
.join('');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Returns true iff `dir` either does not exist or is an empty directory.
|
|
28
|
+
*/
|
|
29
|
+
async function isDirEmpty(dir) {
|
|
30
|
+
if (!(await fsExtra.pathExists(dir))) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
const entries = await fsExtra.readdir(dir);
|
|
34
|
+
return entries.length === 0;
|
|
35
|
+
}
|
|
36
|
+
async function createCommand(appName, opts) {
|
|
37
|
+
if (opts.json) {
|
|
38
|
+
util_logger.setOutputMode('json');
|
|
39
|
+
}
|
|
40
|
+
// Validate workspace.
|
|
41
|
+
const workspace = await util_workspace.assertWorkspace();
|
|
42
|
+
// Validate app name.
|
|
43
|
+
if (!APP_NAME_RE.test(appName)) {
|
|
44
|
+
throw new Error(`App name "${appName}" is invalid. Use lowercase kebab-case (a-z, 0-9, -), ` +
|
|
45
|
+
`2-50 chars, starting with a letter.`);
|
|
46
|
+
}
|
|
47
|
+
// Resolve template.
|
|
48
|
+
// `--html-file` implies `--template html-embed` unless the user already picked one.
|
|
49
|
+
const template = (opts.template ?? (opts.htmlFile ? 'html-embed' : 'default'));
|
|
50
|
+
if (!util_templates.APP_TEMPLATES.includes(template)) {
|
|
51
|
+
throw new Error(`Unknown template "${template}". Available: ${util_templates.APP_TEMPLATES.join(', ')}.`);
|
|
52
|
+
}
|
|
53
|
+
if (opts.htmlFile && !(await fsExtra.pathExists(opts.htmlFile))) {
|
|
54
|
+
throw new Error(`HTML file does not exist: ${opts.htmlFile}`);
|
|
55
|
+
}
|
|
56
|
+
// Validate target dir.
|
|
57
|
+
const appDir = path__default.default.join(workspace, appName);
|
|
58
|
+
if (!(await isDirEmpty(appDir))) {
|
|
59
|
+
throw new Error(`${appDir} is non-empty. Pick a different name or wipe it first.`);
|
|
60
|
+
}
|
|
61
|
+
// Compute substitutions.
|
|
62
|
+
const vars = {
|
|
63
|
+
__APP_NAME__: appName,
|
|
64
|
+
__APP_COMPONENT__: pascalCase(appName),
|
|
65
|
+
};
|
|
66
|
+
const appTemplatesDir = path__default.default.join(util_templates.getTemplatesDir(), 'app');
|
|
67
|
+
await fsExtra.ensureDir(path__default.default.join(appDir, 'src'));
|
|
68
|
+
await fsExtra.ensureDir(path__default.default.join(appDir, '.claude'));
|
|
69
|
+
// package.json (templated).
|
|
70
|
+
const pkgRaw = await promises.readFile(path__default.default.join(appTemplatesDir, 'package.json.tmpl'), 'utf8');
|
|
71
|
+
await fsExtra.writeFile(path__default.default.join(appDir, 'package.json'), util_templates.renderTemplate(pkgRaw, vars));
|
|
72
|
+
// src/index.tsx (templated; choice driven by template).
|
|
73
|
+
const indexTemplate = template === 'html-embed' ? 'html-index.tsx.tmpl' : 'default-index.tsx.tmpl';
|
|
74
|
+
const indexRaw = await promises.readFile(path__default.default.join(appTemplatesDir, indexTemplate), 'utf8');
|
|
75
|
+
await fsExtra.writeFile(path__default.default.join(appDir, 'src', 'index.tsx'), util_templates.renderTemplate(indexRaw, vars));
|
|
76
|
+
// Copy verbatim files.
|
|
77
|
+
await fsExtra.copy(path__default.default.join(appTemplatesDir, 'gitignore'), path__default.default.join(appDir, '.gitignore'));
|
|
78
|
+
await fsExtra.copy(path__default.default.join(appTemplatesDir, 'claude-settings.json'), path__default.default.join(appDir, '.claude', 'settings.json'));
|
|
79
|
+
await fsExtra.copy(path__default.default.join(appTemplatesDir, 'CLAUDE.md'), path__default.default.join(appDir, 'CLAUDE.md'));
|
|
80
|
+
// html-embed: also copy the source HTML.
|
|
81
|
+
if (template === 'html-embed' && opts.htmlFile) {
|
|
82
|
+
await fsExtra.copy(opts.htmlFile, path__default.default.join(appDir, 'src', 'page.html'));
|
|
83
|
+
}
|
|
84
|
+
util_logger.info(`installing into workspace at ${workspace}`);
|
|
85
|
+
await execa.execa('yarn', ['install'], {
|
|
86
|
+
cwd: workspace,
|
|
87
|
+
stdio: 'inherit',
|
|
88
|
+
});
|
|
89
|
+
util_logger.output(`[z2h-cli] app ready at ${appDir}`, {
|
|
90
|
+
ok: true,
|
|
91
|
+
appDir,
|
|
92
|
+
appName,
|
|
93
|
+
template,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
exports.createCommand = createCommand;
|
package/dist/constants.d.ts
CHANGED
|
@@ -3,21 +3,8 @@
|
|
|
3
3
|
* one place) stay local to their file to keep this index small.
|
|
4
4
|
*/
|
|
5
5
|
export declare const SHADOW_DIR_NAME = ".zth";
|
|
6
|
-
/**
|
|
7
|
-
* Protected runtime deps that MUST resolve to a single instance across the
|
|
8
|
-
* wrapper (.zth) and the consumer's src. Declared as peerDependencies in
|
|
9
|
-
* the shadow pkg so yarn hoists them from the workspace root — which is
|
|
10
|
-
* why we enforce their presence in the consumer's own package.json.
|
|
11
|
-
*/
|
|
12
|
-
export declare const PROTECTED_DEPS: Record<string, string>;
|
|
13
|
-
/**
|
|
14
|
-
* Protected dev deps. Same idempotent treatment as PROTECTED_DEPS but live
|
|
15
|
-
* in the consumer's `devDependencies`. These give the LLM-authored consumer
|
|
16
|
-
* code access to monday.com platform types out of the box.
|
|
17
|
-
*/
|
|
18
|
-
export declare const PROTECTED_DEV_DEPS: Record<string, string>;
|
|
19
|
-
export declare const WORKSPACE_DEV_DEPS: Record<string, string>;
|
|
20
6
|
export declare const SHADOW_SCRIPTS: Record<string, string>;
|
|
7
|
+
export declare const SHADOW_DEV_DEPS: Record<string, string>;
|
|
21
8
|
export declare const MIN_PORT = 13000;
|
|
22
9
|
export declare const MAX_PORT = 19999;
|
|
23
10
|
export declare const GITIGNORE_ENTRIES: string[];
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGjD,CAAC;AAQF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAG3C,eAAO,MAAM,YAAY,UAIxB,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -6,41 +6,20 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
6
6
|
*/
|
|
7
7
|
// ─────────── Shadow dir layout ───────────
|
|
8
8
|
const SHADOW_DIR_NAME = '.zth';
|
|
9
|
-
// ───────────
|
|
10
|
-
/**
|
|
11
|
-
* Protected runtime deps that MUST resolve to a single instance across the
|
|
12
|
-
* wrapper (.zth) and the consumer's src. Declared as peerDependencies in
|
|
13
|
-
* the shadow pkg so yarn hoists them from the workspace root — which is
|
|
14
|
-
* why we enforce their presence in the consumer's own package.json.
|
|
15
|
-
*/
|
|
16
|
-
const PROTECTED_DEPS = {
|
|
17
|
-
react: '^18.2.0',
|
|
18
|
-
'react-dom': '^18.2.0',
|
|
19
|
-
'react-error-boundary': '^3.1.3',
|
|
20
|
-
'@mondaydotcomorg/trident-runtime': '^1.24.1',
|
|
21
|
-
'@vibe/core': '^4.0.1',
|
|
22
|
-
};
|
|
23
|
-
/**
|
|
24
|
-
* Protected dev deps. Same idempotent treatment as PROTECTED_DEPS but live
|
|
25
|
-
* in the consumer's `devDependencies`. These give the LLM-authored consumer
|
|
26
|
-
* code access to monday.com platform types out of the box.
|
|
27
|
-
*/
|
|
28
|
-
const PROTECTED_DEV_DEPS = {
|
|
29
|
-
'@mondaydotcomorg/mf-api-types': '^0.1.1',
|
|
30
|
-
'@mondaydotcomorg/bigbrain-types': '^0.3.3',
|
|
31
|
-
};
|
|
32
|
-
// ─────────── Shadow pkg template ───────────
|
|
33
|
-
// TODO — Add trident mf-types / bigbrain-types opt-in.
|
|
34
|
-
const WORKSPACE_DEV_DEPS = {
|
|
35
|
-
'@mondaydotcomorg/trident-toolkit': '^2.9.25',
|
|
36
|
-
'@types/react': '^18.0.14',
|
|
37
|
-
'@types/react-dom': '^18.0.5',
|
|
38
|
-
typescript: '^5.7.2',
|
|
39
|
-
};
|
|
9
|
+
// ─────────── Shadow scripts ───────
|
|
40
10
|
const SHADOW_SCRIPTS = {
|
|
41
11
|
start: 'trident start',
|
|
42
12
|
build: 'trident build',
|
|
43
13
|
};
|
|
14
|
+
// ─────────── Shadow dev deps ───────
|
|
15
|
+
// Yarn berry only wires a workspace member's `node_modules/.bin/` PATH
|
|
16
|
+
// for packages that member explicitly declares. The shadow's scripts
|
|
17
|
+
// invoke `trident`, so trident-toolkit must be declared here for the
|
|
18
|
+
// bin to resolve. `*` is fine — yarn workspaces resolve the actual
|
|
19
|
+
// version from the workspace root's pinned entry.
|
|
20
|
+
const SHADOW_DEV_DEPS = {
|
|
21
|
+
'@mondaydotcomorg/trident-toolkit': '*',
|
|
22
|
+
};
|
|
44
23
|
// ─────────── Auto-allocated dev port range ────
|
|
45
24
|
// High enough to dodge common dev defaults (3000 Next, 5173 Vite, 8080).
|
|
46
25
|
// Collisions within the 7k-port pool are rare for POC; if trident can't
|
|
@@ -59,9 +38,7 @@ const YARNRC_LINES = [
|
|
|
59
38
|
exports.GITIGNORE_ENTRIES = GITIGNORE_ENTRIES;
|
|
60
39
|
exports.MAX_PORT = MAX_PORT;
|
|
61
40
|
exports.MIN_PORT = MIN_PORT;
|
|
62
|
-
exports.
|
|
63
|
-
exports.PROTECTED_DEV_DEPS = PROTECTED_DEV_DEPS;
|
|
41
|
+
exports.SHADOW_DEV_DEPS = SHADOW_DEV_DEPS;
|
|
64
42
|
exports.SHADOW_DIR_NAME = SHADOW_DIR_NAME;
|
|
65
43
|
exports.SHADOW_SCRIPTS = SHADOW_SCRIPTS;
|
|
66
|
-
exports.WORKSPACE_DEV_DEPS = WORKSPACE_DEV_DEPS;
|
|
67
44
|
exports.YARNRC_LINES = YARNRC_LINES;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-workspace.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/__tests__/create-workspace.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.test.d.ts","sourceRoot":"","sources":["../../../../src/commands/__tests__/create.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-workspace.d.ts","sourceRoot":"","sources":["../../../src/commands/create-workspace.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAiBD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyDxF"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { pathExists, readdir, ensureDir, writeFile, copy, readJson } from 'fs-extra';
|
|
4
|
+
import { execa } from 'execa';
|
|
5
|
+
import { setOutputMode, info, output } from '../util/logger.mjs';
|
|
6
|
+
import { getWorkspaceHome } from '../util/workspace.mjs';
|
|
7
|
+
import { getTemplatesDir, renderTemplate } from '../util/templates.mjs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Read the current z2h-cli version from its own package.json — the version
|
|
11
|
+
* that gets pinned into the workspace's devDependencies. That way the
|
|
12
|
+
* workspace's `@mondaydotcomorg/z2h-cli` always matches the version that
|
|
13
|
+
* bootstrapped it.
|
|
14
|
+
*/
|
|
15
|
+
async function readCurrentCliVersion() {
|
|
16
|
+
// util/templates.ts already locates `<package-root>/src/templates`. The
|
|
17
|
+
// package's own package.json sits two levels above templates/.
|
|
18
|
+
const templatesDir = getTemplatesDir();
|
|
19
|
+
const pkgPath = path.resolve(templatesDir, '..', '..', 'package.json');
|
|
20
|
+
const pkg = (await readJson(pkgPath));
|
|
21
|
+
return `^${pkg.version}`;
|
|
22
|
+
}
|
|
23
|
+
async function createWorkspaceCommand(opts) {
|
|
24
|
+
if (opts.json) {
|
|
25
|
+
setOutputMode('json');
|
|
26
|
+
}
|
|
27
|
+
const home = getWorkspaceHome();
|
|
28
|
+
const templatesDir = getTemplatesDir();
|
|
29
|
+
const wsTemplatesDir = path.join(templatesDir, 'workspace');
|
|
30
|
+
// Refuse non-empty target.
|
|
31
|
+
if (await pathExists(home)) {
|
|
32
|
+
const entries = await readdir(home);
|
|
33
|
+
if (entries.length > 0) {
|
|
34
|
+
throw new Error(`${home} is non-empty. Wipe it before running create-workspace.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
await ensureDir(home);
|
|
39
|
+
}
|
|
40
|
+
const [cliVersion, pkgRaw] = await Promise.all([
|
|
41
|
+
readCurrentCliVersion(),
|
|
42
|
+
readFile(path.join(wsTemplatesDir, 'package.json.tmpl'), 'utf8'),
|
|
43
|
+
]);
|
|
44
|
+
// Sources have plain names (gitignore, yarnrc.yml, nvmrc, npmrc) so they
|
|
45
|
+
// aren't interpreted as the active config files of *this* package; we
|
|
46
|
+
// rename to dotfiles at the destination.
|
|
47
|
+
//
|
|
48
|
+
// Yarn berry ships inline at .yarn/releases/. The workspace's .yarnrc.yml
|
|
49
|
+
// sets `yarnPath` to point here, so any `yarn` invocation (system classic
|
|
50
|
+
// or otherwise) reads the rc, delegates to this binary, and runs as 4.5.1
|
|
51
|
+
// — no corepack, no global pin needed. Mirrors how bigbrain-z2h ships its
|
|
52
|
+
// own yarn release.
|
|
53
|
+
await Promise.all([
|
|
54
|
+
writeFile(path.join(home, 'package.json'), renderTemplate(pkgRaw, { __Z2H_CLI_VERSION__: cliVersion })),
|
|
55
|
+
copy(path.join(wsTemplatesDir, 'gitignore'), path.join(home, '.gitignore')),
|
|
56
|
+
copy(path.join(wsTemplatesDir, 'yarnrc.yml'), path.join(home, '.yarnrc.yml')),
|
|
57
|
+
copy(path.join(wsTemplatesDir, 'nvmrc'), path.join(home, '.nvmrc')),
|
|
58
|
+
copy(path.join(wsTemplatesDir, 'npmrc'), path.join(home, '.npmrc')),
|
|
59
|
+
copy(path.join(wsTemplatesDir, 'README.md'), path.join(home, 'README.md')),
|
|
60
|
+
copy(path.join(wsTemplatesDir, 'yarn-releases', 'yarn-4.5.1.cjs'), path.join(home, '.yarn', 'releases', 'yarn-4.5.1.cjs')),
|
|
61
|
+
]);
|
|
62
|
+
info(`bootstrapping workspace at ${home}`);
|
|
63
|
+
await execa('yarn', ['install'], {
|
|
64
|
+
cwd: home,
|
|
65
|
+
stdio: 'inherit',
|
|
66
|
+
});
|
|
67
|
+
output(`[z2h-cli] workspace ready at ${home}`, {
|
|
68
|
+
ok: true,
|
|
69
|
+
workspace: home,
|
|
70
|
+
z2hCliVersion: cliVersion,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { createWorkspaceCommand };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA0BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EvF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { pathExists, ensureDir, writeFile, copy, readdir } from 'fs-extra';
|
|
4
|
+
import { execa } from 'execa';
|
|
5
|
+
import { setOutputMode, info, output } from '../util/logger.mjs';
|
|
6
|
+
import { assertWorkspace } from '../util/workspace.mjs';
|
|
7
|
+
import { APP_TEMPLATES, getTemplatesDir, renderTemplate } from '../util/templates.mjs';
|
|
8
|
+
|
|
9
|
+
const APP_NAME_RE = /^[a-z][a-z0-9-]{1,49}$/;
|
|
10
|
+
/**
|
|
11
|
+
* Convert kebab-case to PascalCase. `demo-app` → `DemoApp`.
|
|
12
|
+
*/
|
|
13
|
+
function pascalCase(input) {
|
|
14
|
+
return input
|
|
15
|
+
.split('-')
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
18
|
+
.join('');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns true iff `dir` either does not exist or is an empty directory.
|
|
22
|
+
*/
|
|
23
|
+
async function isDirEmpty(dir) {
|
|
24
|
+
if (!(await pathExists(dir))) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
const entries = await readdir(dir);
|
|
28
|
+
return entries.length === 0;
|
|
29
|
+
}
|
|
30
|
+
async function createCommand(appName, opts) {
|
|
31
|
+
if (opts.json) {
|
|
32
|
+
setOutputMode('json');
|
|
33
|
+
}
|
|
34
|
+
// Validate workspace.
|
|
35
|
+
const workspace = await assertWorkspace();
|
|
36
|
+
// Validate app name.
|
|
37
|
+
if (!APP_NAME_RE.test(appName)) {
|
|
38
|
+
throw new Error(`App name "${appName}" is invalid. Use lowercase kebab-case (a-z, 0-9, -), ` +
|
|
39
|
+
`2-50 chars, starting with a letter.`);
|
|
40
|
+
}
|
|
41
|
+
// Resolve template.
|
|
42
|
+
// `--html-file` implies `--template html-embed` unless the user already picked one.
|
|
43
|
+
const template = (opts.template ?? (opts.htmlFile ? 'html-embed' : 'default'));
|
|
44
|
+
if (!APP_TEMPLATES.includes(template)) {
|
|
45
|
+
throw new Error(`Unknown template "${template}". Available: ${APP_TEMPLATES.join(', ')}.`);
|
|
46
|
+
}
|
|
47
|
+
if (opts.htmlFile && !(await pathExists(opts.htmlFile))) {
|
|
48
|
+
throw new Error(`HTML file does not exist: ${opts.htmlFile}`);
|
|
49
|
+
}
|
|
50
|
+
// Validate target dir.
|
|
51
|
+
const appDir = path.join(workspace, appName);
|
|
52
|
+
if (!(await isDirEmpty(appDir))) {
|
|
53
|
+
throw new Error(`${appDir} is non-empty. Pick a different name or wipe it first.`);
|
|
54
|
+
}
|
|
55
|
+
// Compute substitutions.
|
|
56
|
+
const vars = {
|
|
57
|
+
__APP_NAME__: appName,
|
|
58
|
+
__APP_COMPONENT__: pascalCase(appName),
|
|
59
|
+
};
|
|
60
|
+
const appTemplatesDir = path.join(getTemplatesDir(), 'app');
|
|
61
|
+
await ensureDir(path.join(appDir, 'src'));
|
|
62
|
+
await ensureDir(path.join(appDir, '.claude'));
|
|
63
|
+
// package.json (templated).
|
|
64
|
+
const pkgRaw = await readFile(path.join(appTemplatesDir, 'package.json.tmpl'), 'utf8');
|
|
65
|
+
await writeFile(path.join(appDir, 'package.json'), renderTemplate(pkgRaw, vars));
|
|
66
|
+
// src/index.tsx (templated; choice driven by template).
|
|
67
|
+
const indexTemplate = template === 'html-embed' ? 'html-index.tsx.tmpl' : 'default-index.tsx.tmpl';
|
|
68
|
+
const indexRaw = await readFile(path.join(appTemplatesDir, indexTemplate), 'utf8');
|
|
69
|
+
await writeFile(path.join(appDir, 'src', 'index.tsx'), renderTemplate(indexRaw, vars));
|
|
70
|
+
// Copy verbatim files.
|
|
71
|
+
await copy(path.join(appTemplatesDir, 'gitignore'), path.join(appDir, '.gitignore'));
|
|
72
|
+
await copy(path.join(appTemplatesDir, 'claude-settings.json'), path.join(appDir, '.claude', 'settings.json'));
|
|
73
|
+
await copy(path.join(appTemplatesDir, 'CLAUDE.md'), path.join(appDir, 'CLAUDE.md'));
|
|
74
|
+
// html-embed: also copy the source HTML.
|
|
75
|
+
if (template === 'html-embed' && opts.htmlFile) {
|
|
76
|
+
await copy(opts.htmlFile, path.join(appDir, 'src', 'page.html'));
|
|
77
|
+
}
|
|
78
|
+
info(`installing into workspace at ${workspace}`);
|
|
79
|
+
await execa('yarn', ['install'], {
|
|
80
|
+
cwd: workspace,
|
|
81
|
+
stdio: 'inherit',
|
|
82
|
+
});
|
|
83
|
+
output(`[z2h-cli] app ready at ${appDir}`, {
|
|
84
|
+
ok: true,
|
|
85
|
+
appDir,
|
|
86
|
+
appName,
|
|
87
|
+
template,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export { createCommand };
|
package/dist/esm/constants.d.ts
CHANGED
|
@@ -3,21 +3,8 @@
|
|
|
3
3
|
* one place) stay local to their file to keep this index small.
|
|
4
4
|
*/
|
|
5
5
|
export declare const SHADOW_DIR_NAME = ".zth";
|
|
6
|
-
/**
|
|
7
|
-
* Protected runtime deps that MUST resolve to a single instance across the
|
|
8
|
-
* wrapper (.zth) and the consumer's src. Declared as peerDependencies in
|
|
9
|
-
* the shadow pkg so yarn hoists them from the workspace root — which is
|
|
10
|
-
* why we enforce their presence in the consumer's own package.json.
|
|
11
|
-
*/
|
|
12
|
-
export declare const PROTECTED_DEPS: Record<string, string>;
|
|
13
|
-
/**
|
|
14
|
-
* Protected dev deps. Same idempotent treatment as PROTECTED_DEPS but live
|
|
15
|
-
* in the consumer's `devDependencies`. These give the LLM-authored consumer
|
|
16
|
-
* code access to monday.com platform types out of the box.
|
|
17
|
-
*/
|
|
18
|
-
export declare const PROTECTED_DEV_DEPS: Record<string, string>;
|
|
19
|
-
export declare const WORKSPACE_DEV_DEPS: Record<string, string>;
|
|
20
6
|
export declare const SHADOW_SCRIPTS: Record<string, string>;
|
|
7
|
+
export declare const SHADOW_DEV_DEPS: Record<string, string>;
|
|
21
8
|
export declare const MIN_PORT = 13000;
|
|
22
9
|
export declare const MAX_PORT = 19999;
|
|
23
10
|
export declare const GITIGNORE_ENTRIES: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAGjD,CAAC;AAQF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAG3C,eAAO,MAAM,YAAY,UAIxB,CAAC"}
|
package/dist/esm/constants.mjs
CHANGED
|
@@ -4,41 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
// ─────────── Shadow dir layout ───────────
|
|
6
6
|
const SHADOW_DIR_NAME = '.zth';
|
|
7
|
-
// ───────────
|
|
8
|
-
/**
|
|
9
|
-
* Protected runtime deps that MUST resolve to a single instance across the
|
|
10
|
-
* wrapper (.zth) and the consumer's src. Declared as peerDependencies in
|
|
11
|
-
* the shadow pkg so yarn hoists them from the workspace root — which is
|
|
12
|
-
* why we enforce their presence in the consumer's own package.json.
|
|
13
|
-
*/
|
|
14
|
-
const PROTECTED_DEPS = {
|
|
15
|
-
react: '^18.2.0',
|
|
16
|
-
'react-dom': '^18.2.0',
|
|
17
|
-
'react-error-boundary': '^3.1.3',
|
|
18
|
-
'@mondaydotcomorg/trident-runtime': '^1.24.1',
|
|
19
|
-
'@vibe/core': '^4.0.1',
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Protected dev deps. Same idempotent treatment as PROTECTED_DEPS but live
|
|
23
|
-
* in the consumer's `devDependencies`. These give the LLM-authored consumer
|
|
24
|
-
* code access to monday.com platform types out of the box.
|
|
25
|
-
*/
|
|
26
|
-
const PROTECTED_DEV_DEPS = {
|
|
27
|
-
'@mondaydotcomorg/mf-api-types': '^0.1.1',
|
|
28
|
-
'@mondaydotcomorg/bigbrain-types': '^0.3.3',
|
|
29
|
-
};
|
|
30
|
-
// ─────────── Shadow pkg template ───────────
|
|
31
|
-
// TODO — Add trident mf-types / bigbrain-types opt-in.
|
|
32
|
-
const WORKSPACE_DEV_DEPS = {
|
|
33
|
-
'@mondaydotcomorg/trident-toolkit': '^2.9.25',
|
|
34
|
-
'@types/react': '^18.0.14',
|
|
35
|
-
'@types/react-dom': '^18.0.5',
|
|
36
|
-
typescript: '^5.7.2',
|
|
37
|
-
};
|
|
7
|
+
// ─────────── Shadow scripts ───────
|
|
38
8
|
const SHADOW_SCRIPTS = {
|
|
39
9
|
start: 'trident start',
|
|
40
10
|
build: 'trident build',
|
|
41
11
|
};
|
|
12
|
+
// ─────────── Shadow dev deps ───────
|
|
13
|
+
// Yarn berry only wires a workspace member's `node_modules/.bin/` PATH
|
|
14
|
+
// for packages that member explicitly declares. The shadow's scripts
|
|
15
|
+
// invoke `trident`, so trident-toolkit must be declared here for the
|
|
16
|
+
// bin to resolve. `*` is fine — yarn workspaces resolve the actual
|
|
17
|
+
// version from the workspace root's pinned entry.
|
|
18
|
+
const SHADOW_DEV_DEPS = {
|
|
19
|
+
'@mondaydotcomorg/trident-toolkit': '*',
|
|
20
|
+
};
|
|
42
21
|
// ─────────── Auto-allocated dev port range ────
|
|
43
22
|
// High enough to dodge common dev defaults (3000 Next, 5173 Vite, 8080).
|
|
44
23
|
// Collisions within the 7k-port pool are rare for POC; if trident can't
|
|
@@ -54,4 +33,4 @@ const YARNRC_LINES = [
|
|
|
54
33
|
"npmRegistryServer: 'https://registry.npmjs.org/'",
|
|
55
34
|
];
|
|
56
35
|
|
|
57
|
-
export { GITIGNORE_ENTRIES, MAX_PORT, MIN_PORT,
|
|
36
|
+
export { GITIGNORE_ENTRIES, MAX_PORT, MIN_PORT, SHADOW_DEV_DEPS, SHADOW_DIR_NAME, SHADOW_SCRIPTS, YARNRC_LINES };
|
package/dist/esm/index.mjs
CHANGED
|
@@ -3,6 +3,8 @@ import { devCommand } from './commands/dev.mjs';
|
|
|
3
3
|
import { buildCommand } from './commands/build.mjs';
|
|
4
4
|
import { cleanCommand } from './commands/clean.mjs';
|
|
5
5
|
import { deployCommand } from './commands/deploy.mjs';
|
|
6
|
+
import { createWorkspaceCommand } from './commands/create-workspace.mjs';
|
|
7
|
+
import { createCommand } from './commands/create.mjs';
|
|
6
8
|
import { errorLog, fail } from './util/logger.mjs';
|
|
7
9
|
|
|
8
10
|
async function main() {
|
|
@@ -74,6 +76,32 @@ async function main() {
|
|
|
74
76
|
fail(`deploy failed: ${err.message}`, { command: 'deploy' }, 2);
|
|
75
77
|
}
|
|
76
78
|
});
|
|
79
|
+
program
|
|
80
|
+
.command('create-workspace')
|
|
81
|
+
.description('Bootstrap the ~/zth-projects/ yarn workspace (one-time setup)')
|
|
82
|
+
.option('--json', 'emit structured JSON on stdout')
|
|
83
|
+
.action(async (opts) => {
|
|
84
|
+
try {
|
|
85
|
+
await createWorkspaceCommand(opts);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
fail(`create-workspace failed: ${err.message}`, { command: 'create-workspace' }, 1);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
program
|
|
92
|
+
.command('create <app-name>')
|
|
93
|
+
.description('Scaffold a new Z2H consumer app inside ~/zth-projects/')
|
|
94
|
+
.option('--template <name>', 'Template name (default | html-embed)')
|
|
95
|
+
.option('--html-file <path>', 'Path to an HTML file to embed (implies --template html-embed)')
|
|
96
|
+
.option('--json', 'emit structured JSON on stdout')
|
|
97
|
+
.action(async (appName, opts) => {
|
|
98
|
+
try {
|
|
99
|
+
await createCommand(appName, opts);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
fail(`create failed: ${err.message}`, { command: 'create' }, 1);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
77
105
|
await program.parseAsync(process.argv);
|
|
78
106
|
}
|
|
79
107
|
void main()
|