myaidev-method 0.3.2 → 0.3.4

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 (80) hide show
  1. package/.claude-plugin/plugin.json +52 -48
  2. package/DEV_WORKFLOW_GUIDE.md +6 -6
  3. package/MCP_INTEGRATION.md +4 -4
  4. package/README.md +81 -64
  5. package/TECHNICAL_ARCHITECTURE.md +112 -18
  6. package/USER_GUIDE.md +57 -40
  7. package/bin/cli.js +49 -127
  8. package/dist/mcp/gutenberg-converter.js +667 -413
  9. package/dist/mcp/wordpress-server.js +1558 -1181
  10. package/extension.json +3 -3
  11. package/package.json +2 -1
  12. package/skills/content-writer/SKILL.md +130 -178
  13. package/skills/infographic/SKILL.md +191 -0
  14. package/skills/myaidev-analyze/SKILL.md +242 -0
  15. package/skills/myaidev-analyze/agents/dependency-mapper-agent.md +236 -0
  16. package/skills/myaidev-analyze/agents/pattern-detector-agent.md +240 -0
  17. package/skills/myaidev-analyze/agents/structure-scanner-agent.md +171 -0
  18. package/skills/myaidev-analyze/agents/tech-profiler-agent.md +291 -0
  19. package/skills/myaidev-architect/SKILL.md +389 -0
  20. package/skills/myaidev-architect/agents/compliance-checker-agent.md +287 -0
  21. package/skills/myaidev-architect/agents/requirements-analyst-agent.md +194 -0
  22. package/skills/myaidev-architect/agents/system-designer-agent.md +315 -0
  23. package/skills/myaidev-coder/SKILL.md +291 -0
  24. package/skills/myaidev-coder/agents/implementer-agent.md +185 -0
  25. package/skills/myaidev-coder/agents/integration-agent.md +168 -0
  26. package/skills/myaidev-coder/agents/pattern-scanner-agent.md +161 -0
  27. package/skills/myaidev-coder/agents/self-reviewer-agent.md +168 -0
  28. package/skills/myaidev-debug/SKILL.md +308 -0
  29. package/skills/myaidev-debug/agents/fix-agent-debug.md +317 -0
  30. package/skills/myaidev-debug/agents/hypothesis-agent.md +226 -0
  31. package/skills/myaidev-debug/agents/investigator-agent.md +250 -0
  32. package/skills/myaidev-debug/agents/symptom-collector-agent.md +231 -0
  33. package/skills/myaidev-documenter/SKILL.md +194 -0
  34. package/skills/myaidev-documenter/agents/code-reader-agent.md +172 -0
  35. package/skills/myaidev-documenter/agents/doc-validator-agent.md +174 -0
  36. package/skills/myaidev-documenter/agents/doc-writer-agent.md +379 -0
  37. package/skills/myaidev-migrate/SKILL.md +300 -0
  38. package/skills/myaidev-migrate/agents/migration-planner-agent.md +237 -0
  39. package/skills/myaidev-migrate/agents/migration-writer-agent.md +248 -0
  40. package/skills/myaidev-migrate/agents/schema-analyzer-agent.md +190 -0
  41. package/skills/myaidev-performance/SKILL.md +270 -0
  42. package/skills/myaidev-performance/agents/benchmark-agent.md +281 -0
  43. package/skills/myaidev-performance/agents/optimizer-agent.md +277 -0
  44. package/skills/myaidev-performance/agents/profiler-agent.md +252 -0
  45. package/skills/myaidev-refactor/SKILL.md +296 -0
  46. package/skills/myaidev-refactor/agents/refactor-executor-agent.md +221 -0
  47. package/skills/myaidev-refactor/agents/refactor-planner-agent.md +213 -0
  48. package/skills/myaidev-refactor/agents/regression-guard-agent.md +242 -0
  49. package/skills/myaidev-refactor/agents/smell-detector-agent.md +233 -0
  50. package/skills/myaidev-reviewer/SKILL.md +385 -0
  51. package/skills/myaidev-reviewer/agents/auto-fixer-agent.md +238 -0
  52. package/skills/myaidev-reviewer/agents/code-analyst-agent.md +220 -0
  53. package/skills/myaidev-reviewer/agents/security-scanner-agent.md +262 -0
  54. package/skills/myaidev-tester/SKILL.md +331 -0
  55. package/skills/myaidev-tester/agents/coverage-analyst-agent.md +163 -0
  56. package/skills/myaidev-tester/agents/tdd-driver-agent.md +242 -0
  57. package/skills/myaidev-tester/agents/test-runner-agent.md +176 -0
  58. package/skills/myaidev-tester/agents/test-strategist-agent.md +154 -0
  59. package/skills/myaidev-tester/agents/test-writer-agent.md +242 -0
  60. package/skills/myaidev-workflow/SKILL.md +567 -0
  61. package/skills/myaidev-workflow/agents/analyzer-agent.md +317 -0
  62. package/skills/myaidev-workflow/agents/coordinator-agent.md +253 -0
  63. package/skills/security-auditor/SKILL.md +1 -1
  64. package/skills/skill-builder/SKILL.md +417 -0
  65. package/src/cli/commands/addon.js +146 -135
  66. package/src/cli/commands/auth.js +9 -1
  67. package/src/config/workflows.js +11 -6
  68. package/src/lib/ascii-banner.js +3 -3
  69. package/src/lib/update-manager.js +120 -61
  70. package/src/mcp/gutenberg-converter.js +667 -413
  71. package/src/mcp/wordpress-server.js +1558 -1181
  72. package/src/statusline/statusline.sh +279 -0
  73. package/src/templates/claude/CLAUDE.md +124 -0
  74. package/skills/sparc-architect/SKILL.md +0 -127
  75. package/skills/sparc-coder/SKILL.md +0 -90
  76. package/skills/sparc-documenter/SKILL.md +0 -155
  77. package/skills/sparc-reviewer/SKILL.md +0 -138
  78. package/skills/sparc-tester/SKILL.md +0 -100
  79. package/skills/sparc-workflow/SKILL.md +0 -130
  80. /package/{marketplace.json → .claude-plugin/marketplace.json} +0 -0
