azclaude-copilot 0.3.7 → 0.3.8
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 +3 -3
- package/package.json +1 -1
- package/templates/hooks/post-tool-use.js +28 -1
- package/templates/hooks/stop.js +29 -2
package/README.md
CHANGED
|
@@ -450,7 +450,7 @@ azclaude-copilot/
|
|
|
450
450
|
├── DOCS.md <- full user guide
|
|
451
451
|
├── SECURITY.md <- security policy + architecture
|
|
452
452
|
├── tests/
|
|
453
|
-
│ └── test-features.sh ←
|
|
453
|
+
│ └── test-features.sh ← 1068 tests
|
|
454
454
|
```
|
|
455
455
|
|
|
456
456
|
---
|
|
@@ -476,11 +476,11 @@ The runner is stateless. These files ARE the state.
|
|
|
476
476
|
|
|
477
477
|
## Verified
|
|
478
478
|
|
|
479
|
-
|
|
479
|
+
1068 tests. Every template, command, capability, agent, and CLI feature verified.
|
|
480
480
|
|
|
481
481
|
```bash
|
|
482
482
|
bash tests/test-features.sh
|
|
483
|
-
# Results:
|
|
483
|
+
# Results: 1068 passed, 0 failed, 1068 total
|
|
484
484
|
```
|
|
485
485
|
|
|
486
486
|
---
|
package/package.json
CHANGED
|
@@ -123,6 +123,33 @@ if (!content.includes(HEADING)) {
|
|
|
123
123
|
|
|
124
124
|
try { fs.writeFileSync(goalsPath, content); } catch (_) {}
|
|
125
125
|
|
|
126
|
+
// ── Memory rotation — keep ## In progress bounded at 30 entries ──────────────
|
|
127
|
+
const ROTATE_THRESHOLD = 30;
|
|
128
|
+
const KEEP_NEWEST = 15;
|
|
129
|
+
const rotLines = content.split('\n');
|
|
130
|
+
const rotHIdx = rotLines.findIndex(l => l.trim() === HEADING);
|
|
131
|
+
if (rotHIdx !== -1) {
|
|
132
|
+
const ipEntries = [];
|
|
133
|
+
for (let i = rotHIdx + 1; i < rotLines.length; i++) {
|
|
134
|
+
if (rotLines[i].startsWith('## ')) break;
|
|
135
|
+
if (rotLines[i].startsWith('- ')) ipEntries.push({ line: rotLines[i], idx: i });
|
|
136
|
+
}
|
|
137
|
+
if (ipEntries.length >= ROTATE_THRESHOLD) {
|
|
138
|
+
const toArchive = ipEntries.slice(KEEP_NEWEST);
|
|
139
|
+
const archiveTs = new Date().toISOString().slice(0, 16);
|
|
140
|
+
const archiveDate = new Date().toISOString().slice(0, 10);
|
|
141
|
+
const archivePath = path.join(cfg, 'memory', 'sessions', `${archiveDate}-edits.md`);
|
|
142
|
+
try { fs.mkdirSync(path.join(cfg, 'memory', 'sessions'), { recursive: true }); } catch (_) {}
|
|
143
|
+
const header = `\n<!-- archived: ${archiveTs} source: post-tool-use -->\n`;
|
|
144
|
+
const payload = toArchive.map(e => e.line).join('\n') + '\n';
|
|
145
|
+
try { fs.appendFileSync(archivePath, header + payload); } catch (_) {}
|
|
146
|
+
// Rewrite goals.md keeping only newest 15 entries
|
|
147
|
+
const archivedSet = new Set(toArchive.map(e => e.idx));
|
|
148
|
+
const pruned = rotLines.filter((_, i) => !archivedSet.has(i));
|
|
149
|
+
try { fs.writeFileSync(goalsPath, pruned.join('\n')); } catch (_) {}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
126
153
|
} // end isFileTool goals tracking
|
|
127
154
|
|
|
128
155
|
// ── Reflex observation capture (standard/strict only) ───────────────────────
|
|
@@ -192,5 +219,5 @@ let editCount = 1;
|
|
|
192
219
|
try { editCount = parseInt(fs.readFileSync(counterPath, 'utf8'), 10) + 1; } catch (_) {}
|
|
193
220
|
try { fs.writeFileSync(counterPath, String(editCount)); } catch (_) {}
|
|
194
221
|
if (editCount > 0 && editCount % 15 === 0) {
|
|
195
|
-
process.
|
|
222
|
+
process.stderr.write(`\n⚠ ${editCount} edits this session — run /snapshot before context compaction loses your reasoning\n`);
|
|
196
223
|
}
|
package/templates/hooks/stop.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
const fs = require('fs');
|
|
12
12
|
const path = require('path');
|
|
13
|
+
const os = require('os');
|
|
13
14
|
|
|
14
15
|
// ── Hook profile gate ───────────────────────────────────────────────────────
|
|
15
16
|
// AZCLAUDE_HOOK_PROFILE=minimal|standard|strict (default: standard)
|
|
@@ -62,8 +63,30 @@ if (content.includes(IN_PROGRESS)) {
|
|
|
62
63
|
|
|
63
64
|
content = withoutIP.join('\n');
|
|
64
65
|
} else {
|
|
65
|
-
// Empty In progress — just remove the heading
|
|
66
|
-
content = content.replace(
|
|
66
|
+
// Empty In progress — just remove the heading + any trailing blank lines
|
|
67
|
+
content = content.replace(new RegExp('\\n' + IN_PROGRESS + '\\n(\\n)*', 'g'), '\n');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── Trim "Done this session" to max 20 entries (overflow → archive) ──────────
|
|
72
|
+
const DONE_KEEP = 20;
|
|
73
|
+
const trimLines = content.split('\n');
|
|
74
|
+
const dTrimIdx = trimLines.findIndex(l => l.trim() === DONE);
|
|
75
|
+
if (dTrimIdx !== -1) {
|
|
76
|
+
const doneEntries = [];
|
|
77
|
+
for (let i = dTrimIdx + 1; i < trimLines.length; i++) {
|
|
78
|
+
if (trimLines[i].startsWith('## ')) break;
|
|
79
|
+
if (trimLines[i].startsWith('- ')) doneEntries.push({ line: trimLines[i], idx: i });
|
|
80
|
+
}
|
|
81
|
+
if (doneEntries.length > DONE_KEEP) {
|
|
82
|
+
const toArchive = doneEntries.slice(DONE_KEEP);
|
|
83
|
+
const archivePath = path.join(cfg, 'memory', 'sessions', `${today}-edits.md`);
|
|
84
|
+
try { fs.mkdirSync(path.join(cfg, 'memory', 'sessions'), { recursive: true }); } catch (_) {}
|
|
85
|
+
const header = `\n<!-- archived: ${today} source: stop -->\n`;
|
|
86
|
+
const payload = toArchive.map(e => e.line).join('\n') + '\n';
|
|
87
|
+
try { fs.appendFileSync(archivePath, header + payload); } catch (_) {}
|
|
88
|
+
const archivedSet = new Set(toArchive.map(e => e.idx));
|
|
89
|
+
content = trimLines.filter((_, i) => !archivedSet.has(i)).join('\n');
|
|
67
90
|
}
|
|
68
91
|
}
|
|
69
92
|
|
|
@@ -71,6 +94,10 @@ if (content.includes(IN_PROGRESS)) {
|
|
|
71
94
|
content = content.replace(/^Updated: .*/m, `Updated: ${today}`);
|
|
72
95
|
try { fs.writeFileSync(goalsPath, content); } catch (_) {}
|
|
73
96
|
|
|
97
|
+
// ── Reset edit counter so checkpoint reminder starts fresh next session ───────
|
|
98
|
+
const counterPath = path.join(os.tmpdir(), `.azclaude-edit-count-${process.ppid || process.pid}`);
|
|
99
|
+
try { fs.writeFileSync(counterPath, '0'); } catch (_) {}
|
|
100
|
+
|
|
74
101
|
// ── Warn if /persist was not run (only in AZCLAUDE projects with obs dir) ──
|
|
75
102
|
const obsDir = path.join('ops', 'observations');
|
|
76
103
|
if (!fs.existsSync(obsDir)) process.exit(0);
|