@mockingbird_konwlage_cli/cli 1.1.0 → 1.2.0

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 (2) hide show
  1. package/index.js +112 -4
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -11,19 +11,51 @@ const program = new Command();
11
11
  program
12
12
  .name('mockingbird-cli')
13
13
  .description('Installs and manages AI skills for various coding clients')
14
- .version('1.0.0');
14
+ .version('1.2.0');
15
15
 
16
16
  program
17
17
  .command('add <slug>')
18
18
  .description('Add an AI skill by its Mockingbird slug or GitHub <org>/<repo>')
19
19
  .option('--agent <agent>', 'The AI client to install the skill for (e.g., cursor, windsurf, claude-code)')
20
+ .option('--remote', 'Use the remote API instead of local')
20
21
  .action(async (slug, options) => {
22
+ // ... (existing add logic)
21
23
  const agent = (options.agent || 'cursor').toLowerCase();
24
+ const isRemote = options.remote || false;
22
25
 
23
26
  console.log(chalk.blue(`[Mockingbird] Installing skill '${slug}' for agent '${agent}'...`));
24
27
 
25
- // The Mockingbird Knowledge API URL
26
- const API_BASE_URL = process.env.MOCKINGBIRD_API_URL || 'https://mockingbird.youmind.com';
28
+ // Configuration discovery logic
29
+ let apiBaseUrl = process.env.MOCKINGBIRD_API_URL;
30
+
31
+ if (!apiBaseUrl) {
32
+ // Check .mockingbirdrc in current directory
33
+ const rcPath = path.join(process.cwd(), '.mockingbirdrc');
34
+ if (fs.existsSync(rcPath)) {
35
+ try {
36
+ const rc = JSON.parse(fs.readFileSync(rcPath, 'utf8'));
37
+ apiBaseUrl = isRemote ? rc.RemoteApiBaseUrl : rc.ApiBaseUrl;
38
+ } catch (e) {
39
+ console.warn(chalk.yellow(`[Warning] Failed to parse .mockingbirdrc: ${e.message}`));
40
+ }
41
+ }
42
+ }
43
+
44
+ if (!apiBaseUrl) {
45
+ // Check appsettings.json in current directory
46
+ const appSettingsPath = path.join(process.cwd(), 'appsettings.json');
47
+ if (fs.existsSync(appSettingsPath)) {
48
+ try {
49
+ const settings = JSON.parse(fs.readFileSync(appSettingsPath, 'utf8'));
50
+ apiBaseUrl = settings.ApiBaseUrl;
51
+ } catch (e) {
52
+ // Ignore parsing errors for general appsettings
53
+ }
54
+ }
55
+ }
56
+
57
+ // Final fallback to local development port
58
+ const API_BASE_URL = apiBaseUrl || 'http://localhost:5287';
27
59
  const apiUrl = `${API_BASE_URL}/api/public/skills/raw/${slug}`;
28
60
 
29
61
  let skillContent = null;
@@ -37,7 +69,7 @@ program
37
69
  console.log(chalk.red('NOT FOUND'));
38
70
  console.error(chalk.red(`\n✖ Error: Failed to find SKILL.md for '${slug}' from Mockingbird Knowledge Base.`));
39
71
  if (error.response && error.response.status === 404) {
40
- console.error(chalk.gray(`The skill might not be registered or supported yet.`));
72
+ console.error(chalk.gray(`The skill might not be registered or supported yet at ${API_BASE_URL}`));
41
73
  } else {
42
74
  console.error(chalk.gray(`Details: ${error.message}`));
43
75
  }
@@ -57,6 +89,82 @@ program
57
89
  }
58
90
  });
59
91
 
