azclaude-copilot 0.5.0 → 0.5.1

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/bin/cli.js CHANGED
@@ -444,36 +444,41 @@ function installScripts(projectDir, cfg) {
444
444
  // ─── Statusline (auto-updating cost/context bar) ─────────────────────────────
445
445
 
446
446
  function installStatusline(projectDir, cfg) {
447
- const scriptSrc = path.join(TEMPLATE_DIR, 'scripts', 'statusline.sh');
447
+ const scriptSrc = path.join(TEMPLATE_DIR, 'scripts', 'statusline.js');
448
448
  if (!fs.existsSync(scriptSrc)) return;
449
449
 
450
- // Copy statusline script to ~/.claude/statusline.sh (global — shared across projects)
450
+ // Copy statusline script to ~/.claude/statusline.js (global — shared across projects)
451
451
  const globalDir = path.join(os.homedir(), '.claude');
452
- const scriptDst = path.join(globalDir, 'statusline.sh');
452
+ const scriptDst = path.join(globalDir, 'statusline.js');
453
453
  fs.mkdirSync(globalDir, { recursive: true });
454
454
  fs.copyFileSync(scriptSrc, scriptDst);
455
- try { fs.chmodSync(scriptDst, '755'); } catch {}
455
+
456
+ // Remove old .sh version if it exists (migrating from v0.5.0)
457
+ const oldSh = path.join(globalDir, 'statusline.sh');
458
+ try { if (fs.existsSync(oldSh)) fs.unlinkSync(oldSh); } catch {}
456
459
 
457
460
  // Configure in global settings.json (statusLine is a global Claude Code setting)
461
+ const nodeExe = process.execPath;
458
462
  const settingsPath = path.join(globalDir, 'settings.json');
459
463
  let settings = {};
460
464
  if (fs.existsSync(settingsPath)) {
461
465
  try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch {}
462
466
  }
463
467
 
464
- // Only add if not already configured (don't overwrite user customization)
465
- if (!settings.statusLine) {
466
- // Use forward-slash path for cross-platform shell compatibility
467
- const scriptPath = scriptDst.replace(/\\/g, '/');
468
+ // Always update the command to use Node.js (migrates from old .sh version)
469
+ const scriptPath = scriptDst.replace(/\\/g, '/');
470
+ const nodePath = nodeExe.replace(/\\/g, '/');
471
+ const needsUpdate = !settings.statusLine
472
+ || (settings.statusLine.command && settings.statusLine.command.includes('statusline.sh'));
473
+ if (needsUpdate) {
468
474
  settings.statusLine = {
469
475
  type: 'command',
470
- command: scriptPath,
476
+ command: `"${nodePath}" "${scriptPath}"`,
471
477
  padding: 1
472
478
  };
473
479
  atomicWriteFileSync(settingsPath, JSON.stringify(settings, null, 2));
474
- ok('Statusline installed — context %, rate limit, session time visible after every turn');
480
+ ok('Statusline installed (Node.js) — context %, rate limit, session time visible after every turn');
475
481
  } else {
476
- // Always refresh the script even if config exists
477
482
  info('Statusline already configured — script refreshed');
478
483
  }
479
484
  }
@@ -994,8 +999,8 @@ function runDoctor() {
994
999
 
995
1000
  // ── Statusline ──────────────────────────────────────────────────────────
996
1001
  console.log('\n[ Statusline ]');
997
- const statuslineScript = path.join(os.homedir(), '.claude', 'statusline.sh');
998
- chk('statusline.sh exists (~/.claude/statusline.sh)', fs.existsSync(statuslineScript));
1002
+ const statuslineScript = path.join(os.homedir(), '.claude', 'statusline.js');
1003
+ chk('statusline.js exists (~/.claude/statusline.js)', fs.existsSync(statuslineScript));
999
1004
  if (cli.hooksDir) {
1000
1005
  const globalSettingsPath = path.join(cli.hooksDir, 'settings.json');
1001
1006
  if (fs.existsSync(globalSettingsPath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azclaude-copilot",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "AI coding environment — 39 commands, 10 skills, 15 agents, memory, reflexes, evolution. Install: npx azclaude-copilot@latest, then open Claude Code.",
5
5
  "bin": {
6
6
  "azclaude": "bin/cli.js",
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ // AZCLAUDE statusline — auto-installed by setup
3
+ // Shows: model | context % (color-coded) | rate limit | session time | lines changed
4
+ // Updates automatically after every turn — no manual action needed.
5
+ // Zero dependencies — uses only Node.js (already required by AZCLAUDE).
6
+ 'use strict';
7
+
8
+ let raw = '';
9
+ process.stdin.setEncoding('utf8');
10
+ process.stdin.on('data', chunk => { raw += chunk; });
11
+ process.stdin.on('end', () => {
12
+ let data = {};
13
+ try { data = JSON.parse(raw); } catch (_) {
14
+ process.stdout.write('[AZCLAUDE] statusline: invalid JSON input\n');
15
+ process.exit(0);
16
+ }
17
+
18
+ // ── Extract metrics ──
19
+ const model = data.model?.display_name || 'Claude';
20
+ const ctxPct = Math.floor(data.context_window?.used_percentage || 0);
21
+ const ctxSize = data.context_window?.context_window_size || 0;
22
+ const cost = data.cost?.total_cost_usd || 0;
23
+ const durMs = data.cost?.total_duration_ms || 0;
24
+ const linesAdd = data.cost?.total_lines_added || 0;
25
+ const linesDel = data.cost?.total_lines_removed || 0;
26
+ const rate5h = data.rate_limits?.five_hour?.used_percentage ?? -1;
27
+
28
+ // ── Format helpers ──
29
+ const durSec = Math.floor(durMs / 1000);
30
+ const mins = Math.floor(durSec / 60);
31
+ const secs = durSec % 60;
32
+
33
+ const ctxLabel = ctxSize >= 1000000 ? '1M' : ctxSize >= 100000 ? '200k' : String(ctxSize);
34
+
35
+ // ── ANSI colors ──
36
+ const GREEN = '\x1b[32m';
37
+ const YELLOW = '\x1b[33m';
38
+ const RED = '\x1b[31m';
39
+ const DIM = '\x1b[2m';
40
+ const BOLD = '\x1b[1m';
41
+ const RESET = '\x1b[0m';
42
+
43
+ // ── Context bar (10 segments) ──
44
+ const filled = Math.floor(ctxPct * 10 / 100);
45
+ const empty = 10 - filled;
46
+ const bar = '\u2593'.repeat(filled) + '\u2591'.repeat(empty);
47
+
48
+ // ── Color thresholds ──
49
+ let ctxColor, ctxWarn = '';
50
+ if (ctxPct >= 80) { ctxColor = RED; ctxWarn = ' COMPACT SOON'; }
51
+ else if (ctxPct >= 60) { ctxColor = YELLOW; }
52
+ else { ctxColor = GREEN; }
53
+
54
+ // ── Line 1: model + context bar ──
55
+ let line1 = `${DIM}[${RESET}${BOLD}${model}${RESET}${DIM}]${RESET} `;
56
+ line1 += `${ctxColor}${bar} ${ctxPct}%${RESET}`;
57
+ line1 += `${DIM}/${ctxLabel}${RESET}`;
58
+ if (ctxWarn) line1 += `${RED}${ctxWarn}${RESET}`;
59
+
60
+ // ── Line 2: rate limit + time + lines + cost ──
61
+ let line2 = '';
62
+
63
+ // Rate limit (only show if available — Pro/Max subscription)
64
+ if (rate5h >= 0) {
65
+ const r = Math.floor(rate5h);
66
+ const rColor = r >= 80 ? RED : r >= 50 ? YELLOW : DIM;
67
+ line2 += `${rColor}Rate: ${r}%${RESET} ${DIM}|${RESET} `;
68
+ }
69
+
70
+ // Duration
71
+ line2 += `${DIM}${mins}m${secs}s${RESET}`;
72
+
73
+ // Lines changed
74
+ if (linesAdd > 0 || linesDel > 0) {
75
+ line2 += ` ${DIM}|${RESET} ${GREEN}+${linesAdd}${RESET}${DIM}/${RESET}${RED}-${linesDel}${RESET}`;
76
+ }
77
+
78
+ // Cost (only show if > 0 — API billing)
79
+ if (cost > 0) {
80
+ line2 += ` ${DIM}|${RESET} $${cost.toFixed(2)}`;
81
+ }
82
+
83
+ // ── Output ──
84
+ process.stdout.write(line1 + '\n');
85
+ process.stdout.write(line2 + '\n');
86
+ });