@construct-space/cli 1.9.4 → 1.9.6

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
@@ -2790,8 +2790,8 @@ var require_lib = __commonJS((exports, module) => {
2790
2790
  });
2791
2791
 
2792
2792
  // src/lib/appdir.ts
2793
- import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
2794
- import { join as join10 } from "path";
2793
+ import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
2794
+ import { join as join11 } from "path";
2795
2795
  import { homedir } from "os";
2796
2796
  import { platform } from "process";
2797
2797
  function dataDir() {
@@ -2800,32 +2800,32 @@ function dataDir() {
2800
2800
  const home = homedir();
2801
2801
  switch (platform) {
2802
2802
  case "darwin":
2803
- return join10(home, "Library", "Application Support", "Construct");
2803
+ return join11(home, "Library", "Application Support", "Construct");
2804
2804
  case "win32": {
2805
- const appData = process.env.APPDATA || join10(home, "AppData", "Roaming");
2806
- return join10(appData, "Construct");
2805
+ const appData = process.env.APPDATA || join11(home, "AppData", "Roaming");
2806
+ return join11(appData, "Construct");
2807
2807
  }
2808
2808
  default: {
2809
- const xdg = process.env.XDG_DATA_HOME || join10(home, ".local", "share");
2810
- return join10(xdg, "construct");
2809
+ const xdg = process.env.XDG_DATA_HOME || join11(home, ".local", "share");
2810
+ return join11(xdg, "construct");
2811
2811
  }
2812
2812
  }
2813
2813
  }
2814
2814
  function profilesDir() {
2815
- return join10(dataDir(), "profiles");
2815
+ return join11(dataDir(), "profiles");
2816
2816
  }
2817
2817
  function activeProfileId() {
2818
2818
  try {
2819
- const credsPath = join10(dataDir(), "credentials.json");
2820
- if (existsSync8(credsPath)) {
2819
+ const credsPath = join11(dataDir(), "credentials.json");
2820
+ if (existsSync9(credsPath)) {
2821
2821
  const c = JSON.parse(readFileSync6(credsPath, "utf-8"));
2822
2822
  if (c.profileId)
2823
2823
  return c.profileId;
2824
2824
  }
2825
2825
  } catch {}
2826
2826
  try {
2827
- const regPath = join10(dataDir(), "profiles.json");
2828
- if (existsSync8(regPath)) {
2827
+ const regPath = join11(dataDir(), "profiles.json");
2828
+ if (existsSync9(regPath)) {
2829
2829
  const r = JSON.parse(readFileSync6(regPath, "utf-8"));
2830
2830
  if (r.active_profile)
2831
2831
  return r.active_profile;
@@ -2836,29 +2836,29 @@ function activeProfileId() {
2836
2836
  function spacesDir() {
2837
2837
  const profileId = activeProfileId();
2838
2838
  if (profileId)
2839
- return join10(profilesDir(), profileId, "spaces");
2840
- return join10(dataDir(), "spaces");
2839
+ return join11(profilesDir(), profileId, "spaces");
2840
+ return join11(dataDir(), "spaces");
2841
2841
  }
2842
2842
  function spaceDir(spaceId) {
2843
- return join10(spacesDir(), spaceId);
2843
+ return join11(spacesDir(), `${spaceId}.space`);
2844
2844
  }
2845
2845
  var init_appdir = () => {};
2846
2846
 
2847
2847
  // src/lib/auth.ts
2848
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync, existsSync as existsSync10, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
2849
- import { join as join12, dirname as dirname4 } from "path";
2848
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, unlinkSync, existsSync as existsSync11, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
2849
+ import { join as join13, dirname as dirname5 } from "path";
2850
2850
  function listDesktopProfiles() {
2851
2851
  const dir = profilesDir();
2852
- if (!existsSync10(dir))
2852
+ if (!existsSync11(dir))
2853
2853
  return [];
2854
2854
  const results = [];
2855
2855
  for (const entry of readdirSync5(dir)) {
2856
- const full = join12(dir, entry);
2856
+ const full = join13(dir, entry);
2857
2857
  try {
2858
- if (!statSync3(full).isDirectory())
2858
+ if (!statSync2(full).isDirectory())
2859
2859
  continue;
2860
- const authPath = join12(full, "auth.json");
2861
- if (!existsSync10(authPath))
2860
+ const authPath = join13(full, "auth.json");
2861
+ if (!existsSync11(authPath))
2862
2862
  continue;
2863
2863
  const data = JSON.parse(readFileSync7(authPath, "utf-8"));
2864
2864
  if (!data.token)
@@ -2877,14 +2877,14 @@ function listDesktopProfiles() {
2877
2877
  return results;
2878
2878
  }
2879
2879
  function legacyCredentialsPath() {
2880
- return join12(dataDir(), LEGACY_CREDENTIALS_FILE);
2880
+ return join13(dataDir(), LEGACY_CREDENTIALS_FILE);
2881
2881
  }
2882
2882
  function registryPath() {
2883
- return join12(dataDir(), PROFILES_REGISTRY);
2883
+ return join13(dataDir(), PROFILES_REGISTRY);
2884
2884
  }
2885
2885
  function readRegistry() {
2886
2886
  const path = registryPath();
2887
- if (!existsSync10(path))
2887
+ if (!existsSync11(path))
2888
2888
  return {};
2889
2889
  try {
2890
2890
  return JSON.parse(readFileSync7(path, "utf-8"));
@@ -2894,7 +2894,7 @@ function readRegistry() {
2894
2894
  }
2895
2895
  function writeRegistry(reg) {
2896
2896
  const path = registryPath();
2897
- mkdirSync4(dirname4(path), { recursive: true });
2897
+ mkdirSync6(dirname5(path), { recursive: true });
2898
2898
  writeFileSync5(path, JSON.stringify({ version: 1, ...reg }, null, 2));
2899
2899
  }
2900
2900
  function store(creds) {
@@ -2902,10 +2902,10 @@ function store(creds) {
2902
2902
  if (!profileId) {
2903
2903
  throw new Error("cannot store credentials without a profile id (user.id or profileId)");
2904
2904
  }
2905
- const profilePath = join12(profilesDir(), profileId, "auth.json");
2906
- mkdirSync4(dirname4(profilePath), { recursive: true });
2905
+ const profilePath = join13(profilesDir(), profileId, "auth.json");
2906
+ mkdirSync6(dirname5(profilePath), { recursive: true });
2907
2907
  let existing = {};
2908
- if (existsSync10(profilePath)) {
2908
+ if (existsSync11(profilePath)) {
2909
2909
  try {
2910
2910
  existing = JSON.parse(readFileSync7(profilePath, "utf-8"));
2911
2911
  } catch {}
@@ -2945,7 +2945,7 @@ function store(creds) {
2945
2945
  }
2946
2946
  function migrateLegacyCredentials() {
2947
2947
  const legacy = legacyCredentialsPath();
2948
- if (!existsSync10(legacy))
2948
+ if (!existsSync11(legacy))
2949
2949
  return;
2950
2950
  try {
2951
2951
  const data = JSON.parse(readFileSync7(legacy, "utf-8"));
@@ -2954,8 +2954,8 @@ function migrateLegacyCredentials() {
2954
2954
  const pid = data.profileId || data.user?.id;
2955
2955
  if (!pid)
2956
2956
  return;
2957
- const profilePath = join12(profilesDir(), pid, "auth.json");
2958
- if (existsSync10(profilePath))
2957
+ const profilePath = join13(profilesDir(), pid, "auth.json");
2958
+ if (existsSync11(profilePath))
2959
2959
  return;
2960
2960
  store({ ...data, profileId: pid });
2961
2961
  } catch {}
@@ -2969,15 +2969,15 @@ function load2() {
2969
2969
  }
2970
2970
  function loadFromActiveProfile() {
2971
2971
  try {
2972
- const regPath = join12(dataDir(), "profiles.json");
2973
- if (!existsSync10(regPath))
2972
+ const regPath = join13(dataDir(), "profiles.json");
2973
+ if (!existsSync11(regPath))
2974
2974
  return null;
2975
2975
  const reg = JSON.parse(readFileSync7(regPath, "utf-8"));
2976
2976
  const activeId = reg.active_profile;
2977
2977
  if (!activeId)
2978
2978
  return null;
2979
- const authPath = join12(profilesDir(), activeId, "auth.json");
2980
- if (!existsSync10(authPath))
2979
+ const authPath = join13(profilesDir(), activeId, "auth.json");
2980
+ if (!existsSync11(authPath))
2981
2981
  return null;
2982
2982
  const a = JSON.parse(readFileSync7(authPath, "utf-8"));
2983
2983
  if (!a.token)
@@ -3014,8 +3014,8 @@ function clear() {
3014
3014
  const reg = readRegistry();
3015
3015
  const activeId = reg.active_profile;
3016
3016
  if (activeId) {
3017
- const profilePath = join12(profilesDir(), activeId, "auth.json");
3018
- if (existsSync10(profilePath)) {
3017
+ const profilePath = join13(profilesDir(), activeId, "auth.json");
3018
+ if (existsSync11(profilePath)) {
3019
3019
  try {
3020
3020
  const data = JSON.parse(readFileSync7(profilePath, "utf-8"));
3021
3021
  data.authenticated = false;
@@ -3025,7 +3025,7 @@ function clear() {
3025
3025
  }
3026
3026
  }
3027
3027
  const legacy = legacyCredentialsPath();
3028
- if (existsSync10(legacy))
3028
+ if (existsSync11(legacy))
3029
3029
  unlinkSync(legacy);
3030
3030
  }
3031
3031
  var LEGACY_CREDENTIALS_FILE = "credentials.json", PROFILES_REGISTRY = "profiles.json", DEFAULT_PORTAL = "https://my.construct.space/api/developer";
@@ -3190,7 +3190,7 @@ function loadCreds() {
3190
3190
  } catch (err) {
3191
3191
  const msg = err instanceof Error ? err.message : String(err);
3192
3192
  throw new Error(msg + `
3193
- Run 'construct login' first.`);
3193
+ Run 'construct login' first.`, { cause: err });
3194
3194
  }
3195
3195
  }
3196
3196
  async function graphRequest(opts) {
@@ -5453,6 +5453,8 @@ async function scaffold(nameArg, options) {
5453
5453
  join2(name, "scripts"),
5454
5454
  join2(name, "references"),
5455
5455
  join2(name, "assets"),
5456
+ join2(name, "tools"),
5457
+ join2(name, "lib"),
5456
5458
  join2(name, "agent", "hooks"),
5457
5459
  join2(name, "agent", "tools"),
5458
5460
  join2(name, "widgets", "summary")
@@ -5516,9 +5518,9 @@ async function scaffold(nameArg, options) {
5516
5518
 
5517
5519
  // src/commands/build.ts
5518
5520
  init_source();
5519
- import { cpSync, existsSync as existsSync6, readFileSync as readFileSync4, readdirSync as readdirSync3, renameSync, statSync as statSync2 } from "fs";
5520
- import { join as join6 } from "path";
5521
- import { createHash } from "crypto";
5521
+ import { existsSync as existsSync7, readFileSync as readFileSync4, readdirSync as readdirSync3, renameSync, rmSync as rmSync2 } from "fs";
5522
+ import { join as join7 } from "path";
5523
+ import { createHash as createHash2 } from "crypto";
5522
5524
 
5523
5525
  // node_modules/ora/index.js
5524
5526
  init_source();
@@ -8154,6 +8156,7 @@ function ora(options) {
8154
8156
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
8155
8157
  import { join as join3 } from "path";
8156
8158
  var MANIFEST_FILE = "space.manifest.json";
8159
+ var HOST_API_VERSION = "0.6.0";
8157
8160
  var idRegex = /^[a-z][a-z0-9-]*$/;
8158
8161
  var versionRegex = /^\d+\.\d+\.\d+/;
8159
8162
  function validate2(m) {
@@ -8247,7 +8250,7 @@ function scanPagesDir(pagesDir) {
8247
8250
  function varNameFromFile(filePath) {
8248
8251
  let cleaned = filePath.replace(/^pages\//, "").replace(/\.vue$/, "");
8249
8252
  cleaned = cleaned.replace(/\[([^\]]+)\]/g, "$1");
8250
- const segments = cleaned.split(/[\/-]/).filter(Boolean);
8253
+ const segments = cleaned.split(/[/-]/).filter(Boolean);
8251
8254
  const name = segments.map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
8252
8255
  return (name || "Index") + "Page";
8253
8256
  }
@@ -8261,11 +8264,11 @@ function resolvePages(m, root, prefix) {
8261
8264
  return m.pages.map((p) => {
8262
8265
  if (p.component) {
8263
8266
  const base = basename(p.component);
8264
- const nameWithoutExt = base.replace(extname(base), "").replace(/[\[\]]/g, "");
8267
+ const nameWithoutExt = base.replace(extname(base), "").replace(/[[\]]/g, "");
8265
8268
  const dir = p.component.replace(/^pages\//, "").replace(/\/[^/]+$/, "");
8266
8269
  let varName;
8267
8270
  if (dir && dir !== p.component.replace(/^pages\//, "")) {
8268
- varName = capitalize(dir.split("/").map((s) => s.replace(/[\[\]]/g, "")).join("-")) + capitalize(nameWithoutExt) + "Page";
8271
+ varName = capitalize(dir.split("/").map((s) => s.replace(/[[\]]/g, "")).join("-")) + capitalize(nameWithoutExt) + "Page";
8269
8272
  } else {
8270
8273
  varName = capitalize(nameWithoutExt) + "Page";
8271
8274
  }
@@ -8281,7 +8284,7 @@ function resolvePages(m, root, prefix) {
8281
8284
  if (existsSync4(legacyFullPath)) {
8282
8285
  let varName = "IndexPage";
8283
8286
  if (p.path) {
8284
- varName = capitalize(p.path.replace(/\[([^\]]+)\]/g, "$1").replace(/[\/:]/g, "-").replace(/-+/g, "-")) + "Page";
8287
+ varName = capitalize(p.path.replace(/\[([^\]]+)\]/g, "$1").replace(/[/:]/g, "-").replace(/-+/g, "-")) + "Page";
8285
8288
  }
8286
8289
  return { varName, importPath: prefix + legacyComponent, path: p.path };
8287
8290
  }
@@ -8362,74 +8365,216 @@ function writeEntry(root, m) {
8362
8365
  writeFileSync3(join4(srcDir, "entry.ts"), generate(root, m));
8363
8366
  }
8364
8367
 
8365
- // src/lib/agent.ts
8366
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, readdirSync as readdirSync2, existsSync as existsSync5 } from "fs";
8367
- import { join as join5, extname as extname2, basename as basename2 } from "path";
8368
- var AGENT_KEY = "construct-agent-obfuscate-v1";
8369
- function encode(content) {
8370
- const key = Buffer.from(AGENT_KEY);
8371
- const data = Buffer.from(content);
8372
- const xored = Buffer.alloc(data.length);
8373
- for (let i = 0;i < data.length; i++) {
8374
- xored[i] = data[i] ^ key[i % key.length];
8375
- }
8376
- return xored.toString("base64");
8377
- }
8378
- function readMdFiles(dir) {
8379
- const result = {};
8380
- if (!existsSync5(dir))
8381
- return result;
8382
- for (const f of readdirSync2(dir)) {
8383
- if (extname2(f) !== ".md")
8368
+ // src/lib/spaceBundle.ts
8369
+ import { createHash } from "crypto";
8370
+ import { cpSync, existsSync as existsSync5, lstatSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, readdirSync as readdirSync2, rmSync, writeFileSync as writeFileSync4 } from "fs";
8371
+ import { basename as basename2, dirname as dirname2, join as join5, relative as relative2 } from "path";
8372
+ var BUNDLE_DIRS = ["agent", "scripts", "references", "assets", "icons", "media", "public", "tools", "lib"];
8373
+ var BUNDLE_FILES = ["SKILL.md"];
8374
+ function stageSpaceResources(root, distDir) {
8375
+ const copied = [];
8376
+ for (const name of BUNDLE_DIRS) {
8377
+ rmSync(join5(distDir, name), { recursive: true, force: true });
8378
+ const src = join5(root, name);
8379
+ if (!existsSync5(src) || !lstatSync(src).isDirectory())
8384
8380
  continue;
8385
- result[basename2(f, ".md")] = readFileSync3(join5(dir, f), "utf-8");
8381
+ cpSync(src, join5(distDir, name), { recursive: true, verbatimSymlinks: true });
8382
+ copied.push(name);
8386
8383
  }
8387
- return result;
8384
+ for (const name of BUNDLE_FILES) {
8385
+ rmSync(join5(distDir, name), { recursive: true, force: true });
8386
+ const src = join5(root, name);
8387
+ if (!existsSync5(src) || !lstatSync(src).isFile())
8388
+ continue;
8389
+ cpSync(src, join5(distDir, name), { verbatimSymlinks: true });
8390
+ copied.push(name);
8391
+ }
8392
+ return copied;
8388
8393
  }
8389
- function readJsonFiles(dir) {
8390
- const result = {};
8391
- if (!existsSync5(dir))
8392
- return result;
8393
- for (const f of readdirSync2(dir)) {
8394
- if (extname2(f) !== ".json")
8394
+ function slashPath(path) {
8395
+ return path.replace(/\\/g, "/");
8396
+ }
8397
+ function copyFileIntoBundle(src, dst) {
8398
+ mkdirSync3(dirname2(dst), { recursive: true });
8399
+ cpSync(src, dst, { verbatimSymlinks: true });
8400
+ }
8401
+ function collectFiles(root) {
8402
+ const files = [];
8403
+ function walk(dir) {
8404
+ for (const name of readdirSync2(dir).sort()) {
8405
+ const path = join5(dir, name);
8406
+ const stat = lstatSync(path);
8407
+ if (stat.isSymbolicLink())
8408
+ continue;
8409
+ if (stat.isDirectory()) {
8410
+ walk(path);
8411
+ } else if (stat.isFile()) {
8412
+ files.push(slashPath(relative2(root, path)));
8413
+ }
8414
+ }
8415
+ }
8416
+ walk(root);
8417
+ return files;
8418
+ }
8419
+ function sha256(path) {
8420
+ return createHash("sha256").update(readFileSync3(path)).digest("hex");
8421
+ }
8422
+ function writeChecksums(spaceDir, spaceId) {
8423
+ const files = collectFiles(spaceDir).filter((file) => file !== "checksums.json");
8424
+ const checksums = {};
8425
+ for (const file of files) {
8426
+ checksums[file] = sha256(join5(spaceDir, file));
8427
+ }
8428
+ writeFileSync4(join5(spaceDir, "checksums.json"), JSON.stringify({
8429
+ format: "construct.space/v1",
8430
+ id: spaceId,
8431
+ files: checksums
8432
+ }, null, 2) + `
8433
+ `);
8434
+ return collectFiles(spaceDir);
8435
+ }
8436
+ function createSpaceBundle(options) {
8437
+ const spaceDir = join5(options.distDir, `${options.spaceId}.space`);
8438
+ const appName = basename2(options.appBundlePath);
8439
+ const cssName = options.cssPath ? basename2(options.cssPath) : "";
8440
+ rmSync(spaceDir, { recursive: true, force: true });
8441
+ mkdirSync3(spaceDir, { recursive: true });
8442
+ copyFileIntoBundle(join5(options.distDir, "manifest.json"), join5(spaceDir, "manifest.json"));
8443
+ copyFileIntoBundle(options.appBundlePath, join5(spaceDir, "app.iife.js"));
8444
+ const hasStyle = Boolean(options.cssPath && existsSync5(options.cssPath));
8445
+ if (hasStyle && options.cssPath) {
8446
+ copyFileIntoBundle(options.cssPath, join5(spaceDir, "style.css"));
8447
+ }
8448
+ for (const entry of readdirSync2(options.distDir)) {
8449
+ if (entry === `${options.spaceId}.space`)
8450
+ continue;
8451
+ if (entry.endsWith(".space"))
8395
8452
  continue;
8396
- result[basename2(f, ".json")] = readFileSync3(join5(dir, f), "utf-8");
8453
+ if (entry === "manifest.json")
8454
+ continue;
8455
+ if (entry === appName || entry === cssName)
8456
+ continue;
8457
+ if (entry.endsWith(".iife.js") || entry.endsWith(".css"))
8458
+ continue;
8459
+ cpSync(join5(options.distDir, entry), join5(spaceDir, entry), {
8460
+ recursive: true,
8461
+ verbatimSymlinks: true
8462
+ });
8397
8463
  }
8398
- return result;
8464
+ return {
8465
+ dir: spaceDir,
8466
+ hasStyle,
8467
+ files: writeChecksums(spaceDir, options.spaceId)
8468
+ };
8399
8469
  }
8400
- function bundleAgentDir(srcDir, distDir) {
8401
- const bundle = {
8402
- config: "",
8403
- tools: readMdFiles(join5(srcDir, "tools")),
8404
- skills: readMdFiles(join5(srcDir, "skills")),
8405
- hooks: readJsonFiles(join5(srcDir, "hooks"))
8470
+
8471
+ // src/lib/spaceTools.ts
8472
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
8473
+ import { join as join6 } from "path";
8474
+ import { arch as nodeArch, platform as nodePlatform } from "process";
8475
+ import { spawnSync } from "child_process";
8476
+ var SPACE_TOOL_TARGETS = [
8477
+ "darwin-arm64",
8478
+ "darwin-x64",
8479
+ "linux-arm64",
8480
+ "linux-x64",
8481
+ "windows-arm64",
8482
+ "windows-x64"
8483
+ ];
8484
+ var GO_TARGETS = {
8485
+ "darwin-arm64": { goos: "darwin", goarch: "arm64", ext: "" },
8486
+ "darwin-x64": { goos: "darwin", goarch: "amd64", ext: "" },
8487
+ "linux-arm64": { goos: "linux", goarch: "arm64", ext: "" },
8488
+ "linux-x64": { goos: "linux", goarch: "amd64", ext: "" },
8489
+ "windows-arm64": { goos: "windows", goarch: "arm64", ext: ".exe" },
8490
+ "windows-x64": { goos: "windows", goarch: "amd64", ext: ".exe" }
8491
+ };
8492
+ function isSpaceToolTarget(value) {
8493
+ return SPACE_TOOL_TARGETS.includes(value);
8494
+ }
8495
+ function currentSpaceToolTarget(platform = nodePlatform, arch = nodeArch) {
8496
+ if (platform === "darwin" && arch === "arm64")
8497
+ return "darwin-arm64";
8498
+ if (platform === "darwin" && arch === "x64")
8499
+ return "darwin-x64";
8500
+ if (platform === "linux" && arch === "arm64")
8501
+ return "linux-arm64";
8502
+ if (platform === "linux" && arch === "x64")
8503
+ return "linux-x64";
8504
+ if (platform === "win32" && arch === "arm64")
8505
+ return "windows-arm64";
8506
+ if (platform === "win32" && arch === "x64")
8507
+ return "windows-x64";
8508
+ return null;
8509
+ }
8510
+ function parseSpaceToolTargets(value = process.env.CONSTRUCT_TOOL_TARGETS) {
8511
+ const raw = value?.trim();
8512
+ if (!raw) {
8513
+ const current = currentSpaceToolTarget();
8514
+ if (!current)
8515
+ throw new Error(`Unsupported tool build platform: ${nodePlatform}-${nodeArch}`);
8516
+ return [current];
8517
+ }
8518
+ if (raw === "all")
8519
+ return [...SPACE_TOOL_TARGETS];
8520
+ const targets = raw.split(/[,\s]+/).filter(Boolean);
8521
+ const invalid = targets.filter((target) => !isSpaceToolTarget(target));
8522
+ if (invalid.length > 0) {
8523
+ throw new Error(`Invalid CONSTRUCT_TOOL_TARGETS value: ${invalid.join(", ")}. ` + `Expected one or more of: ${SPACE_TOOL_TARGETS.join(", ")}, or "all".`);
8524
+ }
8525
+ return Array.from(new Set(targets));
8526
+ }
8527
+ function defaultRunner(invocation) {
8528
+ const result = spawnSync("go", invocation.args, {
8529
+ cwd: invocation.root,
8530
+ env: invocation.env,
8531
+ encoding: "utf-8"
8532
+ });
8533
+ return {
8534
+ status: result.status,
8535
+ stdout: result.stdout || "",
8536
+ stderr: result.stderr || "",
8537
+ error: result.error
8406
8538
  };
8407
- for (const name of ["config.md", "agent.md"]) {
8408
- const path = join5(srcDir, name);
8409
- if (existsSync5(path)) {
8410
- bundle.config = readFileSync3(path, "utf-8");
8411
- break;
8539
+ }
8540
+ function buildSpaceTools(root, distDir, spaceId, options = {}) {
8541
+ const sourcePath = join6(root, "tools.go");
8542
+ if (!existsSync6(sourcePath))
8543
+ return [];
8544
+ const built = [];
8545
+ const targets = options.targets ?? parseSpaceToolTargets(options.env?.CONSTRUCT_TOOL_TARGETS);
8546
+ const runner = options.runner ?? defaultRunner;
8547
+ for (const target of targets) {
8548
+ const goTarget = GO_TARGETS[target];
8549
+ const outputDir = join6(distDir, "tools", target);
8550
+ const outputName = `${spaceId}-tools${goTarget.ext}`;
8551
+ const outputPath = join6(outputDir, outputName);
8552
+ mkdirSync4(outputDir, { recursive: true });
8553
+ const env2 = {
8554
+ ...process.env,
8555
+ ...options.env,
8556
+ GOOS: goTarget.goos,
8557
+ GOARCH: goTarget.goarch
8558
+ };
8559
+ if (!env2.CGO_ENABLED)
8560
+ env2.CGO_ENABLED = "0";
8561
+ const args = ["build", "-trimpath", "-o", outputPath, "./tools.go"];
8562
+ const result = runner({ root, target, outputPath, args, env: env2 });
8563
+ if (result.error) {
8564
+ throw new Error(`Failed to build tools.go for ${target}: ${result.error.message}`);
8565
+ }
8566
+ if (result.status !== 0) {
8567
+ const details = [result.stderr, result.stdout].filter(Boolean).join(`
8568
+ `).trim();
8569
+ throw new Error(`Failed to build tools.go for ${target}${details ? `:
8570
+ ${details}` : ""}`);
8412
8571
  }
8572
+ built.push(`tools/${target}/${outputName}`);
8413
8573
  }
8414
- if (!bundle.config)
8415
- return;
8416
- const encoded = encode(JSON.stringify(bundle));
8417
- writeFileSync4(join5(distDir, "config.agent"), encoded);
8574
+ return built;
8418
8575
  }
8419
8576
 
8420
8577
  // src/commands/build.ts
8421
- var ASSET_DIRS = ["icons", "assets", "media", "public", "bin"];
8422
- function copyAssetDirs(root, distDir) {
8423
- const copied = [];
8424
- for (const name of ASSET_DIRS) {
8425
- const src = join6(root, name);
8426
- if (!existsSync6(src) || !statSync2(src).isDirectory())
8427
- continue;
8428
- cpSync(src, join6(distDir, name), { recursive: true, verbatimSymlinks: true });
8429
- copied.push(name);
8430
- }
8431
- return copied;
8432
- }
8433
8578
  function stripTsComments(source) {
8434
8579
  let out = "";
8435
8580
  let i = 0;
@@ -8518,7 +8663,7 @@ function readObjectEntries(source) {
8518
8663
  i += 1;
8519
8664
  if (i >= source.length)
8520
8665
  break;
8521
- let key = "";
8666
+ let key;
8522
8667
  const quote = source[i];
8523
8668
  if (quote === '"' || quote === "'" || quote === "`") {
8524
8669
  i += 1;
@@ -8629,41 +8774,52 @@ async function build(options) {
8629
8774
  process.exit(1);
8630
8775
  }
8631
8776
  runHook(m.hooks, "postBuild", root);
8632
- const agentDir = join6(root, "agent");
8633
- if (existsSync6(agentDir) && statSync2(agentDir).isDirectory()) {
8634
- const distDir2 = join6(root, "dist");
8635
- bundleAgentDir(agentDir, distDir2);
8636
- bundleAgentDir(agentDir, root);
8777
+ const copiedResources = stageSpaceResources(root, join7(root, "dist"));
8778
+ if (copiedResources.length > 0) {
8779
+ console.log(source_default.blue(` Resources: ${copiedResources.join(", ")}`));
8637
8780
  }
8638
- const copiedAssetDirs = copyAssetDirs(root, join6(root, "dist"));
8639
- if (copiedAssetDirs.length > 0) {
8640
- console.log(source_default.blue(` Assets: ${copiedAssetDirs.join(", ")}`));
8781
+ try {
8782
+ const builtTools = buildSpaceTools(root, join7(root, "dist"), m.id);
8783
+ if (builtTools.length > 0) {
8784
+ console.log(source_default.blue(` Tools: ${builtTools.join(", ")}`));
8785
+ }
8786
+ } catch (err) {
8787
+ console.error(source_default.red(err?.message || String(err)));
8788
+ process.exit(1);
8641
8789
  }
8642
- const distDir = join6(root, "dist");
8790
+ const distDir = join7(root, "dist");
8643
8791
  const expectedBundle = `space-${m.id}.iife.js`;
8644
- let bundlePath = join6(distDir, expectedBundle);
8645
- if (!existsSync6(bundlePath)) {
8792
+ const bundlePath = join7(distDir, expectedBundle);
8793
+ if (!existsSync7(bundlePath)) {
8646
8794
  const matches = readdirSync3(distDir).filter((f) => f.startsWith("space-") && f.endsWith(".iife.js"));
8647
8795
  if (matches.length === 1) {
8648
- renameSync(join6(distDir, matches[0]), bundlePath);
8649
- const oldCSS = join6(distDir, matches[0].replace(".iife.js", ".css"));
8650
- const newCSS = join6(distDir, `space-${m.id}.css`);
8651
- if (existsSync6(oldCSS))
8796
+ renameSync(join7(distDir, matches[0]), bundlePath);
8797
+ const oldCSS = join7(distDir, matches[0].replace(".iife.js", ".css"));
8798
+ const newCSS = join7(distDir, `space-${m.id}.css`);
8799
+ if (existsSync7(oldCSS))
8652
8800
  renameSync(oldCSS, newCSS);
8653
8801
  }
8654
8802
  }
8655
- const expectedCSS = join6(distDir, `space-${m.id}.css`);
8656
- if (!existsSync6(expectedCSS)) {
8803
+ if (!existsSync7(bundlePath)) {
8804
+ console.error(source_default.red(`Build did not emit ${expectedBundle}`));
8805
+ process.exit(1);
8806
+ }
8807
+ const expectedCSS = join7(distDir, `space-${m.id}.css`);
8808
+ if (!existsSync7(expectedCSS)) {
8657
8809
  const cssMatches = readdirSync3(distDir).filter((f) => f.endsWith(".css"));
8658
8810
  const renamedCSS = cssMatches.find((f) => f.startsWith("space-")) || (cssMatches.length === 1 ? cssMatches[0] : undefined);
8659
8811
  if (renamedCSS)
8660
- renameSync(join6(distDir, renamedCSS), expectedCSS);
8812
+ renameSync(join7(distDir, renamedCSS), expectedCSS);
8813
+ }
8814
+ if (!existsSync7(expectedCSS)) {
8815
+ console.error(source_default.red(`Build did not emit CSS. Spaces must import src/style.css so pages and widgets are self-contained.`));
8816
+ process.exit(1);
8661
8817
  }
8662
8818
  const bundleData = readFileSync4(bundlePath);
8663
- const checksum = createHash("sha256").update(bundleData).digest("hex");
8819
+ const checksum = createHash2("sha256").update(bundleData).digest("hex");
8664
8820
  const raw = readRaw(root);
8665
- const actionsPath = join6(root, "src", "actions.ts");
8666
- if (existsSync6(actionsPath)) {
8821
+ const actionsPath = join7(root, "src", "actions.ts");
8822
+ if (existsSync7(actionsPath)) {
8667
8823
  const actionMeta = extractActionMetadata(actionsPath);
8668
8824
  if (actionMeta && Object.keys(actionMeta).length > 0) {
8669
8825
  raw.actions = actionMeta;
@@ -8673,28 +8829,40 @@ async function build(options) {
8673
8829
  writeWithBuild(distDir, raw, {
8674
8830
  checksum,
8675
8831
  size: bundleData.length,
8676
- hostApiVersion: "0.5.0",
8832
+ hostApiVersion: HOST_API_VERSION,
8677
8833
  builtAt: new Date().toISOString()
8678
8834
  });
8679
- console.log(source_default.green(`Built ${m.name} v${m.version}`));
8835
+ const spaceBundle = createSpaceBundle({
8836
+ distDir,
8837
+ spaceId: m.id,
8838
+ appBundlePath: bundlePath,
8839
+ cssPath: expectedCSS
8840
+ });
8841
+ for (const entry of readdirSync3(distDir)) {
8842
+ if (entry === `${m.id}.space`)
8843
+ continue;
8844
+ rmSync2(join7(distDir, entry), { recursive: true, force: true });
8845
+ }
8846
+ console.log(source_default.green(`Built ${m.name} v${m.version} -> dist/${m.id}.space`));
8847
+ console.log(source_default.dim(` ${spaceBundle.files.length} files, ${spaceBundle.hasStyle ? "style.css included" : "no style.css"}`));
8680
8848
  }
8681
8849
 
8682
8850
  // src/commands/dev.ts
8683
8851
  init_source();
8684
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
8685
- import { join as join9 } from "path";
8686
- import { createHash as createHash2 } from "crypto";
8852
+ import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
8853
+ import { join as join10 } from "path";
8854
+ import { createHash as createHash3 } from "crypto";
8687
8855
 
8688
- // node_modules/chokidar/esm/index.js
8689
- import { stat as statcb } from "fs";
8690
- import { stat as stat3, readdir as readdir2 } from "fs/promises";
8856
+ // node_modules/chokidar/index.js
8691
8857
  import { EventEmitter } from "events";
8692
- import * as sysPath2 from "path";
8858
+ import { stat as statcb, Stats } from "fs";
8859
+ import { readdir as readdir2, stat as stat3 } from "fs/promises";
8860
+ import * as sp2 from "path";
8693
8861
 
8694
- // node_modules/readdirp/esm/index.js
8695
- import { stat, lstat, readdir, realpath } from "fs/promises";
8862
+ // node_modules/readdirp/index.js
8863
+ import { lstat, readdir, realpath, stat } from "fs/promises";
8864
+ import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "path";
8696
8865
  import { Readable } from "stream";
8697
- import { resolve as presolve, relative as prelative, join as pjoin, sep as psep } from "path";
8698
8866
  var EntryTypes = {
8699
8867
  FILE_TYPE: "files",
8700
8868
  DIR_TYPE: "directories",
@@ -8750,6 +8918,20 @@ var normalizeFilter = (filter) => {
8750
8918
  };
8751
8919
 
8752
8920
  class ReaddirpStream extends Readable {
8921
+ parents;
8922
+ reading;
8923
+ parent;
8924
+ _stat;
8925
+ _maxDepth;
8926
+ _wantsDir;
8927
+ _wantsFile;
8928
+ _wantsEverything;
8929
+ _root;
8930
+ _isDirent;
8931
+ _statsProp;
8932
+ _rdOptions;
8933
+ _fileFilter;
8934
+ _directoryFilter;
8753
8935
  constructor(options = {}) {
8754
8936
  super({
8755
8937
  objectMode: true,
@@ -8766,7 +8948,7 @@ class ReaddirpStream extends Readable {
8766
8948
  } else {
8767
8949
  this._stat = statMethod;
8768
8950
  }
8769
- this._maxDepth = opts.depth ?? defaultOptions.depth;
8951
+ this._maxDepth = opts.depth != null && Number.isSafeInteger(opts.depth) ? opts.depth : defaultOptions.depth;
8770
8952
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
8771
8953
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
8772
8954
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
@@ -8911,11 +9093,11 @@ function readdirp(root, options = {}) {
8911
9093
  return new ReaddirpStream(options);
8912
9094
  }
8913
9095
 
8914
- // node_modules/chokidar/esm/handler.js
8915
- import { watchFile, unwatchFile, watch as fs_watch } from "fs";
8916
- import { open, stat as stat2, lstat as lstat2, realpath as fsrealpath } from "fs/promises";
8917
- import * as sysPath from "path";
9096
+ // node_modules/chokidar/handler.js
9097
+ import { watch as fs_watch, unwatchFile, watchFile } from "fs";
9098
+ import { realpath as fsrealpath, lstat as lstat2, open, stat as stat2 } from "fs/promises";
8918
9099
  import { type as osType } from "os";
9100
+ import * as sp from "path";
8919
9101
  var STR_DATA = "data";
8920
9102
  var STR_END = "end";
8921
9103
  var STR_CLOSE = "close";
@@ -9207,7 +9389,7 @@ var binaryExtensions = new Set([
9207
9389
  "zip",
9208
9390
  "zipx"
9209
9391
  ]);
9210
- var isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());
9392
+ var isBinaryPath = (filePath) => binaryExtensions.has(sp.extname(filePath).slice(1).toLowerCase());
9211
9393
  var foreach = (val, fn) => {
9212
9394
  if (val instanceof Set) {
9213
9395
  val.forEach(fn);
@@ -9245,7 +9427,7 @@ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
9245
9427
  listener(path);
9246
9428
  emitRaw(rawEvent, evPath, { watchedPath: path });
9247
9429
  if (evPath && path !== evPath) {
9248
- fsWatchBroadcast(sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath));
9430
+ fsWatchBroadcast(sp.resolve(path, evPath), KEY_LISTENERS, sp.join(path, evPath));
9249
9431
  }
9250
9432
  };
9251
9433
  try {
@@ -9360,17 +9542,19 @@ var setFsWatchFileListener = (path, fullPath, options, handlers) => {
9360
9542
  };
9361
9543
 
9362
9544
  class NodeFsHandler {
9545
+ fsw;
9546
+ _boundHandleError;
9363
9547
  constructor(fsW) {
9364
9548
  this.fsw = fsW;
9365
9549
  this._boundHandleError = (error2) => fsW._handleError(error2);
9366
9550
  }
9367
9551
  _watchWithNodeFs(path, listener) {
9368
9552
  const opts = this.fsw.options;
9369
- const directory = sysPath.dirname(path);
9370
- const basename4 = sysPath.basename(path);
9553
+ const directory = sp.dirname(path);
9554
+ const basename4 = sp.basename(path);
9371
9555
  const parent = this.fsw._getWatchedDir(directory);
9372
9556
  parent.add(basename4);
9373
- const absolutePath = sysPath.resolve(path);
9557
+ const absolutePath = sp.resolve(path);
9374
9558
  const options = {
9375
9559
  persistent: opts.persistent
9376
9560
  };
@@ -9397,9 +9581,9 @@ class NodeFsHandler {
9397
9581
  if (this.fsw.closed) {
9398
9582
  return;
9399
9583
  }
9400
- const dirname3 = sysPath.dirname(file);
9401
- const basename4 = sysPath.basename(file);
9402
- const parent = this.fsw._getWatchedDir(dirname3);
9584
+ const dirname4 = sp.dirname(file);
9585
+ const basename4 = sp.basename(file);
9586
+ const parent = this.fsw._getWatchedDir(dirname4);
9403
9587
  let prevStats = stats;
9404
9588
  if (parent.has(basename4))
9405
9589
  return;
@@ -9426,7 +9610,7 @@ class NodeFsHandler {
9426
9610
  prevStats = newStats2;
9427
9611
  }
9428
9612
  } catch (error2) {
9429
- this.fsw._remove(dirname3, basename4);
9613
+ this.fsw._remove(dirname4, basename4);
9430
9614
  }
9431
9615
  } else if (parent.has(basename4)) {
9432
9616
  const at = newStats.atimeMs;
@@ -9481,8 +9665,9 @@ class NodeFsHandler {
9481
9665
  this.fsw._symlinkPaths.set(full, true);
9482
9666
  }
9483
9667
  _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
9484
- directory = sysPath.join(directory, "");
9485
- throttler = this.fsw._throttle("readdir", directory, 1000);
9668
+ directory = sp.join(directory, "");
9669
+ const throttleKey = target ? `${directory}:${target}` : directory;
9670
+ throttler = this.fsw._throttle("readdir", throttleKey, 1000);
9486
9671
  if (!throttler)
9487
9672
  return;
9488
9673
  const previous = this.fsw._getWatchedDir(wh.path);
@@ -9499,7 +9684,7 @@ class NodeFsHandler {
9499
9684
  return;
9500
9685
  }
9501
9686
  const item = entry.path;
9502
- let path = sysPath.join(directory, item);
9687
+ let path = sp.join(directory, item);
9503
9688
  current.add(item);
9504
9689
  if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) {
9505
9690
  return;
@@ -9510,7 +9695,7 @@ class NodeFsHandler {
9510
9695
  }
9511
9696
  if (item === target || !target && !previous.has(item)) {
9512
9697
  this.fsw._incrReadyCount();
9513
- path = sysPath.join(dir, sysPath.relative(dir, path));
9698
+ path = sp.join(dir, sp.relative(dir, path));
9514
9699
  this._addToNodeFs(path, initialAdd, wh, depth + 1);
9515
9700
  }
9516
9701
  }).on(EV.ERROR, this._boundHandleError);
@@ -9536,12 +9721,12 @@ class NodeFsHandler {
9536
9721
  });
9537
9722
  }
9538
9723
  async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath2) {
9539
- const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
9540
- const tracked = parentDir.has(sysPath.basename(dir));
9724
+ const parentDir = this.fsw._getWatchedDir(sp.dirname(dir));
9725
+ const tracked = parentDir.has(sp.basename(dir));
9541
9726
  if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
9542
9727
  this.fsw._emit(EV.ADD_DIR, dir, stats);
9543
9728
  }
9544
- parentDir.add(sysPath.basename(dir));
9729
+ parentDir.add(sp.basename(dir));
9545
9730
  this.fsw._getWatchedDir(dir);
9546
9731
  let throttler;
9547
9732
  let closer;
@@ -9582,7 +9767,7 @@ class NodeFsHandler {
9582
9767
  const follow = this.fsw.options.followSymlinks;
9583
9768
  let closer;
9584
9769
  if (stats.isDirectory()) {
9585
- const absPath = sysPath.resolve(path);
9770
+ const absPath = sp.resolve(path);
9586
9771
  const targetPath = follow ? await fsrealpath(path) : path;
9587
9772
  if (this.fsw.closed)
9588
9773
  return;
@@ -9596,14 +9781,14 @@ class NodeFsHandler {
9596
9781
  const targetPath = follow ? await fsrealpath(path) : path;
9597
9782
  if (this.fsw.closed)
9598
9783
  return;
9599
- const parent = sysPath.dirname(wh.watchPath);
9784
+ const parent = sp.dirname(wh.watchPath);
9600
9785
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
9601
9786
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
9602
9787
  closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
9603
9788
  if (this.fsw.closed)
9604
9789
  return;
9605
9790
  if (targetPath !== undefined) {
9606
- this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);
9791
+ this.fsw._symlinkPaths.set(sp.resolve(path), targetPath);
9607
9792
  }
9608
9793
  } else {
9609
9794
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
@@ -9621,7 +9806,7 @@ class NodeFsHandler {
9621
9806
  }
9622
9807
  }
9623
9808
 
9624
- // node_modules/chokidar/esm/index.js
9809
+ // node_modules/chokidar/index.js
9625
9810
  /*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
9626
9811
  var SLASH = "/";
9627
9812
  var SLASH_SLASH = "//";
@@ -9629,7 +9814,7 @@ var ONE_DOT = ".";
9629
9814
  var TWO_DOTS = "..";
9630
9815
  var STRING_TYPE = "string";
9631
9816
  var BACK_SLASH_RE = /\\/g;
9632
- var DOUBLE_SLASH_RE = /\/\//;
9817
+ var DOUBLE_SLASH_RE = /\/\//g;
9633
9818
  var DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
9634
9819
  var REPLACER_RE = /^\.[/\\]/;
9635
9820
  function arrify(item) {
@@ -9648,11 +9833,11 @@ function createPattern(matcher) {
9648
9833
  if (matcher.path === string)
9649
9834
  return true;
9650
9835
  if (matcher.recursive) {
9651
- const relative4 = sysPath2.relative(matcher.path, string);
9652
- if (!relative4) {
9836
+ const relative5 = sp2.relative(matcher.path, string);
9837
+ if (!relative5) {
9653
9838
  return false;
9654
9839
  }
9655
- return !relative4.startsWith("..") && !sysPath2.isAbsolute(relative4);
9840
+ return !relative5.startsWith("..") && !sp2.isAbsolute(relative5);
9656
9841
  }
9657
9842
  return false;
9658
9843
  };
@@ -9662,14 +9847,12 @@ function createPattern(matcher) {
9662
9847
  function normalizePath(path) {
9663
9848
  if (typeof path !== "string")
9664
9849
  throw new Error("string expected");
9665
- path = sysPath2.normalize(path);
9850
+ path = sp2.normalize(path);
9666
9851
  path = path.replace(/\\/g, "/");
9667
9852
  let prepend = false;
9668
9853
  if (path.startsWith("//"))
9669
9854
  prepend = true;
9670
- const DOUBLE_SLASH_RE2 = /\/\//;
9671
- while (path.match(DOUBLE_SLASH_RE2))
9672
- path = path.replace(DOUBLE_SLASH_RE2, "/");
9855
+ path = path.replace(DOUBLE_SLASH_RE, "/");
9673
9856
  if (prepend)
9674
9857
  path = "/" + path;
9675
9858
  return path;
@@ -9710,31 +9893,32 @@ var toUnix = (string) => {
9710
9893
  if (str.startsWith(SLASH_SLASH)) {
9711
9894
  prepend = true;
9712
9895
  }
9713
- while (str.match(DOUBLE_SLASH_RE)) {
9714
- str = str.replace(DOUBLE_SLASH_RE, SLASH);
9715
- }
9896
+ str = str.replace(DOUBLE_SLASH_RE, SLASH);
9716
9897
  if (prepend) {
9717
9898
  str = SLASH + str;
9718
9899
  }
9719
9900
  return str;
9720
9901
  };
9721
- var normalizePathToUnix = (path) => toUnix(sysPath2.normalize(toUnix(path)));
9902
+ var normalizePathToUnix = (path) => toUnix(sp2.normalize(toUnix(path)));
9722
9903
  var normalizeIgnored = (cwd = "") => (path) => {
9723
9904
  if (typeof path === "string") {
9724
- return normalizePathToUnix(sysPath2.isAbsolute(path) ? path : sysPath2.join(cwd, path));
9905
+ return normalizePathToUnix(sp2.isAbsolute(path) ? path : sp2.join(cwd, path));
9725
9906
  } else {
9726
9907
  return path;
9727
9908
  }
9728
9909
  };
9729
9910
  var getAbsolutePath = (path, cwd) => {
9730
- if (sysPath2.isAbsolute(path)) {
9911
+ if (sp2.isAbsolute(path)) {
9731
9912
  return path;
9732
9913
  }
9733
- return sysPath2.join(cwd, path);
9914
+ return sp2.join(cwd, path);
9734
9915
  };
9735
9916
  var EMPTY_SET = Object.freeze(new Set);
9736
9917
 
9737
9918
  class DirEntry {
9919
+ path;
9920
+ _removeWatcher;
9921
+ items;
9738
9922
  constructor(dir, removeWatcher) {
9739
9923
  this.path = dir;
9740
9924
  this._removeWatcher = removeWatcher;
@@ -9759,7 +9943,7 @@ class DirEntry {
9759
9943
  await readdir2(dir);
9760
9944
  } catch (err) {
9761
9945
  if (this._removeWatcher) {
9762
- this._removeWatcher(sysPath2.dirname(dir), sysPath2.basename(dir));
9946
+ this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
9763
9947
  }
9764
9948
  }
9765
9949
  }
@@ -9787,12 +9971,19 @@ var STAT_METHOD_F = "stat";
9787
9971
  var STAT_METHOD_L = "lstat";
9788
9972
 
9789
9973
  class WatchHelper {
9974
+ fsw;
9975
+ path;
9976
+ watchPath;
9977
+ fullWatchPath;
9978
+ dirParts;
9979
+ followSymlinks;
9980
+ statMethod;
9790
9981
  constructor(path, follow, fsw) {
9791
9982
  this.fsw = fsw;
9792
9983
  const watchPath = path;
9793
9984
  this.path = path = path.replace(REPLACER_RE, "");
9794
9985
  this.watchPath = watchPath;
9795
- this.fullWatchPath = sysPath2.resolve(watchPath);
9986
+ this.fullWatchPath = sp2.resolve(watchPath);
9796
9987
  this.dirParts = [];
9797
9988
  this.dirParts.forEach((parts) => {
9798
9989
  if (parts.length > 1)
@@ -9802,7 +9993,7 @@ class WatchHelper {
9802
9993
  this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
9803
9994
  }
9804
9995
  entryPath(entry) {
9805
- return sysPath2.join(this.watchPath, sysPath2.relative(this.watchPath, entry.fullPath));
9996
+ return sp2.join(this.watchPath, sp2.relative(this.watchPath, entry.fullPath));
9806
9997
  }
9807
9998
  filterPath(entry) {
9808
9999
  const { stats } = entry;
@@ -9817,6 +10008,24 @@ class WatchHelper {
9817
10008
  }
9818
10009
 
9819
10010
  class FSWatcher extends EventEmitter {
10011
+ closed;
10012
+ options;
10013
+ _closers;
10014
+ _ignoredPaths;
10015
+ _throttled;
10016
+ _streams;
10017
+ _symlinkPaths;
10018
+ _watched;
10019
+ _pendingWrites;
10020
+ _pendingUnlinks;
10021
+ _readyCount;
10022
+ _emitReady;
10023
+ _closePromise;
10024
+ _userIgnored;
10025
+ _readyEmitted;
10026
+ _emitRaw;
10027
+ _boundRemove;
10028
+ _nodeFsHandler;
9820
10029
  constructor(_opts = {}) {
9821
10030
  super();
9822
10031
  this.closed = false;
@@ -9925,7 +10134,7 @@ class FSWatcher extends EventEmitter {
9925
10134
  return;
9926
10135
  results.forEach((item) => {
9927
10136
  if (item)
9928
- this.add(sysPath2.dirname(item), sysPath2.basename(_origAdd || item));
10137
+ this.add(sp2.dirname(item), sp2.basename(_origAdd || item));
9929
10138
  });
9930
10139
  });
9931
10140
  return this;
@@ -9936,10 +10145,10 @@ class FSWatcher extends EventEmitter {
9936
10145
  const paths = unifyPaths(paths_);
9937
10146
  const { cwd } = this.options;
9938
10147
  paths.forEach((path) => {
9939
- if (!sysPath2.isAbsolute(path) && !this._closers.has(path)) {
10148
+ if (!sp2.isAbsolute(path) && !this._closers.has(path)) {
9940
10149
  if (cwd)
9941
- path = sysPath2.join(cwd, path);
9942
- path = sysPath2.resolve(path);
10150
+ path = sp2.join(cwd, path);
10151
+ path = sp2.resolve(path);
9943
10152
  }
9944
10153
  this._closePath(path);
9945
10154
  this._addIgnoredPath(path);
@@ -9983,7 +10192,7 @@ class FSWatcher extends EventEmitter {
9983
10192
  getWatched() {
9984
10193
  const watchList = {};
9985
10194
  this._watched.forEach((entry, dir) => {
9986
- const key = this.options.cwd ? sysPath2.relative(this.options.cwd, dir) : dir;
10195
+ const key = this.options.cwd ? sp2.relative(this.options.cwd, dir) : dir;
9987
10196
  const index = key || ONE_DOT;
9988
10197
  watchList[index] = entry.getChildren().sort();
9989
10198
  });
@@ -9999,9 +10208,9 @@ class FSWatcher extends EventEmitter {
9999
10208
  return;
10000
10209
  const opts = this.options;
10001
10210
  if (isWindows)
10002
- path = sysPath2.normalize(path);
10211
+ path = sp2.normalize(path);
10003
10212
  if (opts.cwd)
10004
- path = sysPath2.relative(opts.cwd, path);
10213
+ path = sp2.relative(opts.cwd, path);
10005
10214
  const args = [path];
10006
10215
  if (stats != null)
10007
10216
  args.push(stats);
@@ -10052,7 +10261,7 @@ class FSWatcher extends EventEmitter {
10052
10261
  return this;
10053
10262
  }
10054
10263
  if (opts.alwaysStat && stats === undefined && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
10055
- const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path) : path;
10264
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path) : path;
10056
10265
  let stats2;
10057
10266
  try {
10058
10267
  stats2 = await stat3(fullPath);
@@ -10108,8 +10317,8 @@ class FSWatcher extends EventEmitter {
10108
10317
  const pollInterval = awf.pollInterval;
10109
10318
  let timeoutHandler;
10110
10319
  let fullPath = path;
10111
- if (this.options.cwd && !sysPath2.isAbsolute(path)) {
10112
- fullPath = sysPath2.join(this.options.cwd, path);
10320
+ if (this.options.cwd && !sp2.isAbsolute(path)) {
10321
+ fullPath = sp2.join(this.options.cwd, path);
10113
10322
  }
10114
10323
  const now = new Date;
10115
10324
  const writes = this._pendingWrites;
@@ -10166,7 +10375,7 @@ class FSWatcher extends EventEmitter {
10166
10375
  return new WatchHelper(path, this.options.followSymlinks, this);
10167
10376
  }
10168
10377
  _getWatchedDir(directory) {
10169
- const dir = sysPath2.resolve(directory);
10378
+ const dir = sp2.resolve(directory);
10170
10379
  if (!this._watched.has(dir))
10171
10380
  this._watched.set(dir, new DirEntry(dir, this._boundRemove));
10172
10381
  return this._watched.get(dir);
@@ -10177,8 +10386,8 @@ class FSWatcher extends EventEmitter {
10177
10386
  return Boolean(Number(stats.mode) & 256);
10178
10387
  }
10179
10388
  _remove(directory, item, isDirectory) {
10180
- const path = sysPath2.join(directory, item);
10181
- const fullPath = sysPath2.resolve(path);
10389
+ const path = sp2.join(directory, item);
10390
+ const fullPath = sp2.resolve(path);
10182
10391
  isDirectory = isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);
10183
10392
  if (!this._throttle("remove", path, 100))
10184
10393
  return;
@@ -10196,7 +10405,7 @@ class FSWatcher extends EventEmitter {
10196
10405
  }
10197
10406
  let relPath = path;
10198
10407
  if (this.options.cwd)
10199
- relPath = sysPath2.relative(this.options.cwd, path);
10408
+ relPath = sp2.relative(this.options.cwd, path);
10200
10409
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
10201
10410
  const event = this._pendingWrites.get(relPath).cancelWait();
10202
10411
  if (event === EVENTS.ADD)
@@ -10211,8 +10420,8 @@ class FSWatcher extends EventEmitter {
10211
10420
  }
10212
10421
  _closePath(path) {
10213
10422
  this._closeFile(path);
10214
- const dir = sysPath2.dirname(path);
10215
- this._getWatchedDir(dir).remove(sysPath2.basename(path));
10423
+ const dir = sp2.dirname(path);
10424
+ this._getWatchedDir(dir).remove(sp2.basename(path));
10216
10425
  }
10217
10426
  _closeFile(path) {
10218
10427
  const closers = this._closers.get(path);
@@ -10258,8 +10467,8 @@ function watch(paths, options = {}) {
10258
10467
  // src/commands/dev.ts
10259
10468
  function getEntryWatchPaths(root) {
10260
10469
  return [
10261
- join9(root, MANIFEST_FILE),
10262
- join9(root, "src", "actions.ts")
10470
+ join10(root, MANIFEST_FILE),
10471
+ join10(root, "src", "actions.ts")
10263
10472
  ];
10264
10473
  }
10265
10474
  async function dev() {
@@ -10298,26 +10507,59 @@ async function dev() {
10298
10507
  }
10299
10508
  console.log(source_default.blue("Actions changed -- entry regenerated"));
10300
10509
  });
10301
- const distDir = join9(root, "dist");
10302
- const bundleFile = join9(distDir, `space-${m.id}.iife.js`);
10510
+ const distDir = join10(root, "dist");
10511
+ const bundleFile = join10(distDir, `space-${m.id}.iife.js`);
10512
+ const cssFile = join10(distDir, `space-${m.id}.css`);
10303
10513
  let lastChecksum = "";
10304
- const distWatcher = watch(bundleFile, { ignoreInitial: false });
10305
- distWatcher.on("all", () => {
10306
- if (!existsSync7(bundleFile))
10514
+ const packageSpace = (force = false) => {
10515
+ if (!existsSync8(bundleFile) || !existsSync8(cssFile))
10307
10516
  return;
10308
10517
  const bundleData = readFileSync5(bundleFile);
10309
- const checksum = createHash2("sha256").update(bundleData).digest("hex");
10310
- if (checksum === lastChecksum)
10518
+ const checksum = createHash3("sha256").update(bundleData).digest("hex");
10519
+ if (!force && checksum === lastChecksum)
10311
10520
  return;
10312
10521
  lastChecksum = checksum;
10313
10522
  const raw = readRaw(root);
10314
10523
  writeWithBuild(distDir, raw, {
10315
10524
  checksum,
10316
10525
  size: bundleData.length,
10317
- hostApiVersion: "0.5.0",
10526
+ hostApiVersion: HOST_API_VERSION,
10318
10527
  builtAt: new Date().toISOString()
10319
10528
  });
10320
- console.log(source_default.green(`Built -> dist/ (${(bundleData.length / 1024).toFixed(1)} KB)`));
10529
+ stageSpaceResources(root, distDir);
10530
+ buildSpaceTools(root, distDir, m.id);
10531
+ createSpaceBundle({
10532
+ distDir,
10533
+ spaceId: m.id,
10534
+ appBundlePath: bundleFile,
10535
+ cssPath: cssFile
10536
+ });
10537
+ console.log(source_default.green(`Built -> dist/${m.id}.space (${(bundleData.length / 1024).toFixed(1)} KB)`));
10538
+ };
10539
+ const distWatcher = watch([bundleFile, cssFile], { ignoreInitial: false });
10540
+ distWatcher.on("all", () => {
10541
+ try {
10542
+ packageSpace();
10543
+ } catch (err) {
10544
+ console.error(source_default.red(err?.message || String(err)));
10545
+ }
10546
+ });
10547
+ const resourceWatcher = watch([
10548
+ join10(root, "tools.go"),
10549
+ join10(root, "tools"),
10550
+ join10(root, "lib"),
10551
+ join10(root, "agent"),
10552
+ join10(root, "scripts"),
10553
+ join10(root, "references"),
10554
+ join10(root, "assets"),
10555
+ join10(root, "SKILL.md")
10556
+ ], { ignoreInitial: true });
10557
+ resourceWatcher.on("all", () => {
10558
+ try {
10559
+ packageSpace(true);
10560
+ } catch (err) {
10561
+ console.error(source_default.red(err?.message || String(err)));
10562
+ }
10321
10563
  });
10322
10564
  console.log(source_default.green("Watching for changes... (Ctrl+C to stop)"));
10323
10565
  console.log(source_default.dim("Use the Preview button in Construct to open the Space Runner"));
@@ -10326,19 +10568,16 @@ async function dev() {
10326
10568
 
10327
10569
  // src/commands/run.ts
10328
10570
  init_source();
10329
- import { existsSync as existsSync9, cpSync as cpSync2, mkdirSync as mkdirSync3, readdirSync as readdirSync4, chmodSync, lstatSync, rmSync } from "fs";
10330
- import { join as join11 } from "path";
10571
+ import { existsSync as existsSync10, cpSync as cpSync2, mkdirSync as mkdirSync5, readdirSync as readdirSync4, chmodSync, lstatSync as lstatSync2, rmSync as rmSync3 } from "fs";
10572
+ import { join as join12 } from "path";
10331
10573
  init_appdir();
10332
- function ensureBinExecutable(installDir) {
10574
+ function ensureExecutableResources(installDir) {
10333
10575
  if (process.platform === "win32")
10334
10576
  return;
10335
- const binRoot = join11(installDir, "bin");
10336
- if (!existsSync9(binRoot))
10337
- return;
10338
10577
  const walk = (dir) => {
10339
10578
  for (const name of readdirSync4(dir)) {
10340
- const path = join11(dir, name);
10341
- const st = lstatSync(path);
10579
+ const path = join12(dir, name);
10580
+ const st = lstatSync2(path);
10342
10581
  if (st.isSymbolicLink())
10343
10582
  continue;
10344
10583
  if (st.isDirectory()) {
@@ -10348,7 +10587,11 @@ function ensureBinExecutable(installDir) {
10348
10587
  }
10349
10588
  }
10350
10589
  };
10351
- walk(binRoot);
10590
+ for (const dirname5 of ["tools", "lib"]) {
10591
+ const root = join12(installDir, dirname5);
10592
+ if (existsSync10(root))
10593
+ walk(root);
10594
+ }
10352
10595
  }
10353
10596
  function install() {
10354
10597
  const root = process.cwd();
@@ -10356,34 +10599,36 @@ function install() {
10356
10599
  console.error(source_default.red("No space.manifest.json found in current directory"));
10357
10600
  process.exit(1);
10358
10601
  }
10359
- const distDir = join11(root, "dist");
10360
- if (!existsSync9(distDir)) {
10602
+ const distDir = join12(root, "dist");
10603
+ if (!existsSync10(distDir)) {
10361
10604
  console.error(source_default.red("No dist/ directory found. Run 'construct build' first."));
10362
10605
  process.exit(1);
10363
10606
  }
10364
10607
  const m = read(root);
10365
- const agentDir = join11(root, "agent");
10366
- if (existsSync9(agentDir)) {
10367
- bundleAgentDir(agentDir, distDir);
10608
+ const bundleDir = join12(distDir, `${m.id}.space`);
10609
+ if (!existsSync10(bundleDir)) {
10610
+ console.error(source_default.red(`No dist/${m.id}.space directory found. Run 'construct build' first.`));
10611
+ process.exit(1);
10368
10612
  }
10369
10613
  const installDir = spaceDir(m.id);
10370
- rmSync(installDir, { recursive: true, force: true });
10371
- mkdirSync3(installDir, { recursive: true });
10372
- cpSync2(distDir, installDir, { recursive: true, verbatimSymlinks: true, force: true });
10373
- ensureBinExecutable(installDir);
10614
+ rmSync3(join12(spacesDir(), m.id), { recursive: true, force: true });
10615
+ rmSync3(installDir, { recursive: true, force: true });
10616
+ mkdirSync5(installDir, { recursive: true });
10617
+ cpSync2(bundleDir, installDir, { recursive: true, verbatimSymlinks: true, force: true });
10618
+ ensureExecutableResources(installDir);
10374
10619
  console.log(source_default.green(`Installed ${m.name} -> ${installDir}`));
10375
10620
  console.log(source_default.dim(" Restart Construct to load the updated space."));
10376
10621
  }
10377
10622
 
10378
10623
  // src/commands/publish.ts
10379
10624
  init_source();
10380
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, statSync as statSync5, unlinkSync as unlinkSync2 } from "fs";
10381
- import { join as join14, basename as basename5 } from "path";
10625
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, statSync as statSync4, unlinkSync as unlinkSync2 } from "fs";
10626
+ import { join as join15, basename as basename5 } from "path";
10382
10627
  init_auth();
10383
10628
 
10384
10629
  // src/lib/pack.ts
10385
- import { readdirSync as readdirSync6, statSync as statSync4, existsSync as existsSync11 } from "fs";
10386
- import { join as join13 } from "path";
10630
+ import { readdirSync as readdirSync6, statSync as statSync3, existsSync as existsSync12 } from "fs";
10631
+ import { join as join14 } from "path";
10387
10632
  import { tmpdir } from "os";
10388
10633
  import { execFileSync as execFileSync2 } from "child_process";
10389
10634
  var allowedDirs = [
@@ -10406,7 +10651,9 @@ var allowedDirs = [
10406
10651
  "icons",
10407
10652
  "assets",
10408
10653
  "media",
10409
- "bin"
10654
+ "tools",
10655
+ "lib",
10656
+ "go-tools"
10410
10657
  ];
10411
10658
  var allowedRootFiles = [
10412
10659
  "space.manifest.json",
@@ -10416,20 +10663,24 @@ var allowedRootFiles = [
10416
10663
  "vite.config.js",
10417
10664
  "space.config.ts",
10418
10665
  "types.ts",
10419
- "index.ts"
10666
+ "index.ts",
10667
+ "SKILL.md",
10668
+ "tools.go",
10669
+ "go.mod",
10670
+ "go.sum"
10420
10671
  ];
10421
10672
  var allowedRootPatterns = [/.*\.config\.ts$/, /.*\.config\.js$/];
10422
10673
  var blockedExtensions = [".env", ".log", ".lock", ".lockb"];
10423
10674
  var MAX_SIZE = 50 * 1024 * 1024;
10424
10675
  async function packSource(root) {
10425
- const tarballPath = join13(tmpdir(), `space-source-${Date.now()}.tar.gz`);
10676
+ const tarballPath = join14(tmpdir(), `space-source-${Date.now()}.tar.gz`);
10426
10677
  const entries = [];
10427
10678
  for (const name of allowedRootFiles) {
10428
- if (existsSync11(join13(root, name)))
10679
+ if (existsSync12(join14(root, name)))
10429
10680
  entries.push(name);
10430
10681
  }
10431
10682
  for (const entry of readdirSync6(root)) {
10432
- if (statSync4(join13(root, entry)).isDirectory())
10683
+ if (statSync3(join14(root, entry)).isDirectory())
10433
10684
  continue;
10434
10685
  if (allowedRootFiles.includes(entry))
10435
10686
  continue;
@@ -10439,10 +10690,10 @@ async function packSource(root) {
10439
10690
  entries.push(entry);
10440
10691
  }
10441
10692
  for (const dir of allowedDirs) {
10442
- if (existsSync11(join13(root, dir)))
10693
+ if (existsSync12(join14(root, dir)))
10443
10694
  entries.push(dir);
10444
10695
  }
10445
- const validEntries = entries.filter((e) => existsSync11(join13(root, e)));
10696
+ const validEntries = entries.filter((e) => existsSync12(join14(root, e)));
10446
10697
  if (validEntries.length === 0) {
10447
10698
  throw new Error("No files to pack");
10448
10699
  }
@@ -10450,13 +10701,15 @@ async function packSource(root) {
10450
10701
  "--exclude=node_modules",
10451
10702
  "--exclude=dist",
10452
10703
  "--exclude=.git",
10704
+ "--exclude=go-tools/spaceprobe",
10705
+ "--exclude=go-tools/spaceprobe.exe",
10453
10706
  "--exclude=*.env",
10454
10707
  "--exclude=*.log",
10455
10708
  "--exclude=*.lock",
10456
10709
  "--exclude=*.lockb"
10457
10710
  ];
10458
10711
  execFileSync2("tar", ["czf", tarballPath, ...excludes, ...validEntries], { cwd: root });
10459
- const size = statSync4(tarballPath).size;
10712
+ const size = statSync3(tarballPath).size;
10460
10713
  if (size > MAX_SIZE) {
10461
10714
  throw new Error(`Source exceeds maximum size of ${MAX_SIZE / 1024 / 1024}MB`);
10462
10715
  }
@@ -10535,7 +10788,7 @@ function setVersionInFiles(root, oldVer, newVer) {
10535
10788
  const oldStr = `"version": "${oldVer}"`;
10536
10789
  const newStr = `"version": "${newVer}"`;
10537
10790
  for (const file of ["package.json", "space.manifest.json"]) {
10538
- const path = join14(root, file);
10791
+ const path = join15(root, file);
10539
10792
  try {
10540
10793
  const data = readFileSync8(path, "utf-8");
10541
10794
  writeFileSync6(path, data.replace(oldStr, newStr));
@@ -10694,7 +10947,7 @@ async function publish(options) {
10694
10947
  let tarballPath;
10695
10948
  try {
10696
10949
  tarballPath = await packSource(root);
10697
- const size = statSync5(tarballPath).size;
10950
+ const size = statSync4(tarballPath).size;
10698
10951
  spinner.succeed(`Source packed (${formatBytes(size)})`);
10699
10952
  } catch (err) {
10700
10953
  spinner.fail("Pack failed");
@@ -10762,8 +11015,8 @@ async function publish(options) {
10762
11015
 
10763
11016
  // src/commands/validate.ts
10764
11017
  init_source();
10765
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
10766
- import { join as join15 } from "path";
11018
+ import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
11019
+ import { join as join16 } from "path";
10767
11020
 
10768
11021
  // src/lib/pagePaths.ts
10769
11022
  function pageComponentFromPath(path) {
@@ -10797,21 +11050,21 @@ function validate3() {
10797
11050
  let warnings = 0;
10798
11051
  for (const page of m.pages) {
10799
11052
  const component = page.component || pageComponentFromPath(page.path);
10800
- const fullPath = join15(root, "src", component);
10801
- if (!existsSync12(fullPath)) {
11053
+ const fullPath = join16(root, "src", component);
11054
+ if (!existsSync13(fullPath)) {
10802
11055
  console.log(source_default.yellow(` \u26A0 Page component not found: src/${component}`));
10803
11056
  warnings++;
10804
11057
  }
10805
11058
  }
10806
11059
  if (m.agent) {
10807
- const agentPath = join15(root, m.agent);
10808
- if (!existsSync12(agentPath)) {
11060
+ const agentPath = join16(root, m.agent);
11061
+ if (!existsSync13(agentPath)) {
10809
11062
  console.log(source_default.yellow(` \u26A0 Agent config not found: ${m.agent}`));
10810
11063
  warnings++;
10811
11064
  }
10812
11065
  }
10813
- const pkgPath = join15(root, "package.json");
10814
- if (existsSync12(pkgPath)) {
11066
+ const pkgPath = join16(root, "package.json");
11067
+ if (existsSync13(pkgPath)) {
10815
11068
  const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
10816
11069
  if (pkg.version && pkg.version !== m.version) {
10817
11070
  console.log(source_default.yellow(` \u26A0 Version mismatch: manifest=${m.version} package.json=${pkg.version}`));
@@ -10828,8 +11081,8 @@ function validate3() {
10828
11081
  // src/commands/check.ts
10829
11082
  init_source();
10830
11083
  import { execSync as execSync2 } from "child_process";
10831
- import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
10832
- import { join as join16 } from "path";
11084
+ import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
11085
+ import { join as join17 } from "path";
10833
11086
  function check() {
10834
11087
  const root = process.cwd();
10835
11088
  if (!exists(root)) {
@@ -10848,17 +11101,17 @@ function check() {
10848
11101
  let warnings = 0;
10849
11102
  for (const page of m.pages) {
10850
11103
  const component = page.component || pageComponentFromPath(page.path);
10851
- if (!existsSync13(join16(root, "src", component))) {
11104
+ if (!existsSync14(join17(root, "src", component))) {
10852
11105
  console.log(source_default.yellow(` \u26A0 Page not found: src/${component}`));
10853
11106
  warnings++;
10854
11107
  }
10855
11108
  }
10856
- if (m.agent && !existsSync13(join16(root, m.agent))) {
11109
+ if (m.agent && !existsSync14(join17(root, m.agent))) {
10857
11110
  console.log(source_default.yellow(` \u26A0 Agent config not found: ${m.agent}`));
10858
11111
  warnings++;
10859
11112
  }
10860
- const pkgPath = join16(root, "package.json");
10861
- if (existsSync13(pkgPath)) {
11113
+ const pkgPath = join17(root, "package.json");
11114
+ if (existsSync14(pkgPath)) {
10862
11115
  const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
10863
11116
  if (pkg.version && pkg.version !== m.version) {
10864
11117
  console.log(source_default.yellow(` \u26A0 Version mismatch: manifest=${m.version} package.json=${pkg.version}`));
@@ -10891,8 +11144,8 @@ function check() {
10891
11144
 
10892
11145
  // src/commands/clean.ts
10893
11146
  init_source();
10894
- import { rmSync as rmSync2, existsSync as existsSync14 } from "fs";
10895
- import { join as join17 } from "path";
11147
+ import { rmSync as rmSync4, existsSync as existsSync15 } from "fs";
11148
+ import { join as join18 } from "path";
10896
11149
  function clean(options) {
10897
11150
  const root = process.cwd();
10898
11151
  const dirs = ["dist", ".vite"];
@@ -10901,17 +11154,17 @@ function clean(options) {
10901
11154
  }
10902
11155
  const lockfiles = ["bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"];
10903
11156
  for (const dir of dirs) {
10904
- const path = join17(root, dir);
10905
- if (existsSync14(path)) {
10906
- rmSync2(path, { recursive: true });
11157
+ const path = join18(root, dir);
11158
+ if (existsSync15(path)) {
11159
+ rmSync4(path, { recursive: true });
10907
11160
  console.log(source_default.dim(` Removed ${dir}/`));
10908
11161
  }
10909
11162
  }
10910
11163
  if (options?.all) {
10911
11164
  for (const file of lockfiles) {
10912
- const path = join17(root, file);
10913
- if (existsSync14(path)) {
10914
- rmSync2(path);
11165
+ const path = join18(root, file);
11166
+ if (existsSync15(path)) {
11167
+ rmSync4(path);
10915
11168
  console.log(source_default.dim(` Removed ${file}`));
10916
11169
  }
10917
11170
  }
@@ -11071,8 +11324,8 @@ function update() {
11071
11324
 
11072
11325
  // src/commands/graph/init.ts
11073
11326
  init_source();
11074
- import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "fs";
11075
- import { join as join18 } from "path";
11327
+ import { existsSync as existsSync16, readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
11328
+ import { join as join19 } from "path";
11076
11329
  import { execSync as execSync4 } from "child_process";
11077
11330
  function graphInit() {
11078
11331
  const root = process.cwd();
@@ -11082,10 +11335,10 @@ function graphInit() {
11082
11335
  process.exit(1);
11083
11336
  }
11084
11337
  const m = read(root);
11085
- const modelsDir = join18(root, "src", "models");
11086
- mkdirSync5(modelsDir, { recursive: true });
11087
- const indexPath = join18(modelsDir, "index.ts");
11088
- if (!existsSync15(indexPath)) {
11338
+ const modelsDir = join19(root, "src", "models");
11339
+ mkdirSync7(modelsDir, { recursive: true });
11340
+ const indexPath = join19(modelsDir, "index.ts");
11341
+ if (!existsSync16(indexPath)) {
11089
11342
  writeFileSync7(indexPath, `// Data models for ${m.name}
11090
11343
  // Generated by construct graph init
11091
11344
 
@@ -11093,7 +11346,7 @@ function graphInit() {
11093
11346
  // export { User } from './User'
11094
11347
  `);
11095
11348
  }
11096
- const pkgPath = join18(root, "package.json");
11349
+ const pkgPath = join19(root, "package.json");
11097
11350
  const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
11098
11351
  if (!pkg.dependencies)
11099
11352
  pkg.dependencies = {};
@@ -11125,8 +11378,8 @@ function graphInit() {
11125
11378
 
11126
11379
  // src/commands/graph/generate.ts
11127
11380
  init_source();
11128
- import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6 } from "fs";
11129
- import { join as join19 } from "path";
11381
+ import { existsSync as existsSync17, readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
11382
+ import { join as join20 } from "path";
11130
11383
  var FIELD_TYPES = {
11131
11384
  string: "field.string()",
11132
11385
  int: "field.int()",
@@ -11278,10 +11531,10 @@ function generate2(modelName, fieldSpecs, options) {
11278
11531
  lines.push("");
11279
11532
  const content = lines.join(`
11280
11533
  `);
11281
- const modelsDir = join19(root, "src", "models");
11282
- mkdirSync6(modelsDir, { recursive: true });
11283
- const filePath = join19(modelsDir, `${name}.ts`);
11284
- if (existsSync16(filePath)) {
11534
+ const modelsDir = join20(root, "src", "models");
11535
+ mkdirSync8(modelsDir, { recursive: true });
11536
+ const filePath = join20(modelsDir, `${name}.ts`);
11537
+ if (existsSync17(filePath)) {
11285
11538
  console.log(source_default.yellow(` Model file already exists: src/models/${name}.ts`));
11286
11539
  console.log(source_default.dim(" Overwriting..."));
11287
11540
  }
@@ -11298,9 +11551,9 @@ function generate2(modelName, fieldSpecs, options) {
11298
11551
  console.log();
11299
11552
  }
11300
11553
  function updateBarrel(modelsDir, modelName) {
11301
- const indexPath = join19(modelsDir, "index.ts");
11554
+ const indexPath = join20(modelsDir, "index.ts");
11302
11555
  const exportLine = `export { ${modelName} } from './${modelName}'`;
11303
- if (existsSync16(indexPath)) {
11556
+ if (existsSync17(indexPath)) {
11304
11557
  const content = readFileSync12(indexPath, "utf-8");
11305
11558
  if (content.includes(exportLine))
11306
11559
  return;
@@ -11316,8 +11569,8 @@ function updateBarrel(modelsDir, modelName) {
11316
11569
 
11317
11570
  // src/commands/graph/push.ts
11318
11571
  init_source();
11319
- import { existsSync as existsSync17, readdirSync as readdirSync7, readFileSync as readFileSync13 } from "fs";
11320
- import { join as join20 } from "path";
11572
+ import { existsSync as existsSync18, readdirSync as readdirSync7, readFileSync as readFileSync13 } from "fs";
11573
+ import { join as join21 } from "path";
11321
11574
  init_auth();
11322
11575
  async function graphPush() {
11323
11576
  const root = process.cwd();
@@ -11326,8 +11579,8 @@ async function graphPush() {
11326
11579
  process.exit(1);
11327
11580
  }
11328
11581
  const m = read(root);
11329
- const modelsDir = join20(root, "src", "models");
11330
- if (!existsSync17(modelsDir)) {
11582
+ const modelsDir = join21(root, "src", "models");
11583
+ if (!existsSync18(modelsDir)) {
11331
11584
  console.error(source_default.red("No src/models/ directory found. Run 'construct graph init' first."));
11332
11585
  process.exit(1);
11333
11586
  }
@@ -11340,7 +11593,7 @@ async function graphPush() {
11340
11593
  console.log(source_default.blue(`Pushing ${modelFiles.length} model(s) for space: ${m.id}`));
11341
11594
  const models = [];
11342
11595
  for (const file of modelFiles) {
11343
- const content = readFileSync13(join20(modelsDir, file), "utf-8");
11596
+ const content = readFileSync13(join21(modelsDir, file), "utf-8");
11344
11597
  const model = parseModelFile(content);
11345
11598
  if (model)
11346
11599
  models.push(model);
@@ -11523,8 +11776,8 @@ function parseModelFile(content) {
11523
11776
 
11524
11777
  // src/commands/graph/migrate.ts
11525
11778
  init_source();
11526
- import { existsSync as existsSync18, readdirSync as readdirSync8, readFileSync as readFileSync14 } from "fs";
11527
- import { join as join21 } from "path";
11779
+ import { existsSync as existsSync19, readdirSync as readdirSync8, readFileSync as readFileSync14 } from "fs";
11780
+ import { join as join22 } from "path";
11528
11781
  init_auth();
11529
11782
  async function graphMigrate(options) {
11530
11783
  const root = process.cwd();
@@ -11533,8 +11786,8 @@ async function graphMigrate(options) {
11533
11786
  process.exit(1);
11534
11787
  }
11535
11788
  const m = read(root);
11536
- const modelsDir = join21(root, "src", "models");
11537
- if (!existsSync18(modelsDir)) {
11789
+ const modelsDir = join22(root, "src", "models");
11790
+ if (!existsSync19(modelsDir)) {
11538
11791
  console.error(source_default.red("No src/models/ directory. Run 'construct graph init' first."));
11539
11792
  process.exit(1);
11540
11793
  }
@@ -11564,7 +11817,7 @@ async function graphMigrate(options) {
11564
11817
  const modelFiles = readdirSync8(modelsDir).filter((f) => f.endsWith(".ts") && f !== "index.ts");
11565
11818
  const localModels = [];
11566
11819
  for (const file of modelFiles) {
11567
- const content = readFileSync14(join21(modelsDir, file), "utf-8");
11820
+ const content = readFileSync14(join22(modelsDir, file), "utf-8");
11568
11821
  const model = parseModelFields(content);
11569
11822
  if (model)
11570
11823
  localModels.push(model);
@@ -11700,7 +11953,7 @@ function graphFork(newSpaceID) {
11700
11953
  // package.json
11701
11954
  var package_default = {
11702
11955
  name: "@construct-space/cli",
11703
- version: "1.9.4",
11956
+ version: "1.9.6",
11704
11957
  description: "Construct CLI \u2014 scaffold, build, develop, and publish spaces",
11705
11958
  type: "module",
11706
11959
  bin: {
@@ -11719,7 +11972,9 @@ var package_default = {
11719
11972
  build: "bun build src/index.ts --outdir dist --target bun --format esm && cp -r templates dist/",
11720
11973
  dev: "bun run src/index.ts",
11721
11974
  test: "bun test",
11722
- typecheck: "tsc --noEmit"
11975
+ typecheck: "tsc --noEmit",
11976
+ lint: "eslint src",
11977
+ "lint:fix": "eslint src --fix"
11723
11978
  },
11724
11979
  dependencies: {
11725
11980
  commander: "^14.0.3",
@@ -11730,7 +11985,10 @@ var package_default = {
11730
11985
  },
11731
11986
  devDependencies: {
11732
11987
  "@types/bun": "latest",
11733
- typescript: "^6.0.2"
11988
+ typescript: "^6.0.2",
11989
+ eslint: "^10.4.0",
11990
+ "@eslint/js": "^10.0.1",
11991
+ "typescript-eslint": "^8.59.4"
11734
11992
  },
11735
11993
  keywords: [
11736
11994
  "construct",