halo-agent 2.2.2 → 2.2.3

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.
Files changed (4) hide show
  1. package/index.js +16 -11
  2. package/package.json +1 -1
  3. package/poller.js +2 -1
  4. package/ui.js +50 -8
package/index.js CHANGED
@@ -38,14 +38,18 @@ async function main() {
38
38
  let v = '';
39
39
  try { v = require('./package.json').version; } catch {}
40
40
  ui.banner(v);
41
+ console.log(` ${ui.bold('Usage')} ${ui.gray('halo-agent <command>')}`);
41
42
  console.log('');
42
- console.log(` ${ui.bold('Usage')}`);
43
- console.log(` ${ui.cyan('halo-agent pair')} ${ui.gray('<code>')} One-click pair with the dashboard`);
44
- console.log(` ${ui.cyan('halo-agent start')} Start the agent`);
45
- console.log(` ${ui.cyan('halo-agent install-autostart')} Auto-start at login`);
46
- console.log(` ${ui.cyan('halo-agent uninstall-autostart')} Remove login auto-start`);
47
- console.log(` ${ui.cyan('halo-agent init')} First-time setup (legacy: token paste)`);
48
- console.log(` ${ui.cyan('halo-agent token')} ${ui.gray('<value>')} Update auth token`);
43
+ ui.commandTable([
44
+ ['pair <code>', 'One-click pair with the HALO dashboard'],
45
+ ['start', 'Connect to Chrome and run the agent'],
46
+ ['install-autostart', 'Run automatically at every login'],
47
+ ['uninstall-autostart', 'Remove the login auto-start'],
48
+ ['init', 'First-time setup (legacy token paste)'],
49
+ ['token <value>', 'Update the auth token'],
50
+ ]);
51
+ console.log('');
52
+ ui.hint('Get a pairing code: HALO dashboard → Profile → Auto-apply agent → Get pairing code.');
49
53
  console.log('');
50
54
  process.exit(1);
51
55
  }
@@ -123,7 +127,8 @@ async function runPair(code) {
123
127
  spin.stop(`Paired with HALO`);
124
128
  ui.muted(` Token saved to ~/.halo-agent/config.json`);
125
129
  console.log('');
126
- console.log(` ${ui.gray('Next:')} ${ui.cyan('halo-agent start')}`);
130
+ ui.nextStep('halo-agent start', 'connect Chrome and start applying');
131
+ ui.hint('Or `halo-agent install-autostart` to run it at every login.');
127
132
  console.log('');
128
133
  }
129
134
 
@@ -308,7 +313,7 @@ async function runInit() {
308
313
  saveConfig(config);
309
314
  console.log('');
310
315
  ui.success('Config saved to ~/.halo-agent/config.json');
311
- console.log(` ${ui.gray('Next:')} ${ui.cyan('halo-agent start')}`);
316
+ ui.nextStep('halo-agent start', 'connect Chrome and start applying');
312
317
  console.log('');
313
318
  }
314
319
 