@@ -17,16 +17,24 @@ import inquirer from 'inquirer';
17
17
  import fs from 'fs-extra';
18
18
  import path from 'path';
19
19
  import os from 'os';
20
- import { execSync } from 'child_process';
20
+
21
21
  import matter from 'gray-matter';
22
22
  import { isAuthenticated, getAuthToken, getAuthData, authFetch } from '../../lib/auth-helper.js';
23
23
  import { validateSkill, generateSlug } from '../../lib/skill-validator.js';
24
24
 
25
25
  const API_BASE = 'https://dev.myai1.ai/api/skills';
26
26
  const MARKETPLACE_REPO = 'myaione/myaidev-marketplace';
27
+ const FETCH_TIMEOUT_MS = 10000;
27
28
 
28
29
  // ── Helpers ─────────────────────────────────────────────────────────────
29
30
 
31
+ function fetchWithTimeout(url, options = {}, timeoutMs = FETCH_TIMEOUT_MS) {
32
+ const controller = new AbortController();
33
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
34
+ return fetch(url, { ...options, signal: controller.signal })
35
+ .finally(() => clearTimeout(timeout));
36
+ }
37
+
30
38
  function projectSkillsDir() {
31
39
  return path.join(process.cwd(), '.claude', 'skills');
32
40
  }
