@woodsportal/hubspot-kit 1.0.42-dev.0 → 1.0.42-dev.2

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/dist/{chunk-WHYTQEZX.js → chunk-4UFWXPQG.js} +2 -2
  3. package/dist/{chunk-4GOJPOW3.js → chunk-GXYUGXF5.js} +82 -23
  4. package/dist/chunk-GXYUGXF5.js.map +1 -0
  5. package/dist/cli.js +61 -26
  6. package/dist/cli.js.map +1 -1
  7. package/dist/{exec-VY6BGWF3.js → exec-NS4GKXZS.js} +2 -2
  8. package/dist/{scaffold-page-lifecycle-EHMPWPPE.js → scaffold-page-lifecycle-53AWWGFR.js} +3 -3
  9. package/examples/greenfield/module-hybrid-cdn/README.md +2 -1
  10. package/examples/greenfield/module-hybrid-cdn-auth-full/README.md +2 -1
  11. package/examples/greenfield/module-hybrid-cdn-auth-full/src/features/auth/components/starter-login.tsx +2 -6
  12. package/examples/greenfield/module-hybrid-cdn-auth-full/src/features/auth/sso-callback.ts +6 -0
  13. package/examples/greenfield/module-hybrid-cdn-auth-sso/README.md +2 -1
  14. package/examples/greenfield/module-hybrid-cdn-auth-sso/src/features/auth/sso-callback.ts +6 -0
  15. package/examples/greenfield/module-hybrid-cdn-auth-starter/README.md +2 -1
  16. package/examples/greenfield/module-hybrid-cdn-auth-starter-sidebar/README.md +2 -1
  17. package/package.json +3 -2
  18. package/scripts/build-cdn.mjs +6 -5
  19. package/scripts/dist-cli-pack-smoke.test.mjs +79 -0
  20. package/scripts/ensure-wphs-workspace.mjs +7 -2
  21. package/scripts/resolve-hubspot-cli.mjs +51 -0
  22. package/scripts/resolve-vite-config.mjs +2 -3
  23. package/scripts/resolve-vite-spawn.mjs +48 -0
  24. package/scripts/run-vite-build.mjs +5 -6
  25. package/scripts/watch-hubspot.mjs +11 -13
  26. package/templates/module-hybrid-cdn/README.md +2 -1
  27. package/templates/module-monolith/README.md +2 -1
  28. package/templates/scaffold/auth/_full/src/features/auth/components/starter-login.tsx +79 -0
  29. package/templates/scaffold/auth/_shared/src/app.tsx +8 -3
  30. package/templates/scaffold/auth/_shared/src/features/auth/components/starter-login.tsx +10 -3
  31. package/templates/scaffold/auth/_shared/src/integrations/woodsportal-sdk.ts +1 -0
  32. package/templates/scaffold/auth/_sso/src/features/auth/components/starter-login.tsx +10 -3
  33. package/templates/scaffold/auth/_sso/src/features/auth/sso-callback.ts +6 -0
  34. package/dist/chunk-4GOJPOW3.js.map +0 -1
  35. package/dist/ensure-wphs-workspace-5S3GTO6K.js +0 -234
  36. package/dist/ensure-wphs-workspace-5S3GTO6K.js.map +0 -1
  37. /package/dist/{chunk-WHYTQEZX.js.map → chunk-4UFWXPQG.js.map} +0 -0
  38. /package/dist/{exec-VY6BGWF3.js.map → exec-NS4GKXZS.js.map} +0 -0
  39. /package/dist/{scaffold-page-lifecycle-EHMPWPPE.js.map → scaffold-page-lifecycle-53AWWGFR.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -3,7 +3,9 @@
3
3
  ## Unreleased
4
4
 
5
5
  ### Portal auth scaffold
6
- - **`wp init --auth`** — tiered portal login scaffold: `none` \| `starter` (email/password) \| `sso` \| `full` (SSO + MFA)
6
+ - **`wp init --auth full`** — fix `starter-login` importing `MFA_REQUIRED_SCAFFOLD_MESSAGE` after full-tier `login-session-bridge` merge; add full-tier `starter-login` layer
7
+ - **SSO callback** — export `clearLegacySsoCallbackInFlight` in auth scaffold (`mount-portal` boot)
8
+ - **`wp init` hint** — Getting started uses `npm install` (not `yarn install`); template READMEs aligned
7
9
  - **Interactive `wp init` wizard** — sequential prompts: type → name → router → auth → CDN → confirm
8
10
  - **`templates/scaffold/auth/`** — layered `_shared`, `_sso`, `_full` files merged at init; `woodscli.json` records `scaffold.auth`
9
11
  - **Greenfield examples** — `examples/greenfield/module-hybrid-cdn-auth-{starter,sso,full}`
@@ -30,9 +32,13 @@
30
32
  - **`wp doctor`** — CSS pipeline checks (prefix, `.temp` @source, `skipRuntimeCss`, `module.css` dw utilities, CDN `require_css` warning)
31
33
 
32
34
  ### Windows / fresh init
35
+ - **`wp init` crash** — load unbundled `scripts/ensure-wphs-workspace.mjs` at runtime (fixes tsup double-shebang `Invalid or unexpected token` in published `wp`)
33
36
  - **`wp doctor`** — scaffold `.wphs/` in-process (no swallowed subprocess); surface `wphs-scaffold` errors; re-run ensure before layout checks
34
37
  - **CLI exit** — deferred `process.exit` after @clack spinners (fixes libuv `UV_HANDLE_CLOSING` crash on Windows)
35
38
  - **`wp doctor` severity** — HubSpot CLI missing and placeholder `portal.cdn.json` github slug are warnings (local `wp dev` still works); hard errors remain for real CDN misconfigurations
39
+ - **HubSpot CLI spawn** — resolve `hs.cmd` / shell fallback on Windows (`wp auth`, `upload`, `watch`, `portal use`, doctor checks)
40
+ - **CDN build** — `build-cdn.mjs` / `run-vite-build.mjs` use cross-platform Vite spawn (no hardcoded `yarn`)
41
+ - **CI** — `windows-latest` verify job + packed `dist/cli.js` doctor smoke
36
42
  - **Docs** — Windows notes in [TROUBLESHOOTING.md](./docs/TROUBLESHOOTING.md)
37
43
 
38
44
  ## 1.0.39 — 2026-06-08
@@ -3,7 +3,7 @@ import {
3
3
  ExitCode,
4
4
  WpHsError,
5
5
  runCommand
6
- } from "./chunk-4GOJPOW3.js";
6
+ } from "./chunk-GXYUGXF5.js";
7
7
 
