@construct-space/cli 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2316,8 +2316,8 @@ var {
2316
2316
  } = import__.default;
2317
2317
 
2318
2318
  // src/commands/scaffold.ts
2319
- import { mkdirSync, writeFileSync, existsSync, readFileSync } from "fs";
2320
- import { join, dirname } from "path";
2319
+ import { mkdirSync, writeFileSync, existsSync as existsSync2, readFileSync } from "fs";
2320
+ import { join as join2, dirname } from "path";
2321
2321
 
2322
2322
  // node_modules/chalk/source/vendor/ansi-styles/index.js
2323
2323
  var ANSI_BACKGROUND_OFFSET = 10;
@@ -4541,7 +4541,8 @@ function openBrowser(url) {
4541
4541
  } catch {}
4542
4542
  }
4543
4543
  function git(dir, ...args) {
4544
- return execSync(`git ${args.join(" ")}`, { cwd: dir, encoding: "utf-8" }).trim();
4544
+ const quoted = args.map((a) => a.includes(" ") || a.includes(":") ? `"${a}"` : a);
4545
+ return execSync(`git ${quoted.join(" ")}`, { cwd: dir, encoding: "utf-8" }).trim();
4545
4546
  }
4546
4547
  function gitSafe(dir, ...args) {
4547
4548
  try {
@@ -4573,14 +4574,58 @@ function toDisplayName(name) {
4573
4574
  return name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
4574
4575
  }
4575
4576
 
4577
+ // src/lib/runtime.ts
4578
+ import { execSync as execSync2, spawn } from "child_process";
4579
+ import { existsSync } from "fs";
4580
+ import { join } from "path";
4581
+ function detect() {
4582
+ for (const rt of ["bun", "node"]) {
4583
+ try {
4584
+ const version = execSync2(`${rt} --version`, { encoding: "utf-8" }).trim().replace(/^v/, "");
4585
+ return { name: rt, version, exec: rt };
4586
+ } catch {}
4587
+ }
4588
+ throw new Error("No JavaScript runtime found. Install bun or node.");
4589
+ }
4590
+ function ensureDeps(root, rt) {
4591
+ const nmDir = join(root, "node_modules");
4592
+ if (existsSync(nmDir))
4593
+ return;
4594
+ const cmd = rt.name === "bun" ? "bun install" : "npm install";
4595
+ execSync2(cmd, { cwd: root, stdio: "inherit" });
4596
+ }
4597
+ function buildCmd(root, rt) {
4598
+ const cmd = rt.name === "bun" ? "bun" : "npx";
4599
+ const args = rt.name === "bun" ? ["run", "vite", "build"] : ["vite", "build"];
4600
+ const child = spawn(cmd, args, { cwd: root, stdio: "inherit" });
4601
+ return new Promise((resolve, reject) => {
4602
+ child.on("close", (code) => {
4603
+ if (code === 0)
4604
+ resolve();
4605
+ else
4606
+ reject(new Error(`Build failed with exit code ${code}`));
4607
+ });
4608
+ });
4609
+ }
4610
+ function watchCmd(root, rt) {
4611
+ const cmd = rt.name === "bun" ? "bun" : "npx";
4612
+ const args = rt.name === "bun" ? ["run", "vite", "build", "--watch"] : ["vite", "build", "--watch"];
4613
+ return spawn(cmd, args, { cwd: root, stdio: "pipe" });
4614
+ }
4615
+ function runHook(hooks, hookName, root) {
4616
+ if (!hooks || !hooks[hookName])
4617
+ return;
4618
+ execSync2(hooks[hookName], { cwd: root, stdio: "inherit" });
4619
+ }
4620
+
4576
4621
  // src/commands/scaffold.ts
4577
4622
  var nameRegex = /^[a-z][a-z0-9-]*$/;
4578
4623
  function render(template, data) {
4579
4624
  return template.replace(/\{\{\.Name\}\}/g, data.name).replace(/\{\{\.ID\}\}/g, data.id).replace(/\{\{\.IDUpper\}\}/g, data.idUpper).replace(/\{\{\.DisplayName\}\}/g, data.displayName).replace(/\{\{\.DisplayNameNoSpace\}\}/g, data.displayNameNoSpace);
4580
4625
  }
4581
4626
  function writeTemplate(templateDir, tmplName, outPath, data) {
4582
- const tmplPath = join(templateDir, tmplName);
4583
- if (!existsSync(tmplPath)) {
4627
+ const tmplPath = join2(templateDir, tmplName);
4628
+ if (!existsSync2(tmplPath)) {
4584
4629
  console.warn(source_default.yellow(`Template not found: ${tmplName}`));
4585
4630
  return;
4586
4631
  }
@@ -4588,6 +4633,11 @@ function writeTemplate(templateDir, tmplName, outPath, data) {
4588
4633
  mkdirSync(dirname(outPath), { recursive: true });
4589
4634
  writeFileSync(outPath, render(content, data));
4590
4635
  }
4636
+ async function installScaffoldDeps(root) {
4637
+ const rt = detect();
4638
+ console.log(source_default.blue(`Installing dependencies with ${rt.name}...`));
4639
+ ensureDeps(root, rt);
4640
+ }
4591
4641
  async function scaffold(nameArg, options) {
4592
4642
  let name = nameArg;
4593
4643
  if (!name) {
@@ -4600,7 +4650,7 @@ async function scaffold(nameArg, options) {
4600
4650
  console.error(source_default.red("Invalid name: must be lowercase alphanumeric with hyphens, starting with a letter"));
4601
4651
  process.exit(1);
4602
4652
  }
4603
- if (existsSync(name)) {
4653
+ if (existsSync2(name)) {
4604
4654
  console.error(source_default.red(`Directory '${name}' already exists`));
4605
4655
  process.exit(1);
4606
4656
  }
@@ -4613,55 +4663,76 @@ async function scaffold(nameArg, options) {
4613
4663
  displayName,
4614
4664
  displayNameNoSpace: displayName.replace(/ /g, "")
4615
4665
  };
4616
- console.log(source_default.blue(`Creating space: ${displayName}`));
4666
+ const isFull = options?.full ?? false;
4667
+ console.log(source_default.blue(`Creating space: ${displayName}${isFull ? " (full preset)" : ""}`));
4617
4668
  const dirs = [
4618
4669
  name,
4619
- join(name, "src", "pages"),
4620
- join(name, "src", "components"),
4621
- join(name, "src", "composables"),
4622
- join(name, "agent", "skills"),
4623
- join(name, "agent", "hooks"),
4624
- join(name, "agent", "tools"),
4625
- join(name, "widgets", "summary"),
4626
- join(name, ".github", "workflows")
4670
+ join2(name, "src", "pages"),
4671
+ join2(name, "src", "components"),
4672
+ join2(name, "src", "composables"),
4673
+ join2(name, "agent", "skills"),
4674
+ join2(name, "agent", "hooks"),
4675
+ join2(name, "agent", "tools"),
4676
+ join2(name, "widgets", "summary"),
4677
+ join2(name, ".github", "workflows")
4627
4678
  ];
4628
4679
  for (const d of dirs)
4629
4680
  mkdirSync(d, { recursive: true });
4630
- const templateDir = join(dirname(new URL(import.meta.url).pathname), "..", "..", "templates", "space");
4681
+ const scriptDir = dirname(new URL(import.meta.url).pathname);
4682
+ let templateDir = join2(scriptDir, "templates", "space");
4683
+ if (!existsSync2(templateDir)) {
4684
+ templateDir = join2(scriptDir, "..", "templates", "space");
4685
+ }
4686
+ if (!existsSync2(templateDir)) {
4687
+ templateDir = join2(scriptDir, "..", "..", "templates", "space");
4688
+ }
4631
4689
  const files = {
4632
- "space.manifest.json.tmpl": join(name, "space.manifest.json"),
4633
- "package.json.tmpl": join(name, "package.json"),
4634
- "vite.config.ts.tmpl": join(name, "vite.config.ts"),
4635
- "index.vue.tmpl": join(name, "src", "pages", "index.vue"),
4636
- "config.md.tmpl": join(name, "agent", "config.md"),
4637
- "skill.md.tmpl": join(name, "agent", "skills", "default.md"),
4638
- "safety.json.tmpl": join(name, "agent", "hooks", "safety.json"),
4639
- "build.yml.tmpl": join(name, ".github", "workflows", "build.yml"),
4640
- "tsconfig.json.tmpl": join(name, "tsconfig.json"),
4641
- "gitignore.tmpl": join(name, ".gitignore"),
4642
- "readme.md.tmpl": join(name, "README.md"),
4643
- "widgets/2x1.vue.tmpl": join(name, "widgets", "summary", "2x1.vue"),
4644
- "widgets/4x1.vue.tmpl": join(name, "widgets", "summary", "4x1.vue")
4690
+ "package.json.tmpl": join2(name, "package.json"),
4691
+ "vite.config.ts.tmpl": join2(name, "vite.config.ts"),
4692
+ "index.vue.tmpl": join2(name, "src", "pages", "index.vue"),
4693
+ "config.md.tmpl": join2(name, "agent", "config.md"),
4694
+ "skill.md.tmpl": join2(name, "agent", "skills", "default.md"),
4695
+ "safety.json.tmpl": join2(name, "agent", "hooks", "safety.json"),
4696
+ "build.yml.tmpl": join2(name, ".github", "workflows", "build.yml"),
4697
+ "tsconfig.json.tmpl": join2(name, "tsconfig.json"),
4698
+ "gitignore.tmpl": join2(name, ".gitignore"),
4699
+ "readme.md.tmpl": join2(name, "README.md"),
4700
+ "widgets/2x1.vue.tmpl": join2(name, "widgets", "summary", "2x1.vue"),
4701
+ "widgets/4x1.vue.tmpl": join2(name, "widgets", "summary", "4x1.vue"),
4702
+ "actions.ts.tmpl": join2(name, "src", "actions.ts")
4645
4703
  };
4704
+ if (isFull) {
4705
+ files["full/space.manifest.json.tmpl"] = join2(name, "space.manifest.json");
4706
+ files["full/entry.ts.tmpl"] = join2(name, "src", "entry.ts");
4707
+ } else {
4708
+ files["space.manifest.json.tmpl"] = join2(name, "space.manifest.json");
4709
+ files["entry.ts.tmpl"] = join2(name, "src", "entry.ts");
4710
+ }
4646
4711
  for (const [tmpl, out] of Object.entries(files)) {
4647
4712
  writeTemplate(templateDir, tmpl, out, data);
4648
4713
  }
4714
+ if (isFull) {
4715
+ writeTemplate(templateDir, "full/settings.vue.tmpl", join2(name, "src", "pages", "settings.vue"), data);
4716
+ writeTemplate(templateDir, "full/skill-data.md.tmpl", join2(name, "agent", "skills", "data.md"), data);
4717
+ writeTemplate(templateDir, "full/skill-ui.md.tmpl", join2(name, "agent", "skills", "ui.md"), data);
4718
+ console.log(source_default.blue("Full preset: settings page + extra skills added"));
4719
+ }
4649
4720
  if (options?.withTests) {
4650
- mkdirSync(join(name, "e2e"), { recursive: true });
4651
- writeTemplate(templateDir, "e2e/playwright.config.ts.tmpl", join(name, "playwright.config.ts"), data);
4652
- writeTemplate(templateDir, "e2e/space.spec.ts.tmpl", join(name, "e2e", "space.spec.ts"), data);
4721
+ mkdirSync(join2(name, "e2e"), { recursive: true });
4722
+ writeTemplate(templateDir, "e2e/playwright.config.ts.tmpl", join2(name, "playwright.config.ts"), data);
4723
+ writeTemplate(templateDir, "e2e/space.spec.ts.tmpl", join2(name, "e2e", "space.spec.ts"), data);
4653
4724
  console.log(source_default.blue("E2E testing boilerplate added (Playwright)"));
4654
4725
  }
4726
+ await (options?.installDeps ?? installScaffoldDeps)(name);
4655
4727
  console.log(source_default.green(`Space '${name}' created!`));
4656
4728
  console.log();
4657
4729
  console.log(` cd ${name}`);
4658
- console.log(" bun install");
4659
4730
  console.log(" construct dev");
4660
4731
  console.log();
4661
4732
  }
4662
4733
 
4663
4734
  // src/commands/build.ts
4664
- import { existsSync as existsSync6, readFileSync as readFileSync4, readdirSync as readdirSync2, renameSync, statSync as statSync3 } from "fs";
4735
+ import { existsSync as existsSync6, readFileSync as readFileSync4, readdirSync as readdirSync2, renameSync, statSync as statSync2 } from "fs";
4665
4736
  import { join as join6 } from "path";
4666
4737
  import { createHash } from "crypto";
4667
4738
 
@@ -7295,8 +7366,8 @@ function ora(options) {
7295
7366
  }
7296
7367
 
7297
7368
  // src/lib/manifest.ts
7298
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
7299
- import { join as join2 } from "path";
7369
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
7370
+ import { join as join3 } from "path";
7300
7371
  var MANIFEST_FILE = "space.manifest.json";
7301
7372
  var idRegex = /^[a-z][a-z0-9-]*$/;
7302
7373
  var versionRegex = /^\d+\.\d+\.\d+/;
@@ -7323,27 +7394,27 @@ function validate2(m) {
7323
7394
  return errors2;
7324
7395
  }
7325
7396
  function read(dir) {
7326
- const path = join2(dir, MANIFEST_FILE);
7397
+ const path = join3(dir, MANIFEST_FILE);
7327
7398
  const data = readFileSync2(path, "utf-8");
7328
7399
  return JSON.parse(data);
7329
7400
  }
7330
7401
  function readRaw(dir) {
7331
- const path = join2(dir, MANIFEST_FILE);
7402
+ const path = join3(dir, MANIFEST_FILE);
7332
7403
  const data = readFileSync2(path, "utf-8");
7333
7404
  return JSON.parse(data);
7334
7405
  }
7335
7406
  function writeWithBuild(dir, raw, build) {
7336
7407
  raw.build = build;
7337
- writeFileSync2(join2(dir, "manifest.json"), JSON.stringify(raw, null, 2) + `
7408
+ writeFileSync2(join3(dir, "manifest.json"), JSON.stringify(raw, null, 2) + `
7338
7409
  `);
7339
7410
  }
7340
7411
  function exists(dir) {
7341
- return existsSync2(join2(dir, MANIFEST_FILE));
7412
+ return existsSync3(join3(dir, MANIFEST_FILE));
7342
7413
  }
7343
7414
 
7344
7415
  // src/lib/entry.ts
7345
- import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync3 } from "fs";
7346
- import { join as join3, basename, extname } from "path";
7416
+ import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
7417
+ import { join as join4, basename, extname } from "path";
7347
7418
  function capitalize(s) {
7348
7419
  if (!s)
7349
7420
  return s;
@@ -7371,8 +7442,7 @@ function resolvePages(m, prefix) {
7371
7442
  function resolveWidgets(m, prefix) {
7372
7443
  const imports = [];
7373
7444
  for (const w of m.widgets || []) {
7374
- const sizeKeys = Object.keys(w.sizes).sort();
7375
- for (const sizeKey of sizeKeys) {
7445
+ for (const sizeKey of Object.keys(w.sizes).sort()) {
7376
7446
  imports.push({
7377
7447
  varName: capitalize(w.id) + "Widget" + sizeKey,
7378
7448
  importPath: prefix + w.sizes[sizeKey],
@@ -7384,9 +7454,12 @@ function resolveWidgets(m, prefix) {
7384
7454
  return imports;
7385
7455
  }
7386
7456
  function generate(root, m) {
7387
- const pagePrefix = existsSync3(join3(root, "src", "pages")) ? "./" : "../";
7457
+ const pagePrefix = existsSync4(join4(root, "src", "pages")) ? "./" : "../";
7388
7458
  const pages = resolvePages(m, pagePrefix);
7389
7459
  const widgets = resolveWidgets(m, "../");
7460
+ const actionsPath = join4(root, "src", "actions.ts");
7461
+ const hasActions = existsSync4(actionsPath);
7462
+ console.log(`[entry] root=${root} actionsPath=${actionsPath} hasActions=${hasActions}`);
7390
7463
  const lines = [
7391
7464
  "// Auto-generated entry — do not edit manually",
7392
7465
  "// Generated from space.manifest.json"
@@ -7395,6 +7468,8 @@ function generate(root, m) {
7395
7468
  lines.push(`import ${p.varName} from '${p.importPath}'`);
7396
7469
  for (const w of widgets)
7397
7470
  lines.push(`import ${w.varName} from '${w.importPath}'`);
7471
+ if (hasActions)
7472
+ lines.push("import { actions } from './actions'");
7398
7473
  lines.push("");
7399
7474
  lines.push("const spaceExport = {");
7400
7475
  lines.push(" pages: {");
@@ -7414,13 +7489,14 @@ function generate(root, m) {
7414
7489
  }
7415
7490
  for (const wid of order) {
7416
7491
  lines.push(` '${wid}': {`);
7417
- for (const w of byId.get(wid)) {
7492
+ for (const w of byId.get(wid))
7418
7493
  lines.push(` '${w.sizeKey}': ${w.varName},`);
7419
- }
7420
7494
  lines.push(" },");
7421
7495
  }
7422
7496
  lines.push(" },");
7423
7497
  }
7498
+ if (hasActions)
7499
+ lines.push(" actions,");
7424
7500
  lines.push("}");
7425
7501
  lines.push("");
7426
7502
  lines.push("export default spaceExport");
@@ -7429,53 +7505,9 @@ function generate(root, m) {
7429
7505
  `;
7430
7506
  }
7431
7507
  function writeEntry(root, m) {
7432
- const srcDir = join3(root, "src");
7508
+ const srcDir = join4(root, "src");
7433
7509
  mkdirSync2(srcDir, { recursive: true });
7434
- writeFileSync3(join3(srcDir, "entry.ts"), generate(root, m));
7435
- }
7436
-
7437
- // src/lib/runtime.ts
7438
- import { execSync as execSync2, spawn } from "child_process";
7439
- import { existsSync as existsSync4 } from "fs";
7440
- import { join as join4 } from "path";
7441
- function detect() {
7442
- for (const rt of ["bun", "node"]) {
7443
- try {
7444
- const version = execSync2(`${rt} --version`, { encoding: "utf-8" }).trim().replace(/^v/, "");
7445
- return { name: rt, version, exec: rt };
7446
- } catch {}
7447
- }
7448
- throw new Error("No JavaScript runtime found. Install bun or node.");
7449
- }
7450
- function ensureDeps(root, rt) {
7451
- const nmDir = join4(root, "node_modules");
7452
- if (existsSync4(nmDir))
7453
- return;
7454
- const cmd = rt.name === "bun" ? "bun install" : "npm install";
7455
- execSync2(cmd, { cwd: root, stdio: "inherit" });
7456
- }
7457
- function buildCmd(root, rt) {
7458
- const cmd = rt.name === "bun" ? "bun" : "npx";
7459
- const args = rt.name === "bun" ? ["run", "vite", "build"] : ["vite", "build"];
7460
- const child = spawn(cmd, args, { cwd: root, stdio: "inherit" });
7461
- return new Promise((resolve, reject) => {
7462
- child.on("close", (code) => {
7463
- if (code === 0)
7464
- resolve();
7465
- else
7466
- reject(new Error(`Build failed with exit code ${code}`));
7467
- });
7468
- });
7469
- }
7470
- function watchCmd(root, rt) {
7471
- const cmd = rt.name === "bun" ? "bun" : "npx";
7472
- const args = rt.name === "bun" ? ["run", "vite", "build", "--watch"] : ["vite", "build", "--watch"];
7473
- return spawn(cmd, args, { cwd: root, stdio: "pipe" });
7474
- }
7475
- function runHook(hooks, hookName, root) {
7476
- if (!hooks || !hooks[hookName])
7477
- return;
7478
- execSync2(hooks[hookName], { cwd: root, stdio: "inherit" });
7510
+ writeFileSync3(join4(srcDir, "entry.ts"), generate(root, m));
7479
7511
  }
7480
7512
 
7481
7513
  // src/lib/agent.ts
@@ -7561,7 +7593,7 @@ async function build(options) {
7561
7593
  }
7562
7594
  runHook(m.hooks, "postBuild", root);
7563
7595
  const agentDir = join6(root, "agent");
7564
- if (existsSync6(agentDir) && statSync3(agentDir).isDirectory()) {
7596
+ if (existsSync6(agentDir) && statSync2(agentDir).isDirectory()) {
7565
7597
  const distDir2 = join6(root, "dist");
7566
7598
  bundleAgentDir(agentDir, distDir2);
7567
7599
  bundleAgentDir(agentDir, root);
@@ -7592,8 +7624,8 @@ async function build(options) {
7592
7624
  }
7593
7625
 
7594
7626
  // src/commands/dev.ts
7595
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5, unlinkSync, readFileSync as readFileSync5, cpSync } from "fs";
7596
- import { join as join10 } from "path";
7627
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
7628
+ import { join as join9 } from "path";
7597
7629
  import { createHash as createHash2 } from "crypto";
7598
7630
 
7599
7631
  // node_modules/chokidar/esm/index.js
@@ -9166,58 +9198,13 @@ function watch(paths, options = {}) {
9166
9198
  return watcher;
9167
9199
  }
9168
9200
 
9169
- // src/lib/appdir.ts
9170
- import { join as join9 } from "path";
9171
- import { homedir } from "os";
9172
- import { platform as platform2 } from "process";
9173
- function dataDir() {
9174
- if (process.env.CONSTRUCT_DATA_DIR)
9175
- return process.env.CONSTRUCT_DATA_DIR;
9176
- const home = homedir();
9177
- switch (platform2) {
9178
- case "darwin":
9179
- return join9(home, "Library", "Application Support", "Construct");
9180
- case "win32": {
9181
- const appData = process.env.APPDATA || join9(home, "AppData", "Roaming");
9182
- return join9(appData, "Construct");
9183
- }
9184
- default: {
9185
- const xdg = process.env.XDG_DATA_HOME || join9(home, ".local", "share");
9186
- return join9(xdg, "construct");
9187
- }
9188
- }
9189
- }
9190
- function devDataDir() {
9191
- if (process.env.CONSTRUCT_DATA_DIR)
9192
- return process.env.CONSTRUCT_DATA_DIR;
9193
- const home = homedir();
9194
- switch (platform2) {
9195
- case "darwin":
9196
- return join9(home, "Library", "Application Support", "Construct Dev");
9197
- case "win32": {
9198
- const appData = process.env.APPDATA || join9(home, "AppData", "Roaming");
9199
- return join9(appData, "Construct Dev");
9200
- }
9201
- default: {
9202
- const xdg = process.env.XDG_DATA_HOME || join9(home, ".local", "share");
9203
- return join9(xdg, "construct-dev");
9204
- }
9205
- }
9206
- }
9207
- function spacesDir() {
9208
- return join9(dataDir(), "spaces");
9209
- }
9210
- function devSpacesDir() {
9211
- return join9(devDataDir(), "spaces");
9212
- }
9213
- function spaceDir(spaceId) {
9214
- return join9(spacesDir(), spaceId);
9215
- }
9216
- function devSpaceDir(spaceId) {
9217
- return join9(devSpacesDir(), spaceId);
9218
- }
9219
-
9220
9201
  // src/commands/dev.ts
9202
+ function getEntryWatchPaths(root) {
9203
+ return [
9204
+ join9(root, MANIFEST_FILE),
9205
+ join9(root, "src", "actions.ts")
9206
+ ];
9207
+ }
9221
9208
  async function dev() {
9222
9209
  const root = process.cwd();
9223
9210
  if (!exists(root)) {
@@ -9229,23 +9216,6 @@ async function dev() {
9229
9216
  console.log(source_default.blue(`Dev mode — ${m.id} (${rt.name} ${rt.version})`));
9230
9217
  ensureDeps(root, rt);
9231
9218
  writeEntry(root, m);
9232
- const installDir = spaceDir(m.id);
9233
- mkdirSync3(installDir, { recursive: true });
9234
- const devMarker = join10(installDir, ".dev");
9235
- writeFileSync5(devMarker, "dev");
9236
- const cleanup = () => {
9237
- try {
9238
- unlinkSync(devMarker);
9239
- } catch {}
9240
- };
9241
- process.on("SIGINT", () => {
9242
- cleanup();
9243
- process.exit(0);
9244
- });
9245
- process.on("SIGTERM", () => {
9246
- cleanup();
9247
- process.exit(0);
9248
- });
9249
9219
  const vite = watchCmd(root, rt);
9250
9220
  vite.stdout?.on("data", (data) => {
9251
9221
  process.stdout.write(source_default.dim(data.toString()));
@@ -9253,18 +9223,26 @@ async function dev() {
9253
9223
  vite.stderr?.on("data", (data) => {
9254
9224
  process.stderr.write(source_default.dim(data.toString()));
9255
9225
  });
9256
- const manifestWatcher = watch(join10(root, MANIFEST_FILE), { ignoreInitial: true });
9257
- manifestWatcher.on("change", () => {
9226
+ const regenerateEntry = () => {
9258
9227
  try {
9259
9228
  const newM = read(root);
9260
9229
  writeEntry(root, newM);
9261
- console.log(source_default.blue("Manifest changed — entry regenerated"));
9230
+ console.log(source_default.blue("Entry regenerated"));
9262
9231
  } catch (err) {
9263
9232
  console.error(source_default.red(`Manifest error: ${err.message}`));
9264
9233
  }
9234
+ };
9235
+ const entryWatcher = watch(getEntryWatchPaths(root), { ignoreInitial: true });
9236
+ entryWatcher.on("all", (_, changedPath) => {
9237
+ regenerateEntry();
9238
+ if (changedPath.endsWith(MANIFEST_FILE)) {
9239
+ console.log(source_default.blue("Manifest changed — entry regenerated"));
9240
+ return;
9241
+ }
9242
+ console.log(source_default.blue("Actions changed — entry regenerated"));
9265
9243
  });
9266
- const distDir = join10(root, "dist");
9267
- const bundleFile = join10(distDir, `space-${m.id}.iife.js`);
9244
+ const distDir = join9(root, "dist");
9245
+ const bundleFile = join9(distDir, `space-${m.id}.iife.js`);
9268
9246
  let lastChecksum = "";
9269
9247
  const distWatcher = watch(bundleFile, { ignoreInitial: false });
9270
9248
  distWatcher.on("all", () => {
@@ -9282,25 +9260,47 @@ async function dev() {
9282
9260
  hostApiVersion: "0.2.0",
9283
9261
  builtAt: new Date().toISOString()
9284
9262
  });
9285
- mkdirSync3(installDir, { recursive: true });
9286
- cpSync(distDir, installDir, { recursive: true });
9287
- writeFileSync5(join10(installDir, ".dev"), "dev");
9288
- const devInstall = devSpaceDir(m.id);
9289
- const devParent = join10(devInstall, "..");
9290
- if (existsSync7(devParent)) {
9291
- mkdirSync3(devInstall, { recursive: true });
9292
- cpSync(distDir, devInstall, { recursive: true });
9293
- }
9294
- console.log(source_default.green(`Installed → ${m.id}`));
9263
+ console.log(source_default.green(`Built → dist/ (${(bundleData.length / 1024).toFixed(1)} KB)`));
9295
9264
  });
9296
9265
  console.log(source_default.green("Watching for changes... (Ctrl+C to stop)"));
9266
+ console.log(source_default.dim("Use the Preview button in Construct to open the Space Runner"));
9297
9267
  await new Promise(() => {});
9298
9268
  }
9299
9269
 
9300
9270
  // src/commands/run.ts
9301
- import { existsSync as existsSync8, cpSync as cpSync2, mkdirSync as mkdirSync4 } from "fs";
9271
+ import { existsSync as existsSync8, cpSync, mkdirSync as mkdirSync3 } from "fs";
9302
9272
  import { join as join11 } from "path";
9303
- function run() {
9273
+
9274
+ // src/lib/appdir.ts
9275
+ import { join as join10 } from "path";
9276
+ import { homedir } from "os";
9277
+ import { platform as platform2 } from "process";
9278
+ function dataDir() {
9279
+ if (process.env.CONSTRUCT_DATA_DIR)
9280
+ return process.env.CONSTRUCT_DATA_DIR;
9281
+ const home = homedir();
9282
+ switch (platform2) {
9283
+ case "darwin":
9284
+ return join10(home, "Library", "Application Support", "Construct");
9285
+ case "win32": {
9286
+ const appData = process.env.APPDATA || join10(home, "AppData", "Roaming");
9287
+ return join10(appData, "Construct");
9288
+ }
9289
+ default: {
9290
+ const xdg = process.env.XDG_DATA_HOME || join10(home, ".local", "share");
9291
+ return join10(xdg, "construct");
9292
+ }
9293
+ }
9294
+ }
9295
+ function spacesDir() {
9296
+ return join10(dataDir(), "spaces");
9297
+ }
9298
+ function spaceDir(spaceId) {
9299
+ return join10(spacesDir(), spaceId);
9300
+ }
9301
+
9302
+ // src/commands/run.ts
9303
+ function install() {
9304
9304
  const root = process.cwd();
9305
9305
  if (!exists(root)) {
9306
9306
  console.error(source_default.red("No space.manifest.json found in current directory"));
@@ -9317,18 +9317,18 @@ function run() {
9317
9317
  bundleAgentDir(agentDir, distDir);
9318
9318
  }
9319
9319
  const installDir = spaceDir(m.id);
9320
- mkdirSync4(installDir, { recursive: true });
9321
- cpSync2(distDir, installDir, { recursive: true });
9322
- console.log(source_default.green(`Installed ${m.name} to ${installDir}`));
9320
+ mkdirSync3(installDir, { recursive: true });
9321
+ cpSync(distDir, installDir, { recursive: true });
9322
+ console.log(source_default.green(`Installed ${m.name} ${installDir}`));
9323
9323
  console.log(source_default.dim(" Restart Construct to load the updated space."));
9324
9324
  }
9325
9325
 
9326
9326
  // src/commands/publish.ts
9327
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync7, statSync as statSync6, unlinkSync as unlinkSync3 } from "fs";
9327
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, statSync as statSync4, unlinkSync as unlinkSync2 } from "fs";
9328
9328
  import { join as join14, basename as basename6 } from "path";
9329
9329
 
9330
9330
  // src/lib/auth.ts
9331
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, existsSync as existsSync9 } from "fs";
9331
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync, existsSync as existsSync9 } from "fs";
9332
9332
  import { join as join12, dirname as dirname4 } from "path";
9333
9333
  var CREDENTIALS_FILE = "credentials.json";
9334
9334
  var DEFAULT_PORTAL = "https://developer.construct.space";
@@ -9337,8 +9337,8 @@ function credentialsPath() {
9337
9337
  }
9338
9338
  function store(creds) {
9339
9339
  const path = credentialsPath();
9340
- mkdirSync5(dirname4(path), { recursive: true });
9341
- writeFileSync6(path, JSON.stringify(creds, null, 2) + `
9340
+ mkdirSync4(dirname4(path), { recursive: true });
9341
+ writeFileSync5(path, JSON.stringify(creds, null, 2) + `
9342
9342
  `, { mode: 384 });
9343
9343
  }
9344
9344
  function load2() {
@@ -9363,11 +9363,11 @@ function isAuthenticated() {
9363
9363
  function clear() {
9364
9364
  const path = credentialsPath();
9365
9365
  if (existsSync9(path))
9366
- unlinkSync2(path);
9366
+ unlinkSync(path);
9367
9367
  }
9368
9368
 
9369
9369
  // src/lib/pack.ts
9370
- import { readdirSync as readdirSync3, statSync as statSync5, existsSync as existsSync10 } from "fs";
9370
+ import { readdirSync as readdirSync3, statSync as statSync3, existsSync as existsSync10 } from "fs";
9371
9371
  import { join as join13 } from "path";
9372
9372
  import { tmpdir } from "os";
9373
9373
  import { execSync as execSync3 } from "child_process";
@@ -9410,7 +9410,7 @@ async function packSource(root) {
9410
9410
  entries.push(name);
9411
9411
  }
9412
9412
  for (const entry of readdirSync3(root)) {
9413
- if (statSync5(join13(root, entry)).isDirectory())
9413
+ if (statSync3(join13(root, entry)).isDirectory())
9414
9414
  continue;
9415
9415
  if (allowedRootFiles.includes(entry))
9416
9416
  continue;
@@ -9430,7 +9430,7 @@ async function packSource(root) {
9430
9430
  const excludes = "--exclude=node_modules --exclude=dist --exclude=.git --exclude=*.env --exclude=*.log --exclude=*.lock --exclude=*.lockb";
9431
9431
  const cmd = `tar czf "${tarballPath}" ${excludes} ${validEntries.join(" ")}`;
9432
9432
  execSync3(cmd, { cwd: root });
9433
- const size = statSync5(tarballPath).size;
9433
+ const size = statSync3(tarballPath).size;
9434
9434
  if (size > MAX_SIZE) {
9435
9435
  throw new Error(`Source exceeds maximum size of ${MAX_SIZE / 1024 / 1024}MB`);
9436
9436
  }
@@ -9466,7 +9466,7 @@ function setVersionInFiles(root, oldVer, newVer) {
9466
9466
  const path = join14(root, file);
9467
9467
  try {
9468
9468
  const data = readFileSync7(path, "utf-8");
9469
- writeFileSync7(path, data.replace(oldStr, newStr));
9469
+ writeFileSync6(path, data.replace(oldStr, newStr));
9470
9470
  } catch {}
9471
9471
  }
9472
9472
  }
@@ -9570,7 +9570,7 @@ async function publish(options) {
9570
9570
  let tarballPath;
9571
9571
  try {
9572
9572
  tarballPath = await packSource(root);
9573
- const size = statSync6(tarballPath).size;
9573
+ const size = statSync4(tarballPath).size;
9574
9574
  spinner.succeed(`Source packed (${formatBytes(size)})`);
9575
9575
  } catch (err) {
9576
9576
  spinner.fail("Pack failed");
@@ -9580,7 +9580,7 @@ async function publish(options) {
9580
9580
  const uploadSpinner = ora("Uploading & building...").start();
9581
9581
  try {
9582
9582
  const result = await uploadSource(creds.portal, creds.token, tarballPath, m);
9583
- unlinkSync3(tarballPath);
9583
+ unlinkSync2(tarballPath);
9584
9584
  gitSafe(root, "tag", `v${m.version}`);
9585
9585
  gitSafe(root, "push", "origin", `v${m.version}`);
9586
9586
  if (result.status === "approved" || result.status === "pending_review") {
@@ -9602,7 +9602,7 @@ async function publish(options) {
9602
9602
  }
9603
9603
  } catch (err) {
9604
9604
  uploadSpinner.fail("Upload failed");
9605
- unlinkSync3(tarballPath);
9605
+ unlinkSync2(tarballPath);
9606
9606
  console.error(source_default.red(err.message));
9607
9607
  process.exit(1);
9608
9608
  }
@@ -9860,7 +9860,7 @@ function update() {
9860
9860
  }
9861
9861
 
9862
9862
  // src/commands/graph/init.ts
9863
- import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6 } from "fs";
9863
+ import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "fs";
9864
9864
  import { join as join18 } from "path";
9865
9865
  import { execSync as execSync6 } from "child_process";
9866
9866
  function graphInit() {
@@ -9872,10 +9872,10 @@ function graphInit() {
9872
9872
  }
9873
9873
  const m = read(root);
9874
9874
  const modelsDir = join18(root, "src", "models");
9875
- mkdirSync6(modelsDir, { recursive: true });
9875
+ mkdirSync5(modelsDir, { recursive: true });
9876
9876
  const indexPath = join18(modelsDir, "index.ts");
9877
9877
  if (!existsSync14(indexPath)) {
9878
- writeFileSync8(indexPath, `// Data models for ${m.name}
9878
+ writeFileSync7(indexPath, `// Data models for ${m.name}
9879
9879
  // Generated by construct graph init
9880
9880
 
9881
9881
  // Export your models here:
@@ -9892,7 +9892,7 @@ function graphInit() {
9892
9892
  version = execSync6("npm view @construct-space/graph version", { encoding: "utf-8" }).trim();
9893
9893
  } catch {}
9894
9894
  pkg.dependencies["@construct-space/graph"] = `^${version}`;
9895
- writeFileSync8(pkgPath, JSON.stringify(pkg, null, 2) + `
9895
+ writeFileSync7(pkgPath, JSON.stringify(pkg, null, 2) + `
9896
9896
  `);
9897
9897
  console.log(source_default.blue(`Added @construct-space/graph@^${version} to dependencies`));
9898
9898
  } else {
@@ -9913,7 +9913,7 @@ function graphInit() {
9913
9913
  }
9914
9914
 
9915
9915
  // src/commands/graph/generate.ts
9916
- import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync9, mkdirSync as mkdirSync7 } from "fs";
9916
+ import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6 } from "fs";
9917
9917
  import { join as join19 } from "path";
9918
9918
  var FIELD_TYPES = {
9919
9919
  string: "field.string()",
@@ -10067,13 +10067,13 @@ function generate2(modelName, fieldSpecs, options) {
10067
10067
  const content = lines.join(`
10068
10068
  `);
10069
10069
  const modelsDir = join19(root, "src", "models");
10070
- mkdirSync7(modelsDir, { recursive: true });
10070
+ mkdirSync6(modelsDir, { recursive: true });
10071
10071
  const filePath = join19(modelsDir, `${name}.ts`);
10072
10072
  if (existsSync15(filePath)) {
10073
10073
  console.log(source_default.yellow(` Model file already exists: src/models/${name}.ts`));
10074
10074
  console.log(source_default.dim(" Overwriting..."));
10075
10075
  }
10076
- writeFileSync9(filePath, content);
10076
+ writeFileSync8(filePath, content);
10077
10077
  console.log(source_default.green(` Created src/models/${name}.ts`));
10078
10078
  updateBarrel(modelsDir, name);
10079
10079
  console.log();
@@ -10092,11 +10092,11 @@ function updateBarrel(modelsDir, modelName) {
10092
10092
  const content = readFileSync11(indexPath, "utf-8");
10093
10093
  if (content.includes(exportLine))
10094
10094
  return;
10095
- writeFileSync9(indexPath, content.trimEnd() + `
10095
+ writeFileSync8(indexPath, content.trimEnd() + `
10096
10096
  ` + exportLine + `
10097
10097
  `);
10098
10098
  } else {
10099
- writeFileSync9(indexPath, exportLine + `
10099
+ writeFileSync8(indexPath, exportLine + `
10100
10100
  `);
10101
10101
  }
10102
10102
  console.log(source_default.dim(` Updated src/models/index.ts`));
@@ -10386,13 +10386,13 @@ function parseModelFields(content, fileName) {
10386
10386
  }
10387
10387
 
10388
10388
  // src/index.ts
10389
- var VERSION = "1.0.6";
10389
+ var VERSION = "1.1.0";
10390
10390
  var program2 = new Command;
10391
10391
  program2.name("construct").description("Construct CLI — scaffold, build, develop, and publish spaces").version(VERSION);
10392
- program2.command("scaffold [name]").alias("new").alias("create").description("Create a new Construct space project").option("--with-tests", "Include E2E testing boilerplate").action(async (name, opts) => scaffold(name, opts));
10392
+ program2.command("scaffold [name]").alias("new").alias("create").description("Create a new Construct space project").option("--with-tests", "Include E2E testing boilerplate").option("--full", "Full preset: multiple pages, extra skills, widget templates").action(async (name, opts) => scaffold(name, opts));
10393
10393
  program2.command("build").description("Build the space (generate entry + run Vite)").option("--entry-only", "Only generate src/entry.ts").action(async (opts) => build(opts));
10394
10394
  program2.command("dev").description("Start dev mode with file watching and live reload").action(async () => dev());
10395
- program2.command("run").description("Install built space to Construct spaces directory").action(() => run());
10395
+ program2.command("install").alias("run").description("Install built space to Construct spaces directory").action(() => install());
10396
10396
  program2.command("publish").description("Publish a space to the Construct registry").option("-y, --yes", "Skip all confirmation prompts").option("--bump <type>", "Auto-bump version (patch, minor, major)").action(async (opts) => publish(opts));
10397
10397
  program2.command("validate").description("Validate space.manifest.json").action(() => validate3());
10398
10398
  program2.command("check").description("Run type-check (vue-tsc) and linter (eslint)").action(() => check());
@@ -10406,10 +10406,10 @@ graph.command("generate <model> [fields...]").alias("g").description("Generate a
10406
10406
  graph.command("push").description("Register models with the Graph service").action(async () => graphPush());
10407
10407
  graph.command("migrate").description("Compare local models with server schema and apply changes").option("--apply", "Apply destructive changes (drop columns, alter constraints)").action(async (opts) => graphMigrate(opts));
10408
10408
  var space = program2.command("space").description("Space development commands");
10409
- space.command("scaffold [name]").alias("new").alias("create").option("--with-tests", "Include E2E testing boilerplate").action(async (name, opts) => scaffold(name, opts));
10409
+ space.command("scaffold [name]").alias("new").alias("create").option("--with-tests", "Include E2E testing boilerplate").option("--full", "Full preset: multiple pages, extra skills, widget templates").action(async (name, opts) => scaffold(name, opts));
10410
10410
  space.command("build").option("--entry-only").action(async (opts) => build(opts));
10411
10411
  space.command("dev").action(async () => dev());
10412
- space.command("run").action(() => run());
10412
+ space.command("install").alias("run").action(() => install());
10413
10413
  space.command("publish").option("-y, --yes").option("--bump <type>").action(async (opts) => publish(opts));
10414
10414
  space.command("validate").action(() => validate3());
10415
10415
  space.command("check").action(() => check());