myaidev-method 0.2.19 → 0.2.23

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 (57) hide show
  1. package/CHANGELOG.md +123 -5
  2. package/README.md +205 -13
  3. package/TECHNICAL_ARCHITECTURE.md +64 -2
  4. package/USER_GUIDE.md +453 -48
  5. package/bin/cli.js +187 -2
  6. package/content-rules.example.md +80 -0
  7. package/dist/mcp/mcp-config.json +138 -1
  8. package/dist/mcp/mcp-launcher.js +237 -0
  9. package/dist/mcp/openstack-server.js +1607 -0
  10. package/dist/server/.tsbuildinfo +1 -1
  11. package/dist/server/auth/layers.d.ts +1 -1
  12. package/dist/server/auth/services/AuthService.d.ts +1 -1
  13. package/dist/server/auth/services/TokenService.js.map +1 -1
  14. package/dist/server/auth/services/example.d.ts +5 -5
  15. package/package.json +17 -17
  16. package/src/config/workflows.js +532 -0
  17. package/src/index.js +21 -8
  18. package/src/lib/payloadcms-utils.js +206 -0
  19. package/src/lib/update-manager.js +2 -1
  20. package/src/lib/visual-config-utils.js +321 -295
  21. package/src/lib/visual-generation-utils.js +1080 -740
  22. package/src/lib/workflow-installer.js +512 -0
  23. package/src/libs/security/authorization-checker.js +606 -0
  24. package/src/mcp/openstack-server.js +1607 -0
  25. package/src/scripts/configure-wordpress-mcp.js +8 -3
  26. package/src/scripts/generate-visual-cli.js +365 -235
  27. package/src/scripts/openstack-setup.sh +110 -0
  28. package/src/scripts/ping.js +250 -0
  29. package/src/scripts/security/environment-detect.js +425 -0
  30. package/src/scripts/wordpress/publish-to-wordpress.js +165 -0
  31. package/src/server/auth/services/TokenService.ts +1 -1
  32. package/src/templates/claude/agents/content-rules-setup.md +657 -0
  33. package/src/templates/claude/agents/content-writer.md +328 -1
  34. package/src/templates/claude/agents/openstack-vm-manager.md +281 -0
  35. package/src/templates/claude/agents/osint-researcher.md +1075 -0
  36. package/src/templates/claude/agents/penetration-tester.md +908 -0
  37. package/src/templates/claude/agents/security-auditor.md +244 -0
  38. package/src/templates/claude/agents/security-setup.md +1094 -0
  39. package/src/templates/claude/agents/visual-content-generator.md +182 -4
  40. package/src/templates/claude/agents/webapp-security-tester.md +581 -0
  41. package/src/templates/claude/commands/myai-configure.md +85 -1
  42. package/src/templates/claude/commands/myai-content-rules-setup.md +204 -0
  43. package/src/templates/claude/commands/myai-openstack.md +229 -0
  44. package/src/templates/claude/commands/sc:security-exploit.md +464 -0
  45. package/src/templates/claude/commands/sc:security-recon.md +281 -0
  46. package/src/templates/claude/commands/sc:security-report.md +756 -0
  47. package/src/templates/claude/commands/sc:security-scan.md +441 -0
  48. package/src/templates/claude/commands/sc:security-setup.md +501 -0
  49. package/src/templates/codex/commands/myai-content-rules-setup.md +85 -0
  50. package/src/templates/gemini/commands/myai-content-rules-setup.toml +57 -0
  51. package/.claude/mcp/sparc-orchestrator-server.js +0 -607
  52. package/.claude/mcp/wordpress-server.js +0 -1277
  53. package/src/agents/content-writer-prompt.md +0 -164
  54. package/src/agents/content-writer.json +0 -70
  55. package/src/templates/claude/mcp_config.json +0 -30
  56. package/src/templates/claude/slash_commands.json +0 -166
  57. package/src/templates/scripts/configure-wordpress-mcp.js +0 -181
