@construct-space/cli 1.8.1 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3090,6 +3090,83 @@ var init_whoami = __esm(() => {
3090
3090
  init_auth();
3091
3091
  });
3092
3092
 
3093
+ // src/commands/org.ts
3094
+ var exports_org = {};
3095
+ __export(exports_org, {
3096
+ orgStatus: () => orgStatus
3097
+ });
3098
+ async function orgStatus() {
3099
+ let creds;
3100
+ try {
3101
+ creds = load2();
3102
+ } catch {
3103
+ console.error(source_default.red("Not signed in."));
3104
+ console.error(source_default.dim("Run 'construct login' first."));
3105
+ process.exit(1);
3106
+ }
3107
+ let s;
3108
+ try {
3109
+ const res = await fetch(ACCOUNTS_SCOPE_URL3, {
3110
+ headers: { Authorization: `Bearer ${creds.token}`, Accept: "application/json" }
3111
+ });
3112
+ if (!res.ok) {
3113
+ console.error(source_default.red(`Scope lookup failed (${res.status}).`));
3114
+ console.error(source_default.dim("Token may be expired. Try: construct login"));
3115
+ process.exit(1);
3116
+ }
3117
+ s = await res.json();
3118
+ } catch (err) {
3119
+ console.error(source_default.red(`Could not reach accounts service: ${err?.message || err}`));
3120
+ process.exit(1);
3121
+ }
3122
+ if (!s.authenticated || !s.user) {
3123
+ console.error(source_default.red("Token rejected."));
3124
+ process.exit(1);
3125
+ }
3126
+ if (s.scope === "org" && s.org) {
3127
+ console.log(source_default.cyan("Scope: ") + source_default.bold(`org \u2014 ${s.org.name || s.org.slug || s.org.id}`));
3128
+ if (s.org.slug)
3129
+ console.log(source_default.dim(` slug: ${s.org.slug}`));
3130
+ if (s.org.id)
3131
+ console.log(source_default.dim(` id: ${s.org.id}`));
3132
+ if (s.roles && s.roles.length) {
3133
+ console.log(source_default.dim(` roles: ${s.roles.join(", ")}`));
3134
+ }
3135
+ } else {
3136
+ console.log(source_default.cyan("Scope: ") + source_default.bold("personal"));
3137
+ console.log(source_default.dim(" (switch to an org at https://my.construct.space)"));
3138
+ }
3139
+ console.log();
3140
+ console.log(source_default.cyan("Signed in as"));
3141
+ console.log(` ${s.user.email || s.user.username || s.user.uuid || "(unknown)"}`);
3142
+ if (s.user.uuid)
3143
+ console.log(source_default.dim(` ${s.user.uuid}`));
3144
+ console.log();
3145
+ console.log(source_default.cyan("Publisher (from auth.json)"));
3146
+ if (creds.publisherKey) {
3147
+ const kind = creds.publisherKind || "user";
3148
+ const expected = s.scope === "org" ? "org" : "user";
3149
+ const matches = kind === expected;
3150
+ console.log(` ${source_default.bold(creds.publisherName || "(unnamed)")} ${source_default.dim(`[${kind}]`)}`);
3151
+ console.log(source_default.dim(` key: ${creds.publisherKey.slice(0, 14)}\u2026`));
3152
+ if (!matches) {
3153
+ console.log(source_default.yellow(` \u26A0 publisher kind (${kind}) doesn't match active scope (${expected}).`));
3154
+ console.log(source_default.dim(" Restart the desktop app or run 'construct login' to re-sync."));
3155
+ }
3156
+ } else {
3157
+ console.log(source_default.dim(" (none \u2014 enroll as a developer to get a publisher key)"));
3158
+ }
3159
+ if (s.developer) {
3160
+ console.log();
3161
+ console.log(source_default.dim("developer capability: ") + source_default.green("enabled"));
3162
+ }
3163
+ }
3164
+ var ACCOUNTS_SCOPE_URL3 = "https://my.construct.space/api/accounts/me/scope";
3165
+ var init_org = __esm(() => {
3166
+ init_source();
3167
+ init_auth();
3168
+ });
3169
+
3093
3170
  // src/lib/graphClient.ts
