@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 +975 -313
- package/dist/templates/space/full/space.manifest.json.tmpl +1 -1
- package/dist/templates/space/space.manifest.json.tmpl +1 -1
- package/dist/templates/space/widgets/2x1.vue.tmpl +0 -7
- package/dist/templates/space/widgets/4x1.vue.tmpl +0 -7
- package/package.json +2 -2
- package/templates/space/full/space.manifest.json.tmpl +1 -1
- package/templates/space/space.manifest.json.tmpl +1 -1
- package/templates/space/widgets/2x1.vue.tmpl +0 -7
- package/templates/space/widgets/4x1.vue.tmpl +0 -7
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: (
|
|
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: (
|
|
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
|
|
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
|
-
|
|
4610
|
+
const cmd = hooks?.[hookName];
|
|
4611
|
+
if (!cmd)
|
|
4594
4612
|
return;
|
|
4595
|
-
execSync2(
|
|
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 (
|
|
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
|
|
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 (!["
|
|
7366
|
-
errors2.push('scope: must be "
|
|
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
|
|
7394
|
-
import { join as join4, basename, extname
|
|
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
|
|
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
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
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
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
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
|
-
|
|
8030
|
+
varName = capitalize(cleanPath) + "Page";
|
|
7469
8031
|
}
|
|
7470
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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) &&
|
|
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 =
|
|
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
|
|
7702
|
-
import { join as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7947
|
-
import {
|
|
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(
|
|
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(
|
|
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 =
|
|
8403
|
-
const basename4 =
|
|
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 =
|
|
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 =
|
|
8434
|
-
const basename4 =
|
|
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 =
|
|
8518
|
-
|
|
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 =
|
|
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 =
|
|
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(
|
|
8574
|
-
const tracked = parentDir.has(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
8686
|
-
if (!
|
|
9230
|
+
const relative3 = sysPath2.relative(matcher.path, string);
|
|
9231
|
+
if (!relative3) {
|
|
8687
9232
|
return false;
|
|
8688
9233
|
}
|
|
8689
|
-
return !
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
9300
|
+
var normalizePathToUnix = (path) => toUnix(sysPath2.normalize(toUnix(path)));
|
|
8752
9301
|
var normalizeIgnored = (cwd = "") => (path) => {
|
|
8753
9302
|
if (typeof path === "string") {
|
|
8754
|
-
return normalizePathToUnix(
|
|
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 (
|
|
9309
|
+
if (sysPath2.isAbsolute(path)) {
|
|
8761
9310
|
return path;
|
|
8762
9311
|
}
|
|
8763
|
-
return
|
|
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(
|
|
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 =
|
|
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
|
|
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(
|
|
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 (!
|
|
9518
|
+
if (!sysPath2.isAbsolute(path) && !this._closers.has(path)) {
|
|
8998
9519
|
if (cwd)
|
|
8999
|
-
path =
|
|
9000
|
-
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 ?
|
|
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 =
|
|
9581
|
+
path = sysPath2.normalize(path);
|
|
9061
9582
|
if (opts.cwd)
|
|
9062
|
-
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 ?
|
|
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 && !
|
|
9170
|
-
fullPath =
|
|
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 =
|
|
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 =
|
|
9239
|
-
const fullPath =
|
|
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 =
|
|
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 =
|
|
9273
|
-
this._getWatchedDir(dir).remove(
|
|
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
|
-
|
|
9320
|
-
|
|
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 =
|
|
9360
|
-
const bundleFile =
|
|
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 (!
|
|
9929
|
+
if (!existsSync8(bundleFile))
|
|
9365
9930
|
return;
|
|
9366
|
-
const bundleData =
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
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 (
|
|
9974
|
+
if (existsSync9(agentDir)) {
|
|
9432
9975
|
bundleAgentDir(agentDir, distDir);
|
|
9433
9976
|
}
|
|
9434
9977
|
const installDir = spaceDir(m.id);
|
|
9435
|
-
|
|
9436
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (!
|
|
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(
|
|
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 (
|
|
10060
|
+
if (existsSync10(path))
|
|
9481
10061
|
unlinkSync(path);
|
|
9482
10062
|
}
|
|
9483
10063
|
|
|
9484
10064
|
// src/lib/pack.ts
|
|
9485
|
-
import { readdirSync as
|
|
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 (
|
|
10104
|
+
if (existsSync11(join13(root, name)))
|
|
9525
10105
|
entries.push(name);
|
|
9526
10106
|
}
|
|
9527
|
-
for (const entry of
|
|
9528
|
-
if (
|
|
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 (
|
|
10118
|
+
if (existsSync11(join13(root, dir)))
|
|
9539
10119
|
entries.push(dir);
|
|
9540
10120
|
}
|
|
9541
|
-
const validEntries = entries.filter((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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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 (
|
|
9771
|
-
const pkg = JSON.parse(
|
|
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
|
|
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 (!
|
|
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 && !
|
|
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 (
|
|
9817
|
-
const pkg = JSON.parse(
|
|
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
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
10677
|
+
mkdirSync6(modelsDir, { recursive: true });
|
|
10001
10678
|
const indexPath = join18(modelsDir, "index.ts");
|
|
10002
|
-
if (!
|
|
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(
|
|
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
|
|
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
|
-
|
|
10872
|
+
mkdirSync7(modelsDir, { recursive: true });
|
|
10196
10873
|
const filePath = join19(modelsDir, `${name}.ts`);
|
|
10197
|
-
if (
|
|
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 (
|
|
10217
|
-
const content =
|
|
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
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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.
|
|
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());
|