cocosuperintelligence 1.7.1 → 1.7.3

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.
package/README.md CHANGED
@@ -38,7 +38,7 @@ An illustration built from a real `/SI-Decide` run (Claude Sonnet 5.5, 30 Septem
38
38
 
39
39
  Prerequisites: git, bash, Node.js 14 or newer (for `npx`), and python3 (it generates the `/SI-*` commands).
40
40
 
41
- `npx cocosuperintelligence` installs the latest release. It clones the pinned release tag (currently `v1.7.1`, not floating `main`) into `./coco` of the current directory, then runs `install.sh`. Run it from your home folder, so the clone is `~/coco` and not a folder inside another project. On a fresh machine it took about 3 minutes, including the download. <!-- x-release-please-version -->
41
+ `npx cocosuperintelligence` installs the latest release. It clones the pinned release tag (currently `v1.7.3`, not floating `main`) into `./coco` of the current directory, then runs `install.sh`. Run it from your home folder, so the clone is `~/coco` and not a folder inside another project. On a fresh machine it took about 3 minutes, including the download. <!-- x-release-please-version -->
42
42
 
43
43
  ```bash
44
44
  npx cocosuperintelligence
@@ -25,7 +25,7 @@ set -euo pipefail
25
25
 
26
26
  REPO_URL="https://github.com/coco-research/coco.git"
27
27
  # Keep in sync with package.json version. Clone the last tagged release, not floating main.
28
- PINNED_TAG="v1.7.1" # x-release-please-version
28
+ PINNED_TAG="v1.7.3" # x-release-please-version
29
29
  INSTALL_DIR="${COCO_DIR:-$HOME/.coco}"
30
30
  YES="${COCO_BOOTSTRAP_YES:-}"
31
31
  PASS_THROUGH=()
package/bin/coco.js CHANGED
@@ -308,6 +308,41 @@ function cmdUpdate(argv) {
308
308
  console.log(`\nCoco updated at ${dir}. Re-run install if you want to refresh symlinks:\n bash ${path.join(dir, 'install.sh')}`);
309
309
  }
310
310
 
311
+ // Remove symlinks under home that point at a root or anything inside it.
312
+ // Relative link text is resolved from the link's own directory, then realpath
313
+ // when the target exists. Comparison is a plain string: a clone path is not a
314
+ // glob. The prefix is root plus a separator, so a clone named coco does not
315
+ // take links into coco-research. realpath at the start is find -H: a symlinked
316
+ // home is searched, and a symlinked directory below it is not.
317
+ function sweepLinks(home, roots) {
318
+ if (!fs.existsSync(home)) return;
319
+ let start;
320
+ try { start = fs.realpathSync(home); } catch (_) { return; }
321
+ const inside = (p) => roots.some((r) => p === r || p.startsWith(r.endsWith(path.sep) ? r : r + path.sep));
322
+ const walk = (dir) => {
323
+ let names;
324
+ try { names = fs.readdirSync(dir); } catch (_) { return; }
325
+ for (const name of names) {
326
+ const link = path.join(dir, name);
327
+ let st;
328
+ try { st = fs.lstatSync(link); } catch (_) { continue; }
329
+ if (st.isSymbolicLink()) {
330
+ let target;
331
+ try { target = fs.readlinkSync(link); } catch (_) { continue; }
332
+ const abs = path.resolve(path.dirname(link), target);
333
+ let canon = null;
334
+ try { canon = fs.realpathSync(abs); } catch (_) { /* dangling */ }
335
+ if (inside(abs) || (canon && inside(canon))) {
336
+ try { fs.unlinkSync(link); } catch (e) { console.error(`Could not remove ${link}: ${e.code}`); }
337
+ }
338
+ } else if (st.isDirectory()) {
339
+ walk(link);
340
+ }
341
+ }
342
+ };
343
+ walk(start);
344
+ }
345
+
311
346
  function cmdUninstall(argv) {
312
347
  const force = argv.includes('--force');
313
348
  const dirArg = argv.find((a) => !a.startsWith('--'));
@@ -324,9 +359,10 @@ function cmdUninstall(argv) {
324
359
  if (found.length) refuseClone(dir, `it has ${found.join(' and ')}; pass --force to remove it`);
325
360
  }
326
361
  }
327
- // Prefix match on the resolved clone path plus a trailing slash, so a clone
328
- // named `coco` cannot also delete links into `coco-research` / `coco-connect`.
329
- const prefix = dir.endsWith(path.sep) ? dir : dir + path.sep;
362
+ // install.sh links through whichever path it ran from, so match both.
363
+ let real = dir;
364
+ try { real = fs.realpathSync(dir); } catch (_) { /* absent: only the given path */ }
365
+ const roots = [...new Set([dir, real])];
330
366
  console.log(`Removing symlinks pointing into ${dir}...`);
331
367
  const homes = [
332
368
  path.join(os.homedir(), '.claude'),
@@ -334,10 +370,7 @@ function cmdUninstall(argv) {
334
370
  path.join(os.homedir(), '.grok'),
335
371
  path.join(os.homedir(), '.copilot'),
336
372
  ];
337
- for (const home of homes) {
338
- if (!fs.existsSync(home)) continue;
339
- run('find', [home, '-type', 'l', '-lname', `${prefix}*`, '-delete']);
340
- }
373
+ for (const home of homes) sweepLinks(home, roots);
341
374
  // grok also writes generated files (SI commands, config block, hooks); its installer removes them.
342
375
  // Best-effort: an older pinned clone may not know --uninstall; never abort the uninstall over it.
343
376
  const grokInstaller = path.join(dir, 'adapters', 'grok', 'install.sh');
@@ -347,9 +380,17 @@ function cmdUninstall(argv) {
347
380
  console.log('Note: grok installer cleanup failed (possibly an older pin without --uninstall); continuing.');
348
381
  }
349
382
  }
350
- console.log(`Removing clone at ${dir}...`);
351
- if (fs.existsSync(dir)) {
352
- fs.rmSync(dir, { recursive: true, force: true });
383
+ let isLink = false;
384
+ try { isLink = fs.lstatSync(dir).isSymbolicLink(); } catch (_) { /* absent */ }
385
+ if (isLink) {
386
+ // A symlinked clone dir may point at a checkout the user keeps elsewhere: drop only the link.
387
+ fs.rmSync(dir, { force: true });
388
+ console.log(`Removed the link ${dir}; kept the clone it points to at ${real}. Delete that by hand if you want it gone.`);
389
+ } else {
390
+ console.log(`Removing clone at ${dir}...`);
391
+ if (fs.existsSync(dir)) {
392
+ fs.rmSync(dir, { recursive: true, force: true });
393
+ }
353
394
  }
354
395
  // The update notifier's cache is ours; drop it, and ~/.coco if that leaves it empty.
355
396
  fs.rmSync(UPDATE_CACHE, { force: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cocosuperintelligence",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "description": "CoCo Super Intelligence — summon an advisory board of 495 world-class minds inside your AI coding session. A vendor-neutral orchestration layer for Claude Code, Cursor, and Codex: 228 skills (190 installed by default), 387 commands, 34 agents, and disk-persistent state. 100% local, no telemetry. Open-core: MIT core, proprietary Super Intelligence.",
5
5
  "bin": {
6
6
  "coco": "bin/coco.js"