@automagik/genie 4.260424.19 → 4.260425.1

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
@@ -25,7 +25,7 @@
25
25
  -->
26
26
 
27
27
  <!-- METRICS:START -->
28
- **🚀 122 commits** this week · **7 releases** · **+28.1K LoC** · **6 contributors**
28
+ **🚀 121 commits** this week · **7 releases** · **+28.1K LoC** · **6 contributors**
29
29
 
30
30
  ![Commits per day (30d, all branches)](.genie/assets/commits-30d.svg)
31
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "4.260424.19",
3
+ "version": "4.260425.1",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie",
3
- "version": "4.260424.19",
3
+ "version": "4.260425.1",
4
4
  "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
5
5
  "author": {
6
6
  "name": "Namastex Labs"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genie-plugin",
3
- "version": "4.260424.19",
3
+ "version": "4.260425.1",
4
4
  "private": true,
5
5
  "description": "Runtime dependencies for genie bundled CLIs",
6
6
  "type": "module",
@@ -241,9 +241,37 @@ function promptYesNo(message, { yes }) {
241
241
  // Scan
242
242
  // ---------------------------------------------------------------------------
243
243
 
244
+ function isRootUid() {
245
+ return typeof process.getuid === 'function' && process.getuid() === 0;
246
+ }
247
+
244
248
  function runScan() {
245
249
  section('1/6 Scan — gathering evidence');
246
- const result = spawnSync(process.execPath, [SCAN_SCRIPT, '--json', '--no-progress', '--redact'], {
250
+ const rootMode = isRootUid();
251
+ if (rootMode) {
252
+ process.stderr.write(
253
+ ` ${TTY.bgRed}${TTY.white}${TTY.bold} ROOT MODE ${TTY.reset} ${TTY.red}${TTY.bold}scanning every user home, system-wide persistence, all PIDs, root-only files${TTY.reset}\n`,
254
+ );
255
+ if (process.env.SUDO_USER && process.env.SUDO_USER !== 'root') {
256
+ process.stderr.write(
257
+ ` ${TTY.dim}invoking user: ${TTY.reset}${process.env.SUDO_USER} ${TTY.dim}(reinstall will be routed back to this user via su)${TTY.reset}\n`,
258
+ );
259
+ }
260
+ } else {
261
+ process.stderr.write(
262
+ ` ${TTY.yellow}running as user $(id -un) — for full coverage of other homes + /etc/cron + /etc/systemd + all PIDs, re-run under ${TTY.bold}sudo -E env "PATH=$PATH" genie sec fix${TTY.reset}\n`,
263
+ );
264
+ }
265
+ const scanArgs = [SCAN_SCRIPT, '--json', '--no-progress', '--redact'];
266
+ if (rootMode) {
267
+ // --all-homes enumerates /root + every /home/* + /Users/* on darwin.
268
+ // The persistence + shell-history + impact-surface phases iterate these
269
+ // homes so the deeper coverage falls out naturally once they're in the
270
+ // input list. /etc/cron.* and /etc/systemd/system/* are already in the
271
+ // persistence target table and become readable under root.
272
+ scanArgs.push('--all-homes');
273
+ }
274
+ const result = spawnSync(process.execPath, scanArgs, {
247
275
  stdio: ['ignore', 'pipe', 'inherit'],
248
276
  maxBuffer: 256 * 1024 * 1024,
249
277
  });
@@ -656,6 +684,29 @@ function reinstall(options) {
656
684
  warn('bun not found in PATH — skipping reinstall. Install manually: bun add -g @automagik/genie@next');
657
685
  return { reinstalled: false, reason: 'bun-not-found' };
658
686
  }
687
+
688
+ // When running under sudo, route the install to the invoking user so
689
+ // the bun global ends up in THEIR home (correct ownership + matches the
690
+ // binary that user invokes from the command line). Root's own bun
691
+ // global would be orphaned.
692
+ const sudoUser = process.env.SUDO_USER;
693
+ if (isRootUid() && sudoUser && sudoUser !== 'root') {
694
+ info(`routing reinstall to invoking user: ${sudoUser}`);
695
+ const suBin = findExecutable('su');
696
+ if (!suBin) {
697
+ warn('su not found — falling back to root install (may need manual reinstall as the user later)');
698
+ } else {
699
+ const cmd = `${bunBin} add -g @automagik/genie@next`;
700
+ const result = spawnSync(suBin, ['-', sudoUser, '-c', cmd], { stdio: 'inherit' });
701
+ if (result.status !== 0) {
702
+ warn(`reinstall (as ${sudoUser}) exited with code ${result.status}`);
703
+ return { reinstalled: false, exitCode: result.status, ranAs: sudoUser };
704
+ }
705
+ ok(`reinstalled @automagik/genie@next (as ${sudoUser})`);
706
+ return { reinstalled: true, ranAs: sudoUser };
707
+ }
708
+ }
709
+
659
710
  const result = spawnSync(bunBin, ['add', '-g', '@automagik/genie@next'], { stdio: 'inherit' });
660
711
  if (result.status !== 0) {
661
712
  warn(`reinstall exited with code ${result.status}`);
@@ -681,7 +732,9 @@ function findExecutable(name) {
681
732
  function rescan(options) {
682
733
  if (options.skipRescan) return null;
683
734
  section('6/6 Re-scan — confirm clean state');
684
- const result = spawnSync(process.execPath, [SCAN_SCRIPT, '--json', '--no-progress', '--redact'], {
735
+ const rescanArgs = [SCAN_SCRIPT, '--json', '--no-progress', '--redact'];
736
+ if (isRootUid()) rescanArgs.push('--all-homes');
737
+ const result = spawnSync(process.execPath, rescanArgs, {
685
738
  stdio: ['ignore', 'pipe', 'inherit'],
686
739
  maxBuffer: 256 * 1024 * 1024,
687
740
  });