@construct-space/cli 1.1.9 → 1.1.12

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
@@ -5,25 +5,43 @@ var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
8
13
  var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
9
21
  target = mod != null ? __create(__getProtoOf(mod)) : {};
10
22
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
23
  for (let key of __getOwnPropNames(mod))
12
24
  if (!__hasOwnProp.call(to, key))
13
25
  __defProp(to, key, {
14
- get: () => mod[key],
26
+ get: __accessProp.bind(mod, key),
15
27
  enumerable: true
16
28
  });
29
+ if (canCache)
30
+ cache.set(mod, to);
17
31
  return to;
18
32
  };
19
33
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
+ var __returnValue = (v) => v;
35
+ function __exportSetter(name, newValue) {
36
+ this[name] = __returnValue.bind(null, newValue);
37
+ }
20
38
  var __export = (target, all) => {
21
39
  for (var name in all)
22
40
  __defProp(target, name, {
23
41
  get: all[name],
24
42
  enumerable: true,
25
43
  configurable: true,
26
- set: (newValue) => all[name] = () => newValue
44
+ set: __exportSetter.bind(all, name)
27
45
  });
28
46
  };
29
47
  var __require = import.meta.require;
@@ -2789,7 +2807,6 @@ Object.defineProperties(createChalk.prototype, styles2);
2789
2807
  var chalk = createChalk();
2790
2808
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2791
2809
  var source_default = chalk;
2792
-
2793
2810
  // node_modules/@inquirer/core/dist/lib/key.js
2794
2811
  var isUpKey = (key, keybindings = []) => key.name === "up" || keybindings.includes("vim") && key.name === "k" || keybindings.includes("emacs") && key.ctrl && key.name === "p";
2795
2812
  var isDownKey = (key, keybindings = []) => key.name === "down" || keybindings.includes("vim") && key.name === "j" || keybindings.includes("emacs") && key.ctrl && key.name === "n";