8
8
  // src/schema/woodsportal-hs.ts
9
9
  import { z } from "zod";
@@ -551,4 +551,4 @@ export {
551
551
  normalizePagePath,
552
552
  scaffoldPage
553
553
  };
554
- //# sourceMappingURL=chunk-WHYTQEZX.js.map
554
+ //# sourceMappingURL=chunk-4UFWXPQG.js.map
@@ -83,6 +83,52 @@ function isWpHsError(error) {
83
83
  return error instanceof WpHsError;
84
84
  }
85
85
 
86
+ // src/lib/resolve-external-cli.ts
87
+ import { existsSync } from "fs";
88
+ import { platform } from "os";
89
+ import { resolve } from "path";
90
+ function resolveBin(name, projectRoot) {
91
+ const roots = projectRoot ? [projectRoot] : [];
92
+ if (!roots.includes(process.cwd())) {
93
+ roots.push(process.cwd());
94
+ }
95
+ for (const root of roots) {
96
+ const binDir = resolve(root, "node_modules", ".bin");
97
+ if (platform() === "win32") {
98
+ const cmd = resolve(binDir, `${name}.cmd`);
99
+ if (existsSync(cmd)) {
100
+ return { command: cmd, prefixArgs: [] };
101
+ }
102
+ }
103
+ const shim = resolve(binDir, name);
104
+ if (existsSync(shim)) {
105
+ return { command: shim, prefixArgs: [] };
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+ function resolveHubSpotCliSpawn(projectRoot) {
111
+ const local = resolveBin("hs", projectRoot);
112
+ if (local) {
113
+ return local;
114
+ }
115
+ if (platform() === "win32") {
116
+ return { command: "hs", prefixArgs: [], shell: true };
117
+ }
118
+ return { command: "hs", prefixArgs: [] };
119
+ }
120
+ function applyExternalCliSpawn(command, args, options) {
121
+ if (command === "hs") {
122
+ const spawn2 = resolveHubSpotCliSpawn(options.projectRoot ?? options.cwd);
123
+ return {
124
+ command: spawn2.command,
125
+ args: [...spawn2.prefixArgs, ...args],
126
+ shell: spawn2.shell
127
+ };
128
+ }
129
+ return { command, args };
130
+ }
131
+
86
132
  // src/lib/exec.ts
87
133
  var SECRET_PATTERN = /(token|secret|password|pat|key)=/i;
88
134
  function logExec(logger, command, args, options) {
@@ -98,29 +144,35 @@ function runCommand(command, args, options) {
98
144
  logger?.info(`[dry-run] ${formatExecDebugLine(command, args, cwd, env, options.projectRoot)}`);
99
145
  return { status: 0, stdout: "", stderr: "" };
100
146
  }
101
- logExec(logger, command, args, options);
147
+ const resolved = applyExternalCliSpawn(command, args, {
148
+ projectRoot: options.projectRoot,
149
+ cwd
150
+ });
151
+ logExec(logger, resolved.command, resolved.args, options);
102
152
  if (streamOutput) {
103
- const result2 = spawnSync(command, args, {
153
+ const result2 = spawnSync(resolved.command, resolved.args, {
104
154
  cwd,
105
155
  env,
106
156
  encoding: "utf8",
107
- stdio: "inherit"
157
+ stdio: "inherit",
158
+ shell: resolved.shell
108
159
  });
109
160
  const status2 = result2.status ?? 1;
110
- throwOnBadExit(command, args, status2, "", "", okCodes);
161
+ throwOnBadExit(resolved.command, resolved.args, status2, "", "", okCodes);
111
162
  return { status: status2, stdout: "", stderr: "" };
112
163
  }
113
164
  const spawnOpts = {
114
165
  cwd,
115
166
  env,
116
167
  encoding: "utf8",
117
- stdio: ["inherit", "pipe", "pipe"]
168
+ stdio: ["inherit", "pipe", "pipe"],
169
+ shell: resolved.shell
118
170
  };
119
- const result = spawnSync(command, args, spawnOpts);
171
+ const result = spawnSync(resolved.command, resolved.args, spawnOpts);
120
172
  const status = result.status ?? 1;
121
173
  const stdout = typeof result.stdout === "string" ? result.stdout : "";
122
174
  const stderr = typeof result.stderr === "string" ? result.stderr : "";
123
- throwOnBadExit(command, args, status, stdout, stderr, okCodes);
175
+ throwOnBadExit(resolved.command, resolved.args, status, stdout, stderr, okCodes);
124
176
  return { status, stdout, stderr };
125
177
  }
126
178
  function runNodeScript(scriptPath, args, options) {
@@ -148,13 +200,18 @@ function runCommandAsync(command, args, options) {
148
200
  logger?.info(`[dry-run] ${formatExecDebugLine(command, args, cwd, env, options.projectRoot)}`);
149
201
  return Promise.resolve({ status: 0, stdout: "", stderr: "" });
150
202
  }
151
- logExec(logger, command, args, options);
203
+ const resolved = applyExternalCliSpawn(command, args, {
204
+ projectRoot: options.projectRoot,
205
+ cwd
206
+ });
207
+ logExec(logger, resolved.command, resolved.args, options);
152
208
  if (streamOutput) {
153
- return new Promise((resolve, reject) => {
154
- const child = spawn(command, args, {
209
+ return new Promise((resolve2, reject) => {
210
+ const child = spawn(resolved.command, resolved.args, {
155
211
  cwd,
156
212
  env,
157
- stdio: "inherit"
213
+ stdio: "inherit",
214
+ shell: resolved.shell
158
215
  });
159
216
  child.on("error", (error) => {
160
217
  reject(error);
@@ -162,19 +219,20 @@ function runCommandAsync(command, args, options) {
162
219
  child.on("close", (code) => {
163
220
  const status = code ?? 1;
164
221
  try {
165
- throwOnBadExit(command, args, status, "", "", okCodes);
166
- resolve({ status, stdout: "", stderr: "" });
222
+ throwOnBadExit(resolved.command, resolved.args, status, "", "", okCodes);
223
+ resolve2({ status, stdout: "", stderr: "" });
167
224
  } catch (error) {
168
225
  reject(error);
169
226
  }
170
227
  });
171
228
  });
172
229
  }
173
- return new Promise((resolve, reject) => {
174
- const child = spawn(command, args, {
230
+ return new Promise((resolve2, reject) => {
231
+ const child = spawn(resolved.command, resolved.args, {
175
232
  cwd,
176
233
  env,
177
- stdio: ["inherit", "pipe", "pipe"]
234
+ stdio: ["inherit", "pipe", "pipe"],
235
+ shell: resolved.shell
178
236
  });
179
237
  let stdout = "";
180
238
  let stderr = "";
@@ -192,8 +250,8 @@ function runCommandAsync(command, args, options) {
192
250
  child.on("close", (code) => {
193
251
  const status = code ?? 1;
194
252
  try {
195
- throwOnBadExit(command, args, status, stdout, stderr, okCodes);
196
- resolve({ status, stdout, stderr });
253
+ throwOnBadExit(resolved.command, resolved.args, status, stdout, stderr, okCodes);
254
+ resolve2({ status, stdout, stderr });
197
255
  } catch (error) {
198
256
  reject(error);
199
257
  }
@@ -211,7 +269,7 @@ function runNodeScriptLongRunning(scriptPath, args, options) {
211
269
  );
212
270
  return Promise.resolve(0);
213
271
  }
214
- return new Promise((resolve, reject) => {
272
+ return new Promise((resolve2, reject) => {
215
273
  const child = spawn(process.execPath, [scriptPath, ...args], {
216
274
  cwd,
217
275
  env,
@@ -233,14 +291,14 @@ function runNodeScriptLongRunning(scriptPath, args, options) {
233
291
  process.off("SIGINT", forwardSignal);
234
292
  process.off("SIGTERM", forwardSignal);
235
293
  if (signal === "SIGINT") {
236
- resolve(130);
294
+ resolve2(130);
237
295
  return;
238
296
  }
239
297
  if (signal === "SIGTERM") {
240
- resolve(143);
298
+ resolve2(143);
241
299
  return;
242
300
  }
243
- resolve(code ?? 1);
301
+ resolve2(code ?? 1);
244
302
  });
245
303
  });
246
304
  }
@@ -249,10 +307,11 @@ export {
249
307
  ExitCode,
250
308
  WpHsError,
251
309
  isWpHsError,
310
+ resolveHubSpotCliSpawn,
252
311
  runCommand,
253
312
  runNodeScript,
254
313
  runCommandAsync,
255
314
  runNodeScriptAsync,
256
315
  runNodeScriptLongRunning
257
316
  };
258
- //# sourceMappingURL=chunk-4GOJPOW3.js.map
317
+ //# sourceMappingURL=chunk-GXYUGXF5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/exec.ts","../src/lib/exec-debug.ts","../src/lib/errors.ts","../src/lib/resolve-external-cli.ts"],"sourcesContent":["import { spawn, spawnSync, type SpawnSyncOptions } from 'node:child_process'\n\nimport { formatExecDebugLine } from './exec-debug.js'\nimport { WpHsError, ExitCode } from './errors.js'\nimport { applyExternalCliSpawn } from './resolve-external-cli.js'\nimport type { Logger } from './logger.js'\n\nconst SECRET_PATTERN = /(token|secret|password|pat|key)=/i\n\nexport type RunOptions = {\n cwd: string\n env?: NodeJS.ProcessEnv\n logger?: Logger\n dryRun?: boolean\n timeoutMs?: number\n /** Expected exit code on success (default 0) */\n okCodes?: number[]\n /** Stream child stdout/stderr to the terminal (verbose mode). */\n streamOutput?: boolean\n /** Shorten cwd paths in debug logs. */\n projectRoot?: string\n}\n\nfunction logExec(logger: Logger | undefined, command: string, args: string[], options: RunOptions): void {\n if (!logger) return\n const env = options.env ?? process.env\n logger.debug(\n formatExecDebugLine(command, args, options.cwd, env, options.projectRoot),\n )\n}\n\nexport function runCommand(\n command: string,\n args: string[],\n options: RunOptions,\n): { status: number; stdout: string; stderr: string } {\n const { cwd, env = process.env, logger, dryRun = false, okCodes = [0], streamOutput = false } =\n options\n\n if (dryRun) {\n logger?.info(`[dry-run] ${formatExecDebugLine(command, args, cwd, env, options.projectRoot)}`)\n return { status: 0, stdout: '', stderr: '' }\n }\n\n const resolved = applyExternalCliSpawn(command, args, {\n projectRoot: options.projectRoot,\n cwd,\n })\n\n logExec(logger, resolved.command, resolved.args, options)\n\n if (streamOutput) {\n const result = spawnSync(resolved.command, resolved.args, {\n cwd,\n env,\n encoding: 'utf8',\n stdio: 'inherit',\n shell: resolved.shell,\n })\n const status = result.status ?? 1\n throwOnBadExit(resolved.command, resolved.args, status, '', '', okCodes)\n return { status, stdout: '', stderr: '' }\n }\n\n const spawnOpts: SpawnSyncOptions = {\n cwd,\n env,\n encoding: 'utf8',\n stdio: ['inherit', 'pipe', 'pipe'],\n shell: resolved.shell,\n }\n\n const result = spawnSync(resolved.command, resolved.args, spawnOpts)\n const status = result.status ?? 1\n const stdout = typeof result.stdout === 'string' ? result.stdout : ''\n const stderr = typeof result.stderr === 'string' ? result.stderr : ''\n\n throwOnBadExit(resolved.command, resolved.args, status, stdout, stderr, okCodes)\n\n return { status, stdout, stderr }\n}\n\nexport function runNodeScript(\n scriptPath: string,\n args: string[],\n options: RunOptions,\n): void {\n runCommand(process.execPath, [scriptPath, ...args], options)\n}\n\nfunction throwOnBadExit(\n command: string,\n args: string[],\n status: number,\n stdout: string,\n stderr: string,\n okCodes: number[],\n): void {\n if (okCodes.includes(status)) {\n return\n }\n const detail = stderr.trim() || stdout.trim() || `exit ${status}`\n if (SECRET_PATTERN.test(detail)) {\n throw new WpHsError(`Command failed: ${command}`, {\n exitCode: ExitCode.USER_ERROR,\n remediation: 'Re-run with --verbose for details (secrets are never logged).',\n })\n }\n throw new WpHsError(`Command failed: ${command} ${args.join(' ')}\\n${detail}`, {\n exitCode: ExitCode.USER_ERROR,\n })\n}\n\n/**\n * Non-blocking spawn — keeps the Node event loop alive so @clack spinners animate.\n */\nexport function runCommandAsync(\n command: string,\n args: string[],\n options: RunOptions,\n): Promise<{ status: number; stdout: string; stderr: string }> {\n const { cwd, env = process.env, logger, dryRun = false, okCodes = [0], streamOutput = false } =\n options\n\n if (dryRun) {\n logger?.info(`[dry-run] ${formatExecDebugLine(command, args, cwd, env, options.projectRoot)}`)\n return Promise.resolve({ status: 0, stdout: '', stderr: '' })\n }\n\n const resolved = applyExternalCliSpawn(command, args, {\n projectRoot: options.projectRoot,\n cwd,\n })\n\n logExec(logger, resolved.command, resolved.args, options)\n\n if (streamOutput) {\n return new Promise((resolve, reject) => {\n const child = spawn(resolved.command, resolved.args, {\n cwd,\n env,\n stdio: 'inherit',\n shell: resolved.shell,\n })\n\n child.on('error', (error) => {\n reject(error)\n })\n\n child.on('close', (code) => {\n const status = code ?? 1\n try {\n throwOnBadExit(resolved.command, resolved.args, status, '', '', okCodes)\n resolve({ status, stdout: '', stderr: '' })\n } catch (error) {\n reject(error)\n }\n })\n })\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn(resolved.command, resolved.args, {\n cwd,\n env,\n stdio: ['inherit', 'pipe', 'pipe'],\n shell: resolved.shell,\n })\n\n let stdout = ''\n let stderr = ''\n\n child.stdout?.setEncoding('utf8')\n child.stderr?.setEncoding('utf8')\n child.stdout?.on('data', (chunk: string) => {\n stdout += chunk\n })\n child.stderr?.on('data', (chunk: string) => {\n stderr += chunk\n })\n\n child.on('error', (error) => {\n reject(error)\n })\n\n child.on('close', (code) => {\n const status = code ?? 1\n try {\n throwOnBadExit(resolved.command, resolved.args, status, stdout, stderr, okCodes)\n resolve({ status, stdout, stderr })\n } catch (error) {\n reject(error)\n }\n })\n })\n}\n\nexport function runNodeScriptAsync(\n scriptPath: string,\n args: string[],\n options: RunOptions,\n): Promise<void> {\n return runCommandAsync(process.execPath, [scriptPath, ...args], options).then(() => undefined)\n}\n\n/**\n * Spawn a Node script with inherited stdio and forward SIGINT/SIGTERM (wp watch, long-running tools).\n * Unlike spawnSync, the parent event loop stays alive so Ctrl+C works while the child runs.\n */\nexport function runNodeScriptLongRunning(\n scriptPath: string,\n args: string[],\n options: RunOptions,\n): Promise<number> {\n const { cwd, env = process.env, logger, dryRun = false } = options\n\n if (dryRun) {\n logger?.info(\n `[dry-run] ${formatExecDebugLine(process.execPath, [scriptPath, ...args], cwd, env, options.projectRoot)}`,\n )\n return Promise.resolve(0)\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn(process.execPath, [scriptPath, ...args], {\n cwd,\n env,\n stdio: 'inherit',\n })\n\n const forwardSignal = (signal: NodeJS.Signals) => {\n if (!child.killed) {\n child.kill(signal)\n }\n }\n\n process.on('SIGINT', forwardSignal)\n process.on('SIGTERM', forwardSignal)\n\n child.on('error', (error) => {\n process.off('SIGINT', forwardSignal)\n process.off('SIGTERM', forwardSignal)\n reject(error)\n })\n\n child.on('exit', (code, signal) => {\n process.off('SIGINT', forwardSignal)\n process.off('SIGTERM', forwardSignal)\n\n if (signal === 'SIGINT') {\n resolve(130)\n return\n }\n if (signal === 'SIGTERM') {\n resolve(143)\n return\n }\n\n resolve(code ?? 1)\n })\n })\n}\n","import { basename, relative } from 'node:path'\n\nconst SECRET_ENV_KEY =\n /(_KEY|_TOKEN|_SECRET|_PASSWORD|_PAT|AUTH|CREDENTIAL|GITHUB|NPM_|ERASER|LINEAR|AWS_|SSH_)/i\n\nconst RELEVANT_ENV_PREFIX = /^WP_HS_|^WP_/\n\nexport function isSecretEnvKey(key: string): boolean {\n return SECRET_ENV_KEY.test(key)\n}\n\nexport function maskEnvForLog(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const masked: NodeJS.ProcessEnv = {}\n for (const [key, value] of Object.entries(env)) {\n if (value === undefined) continue\n masked[key] = isSecretEnvKey(key) ? '[redacted]' : value\n }\n return masked\n}\n\nexport function formatRelevantEnv(env: NodeJS.ProcessEnv): string | undefined {\n const pairs = Object.entries(env)\n .filter(([key, value]) => value !== undefined && RELEVANT_ENV_PREFIX.test(key))\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => {\n const shown = isSecretEnvKey(key) ? '[redacted]' : value\n return `${key}=${shown}`\n })\n\n return pairs.length > 0 ? pairs.join(' ') : undefined\n}\n\nfunction shortenScriptPath(scriptPath: string): string {\n const marker = '/scripts/'\n const idx = scriptPath.lastIndexOf(marker)\n if (idx >= 0) {\n return `scripts/${scriptPath.slice(idx + marker.length)}`\n }\n return basename(scriptPath)\n}\n\nexport function formatExecCommand(command: string, args: string[]): string {\n if (command === process.execPath && args.length > 0) {\n const rest = args.slice(1).join(' ')\n return `node ${shortenScriptPath(args[0])}${rest ? ` ${rest}` : ''}`\n }\n return [command, ...args].join(' ')\n}\n\nexport function formatExecCwd(cwd: string, projectRoot?: string): string {\n if (projectRoot) {\n try {\n const rel = relative(projectRoot, cwd)\n if (!rel.startsWith('..')) {\n return rel === '' ? '.' : rel\n }\n } catch {\n // fall through\n }\n }\n const parts = cwd.split('/')\n if (parts.length > 3) {\n return `…/${parts.slice(-2).join('/')}`\n }\n return cwd\n}\n\n/** One-line verbose exec label for developers (no full env dump). */\nexport function formatExecDebugLine(\n command: string,\n args: string[],\n cwd: string,\n env: NodeJS.ProcessEnv,\n projectRoot?: string,\n): string {\n const cmd = formatExecCommand(command, args)\n const cwdLabel = formatExecCwd(cwd, projectRoot)\n const envLabel = formatRelevantEnv(env)\n const parts = [cmd, `cwd=${cwdLabel}`]\n if (envLabel) {\n parts.push(envLabel)\n }\n return parts.join(' ')\n}\n","export const ExitCode = {\n SUCCESS: 0,\n USER_ERROR: 1,\n PREREQUISITE: 2,\n BUILD_FAILED: 3,\n PUBLISH_FAILED: 4,\n AUDIT_FAILED: 5,\n INTERNAL: 10,\n} as const\n\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode]\n\nexport class WpHsError extends Error {\n readonly exitCode: ExitCodeValue\n readonly remediation?: string\n\n constructor(\n message: string,\n options: { exitCode?: ExitCodeValue; remediation?: string; cause?: unknown } = {},\n ) {\n super(message, { cause: options.cause })\n this.name = 'WpHsError'\n this.exitCode = options.exitCode ?? ExitCode.USER_ERROR\n this.remediation = options.remediation\n }\n}\n\nexport function isWpHsError(error: unknown): error is WpHsError {\n return error instanceof WpHsError\n}\n","import { existsSync } from 'node:fs'\nimport { platform } from 'node:os'\nimport { resolve } from 'node:path'\n\nexport type ExternalCliSpawn = {\n command: string\n prefixArgs: string[]\n shell?: boolean\n}\n\nfunction resolveBin(name: string, projectRoot?: string): ExternalCliSpawn | null {\n const roots = projectRoot ? [projectRoot] : []\n if (!roots.includes(process.cwd())) {\n roots.push(process.cwd())\n }\n\n for (const root of roots) {\n const binDir = resolve(root, 'node_modules', '.bin')\n if (platform() === 'win32') {\n const cmd = resolve(binDir, `${name}.cmd`)\n if (existsSync(cmd)) {\n return { command: cmd, prefixArgs: [] }\n }\n }\n const shim = resolve(binDir, name)\n if (existsSync(shim)) {\n return { command: shim, prefixArgs: [] }\n }\n }\n\n return null\n}\n\n/** Resolve HubSpot CLI (`hs`) for cross-platform spawn (Windows `.cmd` shims). */\nexport function resolveHubSpotCliSpawn(projectRoot?: string): ExternalCliSpawn {\n const local = resolveBin('hs', projectRoot)\n if (local) {\n return local\n }\n\n if (platform() === 'win32') {\n return { command: 'hs', prefixArgs: [], shell: true }\n }\n\n return { command: 'hs', prefixArgs: [] }\n}\n\n/** Resolve consumer `wp` binary for watch rebuild subprocesses. */\nexport function resolveWpBinSpawn(projectRoot: string, kitCliPath?: string): ExternalCliSpawn {\n if (kitCliPath && existsSync(kitCliPath)) {\n return { command: process.execPath, prefixArgs: [kitCliPath] }\n }\n\n const local = resolveBin('wp', projectRoot)\n if (local) {\n return local\n }\n\n if (platform() === 'win32') {\n return { command: 'wp', prefixArgs: [], shell: true }\n }\n\n return { command: 'wp', prefixArgs: [] }\n}\n\nexport function applyExternalCliSpawn(\n command: string,\n args: string[],\n options: { projectRoot?: string; cwd?: string },\n): { command: string; args: string[]; shell?: boolean } {\n if (command === 'hs') {\n const spawn = resolveHubSpotCliSpawn(options.projectRoot ?? options.cwd)\n return {\n command: spawn.command,\n args: [...spawn.prefixArgs, ...args],\n shell: spawn.shell,\n }\n }\n\n return { command, args }\n}\n"],"mappings":"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","names":["spawn","result","status","resolve"]}
package/dist/cli.js CHANGED
@@ -19,16 +19,17 @@ import {
19
19
  scaffoldPage,
20
20
  titleFromSlug,
21
21
  usesCdnPipeline
22
- } from "./chunk-WHYTQEZX.js";
22
+ } from "./chunk-4UFWXPQG.js";
23
23
  import {
24
24
  ExitCode,
25
25
  WpHsError,
26
26
  isWpHsError,
27
+ resolveHubSpotCliSpawn,
27
28
  runCommand,
28
29
  runCommandAsync,
29
30
  runNodeScriptAsync,
30
31
  runNodeScriptLongRunning
31
- } from "./chunk-4GOJPOW3.js";
32
+ } from "./chunk-GXYUGXF5.js";
32
33
 
33
34
  // src/cli/program.ts
34
35
  import { Command } from "commander";
@@ -391,12 +392,14 @@ var PLACEHOLDER_PATTERNS = [
391
392
  /portalId:\s*12345678\b/
392
393
  ];
393
394
  function spawnHs(args, options = {}) {
394
- return spawnSync("hs", args, {
395
+ const spawn = resolveHubSpotCliSpawn(options.cwd);
396
+ return spawnSync(spawn.command, [...spawn.prefixArgs, ...args], {
395
397
  cwd: options.cwd,
396
398
  encoding: "utf8",
397
399
  timeout: options.timeoutMs ?? HS_ACCOUNTS_TIMEOUT_MS,
398
400
  // Keep HubSpot CLI off the interactive TTY (avoids hangs under @clack spinners)
399
- stdio: ["ignore", "pipe", "pipe"]
401
+ stdio: ["ignore", "pipe", "pipe"],
402
+ shell: spawn.shell
400
403
  });
401
404
  }
402
405
  function hsTimedOut(result) {
@@ -749,13 +752,20 @@ function formatCdnSetupNote(_projectRoot) {
749
752
  }
750
753
 
751
754
  // src/lib/wphs-workspace.ts
755
+ import { pathToFileURL } from "url";
752
756
  var ensureModulePromise;
757
+ function ensureScriptUrl() {
758
+ return pathToFileURL(kitPath("scripts", "ensure-wphs-workspace.mjs")).href;
759
+ }
753
760
  function loadEnsureModule() {
754
761
  if (!ensureModulePromise) {
755
- ensureModulePromise = Promise.resolve().then(async () => {
756
- const mod = await import("./ensure-wphs-workspace-5S3GTO6K.js");
757
- return mod;
758
- });
762
+ const scriptUrl = ensureScriptUrl();
763
+ ensureModulePromise = import(
764
+ /* webpackIgnore: true */
765
+ scriptUrl
766
+ ).then(
767
+ (mod) => mod
768
+ );
759
769
  }
760
770
  return ensureModulePromise;
761
771
  }
@@ -2677,7 +2687,7 @@ async function runAuditSecrets(ctx) {
2677
2687
 
2678
2688
  // src/cli/commands/init.ts
2679
2689
  import { cpSync as cpSync3, existsSync as existsSync13, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
2680
- import { basename as basename2, resolve as resolve17 } from "path";
2690
+ import { basename as basename3, resolve as resolve17 } from "path";
2681
2691
  import * as p5 from "@clack/prompts";
2682
2692
 
2683
2693
  // src/lib/init-router-scaffold.ts
@@ -2948,6 +2958,7 @@ function patchStarterOnlyBlocks(targetDir, mode) {
2948
2958
  let content = readFileSync11(filePath, "utf8");
2949
2959
  content = stripMarkedBlock(content, "WPHS_AUTH_SSO", hasSso);
2950
2960
  content = stripMarkedBlock(content, "WPHS_AUTH_FULL", hasFull);
2961
+ content = stripMarkedBlock(content, "WPHS_AUTH_NOT_FULL", !hasFull);
2951
2962
  if (!hasFull && relative === "src/integrations/configure-woodsportal-sdk.ts") {
2952
2963
  content = content.replace(
2953
2964
  /^import \{ isMfaPendingSession \} from '@\/features\/auth\/auth-session'\n/m,
@@ -3033,6 +3044,21 @@ function assertFullTierAuthScaffold(targetDir) {
3033
3044
  exitCode: ExitCode.INTERNAL
3034
3045
  });
3035
3046
  }
3047
+ const starterLoginPath = resolve15(targetDir, "src/features/auth/components/starter-login.tsx");
3048
+ if (existsSync11(starterLoginPath)) {
3049
+ const starterLogin = readFileSync11(starterLoginPath, "utf8");
3050
+ if (starterLogin.includes("WPHS_AUTH_")) {
3051
+ throw new WpHsError('Auth scaffold tier "full" left WPHS_AUTH_* markers in starter-login.tsx', {
3052
+ exitCode: ExitCode.INTERNAL
3053
+ });
3054
+ }
3055
+ if (starterLogin.includes("MFA_REQUIRED_SCAFFOLD_MESSAGE")) {
3056
+ throw new WpHsError(
3057
+ 'Auth scaffold tier "full" starter-login.tsx must not import MFA_REQUIRED_SCAFFOLD_MESSAGE',
3058
+ { exitCode: ExitCode.INTERNAL }
3059
+ );
3060
+ }
3061
+ }
3036
3062
  }
3037
3063
  function patchPackageJson(targetDir) {
3038
3064
  const pkgPath = resolve15(targetDir, "package.json");
@@ -3215,6 +3241,7 @@ function readProjectAuthTier(targetDir) {
3215
3241
 
3216
3242
  // src/lib/init-wizard.ts
3217
3243
  import * as p4 from "@clack/prompts";
3244
+ import { basename } from "path";
3218
3245
 
3219
3246
  // src/lib/project-name.ts
3220
3247
  var PROJECT_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
@@ -3280,7 +3307,7 @@ async function runInitWizard(options) {
3280
3307
  projectName = normalizeProjectName(nameAnswer);
3281
3308
  }
3282
3309
  if (!projectName && options.directory) {
3283
- projectName = normalizeProjectName(options.directory.split("/").pop() ?? "my-portal");
3310
+ projectName = normalizeProjectName(basename(options.directory) || "my-portal");
3284
3311
  }
3285
3312
  if (!projectName) {
3286
3313
  throw new WpHsError("Project name is required", {
@@ -3387,7 +3414,10 @@ async function runInitWizard(options) {
3387
3414
  `Auth: ${auth}`,
3388
3415
  ...auth !== "none" ? [`Nav: ${nav}`] : []
3389
3416
  ] : [],
3390
- ...template === "module-hybrid-cdn" ? [`CDN repo: ${cdnSetup?.github ?? "(skipped \u2014 configure later)"}`] : []
3417
+ ...template === "module-hybrid-cdn" ? [
3418
+ `CDN repo: ${cdnSetup?.github ?? "(skipped \u2014 configure later)"}`,
3419
+ ...cdnSetup?.github && /your-org|your-portal-cdn-mirror/i.test(cdnSetup.github) ? [" (placeholder \u2014 run wp setup before wp deploy)"] : []
3420
+ ] : []
3391
3421
  ].join("\n");
3392
3422
  p4.note(summary, "Scaffold summary");
3393
3423
  const confirmed = cancelIfNeeded(
@@ -3412,7 +3442,7 @@ async function runInitWizard(options) {
3412
3442
 
3413
3443
  // src/lib/project-setup.ts
3414
3444
  import { copyFileSync, existsSync as existsSync12, writeFileSync as writeFileSync7 } from "fs";
3415
- import { basename, resolve as resolve16 } from "path";
3445
+ import { basename as basename2, resolve as resolve16 } from "path";
3416
3446
  function envFileForTier2(tier) {
3417
3447
  return tier === "dev" ? ".env.dev" : tier === "stg" ? ".env.stg" : ".env.prod";
3418
3448
  }
@@ -3442,7 +3472,7 @@ function copyMissingFile(projectRoot, targetName, sourceCandidates, dryRun) {
3442
3472
  if (!dryRun) {
3443
3473
  copyFileSync(source, target);
3444
3474
  }
3445
- const from = basename(source);
3475
+ const from = basename2(source);
3446
3476
  return {
3447
3477
  action: "copied",
3448
3478
  path: targetName,
@@ -3723,7 +3753,7 @@ async function runInit(ctx, options) {
3723
3753
  });
3724
3754
  }
3725
3755
  const targetDir = resolveInitTargetDir(options, projectName);
3726
- const slug = projectName ?? basename2(targetDir);
3756
+ const slug = projectName ?? basename3(targetDir);
3727
3757
  assertTargetDirIsScaffoldable(targetDir);
3728
3758
  const templateDir = kitPath("templates", template);
3729
3759
  if (!existsSync13(templateDir)) {
@@ -3793,7 +3823,7 @@ ${toAppend}
3793
3823
  }
3794
3824
  if (!nonInteractive) {
3795
3825
  p5.log.success(`Scaffolded ${template} in ${targetDir}`);
3796
- p5.note(`cd ${slug} && yarn install && wp setup && wp doctor && wp dev`, "Getting started");
3826
+ p5.note(`cd ${slug} && npm install && wp setup && wp doctor && wp dev`, "Getting started");
3797
3827
  } else {
3798
3828
  ctx.logger.success(`Scaffolded ${template} in ${targetDir}`);
3799
3829
  }
@@ -3951,7 +3981,7 @@ async function runExamplesSmoke(ctx, options = {}) {
3951
3981
  const tier = options.tier ?? "static";
3952
3982
  const args = ["--tier", tier];
3953
3983
  if (options.scenario) args.push("--scenario", options.scenario);
3954
- const { runNodeScript } = await import("./exec-VY6BGWF3.js");
3984
+ const { runNodeScript } = await import("./exec-NS4GKXZS.js");
3955
3985
  runNodeScript(kitPath("examples", "smoke", "run-matrix.mjs"), args, {
3956
3986
  cwd: ctx.projectRoot,
3957
3987
  logger: ctx.logger,
@@ -4281,7 +4311,8 @@ async function runPortalUse(ctx, options = {}) {
4281
4311
  runCommand("hs", ["accounts", "use", portal.name], {
4282
4312
  cwd: ctx.projectRoot,
4283
4313
  logger: ctx.logger,
4284
- dryRun: false
4314
+ dryRun: false,
4315
+ projectRoot: ctx.projectRoot
4285
4316
  });
4286
4317
  if (!ctx.global.json && !ctx.global.quiet) {
4287
4318
  printCommandDone(ctx, `Default portal \u2192 ${portal.name}`);
@@ -4466,7 +4497,7 @@ async function runPageAdd(ctx, options) {
4466
4497
  return ExitCode.SUCCESS;
4467
4498
  }
4468
4499
  async function runPageList(ctx) {
4469
- const { listScaffoldedPages } = await import("./scaffold-page-lifecycle-EHMPWPPE.js");
4500
+ const { listScaffoldedPages } = await import("./scaffold-page-lifecycle-53AWWGFR.js");
4470
4501
  const pages = listScaffoldedPages(ctx.projectRoot, ctx.config);
4471
4502
  if (ctx.global.json) {
4472
4503
  ctx.logger.json({ pages });
@@ -4492,7 +4523,7 @@ async function runPageList(ctx) {
4492
4523
  return ExitCode.SUCCESS;
4493
4524
  }
4494
4525
  async function runPageRemove(ctx, options) {
4495
- const { removeScaffoldedPage } = await import("./scaffold-page-lifecycle-EHMPWPPE.js");
4526
+ const { removeScaffoldedPage } = await import("./scaffold-page-lifecycle-53AWWGFR.js");
4496
4527
  const result = removeScaffoldedPage({
4497
4528
  projectRoot: ctx.projectRoot,
4498
4529
  config: ctx.config,
@@ -4855,14 +4886,18 @@ function createProgram() {
4855
4886
  });
4856
4887
  program2.command("auth").description("Authenticate HubSpot CLI (hs auth)").action(async () => {
4857
4888
  const global = program2.opts();
4858
- const ctx = buildContext(global);
4859
- const { runCommand: runCommand2 } = await import("./exec-VY6BGWF3.js");
4860
- runCommand2("hs", ["auth"], {
4861
- cwd: ctx.projectRoot,
4862
- logger: ctx.logger,
4863
- dryRun: ctx.global.dryRun
4889
+ await handle(async () => {
4890
+ const ctx = buildContext(global);
4891
+ const { runCommand: runCommand2 } = await import("./exec-NS4GKXZS.js");
4892
+ runCommand2("hs", ["auth"], {
4893
+ cwd: ctx.projectRoot,
4894
+ logger: ctx.logger,
4895
+ dryRun: ctx.global.dryRun,
4896
+ projectRoot: ctx.projectRoot,
4897
+ streamOutput: true
4898
+ });
4899
+ return ExitCode.SUCCESS;
4864
4900
  });
4865
- process.exit(ExitCode.SUCCESS);
4866
4901
  });
4867
4902
  const portal = program2.command("portal").description("HubSpot default portal selection");
4868
4903
  portal.command("list").alias("ls").description("List portals from hubspot.config.yml").action(async () => {