92
+ program
93
+ .command('push <path>')
94
+ .description('Push a local skill to the Mockingbird Knowledge Base')
95
+ .option('--no-assets', 'Skip bundling assets (images, etc.) and only push the SKILL.md content')
96
+ .action(async (skillPath, options) => {
97
+ const fullPath = path.resolve(skillPath);
98
+ const skillMdPath = fs.statSync(fullPath).isDirectory()
99
+ ? path.join(fullPath, 'SKILL.md')
100
+ : fullPath;
101
+
102
+ if (!fs.existsSync(skillMdPath)) {
103
+ console.error(chalk.red(`✖ Error: SKILL.md not found at ${skillMdPath}`));
104
+ process.exit(1);
105
+ }
106
+
107
+ const skillDir = path.dirname(skillMdPath);
108
+ const skillName = path.basename(skillDir);
109
+
110
+ console.log(chalk.blue(`[Mockingbird] Pushing skill '${skillName}' to knowledge base...`));
111
+
112
+ let content = fs.readFileSync(skillMdPath, 'utf8');
113
+
114
+ // Inject includeAssets flag if --no-assets is used
115
+ if (!options.assets) {
116
+ console.log(chalk.yellow(`[Config] Assets will be excluded from this push.`));
117
+ if (content.startsWith('---')) {
118
+ // Insert into existing yaml
119
+ if (!content.includes('includeAssets:')) {
120
+ content = content.replace('---', `---\nincludeAssets: false`);
121
+ } else {
122
+ content = content.replace(/includeAssets:\s*true/g, 'includeAssets: false');
123
+ }
124
+ } else {
125
+ content = `---\nincludeAssets: false\n---\n\n` + content;
126
+ }
127
+ }
128
+
129
+ // Deployment Logic for Dev Environment: Copy to Transmuter_Workshop/Raw_Incoming/Skills
130
+ // In a real production scenario, this would be a POST request to an API.
131
+ const SLN_ROOT = path.resolve(__dirname, '..');
132
+ const INCOMING_DIR = path.join(SLN_ROOT, 'Transmuter_Workshop', 'Raw_Incoming', 'Skills', 'local-publish', skillName);
133
+
134
+ try {
135
+ if (!fs.existsSync(INCOMING_DIR)) {
136
+ fs.mkdirSync(INCOMING_DIR, { recursive: true });
137
+ }
138
+
139
+ if (options.assets) {
140
+ console.log(chalk.gray(`Bundling full directory: ${skillDir} -> ${INCOMING_DIR}`));
141
+ copyFolderSync(skillDir, INCOMING_DIR);
142
+ // Overwrite with the potentially modified SKILL.md (though here it's only modified if no-assets)
143
+ fs.writeFileSync(path.join(INCOMING_DIR, 'SKILL.md'), content);
144
+ } else {
145
+ console.log(chalk.gray(`Bundling meta only: ${skillMdPath} -> ${INCOMING_DIR}/SKILL.md`));
146
+ fs.writeFileSync(path.join(INCOMING_DIR, 'SKILL.md'), content);
147
+ }
148
+
149
+ console.log(chalk.green(`\n✓ Successfully pushed skill '${skillName}' to workdesk.`));
150
+ console.log(chalk.gray(`The Transmuter service will process it shortly.`));
151
+
152
+ } catch (error) {
153
+ console.error(chalk.red(`\n✖ Error: Failed to push skill. ${error.message}`));
154
+ }
155
+ });
156
+
157
+ function copyFolderSync(from, to) {
158
+ fs.mkdirSync(to, { recursive: true });
159
+ fs.readdirSync(from).forEach(element => {
160
+ if (fs.lstatSync(path.join(from, element)).isFile()) {
161
+ fs.copyFileSync(path.join(from, element), path.join(to, element));
162
+ } else {
163
+ copyFolderSync(path.join(from, element), path.join(to, element));
164
+ }
165
+ });
166
+ }
167
+
60
168
  async function installForAgent(agent, slug, content) {
61
169
  const cwd = process.cwd();
62
170
  // Use the last part of the slug as a clean filename basis
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mockingbird_konwlage_cli/cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Mockingbird AI Developer Client CLI",
5
5
  "main": "index.js",
6
6
  "bin": {