@@ -0,0 +1,425 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MyAIDev Method - Security Environment Detection
5
+ *
6
+ * Detects execution environment and recommends setup approach
7
+ * @module security/environment-detect
8
+ */
9
+
10
+ import { execSync } from 'child_process';
11
+ import fs from 'fs';
12
+
13
+ /**
14
+ * Environment types
15
+ */
16
+ const EnvType = {
17
+ KALI_NATIVE: 'kali_native',
18
+ KALI_DOCKER: 'kali_docker',
19
+ UBUNTU_NATIVE: 'ubuntu_native',
20
+ DEBIAN_NATIVE: 'debian_native',
21
+ FEDORA_NATIVE: 'fedora_native',
22
+ DOCKER_CONTAINER: 'docker_container',
23
+ UNKNOWN: 'unknown'
24
+ };
25
+
26
+ /**
27
+ * Environment detection class
28
+ */
29
+ class EnvironmentDetector {
30
+ constructor() {
31
+ this.osInfo = {};
32
+ this.containerInfo = {};
33
+ this.toolsInfo = {};
34
+ }
35
+
36
+ /**
37
+ * Detect execution environment
38
+ */
39
+ async detect() {
40
+ console.log('šŸ” Detecting security testing environment...\n');
41
+
42
+ // Detect OS
43
+ this.detectOS();
44
+
45
+ // Detect container environment
46
+ this.detectContainer();
47
+
48
+ // Check Docker availability
49
+ this.detectDocker();
50
+
51
+ // Check existing tools
52
+ this.detectTools();
53
+
54
+ // Generate recommendation
55
+ const recommendation = this.generateRecommendation();
56
+
57
+ // Display results
58
+ this.displayResults(recommendation);
59
+
60
+ return {
61
+ os: this.osInfo,
62
+ container: this.containerInfo,
63
+ tools: this.toolsInfo,
64
+ recommendation
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Detect operating system
70
+ */
71
+ detectOS() {
72
+ try {
73
+ // Check if /etc/os-release exists
74
+ if (fs.existsSync('/etc/os-release')) {
75
+ const osRelease = fs.readFileSync('/etc/os-release', 'utf8');
76
+
77
+ // Parse OS release file
78
+ const lines = osRelease.split('\n');
79
+ for (const line of lines) {
80
+ const [key, value] = line.split('=');
81
+ if (value) {
82
+ this.osInfo[key] = value.replace(/"/g, '');
83
+ }
84
+ }
85
+
86
+ // Determine OS type
87
+ const id = this.osInfo.ID || '';
88
+ if (id.includes('kali')) {
89
+ this.osInfo.type = EnvType.KALI_NATIVE;
90
+ } else if (id.includes('ubuntu')) {
91
+ this.osInfo.type = EnvType.UBUNTU_NATIVE;
92
+ } else if (id.includes('debian')) {
93
+ this.osInfo.type = EnvType.DEBIAN_NATIVE;
94
+ } else if (id.includes('fedora') || id.includes('rhel') || id.includes('centos')) {
95
+ this.osInfo.type = EnvType.FEDORA_NATIVE;
96
+ } else {
97
+ this.osInfo.type = EnvType.UNKNOWN;
98
+ }
99
+ }
100
+
101
+ // Get kernel version
102
+ try {
103
+ this.osInfo.kernel = execSync('uname -r', { encoding: 'utf8' }).trim();
104
+ } catch (err) {
105
+ this.osInfo.kernel = 'unknown';
106
+ }
107
+
108
+ // Detect package manager
109
+ if (this.commandExists('apt')) {
110
+ this.osInfo.packageManager = 'apt';
111
+ } else if (this.commandExists('dnf')) {
112
+ this.osInfo.packageManager = 'dnf';
113
+ } else if (this.commandExists('yum')) {
114
+ this.osInfo.packageManager = 'yum';
115
+ } else if (this.commandExists('pacman')) {
116
+ this.osInfo.packageManager = 'pacman';
117
+ } else {
118
+ this.osInfo.packageManager = 'unknown';
119
+ }
120
+
121
+ } catch (err) {
122
+ console.error('Error detecting OS:', err.message);
123
+ this.osInfo.type = EnvType.UNKNOWN;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Detect container environment
129
+ */
130
+ detectContainer() {
131
+ try {
132
+ // Check for /.dockerenv
133
+ if (fs.existsSync('/.dockerenv')) {
134
+ this.containerInfo.isContainer = true;
135
+ this.containerInfo.type = 'docker';
136
+ return;
137
+ }
138
+
139
+ // Check cgroup for docker/container
140
+ if (fs.existsSync('/proc/1/cgroup')) {
141
+ const cgroup = fs.readFileSync('/proc/1/cgroup', 'utf8');
142
+ if (cgroup.includes('docker')) {
143
+ this.containerInfo.isContainer = true;
144
+ this.containerInfo.type = 'docker';
145
+ return;
146
+ }
147
+ if (cgroup.includes('kubepods')) {
148
+ this.containerInfo.isContainer = true;
149
+ this.containerInfo.type = 'kubernetes';
150
+ return;
151
+ }
152
+ }
153
+
154
+ this.containerInfo.isContainer = false;
155
+ } catch (err) {
156
+ this.containerInfo.isContainer = false;
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Detect Docker availability
162
+ */
163
+ detectDocker() {
164
+ try {
165
+ if (this.commandExists('docker')) {
166
+ const version = execSync('docker --version', { encoding: 'utf8' }).trim();
167
+ this.containerInfo.dockerAvailable = true;
168
+ this.containerInfo.dockerVersion = version;
169
+
170
+ // Check if Docker daemon is running
171
+ try {
172
+ execSync('docker ps', { encoding: 'utf8', stdio: 'ignore' });
173
+ this.containerInfo.dockerRunning = true;
174
+ } catch (err) {
175
+ this.containerInfo.dockerRunning = false;
176
+ }
177
+ } else {
178
+ this.containerInfo.dockerAvailable = false;
179
+ }
180
+ } catch (err) {
181
+ this.containerInfo.dockerAvailable = false;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Detect existing security tools
187
+ */
188
+ detectTools() {
189
+ const essentialTools = [
190
+ 'nmap',
191
+ 'masscan',
192
+ 'sqlmap',
193
+ 'nikto',
194
+ 'hydra',
195
+ 'john',
196
+ 'hashcat',
197
+ 'metasploit-framework',
198
+ 'burpsuite',
199
+ 'zaproxy'
200
+ ];
201
+
202
+ const commandMap = {
203
+ 'metasploit-framework': 'msfconsole',
204
+ 'burpsuite': 'burpsuite',
205
+ 'zaproxy': 'zaproxy'
206
+ };
207
+
208
+ const installed = [];
209
+ const missing = [];
210
+
211
+ for (const tool of essentialTools) {
212
+ const command = commandMap[tool] || tool;
213
+ if (this.commandExists(command)) {
214
+ installed.push(tool);
215
+ } else {
216
+ missing.push(tool);
217
+ }
218
+ }
219
+
220
+ this.toolsInfo.installed = installed;
221
+ this.toolsInfo.missing = missing;
222
+ this.toolsInfo.installCount = installed.length;
223
+ this.toolsInfo.totalCount = essentialTools.length;
224
+ this.toolsInfo.percentInstalled = Math.round((installed.length / essentialTools.length) * 100);
225
+ }
226
+
227
+ /**
228
+ * Check if command exists
229
+ */
230
+ commandExists(command) {
231
+ try {
232
+ execSync(`which ${command}`, { stdio: 'ignore' });
233
+ return true;
234
+ } catch (err) {
235
+ return false;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Generate setup recommendation
241
+ */
242
+ generateRecommendation() {
243
+ const rec = {
244
+ approach: '',
245
+ reason: '',
246
+ steps: [],
247
+ estimatedTime: '',
248
+ diskSpace: ''
249
+ };
250
+
251
+ // If already Kali Linux
252
+ if (this.osInfo.type === EnvType.KALI_NATIVE) {
253
+ rec.approach = 'verify_tools';
254
+ rec.reason = 'Kali Linux detected - most tools pre-installed';
255
+ rec.steps = [
256
+ 'Update package lists: sudo apt update',
257
+ 'Upgrade packages: sudo apt upgrade',
258
+ 'Verify tool installations',
259
+ 'Install any missing tools'
260
+ ];
261
+ rec.estimatedTime = '10-15 minutes';
262
+ rec.diskSpace = '~500MB';
263
+ return rec;
264
+ }
265
+
266
+ // If Kali Docker available
267
+ if (this.containerInfo.dockerAvailable && this.containerInfo.dockerRunning) {
268
+ rec.approach = 'kali_docker';
269
+ rec.reason = 'Docker available - isolated environment recommended';
270
+ rec.steps = [
271
+ 'Pull Kali Linux Docker image',
272
+ 'Create persistent volume',
273
+ 'Start Kali container with capabilities',
274
+ 'Install kali-linux-default package',
275
+ 'Verify tool installations'
276
+ ];
277
+ rec.estimatedTime = '20-30 minutes';
278
+ rec.diskSpace = '~3GB';
279
+ return rec;
280
+ }
281
+
282
+ // If Docker available but not running
283
+ if (this.containerInfo.dockerAvailable && !this.containerInfo.dockerRunning) {
284
+ rec.approach = 'kali_docker';
285
+ rec.reason = 'Docker installed but not running';
286
+ rec.steps = [
287
+ 'Start Docker service: sudo systemctl start docker',
288
+ 'Pull Kali Linux Docker image',
289
+ 'Create persistent volume',
290
+ 'Start Kali container',
291
+ 'Install security tools'
292
+ ];
293
+ rec.estimatedTime = '25-35 minutes';
294
+ rec.diskSpace = '~3GB';
295
+ return rec;
296
+ }
297
+
298
+ // Native installation (no Docker)
299
+ if (this.osInfo.type === EnvType.UBUNTU_NATIVE ||
300
+ this.osInfo.type === EnvType.DEBIAN_NATIVE) {
301
+ rec.approach = 'native_install';
302
+ rec.reason = 'Native Linux installation - direct tool installation';
303
+ rec.steps = [
304
+ 'Update package lists',
305
+ 'Install network scanning tools (nmap, masscan)',
306
+ 'Install web testing tools (sqlmap, nikto)',
307
+ 'Install exploitation tools (metasploit)',
308
+ 'Install password tools (john, hashcat, hydra)',
309
+ 'Verify installations'
310
+ ];
311
+ rec.estimatedTime = '45-60 minutes';
312
+ rec.diskSpace = '~2GB';
313
+ return rec;
314
+ }
315
+
316
+ // Fedora/RHEL/CentOS
317
+ if (this.osInfo.type === EnvType.FEDORA_NATIVE) {
318
+ rec.approach = 'native_install';
319
+ rec.reason = 'Fedora/RHEL system - native installation with DNF';
320
+ rec.steps = [
321
+ 'Enable EPEL repository',
322
+ 'Update system: sudo dnf update',
323
+ 'Install security tools via DNF',
324
+ 'Install remaining tools from source',
325
+ 'Verify installations'
326
+ ];
327
+ rec.estimatedTime = '45-60 minutes';
328
+ rec.diskSpace = '~2GB';
329
+ return rec;
330
+ }
331
+
332
+ // Fallback - recommend Docker
333
+ rec.approach = 'install_docker_first';
334
+ rec.reason = 'Unknown environment - Docker installation recommended';
335
+ rec.steps = [
336
+ 'Install Docker: curl -fsSL https://get.docker.com | sh',
337
+ 'Start Docker service',
338
+ 'Follow Kali Docker setup',
339
+ 'Install security tools in container'
340
+ ];
341
+ rec.estimatedTime = '30-45 minutes';
342
+ rec.diskSpace = '~3.5GB';
343
+ return rec;
344
+ }
345
+
346
+ /**
347
+ * Display detection results
348
+ */
349
+ displayResults(recommendation) {
350
+ console.log('═══════════════════════════════════════════════════════');
351
+ console.log('šŸ” Environment Detection Results');
352
+ console.log('═══════════════════════════════════════════════════════\n');
353
+
354
+ // OS Information
355
+ console.log('šŸ“‹ Operating System:');
356
+ console.log(` Name: ${this.osInfo.NAME || 'Unknown'}`);
357
+ console.log(` Version: ${this.osInfo.VERSION || 'Unknown'}`);
358
+ console.log(` ID: ${this.osInfo.ID || 'Unknown'}`);
359
+ console.log(` Kernel: ${this.osInfo.kernel || 'Unknown'}`);
360
+ console.log(` Package Manager: ${this.osInfo.packageManager || 'Unknown'}\n`);
361
+
362
+ // Container Information
363
+ console.log('🐳 Container Environment:');
364
+ console.log(` Running in Container: ${this.containerInfo.isContainer ? 'Yes' : 'No'}`);
365
+ if (this.containerInfo.isContainer) {
366
+ console.log(` Container Type: ${this.containerInfo.type}`);
367
+ }
368
+ console.log(` Docker Available: ${this.containerInfo.dockerAvailable ? 'Yes' : 'No'}`);
369
+ if (this.containerInfo.dockerAvailable) {
370
+ console.log(` Docker Version: ${this.containerInfo.dockerVersion}`);
371
+ console.log(` Docker Running: ${this.containerInfo.dockerRunning ? 'Yes' : 'No'}`);
372
+ }
373
+ console.log();
374
+
375
+ // Security Tools
376
+ console.log('šŸ› ļø Security Tools:');
377
+ console.log(` Installed: ${this.toolsInfo.installCount}/${this.toolsInfo.totalCount} (${this.toolsInfo.percentInstalled}%)`);
378
+ if (this.toolsInfo.installed.length > 0) {
379
+ console.log(` Found: ${this.toolsInfo.installed.slice(0, 5).join(', ')}${this.toolsInfo.installed.length > 5 ? '...' : ''}`);
380
+ }
381
+ console.log();
382
+
383
+ // Recommendation
384
+ console.log('═══════════════════════════════════════════════════════');
385
+ console.log('šŸ“‹ Recommended Setup Approach');
386
+ console.log('═══════════════════════════════════════════════════════\n');
387
+ console.log(`✨ Approach: ${recommendation.approach.toUpperCase().replace(/_/g, ' ')}`);
388
+ console.log(`šŸ“ Reason: ${recommendation.reason}`);
389
+ console.log(`ā±ļø Estimated Time: ${recommendation.estimatedTime}`);
390
+ console.log(`šŸ’¾ Disk Space: ${recommendation.diskSpace}\n`);
391
+
392
+ console.log('šŸ“ Setup Steps:');
393
+ recommendation.steps.forEach((step, index) => {
394
+ console.log(` ${index + 1}. ${step}`);
395
+ });
396
+ console.log();
397
+
398
+ console.log('═══════════════════════════════════════════════════════\n');
399
+ }
400
+ }
401
+
402
+ /**
403
+ * Main execution
404
+ */
405
+ async function main() {
406
+ const detector = new EnvironmentDetector();
407
+ const result = await detector.detect();
408
+
409
+ // Save results to JSON for programmatic use
410
+ const outputPath = '/tmp/security-env-detect.json';
411
+ fs.writeFileSync(outputPath, JSON.stringify(result, null, 2));
412
+ console.log(`šŸ“„ Results saved to: ${outputPath}\n`);
413
+
414
+ process.exit(0);
415
+ }
416
+
417
+ // Run if executed directly
418
+ if (import.meta.url === `file://${process.argv[1]}`) {
419
+ main().catch(err => {
420
+ console.error('āŒ Error:', err.message);
421
+ process.exit(1);
422
+ });
423
+ }
424
+
425
+ export { EnvironmentDetector, EnvType };
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Publish markdown content to WordPress
4
+ *
5
+ * Usage: node publish-to-wordpress.js <file-path> [--status draft|publish]
6
+ */
7
+
8
+ import { readFileSync } from "fs";
9
+ import { resolve } from "path";
10
+ import matter from "gray-matter";
11
+ import dotenv from "dotenv";
12
+ import { marked } from "marked";
13
+ import { GutenbergConverter } from "../../mcp/gutenberg-converter.js";
14
+ import { WordPressMCP } from "../../mcp/wordpress-integration.js";
15
+
16
+ // Load environment variables
17
+ dotenv.config();
18
+
19
+ // Parse command line arguments
20
+ const args = process.argv.slice(2);
21
+ const filePath = args[0];
22
+ const statusIndex = args.indexOf("--status");
23
+ const requestedStatus =
24
+ statusIndex !== -1 && args[statusIndex + 1] ? args[statusIndex + 1] : "draft";
25
+
26
+ if (!filePath) {
27
+ console.error("Error: File path is required");
28
+ console.error(
29
+ "Usage: node publish-to-wordpress.js <file-path> [--status draft|publish]",
30
+ );
31
+ process.exit(1);
32
+ }
33
+
34
+ // Validate WordPress configuration
35
+ if (
36
+ !process.env.WORDPRESS_URL ||
37
+ !process.env.WORDPRESS_USERNAME ||
38
+ !process.env.WORDPRESS_APP_PASSWORD
39
+ ) {
40
+ console.error("Error: WordPress configuration is incomplete");
41
+ console.error("Required environment variables:");
42
+ console.error(" - WORDPRESS_URL");
43
+ console.error(" - WORDPRESS_USERNAME");
44
+ console.error(" - WORDPRESS_APP_PASSWORD");
45
+ console.error(
46
+ "\nRun /myai-configure wordpress to set up your WordPress connection",
47
+ );
48
+ process.exit(1);
49
+ }
50
+
51
+ async function publishToWordPress() {
52
+ try {
53
+ // Read and parse markdown file
54
+ const absolutePath = resolve(filePath);
55
+ const fileContent = readFileSync(absolutePath, "utf-8");
56
+ const { data: frontmatter, content } = matter(fileContent);
57
+
58
+ console.log("šŸ“„ Processing file:", filePath);
59
+ console.log("šŸ“‹ Title:", frontmatter.title || "No title");
60
+
61
+ // Extract interactive blocks before markdown conversion
62
+ // const { markdown: cleanMarkdown, interactiveBlocks } =
63
+ // GutenbergConverter.extractInteractiveBlocks(content);
64
+
65
+ // if (interactiveBlocks.length > 0) {
66
+ // console.log(
67
+ // ` Interactive blocks: ${interactiveBlocks.length} found`,
68
+ // );
69
+ // }
70
+
71
+ // Convert markdown to HTML using marked (preserves placeholders)
72
+ const html = marked.parse(content);
73
+
74
+ // Convert HTML to Gutenberg blocks
75
+ let htmlContent = GutenbergConverter.htmlToGutenberg(html);
76
+
77
+ // Restore interactive blocks as raw HTML blocks
78
+ // if (interactiveBlocks.length > 0) {
79
+ // htmlContent = GutenbergConverter.restoreInteractiveBlocks(
80
+ // htmlContent,
81
+ // interactiveBlocks,
82
+ // );
83
+ // }
84
+
85
+ // Prepare WordPress configuration
86
+ const config = {
87
+ endpoint: {
88
+ url: process.env.WORDPRESS_URL,
89
+ api_version: "wp/v2",
90
+ authentication: {
91
+ username: process.env.WORDPRESS_USERNAME,
92
+ password: process.env.WORDPRESS_APP_PASSWORD,
93
+ },
94
+ },
95
+ defaults: {
96
+ post_status: requestedStatus,
97
+ format: "standard",
98
+ comment_status: "open",
99
+ ping_status: "open",
100
+ },
101
+ };
102
+
103
+ // Initialize WordPress client
104
+ const wp = new WordPressMCP(config);
105
+
106
+ // Prepare post data
107
+ const postParams = {
108
+ title: frontmatter.title || "Untitled",
109
+ content: htmlContent,
110
+ status: requestedStatus,
111
+ excerpt: frontmatter.meta_description || "",
112
+ slug: frontmatter.slug || "",
113
+ use_gutenberg: process.env.USE_GUTENBERG === "true",
114
+ // Note: Tags and categories require ID mapping which will be added in future versions
115
+ };
116
+
117
+ console.log("šŸš€ Publishing to WordPress...");
118
+ console.log(" URL:", process.env.WORDPRESS_URL);
119
+ console.log(" Status:", requestedStatus);
120
+ console.log(
121
+ " Format:",
122
+ postParams.use_gutenberg ? "Gutenberg" : "Classic",
123
+ );
124
+
125
+ // Create the post
126
+ const result = await wp.createPost(postParams);
127
+
128
+ // Success!
129
+ console.log("\nāœ… Successfully published to WordPress!");
130
+ console.log("\nšŸ“„ Post Details:");
131
+ console.log(" Post ID:", result.id);
132
+ console.log(" Title:", result.title.rendered);
133
+ console.log(" Status:", result.status);
134
+ console.log(" Slug:", result.slug);
135
+
136
+ console.log("\nšŸ”— URLs:");
137
+ console.log(" View:", result.link);
138
+ console.log(
139
+ " Edit:",
140
+ `${process.env.WORDPRESS_URL}/wp-admin/post.php?post=${result.id}&action=edit`,
141
+ );
142
+
143
+ return result;
144
+ } catch (error) {
145
+ console.error("\nāŒ Error publishing to WordPress:");
146
+ console.error(error.message);
147
+
148
+ if (error.message.includes("401")) {
149
+ console.error("\nšŸ”‘ Authentication failed. Please check:");
150
+ console.error(" 1. Your WordPress username is correct");
151
+ console.error(" 2. Your Application Password is valid");
152
+ console.error(" 3. Application Passwords are enabled on your site");
153
+ } else if (error.message.includes("404")) {
154
+ console.error("\n🌐 WordPress site not found. Please check:");
155
+ console.error(" 1. Your WORDPRESS_URL is correct");
156
+ console.error(" 2. The site is accessible");
157
+ console.error(" 3. The REST API is enabled");
158
+ }
159
+
160
+ process.exit(1);
161
+ }
162
+ }
163
+
164
+ // Run the publisher
165
+ publishToWordPress();
@@ -6,7 +6,7 @@ import { AuthError, JWTPayload } from "../../../shared/types.js";
6
6
  const TOKEN_EXPIRY_DAYS = 7;
7
7
  const ALGORITHM = "RS256";
8
8
 
9
- let keyPair: { publicKey: jose.KeyLike; privateKey: jose.KeyLike } | null = null;
9
+ let keyPair: { publicKey: jose.CryptoKey; privateKey: jose.CryptoKey } | null = null;
10
10
 
11
11
  export class TokenService extends Context.Tag("TokenService")<
12
12
  TokenService,