azclaude-copilot 0.5.2 → 0.5.4

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
- 1763 tests. Every template, command, capability, agent, hook, and CLI feature verified.
761
+ 1775 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: 1763 passed, 0 failed, 1763 total
765
+ # Results: 1775 passed, 0 failed, 1775 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.2",
3
+ "version": "0.5.4",
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",
@@ -195,6 +195,48 @@ try {
195
195
  }
196
196
  } catch (_) {}
197
197
 
198
+ // ── Compaction Guard — auto-snapshot before context is lost ─────────────────
199
+ // Reads context % signal from statusline (written to temp file after each turn).
200
+ // At >= 70%: warns Claude to save state. At >= 85%: auto-saves checkpoint.
201
+ try {
202
+ const ctxSignalPath = path.join(os.tmpdir(), `.azclaude-ctx-${process.ppid || process.pid}`);
203
+ if (fs.existsSync(ctxSignalPath)) {
204
+ const ctxSignal = JSON.parse(fs.readFileSync(ctxSignalPath, 'utf8'));
205
+ const pct = ctxSignal.ctxPct || 0;
206
+
207
+ if (pct >= 85) {
208
+ // AUTO-SAVE: context is critically high — save checkpoint before compaction wipes it
209
+ const checkpointDir = path.join(cfg, 'memory', 'checkpoints');
210
+ try { fs.mkdirSync(checkpointDir, { recursive: true }); } catch (_) {}
211
+ const ts = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 16);
212
+ const cpPath = path.join(checkpointDir, `${ts}-auto-compaction.md`);
213
+
214
+ // Only auto-save once per threshold crossing (check if already saved)
215
+ const autoSaveMarker = path.join(os.tmpdir(), `.azclaude-autosave-${process.ppid || process.pid}`);
216
+ if (!fs.existsSync(autoSaveMarker)) {
217
+ // Copy goals.md as checkpoint
218
+ if (fs.existsSync(goalsPath)) {
219
+ const goalsContent = fs.readFileSync(goalsPath, 'utf8');
220
+ const header = `---\ndate: ${new Date().toISOString()}\nlabel: auto-compaction-guard-${pct}pct\nfiles_in_progress: []\n---\n\n`;
221
+ fs.writeFileSync(cpPath, header + '## Auto-saved before compaction\n\n' + goalsContent);
222
+ fs.writeFileSync(autoSaveMarker, '');
223
+ }
224
+
225
+ console.log('');
226
+ console.log(`--- COMPACTION GUARD (${pct}%) ---`);
227
+ console.log(`Context at ${pct}% — AUTO-SAVED checkpoint to ${path.basename(cpPath)}`);
228
+ console.log('Run /snapshot NOW to save your reasoning and decisions (goals.md alone is not enough).');
229
+ console.log('--- END GUARD ---');
230
+ }
231
+ } else if (pct >= 70) {
232
+ console.log('');
233
+ console.log(`--- COMPACTION WARNING (${pct}%) ---`);
234
+ console.log(`Context at ${pct}% — compaction approaching. Run /snapshot to save session state.`);
235
+ console.log('--- END WARNING ---');
236
+ }
237
+ }
238
+ } catch (_) {}
239
+
198
240
  // ── First message only — inject full context ────────────────────────────────
199
241
  if (!isFirstMessage) process.exit(0);
200
242
 
@@ -33,6 +33,30 @@ process.stdin.on('end', () => {
33
33
  const cachWrite = data.context_window?.current_usage?.cache_creation_input_tokens || 0;
34
34
  const cachRead = data.context_window?.current_usage?.cache_read_input_tokens || 0;
35
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
+
36
60
  // ── Format helpers ──
37
61
  const durSec = Math.floor(durMs / 1000);
38
62
  const mins = Math.floor(durSec / 60);
@@ -93,6 +117,13 @@ process.stdin.on('end', () => {
93
117
  const empty = 10 - filled;
94
118
  const bar = '\u2593'.repeat(filled) + '\u2591'.repeat(empty);
95
119
 
120
+ // ── Compaction signal — write context % to temp file for hook to read ──
121
+ // This enables the UserPromptSubmit hook to auto-snapshot before compaction.
122
+ try {
123
+ const signalPath = path.join(require('os').tmpdir(), `.azclaude-ctx-${process.ppid || process.pid}`);
124
+ fs.writeFileSync(signalPath, JSON.stringify({ ctxPct, turnsLeft: compactHint ? parseInt(compactHint.replace(/[^0-9]/g,'')) : 999 }));
125
+ } catch (_) {}
126
+
96
127
  // ── Color thresholds ──
97
128
  let ctxColor, ctxWarn = '';
98
129
  if (ctxPct >= 80) { ctxColor = RED; ctxWarn = ' COMPACT SOON'; }
@@ -134,6 +165,12 @@ process.stdin.on('end', () => {
134
165
  line2 += `${DIM}In:${fmtTok(inputTok)} Out:${fmtTok(outputTok)}${RESET} `;
135
166
  }
136
167
 
168
+ // Agent + Skill counts (only show if > 0 — means AZCLAUDE is being used)
169
+ if (agentCount > 0 || skillCount > 0) {
170
+ if (agentCount > 0) line2 += `${CYAN}A:${agentCount}${RESET} `;
171
+ if (skillCount > 0) line2 += `${CYAN}S:${skillCount}${RESET} `;
172
+ }
173
+
137
174
  // Duration
138
175
  line2 += `${DIM}${mins}m${secs}s${RESET}`;
139
176