@@ -2934,7 +2951,7 @@ var effectScheduler = {
2934
2951
  // node_modules/@inquirer/core/dist/lib/use-state.js
2935
2952
  function useState(defaultValue) {
2936
2953
  return withPointer((pointer) => {
2937
- const setState = AsyncResource2.bind(function setState(newValue) {
2954
+ const setState = AsyncResource2.bind(function setState2(newValue) {
2938
2955
  if (pointer.get() !== newValue) {
2939
2956
  pointer.set(newValue);
2940
2957
  handleChange();
@@ -4590,10 +4607,605 @@ function watchCmd(root, _rt) {
4590
4607
  return spawn("bun", ["run", "vite", "build", "--watch"], { cwd: root, stdio: "pipe" });
4591
4608
  }
4592
4609
  function runHook(hooks, hookName, root) {
4593
- if (!hooks || !hooks[hookName])
4610
+ const cmd = hooks?.[hookName];
4611
+ if (!cmd)
4594
4612
  return;
4595
- execSync2(hooks[hookName], { cwd: root, stdio: "inherit" });
4613
+ execSync2(cmd, { cwd: root, stdio: "inherit" });
4614
+ }
4615
+
4616
+ // src/lib/embedded-templates.ts
4617
+ var EMBEDDED_TEMPLATES = {
4618
+ "package.json.tmpl": `{
4619
+ "name": "@construct-spaces/{{.Name}}",
4620
+ "version": "0.1.0",
4621
+ "private": true,
4622
+ "type": "module",
4623
+ "scripts": {
4624
+ "generate-entry": "construct build --entry-only",
4625
+ "build": "construct build",
4626
+ "dev": "construct dev",
4627
+ "check": "construct check",
4628
+ "validate": "construct validate"
4629
+ },
4630
+ "peerDependencies": {
4631
+ "vue": "^3.5.0",
4632
+ "pinia": "^3.0.0",
4633
+ "@vueuse/core": "^14.0.0"
4634
+ },
4635
+ "devDependencies": {
4636
+ "@construct-space/cli": "latest",
4637
+ "@construct-space/sdk": "latest",
4638
+ "@vitejs/plugin-vue": "^5.2.3",
4639
+ "lucide-vue-next": "^1.0.0",
4640
+ "typescript": "^5.9.3",
4641
+ "vite": "^6.3.5",
4642
+ "vue-tsc": "^3.2.5"
4643
+ }
4644
+ }
4645
+ `,
4646
+ "config.md.tmpl": `---
4647
+ id: {{.ID}}
4648
+ name: {{.DisplayName}}
4649
+ category: space
4650
+ description: AI agent for the {{.DisplayName}} space
4651
+ maxIterations: 15
4652
+ tools: []
4653
+ canInvokeAgents: []
4654
+ ---
4655
+
4656
+ You are Construct's {{.DisplayName}} agent. You help users work within the {{.DisplayName}} space.
4657
+
4658
+ ## Context
4659
+
4660
+ Use space_list_actions to discover available actions for this space.
4661
+ Use space_run_action to execute actions.
4662
+ Do NOT call get_project_context \u2014 you work with space content, not project files.
4663
+
4664
+ ## Behavior
4665
+
4666
+ - Start by listing available actions to understand what you can do
4667
+ - Be concise and action-oriented
4668
+ - Focus on tasks relevant to this space
4669
+ `,
4670
+ "full/skill-data.md.tmpl": `---
4671
+ id: {{.ID}}-data
4672
+ name: {{.DisplayName}} Data Management
4673
+ description: Skill for managing {{.DisplayName}} data and content
4674
+ trigger: {{.ID}} data|content|manage
4675
+ category: space
4676
+ tools: [read_file, list_dir, glob, grep, write_file]
4677
+ ---
4678
+
4679
+ # {{.DisplayName}} Data Management Skill
4680
+
4681
+ This skill handles data operations for the {{.DisplayName}} space.
4682
+
4683
+ ## Instructions
4684
+ - Help users create, read, update, and delete content
4685
+ - Validate data before writing
4686
+ - Use the space actions API when available
4687
+ - Prefer batch operations for bulk changes
4688
+ `,
4689
+ "full/entry.ts.tmpl": `// Space entry \u2014 exports pages, widgets, and actions for the host loader.
4690
+ // \`construct dev\` regenerates this from space.manifest.json on changes.
4691
+ import IndexPage from './pages/index.vue'
4692
+ import SettingsPage from './pages/settings.vue'
4693
+ import { actions } from './actions'
4694
+
4695
+ const spaceExport = {
4696
+ pages: {
4697
+ '': IndexPage,
4698
+ 'settings': SettingsPage,
4699
+ },
4700
+ widgets: {},
4701
+ actions,
4702
+ }
4703
+
4704
+ export default spaceExport
4705
+ `,
4706
+ "full/skill-ui.md.tmpl": `---
4707
+ id: {{.ID}}-ui
4708
+ name: {{.DisplayName}} UI Customization
4709
+ description: Skill for customizing the {{.DisplayName}} user interface
4710
+ trigger: {{.ID}} ui|layout|design|style
4711
+ category: space
4712
+ tools: [read_file, write_file, glob]
4713
+ ---
4714
+
4715
+ # {{.DisplayName}} UI Customization Skill
4716
+
4717
+ This skill helps customize the {{.DisplayName}} space interface.
4718
+
4719
+ ## Instructions
4720
+ - Help users adjust layout and styling
4721
+ - Use Construct CSS variables (--app-foreground, --app-background, --app-accent, etc.)
4722
+ - Follow the host design system conventions
4723
+ - Suggest accessible color combinations
4724
+ `,
4725
+ "full/space.manifest.json.tmpl": `{
4726
+ "id": "{{.ID}}",
4727
+ "name": "{{.DisplayName}}",
4728
+ "version": "0.1.0",
4729
+ "description": "{{.DisplayName}} space for Construct",
4730
+ "author": {
4731
+ "name": "Your Name"
4732
+ },
4733
+ "icon": "i-lucide-box",
4734
+ "scope": "both",
4735
+ "minConstructVersion": "0.7.0",
4736
+ "navigation": {
4737
+ "label": "{{.DisplayName}}",
4738
+ "icon": "i-lucide-box",
4739
+ "to": "{{.ID}}",
4740
+ "order": 100
4741
+ },
4742
+ "pages": [
4743
+ {
4744
+ "path": "",
4745
+ "label": "Home",
4746
+ "icon": "i-lucide-home",
4747
+ "default": true
4748
+ },
4749
+ {
4750
+ "path": "settings",
4751
+ "label": "Settings",
4752
+ "icon": "i-lucide-settings"
4753
+ }
4754
+ ],
4755
+ "toolbar": [
4756
+ {
4757
+ "id": "{{.ID}}-new",
4758
+ "icon": "i-lucide-plus",
4759
+ "label": "New {{.DisplayName}}",
4760
+ "action": "create{{.DisplayNameNoSpace}}"
4761
+ }
4762
+ ],
4763
+ "keywords": ["{{.ID}}"],
4764
+ "agent": "agent/config.md",
4765
+ "skills": [
4766
+ "agent/skills/default.md",
4767
+ "agent/skills/data.md",
4768
+ "agent/skills/ui.md"
4769
+ ],
4770
+ "actions": "src/actions.ts",
4771
+ "widgets": [
4772
+ {
4773
+ "id": "summary",
4774
+ "name": "{{.DisplayName}} Summary",
4775
+ "description": "Quick summary widget for {{.DisplayName}}",
4776
+ "icon": "i-lucide-box",
4777
+ "defaultSize": "4x1",
4778
+ "sizes": {
4779
+ "2x1": "widgets/summary/2x1.vue",
4780
+ "4x1": "widgets/summary/4x1.vue"
4781
+ }
4782
+ }
4783
+ ]
4784
+ }
4785
+ `,
4786
+ "full/settings.vue.tmpl": `<script setup lang="ts">
4787
+ /**
4788
+ * {{.DisplayName}} \u2014 Settings page
4789
+ */
4790
+ import { ref } from 'vue'
4791
+
4792
+ const autoSave = ref(true)
4793
+ const theme = ref<'system' | 'light' | 'dark'>('system')
4794
+ </script>
4795
+
4796
+ <template>
4797
+ <div class="h-full overflow-auto p-6">
4798
+ <h1 class="text-xl font-bold text-[var(--app-foreground)] mb-6">Settings</h1>
4799
+
4800
+ <div class="space-y-4 max-w-md">
4801
+ <label class="flex items-center justify-between">
4802
+ <span class="text-sm text-[var(--app-foreground)]">Auto-save</span>
4803
+ <input v-model="autoSave" type="checkbox" class="rounded" />
4804
+ </label>
4805
+
4806
+ <label class="block">
4807
+ <span class="text-sm text-[var(--app-foreground)] block mb-1">Theme</span>
4808
+ <select v-model="theme" class="w-full rounded border border-[var(--app-border)] bg-[var(--app-background)] px-3 py-1.5 text-sm">
4809
+ <option value="system">System</option>
4810
+ <option value="light">Light</option>
4811
+ <option value="dark">Dark</option>
4812
+ </select>
4813
+ </label>
4814
+ </div>
4815
+ </div>
4816
+ </template>
4817
+ `,
4818
+ "vite.config.ts.tmpl": `import { defineConfig } from 'vite'
4819
+ import vue from '@vitejs/plugin-vue'
4820
+ import { resolve } from 'path'
4821
+
4822
+ /**
4823
+ * Host-provided externals \u2014 these are supplied by Construct at runtime
4824
+ * via window.__CONSTRUCT__. Do NOT bundle them; they must stay external.
4825
+ *
4826
+ * Full list lives in: construct-app/frontend/lib/spaceHost.ts
4827
+ */
4828
+ const hostExternals = [
4829
+ 'vue',
4830
+ 'vue-router',
4831
+ 'pinia',
4832
+ '@vueuse/core',
4833
+ '@vueuse/integrations',
4834
+ '@tauri-apps/api',
4835
+ '@tauri-apps/api/core',
4836
+ '@tauri-apps/api/path',
4837
+ '@tauri-apps/api/event',
4838
+ '@tauri-apps/api/webview',
4839
+ '@tauri-apps/plugin-fs',
4840
+ '@tauri-apps/plugin-shell',
4841
+ '@tauri-apps/plugin-dialog',
4842
+ '@tauri-apps/plugin-process',
4843
+ 'lucide-vue-next',
4844
+ 'date-fns',
4845
+ 'dexie',
4846
+ 'zod',
4847
+ '@construct-space/ui',
4848
+ '@construct/sdk',
4849
+ '@construct-space/sdk',
4850
+ ]
4851
+
4852
+ function makeGlobals(externals: string[]): Record<string, string> {
4853
+ const globals: Record<string, string> = {}
4854
+ for (const ext of externals) {
4855
+ // Simple ids use dot access, scoped/slashed ids use bracket access
4856
+ if (/^[a-z]+$/.test(ext)) {
4857
+ globals[ext] = \`window.__CONSTRUCT__.\${ext}\`
4858
+ } else {
4859
+ globals[ext] = \`window.__CONSTRUCT__["\${ext}"]\`
4860
+ }
4861
+ }
4862
+ return globals
4863
+ }
4864
+
4865
+ export default defineConfig({
4866
+ plugins: [vue()],
4867
+ build: {
4868
+ lib: {
4869
+ entry: resolve(__dirname, 'src/entry.ts'),
4870
+ name: '__CONSTRUCT_SPACE_{{.IDUpper}}',
4871
+ fileName: 'space-{{.ID}}',
4872
+ formats: ['iife'],
4873
+ },
4874
+ rollupOptions: {
4875
+ external: hostExternals,
4876
+ output: {
4877
+ globals: makeGlobals(hostExternals),
4878
+ },
4879
+ },
4880
+ },
4881
+ resolve: {
4882
+ alias: {
4883
+ '~': resolve(__dirname),
4884
+ '@': resolve(__dirname, 'src'),
4885
+ },
4886
+ },
4887
+ })
4888
+ `,
4889
+ "index.vue.tmpl": `<script setup lang="ts">
4890
+ /**
4891
+ * {{.DisplayName}} \u2014 Home page
4892
+ *
4893
+ * Host-provided packages (vue, pinia, @vueuse/core, @construct/sdk, etc.)
4894
+ * are available as imports \u2014 they resolve to the host at runtime.
4895
+ */
4896
+ import { ref } from 'vue'
4897
+
4898
+ const greeting = ref('Your space is ready. Start building!')
4899
+ </script>
4900
+
4901
+ <template>
4902
+ <div class="h-full flex items-center justify-center">
4903
+ <div class="text-center">
4904
+ <h1 class="text-2xl font-bold text-[var(--app-foreground)] mb-2">{{.DisplayName}}</h1>
4905
+ <p class="text-sm text-[var(--app-muted)]">{{ greeting }}</p>
4906
+ </div>
4907
+ </div>
4908
+ </template>
4909
+ `,
4910
+ "entry.ts.tmpl": `// Space entry \u2014 exports pages, widgets, and actions for the host loader.
4911
+ // \`construct dev\` regenerates this from space.manifest.json on changes.
4912
+ import IndexPage from './pages/index.vue'
4913
+ import { actions } from './actions'
4914
+
4915
+ const spaceExport = {
4916
+ pages: {
4917
+ '': IndexPage,
4918
+ },
4919
+ widgets: {},
4920
+ actions,
4921
+ }
4922
+
4923
+ export default spaceExport
4924
+ `,
4925
+ "space.manifest.json.tmpl": `{
4926
+ "id": "{{.ID}}",
4927
+ "name": "{{.DisplayName}}",
4928
+ "version": "0.1.0",
4929
+ "description": "{{.DisplayName}} space for Construct",
4930
+ "author": {
4931
+ "name": "Your Name"
4932
+ },
4933
+ "icon": "i-lucide-box",
4934
+ "scope": "both",
4935
+ "minConstructVersion": "0.7.0",
4936
+ "navigation": {
4937
+ "label": "{{.DisplayName}}",
4938
+ "icon": "i-lucide-box",
4939
+ "to": "{{.ID}}",
4940
+ "order": 100
4941
+ },
4942
+ "pages": [
4943
+ {
4944
+ "path": "",
4945
+ "label": "Home",
4946
+ "icon": "i-lucide-home",
4947
+ "default": true
4948
+ }
4949
+ ],
4950
+ "toolbar": [
4951
+ {
4952
+ "id": "{{.ID}}-new",
4953
+ "icon": "i-lucide-plus",
4954
+ "label": "New {{.DisplayName}}",
4955
+ "action": "create{{.DisplayNameNoSpace}}"
4956
+ }
4957
+ ],
4958
+ "keywords": ["{{.ID}}"],
4959
+ "agent": "agent/config.md",
4960
+ "skills": ["agent/skills/default.md"],
4961
+ "actions": {},
4962
+ "widgets": [
4963
+ {
4964
+ "id": "summary",
4965
+ "name": "{{.DisplayName}} Summary",
4966
+ "description": "Quick summary widget for {{.DisplayName}}",
4967
+ "icon": "i-lucide-box",
4968
+ "defaultSize": "4x1",
4969
+ "sizes": {
4970
+ "2x1": "widgets/summary/2x1.vue",
4971
+ "4x1": "widgets/summary/4x1.vue"
4972
+ }
4973
+ }
4974
+ ]
4975
+ }
4976
+ `,
4977
+ "skill.md.tmpl": `---
4978
+ id: {{.ID}}-default
4979
+ name: {{.DisplayName}} Basics
4980
+ description: Default skill for {{.DisplayName}} space
4981
+ trigger: {{.ID}}|help
4982
+ category: space
4983
+ tools: [read_file, list_dir, glob, grep]
4984
+ ---
4985
+
4986
+ # {{.DisplayName}} Space Skill
4987
+
4988
+ This skill provides default behavior for the {{.DisplayName}} space.
4989
+
4990
+ ## Instructions
4991
+ - Assist with {{.DisplayName}}-related tasks
4992
+ - Follow project conventions
4993
+ - Read relevant files before making suggestions
4994
+ `,
4995
+ "gitignore.tmpl": `node_modules/
4996
+ dist/
4997
+ src/entry.ts
4998
+ *.local
4999
+ .DS_Store
5000
+ `,
5001
+ "actions.ts.tmpl": `/**
5002
+ * Space Actions \u2014 exposed to the AI agent via space_run_action
5003
+ *
5004
+ * Define actions here and they'll be automatically available as agent tools.
5005
+ * The agent calls: space_run_action(action: "action_id", payload: {...})
5006
+ */
5007
+
5008
+ // --- Graph SDK (data layer) ---
5009
+ // Uncomment after running \`construct graph init\` and defining models:
5010
+ //
5011
+ // import { useGraph } from '@construct-space/graph'
5012
+ // const graph = useGraph()
5013
+ //
5014
+ // Example action using Graph:
5015
+ // fetchItems: {
5016
+ // description: 'Fetch items from the graph',
5017
+ // params: {
5018
+ // limit: { type: 'number', description: 'Max items to return', required: false },
5019
+ // },
5020
+ // run: async (p: any) => {
5021
+ // const items = await graph.query('Item').limit(p.limit ?? 10).exec()
5022
+ // return { items }
5023
+ // },
5024
+ // },
5025
+
5026
+ export const actions = {
5027
+ // Example action:
5028
+ // hello: {
5029
+ // description: 'Say hello',
5030
+ // params: {
5031
+ // name: { type: 'string', description: 'Name to greet', required: true },
5032
+ // },
5033
+ // run: (p: any) => ({ message: \`Hello \${p.name}!\` }),
5034
+ // },
5035
+ }
5036
+ `,
5037
+ "readme.md.tmpl": `# {{.DisplayName}}
5038
+
5039
+ A Construct space.
5040
+
5041
+ ## Development
5042
+
5043
+ \`\`\`bash
5044
+ bun install
5045
+ construct space dev
5046
+ \`\`\`
5047
+
5048
+ ## Build
5049
+
5050
+ \`\`\`bash
5051
+ construct space build
5052
+ \`\`\`
5053
+
5054
+ Output goes to \`dist/\`.
5055
+ `,
5056
+ "safety.json.tmpl": `{
5057
+ "hooks": [
5058
+ {
5059
+ "id": "{{.ID}}-no-rm-rf",
5060
+ "type": "pre_tool",
5061
+ "tools": ["bash"],
5062
+ "command": "if echo \\"$TOOL_INPUT\\" | grep -qE 'rm\\\\s+-rf\\\\s+/'; then\\n echo '{\\"block\\":true,\\"message\\":\\"Blocked: rm -rf with absolute root path\\"}'\\nfi",
5063
+ "source": "space:{{.ID}}"
5064
+ }
5065
+ ]
5066
+ }
5067
+ `,
5068
+ "e2e/playwright.config.ts.tmpl": `import { defineConfig } from '@playwright/test'
5069
+
5070
+ export default defineConfig({
5071
+ testDir: './e2e',
5072
+ timeout: 30_000,
5073
+ retries: 0,
5074
+ use: {
5075
+ baseURL: 'http://localhost:5173',
5076
+ trace: 'on-first-retry',
5077
+ },
5078
+ webServer: {
5079
+ command: 'construct dev',
5080
+ port: 5173,
5081
+ reuseExistingServer: true,
5082
+ },
5083
+ })
5084
+ `,
5085
+ "e2e/space.spec.ts.tmpl": `import { test, expect } from '@playwright/test'
5086
+
5087
+ test.describe('{{.DisplayName}} space', () => {
5088
+ test('renders the default page', async ({ page }) => {
5089
+ await page.goto('/')
5090
+ await expect(page.locator('[data-testid="space-root"]')).toBeVisible()
5091
+ })
5092
+
5093
+ test('displays the space title', async ({ page }) => {
5094
+ await page.goto('/')
5095
+ await expect(page.locator('text={{.DisplayName}}')).toBeVisible()
5096
+ })
5097
+ })
5098
+ `,
5099
+ "build.yml.tmpl": `name: Build Space
5100
+
5101
+ on:
5102
+ push:
5103
+ tags:
5104
+ - 'v*'
5105
+ pull_request:
5106
+ branches: [main]
5107
+
5108
+ jobs:
5109
+ build:
5110
+ runs-on: ubuntu-latest
5111
+ steps:
5112
+ - uses: actions/checkout@v4
5113
+ - uses: oven-sh/setup-bun@v2
5114
+ with:
5115
+ bun-version: latest
5116
+ - run: bun install
5117
+ - run: bun run build
5118
+ - name: Upload artifacts
5119
+ if: startsWith(github.ref, 'refs/tags/v')
5120
+ uses: actions/upload-artifact@v4
5121
+ with:
5122
+ name: space-dist
5123
+ path: dist/
5124
+
5125
+ release:
5126
+ needs: build
5127
+ if: startsWith(github.ref, 'refs/tags/v')
5128
+ runs-on: ubuntu-latest
5129
+ permissions:
5130
+ contents: write
5131
+ steps:
5132
+ - uses: actions/download-artifact@v4
5133
+ with:
5134
+ name: space-dist
5135
+ path: dist/
5136
+ - run: tar -czf space-dist.tar.gz -C dist .
5137
+ - uses: softprops/action-gh-release@v2
5138
+ with:
5139
+ files: |
5140
+ space-dist.tar.gz
5141
+ dist/manifest.json
5142
+ generate_release_notes: true
5143
+ `,
5144
+ "widgets/2x1.vue.tmpl": `<script setup lang="ts">
5145
+ /**
5146
+ * {{.DisplayName}} Summary Widget \u2014 2\xD71 compact view
5147
+ */
5148
+ </script>
5149
+
5150
+ <template>
5151
+ <div class="h-full flex items-center gap-3 px-3">
5152
+ <div class="size-8 rounded-lg bg-[var(--app-accent)]/10 flex items-center justify-center">
5153
+ <Icon name="i-lucide-box" class="size-4 text-[var(--app-accent)]" />
5154
+ </div>
5155
+ <div class="min-w-0">
5156
+ <p class="text-sm font-medium text-[var(--app-foreground)] truncate">{{.DisplayName}}</p>
5157
+ <p class="text-xs text-[var(--app-muted)]">Ready</p>
5158
+ </div>
5159
+ </div>
5160
+ </template>
5161
+ `,
5162
+ "widgets/4x1.vue.tmpl": `<script setup lang="ts">
5163
+ /**
5164
+ * {{.DisplayName}} Summary Widget \u2014 4\xD71 wide view
5165
+ */
5166
+ </script>
5167
+
5168
+ <template>
5169
+ <div class="h-full flex items-center justify-between px-4">
5170
+ <div class="flex items-center gap-3">
5171
+ <div class="size-8 rounded-lg bg-[var(--app-accent)]/10 flex items-center justify-center">
5172
+ <Icon name="i-lucide-box" class="size-4 text-[var(--app-accent)]" />
5173
+ </div>
5174
+ <div>
5175
+ <p class="text-sm font-medium text-[var(--app-foreground)]">{{.DisplayName}}</p>
5176
+ <p class="text-xs text-[var(--app-muted)]">Your space is ready</p>
5177
+ </div>
5178
+ </div>
5179
+ <div class="text-right">
5180
+ <p class="text-lg font-bold text-[var(--app-foreground)]">0</p>
5181
+ <p class="text-[10px] text-[var(--app-muted)] uppercase">Items</p>
5182
+ </div>
5183
+ </div>
5184
+ </template>
5185
+ `,
5186
+ "tsconfig.json.tmpl": `{
5187
+ "compilerOptions": {
5188
+ "target": "ESNext",
5189
+ "module": "ESNext",
5190
+ "moduleResolution": "bundler",
5191
+ "strict": true,
5192
+ "jsx": "preserve",
5193
+ "noEmit": true,
5194
+ "esModuleInterop": true,
5195
+ "skipLibCheck": true,
5196
+ "paths": {
5197
+ "@/*": ["./src/*"],
5198
+ "@construct/sdk": ["./node_modules/@construct-space/sdk/src/index.ts"]
5199
+ }
5200
+ },
5201
+ "include": [
5202
+ "src/**/*.ts",
5203
+ "src/**/*.vue",
5204
+ "widgets/**/*.vue"
5205
+ ]
4596
5206
  }
5207
+ `
5208
+ };
4597
5209
 
4598
5210
  // src/commands/scaffold.ts
4599
5211
  var nameRegex = /^[a-z][a-z0-9-]*$/;
@@ -4601,12 +5213,16 @@ function render(template, data) {
4601
5213
  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);
4602
5214
  }
4603
5215
  function writeTemplate(templateDir, tmplName, outPath, data) {
5216
+ let content;
4604
5217
  const tmplPath = join2(templateDir, tmplName);
4605
- if (!existsSync2(tmplPath)) {
5218
+ if (existsSync2(tmplPath)) {
5219
+ content = readFileSync(tmplPath, "utf-8");
5220
+ } else if (EMBEDDED_TEMPLATES[tmplName] !== undefined) {
5221
+ content = EMBEDDED_TEMPLATES[tmplName];
5222
+ } else {
4606
5223
  console.warn(source_default.yellow(`Template not found: ${tmplName}`));
4607
5224
  return;
4608
5225
  }
4609
- const content = readFileSync(tmplPath, "utf-8");
4610
5226
  mkdirSync(dirname(outPath), { recursive: true });
4611
5227
  writeFileSync(outPath, render(content, data));
4612
5228
  }
@@ -4709,7 +5325,7 @@ async function scaffold(nameArg, options) {
4709
5325
  }
4710
5326
 
4711
5327
  // src/commands/build.ts
4712
- import { existsSync as existsSync6, readFileSync as readFileSync4, readdirSync as readdirSync3, renameSync, statSync as statSync3 } from "fs";
5328
+ import { existsSync as existsSync6, readFileSync as readFileSync4, readdirSync as readdirSync2, renameSync, statSync as statSync2 } from "fs";
4713
5329
  import { join as join6 } from "path";
4714
5330
  import { createHash } from "crypto";
4715
5331
 
@@ -7362,8 +7978,8 @@ function validate2(m) {
7362
7978
  errors2.push("author: must be an object with a name");
7363
7979
  if (!m.icon)
7364
7980
  errors2.push("icon: must be a string");
7365
- if (!["app", "project", "org", "any"].includes(m.scope))
7366
- errors2.push('scope: must be "app", "project", "org", or "any"');
7981
+ if (!["company", "project", "both"].includes(m.scope))
7982
+ errors2.push('scope: must be "company", "project", or "both"');
7367
7983
  if (!m.pages?.length)
7368
7984
  errors2.push("pages: must be a non-empty array");
7369
7985
  if (!m.navigation?.label)
@@ -7390,84 +8006,30 @@ function exists(dir) {
7390
8006
  }
7391
8007
 
7392
8008
  // src/lib/entry.ts
7393
- import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync4, readdirSync, statSync } from "fs";
7394
- import { join as join4, basename, extname, relative } from "path";
8009
+ import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
8010
+ import { join as join4, basename, extname } from "path";
7395
8011
  function capitalize(s) {
7396
8012
  if (!s)
7397
8013
  return s;
7398
8014
  return s.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
7399
8015
  }
7400
- function scanPagesDir(pagesDir) {
7401
- const results = [];
7402
- function walk(dir, routeSegments) {
7403
- if (!existsSync4(dir))
7404
- return;
7405
- const entries = readdirSync(dir).sort();
7406
- for (const entry of entries) {
7407
- const fullPath = join4(dir, entry);
7408
- const stat = statSync(fullPath);
7409
- if (stat.isDirectory()) {
7410
- const segment = entry.replace(/^\[(.+)\]$/, ":$1");
7411
- walk(fullPath, [...routeSegments, segment]);
7412
- } else if (stat.isFile() && entry.endsWith(".vue")) {
7413
- const nameWithoutExt = entry.replace(/\.vue$/, "");
7414
- const relFile = relative(join4(pagesDir, ".."), fullPath).replace(/\\/g, "/");
7415
- let routePath;
7416
- if (nameWithoutExt === "index") {
7417
- routePath = routeSegments.join("/");
7418
- } else {
7419
- const segment = nameWithoutExt.replace(/^\[(.+)\]$/, ":$1");
7420
- routePath = [...routeSegments, segment].join("/");
7421
- }
7422
- results.push({ filePath: relFile, routePath });
7423
- }
7424
- }
7425
- }
7426
- walk(pagesDir, []);
7427
- return results;
7428
- }
7429
- function varNameFromFile(filePath) {
7430
- let cleaned = filePath.replace(/^pages\//, "").replace(/\.vue$/, "");
7431
- cleaned = cleaned.replace(/\[([^\]]+)\]/g, "$1");
7432
- const segments = cleaned.split(/[\/-]/).filter(Boolean);
7433
- const name = segments.map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
7434
- return (name || "Index") + "Page";
7435
- }
7436
- function resolvePages(m, root, prefix) {
7437
- const pagesDir = join4(root, "src", "pages");
7438
- const fsPages = scanPagesDir(pagesDir);
7439
- const fsMap = new Map;
7440
- for (const fp of fsPages) {
7441
- fsMap.set(fp.routePath, fp);
7442
- }
8016
+ function resolvePages(m, prefix) {
7443
8017
  return m.pages.map((p) => {
7444
- if (p.component) {
7445
- const base = basename(p.component);
7446
- const nameWithoutExt = base.replace(extname(base), "").replace(/[\[\]]/g, "");
7447
- const dir = p.component.replace(/^pages\//, "").replace(/\/[^/]+$/, "");
7448
- let varName;
7449
- if (dir && dir !== p.component.replace(/^pages\//, "")) {
7450
- varName = capitalize(dir.split("/").map((s) => s.replace(/[\[\]]/g, "")).join("-")) + capitalize(nameWithoutExt) + "Page";
7451
- } else {
7452
- varName = capitalize(nameWithoutExt) + "Page";
7453
- }
7454
- return { varName, importPath: prefix + p.component, path: p.path };
7455
- }
7456
- const fsPage = fsMap.get(p.path);
7457
- if (fsPage) {
7458
- const varName = varNameFromFile(fsPage.filePath);
7459
- return { varName, importPath: prefix + fsPage.filePath, path: p.path };
8018
+ let component = p.component;
8019
+ if (!component) {
8020
+ component = p.path === "" ? "pages/index.vue" : `pages/${p.path}.vue`;
7460
8021
  }
7461
- const legacyComponent = p.path === "" ? "pages/index.vue" : `pages/${p.path}.vue`;
7462
- const legacyFullPath = join4(root, "src", legacyComponent);
7463
- if (existsSync4(legacyFullPath)) {
7464
- let varName = "IndexPage";
7465
- if (p.path) {
7466
- varName = capitalize(p.path.replace(/[\/:]/g, "-").replace(/-+/g, "-")) + "Page";
8022
+ let varName = "IndexPage";
8023
+ if (p.path) {
8024
+ let cleanPath = p.path.replace(/:/g, "");
8025
+ if (p.component) {
8026
+ let base = basename(p.component);
8027
+ base = base.replace(extname(base), "").replace(/[\[\]]/g, "");
8028
+ cleanPath = base;
7467
8029
  }
7468
- return { varName, importPath: prefix + legacyComponent, path: p.path };
8030
+ varName = capitalize(cleanPath) + "Page";
7469
8031
  }
7470
- throw new Error(`[entry] Could not resolve component for page "${p.path}". ` + `Checked: manifest component field, filesystem scan of src/pages/, ` + `and legacy fallback at ${legacyComponent}. ` + `Ensure a .vue file exists for this route.`);
8032
+ return { varName, importPath: prefix + component, path: p.path };
7471
8033
  });
7472
8034
  }
7473
8035
  function resolveWidgets(m, prefix) {
@@ -7486,7 +8048,7 @@ function resolveWidgets(m, prefix) {
7486
8048
  }
7487
8049
  function generate(root, m) {
7488
8050
  const pagePrefix = existsSync4(join4(root, "src", "pages")) ? "./" : "../";
7489
- const pages = resolvePages(m, root, pagePrefix);
8051
+ const pages = resolvePages(m, pagePrefix);
7490
8052
  const widgets = resolveWidgets(m, "../");
7491
8053
  const actionsPath = join4(root, "src", "actions.ts");
7492
8054
  const hasActions = existsSync4(actionsPath);
@@ -7542,7 +8104,7 @@ function writeEntry(root, m) {
7542
8104
  }
7543
8105
 
7544
8106
  // src/lib/agent.ts
7545
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, readdirSync as readdirSync2, existsSync as existsSync5 } from "fs";
8107
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, readdirSync, existsSync as existsSync5 } from "fs";
7546
8108
  import { join as join5, extname as extname2, basename as basename2 } from "path";
7547
8109
  var AGENT_KEY = "construct-agent-obfuscate-v1";
7548
8110
  function encode(content) {
@@ -7558,7 +8120,7 @@ function readMdFiles(dir) {
7558
8120
  const result = {};
7559
8121
  if (!existsSync5(dir))
7560
8122
  return result;
7561
- for (const f of readdirSync2(dir)) {
8123
+ for (const f of readdirSync(dir)) {
7562
8124
  if (extname2(f) !== ".md")
7563
8125
  continue;
7564
8126
  result[basename2(f, ".md")] = readFileSync3(join5(dir, f), "utf-8");
@@ -7569,7 +8131,7 @@ function readJsonFiles(dir) {
7569
8131
  const result = {};
7570
8132
  if (!existsSync5(dir))
7571
8133
  return result;
7572
- for (const f of readdirSync2(dir)) {
8134
+ for (const f of readdirSync(dir)) {
7573
8135
  if (extname2(f) !== ".json")
7574
8136
  continue;
7575
8137
  result[basename2(f, ".json")] = readFileSync3(join5(dir, f), "utf-8");
@@ -7659,7 +8221,7 @@ async function build(options) {
7659
8221
  }
7660
8222
  runHook(m.hooks, "postBuild", root);
7661
8223
  const agentDir = join6(root, "agent");
7662
- if (existsSync6(agentDir) && statSync3(agentDir).isDirectory()) {
8224
+ if (existsSync6(agentDir) && statSync2(agentDir).isDirectory()) {
7663
8225
  const distDir2 = join6(root, "dist");
7664
8226
  bundleAgentDir(agentDir, distDir2);
7665
8227
  bundleAgentDir(agentDir, root);
@@ -7668,7 +8230,7 @@ async function build(options) {
7668
8230
  const expectedBundle = `space-${m.id}.iife.js`;
7669
8231
  let bundlePath = join6(distDir, expectedBundle);
7670
8232
  if (!existsSync6(bundlePath)) {
7671
- const matches = readdirSync3(distDir).filter((f) => f.startsWith("space-") && f.endsWith(".iife.js"));
8233
+ const matches = readdirSync2(distDir).filter((f) => f.startsWith("space-") && f.endsWith(".iife.js"));
7672
8234
  if (matches.length === 1) {
7673
8235
  renameSync(join6(distDir, matches[0]), bundlePath);
7674
8236
  const oldCSS = join6(distDir, matches[0].replace(".iife.js", ".css"));
@@ -7698,20 +8260,20 @@ async function build(options) {
7698
8260
  }
7699
8261
 
7700
8262
  // src/commands/dev.ts
7701
- import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
7702
- import { join as join9 } from "path";
8263
+ import { existsSync as existsSync8, readFileSync as readFileSync6, cpSync, mkdirSync as mkdirSync3 } from "fs";
8264
+ import { join as join10 } from "path";
7703
8265
  import { createHash as createHash2 } from "crypto";
7704
8266
 
7705
- // node_modules/chokidar/index.js
8267
+ // node_modules/chokidar/esm/index.js
8268
+ import { stat as statcb } from "fs";
8269
+ import { stat as stat3, readdir as readdir2 } from "fs/promises";
7706
8270
  import { EventEmitter } from "events";
7707
- import { stat as statcb, Stats } from "fs";
7708
- import { readdir as readdir2, stat as stat3 } from "fs/promises";
7709
- import * as sp2 from "path";
8271
+ import * as sysPath2 from "path";
7710
8272
 
7711
- // node_modules/readdirp/index.js
7712
- import { lstat, readdir, realpath, stat } from "fs/promises";
7713
- import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "path";
8273
+ // node_modules/readdirp/esm/index.js
8274
+ import { stat, lstat, readdir, realpath } from "fs/promises";
7714
8275
  import { Readable } from "stream";
8276
+ import { resolve as presolve, relative as prelative, join as pjoin, sep as psep } from "path";
7715
8277
  var EntryTypes = {
7716
8278
  FILE_TYPE: "files",
7717
8279
  DIR_TYPE: "directories",
@@ -7767,20 +8329,6 @@ var normalizeFilter = (filter) => {
7767
8329
  };
7768
8330
 
7769
8331
  class ReaddirpStream extends Readable {
7770
- parents;
7771
- reading;
7772
- parent;
7773
- _stat;
7774
- _maxDepth;
7775
- _wantsDir;
7776
- _wantsFile;
7777
- _wantsEverything;
7778
- _root;
7779
- _isDirent;
7780
- _statsProp;
7781
- _rdOptions;
7782
- _fileFilter;
7783
- _directoryFilter;
7784
8332
  constructor(options = {}) {
7785
8333
  super({
7786
8334
  objectMode: true,
@@ -7797,7 +8345,7 @@ class ReaddirpStream extends Readable {
7797
8345
  } else {
7798
8346
  this._stat = statMethod;
7799
8347
  }
7800
- this._maxDepth = opts.depth != null && Number.isSafeInteger(opts.depth) ? opts.depth : defaultOptions.depth;
8348
+ this._maxDepth = opts.depth ?? defaultOptions.depth;
7801
8349
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
7802
8350
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
7803
8351
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
@@ -7942,11 +8490,11 @@ function readdirp(root, options = {}) {
7942
8490
  return new ReaddirpStream(options);
7943
8491
  }
7944
8492
 
7945
- // node_modules/chokidar/handler.js
7946
- import { watch as fs_watch, unwatchFile, watchFile } from "fs";
7947
- import { realpath as fsrealpath, lstat as lstat2, open, stat as stat2 } from "fs/promises";
8493
+ // node_modules/chokidar/esm/handler.js
8494
+ import { watchFile, unwatchFile, watch as fs_watch } from "fs";
8495
+ import { open, stat as stat2, lstat as lstat2, realpath as fsrealpath } from "fs/promises";
8496
+ import * as sysPath from "path";
7948
8497
  import { type as osType } from "os";
7949
- import * as sp from "path";
7950
8498
  var STR_DATA = "data";
7951
8499
  var STR_END = "end";
7952
8500
  var STR_CLOSE = "close";
@@ -8238,7 +8786,7 @@ var binaryExtensions = new Set([
8238
8786
  "zip",
8239
8787
  "zipx"
8240
8788
  ]);
8241
- var isBinaryPath = (filePath) => binaryExtensions.has(sp.extname(filePath).slice(1).toLowerCase());
8789
+ var isBinaryPath = (filePath) => binaryExtensions.has(sysPath.extname(filePath).slice(1).toLowerCase());
8242
8790
  var foreach = (val, fn) => {
8243
8791
  if (val instanceof Set) {
8244
8792
  val.forEach(fn);
@@ -8276,7 +8824,7 @@ function createFsWatchInstance(path, options, listener, errHandler, emitRaw) {
8276
8824
  listener(path);
8277
8825
  emitRaw(rawEvent, evPath, { watchedPath: path });
8278
8826
  if (evPath && path !== evPath) {
8279
- fsWatchBroadcast(sp.resolve(path, evPath), KEY_LISTENERS, sp.join(path, evPath));
8827
+ fsWatchBroadcast(sysPath.resolve(path, evPath), KEY_LISTENERS, sysPath.join(path, evPath));
8280
8828
  }
8281
8829
  };
8282
8830
  try {
@@ -8391,19 +8939,17 @@ var setFsWatchFileListener = (path, fullPath, options, handlers) => {
8391
8939
  };
8392
8940
 
8393
8941
  class NodeFsHandler {
8394
- fsw;
8395
- _boundHandleError;
8396
8942
  constructor(fsW) {
8397
8943
  this.fsw = fsW;
8398
8944
  this._boundHandleError = (error2) => fsW._handleError(error2);
8399
8945
  }
8400
8946
  _watchWithNodeFs(path, listener) {
8401
8947
  const opts = this.fsw.options;
8402
- const directory = sp.dirname(path);
8403
- const basename4 = sp.basename(path);
8948
+ const directory = sysPath.dirname(path);
8949
+ const basename4 = sysPath.basename(path);
8404
8950
  const parent = this.fsw._getWatchedDir(directory);
8405
8951
  parent.add(basename4);
8406
- const absolutePath = sp.resolve(path);
8952
+ const absolutePath = sysPath.resolve(path);
8407
8953
  const options = {
8408
8954
  persistent: opts.persistent
8409
8955
  };
@@ -8430,8 +8976,8 @@ class NodeFsHandler {
8430
8976
  if (this.fsw.closed) {
8431
8977
  return;
8432
8978
  }
8433
- const dirname3 = sp.dirname(file);
8434
- const basename4 = sp.basename(file);
8979
+ const dirname3 = sysPath.dirname(file);
8980
+ const basename4 = sysPath.basename(file);
8435
8981
  const parent = this.fsw._getWatchedDir(dirname3);
8436
8982
  let prevStats = stats;
8437
8983
  if (parent.has(basename4))
@@ -8514,9 +9060,8 @@ class NodeFsHandler {
8514
9060
  this.fsw._symlinkPaths.set(full, true);
8515
9061
  }
8516
9062
  _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
8517
- directory = sp.join(directory, "");
8518
- const throttleKey = target ? `${directory}:${target}` : directory;
8519
- throttler = this.fsw._throttle("readdir", throttleKey, 1000);
9063
+ directory = sysPath.join(directory, "");
9064
+ throttler = this.fsw._throttle("readdir", directory, 1000);
8520
9065
  if (!throttler)
8521
9066
  return;
8522
9067
  const previous = this.fsw._getWatchedDir(wh.path);
@@ -8533,7 +9078,7 @@ class NodeFsHandler {
8533
9078
  return;
8534
9079
  }
8535
9080
  const item = entry.path;
8536
- let path = sp.join(directory, item);
9081
+ let path = sysPath.join(directory, item);
8537
9082
  current.add(item);
8538
9083
  if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path, item)) {
8539
9084
  return;
@@ -8544,7 +9089,7 @@ class NodeFsHandler {
8544
9089
  }
8545
9090
  if (item === target || !target && !previous.has(item)) {
8546
9091
  this.fsw._incrReadyCount();
8547
- path = sp.join(dir, sp.relative(dir, path));
9092
+ path = sysPath.join(dir, sysPath.relative(dir, path));
8548
9093
  this._addToNodeFs(path, initialAdd, wh, depth + 1);
8549
9094
  }
8550
9095
  }).on(EV.ERROR, this._boundHandleError);
@@ -8570,12 +9115,12 @@ class NodeFsHandler {
8570
9115
  });
8571
9116
  }
8572
9117
  async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath2) {
8573
- const parentDir = this.fsw._getWatchedDir(sp.dirname(dir));
8574
- const tracked = parentDir.has(sp.basename(dir));
9118
+ const parentDir = this.fsw._getWatchedDir(sysPath.dirname(dir));
9119
+ const tracked = parentDir.has(sysPath.basename(dir));
8575
9120
  if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
8576
9121
  this.fsw._emit(EV.ADD_DIR, dir, stats);
8577
9122
  }
8578
- parentDir.add(sp.basename(dir));
9123
+ parentDir.add(sysPath.basename(dir));
8579
9124
  this.fsw._getWatchedDir(dir);
8580
9125
  let throttler;
8581
9126
  let closer;
@@ -8616,7 +9161,7 @@ class NodeFsHandler {
8616
9161
  const follow = this.fsw.options.followSymlinks;
8617
9162
  let closer;
8618
9163
  if (stats.isDirectory()) {
8619
- const absPath = sp.resolve(path);
9164
+ const absPath = sysPath.resolve(path);
8620
9165
  const targetPath = follow ? await fsrealpath(path) : path;
8621
9166
  if (this.fsw.closed)
8622
9167
  return;
@@ -8630,14 +9175,14 @@ class NodeFsHandler {
8630
9175
  const targetPath = follow ? await fsrealpath(path) : path;
8631
9176
  if (this.fsw.closed)
8632
9177
  return;
8633
- const parent = sp.dirname(wh.watchPath);
9178
+ const parent = sysPath.dirname(wh.watchPath);
8634
9179
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
8635
9180
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
8636
9181
  closer = await this._handleDir(parent, stats, initialAdd, depth, path, wh, targetPath);
8637
9182
  if (this.fsw.closed)
8638
9183
  return;
8639
9184
  if (targetPath !== undefined) {
8640
- this.fsw._symlinkPaths.set(sp.resolve(path), targetPath);
9185
+ this.fsw._symlinkPaths.set(sysPath.resolve(path), targetPath);
8641
9186
  }
8642
9187
  } else {
8643
9188
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
@@ -8655,7 +9200,7 @@ class NodeFsHandler {
8655
9200
  }
8656
9201
  }
8657
9202
 
8658
- // node_modules/chokidar/index.js
9203
+ // node_modules/chokidar/esm/index.js
8659
9204
  /*! chokidar - MIT License (c) 2012 Paul Miller (paulmillr.com) */
8660
9205
  var SLASH = "/";
8661
9206
  var SLASH_SLASH = "//";
@@ -8663,7 +9208,7 @@ var ONE_DOT = ".";
8663
9208
  var TWO_DOTS = "..";
8664
9209
  var STRING_TYPE = "string";
8665
9210
  var BACK_SLASH_RE = /\\/g;
8666
- var DOUBLE_SLASH_RE = /\/\//g;
9211
+ var DOUBLE_SLASH_RE = /\/\//;
8667
9212
  var DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
8668
9213
  var REPLACER_RE = /^\.[/\\]/;
8669
9214
  function arrify(item) {
@@ -8682,11 +9227,11 @@ function createPattern(matcher) {
8682
9227
  if (matcher.path === string)
8683
9228
  return true;
8684
9229
  if (matcher.recursive) {
8685
- const relative4 = sp2.relative(matcher.path, string);
8686
- if (!relative4) {
9230
+ const relative3 = sysPath2.relative(matcher.path, string);
9231
+ if (!relative3) {
8687
9232
  return false;
8688
9233
  }
8689
- return !relative4.startsWith("..") && !sp2.isAbsolute(relative4);
9234
+ return !relative3.startsWith("..") && !sysPath2.isAbsolute(relative3);
8690
9235
  }
8691
9236
  return false;
8692
9237
  };
@@ -8696,12 +9241,14 @@ function createPattern(matcher) {
8696
9241
  function normalizePath(path) {
8697
9242
  if (typeof path !== "string")
8698
9243
  throw new Error("string expected");
8699
- path = sp2.normalize(path);
9244
+ path = sysPath2.normalize(path);
8700
9245
  path = path.replace(/\\/g, "/");
8701
9246
  let prepend = false;
8702
9247
  if (path.startsWith("//"))
8703
9248
  prepend = true;
8704
- path = path.replace(DOUBLE_SLASH_RE, "/");
9249
+ const DOUBLE_SLASH_RE2 = /\/\//;
9250
+ while (path.match(DOUBLE_SLASH_RE2))
9251
+ path = path.replace(DOUBLE_SLASH_RE2, "/");
8705
9252
  if (prepend)
8706
9253
  path = "/" + path;
8707
9254
  return path;
@@ -8742,32 +9289,31 @@ var toUnix = (string) => {
8742
9289
  if (str.startsWith(SLASH_SLASH)) {
8743
9290
  prepend = true;
8744
9291
  }
8745
- str = str.replace(DOUBLE_SLASH_RE, SLASH);
9292
+ while (str.match(DOUBLE_SLASH_RE)) {
9293
+ str = str.replace(DOUBLE_SLASH_RE, SLASH);
9294
+ }
8746
9295
  if (prepend) {
8747
9296
  str = SLASH + str;
8748
9297
  }
8749
9298
  return str;
8750
9299
  };
8751
- var normalizePathToUnix = (path) => toUnix(sp2.normalize(toUnix(path)));
9300
+ var normalizePathToUnix = (path) => toUnix(sysPath2.normalize(toUnix(path)));
8752
9301
  var normalizeIgnored = (cwd = "") => (path) => {
8753
9302
  if (typeof path === "string") {
8754
- return normalizePathToUnix(sp2.isAbsolute(path) ? path : sp2.join(cwd, path));
9303
+ return normalizePathToUnix(sysPath2.isAbsolute(path) ? path : sysPath2.join(cwd, path));
8755
9304
  } else {
8756
9305
  return path;
8757
9306
  }
8758
9307
  };
8759
9308
  var getAbsolutePath = (path, cwd) => {
8760
- if (sp2.isAbsolute(path)) {
9309
+ if (sysPath2.isAbsolute(path)) {
8761
9310
  return path;
8762
9311
  }
8763
- return sp2.join(cwd, path);
9312
+ return sysPath2.join(cwd, path);
8764
9313
  };
8765
9314
  var EMPTY_SET = Object.freeze(new Set);
8766
9315
 
8767
9316
  class DirEntry {
8768
- path;
8769
- _removeWatcher;
8770
- items;
8771
9317
  constructor(dir, removeWatcher) {
8772
9318
  this.path = dir;
8773
9319
  this._removeWatcher = removeWatcher;
@@ -8792,7 +9338,7 @@ class DirEntry {
8792
9338
  await readdir2(dir);
8793
9339
  } catch (err) {
8794
9340
  if (this._removeWatcher) {
8795
- this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
9341
+ this._removeWatcher(sysPath2.dirname(dir), sysPath2.basename(dir));
8796
9342
  }
8797
9343
  }
8798
9344
  }
@@ -8820,19 +9366,12 @@ var STAT_METHOD_F = "stat";
8820
9366
  var STAT_METHOD_L = "lstat";
8821
9367
 
8822
9368
  class WatchHelper {
8823
- fsw;
8824
- path;
8825
- watchPath;
8826
- fullWatchPath;
8827
- dirParts;
8828
- followSymlinks;
8829
- statMethod;
8830
9369
  constructor(path, follow, fsw) {
8831
9370
  this.fsw = fsw;
8832
9371
  const watchPath = path;
8833
9372
  this.path = path = path.replace(REPLACER_RE, "");
8834
9373
  this.watchPath = watchPath;
8835
- this.fullWatchPath = sp2.resolve(watchPath);
9374
+ this.fullWatchPath = sysPath2.resolve(watchPath);
8836
9375
  this.dirParts = [];
8837
9376
  this.dirParts.forEach((parts) => {
8838
9377
  if (parts.length > 1)
@@ -8842,7 +9381,7 @@ class WatchHelper {
8842
9381
  this.statMethod = follow ? STAT_METHOD_F : STAT_METHOD_L;
8843
9382
  }
8844
9383
  entryPath(entry) {
8845
- return sp2.join(this.watchPath, sp2.relative(this.watchPath, entry.fullPath));
9384
+ return sysPath2.join(this.watchPath, sysPath2.relative(this.watchPath, entry.fullPath));
8846
9385
  }
8847
9386
  filterPath(entry) {
8848
9387
  const { stats } = entry;
@@ -8857,24 +9396,6 @@ class WatchHelper {
8857
9396
  }
8858
9397
 
8859
9398
  class FSWatcher extends EventEmitter {
8860
- closed;
8861
- options;
8862
- _closers;
8863
- _ignoredPaths;
8864
- _throttled;
8865
- _streams;
8866
- _symlinkPaths;
8867
- _watched;
8868
- _pendingWrites;
8869
- _pendingUnlinks;
8870
- _readyCount;
8871
- _emitReady;
8872
- _closePromise;
8873
- _userIgnored;
8874
- _readyEmitted;
8875
- _emitRaw;
8876
- _boundRemove;
8877
- _nodeFsHandler;
8878
9399
  constructor(_opts = {}) {
8879
9400
  super();
8880
9401
  this.closed = false;
@@ -8983,7 +9504,7 @@ class FSWatcher extends EventEmitter {
8983
9504
  return;
8984
9505
  results.forEach((item) => {
8985
9506
  if (item)
8986
- this.add(sp2.dirname(item), sp2.basename(_origAdd || item));
9507
+ this.add(sysPath2.dirname(item), sysPath2.basename(_origAdd || item));
8987
9508
  });
8988
9509
  });
8989
9510
  return this;
@@ -8994,10 +9515,10 @@ class FSWatcher extends EventEmitter {
8994
9515
  const paths = unifyPaths(paths_);
8995
9516
  const { cwd } = this.options;
8996
9517
  paths.forEach((path) => {
8997
- if (!sp2.isAbsolute(path) && !this._closers.has(path)) {
9518
+ if (!sysPath2.isAbsolute(path) && !this._closers.has(path)) {
8998
9519
  if (cwd)
8999
- path = sp2.join(cwd, path);
9000
- path = sp2.resolve(path);
9520
+ path = sysPath2.join(cwd, path);
9521
+ path = sysPath2.resolve(path);
9001
9522
  }
9002
9523
  this._closePath(path);
9003
9524
  this._addIgnoredPath(path);
@@ -9041,7 +9562,7 @@ class FSWatcher extends EventEmitter {
9041
9562
  getWatched() {
9042
9563
  const watchList = {};
9043
9564
  this._watched.forEach((entry, dir) => {
9044
- const key = this.options.cwd ? sp2.relative(this.options.cwd, dir) : dir;
9565
+ const key = this.options.cwd ? sysPath2.relative(this.options.cwd, dir) : dir;
9045
9566
  const index = key || ONE_DOT;
9046
9567
  watchList[index] = entry.getChildren().sort();
9047
9568
  });
@@ -9057,9 +9578,9 @@ class FSWatcher extends EventEmitter {
9057
9578
  return;
9058
9579
  const opts = this.options;
9059
9580
  if (isWindows)
9060
- path = sp2.normalize(path);
9581
+ path = sysPath2.normalize(path);
9061
9582
  if (opts.cwd)
9062
- path = sp2.relative(opts.cwd, path);
9583
+ path = sysPath2.relative(opts.cwd, path);
9063
9584
  const args = [path];
9064
9585
  if (stats != null)
9065
9586
  args.push(stats);
@@ -9110,7 +9631,7 @@ class FSWatcher extends EventEmitter {
9110
9631
  return this;
9111
9632
  }
9112
9633
  if (opts.alwaysStat && stats === undefined && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
9113
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path) : path;
9634
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path) : path;
9114
9635
  let stats2;
9115
9636
  try {
9116
9637
  stats2 = await stat3(fullPath);
@@ -9166,8 +9687,8 @@ class FSWatcher extends EventEmitter {
9166
9687
  const pollInterval = awf.pollInterval;
9167
9688
  let timeoutHandler;
9168
9689
  let fullPath = path;
9169
- if (this.options.cwd && !sp2.isAbsolute(path)) {
9170
- fullPath = sp2.join(this.options.cwd, path);
9690
+ if (this.options.cwd && !sysPath2.isAbsolute(path)) {
9691
+ fullPath = sysPath2.join(this.options.cwd, path);
9171
9692
  }
9172
9693
  const now = new Date;
9173
9694
  const writes = this._pendingWrites;
@@ -9224,7 +9745,7 @@ class FSWatcher extends EventEmitter {
9224
9745
  return new WatchHelper(path, this.options.followSymlinks, this);
9225
9746
  }
9226
9747
  _getWatchedDir(directory) {
9227
- const dir = sp2.resolve(directory);
9748
+ const dir = sysPath2.resolve(directory);
9228
9749
  if (!this._watched.has(dir))
9229
9750
  this._watched.set(dir, new DirEntry(dir, this._boundRemove));
9230
9751
  return this._watched.get(dir);
@@ -9235,8 +9756,8 @@ class FSWatcher extends EventEmitter {
9235
9756
  return Boolean(Number(stats.mode) & 256);
9236
9757
  }
9237
9758
  _remove(directory, item, isDirectory) {
9238
- const path = sp2.join(directory, item);
9239
- const fullPath = sp2.resolve(path);
9759
+ const path = sysPath2.join(directory, item);
9760
+ const fullPath = sysPath2.resolve(path);
9240
9761
  isDirectory = isDirectory != null ? isDirectory : this._watched.has(path) || this._watched.has(fullPath);
9241
9762
  if (!this._throttle("remove", path, 100))
9242
9763
  return;
@@ -9254,7 +9775,7 @@ class FSWatcher extends EventEmitter {
9254
9775
  }
9255
9776
  let relPath = path;
9256
9777
  if (this.options.cwd)
9257
- relPath = sp2.relative(this.options.cwd, path);
9778
+ relPath = sysPath2.relative(this.options.cwd, path);
9258
9779
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
9259
9780
  const event = this._pendingWrites.get(relPath).cancelWait();
9260
9781
  if (event === EVENTS.ADD)
@@ -9269,8 +9790,8 @@ class FSWatcher extends EventEmitter {
9269
9790
  }
9270
9791
  _closePath(path) {
9271
9792
  this._closeFile(path);
9272
- const dir = sp2.dirname(path);
9273
- this._getWatchedDir(dir).remove(sp2.basename(path));
9793
+ const dir = sysPath2.dirname(path);
9794
+ this._getWatchedDir(dir).remove(sysPath2.basename(path));
9274
9795
  }
9275
9796
  _closeFile(path) {
9276
9797
  const closers = this._closers.get(path);
@@ -9313,11 +9834,55 @@ function watch(paths, options = {}) {
9313
9834
  return watcher;
9314
9835
  }
9315
9836
 
9837
+ // src/lib/appdir.ts
9838
+ import { join as join9 } from "path";
9839
+ import { homedir } from "os";
9840
+ import { platform as platform2 } from "process";
9841
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
9842
+ function dataDir() {
9843
+ if (process.env.CONSTRUCT_DATA_DIR)
9844
+ return process.env.CONSTRUCT_DATA_DIR;
9845
+ const home = homedir();
9846
+ switch (platform2) {
9847
+ case "darwin":
9848
+ return join9(home, "Library", "Application Support", "Construct");
9849
+ case "win32": {
9850
+ const appData = process.env.APPDATA || join9(home, "AppData", "Roaming");
9851
+ return join9(appData, "Construct");
9852
+ }
9853
+ default: {
9854
+ const xdg = process.env.XDG_DATA_HOME || join9(home, ".local", "share");
9855
+ return join9(xdg, "construct");
9856
+ }
9857
+ }
9858
+ }
9859
+ function activeProfileId() {
9860
+ try {
9861
+ const profilesPath = join9(dataDir(), "profiles.json");
9862
+ if (!existsSync7(profilesPath))
9863
+ return null;
9864
+ const data = JSON.parse(readFileSync5(profilesPath, "utf-8"));
9865
+ return data?.active_profile || null;
9866
+ } catch {
9867
+ return null;
9868
+ }
9869
+ }
9870
+ function spacesDir() {
9871
+ const profileId = activeProfileId();
9872
+ if (profileId) {
9873
+ return join9(dataDir(), "profiles", profileId, "spaces");
9874
+ }
9875
+ return join9(dataDir(), "spaces");
9876
+ }
9877
+ function spaceDir(spaceId) {
9878
+ return join9(spacesDir(), spaceId);
9879
+ }
9880
+
9316
9881
  // src/commands/dev.ts
9317
9882
  function getEntryWatchPaths(root) {
9318
9883
  return [
9319
- join9(root, MANIFEST_FILE),
9320
- join9(root, "src", "actions.ts")
9884
+ join10(root, MANIFEST_FILE),
9885
+ join10(root, "src", "actions.ts")
9321
9886
  ];
9322
9887
  }
9323
9888
  async function dev() {
@@ -9356,14 +9921,14 @@ async function dev() {
9356
9921
  }
9357
9922
  console.log(source_default.blue("Actions changed \u2014 entry regenerated"));
9358
9923
  });
9359
- const distDir = join9(root, "dist");
9360
- const bundleFile = join9(distDir, `space-${m.id}.iife.js`);
9924
+ const distDir = join10(root, "dist");
9925
+ const bundleFile = join10(distDir, `space-${m.id}.iife.js`);
9361
9926
  let lastChecksum = "";
9362
9927
  const distWatcher = watch(bundleFile, { ignoreInitial: false });
9363
9928
  distWatcher.on("all", () => {
9364
- if (!existsSync7(bundleFile))
9929
+ if (!existsSync8(bundleFile))
9365
9930
  return;
9366
- const bundleData = readFileSync5(bundleFile);
9931
+ const bundleData = readFileSync6(bundleFile);
9367
9932
  const checksum = createHash2("sha256").update(bundleData).digest("hex");
9368
9933
  if (checksum === lastChecksum)
9369
9934
  return;
@@ -9375,7 +9940,15 @@ async function dev() {
9375
9940
  hostApiVersion: "0.2.0",
9376
9941
  builtAt: new Date().toISOString()
9377
9942
  });
9378
- console.log(source_default.green(`Built \u2192 dist/ (${(bundleData.length / 1024).toFixed(1)} KB)`));
9943
+ try {
9944
+ const installDir = spaceDir(m.id);
9945
+ mkdirSync3(installDir, { recursive: true });
9946
+ cpSync(distDir, installDir, { recursive: true });
9947
+ console.log(source_default.green(`Built + installed \u2192 ${installDir} (${(bundleData.length / 1024).toFixed(1)} KB)`));
9948
+ } catch (err) {
9949
+ console.log(source_default.green(`Built \u2192 dist/ (${(bundleData.length / 1024).toFixed(1)} KB)`));
9950
+ console.log(source_default.yellow(` Install failed: ${err.message}`));
9951
+ }
9379
9952
  });
9380
9953
  console.log(source_default.green("Watching for changes... (Ctrl+C to stop)"));
9381
9954
  console.log(source_default.dim("Use the Preview button in Construct to open the Space Runner"));
@@ -9383,38 +9956,8 @@ async function dev() {
9383
9956
  }
9384
9957
 
9385
9958
  // src/commands/run.ts
9386
- import { existsSync as existsSync8, cpSync, mkdirSync as mkdirSync3 } from "fs";
9959
+ import { existsSync as existsSync9, cpSync as cpSync2, mkdirSync as mkdirSync4 } from "fs";
9387
9960
  import { join as join11 } from "path";
9388
-
9389
- // src/lib/appdir.ts
9390
- import { join as join10 } from "path";
9391
- import { homedir } from "os";
9392
- import { platform as platform2 } from "process";
9393
- function dataDir() {
9394
- if (process.env.CONSTRUCT_DATA_DIR)
9395
- return process.env.CONSTRUCT_DATA_DIR;
9396
- const home = homedir();
9397
- switch (platform2) {
9398
- case "darwin":
9399
- return join10(home, "Library", "Application Support", "Construct");
9400
- case "win32": {
9401
- const appData = process.env.APPDATA || join10(home, "AppData", "Roaming");
9402
- return join10(appData, "Construct");
9403
- }
9404
- default: {
9405
- const xdg = process.env.XDG_DATA_HOME || join10(home, ".local", "share");
9406
- return join10(xdg, "construct");
9407
- }
9408
- }
9409
- }
9410
- function spacesDir() {
9411
- return join10(dataDir(), "spaces");
9412
- }
9413
- function spaceDir(spaceId) {
9414
- return join10(spacesDir(), spaceId);
9415
- }
9416
-
9417
- // src/commands/run.ts
9418
9961
  function install() {
9419
9962
  const root = process.cwd();
9420
9963
  if (!exists(root)) {
@@ -9422,46 +9965,83 @@ function install() {
9422
9965
  process.exit(1);
9423
9966
  }
9424
9967
  const distDir = join11(root, "dist");
9425
- if (!existsSync8(distDir)) {
9968
+ if (!existsSync9(distDir)) {
9426
9969
  console.error(source_default.red("No dist/ directory found. Run 'construct build' first."));
9427
9970
  process.exit(1);
9428
9971
  }
9429
9972
  const m = read(root);
9430
9973
  const agentDir = join11(root, "agent");
9431
- if (existsSync8(agentDir)) {
9974
+ if (existsSync9(agentDir)) {
9432
9975
  bundleAgentDir(agentDir, distDir);
9433
9976
  }
9434
9977
  const installDir = spaceDir(m.id);
9435
- mkdirSync3(installDir, { recursive: true });
9436
- cpSync(distDir, installDir, { recursive: true });
9978
+ mkdirSync4(installDir, { recursive: true });
9979
+ cpSync2(distDir, installDir, { recursive: true });
9437
9980
  console.log(source_default.green(`Installed ${m.name} \u2192 ${installDir}`));
9438
9981
  console.log(source_default.dim(" Restart Construct to load the updated space."));
9439
9982
  }
9440
9983
 
9441
9984
  // src/commands/publish.ts
9442
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, statSync as statSync5, unlinkSync as unlinkSync2 } from "fs";
9985
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, statSync as statSync4, unlinkSync as unlinkSync2 } from "fs";
9443
9986
  import { join as join14, basename as basename6 } from "path";
9444
9987
 
9445
9988
  // src/lib/auth.ts
9446
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync, existsSync as existsSync9 } from "fs";
9989
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync, existsSync as existsSync10 } from "fs";
9447
9990
  import { join as join12, dirname as dirname4 } from "path";
9448
9991
  var CREDENTIALS_FILE = "credentials.json";
9992
+ var APP_PROFILES_FILE = "profiles.json";
9449
9993
  var DEFAULT_PORTAL = "https://developer.construct.space";
9450
9994
  function credentialsPath() {
9451
9995
  return join12(dataDir(), CREDENTIALS_FILE);
9452
9996
  }
9997
+ function appProfilesPath() {
9998
+ return join12(dataDir(), APP_PROFILES_FILE);
9999
+ }
10000
+ function appProfileAuthPath(profileId) {
10001
+ return join12(dataDir(), "profiles", profileId, "auth.json");
10002
+ }
10003
+ function loadFromApp() {
10004
+ try {
10005
+ const profilesPath = appProfilesPath();
10006
+ if (!existsSync10(profilesPath))
10007
+ return null;
10008
+ const profiles = JSON.parse(readFileSync7(profilesPath, "utf-8"));
10009
+ if (!profiles?.active_profile)
10010
+ return null;
10011
+ const authPath = appProfileAuthPath(profiles.active_profile);
10012
+ if (!existsSync10(authPath))
10013
+ return null;
10014
+ const auth = JSON.parse(readFileSync7(authPath, "utf-8"));
10015
+ if (!auth?.authenticated || !auth?.token)
10016
+ return null;
10017
+ return {
10018
+ token: auth.token,
10019
+ portal: DEFAULT_PORTAL,
10020
+ user: {
10021
+ id: auth.user.id,
10022
+ name: auth.user.name || [auth.user.first_name, auth.user.last_name].filter(Boolean).join(" ") || auth.user.email,
10023
+ email: auth.user.email
10024
+ }
10025
+ };
10026
+ } catch {
10027
+ return null;
10028
+ }
10029
+ }
9453
10030
  function store(creds) {
9454
10031
  const path = credentialsPath();
9455
- mkdirSync4(dirname4(path), { recursive: true });
10032
+ mkdirSync5(dirname4(path), { recursive: true });
9456
10033
  writeFileSync5(path, JSON.stringify(creds, null, 2) + `
9457
10034
  `, { mode: 384 });
9458
10035
  }
9459
10036
  function load2() {
10037
+ const fromApp = loadFromApp();
10038
+ if (fromApp)
10039
+ return fromApp;
9460
10040
  const path = credentialsPath();
9461
- if (!existsSync9(path)) {
9462
- throw new Error("not logged in \u2014 run 'construct login' first");
10041
+ if (!existsSync10(path)) {
10042
+ throw new Error("not logged in \u2014 run 'construct login' first (or sign in to the Construct app)");
9463
10043
  }
9464
- const data = JSON.parse(readFileSync6(path, "utf-8"));
10044
+ const data = JSON.parse(readFileSync7(path, "utf-8"));
9465
10045
  if (!data.token) {
9466
10046
  throw new Error("not logged in \u2014 run 'construct login' first");
9467
10047
  }
@@ -9477,12 +10057,12 @@ function isAuthenticated() {
9477
10057
  }
9478
10058
  function clear() {
9479
10059
  const path = credentialsPath();
9480
- if (existsSync9(path))
10060
+ if (existsSync10(path))
9481
10061
  unlinkSync(path);
9482
10062
  }
9483
10063
 
9484
10064
  // src/lib/pack.ts
9485
- import { readdirSync as readdirSync4, statSync as statSync4, existsSync as existsSync10 } from "fs";
10065
+ import { readdirSync as readdirSync3, statSync as statSync3, existsSync as existsSync11 } from "fs";
9486
10066
  import { join as join13 } from "path";
9487
10067
  import { tmpdir } from "os";
9488
10068
  import { execSync as execSync3 } from "child_process";
@@ -9521,11 +10101,11 @@ async function packSource(root) {
9521
10101
  const tarballPath = join13(tmpdir(), `space-source-${Date.now()}.tar.gz`);
9522
10102
  const entries = [];
9523
10103
  for (const name of allowedRootFiles) {
9524
- if (existsSync10(join13(root, name)))
10104
+ if (existsSync11(join13(root, name)))
9525
10105
  entries.push(name);
9526
10106
  }
9527
- for (const entry of readdirSync4(root)) {
9528
- if (statSync4(join13(root, entry)).isDirectory())
10107
+ for (const entry of readdirSync3(root)) {
10108
+ if (statSync3(join13(root, entry)).isDirectory())
9529
10109
  continue;
9530
10110
  if (allowedRootFiles.includes(entry))
9531
10111
  continue;
@@ -9535,17 +10115,17 @@ async function packSource(root) {
9535
10115
  entries.push(entry);
9536
10116
  }
9537
10117
  for (const dir of allowedDirs) {
9538
- if (existsSync10(join13(root, dir)))
10118
+ if (existsSync11(join13(root, dir)))
9539
10119
  entries.push(dir);
9540
10120
  }
9541
- const validEntries = entries.filter((e) => existsSync10(join13(root, e)));
10121
+ const validEntries = entries.filter((e) => existsSync11(join13(root, e)));
9542
10122
  if (validEntries.length === 0) {
9543
10123
  throw new Error("No files to pack");
9544
10124
  }
9545
10125
  const excludes = "--exclude=node_modules --exclude=dist --exclude=.git --exclude=*.env --exclude=*.log --exclude=*.lock --exclude=*.lockb";
9546
10126
  const cmd = `tar czf "${tarballPath}" ${excludes} ${validEntries.join(" ")}`;
9547
10127
  execSync3(cmd, { cwd: root });
9548
- const size = statSync4(tarballPath).size;
10128
+ const size = statSync3(tarballPath).size;
9549
10129
  if (size > MAX_SIZE) {
9550
10130
  throw new Error(`Source exceeds maximum size of ${MAX_SIZE / 1024 / 1024}MB`);
9551
10131
  }
@@ -9556,7 +10136,7 @@ async function packSource(root) {
9556
10136
  async function uploadSource(portalURL, token, tarballPath, m) {
9557
10137
  const formData = new FormData;
9558
10138
  formData.append("manifest", JSON.stringify(m));
9559
- const fileData = readFileSync7(tarballPath);
10139
+ const fileData = readFileSync8(tarballPath);
9560
10140
  const blob = new Blob([fileData]);
9561
10141
  formData.append("source", blob, basename6(tarballPath));
9562
10142
  const resp = await fetch(`${portalURL}/api/publish`, {
@@ -9568,16 +10148,6 @@ async function uploadSource(portalURL, token, tarballPath, m) {
9568
10148
  if (resp.status === 401) {
9569
10149
  throw new Error("authentication failed \u2014 run 'construct login' to re-authenticate");
9570
10150
  }
9571
- if (resp.status === 403) {
9572
- let msg = result.error || "You are not the owner of this space";
9573
- if (result.owner_user_id) {
9574
- msg += `
9575
- Current owner: ${result.owner_user_id}`;
9576
- }
9577
- msg += `
9578
- Fork to a new space_id to publish your own version.`;
9579
- throw new Error(msg);
9580
- }
9581
10151
  if (resp.status >= 400) {
9582
10152
  const msg = result.error || result.errors?.join("; ") || `server returned ${resp.status}`;
9583
10153
  throw new Error(msg);
@@ -9590,7 +10160,7 @@ function setVersionInFiles(root, oldVer, newVer) {
9590
10160
  for (const file of ["package.json", "space.manifest.json"]) {
9591
10161
  const path = join14(root, file);
9592
10162
  try {
9593
- const data = readFileSync7(path, "utf-8");
10163
+ const data = readFileSync8(path, "utf-8");
9594
10164
  writeFileSync6(path, data.replace(oldStr, newStr));
9595
10165
  } catch {}
9596
10166
  }
@@ -9612,6 +10182,24 @@ async function publish(options) {
9612
10182
  console.log(source_default.dim(" Run 'construct login' to authenticate."));
9613
10183
  process.exit(1);
9614
10184
  }
10185
+ const publishers = creds.publishers || [];
10186
+ if (publishers.length === 0) {
10187
+ console.log(source_default.yellow(" No publisher linked to this session. The upload will likely be rejected."));
10188
+ console.log(source_default.dim(" Run 'construct login' after enrolling at developer.construct.space."));
10189
+ } else {
10190
+ const primary = publishers[0];
10191
+ const kindLabel = primary.kind === "org" ? source_default.cyan("org") : primary.kind === "user" ? source_default.blue("personal") : source_default.dim("legacy");
10192
+ console.log(source_default.dim(` Publishing as ${primary.name} (${kindLabel})`));
10193
+ if (publishers.length > 1 && !yes) {
10194
+ const proceed = await dist_default4({
10195
+ message: `You have ${publishers.length} publisher identities. Publish under ${primary.name}?`
10196
+ });
10197
+ if (!proceed) {
10198
+ console.log("Cancelled.");
10199
+ return;
10200
+ }
10201
+ }
10202
+ }
9615
10203
  const status = gitSafe(root, "status", "--porcelain");
9616
10204
  if (status) {
9617
10205
  console.log(source_default.yellow("You have uncommitted changes."));
@@ -9695,7 +10283,7 @@ async function publish(options) {
9695
10283
  let tarballPath;
9696
10284
  try {
9697
10285
  tarballPath = await packSource(root);
9698
- const size = statSync5(tarballPath).size;
10286
+ const size = statSync4(tarballPath).size;
9699
10287
  spinner.succeed(`Source packed (${formatBytes(size)})`);
9700
10288
  } catch (err) {
9701
10289
  spinner.fail("Pack failed");
@@ -9734,7 +10322,7 @@ async function publish(options) {
9734
10322
  }
9735
10323
 
9736
10324
  // src/commands/validate.ts
9737
- import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
10325
+ import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
9738
10326
  import { join as join15 } from "path";
9739
10327
  function validate3() {
9740
10328
  const root = process.cwd();
@@ -9754,21 +10342,21 @@ function validate3() {
9754
10342
  for (const page of m.pages) {
9755
10343
  const component = page.component || (page.path === "" ? "pages/index.vue" : `pages/${page.path}.vue`);
9756
10344
  const fullPath = join15(root, "src", component);
9757
- if (!existsSync11(fullPath)) {
10345
+ if (!existsSync12(fullPath)) {
9758
10346
  console.log(source_default.yellow(` \u26A0 Page component not found: src/${component}`));
9759
10347
  warnings++;
9760
10348
  }
9761
10349
  }
9762
10350
  if (m.agent) {
9763
10351
  const agentPath = join15(root, m.agent);
9764
- if (!existsSync11(agentPath)) {
10352
+ if (!existsSync12(agentPath)) {
9765
10353
  console.log(source_default.yellow(` \u26A0 Agent config not found: ${m.agent}`));
9766
10354
  warnings++;
9767
10355
  }
9768
10356
  }
9769
10357
  const pkgPath = join15(root, "package.json");
9770
- if (existsSync11(pkgPath)) {
9771
- const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
10358
+ if (existsSync12(pkgPath)) {
10359
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
9772
10360
  if (pkg.version && pkg.version !== m.version) {
9773
10361
  console.log(source_default.yellow(` \u26A0 Version mismatch: manifest=${m.version} package.json=${pkg.version}`));
9774
10362
  warnings++;
@@ -9783,7 +10371,7 @@ function validate3() {
9783
10371
 
9784
10372
  // src/commands/check.ts
9785
10373
  import { execSync as execSync4 } from "child_process";
9786
- import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
10374
+ import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
9787
10375
  import { join as join16 } from "path";
9788
10376
  function check() {
9789
10377
  const root = process.cwd();
@@ -9803,18 +10391,18 @@ function check() {
9803
10391
  let warnings = 0;
9804
10392
  for (const page of m.pages) {
9805
10393
  const component = page.component || (page.path === "" ? "pages/index.vue" : `pages/${page.path}.vue`);
9806
- if (!existsSync12(join16(root, "src", component))) {
10394
+ if (!existsSync13(join16(root, "src", component))) {
9807
10395
  console.log(source_default.yellow(` \u26A0 Page not found: src/${component}`));
9808
10396
  warnings++;
9809
10397
  }
9810
10398
  }
9811
- if (m.agent && !existsSync12(join16(root, m.agent))) {
10399
+ if (m.agent && !existsSync13(join16(root, m.agent))) {
9812
10400
  console.log(source_default.yellow(` \u26A0 Agent config not found: ${m.agent}`));
9813
10401
  warnings++;
9814
10402
  }
9815
10403
  const pkgPath = join16(root, "package.json");
9816
- if (existsSync12(pkgPath)) {
9817
- const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
10404
+ if (existsSync13(pkgPath)) {
10405
+ const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
9818
10406
  if (pkg.version && pkg.version !== m.version) {
9819
10407
  console.log(source_default.yellow(` \u26A0 Version mismatch: manifest=${m.version} package.json=${pkg.version}`));
9820
10408
  warnings++;
@@ -9845,7 +10433,7 @@ function check() {
9845
10433
  }
9846
10434
 
9847
10435
  // src/commands/clean.ts
9848
- import { rmSync, existsSync as existsSync13 } from "fs";
10436
+ import { rmSync, existsSync as existsSync14 } from "fs";
9849
10437
  import { join as join17 } from "path";
9850
10438
  function clean(options) {
9851
10439
  const root = process.cwd();
@@ -9856,7 +10444,7 @@ function clean(options) {
9856
10444
  const lockfiles = ["bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"];
9857
10445
  for (const dir of dirs) {
9858
10446
  const path = join17(root, dir);
9859
- if (existsSync13(path)) {
10447
+ if (existsSync14(path)) {
9860
10448
  rmSync(path, { recursive: true });
9861
10449
  console.log(source_default.dim(` Removed ${dir}/`));
9862
10450
  }
@@ -9864,7 +10452,7 @@ function clean(options) {
9864
10452
  if (options?.all) {
9865
10453
  for (const file of lockfiles) {
9866
10454
  const path = join17(root, file);
9867
- if (existsSync13(path)) {
10455
+ if (existsSync14(path)) {
9868
10456
  rmSync(path);
9869
10457
  console.log(source_default.dim(` Removed ${file}`));
9870
10458
  }
@@ -9877,6 +10465,12 @@ function clean(options) {
9877
10465
  import { createServer } from "http";
9878
10466
  async function login(options) {
9879
10467
  const portalURL = options?.portal || DEFAULT_PORTAL;
10468
+ const fromApp = loadFromApp();
10469
+ if (fromApp) {
10470
+ console.log(source_default.green(`Using Construct app profile: ${fromApp.user?.name || fromApp.user?.email}`));
10471
+ console.log(source_default.dim(" To use a different identity, sign out of the app or run `construct logout` after login."));
10472
+ return;
10473
+ }
9880
10474
  if (isAuthenticated()) {
9881
10475
  const creds = load2();
9882
10476
  const name = creds.user?.name || "unknown";
@@ -9942,18 +10536,101 @@ async function login(options) {
9942
10536
  const resp = await fetch(`${portalURL}/api/auth/cli-verify`, {
9943
10537
  headers: { Authorization: `Bearer ${token}` }
9944
10538
  });
9945
- const { user } = await resp.json();
9946
- store({ token, portal: portalURL, user });
10539
+ const { user, publishers } = await resp.json();
10540
+ store({ token, portal: portalURL, user, publishers });
9947
10541
  console.log();
9948
10542
  console.log(source_default.green(`Logged in as ${user?.name || "there"}`));
10543
+ const list = publishers || [];
10544
+ if (list.length === 0) {
10545
+ console.log(source_default.yellow(" No publisher yet. Run developer enrollment to publish spaces."));
10546
+ } else {
10547
+ for (const p of list) {
10548
+ const label = p.kind === "org" ? source_default.cyan("org") : p.kind === "user" ? source_default.blue("personal") : source_default.dim("legacy");
10549
+ console.log(source_default.dim(` Publisher: ${p.name} (${label})`));
10550
+ }
10551
+ }
9949
10552
  } catch (err) {
9950
10553
  console.error(source_default.red(`Login failed: ${err.message}`));
9951
10554
  process.exit(1);
9952
10555
  }
9953
10556
  }
9954
10557
  function logout() {
10558
+ const wasCli = isAuthenticated();
9955
10559
  clear();
9956
- console.log(source_default.green("Logged out."));
10560
+ if (wasCli) {
10561
+ console.log(source_default.green("Logged out of CLI credentials."));
10562
+ } else {
10563
+ console.log(source_default.dim("No CLI credentials to clear."));
10564
+ }
10565
+ const appStill = loadFromApp();
10566
+ if (appStill) {
10567
+ console.log();
10568
+ console.log(source_default.yellow("Note: the Construct app is still signed in as ") + source_default.white(appStill.user?.name || appStill.user?.email || ""));
10569
+ console.log(source_default.dim(" The CLI will continue to use the app profile. Sign out of the app to fully disconnect."));
10570
+ }
10571
+ }
10572
+
10573
+ // src/commands/whoami.ts
10574
+ async function whoami() {
10575
+ const fromApp = loadFromApp();
10576
+ let creds = null;
10577
+ let source = "none";
10578
+ if (fromApp) {
10579
+ creds = fromApp;
10580
+ source = "app";
10581
+ } else {
10582
+ try {
10583
+ creds = load2();
10584
+ source = "cli";
10585
+ } catch {
10586
+ source = "none";
10587
+ }
10588
+ }
10589
+ if (source === "none" || !creds) {
10590
+ console.log(source_default.yellow("Not signed in."));
10591
+ console.log(source_default.dim(" Run ") + source_default.white("construct login") + source_default.dim(" or sign in to the Construct app."));
10592
+ return;
10593
+ }
10594
+ const user = creds.user;
10595
+ const sourceLabel = source === "app" ? source_default.cyan("Construct app profile") : source_default.blue("CLI login");
10596
+ console.log();
10597
+ console.log(source_default.bold(user?.name || "Signed in"));
10598
+ console.log(source_default.dim(" " + (user?.email || "")));
10599
+ console.log(source_default.dim(" id: ") + source_default.dim(user?.id || "\u2014"));
10600
+ console.log(source_default.dim(" source: ") + sourceLabel);
10601
+ console.log(source_default.dim(" portal: ") + (creds.portal || DEFAULT_PORTAL));
10602
+ try {
10603
+ const resp = await fetch(`${creds.portal || DEFAULT_PORTAL}/api/auth/cli-verify`, {
10604
+ headers: { Authorization: `Bearer ${creds.token}` }
10605
+ });
10606
+ if (!resp.ok) {
10607
+ console.log(source_default.dim(" publishers: ") + source_default.red(`error (${resp.status})`));
10608
+ return;
10609
+ }
10610
+ const body = await resp.json();
10611
+ const list = body.publishers || [];
10612
+ if (list.length === 0) {
10613
+ console.log(source_default.dim(" publishers: ") + source_default.yellow("none yet \u2014 enroll at developer.construct.space"));
10614
+ return;
10615
+ }
10616
+ console.log();
10617
+ console.log(source_default.bold("Publishers"));
10618
+ for (const p of list) {
10619
+ const kindLabel = p.kind === "org" ? source_default.cyan("org") : p.kind === "user" ? source_default.blue("personal") : source_default.dim("legacy");
10620
+ const verified = p.verified ? source_default.green(" \u2713") : "";
10621
+ console.log(` ${source_default.white(p.name)} (${kindLabel})${verified}`);
10622
+ if (p.orgId)
10623
+ console.log(source_default.dim(` org: ${p.orgId}`));
10624
+ }
10625
+ } catch (err) {
10626
+ console.log(source_default.dim(" publishers: ") + source_default.red("could not reach portal"));
10627
+ }
10628
+ console.log();
10629
+ if (source === "app") {
10630
+ console.log(source_default.dim("To switch identities, change the active profile in the Construct app."));
10631
+ } else {
10632
+ console.log(source_default.dim("To switch identities, run 'construct logout' then 'construct login'."));
10633
+ }
9957
10634
  }
9958
10635
 
9959
10636
  // src/commands/update.ts
@@ -9985,7 +10662,7 @@ function update() {
9985
10662
  }
9986
10663
 
9987
10664
  // src/commands/graph/init.ts
9988
- import { existsSync as existsSync14, readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "fs";
10665
+ import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6 } from "fs";
9989
10666
  import { join as join18 } from "path";
9990
10667
  import { execSync as execSync6 } from "child_process";
9991
10668
  function graphInit() {
@@ -9997,9 +10674,9 @@ function graphInit() {
9997
10674
  }
9998
10675
  const m = read(root);
9999
10676
  const modelsDir = join18(root, "src", "models");
10000
- mkdirSync5(modelsDir, { recursive: true });
10677
+ mkdirSync6(modelsDir, { recursive: true });
10001
10678
  const indexPath = join18(modelsDir, "index.ts");
10002
- if (!existsSync14(indexPath)) {
10679
+ if (!existsSync15(indexPath)) {
10003
10680
  writeFileSync7(indexPath, `// Data models for ${m.name}
10004
10681
  // Generated by construct graph init
10005
10682
 
@@ -10008,7 +10685,7 @@ function graphInit() {
10008
10685
  `);
10009
10686
  }
10010
10687
  const pkgPath = join18(root, "package.json");
10011
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
10688
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
10012
10689
  if (!pkg.dependencies)
10013
10690
  pkg.dependencies = {};
10014
10691
  if (!pkg.dependencies["@construct-space/graph"]) {
@@ -10038,7 +10715,7 @@ function graphInit() {
10038
10715
  }
10039
10716
 
10040
10717
  // src/commands/graph/generate.ts
10041
- import { existsSync as existsSync15, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync6 } from "fs";
10718
+ import { existsSync as existsSync16, readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7 } from "fs";
10042
10719
  import { join as join19 } from "path";
10043
10720
  var FIELD_TYPES = {
10044
10721
  string: "field.string()",
@@ -10192,9 +10869,9 @@ function generate2(modelName, fieldSpecs, options) {
10192
10869
  const content = lines.join(`
10193
10870
  `);
10194
10871
  const modelsDir = join19(root, "src", "models");
10195
- mkdirSync6(modelsDir, { recursive: true });
10872
+ mkdirSync7(modelsDir, { recursive: true });
10196
10873
  const filePath = join19(modelsDir, `${name}.ts`);
10197
- if (existsSync15(filePath)) {
10874
+ if (existsSync16(filePath)) {
10198
10875
  console.log(source_default.yellow(` Model file already exists: src/models/${name}.ts`));
10199
10876
  console.log(source_default.dim(" Overwriting..."));
10200
10877
  }
@@ -10213,8 +10890,8 @@ function generate2(modelName, fieldSpecs, options) {
10213
10890
  function updateBarrel(modelsDir, modelName) {
10214
10891
  const indexPath = join19(modelsDir, "index.ts");
10215
10892
  const exportLine = `export { ${modelName} } from './${modelName}'`;
10216
- if (existsSync15(indexPath)) {
10217
- const content = readFileSync11(indexPath, "utf-8");
10893
+ if (existsSync16(indexPath)) {
10894
+ const content = readFileSync12(indexPath, "utf-8");
10218
10895
  if (content.includes(exportLine))
10219
10896
  return;
10220
10897
  writeFileSync8(indexPath, content.trimEnd() + `
@@ -10228,7 +10905,7 @@ function updateBarrel(modelsDir, modelName) {
10228
10905
  }
10229
10906
 
10230
10907
  // src/commands/graph/push.ts
10231
- import { existsSync as existsSync16, readdirSync as readdirSync5, readFileSync as readFileSync12 } from "fs";
10908
+ import { existsSync as existsSync17, readdirSync as readdirSync4, readFileSync as readFileSync13 } from "fs";
10232
10909
  import { join as join20, basename as basename7 } from "path";
10233
10910
  async function graphPush() {
10234
10911
  const root = process.cwd();
@@ -10238,11 +10915,11 @@ async function graphPush() {
10238
10915
  }
10239
10916
  const m = read(root);
10240
10917
  const modelsDir = join20(root, "src", "models");
10241
- if (!existsSync16(modelsDir)) {
10918
+ if (!existsSync17(modelsDir)) {
10242
10919
  console.error(source_default.red("No src/models/ directory found. Run 'construct graph init' first."));
10243
10920
  process.exit(1);
10244
10921
  }
10245
- const modelFiles = readdirSync5(modelsDir).filter((f) => f.endsWith(".ts") && f !== "index.ts");
10922
+ const modelFiles = readdirSync4(modelsDir).filter((f) => f.endsWith(".ts") && f !== "index.ts");
10246
10923
  if (modelFiles.length === 0) {
10247
10924
  console.error(source_default.red("No model files found in src/models/"));
10248
10925
  console.log(source_default.dim(" Generate one: construct graph g User name:string email:string"));
@@ -10251,7 +10928,7 @@ async function graphPush() {
10251
10928
  console.log(source_default.blue(`Pushing ${modelFiles.length} model(s) for space: ${m.id}`));
10252
10929
  const models = [];
10253
10930
  for (const file of modelFiles) {
10254
- const content = readFileSync12(join20(modelsDir, file), "utf-8");
10931
+ const content = readFileSync13(join20(modelsDir, file), "utf-8");
10255
10932
  const model = parseModelFile(content, basename7(file, ".ts"));
10256
10933
  if (model)
10257
10934
  models.push(model);
@@ -10270,14 +10947,12 @@ async function graphPush() {
10270
10947
  const graphURL = process.env.GRAPH_URL || "https://graph.construct.space";
10271
10948
  const spinner = ora("Registering models...").start();
10272
10949
  try {
10273
- const userID = creds.user?.id || "";
10274
10950
  const resp = await fetch(`${graphURL}/api/schemas/register`, {
10275
10951
  method: "POST",
10276
10952
  headers: {
10277
10953
  "Content-Type": "application/json",
10278
10954
  Authorization: `Bearer ${creds.token}`,
10279
- "X-Space-ID": m.id,
10280
- "X-Auth-User-ID": userID
10955
+ "X-Space-ID": m.id
10281
10956
  },
10282
10957
  body: JSON.stringify({
10283
10958
  space_id: m.id,
@@ -10287,20 +10962,6 @@ async function graphPush() {
10287
10962
  manifest: { version: 1, models }
10288
10963
  })
10289
10964
  });
10290
- if (resp.status === 403) {
10291
- spinner.fail("Ownership check failed");
10292
- try {
10293
- const errBody = await resp.json();
10294
- console.error(source_default.red(` ${errBody.error || "You are not the owner of this space"}`));
10295
- if (errBody.owner_user_id) {
10296
- console.error(source_default.dim(` Current owner: ${errBody.owner_user_id}`));
10297
- }
10298
- console.error(source_default.dim(" Fork to a new space_id to publish your own version."));
10299
- } catch {
10300
- console.error(source_default.red(` 403: Forbidden \u2014 ownership check failed`));
10301
- }
10302
- process.exit(1);
10303
- }
10304
10965
  if (!resp.ok) {
10305
10966
  const body = await resp.text();
10306
10967
  spinner.fail("Registration failed");
@@ -10383,7 +11044,7 @@ function parseModelFile(content, fileName) {
10383
11044
  }
10384
11045
 
10385
11046
  // src/commands/graph/migrate.ts
10386
- import { existsSync as existsSync17, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
11047
+ import { existsSync as existsSync18, readdirSync as readdirSync5, readFileSync as readFileSync14 } from "fs";
10387
11048
  import { join as join21, basename as basename8 } from "path";
10388
11049
  async function graphMigrate(options) {
10389
11050
  const root = process.cwd();
@@ -10393,7 +11054,7 @@ async function graphMigrate(options) {
10393
11054
  }
10394
11055
  const m = read(root);
10395
11056
  const modelsDir = join21(root, "src", "models");
10396
- if (!existsSync17(modelsDir)) {
11057
+ if (!existsSync18(modelsDir)) {
10397
11058
  console.error(source_default.red("No src/models/ directory. Run 'construct graph init' first."));
10398
11059
  process.exit(1);
10399
11060
  }
@@ -10420,10 +11081,10 @@ async function graphMigrate(options) {
10420
11081
  spinner.fail("Could not fetch schema");
10421
11082
  process.exit(1);
10422
11083
  }
10423
- const modelFiles = readdirSync6(modelsDir).filter((f) => f.endsWith(".ts") && f !== "index.ts");
11084
+ const modelFiles = readdirSync5(modelsDir).filter((f) => f.endsWith(".ts") && f !== "index.ts");
10424
11085
  const localModels = [];
10425
11086
  for (const file of modelFiles) {
10426
- const content = readFileSync13(join21(modelsDir, file), "utf-8");
11087
+ const content = readFileSync14(join21(modelsDir, file), "utf-8");
10427
11088
  const model = parseModelFields(content, basename8(file, ".ts"));
10428
11089
  if (model)
10429
11090
  localModels.push(model);
@@ -10527,7 +11188,7 @@ function parseModelFields(content, fileName) {
10527
11188
  }
10528
11189
 
10529
11190
  // src/index.ts
10530
- var VERSION = "1.1.9";
11191
+ var VERSION = "1.1.12";
10531
11192
  var program2 = new Command;
10532
11193
  program2.name("construct").description("Construct CLI \u2014 scaffold, build, develop, and publish spaces").version(VERSION);
10533
11194
  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));
@@ -10540,6 +11201,7 @@ program2.command("check").description("Run type-check (vue-tsc) and linter (esli
10540
11201
  program2.command("clean").description("Remove build artifacts").option("--all", "Also remove node_modules and lockfiles").action((opts) => clean(opts));
10541
11202
  program2.command("login").description("Authenticate with Construct").option("--portal <url>", "Portal URL").action(async (opts) => login(opts));
10542
11203
  program2.command("logout").description("Sign out").action(() => logout());
11204
+ program2.command("whoami").alias("status").description("Show the active profile, its source (app or CLI), and linked publishers").action(() => whoami());
10543
11205
  program2.command("update").description("Update the CLI to the latest version").action(() => update());
10544
11206
  var graph = program2.command("graph").description("Construct Graph \u2014 data models and GraphQL");
10545
11207
  graph.command("init").description("Initialize Graph in a space project").action(() => graphInit());