organtic 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.mjs +165 -15
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
3
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, cpSync, readdirSync } from "fs";
4
4
  import { join } from "path";
5
5
  import { homedir } from "os";
6
6
  import { createInterface } from "readline";
7
+ import { execSync } from "child_process";
7
8
 
8
9
  const MARKETPLACE_REPO = "Adanmohh/organtic";
9
10
  const MARKETPLACE_NAME = "organtic";
11
+ const GITHUB_URL = `https://github.com/${MARKETPLACE_REPO}.git`;
10
12
 
11
13
  const PLUGINS = [
12
14
  {
@@ -147,31 +149,161 @@ function box(chalk, lines, { title = "", width = 48, borderColor = null } = {})
147
149
  }
148
150
 
149
151
  // ---------------------------------------------------------------------------
150
- // Settings.json management
152
+ // Path helpers
151
153
  // ---------------------------------------------------------------------------
152
154
 
155
+ function getClaudeDir() {
156
+ return join(homedir(), ".claude");
157
+ }
158
+
159
+ function getPluginsDir() {
160
+ return join(getClaudeDir(), "plugins");
161
+ }
162
+
153
163
  function getSettingsPath() {
154
- return join(homedir(), ".claude", "settings.json");
164
+ return join(getClaudeDir(), "settings.json");
165
+ }
166
+
167
+ function getKnownMarketplacesPath() {
168
+ return join(getPluginsDir(), "known_marketplaces.json");
169
+ }
170
+
171
+ function getInstalledPluginsPath() {
172
+ return join(getPluginsDir(), "installed_plugins.json");
173
+ }
174
+
175
+ function getMarketplacePath() {
176
+ return join(getPluginsDir(), "marketplaces", MARKETPLACE_NAME);
155
177
  }
156
178
 
157
- function readSettings() {
158
- const path = getSettingsPath();
159
- if (!existsSync(path)) return {};
179
+ function getCachePath() {
180
+ return join(getPluginsDir(), "cache", MARKETPLACE_NAME);
181
+ }
182
+
183
+ // ---------------------------------------------------------------------------
184
+ // JSON file helpers
185
+ // ---------------------------------------------------------------------------
186
+
187
+ function readJson(path) {
188
+ if (!existsSync(path)) return null;
160
189
  try {
161
190
  return JSON.parse(readFileSync(path, "utf-8"));
162
191
  } catch {
163
- return {};
192
+ return null;
164
193
  }
165
194
  }
166
195
 
167
- function writeSettings(settings) {
168
- const dir = join(homedir(), ".claude");
196
+ function writeJson(path, data) {
197
+ const dir = join(path, "..");
169
198
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
170
- writeFileSync(getSettingsPath(), JSON.stringify(settings, null, 2) + "\n");
199
+ writeFileSync(path, JSON.stringify(data, null, 2) + "\n");
171
200
  }
172
201
 
173
- function installPlugins(selected) {
174
- const settings = readSettings();
202
+ // ---------------------------------------------------------------------------
203
+ // Installation logic
204
+ // ---------------------------------------------------------------------------
205
+
206
+ function cloneMarketplace() {
207
+ const marketplacePath = getMarketplacePath();
208
+
209
+ if (existsSync(marketplacePath)) {
210
+ // Pull latest
211
+ try {
212
+ execSync("git pull --ff-only", { cwd: marketplacePath, stdio: "pipe" });
213
+ } catch {
214
+ // If pull fails, remove and re-clone
215
+ execSync(`rm -rf "${marketplacePath}"`, { stdio: "pipe" });
216
+ mkdirSync(join(getPluginsDir(), "marketplaces"), { recursive: true });
217
+ execSync(`git clone "${GITHUB_URL}" "${marketplacePath}"`, { stdio: "pipe" });
218
+ }
219
+ } else {
220
+ mkdirSync(join(getPluginsDir(), "marketplaces"), { recursive: true });
221
+ execSync(`git clone "${GITHUB_URL}" "${marketplacePath}"`, { stdio: "pipe" });
222
+ }
223
+
224
+ // Get commit SHA
225
+ const sha = execSync("git rev-parse HEAD", { cwd: marketplacePath, encoding: "utf-8" }).trim();
226
+ return sha;
227
+ }
228
+
229
+ function getPluginVersion(pluginDir) {
230
+ const manifestPath = join(pluginDir, ".claude-plugin", "plugin.json");
231
+ const manifest = readJson(manifestPath);
232
+ return manifest?.version || "1.0.0";
233
+ }
234
+
235
+ function cachePlugins(selected, commitSha) {
236
+ const marketplacePath = getMarketplacePath();
237
+ const cachePath = getCachePath();
238
+ const results = [];
239
+
240
+ for (const plugin of selected) {
241
+ const srcDir = join(marketplacePath, plugin.name);
242
+ const version = getPluginVersion(srcDir);
243
+ const versionSlug = commitSha.substring(0, 12);
244
+ const destDir = join(cachePath, plugin.name, versionSlug);
245
+
246
+ mkdirSync(destDir, { recursive: true });
247
+ cpSync(srcDir, destDir, { recursive: true });
248
+
249
+ results.push({
250
+ name: plugin.name,
251
+ version,
252
+ versionSlug,
253
+ installPath: destDir,
254
+ commitSha,
255
+ });
256
+ }
257
+
258
+ return results;
259
+ }
260
+
261
+ function updateKnownMarketplaces() {
262
+ const path = getKnownMarketplacesPath();
263
+ const data = readJson(path) || {};
264
+
265
+ data[MARKETPLACE_NAME] = {
266
+ source: {
267
+ source: "github",
268
+ repo: MARKETPLACE_REPO,
269
+ },
270
+ installLocation: getMarketplacePath().replace(/\//g, "\\"),
271
+ lastUpdated: new Date().toISOString(),
272
+ };
273
+
274
+ writeJson(path, data);
275
+ }
276
+
277
+ function updateInstalledPlugins(cachedPlugins) {
278
+ const path = getInstalledPluginsPath();
279
+ const data = readJson(path) || { version: 2, plugins: {} };
280
+
281
+ if (!data.plugins) data.plugins = {};
282
+ if (!data.version) data.version = 2;
283
+
284
+ const now = new Date().toISOString();
285
+ const projectPath = homedir();
286
+
287
+ for (const plugin of cachedPlugins) {
288
+ const key = `${plugin.name}@${MARKETPLACE_NAME}`;
289
+ data.plugins[key] = [
290
+ {
291
+ scope: "project",
292
+ installPath: plugin.installPath.replace(/\//g, "\\"),
293
+ version: plugin.version,
294
+ installedAt: now,
295
+ lastUpdated: now,
296
+ gitCommitSha: plugin.commitSha,
297
+ projectPath: projectPath.replace(/\//g, "\\"),
298
+ },
299
+ ];
300
+ }
301
+
302
+ writeJson(path, data);
303
+ }
304
+
305
+ function updateSettings(selected) {
306
+ const settings = readJson(getSettingsPath()) || {};
175
307
 
176
308
  // Add marketplace
177
309
  if (!settings.extraKnownMarketplaces) {
@@ -192,7 +324,25 @@ function installPlugins(selected) {
192
324
  settings.enabledPlugins[`${plugin.name}@${MARKETPLACE_NAME}`] = true;
193
325
  }
194
326
 
195
- writeSettings(settings);
327
+ writeJson(getSettingsPath(), settings);
328
+ }
329
+
330
+ function installPlugins(selected) {
331
+ // 1. Clone/update marketplace repo
332
+ const commitSha = cloneMarketplace();
333
+
334
+ // 2. Cache plugin files
335
+ const cachedPlugins = cachePlugins(selected, commitSha);
336
+
337
+ // 3. Register marketplace in known_marketplaces.json
338
+ updateKnownMarketplaces();
339
+
340
+ // 4. Register plugins in installed_plugins.json
341
+ updateInstalledPlugins(cachedPlugins);
342
+
343
+ // 5. Update settings.json (enabledPlugins + extraKnownMarketplaces)
344
+ updateSettings(selected);
345
+
196
346
  return true;
197
347
  }
198
348
 
@@ -313,14 +463,14 @@ async function main() {
313
463
  // ── Install ───────────────────────────────────────────────────────────
314
464
 
315
465
  const spinner = ora({
316
- text: `Installing ${selected.length} plugin${selected.length > 1 ? "s" : ""} to ~/.claude/settings.json...`,
466
+ text: `Cloning marketplace and installing ${selected.length} plugin${selected.length > 1 ? "s" : ""}...`,
317
467
  color: "cyan",
318
468
  }).start();
319
469
 
320
470
  try {
321
471
  installPlugins(selected);
322
472
  spinner.succeed(
323
- `${bold(`${selected.length} plugins`)} ${dim("installed to")} ${dim("~/.claude/settings.json")}`
473
+ `${bold(`${selected.length} plugins`)} ${dim("installed to")} ${dim("~/.claude/")}`
324
474
  );
325
475
  } catch (err) {
326
476
  spinner.fail(red(`Failed: ${err.message}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "organtic",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "The AI-native organization. 25 experts from idea to launch. Strategy pipeline (validate > build > launch) + execution plugins (craft, document, present, studio). Claude Code plugin ecosystem.",
5
5
  "bin": {
6
6
  "organtic": "./index.mjs"