create-interview-cockpit 0.8.0 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-interview-cockpit",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Scaffold a personal AI-powered interview prep cockpit",
5
5
  "type": "module",
6
6
  "bin": {
@@ -258,6 +258,12 @@ function isModuleFederationGeneratedPath(filePath: string): boolean {
258
258
  return /(^|\/)dist\//.test(filePath);
259
259
  }
260
260
 
261
+ function normalizeModuleFederationPreviewPath(input: string): string {
262
+ const trimmed = input.trim();
263
+ if (!trimmed) return "/";
264
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
265
+ }
266
+
261
267
  function getModuleFederationCommandRoots(
262
268
  files: Record<string, string>,
263
269
  ): string[] {
@@ -342,12 +348,15 @@ export default function CodeRunnerModal() {
342
348
  const [nxStarting, setNxStarting] = useState(false);
343
349
  const [nxError, setNxError] = useState<string | null>(null);
344
350
  const nxIframeRef = useRef<HTMLIFrameElement>(null);
351
+ const mfIframeRef = useRef<HTMLIFrameElement>(null);
345
352
  const [mfSandboxId, setMfSandboxId] = useState<string | null>(null);
346
353
  const [mfHostUrl, setMfHostUrl] = useState<string | null>(null);
347
354
  const [mfAppUrls, setMfAppUrls] = useState<Record<string, string>>({});
348
355
  const [mfStarting, setMfStarting] = useState(false);
349
356
  const [mfError, setMfError] = useState<string | null>(null);
350
357
  const [mfPreviewApp, setMfPreviewApp] = useState("host");
358
+ const [mfPreviewPath, setMfPreviewPath] = useState("/");
359
+ const [mfNavInput, setMfNavInput] = useState("/");
351
360
  const [mfConsoleOutput, setMfConsoleOutput] = useState<OutputLine[]>([]);
352
361
  const [mfConsoleCommand, setMfConsoleCommand] = useState("npm run build");
353
362
  const [mfConsoleCwd, setMfConsoleCwd] = useState("apps/host");
@@ -592,6 +601,8 @@ export default function CodeRunnerModal() {
592
601
  setServerCollapsed(true);
593
602
  setClientCollapsed(false);
594
603
  setMfPreviewApp("host");
604
+ setMfPreviewPath("/");
605
+ setMfNavInput("/");
595
606
  setMfConsoleCommand("npm run build");
596
607
  setMfConsoleCwd("apps/host");
597
608
  setMfConsoleOutput([]);
@@ -1158,6 +1169,8 @@ export default function CodeRunnerModal() {
1158
1169
  setMfPreviewApp(
1159
1170
  info.appUrls.host ? "host" : (Object.keys(info.appUrls)[0] ?? "host"),
1160
1171
  );
1172
+ setMfPreviewPath("/");
1173
+ setMfNavInput("/");
1161
1174
  setReactClientTab("preview");
1162
1175
  setServerCollapsed(true);
1163
1176
  setClientCollapsed(false);
@@ -1494,6 +1507,8 @@ export default function CodeRunnerModal() {
1494
1507
  setServerCollapsed(true);
1495
1508
  setClientCollapsed(false);
1496
1509
  setMfPreviewApp("host");
1510
+ setMfPreviewPath("/");
1511
+ setMfNavInput("/");
1497
1512
  setMfError(null);
1498
1513
  }
1499
1514
  if (ct === "module-federation") {
@@ -1757,6 +1772,16 @@ export default function CodeRunnerModal() {
1757
1772
  const moduleFederationGeneratedFileSet = new Set(
1758
1773
  moduleFederationGeneratedFiles,
1759
1774
  );
1775
+ const moduleFederationPreviewBaseUrl =
1776
+ mfAppUrls[mfPreviewApp] ?? mfHostUrl ?? "";
1777
+ const moduleFederationPreviewPath =
1778
+ normalizeModuleFederationPreviewPath(mfPreviewPath);
1779
+ const moduleFederationPreviewUrl = moduleFederationPreviewBaseUrl
1780
+ ? `${moduleFederationPreviewBaseUrl}${moduleFederationPreviewPath}`
1781
+ : "";
1782
+ const moduleFederationPreviewHostLabel = moduleFederationPreviewBaseUrl
1783
+ ? moduleFederationPreviewBaseUrl.replace(/^https?:\/\//, "")
1784
+ : "localhost";
1760
1785
  const visibleReactFiles =
1761
1786
  clientType === "module-federation"
1762
1787
  ? Array.from(
@@ -3230,7 +3255,7 @@ export default function CodeRunnerModal() {
3230
3255
  </div>
3231
3256
  )}
3232
3257
  {clientType === "module-federation" && (
3233
- <div className="flex items-center gap-1 px-2 py-1 bg-slate-800 border-b border-slate-700 shrink-0 overflow-x-auto">
3258
+ <div className="flex items-center gap-1 px-2 py-1 bg-slate-800 border-b border-slate-700 shrink-0 min-w-0">
3234
3259
  {Object.entries(mfAppUrls).map(([name, url]) => (
3235
3260
  <button
3236
3261
  key={name}
@@ -3246,11 +3271,69 @@ export default function CodeRunnerModal() {
3246
3271
  {name}
3247
3272
  </button>
3248
3273
  ))}
3249
- <div className="ml-auto text-[9px] font-mono text-slate-600 shrink-0">
3250
- {mfAppUrls[mfPreviewApp] ??
3251
- mfHostUrl ??
3252
- "Start webpack to preview"}
3253
- </div>
3274
+ <button
3275
+ type="button"
3276
+ onClick={() => {
3277
+ if (
3278
+ mfIframeRef.current &&
3279
+ moduleFederationPreviewUrl
3280
+ ) {
3281
+ mfIframeRef.current.src =
3282
+ moduleFederationPreviewUrl;
3283
+ }
3284
+ }}
3285
+ className="p-0.5 rounded text-slate-500 hover:text-slate-200 disabled:opacity-30 disabled:cursor-not-allowed transition-colors shrink-0"
3286
+ title="Refresh"
3287
+ disabled={!moduleFederationPreviewUrl}
3288
+ >
3289
+ <svg
3290
+ className="w-3 h-3"
3291
+ viewBox="0 0 16 16"
3292
+ fill="currentColor"
3293
+ >
3294
+ <path d="M13.65 2.35A8 8 0 1 0 15 8h-2a6 6 0 1 1-1.1-3.48L10 6h5V1l-1.35 1.35z" />
3295
+ </svg>
3296
+ </button>
3297
+ <form
3298
+ className="flex-1 flex items-center gap-1 bg-slate-900 border border-slate-600 rounded px-2 py-0.5 focus-within:border-cyan-500/60 transition-colors min-w-0"
3299
+ onSubmit={(e) => {
3300
+ e.preventDefault();
3301
+ const nextPath =
3302
+ normalizeModuleFederationPreviewPath(
3303
+ mfNavInput,
3304
+ );
3305
+ setMfPreviewPath(nextPath);
3306
+ setMfNavInput(nextPath);
3307
+ if (
3308
+ nextPath === moduleFederationPreviewPath &&
3309
+ mfIframeRef.current &&
3310
+ moduleFederationPreviewBaseUrl
3311
+ ) {
3312
+ mfIframeRef.current.src = `${moduleFederationPreviewBaseUrl}${nextPath}`;
3313
+ }
3314
+ }}
3315
+ >
3316
+ <span className="text-slate-600 text-[9px] font-mono select-none shrink-0">
3317
+ {moduleFederationPreviewHostLabel}
3318
+ </span>
3319
+ <input
3320
+ value={mfNavInput}
3321
+ onChange={(e) => setMfNavInput(e.target.value)}
3322
+ onFocus={(e) => e.target.select()}
3323
+ className="flex-1 bg-transparent text-[11px] font-mono text-slate-200 outline-none placeholder-slate-600 min-w-0"
3324
+ placeholder="/"
3325
+ spellCheck={false}
3326
+ />
3327
+ </form>
3328
+ {moduleFederationPreviewUrl ? (
3329
+ <span className="text-[9px] font-mono text-green-400 shrink-0">
3330
+ ● live
3331
+ </span>
3332
+ ) : (
3333
+ <span className="text-[9px] font-mono text-slate-600 shrink-0">
3334
+ Start webpack to preview
3335
+ </span>
3336
+ )}
3254
3337
  </div>
3255
3338
  )}
3256
3339
  {((clientType === "module-federation" && mfError) ||
@@ -3302,9 +3385,10 @@ export default function CodeRunnerModal() {
3302
3385
  {!mfStarting &&
3303
3386
  clientType === "module-federation" &&
3304
3387
  mfSandboxId &&
3305
- (mfAppUrls[mfPreviewApp] ?? mfHostUrl) && (
3388
+ moduleFederationPreviewUrl && (
3306
3389
  <iframe
3307
- src={mfAppUrls[mfPreviewApp] ?? mfHostUrl ?? ""}
3390
+ ref={mfIframeRef}
3391
+ src={moduleFederationPreviewUrl}
3308
3392
  className="flex-1 min-h-0 w-full border-0 bg-white"
3309
3393
  title="Webpack Module Federation Preview"
3310
3394
  />
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.6.0"
2
+ "version": "0.7.0"
3
3
  }