obsidian-plugin-config 1.7.3 → 1.7.5

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.
@@ -1,393 +1,397 @@
1
- #!/usr/bin/env tsx
2
-
3
- import fs from 'fs';
4
- import path from 'path';
5
- import { execSync } from 'child_process';
6
-
7
- /**
8
- * Generate bin/obsidian-inject.js from template
9
- */
10
- async function generateBinFile(): Promise<void> {
11
- console.log(`\nšŸ”§ Generating bin/obsidian-inject.js...`);
12
-
13
- const binDir = 'bin';
14
- const binPath = path.join(binDir, 'obsidian-inject.js');
15
-
16
- // Ensure bin directory exists
17
- if (!fs.existsSync(binDir)) {
18
- fs.mkdirSync(binDir, { recursive: true });
19
- console.log(` šŸ“ Created ${binDir} directory`);
20
- }
21
-
22
- // Read package.json for version info
23
- const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
24
-
25
- const binContent = `#!/usr/bin/env node
26
-
27
- /**
28
- * Obsidian Plugin Config - CLI Entry Point
29
- * Global command: obsidian-inject
30
- * Version: ${packageJson.version}
31
- */
32
-
33
- import { execSync } from 'child_process';
34
- import { fileURLToPath } from 'url';
35
- import { dirname, join, isAbsolute, resolve } from 'path';
36
- import fs from 'fs';
37
-
38
- // Get the directory of this script
39
- const __filename = fileURLToPath(import.meta.url);
40
- const __dirname = dirname(__filename);
41
- const packageRoot = dirname(__dirname);
42
-
43
- // Path to the injection script
44
- const injectScriptPath = join(packageRoot, 'scripts', 'inject-path.ts');
45
-
46
- function showHelp() {
47
- console.log(\`
48
- Obsidian Plugin Config - Global CLI
49
- Injection system for autonomous Obsidian plugins
50
-
51
- USAGE:
52
- obsidian-inject # Inject in current directory (with confirmation)
53
- obsidian-inject <path> # Inject by path (with confirmation)
54
- obsidian-inject <path> --no # Inject without confirmation
55
- obsidian-inject --help, -h # Show this help
56
-
57
- OPTIONS:
58
- --no, -n # Skip confirmation prompts (auto-confirm all)
59
- --dry-run # Verification only (no changes)
60
-
61
- EXAMPLES:
62
- cd my-plugin && obsidian-inject
63
- obsidian-inject ../my-other-plugin
64
- obsidian-inject ../my-plugin --no
65
- obsidian-inject "C:\\\\Users\\\\dev\\\\plugins\\\\my-plugin"
66
-
67
- WHAT IS INJECTED:
68
- āœ… Local scripts (esbuild.config.ts, acp.ts, utils.ts, etc.)
69
- āœ… Package.json configuration (scripts, dependencies)
70
- āœ… Config files (tsconfig, eslint, prettier, vscode, github)
71
- āœ… Yarn protection enforced
72
- āœ… Automatic dependency installation
73
-
74
- ARCHITECTURE:
75
- - Plugin becomes AUTONOMOUS with local scripts
76
- - No external dependencies required after injection
77
- - Updates possible via re-injection
78
-
79
- More info: https://github.com/3C0D/obsidian-plugin-config
80
- \`);
81
- }
82
-
83
- function main() {
84
- const args = process.argv.slice(2);
85
-
86
- // Handle help flags
87
- if (args.includes('--help') || args.includes('-h')) {
88
- showHelp();
89
- process.exit(0);
90
- }
91
-
92
- // Check if injection script exists
93
- if (!fs.existsSync(injectScriptPath)) {
94
- console.error(\`āŒ Error: Injection script not found at \${injectScriptPath}\`);
95
- console.error(\` Make sure obsidian-plugin-config is properly installed.\`);
96
- process.exit(1);
97
- }
98
-
99
- // Parse arguments
100
- const noConfirm = args.includes('--no') || args.includes('-n');
101
- const dryRun = args.includes('--dry-run');
102
- const pathArg = args.find(arg => !arg.startsWith('-'));
103
-
104
- // Determine target path (resolve relative to user's current directory)
105
- const userCwd = process.cwd();
106
- let targetPath = pathArg || userCwd;
107
-
108
- // If relative path, resolve from user's current directory
109
- if (pathArg && !isAbsolute(pathArg)) {
110
- targetPath = resolve(userCwd, pathArg);
111
- }
112
-
113
- console.log(\`šŸŽÆ Obsidian Plugin Config - Global Injection\`);
114
- console.log(\`šŸ“ Target: \${targetPath}\`);
115
- console.log(\`ā“ Confirmation: \${noConfirm ? 'Disabled (auto-confirm)' : 'Enabled'}\`);
116
- console.log(\`šŸ“¦ From: \${packageRoot}\\n\`);
117
-
118
- try {
119
- // Check if target directory has package.json
120
- const targetPackageJson = join(targetPath, 'package.json');
121
- if (!fs.existsSync(targetPackageJson)) {
122
- console.error(\`āŒ Error: package.json not found in \${targetPath}\`);
123
- console.error(\` Make sure this is a valid Node.js project.\`);
124
- process.exit(1);
125
- }
126
-
127
- // Prevent injecting into obsidian-plugin-config itself
128
- const pkg = JSON.parse(fs.readFileSync(targetPackageJson, 'utf8'));
129
- if (pkg.name === 'obsidian-plugin-config') {
130
- console.error(\`āŒ Cannot inject into obsidian-plugin-config itself.\`);
131
- process.exit(1);
132
- }
133
-
134
- // Clean NPM artifacts if package-lock.json exists
135
- const packageLockPath = join(targetPath, 'package-lock.json');
136
- if (fs.existsSync(packageLockPath)) {
137
- console.log(\`🧹 NPM installation detected, cleaning...\`);
138
-
139
- try {
140
- // Remove package-lock.json
141
- fs.unlinkSync(packageLockPath);
142
- console.log(\` šŸ—‘ļø package-lock.json removed\`);
143
-
144
- // Remove node_modules if it exists
145
- const nodeModulesPath = join(targetPath, 'node_modules');
146
- if (fs.existsSync(nodeModulesPath)) {
147
- fs.rmSync(nodeModulesPath, { recursive: true, force: true });
148
- console.log(\` šŸ—‘ļø node_modules removed (will be reinstalled with Yarn)\`);
149
- }
150
-
151
- console.log(\` āœ… NPM artifacts cleaned to avoid Yarn conflicts\`);
152
-
153
- } catch (cleanError) {
154
- console.error(\` āŒ Cleanup failed:\`, cleanError.message);
155
- console.log(\` šŸ’” Manually remove package-lock.json and node_modules\`);
156
- }
157
- }
158
-
159
- // Check if tsx is available locally in target
160
- try {
161
- execSync('npx tsx --version', {
162
- cwd: targetPath,
163
- stdio: 'pipe'
164
- });
165
- console.log(\`āœ… tsx available locally\`);
166
- } catch {
167
- console.log(\`āš ļø tsx not found, installing...\`);
168
-
169
- // Install tsx locally in target directory
170
- try {
171
- execSync('yarn add -D tsx', {
172
- cwd: targetPath,
173
- stdio: 'inherit'
174
- });
175
- console.log(\`āœ… tsx installed successfully\`);
176
- } catch (installError) {
177
- console.error(\`āŒ tsx installation failed:\`, installError.message);
178
- console.error(\` Try installing tsx manually: cd "\${targetPath}" && yarn add -D tsx\`);
179
- process.exit(1);
180
- }
181
- }
182
-
183
- // Execute the injection script with tsx
184
- const yesOption = noConfirm ? ' --yes' : '';
185
- const dryRunOption = dryRun ? ' --dry-run' : '';
186
- const command = \`npx tsx "\${injectScriptPath}" "\${targetPath}"\${yesOption}\${dryRunOption}\`;
187
-
188
- execSync(command, {
189
- stdio: 'inherit',
190
- cwd: targetPath // Use target directory to ensure tsx is available
191
- });
192
-
193
- console.log(\`\\nāœ… Injection completed successfully!\`);
194
-
195
- } catch (error) {
196
- console.error(\`\\nāŒ Injection error:\`, error.message);
197
- process.exit(1);
198
- }
199
- }
200
-
201
- // Run the CLI
202
- main();
203
- `;
204
-
205
- fs.writeFileSync(binPath, binContent, 'utf8');
206
- console.log(` āœ… Generated ${binPath}`);
207
- }
208
-
209
- /**
210
- * Ensure NPM authentication, prompting login if needed, then verifying success.
211
- */
212
- async function ensureNpmAuth(): Promise<void> {
213
- console.log(`šŸ” Checking NPM authentication...`);
214
-
215
- const checkWhoami = (): string | null => {
216
- try {
217
- return execSync('npm whoami --registry https://registry.npmjs.org/', {
218
- stdio: 'pipe',
219
- encoding: 'utf8'
220
- }).trim();
221
- } catch {
222
- return null;
223
- }
224
- };
225
-
226
- const whoami = checkWhoami();
227
- if (whoami) {
228
- console.log(` āœ… Logged in as: ${whoami}\n`);
229
- return;
230
- }
231
-
232
- console.log(` āš ļø Not logged in to NPM`);
233
- console.log(`šŸ”‘ Please login to NPM to publish the package`);
234
- console.log(` Opening browser for authentication...\n`);
235
-
236
- try {
237
- execSync('npm login --auth-type=web --registry https://registry.npmjs.org/', {
238
- stdio: 'inherit'
239
- });
240
- } catch {
241
- console.error(`\n āŒ NPM login failed`);
242
- console.error(` Please run 'npm login' manually and try again`);
243
- throw new Error('NPM authentication required');
244
- }
245
-
246
- // Verify login actually succeeded
247
- const whoamiAfter = checkWhoami();
248
- if (!whoamiAfter) {
249
- console.error(`\n āŒ Login appeared to complete but authentication could not be verified`);
250
- throw new Error('NPM authentication required');
251
- }
252
-
253
- console.log(`\n āœ… Successfully logged in as: ${whoamiAfter}\n`);
254
- }
255
-
256
- /**
257
- * Complete NPM workflow - Version, Commit, Push, Publish
258
- */
259
- async function buildAndPublishNpm(): Promise<void> {
260
- console.log(`šŸš€ Obsidian Plugin Config - NPM Publish Workflow`);
261
- console.log(`Automation: version → bin → verify → commit → publish\n`);
262
-
263
- try {
264
- // Step 0: Check NPM authentication
265
- await ensureNpmAuth();
266
-
267
- // Step 1: Update version
268
- console.log(`šŸ“‹ Step 1/5: Updating version...`);
269
- execSync('tsx scripts/update-version-config.ts', { stdio: 'inherit' });
270
-
271
- // Step 2: Generate bin file
272
- console.log(`\nšŸ”§ Step 2/5: Generating bin/obsidian-inject.js...`);
273
- await generateBinFile();
274
-
275
- // Step 3: Verify package
276
- console.log(`\nšŸ“‹ Step 3/5: Verifying package...`);
277
- verifyPackage();
278
-
279
- // Step 4: Commit and push
280
- console.log(`\nšŸ“¤ Step 4/5: Committing and pushing changes...`);
281
- try {
282
- // Add all changes
283
- execSync('git add -A', { stdio: 'pipe' });
284
-
285
- // Check if there are changes to commit
286
- const status = execSync('git status --porcelain', { encoding: 'utf8' });
287
- if (status.trim()) {
288
- const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
289
- execSync(`git commit -m "Publish NPM package v${packageJson.version}"`, {
290
- stdio: 'pipe'
291
- });
292
-
293
- // Get current branch and push
294
- const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
295
- encoding: 'utf8'
296
- }).trim();
297
- execSync(`git push origin ${currentBranch}`, { stdio: 'inherit' });
298
- console.log(` āœ… Changes committed and pushed`);
299
- } else {
300
- console.log(` ā„¹ļø No changes to commit`);
301
- }
302
- } catch (error) {
303
- console.error(
304
- ` āŒ Commit/push failed: ${error instanceof Error ? error.message : String(error)}`
305
- );
306
- throw error;
307
- }
308
-
309
- // Step 5: Publish to NPM
310
- console.log(`\nšŸ“¤ Step 5/5: Publishing to NPM...`);
311
- execSync('npm publish --registry https://registry.npmjs.org/', {
312
- stdio: 'inherit'
313
- });
314
-
315
- // Optional: Update global CLI automatically
316
- console.log(`\nšŸŒ Updating global CLI...`);
317
- console.log(` ā³ Waiting 30s for NPM registry propagation...`);
318
- await new Promise((resolve) => setTimeout(resolve, 30000));
319
- try {
320
- execSync(
321
- 'npm install -g obsidian-plugin-config@latest --force --engine-strict=false',
322
- { stdio: 'inherit' }
323
- );
324
- console.log(` āœ… Global CLI updated`);
325
- } catch {
326
- console.log(` āš ļø Global CLI update failed (NPM registry may need more time)`);
327
- console.log(
328
- ` šŸ’” Run manually in a few minutes: npm install -g obsidian-plugin-config@latest --force`
329
- );
330
- }
331
- console.log(`\nšŸŽ‰ Complete workflow successful!`);
332
- console.log(` Test: cd any-plugin && obsidian-inject`);
333
- } catch (error) {
334
- console.error(
335
- `\nāŒ Workflow failed: ${error instanceof Error ? error.message : String(error)}`
336
- );
337
- process.exit(1);
338
- }
339
- }
340
-
341
- /**
342
- * Verify package is ready for publication
343
- */
344
- function verifyPackage(): void {
345
- // Check required scripts
346
- const requiredScripts = [
347
- 'scripts/inject-path.ts',
348
- 'scripts/inject-prompt.ts',
349
- 'scripts/inject-core.ts',
350
- 'scripts/utils.ts',
351
- 'scripts/acp.ts',
352
- 'scripts/update-version-config.ts',
353
- 'scripts/help.ts'
354
- ];
355
-
356
- for (const script of requiredScripts) {
357
- if (!fs.existsSync(script)) {
358
- throw new Error(`Missing required script: ${script}`);
359
- }
360
- }
361
- console.log(` āœ… All required scripts present`);
362
-
363
- // Check package.json
364
- const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
365
- const requiredFields = [
366
- 'name',
367
- 'version',
368
- 'description',
369
- 'bin',
370
- 'repository',
371
- 'author'
372
- ];
373
-
374
- for (const field of requiredFields) {
375
- if (!packageJson[field]) {
376
- throw new Error(`Missing required package.json field: ${field}`);
377
- }
378
- }
379
- console.log(` āœ… Package.json valid (v${packageJson.version})`);
380
-
381
- // Check bin file exists
382
- if (!fs.existsSync('bin/obsidian-inject.js')) {
383
- throw new Error(`Missing bin file: bin/obsidian-inject.js`);
384
- }
385
- console.log(` āœ… Bin file ready`);
386
-
387
- // Quick build test
388
- execSync('tsc --noEmit', { stdio: 'pipe' });
389
- console.log(` āœ… TypeScript check passed`);
390
- }
391
-
392
- // Run the script
393
- await buildAndPublishNpm();
1
+ #!/usr/bin/env tsx
2
+
3
+ import { readFile, writeFile, mkdir } from 'fs/promises';
4
+ import path from 'path';
5
+ import { execSync } from 'child_process';
6
+ import { gitExec, gitOutput, isValidPath } from './utils.ts';
7
+
8
+ /**
9
+ * Generate bin/obsidian-inject.js from template
10
+ */
11
+ async function generateBinFile(): Promise<void> {
12
+ console.log(`\nšŸ”§ Generating bin/obsidian-inject.js...`);
13
+
14
+ const binDir = 'bin';
15
+ const binPath = path.join(binDir, 'obsidian-inject.js');
16
+
17
+ // Ensure bin directory exists
18
+ if (!(await isValidPath(binDir))) {
19
+ await mkdir(binDir, { recursive: true });
20
+ console.log(` šŸ“ Created ${binDir} directory`);
21
+ }
22
+
23
+ // Read package.json for version info
24
+ const packageJson = JSON.parse(await readFile('package.json', 'utf8'));
25
+
26
+ const binContent = `#!/usr/bin/env node
27
+
28
+ /**
29
+ * Obsidian Plugin Config - CLI Entry Point
30
+ * Global command: obsidian-inject
31
+ * Version: ${packageJson.version}
32
+ */
33
+
34
+ import { execSync } from 'child_process';
35
+ import { fileURLToPath } from 'url';
36
+ import { dirname, join, isAbsolute, resolve } from 'path';
37
+ import { readFile, access, unlink, rm } from 'fs/promises';
38
+
39
+ // Get the directory of this script
40
+ const __filename = fileURLToPath(import.meta.url);
41
+ const __dirname = dirname(__filename);
42
+ const packageRoot = dirname(__dirname);
43
+
44
+ // Path to the injection script
45
+ const injectScriptPath = join(packageRoot, 'scripts', 'inject-path.ts');
46
+
47
+ async function pathExists(p) {
48
+ try {
49
+ await access(p);
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ function showHelp() {
57
+ console.log(\`
58
+ Obsidian Plugin Config - Global CLI
59
+ Injection system for autonomous Obsidian plugins
60
+
61
+ USAGE:
62
+ obsidian-inject # Inject in current directory (with confirmation)
63
+ obsidian-inject <path> # Inject by path (with confirmation)
64
+ obsidian-inject <path> --no # Inject without confirmation
65
+ obsidian-inject --help, -h # Show this help
66
+
67
+ OPTIONS:
68
+ --no, -n # Skip confirmation prompts (auto-confirm all)
69
+ --dry-run # Verification only (no changes)
70
+
71
+ EXAMPLES:
72
+ cd my-plugin && obsidian-inject
73
+ obsidian-inject ../my-other-plugin
74
+ obsidian-inject ../my-plugin --no
75
+ obsidian-inject "C:\\\\Users\\\\dev\\\\plugins\\\\my-plugin"
76
+
77
+ WHAT IS INJECTED:
78
+ āœ… Local scripts (esbuild.config.ts, acp.ts, utils.ts, etc.)
79
+ āœ… Package.json configuration (scripts, dependencies)
80
+ āœ… Config files (tsconfig, eslint, prettier, vscode, github)
81
+ āœ… Yarn protection enforced
82
+ āœ… Automatic dependency installation
83
+
84
+ ARCHITECTURE:
85
+ - Plugin becomes AUTONOMOUS with local scripts
86
+ - No external dependencies required after injection
87
+ - Updates possible via re-injection
88
+
89
+ More info: https://github.com/3C0D/obsidian-plugin-config
90
+ \`);
91
+ }
92
+
93
+ async function main() {
94
+ const args = process.argv.slice(2);
95
+
96
+ // Handle help flags
97
+ if (args.includes('--help') || args.includes('-h')) {
98
+ showHelp();
99
+ process.exit(0);
100
+ }
101
+
102
+ // Check if injection script exists
103
+ if (!(await pathExists(injectScriptPath))) {
104
+ console.error(\`āŒ Error: Injection script not found at \${injectScriptPath}\`);
105
+ console.error(\` Make sure obsidian-plugin-config is properly installed.\`);
106
+ process.exit(1);
107
+ }
108
+
109
+ // Parse arguments
110
+ const noConfirm = args.includes('--no') || args.includes('-n');
111
+ const dryRun = args.includes('--dry-run');
112
+ const pathArg = args.find(arg => !arg.startsWith('-'));
113
+
114
+ // Determine target path (resolve relative to user's current directory)
115
+ const userCwd = process.cwd();
116
+ let targetPath = pathArg || userCwd;
117
+
118
+ // If relative path, resolve from user's current directory
119
+ if (pathArg && !isAbsolute(pathArg)) {
120
+ targetPath = resolve(userCwd, pathArg);
121
+ }
122
+
123
+ console.log(\`šŸŽÆ Obsidian Plugin Config - Global Injection\`);
124
+ console.log(\`šŸ“ Target: \${targetPath}\`);
125
+ console.log(\`ā“ Confirmation: \${noConfirm ? 'Disabled (auto-confirm)' : 'Enabled'}\`);
126
+ console.log(\`šŸ“¦ From: \${packageRoot}\\n\`);
127
+
128
+ try {
129
+ // Check if target directory has package.json
130
+ const targetPackageJson = join(targetPath, 'package.json');
131
+ if (!(await pathExists(targetPackageJson))) {
132
+ console.error(\`āŒ Error: package.json not found in \${targetPath}\`);
133
+ console.error(\` Make sure this is a valid Node.js project.\`);
134
+ process.exit(1);
135
+ }
136
+
137
+ // Prevent injecting into obsidian-plugin-config itself
138
+ const pkg = JSON.parse(await readFile(targetPackageJson, 'utf8'));
139
+ if (pkg.name === 'obsidian-plugin-config') {
140
+ console.error(\`āŒ Cannot inject into obsidian-plugin-config itself.\`);
141
+ process.exit(1);
142
+ }
143
+
144
+ // Clean NPM artifacts if package-lock.json exists
145
+ const packageLockPath = join(targetPath, 'package-lock.json');
146
+ if (await pathExists(packageLockPath)) {
147
+ console.log(\`🧹 NPM installation detected, cleaning...\`);
148
+
149
+ try {
150
+ // Remove package-lock.json
151
+ await unlink(packageLockPath);
152
+ console.log(\` šŸ—‘ļø package-lock.json removed\`);
153
+
154
+ // Remove node_modules if it exists
155
+ const nodeModulesPath = join(targetPath, 'node_modules');
156
+ if (await pathExists(nodeModulesPath)) {
157
+ await rm(nodeModulesPath, { recursive: true, force: true });
158
+ console.log(\` šŸ—‘ļø node_modules removed (will be reinstalled with Yarn)\`);
159
+ }
160
+
161
+ console.log(\` āœ… NPM artifacts cleaned to avoid Yarn conflicts\`);
162
+
163
+ } catch (cleanError) {
164
+ console.error(\` āŒ Cleanup failed:\`, cleanError instanceof Error ? cleanError.message : String(cleanError));
165
+ console.log(\` šŸ’” Manually remove package-lock.json and node_modules\`);
166
+ }
167
+ }
168
+
169
+ // Check if tsx is available locally in target
170
+ try {
171
+ execSync('npx tsx --version', {
172
+ cwd: targetPath,
173
+ stdio: 'pipe'
174
+ });
175
+ console.log(\`āœ… tsx available locally\`);
176
+ } catch {
177
+ console.log(\`āš ļø tsx not found, installing...\`);
178
+
179
+ // Install tsx locally in target directory
180
+ try {
181
+ execSync('yarn add -D tsx', {
182
+ cwd: targetPath,
183
+ stdio: 'inherit'
184
+ });
185
+ console.log(\`āœ… tsx installed successfully\`);
186
+ } catch (installError) {
187
+ console.error(\`āŒ tsx installation failed:\`, installError.message);
188
+ console.error(\` Try installing tsx manually: cd "\${targetPath}" && yarn add -D tsx\`);
189
+ process.exit(1);
190
+ }
191
+ }
192
+
193
+ // Execute the injection script with tsx
194
+ const yesOption = noConfirm ? ' --yes' : '';
195
+ const dryRunOption = dryRun ? ' --dry-run' : '';
196
+ const command = \`npx tsx "\${injectScriptPath}" "\${targetPath}"\${yesOption}\${dryRunOption}\`;
197
+
198
+ execSync(command, {
199
+ stdio: 'inherit',
200
+ cwd: targetPath // Use target directory to ensure tsx is available
201
+ });
202
+
203
+ console.log(\`\\nāœ… Injection completed successfully!\`);
204
+
205
+ } catch (error) {
206
+ console.error(\`\\nāŒ Injection error:\`, error.message);
207
+ process.exit(1);
208
+ }
209
+ }
210
+
211
+ main().catch(console.error);
212
+ `;
213
+
214
+ await writeFile(binPath, binContent, 'utf8');
215
+ console.log(` āœ… Generated ${binPath}`);
216
+ }
217
+
218
+ /**
219
+ * Ensure NPM authentication, prompting login if needed, then verifying success.
220
+ */
221
+ async function ensureNpmAuth(): Promise<void> {
222
+ console.log(`šŸ” Checking NPM authentication...`);
223
+
224
+ const checkWhoami = (): string | null => {
225
+ try {
226
+ return execSync('npm whoami --registry https://registry.npmjs.org/', {
227
+ stdio: 'pipe',
228
+ encoding: 'utf8'
229
+ }).trim();
230
+ } catch {
231
+ return null;
232
+ }
233
+ };
234
+
235
+ const whoami = checkWhoami();
236
+ if (whoami) {
237
+ console.log(` āœ… Logged in as: ${whoami}\n`);
238
+ return;
239
+ }
240
+
241
+ console.log(` āš ļø Not logged in to NPM`);
242
+ console.log(`šŸ”‘ Please login to NPM to publish the package`);
243
+ console.log(` Opening browser for authentication...\n`);
244
+
245
+ try {
246
+ execSync('npm login --auth-type=web --registry https://registry.npmjs.org/', {
247
+ stdio: 'inherit'
248
+ });
249
+ } catch {
250
+ console.error(`\n āŒ NPM login failed`);
251
+ console.error(` Please run 'npm login' manually and try again`);
252
+ throw new Error('NPM authentication required');
253
+ }
254
+
255
+ // Verify login actually succeeded
256
+ const whoamiAfter = checkWhoami();
257
+ if (!whoamiAfter) {
258
+ console.error(
259
+ `\n āŒ Login appeared to complete but authentication could not be verified`
260
+ );
261
+ throw new Error('NPM authentication required');
262
+ }
263
+
264
+ console.log(`\n āœ… Successfully logged in as: ${whoamiAfter}\n`);
265
+ }
266
+
267
+ /**
268
+ * Complete NPM workflow - Version, Commit, Push, Publish
269
+ */
270
+ async function buildAndPublishNpm(): Promise<void> {
271
+ console.log(`šŸš€ Obsidian Plugin Config - NPM Publish Workflow`);
272
+ console.log(`Automation: version → bin → verify → commit → publish\n`);
273
+
274
+ try {
275
+ // Step 0: Check NPM authentication
276
+ await ensureNpmAuth();
277
+
278
+ // Step 1: Update version
279
+ console.log(`šŸ“‹ Step 1/5: Updating version...`);
280
+ gitExec('npx tsx scripts/update-version-config.ts');
281
+
282
+ // Step 2: Generate bin file
283
+ console.log(`\nšŸ”§ Step 2/5: Generating bin/obsidian-inject.js...`);
284
+ await generateBinFile();
285
+
286
+ // Step 3: Verify package
287
+ console.log(`\nšŸ“‹ Step 3/5: Verifying package...`);
288
+ await verifyPackage();
289
+
290
+ // Step 4: Commit and push
291
+ console.log(`\nšŸ“¤ Step 4/5: Committing and pushing changes...`);
292
+ try {
293
+ // Add all changes
294
+ gitExec('git add -A');
295
+
296
+ // Check if there are changes to commit
297
+ const status = gitOutput('git status --porcelain');
298
+ if (status.trim()) {
299
+ const packageJson = JSON.parse(await readFile('package.json', 'utf8'));
300
+ gitExec(`git commit -m "Publish NPM package v${packageJson.version}"`);
301
+
302
+ // Get current branch and push
303
+ const currentBranch = gitOutput('git rev-parse --abbrev-ref HEAD');
304
+ gitExec(`git push origin ${currentBranch}`);
305
+ console.log(` āœ… Changes committed and pushed`);
306
+ } else {
307
+ console.log(` ā„¹ļø No changes to commit`);
308
+ }
309
+ } catch (error) {
310
+ console.error(
311
+ ` āŒ Commit/push failed: ${error instanceof Error ? error.message : String(error)}`
312
+ );
313
+ throw error;
314
+ }
315
+
316
+ // Step 5: Publish to NPM
317
+ console.log(`\nšŸ“¤ Step 5/5: Publishing to NPM...`);
318
+ gitExec('npm publish --registry https://registry.npmjs.org/');
319
+
320
+ // Optional: Update global CLI automatically
321
+ console.log(`\nšŸŒ Updating global CLI...`);
322
+ console.log(` ā³ Waiting 30s for NPM registry propagation...`);
323
+ await new Promise((resolve) => setTimeout(resolve, 30000));
324
+ try {
325
+ gitExec(
326
+ 'npm install -g obsidian-plugin-config@latest --force --engine-strict=false'
327
+ );
328
+ console.log(` āœ… Global CLI updated`);
329
+ } catch {
330
+ console.log(` āš ļø Global CLI update failed (NPM registry may need more time)`);
331
+ console.log(
332
+ ` šŸ’” Run manually in a few minutes: npm install -g obsidian-plugin-config@latest --force`
333
+ );
334
+ }
335
+ console.log(`\nšŸŽ‰ Complete workflow successful!`);
336
+ console.log(` Test: cd any-plugin && obsidian-inject`);
337
+ } catch (error) {
338
+ console.error(
339
+ `\nāŒ Workflow failed: ${error instanceof Error ? error.message : String(error)}`
340
+ );
341
+ process.exit(1);
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Verify package is ready for publication
347
+ */
348
+ async function verifyPackage(): Promise<void> {
349
+ // Check required scripts
350
+ const requiredScripts = [
351
+ 'scripts/inject-path.ts',
352
+ 'scripts/inject-prompt.ts',
353
+ 'scripts/inject-core.ts',
354
+ 'scripts/utils.ts',
355
+ 'scripts/acp.ts',
356
+ 'scripts/update-version-config.ts',
357
+ 'scripts/help.ts'
358
+ ];
359
+
360
+ for (const script of requiredScripts) {
361
+ if (!(await isValidPath(script))) {
362
+ throw new Error(`Missing required script: ${script}`);
363
+ }
364
+ }
365
+ console.log(` āœ… All required scripts present`);
366
+
367
+ // Check package.json
368
+ const packageJson = JSON.parse(await readFile('package.json', 'utf8'));
369
+ const requiredFields = [
370
+ 'name',
371
+ 'version',
372
+ 'description',
373
+ 'bin',
374
+ 'repository',
375
+ 'author'
376
+ ];
377
+
378
+ for (const field of requiredFields) {
379
+ if (!packageJson[field]) {
380
+ throw new Error(`Missing required package.json field: ${field}`);
381
+ }
382
+ }
383
+ console.log(` āœ… Package.json valid (v${packageJson.version})`);
384
+
385
+ // Check bin file exists
386
+ if (!(await isValidPath('bin/obsidian-inject.js'))) {
387
+ throw new Error(`Missing bin file: bin/obsidian-inject.js`);
388
+ }
389
+ console.log(` āœ… Bin file ready`);
390
+
391
+ // Quick build test (suppress tsc output, only show pass/fail)
392
+ gitExec('npx tsc --noEmit', undefined, true);
393
+ console.log(` āœ… TypeScript check passed`);
394
+ }
395
+
396
+ // Run the script
397
+ await buildAndPublishNpm();