@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/.claude-plugin/marketplace.json +11 -2
- package/dist/claudio.js +1 -1
- package/dist/genie.js +50 -45
- package/dist/term.js +1 -1
- package/install.sh +29 -29
- package/package.json +1 -1
- package/src/genie-commands/tui.ts +63 -0
- package/src/genie.ts +10 -0
- package/src/lib/version.ts +1 -1
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.
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
if
|
|
500
|
-
|
|
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
|
-
#
|
|
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
|
@@ -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')
|
package/src/lib/version.ts
CHANGED