azclaude-copilot 0.5.1 → 0.5.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.
package/README.md CHANGED
@@ -758,11 +758,11 @@ An agent is a sub-process. Use one when work must happen **in parallel** or **in
758
758
 
759
759
  ## Verified
760
760
 
761
- 1758 tests. Every template, command, capability, agent, hook, and CLI feature verified.
761
+ 1767 tests. Every template, command, capability, agent, hook, and CLI feature verified.
762
762
 
763
763
  ```bash
764
764
  bash tests/test-features.sh
765
- # Results: 1758 passed, 0 failed, 1758 total
765
+ # Results: 1767 passed, 0 failed, 1767 total
766
766
  ```
767
767
 
768
768
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "azclaude-copilot",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
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",
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  // AZCLAUDE statusline — auto-installed by setup
3
- // Shows: model | context % (color-coded) | rate limit | session time | lines changed
3
+ // Shows: model | context bar | git branch | rate limit | cache | time | lines | cost
4
4
  // Updates automatically after every turn — no manual action needed.
5
5
  // Zero dependencies — uses only Node.js (already required by AZCLAUDE).
6
6
  'use strict';
7
7
 
8
+ const { execSync } = require('child_process');
9
+
8
10
  let raw = '';
9
11
  process.stdin.setEncoding('utf8');
10
12
  process.stdin.on('data', chunk => { raw += chunk; });
