@mdfriday/foundry 26.3.6 → 26.3.8

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/cli.js CHANGED
@@ -118,6 +118,7 @@ var init_project_metadata = __esm({
118
118
  contentLinks;
119
119
  staticLink;
120
120
  fileLink;
121
+ baseURLStructure;
121
122
  constructor(data) {
122
123
  this.id = data.id;
123
124
  this.name = data.name;
@@ -129,6 +130,7 @@ var init_project_metadata = __esm({
129
130
  this.contentLinks = data.contentLinks || [];
130
131
  this.staticLink = data.staticLink || null;
131
132
  this.fileLink = data.fileLink || null;
133
+ this.baseURLStructure = data.baseURLStructure || null;
132
134
  }
133
135
  static create(data) {
134
136
  if (!data.id || !data.name) {
@@ -168,6 +170,9 @@ var init_project_metadata = __esm({
168
170
  if (this.fileLink) {
169
171
  result.fileLink = this.fileLink;
170
172
  }
173
+ if (this.baseURLStructure) {
174
+ result.baseURLStructure = this.baseURLStructure;
175
+ }
171
176
  return result;
172
177
  }
173
178
  };
@@ -1337,6 +1342,80 @@ var init_project = __esm({
1337
1342
  }
1338
1343
  return linkDirs;
1339
1344
  }
1345
+ // ============================================================================
1346
+ // baseURL Structure Management
1347
+ // ============================================================================
1348
+ /**
1349
+ * 获取 baseURL(从 Hugo config.json)
1350
+ */
1351
+ async getBaseURL() {
1352
+ const config = await this.loadConfig();
1353
+ return config.baseURL || "/";
1354
+ }
1355
+ /**
1356
+ * 设置 baseURL(更新 Hugo config.json)
1357
+ */
1358
+ async setBaseURL(baseURL) {
1359
+ const config = await this.loadConfig();
1360
+ config.baseURL = baseURL;
1361
+ const configPath = import_path2.default.join(this.projectPath, "config.json");
1362
+ await import_fs.promises.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
1363
+ this.config = config;
1364
+ }
1365
+ /**
1366
+ * 解析 baseURL 路径信息
1367
+ */
1368
+ parseBaseURLPath(baseURL) {
1369
+ let normalized = baseURL.trim();
1370
+ if (normalized.startsWith("/")) {
1371
+ normalized = normalized.slice(1);
1372
+ }
1373
+ if (normalized.endsWith("/")) {
1374
+ normalized = normalized.slice(0, -1);
1375
+ }
1376
+ if (normalized === "") {
1377
+ return {
1378
+ isRoot: true,
1379
+ pathParts: [],
1380
+ parentParts: [],
1381
+ finalDirName: "",
1382
+ relativeToPublic: "."
1383
+ };
1384
+ }
1385
+ const parts = normalized.split("/").filter((p2) => p2 !== "");
1386
+ if (parts.length === 0) {
1387
+ return {
1388
+ isRoot: true,
1389
+ pathParts: [],
1390
+ parentParts: [],
1391
+ finalDirName: "",
1392
+ relativeToPublic: "."
1393
+ };
1394
+ }
1395
+ const depth = parts.length;
1396
+ const relativeToPublic = depth === 1 ? "." : "../".repeat(depth - 1).slice(0, -1);
1397
+ return {
1398
+ isRoot: false,
1399
+ pathParts: parts,
1400
+ parentParts: parts.slice(0, -1),
1401
+ finalDirName: parts[parts.length - 1],
1402
+ relativeToPublic
1403
+ };
1404
+ }
1405
+ /**
1406
+ * 获取当前 baseURL 结构信息
1407
+ */
1408
+ getBaseURLStructure() {
1409
+ return this.metadata.baseURLStructure || null;
1410
+ }
1411
+ /**
1412
+ * 更新 baseURL 结构记录
1413
+ */
1414
+ updateBaseURLStructure(info) {
1415
+ this.metadata = this.metadata.update({
1416
+ baseURLStructure: info
1417
+ });
1418
+ }
1340
1419
  };
1341
1420
  }
1342
1421
  });
@@ -3182,6 +3261,17 @@ var init_workspace_factory = __esm({
3182
3261
  };
3183
3262
  await this.workspaceRepo.saveWorkspaceMetadata(absolutePath, metadata.toJSON());
3184
3263
  await this.workspaceRepo.saveProjectRegistry(absolutePath, emptyRegistry);
3264
+ if (this.fileSystemRepo) {
3265
+ const mdfridayDir = import_path3.default.join(absolutePath, ".mdfriday");
3266
+ const configPath = import_path3.default.join(mdfridayDir, "config.json");
3267
+ await this.fileSystemRepo.writeFile(configPath, "{}", "utf-8");
3268
+ const userDataPath = import_path3.default.join(mdfridayDir, "user-data.json");
3269
+ await this.fileSystemRepo.writeFile(userDataPath, "{}", "utf-8");
3270
+ log5.debug("Initialized configuration files", {
3271
+ configPath,
3272
+ userDataPath
3273
+ });
3274
+ }
3185
3275
  const authentication = new Authentication(absolutePath, false);
3186
3276
  const workspace = new Workspace(
3187
3277
  absolutePath,
@@ -3292,7 +3382,8 @@ var init_workspace_factory = __esm({
3292
3382
  });
3293
3383
  const defaultTheme = options.theme || "https://gohugo.net/quartz-theme.zip?version=1.2";
3294
3384
  const config = {
3295
- baseURL: "/",
3385
+ baseURL: options.baseURL || "/",
3386
+ // 新增:使用传入的 baseURL
3296
3387
  title: name,
3297
3388
  contentDir,
3298
3389
  publishDir,
@@ -3781,6 +3872,154 @@ var init_workspace_factory = __esm({
3781
3872
  // ============================================================================
3782
3873
  // Private Helpers
3783
3874
  // ============================================================================
3875
+ // ============================================================================
3876
+ // baseURL Structure Management
3877
+ // ============================================================================
3878
+ /**
3879
+ * 在 public/ 目录下创建 baseURL 访问路径结构
3880
+ *
3881
+ * 例如:baseURL = "/blog/" 时,在 public/ 下创建 blog/ -> . (symlink)
3882
+ */
3883
+ async setupBaseURLStructure(project) {
3884
+ if (!this.fileSystemRepo) {
3885
+ throw new Error("FileSystemRepository is required for baseURL structure");
3886
+ }
3887
+ const baseURL = await project.getBaseURL();
3888
+ const pathInfo = project.parseBaseURLPath(baseURL);
3889
+ const projectRoot = project.getPath();
3890
+ const publicDir = import_path3.default.join(projectRoot, "public");
3891
+ if (pathInfo.isRoot) {
3892
+ log5.debug("baseURL is root, no structure needed");
3893
+ return {
3894
+ serverRoot: publicDir,
3895
+ baseURL: "/",
3896
+ symlinkCreated: false
3897
+ };
3898
+ }
3899
+ log5.info("Creating baseURL structure in public/", {
3900
+ baseURL,
3901
+ pathParts: pathInfo.pathParts
3902
+ });
3903
+ let currentDir = publicDir;
3904
+ for (const dirName of pathInfo.parentParts) {
3905
+ currentDir = import_path3.default.join(currentDir, dirName);
3906
+ if (!await this.fileSystemRepo.exists(currentDir)) {
3907
+ await this.fileSystemRepo.createDirectory(currentDir, false);
3908
+ log5.debug(`Created parent directory: ${dirName}`);
3909
+ }
3910
+ }
3911
+ const symlinkPath = import_path3.default.join(currentDir, pathInfo.finalDirName);
3912
+ if (await this.fileSystemRepo.exists(symlinkPath)) {
3913
+ await this.fileSystemRepo.remove(symlinkPath, true);
3914
+ log5.debug(`Removed existing symlink: ${symlinkPath}`);
3915
+ }
3916
+ const symlinkResult = await this.fileSystemRepo.createSymlink(
3917
+ pathInfo.relativeToPublic,
3918
+ symlinkPath
3919
+ );
3920
+ if (!symlinkResult.success) {
3921
+ log5.error("Failed to create baseURL symlink", {
3922
+ target: pathInfo.relativeToPublic,
3923
+ link: symlinkPath,
3924
+ error: symlinkResult.error
3925
+ });
3926
+ throw new Error(`Failed to create baseURL structure: ${symlinkResult.error}`);
3927
+ }
3928
+ log5.info("baseURL structure created successfully", {
3929
+ symlinkPath: pathInfo.pathParts.join("/"),
3930
+ target: pathInfo.relativeToPublic
3931
+ });
3932
+ project.updateBaseURLStructure({
3933
+ baseURL,
3934
+ createdAt: Date.now(),
3935
+ pathParts: pathInfo.pathParts
3936
+ });
3937
+ await this.projectRepo.saveProjectMetadata(
3938
+ project.getPath(),
3939
+ project.getMetadata().toJSON()
3940
+ );
3941
+ return {
3942
+ serverRoot: publicDir,
3943
+ baseURL,
3944
+ symlinkCreated: true
3945
+ };
3946
+ }
3947
+ /**
3948
+ * 清理 public/ 下的 baseURL 路径结构
3949
+ */
3950
+ async cleanBaseURLStructure(project) {
3951
+ if (!this.fileSystemRepo) {
3952
+ return;
3953
+ }
3954
+ const structureInfo = project.getBaseURLStructure();
3955
+ if (!structureInfo || structureInfo.pathParts.length === 0) {
3956
+ return;
3957
+ }
3958
+ const projectRoot = project.getPath();
3959
+ const publicDir = import_path3.default.join(projectRoot, "public");
3960
+ log5.info("Cleaning baseURL structure in public/", {
3961
+ pathParts: structureInfo.pathParts
3962
+ });
3963
+ for (let i = structureInfo.pathParts.length; i > 0; i--) {
3964
+ const targetPath = import_path3.default.join(
3965
+ publicDir,
3966
+ ...structureInfo.pathParts.slice(0, i)
3967
+ );
3968
+ if (await this.fileSystemRepo.exists(targetPath)) {
3969
+ await this.fileSystemRepo.remove(targetPath, true);
3970
+ log5.debug(`Removed: ${structureInfo.pathParts.slice(0, i).join("/")}`);
3971
+ }
3972
+ if (i > 1) {
3973
+ const parentPath = import_path3.default.join(
3974
+ publicDir,
3975
+ ...structureInfo.pathParts.slice(0, i - 1)
3976
+ );
3977
+ if (await this.fileSystemRepo.exists(parentPath)) {
3978
+ const children = await this.fileSystemRepo.readDirectory(parentPath);
3979
+ if (children.length > 0) {
3980
+ break;
3981
+ }
3982
+ }
3983
+ }
3984
+ }
3985
+ project.updateBaseURLStructure(null);
3986
+ await this.projectRepo.saveProjectMetadata(
3987
+ project.getPath(),
3988
+ project.getMetadata().toJSON()
3989
+ );
3990
+ log5.info("baseURL structure cleaned");
3991
+ }
3992
+ /**
3993
+ * 确保 baseURL 结构正确
3994
+ * 检查 baseURL 是否变化,如需要则重新创建
3995
+ */
3996
+ async ensureBaseURLStructure(project) {
3997
+ const currentBaseURL = await project.getBaseURL();
3998
+ const structureInfo = project.getBaseURLStructure();
3999
+ const needRecreate = !structureInfo || structureInfo.baseURL !== currentBaseURL;
4000
+ if (needRecreate) {
4001
+ if (structureInfo) {
4002
+ log5.info("baseURL changed, recreating structure", {
4003
+ old: structureInfo.baseURL,
4004
+ new: currentBaseURL
4005
+ });
4006
+ await this.cleanBaseURLStructure(project);
4007
+ }
4008
+ const result = await this.setupBaseURLStructure(project);
4009
+ return {
4010
+ ...result,
4011
+ recreated: true
4012
+ };
4013
+ }
4014
+ return {
4015
+ serverRoot: import_path3.default.join(project.getPath(), "public"),
4016
+ baseURL: currentBaseURL,
4017
+ recreated: false
4018
+ };
4019
+ }
4020
+ // ============================================================================
4021
+ // Private Helpers
4022
+ // ============================================================================
3784
4023
  createSampleContent() {
3785
4024
  return `---
3786
4025
  title: Welcome to MDFriday
@@ -4048,6 +4287,29 @@ Please specify a project name with --project <name>`);
4048
4287
  createIdentityStorage(workspace) {
4049
4288
  return this.workspaceFactory.createIdentityStorage(workspace);
4050
4289
  }
4290
+ // ============================================================================
4291
+ // baseURL Structure Management
4292
+ // ============================================================================
4293
+ /**
4294
+ * 设置项目的 baseURL 路径结构
4295
+ * 在 public/ 目录下创建对应的 symlink 结构
4296
+ */
4297
+ async setupProjectBaseURLStructure(project) {
4298
+ return this.workspaceFactory.setupBaseURLStructure(project);
4299
+ }
4300
+ /**
4301
+ * 清理项目的 baseURL 路径结构
4302
+ */
4303
+ async cleanProjectBaseURLStructure(project) {
4304
+ return this.workspaceFactory.cleanBaseURLStructure(project);
4305
+ }
4306
+ /**
4307
+ * 确保项目的 baseURL 路径结构正确
4308
+ * 检查 baseURL 是否变化,如需要则重新创建
4309
+ */
4310
+ async ensureProjectBaseURLStructure(project) {
4311
+ return this.workspaceFactory.ensureBaseURLStructure(project);
4312
+ }
4051
4313
  };
4052
4314
  }
4053
4315
  });
@@ -50497,16 +50759,20 @@ var ProjectNewCommand = class {
50497
50759
  createOptions.theme = options.theme;
50498
50760
  if (options.path)
50499
50761
  createOptions.projectPath = options.path;
50762
+ if (options.baseUrl)
50763
+ createOptions.baseURL = options.baseUrl;
50500
50764
  const project = await this.workspaceAppService.createProject(workspace, name, createOptions);
50501
50765
  const info = project.getInfo();
50502
50766
  const displayTheme = options.theme || "quartz (default)";
50767
+ const baseURL = options.baseUrl || "/";
50503
50768
  log19.info(`Created project: ${name}`);
50504
50769
  return {
50505
50770
  success: true,
50506
50771
  message: `\u2713 Project created: ${name}
50507
50772
  Path: ${info.path}
50508
50773
  Theme: ${displayTheme}
50509
- Language: ${options.language || defaultLanguage2}`,
50774
+ Language: ${options.language || defaultLanguage2}
50775
+ ` + (baseURL !== "/" ? ` Base URL: ${baseURL}` : ""),
50510
50776
  data: info
50511
50777
  };
50512
50778
  } catch (error) {
@@ -51399,11 +51665,19 @@ var BuildCommand = class {
51399
51665
  project.addBuildHistory(historyEntry);
51400
51666
  await this.workspaceAppService.saveProject(project);
51401
51667
  log82.info(`Build completed in ${duration}ms`);
51668
+ const structureInfo = await this.workspaceAppService.setupProjectBaseURLStructure(project);
51669
+ log82.debug("baseURL structure setup complete", structureInfo);
51402
51670
  let message = `\u2713 Built site in ${(duration / 1e3).toFixed(1)}s
51403
51671
  `;
51404
51672
  message += `\u2713 Project: ${project.getName()}
51405
51673
  `;
51406
51674
  message += `\u2713 Output: ${outputDir}`;
51675
+ if (structureInfo.symlinkCreated) {
51676
+ message += `
51677
+ \u2713 Base URL structure created: ${structureInfo.baseURL}`;
51678
+ message += `
51679
+ Run 'mdf serve' to preview at http://localhost:8080${structureInfo.baseURL}`;
51680
+ }
51407
51681
  if (options.parallel) {
51408
51682
  message += "\n\u2713 Used parallel processing";
51409
51683
  }
@@ -51426,7 +51700,8 @@ var BuildCommand = class {
51426
51700
  duration,
51427
51701
  outputDir,
51428
51702
  contentDirs,
51429
- snapshot: snapshotInfo
51703
+ snapshot: snapshotInfo,
51704
+ baseURL: structureInfo.baseURL
51430
51705
  }
51431
51706
  };
51432
51707
  } catch (error) {
@@ -52571,6 +52846,10 @@ var ServeCommand = class {
52571
52846
  const host = options.host || "localhost";
52572
52847
  const livereloadPort = options.livereloadPort || 35729;
52573
52848
  const enableLivereload = options.livereload !== false;
52849
+ const structureInfo = await this.workspaceAppService.ensureProjectBaseURLStructure(project);
52850
+ if (structureInfo.recreated) {
52851
+ log88.info("baseURL structure created/updated");
52852
+ }
52574
52853
  const projContentDirs = await project.getContentDirs();
52575
52854
  const contentDirs = project.getLinkDirs();
52576
52855
  const modulesDir = workspace.getModulesDir();
@@ -52618,11 +52897,10 @@ var ServeCommand = class {
52618
52897
  if (!this.coordinator.isInitialized()) {
52619
52898
  throw new Error("Failed to initialize build coordinator");
52620
52899
  }
52621
- const liveReloadStatus = this.coordinator.getLiveReloadStatus();
52622
- const url = liveReloadStatus.url || `http://${host}:${port}`;
52623
- log88.info(`Server running at ${url}`);
52900
+ const serverUrl = `http://${host}:${port}${structureInfo.baseURL}`;
52901
+ log88.info(`Server running at ${serverUrl}`);
52624
52902
  if (options.open) {
52625
- await this.openBrowser(url);
52903
+ await this.openBrowser(serverUrl);
52626
52904
  }
52627
52905
  let isShuttingDown = false;
52628
52906
  const cleanup = async () => {
@@ -52651,14 +52929,14 @@ var ServeCommand = class {
52651
52929
  process.on("SIGHUP", cleanup);
52652
52930
  return {
52653
52931
  success: true,
52654
- message: `\u2713 Server running at ${url}
52932
+ message: `\u2713 Server running at ${serverUrl}
52655
52933
  ` + (enableLivereload ? `\u2713 LiveReload enabled on port ${livereloadPort}
52656
52934
  ` : "") + (options.publish ? `\u2713 Auto-publish enabled (${options.publish})
52657
52935
  ` : "") + `\u2713 Watching for changes...
52658
52936
 
52659
52937
  Press Ctrl+C to stop`,
52660
52938
  data: {
52661
- url,
52939
+ url: serverUrl,
52662
52940
  port,
52663
52941
  host,
52664
52942
  livereloadPort: enableLivereload ? livereloadPort : void 0,
@@ -54369,6 +54647,7 @@ Commands:
54369
54647
  --source-file <path> Create from single file (uses note theme by default)
54370
54648
  --theme <url> Theme URL (default: quartz)
54371
54649
  --language <lang> Default language (default: en)
54650
+ --base-url <url> Base URL for the site (e.g., /blog/)
54372
54651
  project list List all projects
54373
54652
  project show [name] Show project details
54374
54653
  project delete <name> Delete a project
@@ -54477,6 +54756,8 @@ Examples:
54477
54756
 
54478
54757
  # Project
54479
54758
  mdf project new my-blog Create a new project
54759
+ mdf project new my-blog --base-url /blog/
54760
+ Create project with custom base URL
54480
54761
  mdf project new my-blog --source ~/Documents/my-blog
54481
54762
  Create project from existing folder (auto-detect content/static)
54482
54763
  mdf project new my-note --source-file ~/Documents/my-note.md
@@ -54551,7 +54832,7 @@ For more information, visit: https://help.mdfriday.com
54551
54832
  * Show version
54552
54833
  */
54553
54834
  showVersion() {
54554
- const version = "26.3.6";
54835
+ const version = "26.3.8";
54555
54836
  return {
54556
54837
  success: true,
54557
54838
  message: `MDFriday CLI v${version}`