@@ -467,8 +472,8 @@ async function waitForChromeGone(timeoutMs) {
467
472
  async function runStart() {
468
473
  const config = loadConfig();
469
474
  if (!config || !config.token) {
470
- ui.fail('No config found.');
471
- console.log(` ${ui.gray('Run')} ${ui.cyan('halo-agent pair <code>')} ${ui.gray('first. Get a code from the HALO dashboard.')}`);
475
+ ui.fail('Not paired yet — no config found.');
476
+ ui.nextStep('halo-agent pair <code>', 'get a code from the HALO dashboard');
472
477
  process.exit(1);
473
478
  }
474
479
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "halo-agent",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
4
4
  "description": "HALO local apply agent — auto-fills job applications using your real Chrome session",
5
5
  "main": "index.js",
6
6
  "bin": {
package/poller.js CHANGED
@@ -15,7 +15,8 @@ let sessionId = null;
15
15
 
16
16
  async function startPolling(chromeConn, config) {
17
17
  ui.success('Listening for jobs');
18
- ui.muted(` Polling every 5s. ${ui.cyan('Ctrl-C')} to stop.`);
18
+ ui.hint(`Queue one from HALO: a job's prep page → Approve & send to agent.`);
19
+ ui.muted(` Polling every 5s · ${ui.cyan('Ctrl-C')} to stop`);
19
20
  console.log('');
20
21
 
21
22
  // Register agent session with backend
package/ui.js CHANGED
@@ -41,15 +41,56 @@ const warn = (msg) => console.log(`${yellow('!')} ${msg}`);
41
41
  const muted = (msg) => console.log(gray(msg));
42
42
  const step = (msg) => console.log(`${gray(sym.dot)} ${msg}`);
43
43
 
44
- // Banner shown on `start`. Three lines so it has presence on camera without
45
- // being a giant ASCII-art block that ages badly.
44
+ // Strip ANSI so box math measures the VISIBLE width, not the escape-padded
45
+ // string length. Without this, colored content overflows the box border.
46
+ const STRIP_ANSI = /\x1b\[[0-9;]*m/g;
47
+ const visLen = (s) => String(s).replace(STRIP_ANSI, '').length;
48
+
49
+ // Box-drawing glyphs (rounded). ASCII fallback on legacy Windows terminals.
50
+ const box = (process.platform === 'win32' && !process.env.WT_SESSION)
51
+ ? { tl: '+', tr: '+', bl: '+', br: '+', h: '-', v: '|' }
52
+ : { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' };
53
+
54
+ // The compact boxed wordmark. Ember mark + tagline + version, in a rounded
55
+ // box — the Vercel/Bun look. Reads well on camera and in a small terminal,
56
+ // and ages better than big ASCII art. The ⬢ is HALO's hex mark.
46
57
  function banner(version) {
47
- const v = version ? gray(`v${version}`) : '';
48
- const line = gray(''.repeat(40));
58
+ const mark = `${ember('⬢')} ${ember(bold('HALO'))}`;
59
+ const ver = version ? `${gray('agent')} ${gray('v' + version)}` : gray('agent');
60
+ // Two content lines.
61
+ const line1 = `${mark} ${gray('·')} ${ver}`;
62
+ const line2 = gray('auto-apply, in your own Chrome');
63
+ const inner = Math.max(visLen(line1), visLen(line2)) + 2; // 1 space padding each side
64
+ const pad = (s) => ' ' + s + ' '.repeat(inner - visLen(s) - 1);
65
+ const top = gray(box.tl + box.h.repeat(inner) + box.tr);
66
+ const bot = gray(box.bl + box.h.repeat(inner) + box.br);
67
+ const bar = gray(box.v);
68
+ console.log('');
69
+ console.log(` ${top}`);
70
+ console.log(` ${bar}${pad(line1)}${bar}`);
71
+ console.log(` ${bar}${pad(line2)}${bar}`);
72
+ console.log(` ${bot}`);
49
73
  console.log('');
50
- console.log(` ${ember(bold('HALO'))} ${bold('Agent')} ${v}`);
51
- console.log(` ${gray('Auto-apply, in your own Chrome.')}`);
52
- console.log(` ${line}`);
74
+ }
75
+
76
+ // Affordance helper: the obvious next command, rendered consistently so the
77
+ // user always knows what to type next. Shown after pair/init/etc.
78
+ function nextStep(cmd, note) {
79
+ const tail = note ? ` ${gray(note)}` : '';
80
+ console.log(` ${gray('Next')} ${gray(sym.arrow)} ${cyan(cmd)}${tail}`);
81
+ }
82
+
83
+ // A hint line — softer than nextStep, for "you can also…" affordances.
84
+ function hint(msg) {
85
+ console.log(` ${gray(sym.dot)} ${gray(msg)}`);
86
+ }
87
+
88
+ // Aligned command table for the usage screen. rows: [[cmd, desc], ...].
89
+ function commandTable(rows) {
90
+ const w = Math.max(...rows.map(([c]) => c.length));
91
+ for (const [cmd, desc] of rows) {
92
+ console.log(` ${cyan(cmd.padEnd(w))} ${gray(desc)}`);
93
+ }
53
94
  }
54
95
 
55
96
  // Lightweight spinner for waiting states ("Connecting to Chrome..."). Frames
@@ -81,5 +122,6 @@ function spinner(message) {
81
122
 
82
123
  module.exports = {
83
124
  bold, dim, red, green, yellow, blue, magenta, cyan, gray, ember,
84
- sym, success, fail, info, warn, muted, step, banner, spinner,
125
+ sym, success, fail, info, warn, muted, step,
126
+ banner, spinner, nextStep, hint, commandTable, visLen,
85
127
  };