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 +2 -2
- package/package.json +1 -1
- package/templates/scripts/statusline.js +103 -6
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
|
-
|
|
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:
|
|
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.
|
|
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
|
|
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
|
|
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 += ` ${
|
|
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}
|
|
177
|
+
line2 += ` ${DIM}$${cost.toFixed(2)}${RESET}`;
|
|
81
178
|
}
|
|
82
179
|
|
|
83
180
|
// ── Output ──
|