@automagik/genie 0.260203.503 → 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.0503";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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/genie",
3
- "version": "0.260203.0503",
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.0503';
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)