termify-agent 1.0.29 → 1.0.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termify-agent",
3
- "version": "1.0.29",
3
+ "version": "1.0.30",
4
4
  "description": "Termify Agent CLI - Connect your local terminal to Termify",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -33,13 +33,15 @@
33
33
  "chalk": "^5.3.0",
34
34
  "commander": "^12.0.0",
35
35
  "conf": "^12.0.0",
36
- "node-pty": "^1.1.0",
37
36
  "open": "^10.0.0",
38
37
  "ora": "^8.0.1",
39
38
  "simple-git": "^3.30.0",
40
- "ssh2": "^1.15.0",
41
39
  "ws": "^8.16.0"
42
40
  },
41
+ "optionalDependencies": {
42
+ "node-pty": "^1.1.0",
43
+ "ssh2": "^1.15.0"
44
+ },
43
45
  "devDependencies": {
44
46
  "@types/node": "^20.11.0",
45
47
  "@types/ssh2": "^1.15.0",
@@ -31,30 +31,29 @@ const STATS_AGENT_PATH = join(TERMIFY_DIR, `stats-agent${EXE}`);
31
31
  const MCP_DIR = join(TERMIFY_DIR, 'termify-mcp');
32
32
  const MCP_BUNDLE_PATH = join(MCP_DIR, 'index.mjs');
33
33
 
34
+ // Marker: skip node-pty test on repeated installs if it already works for this ABI
35
+ const NODE_PTY_OK_MARKER = join(TERMIFY_DIR, `.node-pty-ok-${process.versions.modules}`);
36
+
34
37
  /**
35
- * Test if node-pty actually works by spawning a shell
38
+ * Test if node-pty actually works by spawning a shell in a child process.
39
+ * Uses child process to isolate potential SIGSEGV from bad prebuilds.
36
40
  */
37
41
  function testNodePty() {
42
+ // Fast path: marker from previous successful install
43
+ if (existsSync(NODE_PTY_OK_MARKER)) return true;
44
+
38
45
  try {
39
- const testScript = `
40
- const pty = require('node-pty');
41
- const term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : '/bin/sh', [], {
42
- name: 'xterm-256color',
43
- cols: 80,
44
- rows: 24,
45
- cwd: process.env.HOME || process.env.USERPROFILE || '/',
46
- env: process.env
47
- });
48
- term.kill();
49
- process.exit(0);
50
- `;
51
- execSync(`node -e "${testScript.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`, {
46
+ execSync('node -e "require(\'node-pty\').spawn(\'/bin/sh\',[],{cols:80,rows:24}).kill()"', {
52
47
  stdio: 'pipe',
53
- timeout: 10000,
48
+ timeout: 5000,
54
49
  cwd: process.cwd(),
55
50
  });
51
+ // Cache result for next install
52
+ mkdirSync(TERMIFY_DIR, { recursive: true });
53
+ try { writeFileSync(NODE_PTY_OK_MARKER, Date.now().toString()); } catch {}
56
54
  return true;
57
- } catch (err) {
55
+ } catch {
56
+ try { unlinkSync(NODE_PTY_OK_MARKER); } catch {}
58
57
  return false;
59
58
  }
60
59
  }
@@ -77,21 +76,20 @@ function resolveNodePtyDir() {
77
76
  * For Node.js v24+, prebuilds may not be compatible, so we compile from source
78
77
  */
79
78
  function rebuildNodePty() {
80
- console.log('[termify-agent] Setting up node-pty for your platform...');
81
- console.log(`[termify-agent] Node.js version: ${process.version}`);
79
+ // node-pty is an optional dependency — skip entirely if not installed
80
+ const nodePtyDir = resolveNodePtyDir();
81
+ if (!nodePtyDir) {
82
+ console.log('[termify-agent] node-pty not installed (optional), skipping PTY setup.');
83
+ return false;
84
+ }
82
85
 
83
- // First, check if node-pty already works
86
+ // Fast path: already works (cached or live test)
84
87
  if (testNodePty()) {
85
- console.log('[termify-agent] node-pty is already working.');
88
+ console.log('[termify-agent] node-pty is working.');
86
89
  return true;
87
90
  }
88
91
 
89
- const nodePtyDir = resolveNodePtyDir();
90
- if (!nodePtyDir) {
91
- console.error('[termify-agent] CRITICAL: node-pty directory not found.');
92
- console.error('[termify-agent] Manual fix: npm install node-pty --build-from-source');
93
- return false;
94
- }
92
+ console.log(`[termify-agent] Node.js version: ${process.version}`);
95
93
 
96
94
  console.log(`[termify-agent] node-pty resolved at: ${nodePtyDir}`);
97
95
  console.log('[termify-agent] node-pty prebuilt not working, attempting source rebuild...');
@@ -787,57 +785,95 @@ function ensureCodexInstructions() {
787
785
  }
788
786
  }
789
787
 
788
+ // ---------------------------------------------------------------------------
789
+ // Pretty CLI output (no external deps — runs during postinstall)
790
+ // ---------------------------------------------------------------------------
791
+
792
+ const CYAN = '\x1b[36m';
793
+ const GREEN = '\x1b[32m';
794
+ const YELLOW = '\x1b[33m';
795
+ const DIM = '\x1b[2m';
796
+ const BOLD = '\x1b[1m';
797
+ const RESET = '\x1b[0m';
798
+ const CHECK = `${GREEN}✔${RESET}`;
799
+ const WARN = `${YELLOW}⚠${RESET}`;
800
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
801
+
802
+ function createSpinner(text) {
803
+ let i = 0;
804
+ const id = setInterval(() => {
805
+ process.stdout.write(`\r ${CYAN}${SPINNER_FRAMES[i++ % SPINNER_FRAMES.length]}${RESET} ${text} `);
806
+ }, 80);
807
+ return {
808
+ succeed(msg) { clearInterval(id); process.stdout.write(`\r ${CHECK} ${msg || text} \n`); },
809
+ warn(msg) { clearInterval(id); process.stdout.write(`\r ${WARN} ${msg || text} \n`); },
810
+ update(t) { text = t; },
811
+ };
812
+ }
813
+
814
+ // Suppress verbose internal logs — only spinner UI shows
815
+ const _log = console.log;
816
+ const _warn = console.warn;
817
+ const _err = console.error;
818
+ function muteConsole() { console.log = () => {}; console.warn = () => {}; console.error = () => {}; }
819
+ function unmuteConsole() { console.log = _log; console.warn = _warn; console.error = _err; }
820
+
790
821
  /**
791
822
  * Main
792
823
  */
793
824
  async function main() {
794
- console.log('[termify-agent] Running postinstall...');
795
- console.log(`[termify-agent] Platform: ${platform()}-${arch()}`);
796
-
797
- // Step 1: Rebuild node-pty (critical for terminal functionality)
798
- const nodePtyOk = rebuildNodePty();
799
- if (!nodePtyOk) {
800
- console.error('[termify-agent] WARNING: Terminal features may not work until node-pty is fixed.');
801
- }
802
-
803
- // Step 2: Install termify-daemon (efficient process monitoring)
804
- try {
805
- await installDaemon();
806
- } catch (err) {
807
- console.warn(`[termify-agent] Warning: ${err.message}`);
808
- }
809
-
810
- // Step 3: Install stats-agent (system stats collection)
811
- try {
812
- await installStatsAgent();
813
- } catch (err) {
814
- console.warn(`[termify-agent] Warning: ${err.message}`);
815
- }
816
-
817
- // Step 4: Install termify-mcp, hooks, and configure all CLIs
825
+ console.log('');
826
+ console.log(` ${BOLD}${CYAN}Termify Agent${RESET} ${DIM}postinstall${RESET}`);
827
+ console.log(` ${DIM}${platform()}-${arch()} · Node ${process.version}${RESET}`);
828
+ console.log('');
829
+
830
+ muteConsole();
831
+
832
+ // Step 1: node-pty
833
+ const s1 = createSpinner('Checking node-pty...');
834
+ const ptyOk = rebuildNodePty();
835
+ if (ptyOk) s1.succeed('node-pty ready');
836
+ else s1.warn('node-pty skipped ${DIM}(optional)${RESET}');
837
+
838
+ // Step 2+3: Binaries in parallel
839
+ const s2 = createSpinner('Installing binaries...');
840
+ const [daemonOk, statsOk] = await Promise.all([
841
+ installDaemon().catch(() => false),
842
+ installStatsAgent().catch(() => false),
843
+ ]);
844
+ const parts = [];
845
+ if (daemonOk) parts.push('daemon');
846
+ if (statsOk) parts.push('stats-agent');
847
+ if (parts.length) s2.succeed(`Binaries ready ${DIM}(${parts.join(', ')})${RESET}`);
848
+ else s2.warn('Binaries skipped');
849
+
850
+ // Step 3: MCP + hooks
851
+ const s3 = createSpinner('Configuring hooks & MCP...');
818
852
  try {
819
853
  installTermifyMcp();
854
+ s3.succeed(`Hooks & MCP configured ${DIM}(Claude · Gemini · Codex)${RESET}`);
820
855
  } catch (err) {
821
- console.warn(`[termify-agent] Warning: ${err.message}`);
856
+ s3.warn(`Hooks & MCP: ${err.message}`);
822
857
  }
823
858
 
824
- // Step 5: Ensure AI tool instructions include termify_status usage
859
+ // Step 4: Instructions
860
+ const s4 = createSpinner('Updating AI instructions...');
825
861
  try {
826
862
  ensureClaudeInstructions();
827
- } catch (err) {
828
- console.warn(`[termify-agent] Warning: ${err.message}`);
829
- }
830
- try {
831
863
  ensureCodexInstructions();
864
+ s4.succeed('AI instructions updated');
832
865
  } catch (err) {
833
- console.warn(`[termify-agent] Warning: ${err.message}`);
866
+ s4.warn(`Instructions: ${err.message}`);
834
867
  }
835
868
 
836
- console.log('[termify-agent] Postinstall complete.');
869
+ unmuteConsole();
870
+
871
+ console.log('');
872
+ console.log(` ${GREEN}${BOLD}Done!${RESET} ${DIM}Termify Agent is ready.${RESET}`);
873
+ console.log('');
837
874
  }
838
875
 
839
876
  main().catch((err) => {
840
- console.warn(`[termify-agent] Postinstall warning: ${err.message}`);
841
- // Never fail the install - postinstall errors should be warnings only
877
+ console.warn(`\n ${WARN} Postinstall warning: ${err.message}\n`);
842
878
  process.exit(0);
843
879
  });