create-vault-cms 1.0.0 → 1.0.3

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 (3) hide show
  1. package/README.md +27 -27
  2. package/package.json +2 -1
  3. package/src/cli.js +53 -21
package/README.md CHANGED
@@ -25,48 +25,48 @@ Use [Obsidian](https://obsidian.md) as a content management system for your [Ast
25
25
 
26
26
  ## Installation Guide
27
27
 
28
- 1. Clone or install your Astro theme of choice.
29
- 2. Clone or download a zip of this repo.
30
- 3. Copy the contents of the `Starter Vault` folder into your Astro project. **Recommended location:** `src/content` folder, but it can be placed at the level of `src/content` or higher (like the project root).
31
- 4. Open Obsidian and select the "Open folder as vault" option, and select the folder containing the `.obsidian` directory.
32
- 5. The Vault CMS plugin will automatically detect your Astro project structure and guide you through setup via a wizard.
28
+ The easiest way to install Vault CMS is via the CLI:
33
29
 
34
- ### Starter Vault vs Theme Examples
30
+ ```bash
31
+ # Using pnpm
32
+ pnpm create vault-cms
35
33
 
36
- - **`Starter Vault`**: This is the adaptive vault that works with any Astro theme. It automatically detects your theme's structure and configures itself accordingly. This is what you should copy into your project.
34
+ # Using npm
35
+ npm create vault-cms
37
36
 
38
- - **`Theme Examples`**: This folder contains preconfigured vault examples for specific Astro themes (Slate, Chiri, Starlight). These serve as reference examples showing how Vault CMS can be configured for particular themes. You don't need to use these unless you want to see theme-specific configurations.
39
-
40
- ### Using Theme Examples
37
+ # Using yarn
38
+ yarn create vault-cms
39
+ ```
41
40
 
42
- If you're using one of the supported themes (Slate, Chiri, or Starlight) and want to use a preconfigured vault example instead of the adaptive Starter Vault:
41
+ This will automatically:
42
+ 1. Copy the necessary `_bases` and `.obsidian` configuration folders.
43
+ 2. Setup a `README.md` for your vault.
44
+ 3. Update your `.gitignore` with the recommended Obsidian excludes.
43
45
 
44
- 1. Navigate to the `Theme Examples` folder and find your theme's folder (e.g., `Slate`, `Chiri`, or `Starlight`).
45
- 2. **Copy the CONTENTS** of that theme folder (not the folder itself) into your Astro project's `src/content` folder.
46
- - ⚠️ **Important**: Copy the files and folders inside the theme folder, not the theme folder itself. For example, if using Slate, copy the contents of `Theme Examples/Slate/` (like `_bases/`, `post/`, etc.) into `src/content/`, not the `Slate` folder. (Note: `_bases` is the new standard, but `bases` is still supported for backwards compatibility).
47
- 3. Open Obsidian and select "Open folder as vault", then select your `src/content` folder (or the folder containing the `.obsidian` directory).
48
- 4. The vault should already be preconfigured for your theme.
46
+ ### Manual Installation
49
47
 
50
- > [!TIP]
51
- > If you're unsure which to use, start with the **Starter Vault** - it will automatically adapt to your theme. Use the Theme Examples only if you want to see a preconfigured setup for a specific theme.
48
+ If you prefer to install manually:
49
+ 1. Clone or download a zip of this repo.
50
+ 2. Copy the `_bases` and `.obsidian` folders into your Astro project (e.g., in `src/content`).
51
+ 3. Open Obsidian and select "Open folder as vault", then select the folder containing the `.obsidian` directory.
52
52
 
53
53
  ## How Auto-Detection Works
54
54
 
55
55
  Vault CMS automatically detects and configures itself based on your Astro project:
56
56
 
57
- - **Project Detection**: Automatically finds your Astro project by locating `astro.config.mjs`, `astro.config.ts`, or other Astro config files
58
- - **Content Type Detection**: Scans your content folders (like `posts`, `pages`, `docs`, etc.) and automatically identifies them as content types
59
- - **Frontmatter Analysis**: Analyzes existing content files to detect frontmatter properties (title, date, description, etc.) and configures the plugin accordingly
60
- - **Theme Adaptation**: Adapts to your Astro theme's specific quirks and requirements automatically
57
+ - **Project Detection**: Automatically finds your Astro project by locating `astro.config.mjs`, `astro.config.ts`, or other Astro config files.
58
+ - **Content Type Detection**: Scans your content folders (like `posts`, `pages`, `docs`, etc.) and automatically identifies them as content types.
59
+ - **Frontmatter Analysis**: Analyzes existing content files to detect frontmatter properties (title, date, description, etc.) and configures the plugin accordingly.
60
+ - **Theme Adaptation**: Adapts to your Astro theme's specific quirks and requirements automatically.
61
61
 
62
62
  When you first open the vault, a setup wizard will guide you through the configuration process. The wizard uses the auto-detected information to pre-populate settings, making setup quick and easy. You can always run the wizard again later by using the "Open Setup Wizard" command.
63
63
 
64
64
  ### Recommended .gitignore
65
65
 
66
- Add the following to your Astro project's `.gitignore` file:
66
+ If you are not using the CLI, add the following to your Astro project's `.gitignore` file:
67
67
  ```
68
- # Obsidian workspace files
69
- **/.obsidian/workspace.json
70
- **/.obsidian/workspace-mobile.json
68
+ # Obsidian
69
+ .obsidian/workspace.json
70
+ .obsidian/workspace-mobile.json
71
71
  ```
72
- This prevents conflicts between multiple devices.
72
+ This prevents conflicts between multiple devices and keeps your vault clean.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-vault-cms",
3
- "version": "1.0.0",
3
+ "version": "1.0.3",
4
4
  "description": "Installer for Vault CMS",
5
5
  "main": "src/cli.js",
6
6
  "bin": {
@@ -27,6 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/davidvkimball/vault-cms#readme",
29
29
  "dependencies": {
30
+ "adm-zip": "^0.5.16",
30
31
  "commander": "^14.0.2",
31
32
  "fs-extra": "^11.3.3"
32
33
  }
package/src/cli.js CHANGED
@@ -3,56 +3,67 @@
3
3
  const { Command } = require('commander');
4
4
  const fs = require('fs-extra');
5
5
  const path = require('path');
6
- const { execSync } = require('child_process');
6
+ const https = require('https');
7
+ const AdmZip = require('adm-zip');
8
+
9
+ // Read version from package.json
10
+ const pkg = require('../package.json');
7
11
 
8
12
  const program = new Command();
9
13
 
10
14
  program
11
15
  .name('create-vault-cms')
12
16
  .description('Official installer for Vault CMS')
13
- .version('1.0.0');
17
+ .version(pkg.version);
14
18
 
15
19
  program
16
20
  .argument('[target]', 'target directory', '.')
17
21
  .option('-t, --template <name>', 'template to use (from vault-cms-presets)')
18
22
  .action(async (target, options) => {
19
23
  const targetDir = path.resolve(target);
20
- const tempDir = path.join(targetDir, '.vault-cms-temp');
24
+ const tempZip = path.join(targetDir, 'vault-cms-temp.zip');
25
+ const extractDir = path.join(targetDir, '.vault-cms-temp-extract');
21
26
 
22
- const repoUrl = options.template
23
- ? 'https://github.com/davidvkimball/vault-cms-presets.git'
24
- : 'https://github.com/davidvkimball/vault-cms.git';
27
+ const repoName = options.template ? 'vault-cms-presets' : 'vault-cms';
28
+ const zipUrl = `https://github.com/davidvkimball/${repoName}/archive/refs/heads/master.zip`;
25
29
 
26
30
  console.log(`🚀 Installing Vault CMS${options.template ? ` (template: ${options.template})` : ''}...`);
27
31
 
28
32
  try {
29
- // 1. Download
30
- console.log(' 📦 Downloading files...');
31
- execSync(`git clone --depth 1 ${repoUrl} "${tempDir}"`, { stdio: 'ignore' });
33
+ // 1. Create target directory
34
+ await fs.ensureDir(targetDir);
35
+
36
+ // 2. Download ZIP
37
+ console.log(' 📦 Downloading archive...');
38
+ await downloadFile(zipUrl, tempZip);
39
+
40
+ // 3. Extract ZIP
41
+ console.log(' 📂 Extracting files...');
42
+ const zip = new AdmZip(tempZip);
43
+ zip.extractAllTo(extractDir, true);
44
+
45
+ // 4. Identify the inner folder (GitHub zips wrap content in a folder named repo-branch)
46
+ const folders = await fs.readdir(extractDir);
47
+ const innerFolder = path.join(extractDir, folders[0]);
48
+ const sourcePath = options.template ? path.join(innerFolder, options.template) : innerFolder;
32
49
 
33
- // 2. Determine source path
34
- const sourcePath = options.template ? path.join(tempDir, options.template) : tempDir;
35
-
36
50
  if (!(await fs.pathExists(sourcePath))) {
37
51
  throw new Error(`Template "${options.template}" not found in presets repository.`);
38
52
  }
39
53
 
40
- // 3. Define what to keep
54
+ // 5. Move selected files
41
55
  const toKeep = ['_bases', '.obsidian', 'README.md'];
42
-
43
- // 4. Move selected files
44
- await fs.ensureDir(targetDir);
45
56
  for (const item of toKeep) {
46
57
  const src = path.join(sourcePath, item);
47
58
  const dest = path.join(targetDir, item);
48
59
 
49
60
  if (await fs.pathExists(src)) {
50
- await fs.copy(src, dest);
61
+ await fs.copy(src, dest, { overwrite: true });
51
62
  console.log(` ✓ Added ${item}`);
52
63
  }
53
64
  }
54
65
 
55
- // 5. Update .gitignore
66
+ // 6. Handle .gitignore
56
67
  const gitignorePath = path.join(targetDir, '.gitignore');
57
68
  const ignores = '\n# Vault CMS / Obsidian\n.obsidian/workspace.json\n.obsidian/workspace-mobile.json\n.ref/\n';
58
69
 
@@ -67,15 +78,36 @@ program
67
78
  console.log(' ✓ Created .gitignore');
68
79
  }
69
80
 
70
- // 6. Cleanup
71
- await fs.remove(tempDir);
81
+ // 7. Cleanup
82
+ await fs.remove(tempZip);
83
+ await fs.remove(extractDir);
72
84
 
73
85
  console.log('\n✨ Vault CMS is ready!');
74
86
  } catch (err) {
75
87
  console.error('\n❌ Installation failed:', err.message);
76
- if (await fs.pathExists(tempDir)) await fs.remove(tempDir);
88
+ if (await fs.pathExists(tempZip)) await fs.remove(tempZip);
89
+ if (await fs.pathExists(extractDir)) await fs.remove(extractDir);
77
90
  process.exit(1);
78
91
  }
79
92
  });
80
93
 
94
+ function downloadFile(url, dest) {
95
+ return new Promise((resolve, reject) => {
96
+ https.get(url, (res) => {
97
+ if (res.statusCode === 301 || res.statusCode === 302) {
98
+ return downloadFile(res.headers.location, dest).then(resolve).catch(reject);
99
+ }
100
+ if (res.statusCode !== 200) {
101
+ return reject(new Error(`Failed to download: ${res.statusCode}`));
102
+ }
103
+ const file = fs.createWriteStream(dest);
104
+ res.pipe(file);
105
+ file.on('finish', () => {
106
+ file.close();
107
+ resolve();
108
+ });
109
+ }).on('error', reject);
110
+ });
111
+ }
112
+
81
113
  program.parse();