devsurface 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0
4
+
5
+ - Added structured `setupGuide` steps in `devsurface.config.json`: each step can be a plain string or an object with `title`, `description`, and a `command` or `script` key that turns it into a one-click action button in the Onboarding tab.
6
+ - Updated `devsurface init` to generate a richer config with grouped commands (First-time setup, Daily development, Before committing) and actionable setup steps.
7
+ - Added plain-English explanations for every package script in the dashboard, so non-technical users can see what a command like `vite` or `tsc --noEmit` actually does before running it.
8
+
3
9
  ## 0.6.0
4
10
 
5
11
  - Added guided onboarding with a setup readiness score (0–100%) computed from scan and doctor results.
@@ -75,20 +75,37 @@ function toSetupGuide(value, warnings) {
75
75
  return void 0;
76
76
  }
77
77
  if (!Array.isArray(value)) {
78
- warnings.push("setupGuide must be an array of strings.");
78
+ warnings.push("setupGuide must be an array of strings or step objects.");
79
79
  return void 0;
80
80
  }
81
81
  const steps = [];
82
82
  for (const entry of value) {
83
- if (typeof entry !== "string") {
84
- warnings.push("setupGuide entries must be strings.");
85
- continue;
86
- }
87
- const trimmed = entry.trim();
88
- if (trimmed.length === 0) {
89
- continue;
83
+ if (typeof entry === "string") {
84
+ const trimmed = entry.trim();
85
+ if (trimmed.length > 0) {
86
+ steps.push(trimmed.slice(0, MAX_SETUP_GUIDE_STEP_LENGTH));
87
+ }
88
+ } else if (isRecord(entry)) {
89
+ if (typeof entry.title !== "string" || entry.title.trim().length === 0) {
90
+ warnings.push("setupGuide step objects must have a non-empty title string.");
91
+ continue;
92
+ }
93
+ const step = {
94
+ title: entry.title.trim().slice(0, MAX_SETUP_GUIDE_STEP_LENGTH)
95
+ };
96
+ if (typeof entry.description === "string" && entry.description.trim().length > 0) {
97
+ step.description = entry.description.trim().slice(0, MAX_SETUP_GUIDE_STEP_LENGTH);
98
+ }
99
+ if (typeof entry.command === "string" && entry.command.trim().length > 0) {
100
+ step.command = entry.command.trim();
101
+ }
102
+ if (typeof entry.script === "string" && entry.script.trim().length > 0) {
103
+ step.script = entry.script.trim();
104
+ }
105
+ steps.push(step);
106
+ } else {
107
+ warnings.push("setupGuide entries must be strings or step objects.");
90
108
  }
91
- steps.push(trimmed.slice(0, MAX_SETUP_GUIDE_STEP_LENGTH));
92
109
  }
93
110
  if (steps.length > MAX_SETUP_GUIDE_STEPS) {
94
111
  warnings.push(`setupGuide may contain at most ${MAX_SETUP_GUIDE_STEPS} steps.`);
package/dist/cli/index.js CHANGED
@@ -56,15 +56,17 @@ var defaultConfig = {
56
56
  description: "Local developer control panel",
57
57
  commands: {
58
58
  install: "npm install",
59
+ migrate: "npm run db:migrate",
60
+ seed: "npm run db:seed",
59
61
  dev: "npm run dev",
60
62
  build: "npm run build",
61
63
  test: "npm test",
62
64
  lint: "npm run lint"
63
65
  },
64
66
  groups: {
65
- Setup: ["install"],
66
- Development: ["dev"],
67
- Quality: ["test", "lint"],
67
+ "First-time setup": ["install", "migrate", "seed"],
68
+ "Daily development": ["dev"],
69
+ "Before committing": ["test", "lint"],
68
70
  Build: ["build"]
69
71
  },
70
72
  ports: [3e3],
@@ -76,10 +78,23 @@ var defaultConfig = {
76
78
  docker: true
77
79
  },
78
80
  setupGuide: [
81
+ {
82
+ title: "Install dependencies",
83
+ description: "Run the package manager install to set up node_modules.",
84
+ command: "install"
85
+ },
79
86
  "Copy .env.example to .env",
80
- "Fill in required environment values",
81
- "Install dependencies",
82
- "Start the dev server"
87
+ "Fill in required environment values (DATABASE_URL, etc.)",
88
+ {
89
+ title: "Run database migrations",
90
+ description: "Apply the database schema to your local database.",
91
+ command: "migrate"
92
+ },
93
+ {
94
+ title: "Start the development server",
95
+ description: "Run the local dev server and open the app in a browser.",
96
+ command: "dev"
97
+ }
83
98
  ],
84
99
  docs: ""
85
100
  };
@@ -136,20 +151,37 @@ function toSetupGuide(value, warnings) {
136
151
  return void 0;
137
152
  }
138
153
  if (!Array.isArray(value)) {
139
- warnings.push("setupGuide must be an array of strings.");
154
+ warnings.push("setupGuide must be an array of strings or step objects.");
140
155
  return void 0;
141
156
  }
142
157
  const steps = [];
143
158
  for (const entry of value) {
144
- if (typeof entry !== "string") {
145
- warnings.push("setupGuide entries must be strings.");
146
- continue;
147
- }
148
- const trimmed = entry.trim();
149
- if (trimmed.length === 0) {
150
- continue;
159
+ if (typeof entry === "string") {
160
+ const trimmed = entry.trim();
161
+ if (trimmed.length > 0) {
162
+ steps.push(trimmed.slice(0, MAX_SETUP_GUIDE_STEP_LENGTH));
163
+ }
164
+ } else if (isRecord(entry)) {
165
+ if (typeof entry.title !== "string" || entry.title.trim().length === 0) {
166
+ warnings.push("setupGuide step objects must have a non-empty title string.");
167
+ continue;
168
+ }
169
+ const step = {
170
+ title: entry.title.trim().slice(0, MAX_SETUP_GUIDE_STEP_LENGTH)
171
+ };
172
+ if (typeof entry.description === "string" && entry.description.trim().length > 0) {
173
+ step.description = entry.description.trim().slice(0, MAX_SETUP_GUIDE_STEP_LENGTH);
174
+ }
175
+ if (typeof entry.command === "string" && entry.command.trim().length > 0) {
176
+ step.command = entry.command.trim();
177
+ }
178
+ if (typeof entry.script === "string" && entry.script.trim().length > 0) {
179
+ step.script = entry.script.trim();
180
+ }
181
+ steps.push(step);
182
+ } else {
183
+ warnings.push("setupGuide entries must be strings or step objects.");
151
184
  }
152
- steps.push(trimmed.slice(0, MAX_SETUP_GUIDE_STEP_LENGTH));
153
185
  }
154
186
  if (steps.length > MAX_SETUP_GUIDE_STEPS) {
155
187
  warnings.push(`setupGuide may contain at most ${MAX_SETUP_GUIDE_STEPS} steps.`);
@@ -1692,14 +1724,33 @@ function buildOnboardingPlan(scan, warnings) {
1692
1724
  blocking: false
1693
1725
  });
1694
1726
  }
1727
+ const allCommands = { ...scan.presetCommands, ...scan.config?.config.commands ?? {} };
1695
1728
  for (const [index, entry] of (scan.config?.config.setupGuide ?? []).entries()) {
1696
- steps.push({
1697
- id: `guide-${index}`,
1698
- title: entry,
1699
- description: "From the project setup guide.",
1700
- status: "manual",
1701
- blocking: false
1702
- });
1729
+ if (typeof entry === "string") {
1730
+ steps.push({
1731
+ id: `guide-${index}`,
1732
+ title: entry,
1733
+ description: "From the project setup guide.",
1734
+ status: "manual",
1735
+ blocking: false
1736
+ });
1737
+ } else {
1738
+ const step = entry;
1739
+ let action;
1740
+ if (step.command !== void 0 && step.command in allCommands) {
1741
+ action = { kind: "run-command", label: "Run", target: step.command };
1742
+ } else if (step.script !== void 0) {
1743
+ action = { kind: "run-script", label: "Run", target: step.script };
1744
+ }
1745
+ steps.push({
1746
+ id: `guide-${index}`,
1747
+ title: step.title,
1748
+ description: step.description ?? "From the project setup guide.",
1749
+ status: action !== void 0 ? "todo" : "manual",
1750
+ blocking: false,
1751
+ action
1752
+ });
1753
+ }
1703
1754
  }
1704
1755
  const docs = scan.config?.config.docs;
1705
1756
  if (typeof docs === "string" && docs.length > 0 && isSafeHttpUrl(docs)) {
@@ -2937,7 +2988,7 @@ import path16 from "path";
2937
2988
  import spawn4 from "cross-spawn";
2938
2989
 
2939
2990
  // src/version.ts
2940
- var DEV_SURFACE_VERSION = "0.6.0";
2991
+ var DEV_SURFACE_VERSION = "0.7.0";
2941
2992
 
2942
2993
  // src/server/localAccess.ts
2943
2994
  var LOCAL_HOSTNAMES = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1"]);