@@ -25,6 +27,36 @@ process.stdin.on('end', () => {
25
27
  const linesDel = data.cost?.total_lines_removed || 0;
26
28
  const rate5h = data.rate_limits?.five_hour?.used_percentage ?? -1;
27
29
 
30
+ // Token details
31
+ const inputTok = data.context_window?.total_input_tokens || 0;
32
+ const outputTok = data.context_window?.total_output_tokens || 0;
33
+ const cachWrite = data.context_window?.current_usage?.cache_creation_input_tokens || 0;
34
+ const cachRead = data.context_window?.current_usage?.cache_read_input_tokens || 0;
35
+
36
+ // ── Agent + Skill usage (from observations.jsonl — tracked by post-tool-use hook) ──
37
+ const fs = require('fs');
38
+ const path = require('path');
39
+ const projectDir = data.workspace?.current_dir || data.workspace?.project_dir || process.cwd();
40
+ const sessionPid = process.ppid || process.pid;
41
+ let agentCount = 0, skillCount = 0;
42
+ try {
43
+ const obsPath = path.join(projectDir, '.claude', 'memory', 'reflexes', 'observations.jsonl');
44
+ if (fs.existsSync(obsPath)) {
45
+ const lines = fs.readFileSync(obsPath, 'utf8').split('\n').filter(Boolean);
46
+ for (const line of lines) {
47
+ try {
48
+ const obs = JSON.parse(line);
49
+ // Count only this session's observations
50
+ if (String(obs.session) !== String(sessionPid)) continue;
51
+ if (obs.tool === 'Agent' || obs.tool === 'Task') agentCount++;
52
+ if (obs.tool === 'Skill') skillCount++;
53
+ // Also count Read calls on SKILL.md files as skill usage
54
+ if (obs.tool === 'Read' && obs.file && /skills\/.*SKILL\.md/.test(obs.file)) skillCount++;
55
+ } catch (_) {}
56
+ }
57
+ }
58
+ } catch (_) {}
59
+
28
60
  // ── Format helpers ──
29
61
  const durSec = Math.floor(durMs / 1000);
30
62
  const mins = Math.floor(durSec / 60);
@@ -32,10 +64,50 @@ process.stdin.on('end', () => {
32
64
 
33
65
  const ctxLabel = ctxSize >= 1000000 ? '1M' : ctxSize >= 100000 ? '200k' : String(ctxSize);
34
66
 
67
+ // Format large token numbers: 1234567 → 1.2M, 12345 → 12k
68
+ function fmtTok(n) {
69
+ if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
70
+ if (n >= 1000) return (n / 1000).toFixed(0) + 'k';
71
+ return String(n);
72
+ }
73
+
74
+ // ── Git info (cached — fast on subsequent calls) ──
75
+ let gitBranch = '';
76
+ let gitDirty = 0;
77
+ try {
78
+ gitBranch = execSync('git branch --show-current 2>/dev/null', { encoding: 'utf8', timeout: 2000 }).trim();
79
+ const status = execSync('git status --porcelain 2>/dev/null', { encoding: 'utf8', timeout: 2000 }).trim();
80
+ gitDirty = status ? status.split('\n').length : 0;
81
+ } catch (_) {}
82
+
83
+ // ── Compaction prediction ──
84
+ // Estimate turns remaining before context hits 90% (compaction threshold)
85
+ // Uses average tokens per turn from session data
86
+ let compactHint = '';
87
+ if (ctxPct > 0 && ctxPct < 90 && inputTok > 0) {
88
+ const totalTok = Math.floor(ctxSize * ctxPct / 100);
89
+ const remaining = Math.floor(ctxSize * 0.9) - totalTok;
90
+ // Rough estimate: average ~4000 tokens per turn (input + output + overhead)
91
+ const avgPerTurn = 4000;
92
+ const turnsLeft = Math.max(1, Math.floor(remaining / avgPerTurn));
93
+ if (turnsLeft <= 20) {
94
+ compactHint = turnsLeft <= 5 ? ` ~${turnsLeft}t!` : ` ~${turnsLeft}t`;
95
+ }
96
+ }
97
+
98
+ // ── Cache hit ratio ──
99
+ let cacheHint = '';
100
+ if (cachRead > 0 || cachWrite > 0) {
101
+ const total = cachRead + cachWrite;
102
+ const hitPct = total > 0 ? Math.floor(cachRead / total * 100) : 0;
103
+ cacheHint = `Cache:${hitPct}%`;
104
+ }
105
+
35
106
  // ── ANSI colors ──
36
107
  const GREEN = '\x1b[32m';
37
108
  const YELLOW = '\x1b[33m';
38
109
  const RED = '\x1b[31m';
110
+ const CYAN = '\x1b[36m';
39
111
  const DIM = '\x1b[2m';
40
112
  const BOLD = '\x1b[1m';
41
113
  const RESET = '\x1b[0m';
@@ -51,20 +123,45 @@ process.stdin.on('end', () => {
51
123
  else if (ctxPct >= 60) { ctxColor = YELLOW; }
52
124
  else { ctxColor = GREEN; }
53
125
 
54
- // ── Line 1: model + context bar ──
126
+ // ── Line 1: model + context bar + compaction prediction ──
55
127
  let line1 = `${DIM}[${RESET}${BOLD}${model}${RESET}${DIM}]${RESET} `;
56
128
  line1 += `${ctxColor}${bar} ${ctxPct}%${RESET}`;
57
129
  line1 += `${DIM}/${ctxLabel}${RESET}`;
58
130
  if (ctxWarn) line1 += `${RED}${ctxWarn}${RESET}`;
131
+ if (compactHint) {
132
+ const compColor = compactHint.includes('!') ? RED : YELLOW;
133
+ line1 += `${compColor}${compactHint}${RESET}`;
134
+ }
135
+ // Git branch
136
+ if (gitBranch) {
137
+ line1 += ` ${DIM}|${RESET} ${CYAN}${gitBranch}${RESET}`;
138
+ if (gitDirty > 0) line1 += `${YELLOW}*${gitDirty}${RESET}`;
139
+ }
59
140
 
60
- // ── Line 2: rate limit + time + lines + cost ──
141
+ // ── Line 2: rate limit + cache + tokens + time + lines + cost ──
61
142
  let line2 = '';
62
143
 
63
144
  // Rate limit (only show if available — Pro/Max subscription)
64
145
  if (rate5h >= 0) {
65
146
  const r = Math.floor(rate5h);
66
147
  const rColor = r >= 80 ? RED : r >= 50 ? YELLOW : DIM;
67
- line2 += `${rColor}Rate: ${r}%${RESET} ${DIM}|${RESET} `;
148
+ line2 += `${rColor}Rate:${r}%${RESET} `;
149
+ }
150
+
151
+ // Cache hit ratio
152
+ if (cacheHint) {
153
+ line2 += `${DIM}${cacheHint}${RESET} `;
154
+ }
155
+
156
+ // Token totals
157
+ if (inputTok > 0 || outputTok > 0) {
158
+ line2 += `${DIM}In:${fmtTok(inputTok)} Out:${fmtTok(outputTok)}${RESET} `;
159
+ }
160
+
161
+ // Agent + Skill counts (only show if > 0 — means AZCLAUDE is being used)
162
+ if (agentCount > 0 || skillCount > 0) {
163
+ if (agentCount > 0) line2 += `${CYAN}A:${agentCount}${RESET} `;
164
+ if (skillCount > 0) line2 += `${CYAN}S:${skillCount}${RESET} `;
68
165
  }
69
166
 
70
167
  // Duration
@@ -72,12 +169,12 @@ process.stdin.on('end', () => {
72
169
 
73
170
  // Lines changed
74
171
  if (linesAdd > 0 || linesDel > 0) {
75
- line2 += ` ${DIM}|${RESET} ${GREEN}+${linesAdd}${RESET}${DIM}/${RESET}${RED}-${linesDel}${RESET}`;
172
+ line2 += ` ${GREEN}+${linesAdd}${RESET}${DIM}/${RESET}${RED}-${linesDel}${RESET}`;
76
173
  }
77
174
 
78
175
  // Cost (only show if > 0 — API billing)
79
176
  if (cost > 0) {
80
- line2 += ` ${DIM}|${RESET} $${cost.toFixed(2)}`;
177
+ line2 += ` ${DIM}$${cost.toFixed(2)}${RESET}`;
81
178
  }
82
179
 
83
180
  // ── Output ──