@automagik/genie 0.260203.448 → 0.260203.624

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/dist/term.js CHANGED
@@ -27,7 +27,7 @@ Expecting one of '${E.join("', '")}'`);let B=`${D}Help`;return this.on(B,($)=>{l
27
27
  `)$+=EF(X)}}return $};BF.exports=(D,F,E)=>{return String(D).normalize().replace(/\r\n/g,`
28
28
  `).split(`
29
29
  `).map((B)=>qE(B,F,E)).join(`
30
- `)}});var qF=c((ZQ,YF)=>{var _E=FD("stream");class JF extends _E{#E=null;constructor(D={}){super(D);this.writable=this.readable=!0,this.muted=!1,this.on("pipe",this._onpipe),this.replace=D.replace,this._prompt=D.prompt||null,this._hadControl=!1}#F(D,F){if(this._dest)return this._dest[D];if(this._src)return this._src[D];return F}#D(D,...F){if(typeof this._dest?.[D]==="function")this._dest[D](...F);if(typeof this._src?.[D]==="function")this._src[D](...F)}get isTTY(){if(this.#E!==null)return this.#E;return this.#F("isTTY",!1)}set isTTY(D){this.#E=D}get rows(){return this.#F("rows")}get columns(){return this.#F("columns")}mute(){this.muted=!0}unmute(){this.muted=!1}_onpipe(D){this._src=D}pipe(D,F){return this._dest=D,super.pipe(D,F)}pause(){if(this._src)return this._src.pause()}resume(){if(this._src)return this._src.resume()}write(D){if(this.muted){if(!this.replace)return!0;if(D.match(/^\u001b/)){if(D.indexOf(this._prompt)===0)D=D.slice(this._prompt.length),D=D.replace(/./g,this.replace),D=this._prompt+D;return this._hadControl=!0,this.emit("data",D)}else{if(this._prompt&&this._hadControl&&D.indexOf(this._prompt)===0)this._hadControl=!1,this.emit("data",this._prompt),D=D.slice(this._prompt.length);D=D.toString().replace(/./g,this.replace)}}this.emit("data",D)}end(D){if(this.muted)if(D&&this.replace)D=D.toString().replace(/./g,this.replace);else D=null;if(D)this.emit("data",D);this.emit("end")}destroy(...D){return this.#D("destroy",...D)}destroySoon(...D){return this.#D("destroySoon",...D)}close(...D){return this.#D("close",...D)}}YF.exports=JF});var g8=iD(h8(),1),{program:HB,createCommand:_B,createArgument:GB,createOption:WB,CommanderError:UB,InvalidArgumentError:AB,InvalidOptionArgumentError:CB,Command:l8,Argument:zB,Option:VB,Help:KB}=g8.default;var m8="0.260203.0448";import{join as X7}from"path";var r=[];for(let D=0;D<256;++D)r.push((D+256).toString(16).slice(1));function c8(D,F=0){return(r[D[F+0]]+r[D[F+1]]+r[D[F+2]]+r[D[F+3]]+"-"+r[D[F+4]]+r[D[F+5]]+"-"+r[D[F+6]]+r[D[F+7]]+"-"+r[D[F+8]]+r[D[F+9]]+"-"+r[D[F+10]]+r[D[F+11]]+r[D[F+12]]+r[D[F+13]]+r[D[F+14]]+r[D[F+15]]).toLowerCase()}import{randomFillSync as w5}from"crypto";var K0=new Uint8Array(256),V0=K0.length;function q3(){if(V0>K0.length-16)w5(K0),V0=0;return K0.slice(V0,V0+=16)}import{randomUUID as v5}from"crypto";var H3={randomUUID:v5};function u5(D,F,E){if(H3.randomUUID&&!F&&!D)return H3.randomUUID();D=D||{};let B=D.random??D.rng?.()??q3();if(B.length<16)throw Error("Random bytes length must be >= 16");if(B[6]=B[6]&15|64,B[8]=B[8]&63|128,F){if(E=E||0,E<0||E+16>F.length)throw RangeError(`UUID byte range ${E}:${E+15} is out of buffer bounds`);for(let $=0;$<16;++$)F[E+$]=B[$];return F}return c8(B)}var R0=u5;import{exec as x5}from"child_process";import{promisify as k5}from"util";import{join as y5}from"path";import{mkdirSync as h5,existsSync as g5}from"fs";import{homedir as l5}from"os";var m5=k5(x5);function c5(){let D=y5(l5(),".genie","logs","tmux");if(!g5(D))h5(D,{recursive:!0});return D}function p5(D){return D.filter((F)=>!/^-v+$/.test(F))}function d5(){return process.env.GENIE_TMUX_DEBUG==="1"}async function p8(D){let F=typeof D==="string"?D.split(/\s+/).filter(Boolean):D,E=p5(F),B=d5(),$={};if(B)E=["-v",...E],$.cwd=c5();let X=`tmux ${E.join(" ")}`,{stdout:Q}=await m5(X,$);return Q.trim()}var i5={type:"bash"};async function O(D){try{return await p8(D)}catch(F){throw Error(`Failed to execute tmux command: ${F.message}`)}}async function W3(){try{let F=await O("list-sessions -F '#{session_id}:#{session_name}:#{?session_attached,1,0}:#{session_windows}'");if(!F)return[];return F.split(`
30
+ `)}});var qF=c((ZQ,YF)=>{var _E=FD("stream");class JF extends _E{#E=null;constructor(D={}){super(D);this.writable=this.readable=!0,this.muted=!1,this.on("pipe",this._onpipe),this.replace=D.replace,this._prompt=D.prompt||null,this._hadControl=!1}#F(D,F){if(this._dest)return this._dest[D];if(this._src)return this._src[D];return F}#D(D,...F){if(typeof this._dest?.[D]==="function")this._dest[D](...F);if(typeof this._src?.[D]==="function")this._src[D](...F)}get isTTY(){if(this.#E!==null)return this.#E;return this.#F("isTTY",!1)}set isTTY(D){this.#E=D}get rows(){return this.#F("rows")}get columns(){return this.#F("columns")}mute(){this.muted=!0}unmute(){this.muted=!1}_onpipe(D){this._src=D}pipe(D,F){return this._dest=D,super.pipe(D,F)}pause(){if(this._src)return this._src.pause()}resume(){if(this._src)return this._src.resume()}write(D){if(this.muted){if(!this.replace)return!0;if(D.match(/^\u001b/)){if(D.indexOf(this._prompt)===0)D=D.slice(this._prompt.length),D=D.replace(/./g,this.replace),D=this._prompt+D;return this._hadControl=!0,this.emit("data",D)}else{if(this._prompt&&this._hadControl&&D.indexOf(this._prompt)===0)this._hadControl=!1,this.emit("data",this._prompt),D=D.slice(this._prompt.length);D=D.toString().replace(/./g,this.replace)}}this.emit("data",D)}end(D){if(this.muted)if(D&&this.replace)D=D.toString().replace(/./g,this.replace);else D=null;if(D)this.emit("data",D);this.emit("end")}destroy(...D){return this.#D("destroy",...D)}destroySoon(...D){return this.#D("destroySoon",...D)}close(...D){return this.#D("close",...D)}}YF.exports=JF});var g8=iD(h8(),1),{program:HB,createCommand:_B,createArgument:GB,createOption:WB,CommanderError:UB,InvalidArgumentError:AB,InvalidOptionArgumentError:CB,Command:l8,Argument:zB,Option:VB,Help:KB}=g8.default;var m8="0.260203.0624";import{join as X7}from"path";var r=[];for(let D=0;D<256;++D)r.push((D+256).toString(16).slice(1));function c8(D,F=0){return(r[D[F+0]]+r[D[F+1]]+r[D[F+2]]+r[D[F+3]]+"-"+r[D[F+4]]+r[D[F+5]]+"-"+r[D[F+6]]+r[D[F+7]]+"-"+r[D[F+8]]+r[D[F+9]]+"-"+r[D[F+10]]+r[D[F+11]]+r[D[F+12]]+r[D[F+13]]+r[D[F+14]]+r[D[F+15]]).toLowerCase()}import{randomFillSync as w5}from"crypto";var K0=new Uint8Array(256),V0=K0.length;function q3(){if(V0>K0.length-16)w5(K0),V0=0;return K0.slice(V0,V0+=16)}import{randomUUID as v5}from"crypto";var H3={randomUUID:v5};function u5(D,F,E){if(H3.randomUUID&&!F&&!D)return H3.randomUUID();D=D||{};let B=D.random??D.rng?.()??q3();if(B.length<16)throw Error("Random bytes length must be >= 16");if(B[6]=B[6]&15|64,B[8]=B[8]&63|128,F){if(E=E||0,E<0||E+16>F.length)throw RangeError(`UUID byte range ${E}:${E+15} is out of buffer bounds`);for(let $=0;$<16;++$)F[E+$]=B[$];return F}return c8(B)}var R0=u5;import{exec as x5}from"child_process";import{promisify as k5}from"util";import{join as y5}from"path";import{mkdirSync as h5,existsSync as g5}from"fs";import{homedir as l5}from"os";var m5=k5(x5);function c5(){let D=y5(l5(),".genie","logs","tmux");if(!g5(D))h5(D,{recursive:!0});return D}function p5(D){return D.filter((F)=>!/^-v+$/.test(F))}function d5(){return process.env.GENIE_TMUX_DEBUG==="1"}async function p8(D){let F=typeof D==="string"?D.split(/\s+/).filter(Boolean):D,E=p5(F),B=d5(),$={};if(B)E=["-v",...E],$.cwd=c5();let X=`tmux ${E.join(" ")}`,{stdout:Q}=await m5(X,$);return Q.trim()}var i5={type:"bash"};async function O(D){try{return await p8(D)}catch(F){throw Error(`Failed to execute tmux command: ${F.message}`)}}async function W3(){try{let F=await O("list-sessions -F '#{session_id}:#{session_name}:#{?session_attached,1,0}:#{session_windows}'");if(!F)return[];return F.split(`
31
31
  `).map((E)=>{let[B,$,X,Q]=E.split(":");return{id:B,name:$,attached:X==="1",windows:parseInt(Q,10)}})}catch(D){if(D.message.includes("no server running"))return[];throw D}}async function v(D){try{return(await W3()).find((E)=>E.name===D)||null}catch(F){return null}}async function x(D){try{let E=await O(`list-windows -t '${D}' -F '#{window_id}:#{window_name}:#{?window_active,1,0}'`);if(!E)return[];return E.split(`
32
32
  `).map((B)=>{let[$,X,Q]=B.split(":");return{id:$,name:X,active:Q==="1",sessionId:D}})}catch(F){if(F.message.includes("no server running")||F.message.includes("session not found"))return[];throw F}}async function h(D){try{let E=await O(`list-panes -t '${D}' -F '#{pane_id}:#{pane_title}:#{?pane_active,1,0}'`);if(!E)return[];return E.split(`
33
33
  `).map((B)=>{let[$,X,Q]=B.split(":");return{id:$,windowId:D,title:X,active:Q==="1"}})}catch(F){if(F.message.includes("no server running")||F.message.includes("window not found"))return[];throw F}}async function p(D,F=200,E=!1){try{return await O(`capture-pane -p ${E?"-e":""} -t '${D}' -S -${F} -E -`)}catch(B){if(B.message.includes("no server running")||B.message.includes("pane not found"))return"";throw B}}async function nD(D){return await O(`new-session -d -s "${D}" -e LC_ALL=C.UTF-8 -e LANG=C.UTF-8`),v(D)}async function j0(D,F){let E=await O(`new-window -t '${D}' -n '${F}'`);return(await x(D)).find(($)=>$.name===F)||null}async function M0(D){await O(`kill-session -t '${D}'`)}async function d8(D){await O(`kill-window -t '${D}'`)}async function W2(D){await O(`kill-pane -t '${D}'`)}function n5(D){return D.replace(/'/g,"'\\''")}async function U2(D,F="vertical",E,B){let $="split-window";if(F==="horizontal")$+=" -h";else $+=" -v";if(B)$+=` -c '${n5(B)}'`;if(E!==void 0&&E>0&&E<100)$+=` -p ${E}`;$+=` -t '${D}'`,$+=" -P -F '#{pane_id}'";let X=(await O($)).trim(),Q=await O(`display-message -p -t '${X}' '#{window_id}'`);return{id:X,windowId:Q.trim(),active:!1,title:""}}var _3=new Map,G3="TMUX_MCP_START",L0="TMUX_MCP_DONE_";async function QD(D,F,E,B){let $=R0(),X;if(E||B)X=F;else{let Q=r5();X=`echo "${G3}"; ${F}; echo "${Q}"`}if(_3.set($,{id:$,paneId:D,command:F,status:"pending",startTime:new Date,rawMode:E||B}),B)if(["Up","Down","Left","Right","Escape","Tab","Enter","Space","BSpace","Delete","Home","End","PageUp","PageDown","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12"].includes(X))await O(`send-keys -t '${D}' ${X}`);else for(let J of X)await O(`send-keys -t '${D}' '${J.replace(/'/g,"'\\''")}'`);else await O(`send-keys -t '${D}' '${X.replace(/'/g,"'\\''")}' Enter`);return $}async function i8(D){let F=_3.get(D);if(!F)return null;if(F.status!=="pending")return F;let E=await p(F.paneId,1000);if(F.rawMode)return F.result="Status tracking unavailable for rawMode commands. Use capture-pane to monitor interactive apps instead.",F;let B=E.lastIndexOf(G3),$=E.lastIndexOf(L0);if(B===-1||$===-1||$<=B)return F.result="Command output could not be captured properly",F;let X=E.substring($).split(`
package/install.sh CHANGED
@@ -108,11 +108,19 @@ confirm_no() {
108
108
 
109
109
  # Get installed genie-cli version
110
110
  get_installed_version() {
111
- if check_command genie; then
112
- genie --version 2>/dev/null | head -1 || echo ""
113
- else
114
- echo ""
111
+ local version=""
112
+
113
+ # Try bun first (check global packages)
114
+ if check_command bun; then
115
+ version=$(bun pm ls -g 2>/dev/null | grep "$PACKAGE_NAME" | grep -o '@[0-9][^[:space:]]*' | tr -d '@' || true)
116
+ fi
117
+
118
+ # Fallback to npm
119
+ if [[ -z "$version" ]] && check_command npm; then
120
+ version=$(npm ls -g "$PACKAGE_NAME" --depth=0 2>/dev/null | grep "$PACKAGE_NAME" | grep -o '@[0-9][^[:space:]]*' | tr -d '@' || true)
115
121
  fi
122
+
123
+ echo "$version"
116
124
  }
117
125
 
118
126
  # Get latest version from npm registry
@@ -447,12 +455,7 @@ run_claudio_setup() {
447
455
  # ─────────────────────────────────────────────────────────────────────────────
448
456
 
449
457
  run_install() {
450
- local installed_version latest_version
451
-
452
- # Check current installation status
453
- installed_version=$(get_installed_version)
454
-
455
- # Required prerequisites (needed for version check)
458
+ # ─── Prerequisites ───
456
459
  header "Checking prerequisites..."
457
460
  install_git_if_needed
458
461
  install_node_if_needed
@@ -460,13 +463,16 @@ run_install() {
460
463
  install_tmux_if_needed
461
464
  install_jq_if_needed
462
465
  install_rg_if_needed
466
+ install_claude_if_needed
463
467
 
464
- # Check versions
468
+ # ─── Genie CLI Install/Update ───
469
+ header "Checking Genie CLI..."
470
+ local installed_version latest_version
471
+ installed_version=$(get_installed_version)
465
472
  latest_version=$(get_latest_version)
466
473
 
467
474
  if [[ -n "$installed_version" ]]; then
468
475
  log "Genie CLI ${BOLD}$installed_version${NC} installed"
469
-
470
476
  if [[ -n "$latest_version" ]]; then
471
477
  if [[ "$installed_version" == "$latest_version" ]]; then
472
478
  success "Genie CLI is up to date"
@@ -484,29 +490,23 @@ run_install() {
484
490
  warn "Could not check latest version"
485
491
  fi
486
492
  else
487
- # Fresh install
488
- header "Installing Genie CLI..."
489
493
  install_genie_cli
490
494
  fi
491
495
 
492
- # Optional: Claude Code CLI
493
- echo
494
- info "AI-powered coding assistant from Anthropic"
495
- if confirm "Install Claude Code CLI?"; then
496
- install_claude_if_needed
497
-
498
- # Optional: Genie Plugin (only if Claude installed)
499
- if check_command claude; then
500
- echo
501
- info "Adds skills, agents, and hooks to Claude Code"
502
- if confirm "Install Genie plugin for Claude Code?"; then
503
- install_plugin_if_needed
504
- fi
496
+ # ─── Configuration Wizard ───
497
+ header "Configuration"
498
+ echo -e "${DIM}────────────────────────────────────${NC}"
499
+
500
+ # Plugin for Claude Code
501
+ if check_command claude; then
502
+ info "Adds skills, agents, and hooks to Claude Code"
503
+ if confirm "Install Genie plugin for Claude Code?"; then
504
+ install_plugin_if_needed
505
505
  fi
506
+ echo
506
507
  fi
507
508
 
508
- # Optional: Claudio setup
509
- echo
509
+ # Claudio profiles
510
510
  info "Manage multiple Claude API configurations"
511
511
  if confirm "Configure Claudio profiles?"; then
512
512
  run_claudio_setup
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "0.260203.0448",
3
+ "version": "0.260203.0624",
4
4
  "description": "Collaborative terminal toolkit for human + AI workflows",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Genie TUI Command
3
+ *
4
+ * Persistent "master genie" session that:
5
+ * - Always lives in ~/workspace
6
+ * - Uses fixed session name "genie"
7
+ * - Persists until manually reset via --reset flag
8
+ * - Starts Claude Code on first creation
9
+ */
10
+
11
+ import { spawnSync } from 'child_process';
12
+ import { homedir } from 'os';
13
+ import { join } from 'path';
14
+ import * as tmux from '../lib/tmux.js';
15
+
16
+ const SESSION_NAME = 'genie';
17
+ const WORKSPACE_DIR = join(homedir(), 'workspace');
18
+
19
+ export interface TuiOptions {
20
+ reset?: boolean;
21
+ }
22
+
23
+ export async function tuiCommand(options: TuiOptions = {}): Promise<void> {
24
+ try {
25
+ // Handle reset flag - kill existing session
26
+ if (options.reset) {
27
+ const existing = await tmux.findSessionByName(SESSION_NAME);
28
+ if (existing) {
29
+ console.log(`🗑️ Resetting session "${SESSION_NAME}"...`);
30
+ await tmux.killSession(SESSION_NAME);
31
+ }
32
+ }
33
+
34
+ // Check if session exists
35
+ let session = await tmux.findSessionByName(SESSION_NAME);
36
+
37
+ if (!session) {
38
+ // Create session
39
+ console.log(`✨ Creating session "${SESSION_NAME}"...`);
40
+ session = await tmux.createSession(SESSION_NAME);
41
+ if (!session) {
42
+ console.error(`❌ Failed to create session "${SESSION_NAME}"`);
43
+ process.exit(1);
44
+ }
45
+
46
+ // Change to workspace directory
47
+ await tmux.executeTmux(`send-keys -t '${SESSION_NAME}' 'cd ${WORKSPACE_DIR}' Enter`);
48
+
49
+ // Start Claude Code
50
+ await tmux.executeTmux(`send-keys -t '${SESSION_NAME}' 'claude' Enter`);
51
+ console.log(`✅ Started Claude Code in ${WORKSPACE_DIR}`);
52
+ } else {
53
+ console.log(`📎 Session "${SESSION_NAME}" already exists`);
54
+ }
55
+
56
+ // Attach to session (replaces current process)
57
+ console.log(`📎 Attaching...`);
58
+ spawnSync('tmux', ['attach', '-t', SESSION_NAME], { stdio: 'inherit' });
59
+ } catch (error: any) {
60
+ console.error(`❌ Error: ${error.message}`);
61
+ process.exit(1);
62
+ }
63
+ }
package/src/genie.ts CHANGED
@@ -7,6 +7,7 @@ import { setupCommand, type SetupOptions } from './genie-commands/setup.js';
7
7
  import { updateCommand } from './genie-commands/update.js';
8
8
  import { uninstallCommand } from './genie-commands/uninstall.js';
9
9
  import { doctorCommand } from './genie-commands/doctor.js';
10
+ import { tuiCommand, type TuiOptions } from './genie-commands/tui.js';
10
11
  import {
11
12
  shortcutsShowCommand,
12
13
  shortcutsInstallCommand,
@@ -61,6 +62,15 @@ program
61
62
  .description('Remove Genie CLI and clean up hooks')
62
63
  .action(uninstallCommand);
63
64
 
65
+ // TUI command - attach to master genie session
66
+ program
67
+ .command('tui')
68
+ .description('Attach to master genie session in ~/workspace')
69
+ .option('-r, --reset', 'Kill existing session and start fresh')
70
+ .action(async (options: TuiOptions) => {
71
+ await tuiCommand(options);
72
+ });
73
+
64
74
  // Shortcuts command group - manage tmux keyboard shortcuts
65
75
  const shortcuts = program
66
76
  .command('shortcuts')
@@ -1,5 +1,5 @@
1
1
  // Runtime version (baked in at build time)
2
- export const VERSION = '0.260203.0448';
2
+ export const VERSION = '0.260203.0624';
3
3
 
4
4
  // Generate version string from current datetime
5
5
  // Format: 0.YYMMDD.HHMM (e.g., 0.260201.1430 = Feb 1, 2026 at 14:30)