@@ -57,6 +65,7 @@ async function requireAuth() {
57
65
  export function registerAddonCommand(program) {
58
66
  const addon = program
59
67
  .command('addon [name]')
68
+ .enablePositionalOptions()
60
69
  .description('Install a skill from the MyAIDev marketplace')
61
70
  .option('--project', 'Install to project .claude/skills/')
62
71
  .option('--global', 'Install to global ~/.claude/skills/')
@@ -68,6 +77,16 @@ export function registerAddonCommand(program) {
68
77
  await installSkill(name, options);
69
78
  });
70
79
 
80
+ // ── addon install ───────────────────────────────────────────────────
81
+ addon
82
+ .command('install <name>')
83
+ .description('Install a skill from the marketplace')
84
+ .option('--project', 'Install to project .claude/skills/')
85
+ .option('--global', 'Install to global ~/.claude/skills/')
86
+ .action(async (name, opts) => {
87
+ await installSkill(name, opts);
88
+ });
89
+
71
90
  // ── addon list ──────────────────────────────────────────────────────
72
91
  addon
73
92
  .command('list')
@@ -154,7 +173,7 @@ async function installSkill(name, options) {
154
173
 
155
174
  try {
156
175
  // Search for skill
157
- const res = await fetch(`${API_BASE}?search=${encodeURIComponent(name)}&limit=5`);
176
+ const res = await fetchWithTimeout(`${API_BASE}?search=${encodeURIComponent(name)}&limit=5`);
158
177
  if (!res.ok) throw new Error(`API error: ${res.status}`);
159
178
  const body = await res.json();
160
179
  const skills = body.skills || [];
@@ -196,11 +215,12 @@ async function installSkill(name, options) {
196
215
  const { location } = await inquirer.prompt([{
197
216
  type: 'list',
198
217
  name: 'location',
199
- message: 'Install location:',
218
+ message: 'Where do you want to install this skill?',
200
219
  choices: [
201
- { name: `Project ${chalk.gray('.claude/skills/')}`, value: 'project' },
202
- { name: `Global ${chalk.gray('~/.claude/skills/')}`, value: 'global' },
220
+ { name: `Project ${chalk.gray('.claude/skills/ (this project only)')}`, value: 'project' },
221
+ { name: `Global ${chalk.gray('~/.claude/skills/ (available everywhere)')}`, value: 'global' },
203
222
  ],
223
+ default: 'project',
204
224
  }]);
205
225
  targetDir = location === 'project' ? projectSkillsDir() : globalSkillsDir();
206
226
  }
@@ -210,14 +230,23 @@ async function installSkill(name, options) {
210
230
 
211
231
  // Download
212
232
  const dlSpinner = ora(`Downloading ${chalk.cyan(skill.name)}...`).start();
213
- const dlRes = await fetch(`${API_BASE}/${skill.id}/download`);
233
+ const dlRes = await fetchWithTimeout(`${API_BASE}/${skill.id}/download`);
214
234
  if (!dlRes.ok) throw new Error(`Download failed: ${dlRes.status}`);
215
- const dlBody = await dlRes.json();
216
235
 
217
- if (!dlBody.content) throw new Error('Skill content is empty');
236
+ // Handle both JSON and raw markdown responses
237
+ const contentType = dlRes.headers.get('content-type') || '';
238
+ let content;
239
+ if (contentType.includes('application/json')) {
240
+ const dlBody = await dlRes.json();
241
+ content = dlBody.content;
242
+ } else {
243
+ content = await dlRes.text();
244
+ }
245
+
246
+ if (!content) throw new Error('Skill content is empty');
218
247
 
219
248
  await fs.ensureDir(installPath);
220
- await fs.writeFile(path.join(installPath, 'SKILL.md'), dlBody.content, 'utf8');
249
+ await fs.writeFile(path.join(installPath, 'SKILL.md'), content, 'utf8');
221
250
 
222
251
  dlSpinner.succeed(chalk.green(`Installed ${chalk.bold(skill.name)}`));
223
252
 
@@ -225,7 +254,13 @@ async function installSkill(name, options) {
225
254
  console.log(chalk.gray(` → ${rel}/SKILL.md`));
226
255
  console.log(chalk.cyan('\n Restart Claude Code to load the new skill.\n'));
227
256
  } catch (err) {
228
- spinner.fail(chalk.red(`Failed to install: ${err.message}`));
257
+ if (err.name === 'AbortError') {
258
+ spinner.fail(chalk.red('Request timed out. Check your internet connection.'));
259
+ } else if (err.cause?.code === 'ENOTFOUND' || err.message?.includes('ENOTFOUND')) {
260
+ spinner.fail(chalk.red('Cannot reach marketplace API. Check your internet connection.'));
261
+ } else {
262
+ spinner.fail(chalk.red(`Failed to install: ${err.message}`));
263
+ }
229
264
  process.exit(1);
230
265
  }
231
266
  }
@@ -241,7 +276,7 @@ async function listMarketplace(opts) {
241
276
  if (opts.sort) params.set('sort', opts.sort);
242
277
  params.set('limit', opts.limit || '20');
243
278
 
244
- const res = await fetch(`${API_BASE}?${params}`);
279
+ const res = await fetchWithTimeout(`${API_BASE}?${params}`);
245
280
  if (!res.ok) throw new Error(`API error: ${res.status}`);
246
281
  const body = await res.json();
247
282
  const skills = body.skills || [];
@@ -264,15 +299,22 @@ async function listMarketplace(opts) {
264
299
  for (const s of skills) {
265
300
  const stars = String(s.stars ?? 0).padStart(3);
266
301
  const downloads = String(s.downloads ?? 0).padStart(5);
302
+ const author = s.authorName || s.author || 'unknown';
267
303
  console.log(
268
- ` ${chalk.green(pad(s.name, 24))} ${chalk.gray(pad(truncate(s.description, 38), 40))} ${chalk.white(pad(truncate(s.author, 14), 16))} ${chalk.yellow(stars)} ${chalk.blue(downloads)}`
304
+ ` ${chalk.green(pad(s.name, 24))} ${chalk.gray(pad(truncate(s.description, 38), 40))} ${chalk.white(pad(truncate(author, 14), 16))} ${chalk.yellow(stars)} ${chalk.blue(downloads)}`
269
305
  );
270
306
  }
271
307
 
272
308
  console.log(chalk.gray('\n Install: myaidev-method addon <name>'));
273
309
  console.log(chalk.gray(' Search: myaidev-method addon search <query>\n'));
274
310
  } catch (err) {
275
- spinner.fail(chalk.red(`Failed to fetch marketplace: ${err.message}`));
311
+ if (err.name === 'AbortError') {
312
+ spinner.fail(chalk.red('Request timed out. Check your internet connection.'));
313
+ } else if (err.cause?.code === 'ENOTFOUND' || err.message?.includes('ENOTFOUND')) {
314
+ spinner.fail(chalk.red('Cannot reach marketplace API. Check your internet connection.'));
315
+ } else {
316
+ spinner.fail(chalk.red(`Failed to fetch marketplace: ${err.message}`));
317
+ }
276
318
  process.exit(1);
277
319
  }
278
320
  }
@@ -284,7 +326,7 @@ async function searchMarketplace(query, opts) {
284
326
 
285
327
  try {
286
328
  const params = new URLSearchParams({ search: query, limit: opts.limit || '10' });
287
- const res = await fetch(`${API_BASE}?${params}`);
329
+ const res = await fetchWithTimeout(`${API_BASE}?${params}`);
288
330
  if (!res.ok) throw new Error(`API error: ${res.status}`);
289
331
  const body = await res.json();
290
332
  const skills = body.skills || [];
@@ -301,19 +343,26 @@ async function searchMarketplace(query, opts) {
301
343
  for (const s of skills) {
302
344
  const stars = s.stars ?? 0;
303
345
  const downloads = s.downloads ?? 0;
346
+ const author = s.authorName || s.author || 'unknown';
304
347
  // Highlight matching parts of the name
305
348
  const highlighted = s.name.replace(
306
349
  new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi'),
307
350
  (m) => chalk.yellow.bold(m)
308
351
  );
309
352
 
310
- console.log(` ${chalk.green('●')} ${highlighted} ${chalk.gray(`by ${s.author}`)}`);
353
+ console.log(` ${chalk.green('●')} ${highlighted} ${chalk.gray(`by ${author}`)}`);
311
354
  console.log(` ${chalk.gray(truncate(s.description, 70))}`);
312
355
  console.log(` ${chalk.yellow(`⭐ ${stars}`)} ${chalk.blue(`⬇ ${downloads}`)} ${chalk.gray(`Install: myaidev-method addon ${s.slug || s.name.toLowerCase().replace(/\s+/g, '-')}`)}`);
313
356
  console.log('');
314
357
  }
315
358
  } catch (err) {
316
- spinner.fail(chalk.red(`Search failed: ${err.message}`));
359
+ if (err.name === 'AbortError') {
360
+ spinner.fail(chalk.red('Request timed out. Check your internet connection.'));
361
+ } else if (err.cause?.code === 'ENOTFOUND' || err.message?.includes('ENOTFOUND')) {
362
+ spinner.fail(chalk.red('Cannot reach marketplace API. Check your internet connection.'));
363
+ } else {
364
+ spinner.fail(chalk.red(`Search failed: ${err.message}`));
365
+ }
317
366
  process.exit(1);
318
367
  }
319
368
  }
@@ -648,26 +697,10 @@ async function scaffoldSkill() {
648
697
  return targetDir;
649
698
  }
650
699
 
651
- function ghAvailable() {
652
- try {
653
- execSync('gh auth status', { stdio: 'pipe' });
654
- return true;
655
- } catch {
656
- return false;
657
- }
658
- }
659
-
660
700
  async function submitSkill(opts) {
661
- // Step 1: Auth checks
701
+ // Step 1: Auth check
662
702
  if (!(await requireAuth())) return;
663
703
 
664
- if (!ghAvailable()) {
665
- console.log(chalk.red('\n✗ GitHub CLI (gh) is required for submissions.'));
666
- console.log(chalk.gray(' Install: https://cli.github.com'));
667
- console.log(chalk.gray(' Then: gh auth login\n'));
668
- return;
669
- }
670
-
671
704
  // Step 2: Detect or scaffold SKILL.md
672
705
  let targetPath = opts.dir ? path.resolve(opts.dir) : process.cwd();
673
706
  let skillDir = targetPath;
@@ -699,14 +732,13 @@ async function submitSkill(opts) {
699
732
 
700
733
  const scaffoldedDir = await scaffoldSkill();
701
734
  if (!scaffoldedDir) return;
702
- // User needs to edit the scaffold first
703
735
  return;
704
736
  }
705
737
 
706
- // Step 3: Validate
738
+ // Step 3: Local validation
707
739
  const spinner = ora('Validating skill...').start();
708
740
  const result = await validateSkill(skillDir, {
709
- checkDuplicates: true,
741
+ checkDuplicates: false,
710
742
  apiBase: API_BASE,
711
743
  });
712
744
  spinner.stop();
@@ -729,11 +761,11 @@ async function submitSkill(opts) {
729
761
  }
730
762
 
731
763
  // Step 4: Show summary and confirm
732
- const slug = result.info.slug;
733
764
  console.log(chalk.cyan('\n📤 Submit to MyAIDev Marketplace\n'));
734
765
  console.log(` ${chalk.gray('Name:')} ${chalk.white.bold(result.info.name)}`);
735
- console.log(` ${chalk.gray('Slug:')} ${chalk.white(slug)}`);
766
+ console.log(` ${chalk.gray('Slug:')} ${chalk.white(result.info.slug)}`);
736
767
  console.log(` ${chalk.gray('Description:')} ${chalk.white(truncate(result.info.description, 60))}`);
768
+ console.log(` ${chalk.gray('Category:')} ${result.info.category || 'general'}`);
737
769
  console.log(` ${chalk.gray('Sections:')} ${result.info.sectionCount}`);
738
770
  console.log('');
739
771
 
@@ -750,116 +782,75 @@ async function submitSkill(opts) {
750
782
  }
751
783
  }
752
784
 
753
- // Step 5: Fork, branch, commit, PR
754
- const prSpinner = ora('Creating pull request...').start();
755
- const tmpDir = path.join(os.tmpdir(), `myaidev-submit-${Date.now()}`);
785
+ // Step 5: Submit via API
786
+ const submitSpinner = ora('Submitting skill for review...').start();
756
787
 
757
788
  try {
758
- // Fork and clone
759
- try {
760
- execSync(`gh repo fork ${MARKETPLACE_REPO} --clone=false`, { stdio: 'pipe' });
761
- } catch {
762
- // Fork may already exist, that's fine
763
- }
764
-
765
- // Get the user's GitHub username
766
- const ghUser = execSync('gh api user --jq .login', { encoding: 'utf8' }).trim();
767
-
768
- // Clone the user's fork
769
- execSync(`gh repo clone ${ghUser}/myaidev-marketplace "${tmpDir}" -- --depth 1`, { stdio: 'pipe' });
770
-
771
- // Create branch
772
- const branch = `skill/${slug}`;
773
- execSync(`git -C "${tmpDir}" checkout -b ${branch}`, { stdio: 'pipe' });
774
-
775
- // Copy skill files
776
- const destDir = path.join(tmpDir, 'skills', slug);
777
- await fs.ensureDir(destDir);
778
- await fs.copy(skillDir, destDir, {
779
- filter: (src) => {
780
- const ext = path.extname(src).toLowerCase();
781
- const base = path.basename(src);
782
- // Copy directories and allowed file types
783
- if (fs.statSync(src).isDirectory()) return true;
784
- return ['.md', '.json', '.yaml', '.yml', '.sh', '.js', '.ts', '.py', '.txt'].includes(ext) || base === '.gitkeep';
785
- },
789
+ const content = await fs.readFile(skillFile, 'utf8');
790
+
791
+ const res = await authFetch(`${API_BASE}/submissions`, {
792
+ method: 'POST',
793
+ body: JSON.stringify({
794
+ content,
795
+ category: result.info.category || undefined,
796
+ }),
786
797
  });
787
798
 
788
- // Commit
789
- execSync(`git -C "${tmpDir}" add skills/${slug}`, { stdio: 'pipe' });
790
- execSync(`git -C "${tmpDir}" commit -m "feat: add skill ${result.info.name}"`, { stdio: 'pipe' });
791
-
792
- // Push
793
- execSync(`git -C "${tmpDir}" push -u origin ${branch}`, { stdio: 'pipe' });
794
-
795
- // Create PR
796
- const prBody = [
797
- `## Skill Submission: ${result.info.name}`,
798
- '',
799
- `**Description**: ${result.info.description || 'N/A'}`,
800
- `**Category**: ${result.info.category || 'general'}`,
801
- '',
802
- '### Checklist',
803
- '- [x] SKILL.md has valid YAML frontmatter',
804
- '- [x] Passes local validation',
805
- '- [ ] Tested locally with Claude Code',
806
- ].join('\n');
807
-
808
- const prOutput = execSync(
809
- `gh pr create --repo ${MARKETPLACE_REPO} --head ${ghUser}:${branch} --title "feat: add skill ${result.info.name}" --body "${prBody.replace(/"/g, '\\"')}"`,
810
- { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
811
- ).trim();
812
-
813
- prSpinner.succeed(chalk.green('Pull request created!'));
814
-
815
- // Extract PR URL from output
816
- const prUrl = prOutput.match(/https:\/\/github\.com\S+/)?.[0] || prOutput;
817
- console.log(chalk.gray(` PR: ${prUrl}`));
818
-
819
- // Step 6: Record submission
820
- try {
821
- await authFetch(`${API_BASE}/submissions`, {
822
- method: 'POST',
823
- body: JSON.stringify({
824
- skillName: result.info.name,
825
- slug,
826
- description: result.info.description || '',
827
- prUrl,
828
- }),
829
- });
830
- } catch {
831
- // Non-fatal: submission tracking is optional
832
- }
833
-
834
- console.log(chalk.cyan('\n Status: awaiting review'));
835
- console.log(chalk.gray(' Check: myaidev-method addon status\n'));
799
+ if (!res.ok) {
800
+ const body = await res.json().catch(() => ({}));
801
+ if (body.validation?.errors?.length) {
802
+ submitSpinner.fail(chalk.red('Server validation failed:'));
803
+ for (const err of body.validation.errors) {
804
+ console.log(chalk.red(` ${err}`));
805
+ }
806
+ return;
807
+ }
808
+ throw new Error(body.error || `API error: ${res.status}`);
809
+ }
810
+
811
+ const body = await res.json();
812
+ const submission = body.submission;
813
+
814
+ submitSpinner.succeed(chalk.green('Skill submitted for review!'));
815
+
816
+ console.log('');
817
+ console.log(` ${chalk.gray('Submission ID:')} ${chalk.white(submission.id)}`);
818
+ console.log(` ${chalk.gray('Status:')} ${chalk.yellow(submission.status)}`);
819
+ console.log('');
820
+ console.log(chalk.gray(' AI analysis will run automatically.'));
821
+ console.log(chalk.gray(' An admin will review and approve your skill.'));
822
+ console.log(chalk.gray(` Check status: ${chalk.white('myaidev-method addon status')}\n`));
836
823
  } catch (err) {
837
- prSpinner.fail(chalk.red(`Submission failed: ${err.message}`));
824
+ submitSpinner.fail(chalk.red(`Submission failed: ${err.message}`));
838
825
  process.exit(1);
839
- } finally {
840
- // Clean up temp directory
841
- await fs.remove(tmpDir).catch(() => {});
842
826
  }
843
827
  }
844
828
 
845
829
  // ── Status Command ─────────────────────────────────────────────────────
846
830
 
847
- async function checkStatus(name) {
831
+ async function checkStatus(nameOrId) {
848
832
  if (!(await requireAuth())) return;
849
833
 
850
834
  const spinner = ora('Fetching submission status...').start();
851
835
 
852
836
  try {
853
- const params = name ? `?name=${encodeURIComponent(name)}` : '';
854
- const res = await authFetch(`${API_BASE}/submissions${params}`);
855
-
856
- if (!res.ok) {
857
- throw new Error(`API error: ${res.status}`);
837
+ // If it looks like a UUID, fetch by ID
838
+ const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(nameOrId || '');
839
+
840
+ let submissions;
841
+ if (isUuid) {
842
+ const res = await authFetch(`${API_BASE}/submissions/${nameOrId}`);
843
+ if (!res.ok) throw new Error(`API error: ${res.status}`);
844
+ const body = await res.json();
845
+ submissions = body.submission ? [body.submission] : [];
846
+ } else {
847
+ const params = nameOrId ? `?name=${encodeURIComponent(nameOrId)}` : '';
848
+ const res = await authFetch(`${API_BASE}/submissions${params}`);
849
+ if (!res.ok) throw new Error(`API error: ${res.status}`);
850
+ const body = await res.json();
851
+ submissions = body.submissions || [];
858
852
  }
859
853
 
860
- const body = await res.json();
861
- const submissions = body.submissions || [];
862
-
863
854
  spinner.stop();
864
855
 
865
856
  if (submissions.length === 0) {
@@ -873,16 +864,36 @@ async function checkStatus(name) {
873
864
  for (const sub of submissions) {
874
865
  const statusColor = {
875
866
  pending_review: chalk.yellow,
867
+ ai_analyzing: chalk.magenta,
868
+ ready_for_review: chalk.blue,
876
869
  approved: chalk.green,
877
- merged: chalk.green.bold,
878
870
  rejected: chalk.red,
879
871
  changes_requested: chalk.yellow,
880
872
  }[sub.status] || chalk.gray;
881
873
 
882
- console.log(` ${chalk.white.bold(sub.skillName)} ${statusColor(`[${sub.status}]`)}`);
883
- if (sub.prUrl) console.log(chalk.gray(` PR: ${sub.prUrl}`));
884
- if (sub.reviewNotes) console.log(chalk.gray(` Notes: ${sub.reviewNotes}`));
885
- console.log(chalk.gray(` Submitted: ${new Date(sub.createdAt).toLocaleDateString()}`));
874
+ const statusLabel = {
875
+ pending_review: 'pending review',
876
+ ai_analyzing: 'AI analyzing...',
877
+ ready_for_review: 'ready for review',
878
+ approved: 'approved',
879
+ rejected: 'rejected',
880
+ changes_requested: 'changes requested',
881
+ }[sub.status] || sub.status;
882
+
883
+ console.log(` ${chalk.white.bold(sub.skillName)} ${statusColor(`[${statusLabel}]`)}`);
884
+
885
+ // Show AI score if available
886
+ if (sub.aiAnalysis?.overallScore != null) {
887
+ const score = sub.aiAnalysis.overallScore;
888
+ const scoreColor = score >= 75 ? chalk.green : score >= 50 ? chalk.yellow : chalk.red;
889
+ console.log(` ${chalk.gray('AI Score:')} ${scoreColor(`${score}/100`)} ${chalk.gray(`(${sub.aiAnalysis.recommendation})`)}`);
890
+ } else if (sub.aiAnalysisStatus === 'running') {
891
+ console.log(` ${chalk.gray('AI Score:')} ${chalk.magenta('analyzing...')}`);
892
+ }
893
+
894
+ if (sub.reviewNotes) console.log(` ${chalk.gray('Review:')} ${sub.reviewNotes}`);
895
+ console.log(` ${chalk.gray('Submitted:')} ${new Date(sub.createdAt).toLocaleDateString()}`);
896
+ if (sub.reviewedAt) console.log(` ${chalk.gray('Reviewed:')} ${new Date(sub.reviewedAt).toLocaleDateString()}`);
886
897
  console.log('');
887
898
  }
888
899
  } catch (err) {
@@ -9,6 +9,14 @@ import { getAuthData, saveAuth, clearAuth, isAuthenticated } from '../../lib/aut
9
9
 
10
10
  const API_BASE = 'https://dev.myai1.ai';
11
11
 
12
+ function ensureHttpsUrl(url) {
13
+ const value = String(url ?? '').trim();
14
+ if (!value) return value;
15
+ if (/^https:\/\//i.test(value)) return value;
16
+ if (/^http:\/\//i.test(value)) return value.replace(/^http:\/\//i, 'https://');
17
+ return `https://${value.replace(/^\/+/, '')}`;
18
+ }
19
+
12
20
  export function registerAuthCommands(program) {
13
21
  // ── login ───────────────────────────────────────────────────────────
14
22
  program
@@ -31,7 +39,7 @@ export function registerAuthCommands(program) {
31
39
  if (!initRes.ok) throw new Error(`Server returned ${initRes.status}`);
32
40
  const initData = await initRes.json();
33
41
  sessionId = initData.sessionId;
34
- authUrl = initData.authUrl;
42
+ authUrl = ensureHttpsUrl(initData.authUrl);
35
43
  } catch (err) {
36
44
  console.log(chalk.red(' ✗ Failed to connect to MyAIDev marketplace.'));
37
45
  console.log(chalk.gray(` ${err.message}\n`));
@@ -74,12 +74,17 @@ const WORKFLOWS = {
74
74
  name: 'Development Workflow',
75
75
  description: 'SPARC methodology for systematic software development',
76
76
  skills: [
77
- 'sparc-architect',
78
- 'sparc-coder',
79
- 'sparc-tester',
80
- 'sparc-reviewer',
81
- 'sparc-documenter',
82
- 'sparc-workflow'
77
+ 'myaidev-workflow',
78
+ 'myaidev-architect',
79
+ 'myaidev-coder',
80
+ 'myaidev-tester',
81
+ 'myaidev-reviewer',
82
+ 'myaidev-documenter',
83
+ 'myaidev-analyze',
84
+ 'myaidev-debug',
85
+ 'myaidev-refactor',
86
+ 'myaidev-performance',
87
+ 'myaidev-migrate'
83
88
  ],
84
89
  scripts: [],
85
90
  libs: [],
@@ -77,10 +77,10 @@ ${chalk.bold.hex('#808080')('─────────────────
77
77
  */
78
78
  export function getInitSuccessMessage(cliType) {
79
79
  const commands = cliType === 'claude'
80
- ? ' • View README: Press Ctrl+Shift+P → "Toggle Documentation"\n • Run workflow: /myai-sparc-workflow "Build your feature"'
80
+ ? ' • View README: Press Ctrl+Shift+P → "Toggle Documentation"\n • Run workflow: /myaidev-workflow "Build your feature"'
81
81
  : cliType === 'gemini'
82
- ? ' • View commands: ls .gemini/commands/\n • Run workflow: /myai-sparc-workflow "Build your feature"'
83
- : ' • View commands: ls .opencode/commands/\n • Run workflow: /myai-sparc-workflow "Build your feature"';
82
+ ? ' • View commands: ls .gemini/commands/\n • Run workflow: /myaidev-workflow "Build your feature"'
83
+ : ' • View commands: ls .opencode/commands/\n • Run workflow: /myaidev-workflow "Build your feature"';
84
84
 
85
85
  return `
86
86
  ${chalk.green.bold('✨ Installation Complete!')}