3094
3171
  function graphBaseURL() {
3095
3172
  return process.env.GRAPH_URL || "https://graph.construct.space";
@@ -5373,7 +5450,9 @@ async function scaffold(nameArg, options) {
5373
5450
  join2(name, "src", "pages"),
5374
5451
  join2(name, "src", "components"),
5375
5452
  join2(name, "src", "composables"),
5376
- join2(name, "agent", "skills"),
5453
+ join2(name, "scripts"),
5454
+ join2(name, "references"),
5455
+ join2(name, "assets"),
5377
5456
  join2(name, "agent", "hooks"),
5378
5457
  join2(name, "agent", "tools"),
5379
5458
  join2(name, "widgets", "summary")
@@ -5394,7 +5473,7 @@ async function scaffold(nameArg, options) {
5394
5473
  "style.css.tmpl": join2(name, "src", "style.css"),
5395
5474
  "index.vue.tmpl": join2(name, "src", "pages", "index.vue"),
5396
5475
  "config.md.tmpl": join2(name, "agent", "config.md"),
5397
- "skill.md.tmpl": join2(name, "agent", "skills", "default.md"),
5476
+ "skill.md.tmpl": join2(name, "SKILL.md"),
5398
5477
  "safety.json.tmpl": join2(name, "agent", "hooks", "safety.json"),
5399
5478
  "tsconfig.json.tmpl": join2(name, "tsconfig.json"),
5400
5479
  "eslint.config.js.tmpl": join2(name, "eslint.config.js"),
@@ -5417,9 +5496,9 @@ async function scaffold(nameArg, options) {
5417
5496
  }
5418
5497
  if (isFull) {
5419
5498
  writeTemplate(templateDir, "full/settings.vue.tmpl", join2(name, "src", "pages", "settings.vue"), data);
5420
- writeTemplate(templateDir, "full/skill-data.md.tmpl", join2(name, "agent", "skills", "data.md"), data);
5421
- writeTemplate(templateDir, "full/skill-ui.md.tmpl", join2(name, "agent", "skills", "ui.md"), data);
5422
- console.log(source_default.blue("Full preset: settings page + extra skills added"));
5499
+ writeTemplate(templateDir, "full/skill-data.md.tmpl", join2(name, "references", "data.md"), data);
5500
+ writeTemplate(templateDir, "full/skill-ui.md.tmpl", join2(name, "references", "ui.md"), data);
5501
+ console.log(source_default.blue("Full preset: settings page + references/data.md + references/ui.md"));
5423
5502
  }
5424
5503
  if (options?.withTests) {
5425
5504
  mkdirSync(join2(name, "e2e"), { recursive: true });
@@ -10468,6 +10547,13 @@ async function publish(options) {
10468
10547
  const yes = options?.yes ?? false;
10469
10548
  const wantPrivate = options?.private ?? false;
10470
10549
  const wantPublic = options?.public ?? false;
10550
+ const scopeOpt = options?.scope ? options.scope.toLowerCase() : undefined;
10551
+ if (scopeOpt && scopeOpt !== "user" && scopeOpt !== "org") {
10552
+ console.error(source_default.red(`--scope must be 'user' or 'org', got '${options?.scope}'.`));
10553
+ process.exit(1);
10554
+ }
10555
+ const wantOrgScope = scopeOpt === "org";
10556
+ const wantUserScope = scopeOpt === "user";
10471
10557
  if (wantPrivate && wantPublic) {
10472
10558
  console.error(source_default.red("Cannot combine --private and --public. Pick one."));
10473
10559
  process.exit(1);
@@ -10561,10 +10647,19 @@ async function publish(options) {
10561
10647
  console.log(source_default.dim(" (Org Settings \u2192 Developer), then re-run this command."));
10562
10648
  console.log();
10563
10649
  }
10564
- if (wantPrivate && creds.publisherKind !== "org") {
10650
+ if (wantUserScope && creds.publisherKind === "org" && !options?.apiKey) {
10651
+ console.error(source_default.red("--scope=user, but the active publisher in auth.json is an org publisher."));
10652
+ console.error(source_default.dim(" Switch context to personal in the desktop app, or pass --api-key with a personal key."));
10653
+ process.exit(1);
10654
+ }
10655
+ if (wantOrgScope && creds.publisherKind === "user" && !options?.apiKey) {
10656
+ creds = { ...creds, publisherKey: undefined, publisherKind: undefined, publisherName: undefined };
10657
+ }
10658
+ if (wantPrivate && creds.publisherKind !== "org" && !wantOrgScope) {
10565
10659
  console.error(source_default.red("--private requires an org publisher key."));
10566
10660
  console.error(source_default.dim(" Personal publishes are always public."));
10567
- console.error(source_default.dim(" Enrol an org from the desktop app (Org Settings \u2192 Developer) and re-run."));
10661
+ console.error(source_default.dim(" Pass --scope=org to publish as your active org, or enrol an org"));
10662
+ console.error(source_default.dim(" from the desktop app (Org Settings \u2192 Developer) first."));
10568
10663
  process.exit(1);
10569
10664
  }
10570
10665
  console.log();
@@ -10609,12 +10704,24 @@ async function publish(options) {
10609
10704
  const uploadSpinner = ora("Uploading & building...").start();
10610
10705
  try {
10611
10706
  const explicitKey = options?.apiKey || process.env.CONSTRUCT_PUBLISHER_KEY;
10612
- const initialKey = explicitKey || creds.publisherKey;
10707
+ let initialKey = explicitKey || creds.publisherKey;
10708
+ if (wantOrgScope && !explicitKey && !initialKey) {
10709
+ uploadSpinner.text = "Fetching org publisher key\u2026";
10710
+ const orgKey = await fetchOrgPublisherKey(creds.portal, creds.token);
10711
+ if (!orgKey) {
10712
+ uploadSpinner.fail("No org publisher available for --scope=org");
10713
+ console.error(source_default.dim(" Switch into an org context in the desktop app, or pass --api-key"));
10714
+ console.error(source_default.dim(" with a csk_live_* key the org owns."));
10715
+ unlinkSync2(tarballPath);
10716
+ process.exit(1);
10717
+ }
10718
+ initialKey = orgKey;
10719
+ }
10613
10720
  let result;
10614
10721
  try {
10615
10722
  result = await uploadSource(creds.portal, creds.token, initialKey, tarballPath, m, { private: wantPrivate, public: wantPublic });
10616
10723
  } catch (e) {
10617
- if (e?.ownerKind === "org" && !creds.publisherKey) {
10724
+ if (e?.ownerKind === "org" && !creds.publisherKey && !wantUserScope) {
10618
10725
  uploadSpinner.text = "Fetching org publisher key\u2026";
10619
10726
  const orgKey = await fetchOrgPublisherKey(creds.portal, creds.token);
10620
10727
  if (!orgKey)
@@ -11593,7 +11700,7 @@ function graphFork(newSpaceID) {
11593
11700
  // package.json
11594
11701
  var package_default = {
11595
11702
  name: "@construct-space/cli",
11596
- version: "1.8.1",
11703
+ version: "1.9.1",
11597
11704
  description: "Construct CLI \u2014 scaffold, build, develop, and publish spaces",
11598
11705
  type: "module",
11599
11706
  bin: {
@@ -11645,7 +11752,7 @@ program2.command("scaffold [name]").alias("new").alias("create").description("Cr
11645
11752
  program2.command("build").description("Build the space (generate entry + run Vite)").option("--entry-only", "Only generate src/entry.ts").action(async (opts) => build(opts));
11646
11753
  program2.command("dev").description("Start dev mode with file watching and live reload").action(async () => dev());
11647
11754
  program2.command("install").alias("run").description("Install built space to Construct spaces directory").action(() => install());
11648
- program2.command("publish").description("Publish a space to the Construct registry").option("-y, --yes", "Skip all confirmation prompts").option("--bump <type>", "Auto-bump version (patch, minor, major)").option("--private", "Publish as org-private (catalog-listed only inside the owning org). Requires an org publisher key.").option("--public", "Flip a previously-private space back to the public catalog on this publish. Without --private or --public, visibility is preserved on update (and defaults to public on first publish).").option("--api-key <key>", "Publisher API key (csk_live_\u2026). Overrides any key stored in the active profile. Also reads CONSTRUCT_PUBLISHER_KEY.").action(async (opts) => publish(opts));
11755
+ program2.command("publish").description("Publish a space to the Construct registry").option("-y, --yes", "Skip all confirmation prompts").option("--bump <type>", "Auto-bump version (patch, minor, major)").option("--private", "Publish as org-private (catalog-listed only inside the owning org). Requires an org publisher key.").option("--public", "Flip a previously-private space back to the public catalog on this publish. Without --private or --public, visibility is preserved on update (and defaults to public on first publish).").option("--scope <scope>", "Publish as 'user' (personal) or 'org'. Without this flag, the active publisher in auth.json decides.").option("--api-key <key>", "Publisher API key (csk_live_\u2026). Overrides any key stored in the active profile. Also reads CONSTRUCT_PUBLISHER_KEY.").action(async (opts) => publish(opts));
11649
11756
  program2.command("validate").description("Validate space.manifest.json").action(() => validate3());
11650
11757
  program2.command("check").description("Run type-check (vue-tsc) and linter (eslint)").action(() => check());
11651
11758
  program2.command("clean").description("Remove build artifacts").option("--all", "Also remove node_modules and lockfiles").action((opts) => clean(opts));
@@ -11653,6 +11760,8 @@ program2.command("login").description("Authenticate with Construct").option("--p
11653
11760
  program2.command("logout").description("Sign out").action(() => logout());
11654
11761
  program2.command("update").description("Update the CLI to the latest version").action(() => update());
11655
11762
  program2.command("whoami").alias("status").description("Show the signed-in user + current org scope").action(async () => (await Promise.resolve().then(() => (init_whoami(), exports_whoami))).whoami());
11763
+ var org = program2.command("org").description("Inspect the active organization context");
11764
+ org.command("status").description("Show active scope, publisher, and roles").action(async () => (await Promise.resolve().then(() => (init_org(), exports_org))).orgStatus());
11656
11765
  var graph = program2.command("graph").description("Construct Graph \u2014 data models and GraphQL");
11657
11766
  graph.command("init").description("Initialize Graph in a space project").action(() => graphInit());
11658
11767
  graph.command("generate <model> [fields...]").alias("g").description("Generate a data model").option("--access <rules>", "Access rules (e.g. read:member,create:member,update:owner,delete:admin)").action((model, fields, opts) => generate2(model, fields, opts));
@@ -1,18 +1,14 @@
1
- ---
2
- id: {{.ID}}-data
3
- name: {{.DisplayName}} Data Management
4
- description: Skill for managing {{.DisplayName}} data and content
5
- trigger: {{.ID}} data|content|manage
6
- category: space
7
- tools: [read_file, list_dir, glob, grep, write_file]
8
- ---
1
+ # {{.DisplayName}} — data
9
2
 
10
- # {{.DisplayName}} Data Management Skill
3
+ Reference doc for the agent when working with {{.DisplayName}} data.
11
4
 
12
- This skill handles data operations for the {{.DisplayName}} space.
5
+ ## Storage model
13
6
 
14
- ## Instructions
15
- - Help users create, read, update, and delete content
16
- - Validate data before writing
17
- - Use the space actions API when available
18
- - Prefer batch operations for bulk changes
7
+ Describe where {{.DisplayName}} data lives (Graph models, local storage, server API…). Edit this section to match the actual model.
8
+
9
+ ## CRUD conventions
10
+
11
+ - Validate inputs before writing
12
+ - Prefer the space's actions API over raw file or DB writes
13
+ - Batch bulk changes when possible
14
+ - Read existing rows before modifying — changes should be additive when in doubt
@@ -1,18 +1,23 @@
1
- ---
2
- id: {{.ID}}-ui
3
- name: {{.DisplayName}} UI Customization
4
- description: Skill for customizing the {{.DisplayName}} user interface
5
- trigger: {{.ID}} ui|layout|design|style
6
- category: space
7
- tools: [read_file, write_file, glob]
8
- ---
9
-
10
- # {{.DisplayName}} UI Customization Skill
11
-
12
- This skill helps customize the {{.DisplayName}} space interface.
13
-
14
- ## Instructions
15
- - Help users adjust layout and styling
16
- - Use Construct CSS variables (--app-foreground, --app-background, --app-accent, etc.)
17
- - Follow the host design system conventions
18
- - Suggest accessible color combinations
1
+ # {{.DisplayName}} — UI
2
+
3
+ Reference doc for the agent when adjusting {{.DisplayName}}'s UI.
4
+
5
+ ## Design tokens
6
+
7
+ Use Construct CSS variables instead of hardcoded values:
8
+
9
+ - `--app-foreground`, `--app-background`
10
+ - `--app-accent`, `--app-accent-fg`
11
+ - `--app-border`, `--app-muted`
12
+
13
+ ## Layout
14
+
15
+ - Live inside the host shell — avoid full-bleed layouts that conflict with the sidebar/header
16
+ - Use the `@construct-space/ui` primitives (`Card`, `Button`, `Badge`, ) for consistency
17
+ - Prefer flex/grid over absolute positioning
18
+
19
+ ## Accessibility
20
+
21
+ - Maintain 4.5:1 contrast for body text
22
+ - Visible focus rings on every interactive element
23
+ - Don't rely on color alone for state
@@ -39,11 +39,7 @@
39
39
  ],
40
40
  "keywords": ["{{.ID}}"],
41
41
  "agent": "agent/config.md",
42
- "skills": [
43
- "agent/skills/default.md",
44
- "agent/skills/data.md",
45
- "agent/skills/ui.md"
46
- ],
42
+ "skills": ["SKILL.md"],
47
43
  "actions": "src/actions.ts",
48
44
  "widgets": [
49
45
  {
@@ -1,17 +1,31 @@
1
1
  ---
2
- id: {{.ID}}-default
3
- name: {{.DisplayName}} Basics
4
- description: Default skill for {{.DisplayName}} space
5
- trigger: {{.ID}}|help
2
+ name: {{.ID}}
3
+ description: Help the user with tasks inside the {{.DisplayName}} space. Use when the user is working in {{.DisplayName}}, mentions {{.ID}}-related concepts, or asks what this space can do.
4
+ allowed-tools: Read Glob Grep
6
5
  category: space
7
- tools: [read_file, list_dir, glob, grep]
6
+ scope: any
8
7
  ---
9
8
 
10
- # {{.DisplayName}} Space Skill
9
+ # {{.DisplayName}}
11
10
 
12
- This skill provides default behavior for the {{.DisplayName}} space.
11
+ Help the user with tasks inside the {{.DisplayName}} space.
12
+
13
+ ## When to use
14
+
15
+ - The user is inside the {{.DisplayName}} space
16
+ - The user types `{{.ID}}` or asks about {{.DisplayName}}-related work
17
+ - The user invokes a {{.DisplayName}} action
13
18
 
14
19
  ## Instructions
15
- - Assist with {{.DisplayName}}-related tasks
16
- - Follow project conventions
17
- - Read relevant files before making suggestions
20
+
21
+ - Read existing files in the space before suggesting changes
22
+ - Prefer space actions (see `src/actions.ts`) over generic file edits
23
+ - Surface the space's conventions when proposing new code
24
+
25
+ ## Resources
26
+
27
+ The agent loads these on demand:
28
+
29
+ - `references/` — domain-specific docs (data model, UI conventions, …)
30
+ - `scripts/` — supporting executables
31
+ - `assets/` — templates and static resources
@@ -34,7 +34,7 @@
34
34
  ],
35
35
  "keywords": ["{{.ID}}"],
36
36
  "agent": "agent/config.md",
37
- "skills": ["agent/skills/default.md"],
37
+ "skills": ["SKILL.md"],
38
38
  "actions": "src/actions.ts",
39
39
  "widgets": [
40
40
  {
@@ -7,7 +7,16 @@ import { resolve } from 'path'
7
7
  * Host-provided externals — these are supplied by Construct at runtime
8
8
  * via window.__CONSTRUCT__. Do NOT bundle them; they must stay external.
9
9
  *
10
- * Full list lives in: construct-app/frontend/lib/spaceHost.ts
10
+ * Source of truth: construct-app/frontend/lib/spaceHost.ts
11
+ *
12
+ * IMPORTANT — only add a package here AFTER confirming spaceHost.ts
13
+ * actually puts it on window.__CONSTRUCT__. Externalising a package the
14
+ * host doesn't expose silently substitutes `undefined`; you'll see
15
+ * "X is not a function" at runtime. When in doubt, bundle it (omit from
16
+ * this list) — bundle bloat is cheaper than a broken space.
17
+ *
18
+ * Notably NOT externalised:
19
+ * @construct-space/graph — host does not expose this. Bundle it.
11
20
  */
12
21
  const hostExternals = [
13
22
  'vue',
@@ -21,7 +30,6 @@ const hostExternals = [
21
30
  'zod',
22
31
  '@construct-space/ui',
23
32
  '@construct-space/sdk',
24
- '@construct-space/graph',
25
33
  '@construct/sdk', // legacy alias — keep during cutover
26
34
  ]
27
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@construct-space/cli",
3
- "version": "1.8.1",
3
+ "version": "1.9.1",
4
4
  "description": "Construct CLI — scaffold, build, develop, and publish spaces",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,18 +1,14 @@
1
- ---
2
- id: {{.ID}}-data
3
- name: {{.DisplayName}} Data Management
4
- description: Skill for managing {{.DisplayName}} data and content
5
- trigger: {{.ID}} data|content|manage
6
- category: space
7
- tools: [read_file, list_dir, glob, grep, write_file]
8
- ---
1
+ # {{.DisplayName}} — data
9
2
 
10
- # {{.DisplayName}} Data Management Skill
3
+ Reference doc for the agent when working with {{.DisplayName}} data.
11
4
 
12
- This skill handles data operations for the {{.DisplayName}} space.
5
+ ## Storage model
13
6
 
14
- ## Instructions
15
- - Help users create, read, update, and delete content
16
- - Validate data before writing
17
- - Use the space actions API when available
18
- - Prefer batch operations for bulk changes
7
+ Describe where {{.DisplayName}} data lives (Graph models, local storage, server API…). Edit this section to match the actual model.
8
+
9
+ ## CRUD conventions
10
+
11
+ - Validate inputs before writing
12
+ - Prefer the space's actions API over raw file or DB writes
13
+ - Batch bulk changes when possible
14
+ - Read existing rows before modifying — changes should be additive when in doubt
@@ -1,18 +1,23 @@
1
- ---
2
- id: {{.ID}}-ui
3
- name: {{.DisplayName}} UI Customization
4
- description: Skill for customizing the {{.DisplayName}} user interface
5
- trigger: {{.ID}} ui|layout|design|style
6
- category: space
7
- tools: [read_file, write_file, glob]
8
- ---
9
-
10
- # {{.DisplayName}} UI Customization Skill
11
-
12
- This skill helps customize the {{.DisplayName}} space interface.
13
-
14
- ## Instructions
15
- - Help users adjust layout and styling
16
- - Use Construct CSS variables (--app-foreground, --app-background, --app-accent, etc.)
17
- - Follow the host design system conventions
18
- - Suggest accessible color combinations
1
+ # {{.DisplayName}} — UI
2
+
3
+ Reference doc for the agent when adjusting {{.DisplayName}}'s UI.
4
+
5
+ ## Design tokens
6
+
7
+ Use Construct CSS variables instead of hardcoded values:
8
+
9
+ - `--app-foreground`, `--app-background`
10
+ - `--app-accent`, `--app-accent-fg`
11
+ - `--app-border`, `--app-muted`
12
+
13
+ ## Layout
14
+
15
+ - Live inside the host shell — avoid full-bleed layouts that conflict with the sidebar/header
16
+ - Use the `@construct-space/ui` primitives (`Card`, `Button`, `Badge`, ) for consistency
17
+ - Prefer flex/grid over absolute positioning
18
+
19
+ ## Accessibility
20
+
21
+ - Maintain 4.5:1 contrast for body text
22
+ - Visible focus rings on every interactive element
23
+ - Don't rely on color alone for state
@@ -39,11 +39,7 @@
39
39
  ],
40
40
  "keywords": ["{{.ID}}"],
41
41
  "agent": "agent/config.md",
42
- "skills": [
43
- "agent/skills/default.md",
44
- "agent/skills/data.md",
45
- "agent/skills/ui.md"
46
- ],
42
+ "skills": ["SKILL.md"],
47
43
  "actions": "src/actions.ts",
48
44
  "widgets": [
49
45
  {
@@ -1,17 +1,31 @@
1
1
  ---
2
- id: {{.ID}}-default
3
- name: {{.DisplayName}} Basics
4
- description: Default skill for {{.DisplayName}} space
5
- trigger: {{.ID}}|help
2
+ name: {{.ID}}
3
+ description: Help the user with tasks inside the {{.DisplayName}} space. Use when the user is working in {{.DisplayName}}, mentions {{.ID}}-related concepts, or asks what this space can do.
4
+ allowed-tools: Read Glob Grep
6
5
  category: space
7
- tools: [read_file, list_dir, glob, grep]
6
+ scope: any
8
7
  ---
9
8
 
10
- # {{.DisplayName}} Space Skill
9
+ # {{.DisplayName}}
11
10
 
12
- This skill provides default behavior for the {{.DisplayName}} space.
11
+ Help the user with tasks inside the {{.DisplayName}} space.
12
+
13
+ ## When to use
14
+
15
+ - The user is inside the {{.DisplayName}} space
16
+ - The user types `{{.ID}}` or asks about {{.DisplayName}}-related work
17
+ - The user invokes a {{.DisplayName}} action
13
18
 
14
19
  ## Instructions
15
- - Assist with {{.DisplayName}}-related tasks
16
- - Follow project conventions
17
- - Read relevant files before making suggestions
20
+
21
+ - Read existing files in the space before suggesting changes
22
+ - Prefer space actions (see `src/actions.ts`) over generic file edits
23
+ - Surface the space's conventions when proposing new code
24
+
25
+ ## Resources
26
+
27
+ The agent loads these on demand:
28
+
29
+ - `references/` — domain-specific docs (data model, UI conventions, …)
30
+ - `scripts/` — supporting executables
31
+ - `assets/` — templates and static resources
@@ -34,7 +34,7 @@
34
34
  ],
35
35
  "keywords": ["{{.ID}}"],
36
36
  "agent": "agent/config.md",
37
- "skills": ["agent/skills/default.md"],
37
+ "skills": ["SKILL.md"],
38
38
  "actions": "src/actions.ts",
39
39
  "widgets": [
40
40
  {
@@ -7,7 +7,16 @@ import { resolve } from 'path'
7
7
  * Host-provided externals — these are supplied by Construct at runtime
8
8
  * via window.__CONSTRUCT__. Do NOT bundle them; they must stay external.
9
9
  *
10
- * Full list lives in: construct-app/frontend/lib/spaceHost.ts
10
+ * Source of truth: construct-app/frontend/lib/spaceHost.ts
11
+ *
12
+ * IMPORTANT — only add a package here AFTER confirming spaceHost.ts
13
+ * actually puts it on window.__CONSTRUCT__. Externalising a package the
14
+ * host doesn't expose silently substitutes `undefined`; you'll see
15
+ * "X is not a function" at runtime. When in doubt, bundle it (omit from
16
+ * this list) — bundle bloat is cheaper than a broken space.
17
+ *
18
+ * Notably NOT externalised:
19
+ * @construct-space/graph — host does not expose this. Bundle it.
11
20
  */
12
21
  const hostExternals = [
13
22
  'vue',
@@ -21,7 +30,6 @@ const hostExternals = [
21
30
  'zod',
22
31
  '@construct-space/ui',
23
32
  '@construct-space/sdk',
24
- '@construct-space/graph',
25
33
  '@construct/sdk', // legacy alias — keep during cutover
26
34
  ]
27
35