azclaude-copilot 0.6.0 → 0.7.0
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +34 -21
- package/bin/cli.js +60 -2
- package/package.json +2 -2
- package/templates/commands/visualize.md +48 -0
- package/templates/hooks/post-tool-use.js +18 -1
- package/templates/hooks/pre-tool-use.js +21 -0
- package/templates/hooks/stop.js +34 -0
- package/templates/hooks/user-prompt.js +16 -0
- package/templates/hooks/visualizer-hook.js +58 -0
- package/templates/visualizer/public/app.js +395 -0
- package/templates/visualizer/public/audio.js +210 -0
- package/templates/visualizer/public/canvas.js +234 -0
- package/templates/visualizer/public/index.html +93 -0
- package/templates/visualizer/public/style.css +178 -0
- package/templates/visualizer/server.js +225 -0
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
"plugins": [
|
|
9
9
|
{
|
|
10
10
|
"name": "azclaude",
|
|
11
|
-
"description": "AZCLAUDE is a complete AI coding environment for Claude Code. It installs
|
|
12
|
-
"version": "0.
|
|
11
|
+
"description": "AZCLAUDE is a complete AI coding environment for Claude Code. It installs 40 commands, 10 auto-invoked skills, 15 specialized agents, 5 hooks, a real-time pipeline visualizer, and a persistent memory system — in one command.\n\nKey features:\n• Memory across sessions — goals.md + checkpoints injected automatically before every session\n• Self-improving loop — /reflect fixes stale CLAUDE.md rules, /reflexes learns from tool-use patterns, /evolve creates agents from git evidence\n• Autonomous copilot mode — /copilot runs a three-tier team (orchestrator → problem-architect → milestone-builder) across sessions until the product ships\n• Spec-driven workflow — /constitute writes project rules, /spec writes structured ACs, /analyze detects plan drift and ghost milestones, /blueprint traces every milestone to a spec\n• Security layer — 111-rule environment scan (/sentinel), pre-write secret blocking, pre-ship credential audit\n• Progressive levels 0–10 — start with CLAUDE.md, grow into multi-agent pipelines and self-evolving environments\n• Zero dependencies — no npm packages, no external APIs, no vector databases. Plain markdown files and Claude Code's native architecture.\n• Smart install — npx azclaude-copilot@latest auto-detects first install vs upgrade vs verify. Context-aware onboarding shows the right next command for your project state.\n\nExample use cases:\n• /setup — scan an existing project, detect stack + domain + scale, fill CLAUDE.md, generate project-specific skills and agents automatically\n• /copilot \"Build a compliance SaaS with trilingual support\" — walk away, come back to working code across multiple sessions\n• /sentinel — run a scored security audit (0–100, grade A–F) across hooks, permissions, MCP servers, agent configs, and secrets\n• /evolve — detect gaps in the environment, generate new skills and agents from git co-change evidence, report score delta (e.g. 42/100 → 68/100)\n• /constitute — write your project's constitution (non-negotiables, architectural commitments, definition of done) — gates all future AI actions\n• /analyze — cross-artifact consistency check: ghost milestones, spec vs. code drift, unplanned commits\n• /reflect — find stale, missing, or contradicting rules in CLAUDE.md and propose exact fixes\n• /debate \"REST vs GraphQL for this project\" — adversarial evidence-based decision with order-independent scoring, logged to decisions.md",
|
|
12
|
+
"version": "0.7.0",
|
|
13
13
|
"source": {
|
|
14
14
|
"source": "github",
|
|
15
15
|
"repo": "haytamAroui/AZ-CLAUDE-COPILOT",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azclaude",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AZCLAUDE is a complete AI coding environment for Claude Code. It installs
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "AZCLAUDE is a complete AI coding environment for Claude Code. It installs 40 commands, 10 auto-invoked skills, 15 specialized agents, 5 hooks, a real-time pipeline visualizer, and a persistent memory system — in one command.\n\nKey features:\n• Memory across sessions — goals.md + checkpoints injected automatically before every session\n• Self-improving loop — /reflect fixes stale CLAUDE.md rules, /reflexes learns from tool-use patterns, /evolve creates agents from git evidence\n• Autonomous copilot mode — /copilot runs a three-tier team (orchestrator → problem-architect → milestone-builder) across sessions until the product ships\n• Spec-driven workflow — /constitute writes project rules, /spec writes structured ACs, /analyze detects plan drift and ghost milestones, /blueprint traces every milestone to a spec\n• Security layer — 111-rule environment scan (/sentinel), pre-write secret blocking, pre-ship credential audit\n• Progressive levels 0–10 — start with CLAUDE.md, grow into multi-agent pipelines and self-evolving environments\n• Zero dependencies — no npm packages, no external APIs, no vector databases. Plain markdown files and Claude Code's native architecture.\n• Smart install — npx azclaude-copilot@latest auto-detects first install vs upgrade vs verify. Context-aware onboarding shows the right next command for your project state.\n\nExample use cases:\n• /setup — scan an existing project, detect stack + domain + scale, fill CLAUDE.md, generate project-specific skills and agents automatically\n• /copilot \"Build a compliance SaaS with trilingual support\" — walk away, come back to working code across multiple sessions\n• /sentinel — run a scored security audit (0–100, grade A–F) across hooks, permissions, MCP servers, agent configs, and secrets\n• /evolve — detect gaps in the environment, generate new skills and agents from git co-change evidence, report score delta (e.g. 42/100 → 68/100)\n• /constitute — write your project's constitution (non-negotiables, architectural commitments, definition of done) — gates all future AI actions\n• /analyze — cross-artifact consistency check: ghost milestones, spec vs. code drift, unplanned commits\n• /reflect — find stale, missing, or contradicting rules in CLAUDE.md and propose exact fixes\n• /debate \"REST vs GraphQL for this project\" — adversarial evidence-based decision with order-independent scoring, logged to decisions.md",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "haytamAroui",
|
|
7
7
|
"url": "https://github.com/haytamAroui"
|
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Repeats the same mistakes. antipatterns.md prevents known failures.
|
|
|
40
40
|
Forgets what was decided. decisions.md logs every architecture choice.
|
|
41
41
|
Loses reasoning mid-session. /snapshot saves WHY — auto-injected next session.
|
|
42
42
|
Can't work autonomously. /copilot builds, tests, commits, ships — unattended.
|
|
43
|
-
Agents run serially, one at a time.
|
|
43
|
+
Agents run serially, one at a time. DAG dispatch + merge-on-complete runs 6 agents simultaneously.
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
One install. Any stack. Zero dependencies.
|
|
@@ -110,7 +110,7 @@ npx azclaude-copilot@latest
|
|
|
110
110
|
|
|
111
111
|
One command, no flags. Auto-detects whether this is a fresh install or an upgrade:
|
|
112
112
|
|
|
113
|
-
- **First time** → full install (
|
|
113
|
+
- **First time** → full install (40 commands, 5 hooks, 15 agents, 10 skills, memory, reflexes). Creates folders, instructions, and hooks — **no manual setup required.**
|
|
114
114
|
- **Already installed, older version** → auto-upgrades everything to latest templates
|
|
115
115
|
- **Already up to date** → verifies, no overwrites
|
|
116
116
|
|
|
@@ -123,7 +123,7 @@ npx azclaude-copilot@latest doctor # 32 checks — verify everything is wired
|
|
|
123
123
|
|
|
124
124
|
## What You Get
|
|
125
125
|
|
|
126
|
-
**
|
|
126
|
+
**40 commands** · **10 auto-invoked skills** · **15 agents** · **5 hooks** · **memory across sessions** · **learned reflexes** · **self-evolving environment**
|
|
127
127
|
|
|
128
128
|
```
|
|
129
129
|
.claude/
|
|
@@ -272,7 +272,7 @@ Claude Code
|
|
|
272
272
|
│ └── stop.js → Session cleanup, friction logging
|
|
273
273
|
│
|
|
274
274
|
└── Markdown files (capability — Claude reads natively, zero overhead)
|
|
275
|
-
├──
|
|
275
|
+
├── 40 commands → Claude reads the .md, follows instructions
|
|
276
276
|
├── 15 agents → Claude spawns as subagents with Task tool
|
|
277
277
|
├── 10 skills → Auto-invoked when relevant context detected
|
|
278
278
|
├── 48 capabilities → Lazy-loaded via manifest.md (~100 tokens overhead)
|
|
@@ -357,19 +357,19 @@ Never writes code Never implements
|
|
|
357
357
|
|
|
358
358
|
## Parallel Execution
|
|
359
359
|
|
|
360
|
-
AZCLAUDE runs
|
|
360
|
+
AZCLAUDE runs up to 6 Claude Code agents simultaneously using **DAG-based dispatch** — each milestone launches the moment its dependencies are satisfied, not when an entire wave completes. Merge-on-complete means finished agents unblock dependents immediately.
|
|
361
361
|
|
|
362
362
|
```
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
363
|
+
M0 (foundation) → done ← auto-detected shared files
|
|
364
|
+
↓
|
|
365
|
+
┌────────────┬────────────┬────────────┬────────────┬────────────┬──────────────┐
|
|
366
|
+
M1 (auth) M2 (profile) M3 (email) M4 (tests) M5 (NIST) M6 (dashboard)
|
|
367
|
+
└���────┬──────┴────────────┴─────┬──────┴────────────┴────────────┴──────────────┘
|
|
368
|
+
↓ ↓ ← merge-on-complete: M1 done → M7 starts
|
|
369
|
+
M7 (API routes) M8 (integration) immediately, doesn't wait for M2-M6
|
|
370
370
|
```
|
|
371
371
|
|
|
372
|
-
|
|
372
|
+
DAG dispatch instead of sequential waves. Same output, ~50% faster wall clock.
|
|
373
373
|
|
|
374
374
|
### Real case — ShopFlow e-commerce sprint
|
|
375
375
|
|
|
@@ -410,13 +410,26 @@ What the classifier caught: M1 and M2 were separate plan milestones but both wro
|
|
|
410
410
|
|
|
411
411
|
**On tokens:** You will notice the token counts look large. You would spend the same tokens building this sequentially — the work is identical. What changes is wall-clock time. Sequential execution: each agent waits for the previous one to finish → ~2 hours. Parallel waves: agents run simultaneously → ~15 minutes. Same total tokens. Same output. One-eighth the time.
|
|
412
412
|
|
|
413
|
-
###
|
|
413
|
+
### v0.6.0: What changed in parallel execution
|
|
414
|
+
|
|
415
|
+
| Before (wave-based) | After (DAG-based) |
|
|
416
|
+
|---------------------|-------------------|
|
|
417
|
+
| Wave 2 waits for ALL of Wave 1 | Each milestone launches when its `Depends:` are satisfied |
|
|
418
|
+
| Max 3 agents at once | Max 6 agents (test-only agents uncapped) |
|
|
419
|
+
| Manual Wave 0 for shared files | Auto-foundation detection extracts shared-file edits |
|
|
420
|
+
| Agents re-read shared files independently | Pre-read injection: shared files read once, injected inline |
|
|
421
|
+
| Agents run full test suite | Scoped tests: each agent runs only its module's tests |
|
|
422
|
+
| Merge after entire wave completes | Merge-on-complete: each branch merges immediately, unblocks dependents |
|
|
423
|
+
| Context loss kills the wave | Wave state file survives compaction, auto-resumes on next session |
|
|
424
|
+
|
|
425
|
+
### Five-layer safety model
|
|
414
426
|
|
|
415
427
|
Parallel execution is safe only when agents don't write to the same files. The key insight: **Layer 0 makes conflicts impossible by design** before any safety checking begins.
|
|
416
428
|
|
|
417
429
|
| Layer | When | What |
|
|
418
430
|
|-------|------|------|
|
|
419
431
|
| **0 — Task Classifier** | `/blueprint`, before milestones exist | Groups coupled work into single milestones. Conflicts become impossible by construction. |
|
|
432
|
+
| **0b — Foundation Detection** | Before dispatch | Auto-detects shared files (models, schemas) → sequential Wave 0 before any parallel agents |
|
|
420
433
|
| **1 — Directory + import check** | `/blueprint`, post-plan | Fast grep: same dirs? shared utility imports? |
|
|
421
434
|
| **2 — problem-architect file scan** | Post-plan, per milestone | Returns exact `Files Written:` paths + `Parallel Safe: YES/NO` |
|
|
422
435
|
| **3 — Orchestrator dispatch gate** | Runtime, final | Overlap check before spawning. Cannot be bypassed. |
|
|
@@ -427,12 +440,12 @@ Claude Code's `isolation: "worktree"` in the Task tool is a raw primitive — li
|
|
|
427
440
|
|
|
428
441
|
| Without AZCLAUDE | With AZCLAUDE |
|
|
429
442
|
|------------------|---------------|
|
|
430
|
-
| Which tasks to parallelize? | **Task Classifier** — groups coupled work,
|
|
431
|
-
| Is it safe to parallelize? | **
|
|
432
|
-
| What context does each agent need? | **Problem-Architect** —
|
|
443
|
+
| Which tasks to parallelize? | **Task Classifier + DAG dispatch** — groups coupled work, launches on dependency satisfaction |
|
|
444
|
+
| Is it safe to parallelize? | **Five-layer safety** — classifier + foundation + dir check + file scan + dispatch gate |
|
|
445
|
+
| What context does each agent need? | **Problem-Architect** — Team Spec + pre-read injection (shared files read once) |
|
|
433
446
|
| What conventions to follow? | **patterns.md / antipatterns.md** — injected automatically |
|
|
434
|
-
| What if one agent fails? | **Blocker recovery + /debate escalation** |
|
|
435
|
-
| What happens when the session ends? | **
|
|
447
|
+
| What if one agent fails? | **Blocker recovery + /debate escalation** (other agents continue) |
|
|
448
|
+
| What happens when the session ends? | **DAG state file + checkpoints** — auto-resumes interrupted waves |
|
|
436
449
|
| How do we improve over time? | **/evolve** — new agents from git evidence every 3 milestones |
|
|
437
450
|
|
|
438
451
|
**Claude Code is the engine. AZCLAUDE is the transmission, the steering, and the GPS — the system that makes those cylinders produce coordinated forward motion instead of random spinning.**
|
|
@@ -624,11 +637,11 @@ AZCLAUDE is a lazy-loaded environment of 48 capability modules. It only loads wh
|
|
|
624
637
|
|
|
625
638
|
## Verified
|
|
626
639
|
|
|
627
|
-
|
|
640
|
+
1868 tests. Every template, command, capability, agent, hook, and CLI feature verified.
|
|
628
641
|
|
|
629
642
|
```bash
|
|
630
643
|
bash tests/test-features.sh
|
|
631
|
-
# Results:
|
|
644
|
+
# Results: 1868 passed, 0 failed, 1868 total
|
|
632
645
|
```
|
|
633
646
|
|
|
634
647
|
---
|
package/bin/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ const { execSync } = require('child_process');
|
|
|
8
8
|
|
|
9
9
|
const TEMPLATE_DIR = path.join(__dirname, '..', 'templates');
|
|
10
10
|
const CORE_COMMANDS = ['setup', 'fix', 'add', 'audit', 'test', 'blueprint', 'ship', 'pulse', 'explain', 'snapshot', 'persist'];
|
|
11
|
-
const EXTENDED_COMMANDS = ['dream', 'refactor', 'doc', 'loop', 'migrate', 'deps', 'find', 'create', 'reflect', 'hookify', 'sentinel', 'clarify', 'spec', 'analyze', 'constitute', 'tasks', 'issues', 'driven', 'mcp', 'verify', 'inoculate', 'ghost-test'];
|
|
11
|
+
const EXTENDED_COMMANDS = ['dream', 'refactor', 'doc', 'loop', 'migrate', 'deps', 'find', 'create', 'reflect', 'hookify', 'sentinel', 'clarify', 'spec', 'analyze', 'constitute', 'tasks', 'issues', 'driven', 'mcp', 'verify', 'inoculate', 'ghost-test', 'visualize'];
|
|
12
12
|
const ADVANCED_COMMANDS = ['evolve', 'debate', 'level-up', 'copilot', 'reflexes', 'parallel'];
|
|
13
13
|
const COMMANDS = [...CORE_COMMANDS, ...EXTENDED_COMMANDS, ...ADVANCED_COMMANDS];
|
|
14
14
|
|
|
@@ -118,7 +118,7 @@ function substitutePaths(content, cfg) {
|
|
|
118
118
|
|
|
119
119
|
// ─── Hook Scripts ─────────────────────────────────────────────────────────────
|
|
120
120
|
|
|
121
|
-
const HOOK_SCRIPTS = ['user-prompt.js', 'stop.js', 'post-tool-use.js', 'pre-tool-use.js'];
|
|
121
|
+
const HOOK_SCRIPTS = ['user-prompt.js', 'stop.js', 'post-tool-use.js', 'pre-tool-use.js', 'visualizer-hook.js'];
|
|
122
122
|
|
|
123
123
|
function copyHookScripts(dstDir) {
|
|
124
124
|
fs.mkdirSync(dstDir, { recursive: true });
|
|
@@ -140,11 +140,15 @@ function buildHookEntries(scriptsDir) {
|
|
|
140
140
|
const stopScript = path.join(scriptsDir, 'stop.js');
|
|
141
141
|
const postToolUseScript = path.join(scriptsDir, 'post-tool-use.js');
|
|
142
142
|
const preToolUseScript = path.join(scriptsDir, 'pre-tool-use.js');
|
|
143
|
+
const vizScript = path.join(scriptsDir, 'visualizer-hook.js');
|
|
143
144
|
return {
|
|
144
145
|
UserPromptSubmit: [{ matcher: '', hooks: [{ type: 'command', command: `"${nodeExe}" "${userPromptScript}"` }] }],
|
|
145
146
|
Stop: [{ matcher: '', hooks: [{ type: 'command', command: `"${nodeExe}" "${stopScript}"` }] }],
|
|
146
147
|
PreToolUse: [{ matcher: 'Write|Edit|MultiEdit', hooks: [{ type: 'command', command: `"${nodeExe}" "${preToolUseScript}"` }] }],
|
|
147
148
|
PostToolUse: [{ matcher: 'Write|Edit|Read|Bash|Grep', hooks: [{ type: 'command', command: `"${nodeExe}" "${postToolUseScript}"` }] }],
|
|
149
|
+
Notification: [{ matcher: '', hooks: [{ type: 'command', command: `"${nodeExe}" "${vizScript}"` }] }],
|
|
150
|
+
SubagentStart: [{ matcher: '', hooks: [{ type: 'command', command: `"${nodeExe}" "${vizScript}"` }] }],
|
|
151
|
+
SubagentStop: [{ matcher: '', hooks: [{ type: 'command', command: `"${nodeExe}" "${vizScript}"` }] }],
|
|
148
152
|
};
|
|
149
153
|
}
|
|
150
154
|
|
|
@@ -441,6 +445,23 @@ function installScripts(projectDir, cfg) {
|
|
|
441
445
|
ok(`Scripts installed/updated (${cfg}/scripts/)`);
|
|
442
446
|
}
|
|
443
447
|
|
|
448
|
+
// ─── Visualizer (real-time pipeline dashboard) ──────────────────────────────
|
|
449
|
+
|
|
450
|
+
function installVisualizer(projectDir, cfg) {
|
|
451
|
+
const src = path.join(TEMPLATE_DIR, 'visualizer');
|
|
452
|
+
if (!fs.existsSync(src)) return;
|
|
453
|
+
const dst = path.join(projectDir, cfg, 'visualizer');
|
|
454
|
+
if (fs.existsSync(dst)) {
|
|
455
|
+
// Refresh files
|
|
456
|
+
copyDir(src, dst);
|
|
457
|
+
info('Visualizer files refreshed');
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
461
|
+
copyDir(src, dst);
|
|
462
|
+
ok(`Visualizer installed (${cfg}/visualizer/) — start with: AZCLAUDE_VISUALIZER=8765 node ${cfg}/visualizer/server.js`);
|
|
463
|
+
}
|
|
464
|
+
|
|
444
465
|
// ─── Statusline (auto-updating cost/context bar) ─────────────────────────────
|
|
445
466
|
|
|
446
467
|
function installStatusline(projectDir, cfg) {
|
|
@@ -1116,6 +1137,42 @@ function copyDir(src, dst) {
|
|
|
1116
1137
|
if (process.argv[2] === 'doctor' && process.argv[3] === '--audit') { runAudit(); process.exit(0); }
|
|
1117
1138
|
if (process.argv[2] === 'doctor') { runDoctor(); process.exit(0); }
|
|
1118
1139
|
if (process.argv[2] === 'demo') { runDemo(); process.exit(0); }
|
|
1140
|
+
if (process.argv[2] === 'visualize') {
|
|
1141
|
+
const action = process.argv[3] || 'start';
|
|
1142
|
+
const detectedCli = detectCLI();
|
|
1143
|
+
const vizCfg = detectedCli.cfg;
|
|
1144
|
+
const serverPath = path.join(process.cwd(), vizCfg, 'visualizer', 'server.js');
|
|
1145
|
+
if (!fs.existsSync(serverPath)) {
|
|
1146
|
+
console.error('Visualizer not installed. Run: npx azclaude-copilot');
|
|
1147
|
+
process.exit(1);
|
|
1148
|
+
}
|
|
1149
|
+
if (action === 'stop') {
|
|
1150
|
+
const pidFile = path.join(os.tmpdir(), '.azclaude-visualizer.pid');
|
|
1151
|
+
if (fs.existsSync(pidFile)) {
|
|
1152
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf8'), 10);
|
|
1153
|
+
try { process.kill(pid); } catch (_) {}
|
|
1154
|
+
try { fs.unlinkSync(pidFile); } catch (_) {}
|
|
1155
|
+
ok('Visualizer stopped');
|
|
1156
|
+
} else {
|
|
1157
|
+
info('No running visualizer found');
|
|
1158
|
+
}
|
|
1159
|
+
} else {
|
|
1160
|
+
const port = process.argv[4] || '8765';
|
|
1161
|
+
const { spawn } = require('child_process');
|
|
1162
|
+
const child = spawn(process.execPath, [serverPath], {
|
|
1163
|
+
detached: true, stdio: 'ignore',
|
|
1164
|
+
env: Object.assign({}, process.env, { AZCLAUDE_VISUALIZER: port })
|
|
1165
|
+
});
|
|
1166
|
+
child.unref();
|
|
1167
|
+
const pidFile = path.join(os.tmpdir(), '.azclaude-visualizer.pid');
|
|
1168
|
+
fs.writeFileSync(pidFile, String(child.pid));
|
|
1169
|
+
ok(`Visualizer started on port ${port} (PID: ${child.pid})`);
|
|
1170
|
+
info(`Open: http://localhost:${port}`);
|
|
1171
|
+
info(`Set env: AZCLAUDE_VISUALIZER=${port}`);
|
|
1172
|
+
}
|
|
1173
|
+
process.exit(0);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1119
1176
|
if (process.argv[2] === 'copilot') {
|
|
1120
1177
|
// Delegate to copilot runner
|
|
1121
1178
|
const copilotScript = path.join(__dirname, 'copilot.js');
|
|
@@ -1182,6 +1239,7 @@ installCapabilities(projectDir, cli.cfg, fullInstall);
|
|
|
1182
1239
|
installCommands(projectDir, cli.cfg);
|
|
1183
1240
|
installSkills(projectDir, cli.cfg);
|
|
1184
1241
|
installScripts(projectDir, cli.cfg);
|
|
1242
|
+
installVisualizer(projectDir, cli.cfg);
|
|
1185
1243
|
installStatusline(projectDir, cli.cfg);
|
|
1186
1244
|
installAgents(projectDir, cli.cfg);
|
|
1187
1245
|
installRulesFile(projectDir, cli.cfg, cli.rulesFile);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "azclaude-copilot",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "AI coding environment —
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "AI coding environment — 40 commands, 10 skills, 15 agents, real-time visualizer, memory, reflexes, evolution. Install: npx azclaude-copilot@latest, then open Claude Code.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"azclaude": "bin/cli.js",
|
|
7
7
|
"azclaude-copilot": "bin/copilot.js"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# /visualize — Real-Time Session Visualizer
|
|
2
|
+
|
|
3
|
+
Start or stop the AZCLAUDE pipeline-aware visualizer dashboard.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Start the visualizer server
|
|
9
|
+
AZCLAUDE_VISUALIZER=8765 node .claude/visualizer/server.js &
|
|
10
|
+
|
|
11
|
+
# Or via CLI
|
|
12
|
+
azclaude-copilot visualize
|
|
13
|
+
|
|
14
|
+
# Open in browser
|
|
15
|
+
# http://localhost:8765
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Set `AZCLAUDE_VISUALIZER=8765` in your environment so hooks send events to the dashboard.
|
|
19
|
+
|
|
20
|
+
## What You See
|
|
21
|
+
|
|
22
|
+
**Canvas (left 70%):**
|
|
23
|
+
- Tycho-inspired ambient sunset animation
|
|
24
|
+
- Particle blooms on every tool call (color-coded per tool)
|
|
25
|
+
- Red flash on security blocks, amber on warnings
|
|
26
|
+
- Generative F# pentatonic ambient music (toggle on/off)
|
|
27
|
+
|
|
28
|
+
**Sidebar (right 30%):**
|
|
29
|
+
- **Pipeline Progress** — 4-stage bar: architect → implement → review → test
|
|
30
|
+
- **Brain Router Intent** — BUILD, FIX, REFACTOR, TEST, PLAN, etc.
|
|
31
|
+
- **Security Events** — blocks and warnings with rule names
|
|
32
|
+
- **Tool Timeline** — smart summaries, live timers, diff stats (+N/-M)
|
|
33
|
+
- **Session Stats** — tool count, total time, session clock
|
|
34
|
+
|
|
35
|
+
## Stopping
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
azclaude-copilot visualize stop
|
|
39
|
+
# Or just close the terminal running the server
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
The port is set via the `AZCLAUDE_VISUALIZER` environment variable:
|
|
45
|
+
- `AZCLAUDE_VISUALIZER=8765` — default port
|
|
46
|
+
- `AZCLAUDE_VISUALIZER=9000` — custom port
|
|
47
|
+
|
|
48
|
+
When the env var is unset, hooks skip the visualizer POST entirely (zero overhead).
|
|
@@ -178,12 +178,29 @@ if (HOOK_PROFILE !== 'minimal') {
|
|
|
178
178
|
if (seq.length > 3) seq = seq.slice(-3);
|
|
179
179
|
try { fs.writeFileSync(seqPath, JSON.stringify(seq)); } catch (_) {}
|
|
180
180
|
|
|
181
|
+
const seqStr = seq.join('→');
|
|
181
182
|
const obs = JSON.stringify({
|
|
182
183
|
ts: obsTs, tool, file: safeRel, session: process.ppid || process.pid,
|
|
183
|
-
event: 'complete', seq:
|
|
184
|
+
event: 'complete', seq: seqStr
|
|
184
185
|
});
|
|
185
186
|
fs.appendFileSync(obsPath, obs + '\n');
|
|
186
187
|
|
|
188
|
+
// ── Visualizer event (opt-in) ──
|
|
189
|
+
if (process.env.AZCLAUDE_VISUALIZER) {
|
|
190
|
+
try {
|
|
191
|
+
const vPort = parseInt(process.env.AZCLAUDE_VISUALIZER, 10) || 8765;
|
|
192
|
+
const payload = JSON.stringify({ type: 'tool-complete', tool: tool, file: safeRel, diffStat: diffStat || '', seq: seqStr });
|
|
193
|
+
const vReq = require('http').request(
|
|
194
|
+
{ hostname: '127.0.0.1', port: vPort, path: '/event', method: 'POST',
|
|
195
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } },
|
|
196
|
+
() => {}
|
|
197
|
+
);
|
|
198
|
+
vReq.setTimeout(1500, () => vReq.destroy());
|
|
199
|
+
vReq.on('error', () => {});
|
|
200
|
+
vReq.end(payload);
|
|
201
|
+
} catch (_v) {}
|
|
202
|
+
}
|
|
203
|
+
|
|
187
204
|
// Auto-truncate: stat-based size check (avoids reading entire file every call)
|
|
188
205
|
try {
|
|
189
206
|
const obsStat = fs.statSync(obsPath);
|
|
@@ -49,6 +49,23 @@ function _logSec(rule, level, target) {
|
|
|
49
49
|
function _getDedup() { try { return JSON.parse(fs.readFileSync(_dedupPath, 'utf8')); } catch(_) { return {}; } }
|
|
50
50
|
function _saveDedup(d) { try { fs.writeFileSync(_dedupPath, JSON.stringify(d)); } catch(_) {} }
|
|
51
51
|
|
|
52
|
+
// ── Visualizer relay (opt-in, fire-and-forget) ──
|
|
53
|
+
function _vizPost(payload) {
|
|
54
|
+
if (!process.env.AZCLAUDE_VISUALIZER) return;
|
|
55
|
+
try {
|
|
56
|
+
const vPort = parseInt(process.env.AZCLAUDE_VISUALIZER, 10) || 8765;
|
|
57
|
+
const data = JSON.stringify(Object.assign({ type: 'security-event' }, payload));
|
|
58
|
+
const vReq = require('http').request(
|
|
59
|
+
{ hostname: '127.0.0.1', port: vPort, path: '/event', method: 'POST',
|
|
60
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) } },
|
|
61
|
+
() => {}
|
|
62
|
+
);
|
|
63
|
+
vReq.setTimeout(1500, () => vReq.destroy());
|
|
64
|
+
vReq.on('error', () => {});
|
|
65
|
+
vReq.end(data);
|
|
66
|
+
} catch (_) {}
|
|
67
|
+
}
|
|
68
|
+
|
|
52
69
|
// ── Gate: Bash tool — scan shell commands ────────────────────────────────────
|
|
53
70
|
if (toolName === 'Bash' && command) {
|
|
54
71
|
const BASH_RULES = [
|
|
@@ -63,12 +80,14 @@ if (toolName === 'Bash' && command) {
|
|
|
63
80
|
if (!rule.test.test(command)) continue;
|
|
64
81
|
_logSec(rule.id, rule.block ? 'block' : 'warn', command.slice(0, 80));
|
|
65
82
|
if (rule.block) {
|
|
83
|
+
_vizPost({ level: 'block', rule: rule.id, message: rule.message });
|
|
66
84
|
process.stderr.write(`\n✗ SECURITY BLOCK [${rule.id}]: ${rule.message}\n Command: ${command.slice(0, 120)}\n\n`);
|
|
67
85
|
process.exit(2);
|
|
68
86
|
}
|
|
69
87
|
const key = `bash:${rule.id}`;
|
|
70
88
|
if (!dedup[key]) {
|
|
71
89
|
dedup[key] = true; _saveDedup(dedup);
|
|
90
|
+
_vizPost({ level: 'warn', rule: rule.id, message: rule.message });
|
|
72
91
|
process.stderr.write(`\n⚠ SECURITY [${rule.id}]: ${rule.message}\n`);
|
|
73
92
|
}
|
|
74
93
|
}
|
|
@@ -321,6 +340,7 @@ for (const rule of RULES) {
|
|
|
321
340
|
if (rule.block) {
|
|
322
341
|
// Always emit the block message — secrets must never be silently swallowed
|
|
323
342
|
_logSec(rule.id, 'block', displayName);
|
|
343
|
+
_vizPost({ level: 'block', rule: rule.id, message: rule.message });
|
|
324
344
|
process.stderr.write(
|
|
325
345
|
`\n✗ SECURITY BLOCK: ${rule.message} in ${displayName}.\n` +
|
|
326
346
|
` Use environment variables instead: process.env.MY_SECRET\n` +
|
|
@@ -335,6 +355,7 @@ for (const rule of RULES) {
|
|
|
335
355
|
dedup[dedupKey] = true;
|
|
336
356
|
saveDedup();
|
|
337
357
|
_logSec(rule.id, 'warn', displayName);
|
|
358
|
+
_vizPost({ level: 'warn', rule: rule.id, message: rule.message });
|
|
338
359
|
|
|
339
360
|
process.stderr.write(
|
|
340
361
|
`\n⚠ SECURITY: ${rule.message.split(' — ')[0]} in ${displayName} — ${rule.message.includes(' — ') ? rule.message.split(' — ')[1] : rule.message}\n`
|
package/templates/hooks/stop.js
CHANGED
|
@@ -173,6 +173,40 @@ if (fs.existsSync(seclogPath)) {
|
|
|
173
173
|
} catch (_) {}
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
// ── Visualizer session-summary event (opt-in) ──
|
|
177
|
+
if (process.env.AZCLAUDE_VISUALIZER) {
|
|
178
|
+
try {
|
|
179
|
+
const vPort = parseInt(process.env.AZCLAUDE_VISUALIZER, 10) || 8765;
|
|
180
|
+
// Gather session data for the dashboard
|
|
181
|
+
let vizDuration = null, vizBlocks = 0, vizWarnings = 0;
|
|
182
|
+
const vizStartPath = path.join(os.tmpdir(), `.azclaude-session-start-${process.ppid || process.pid}`);
|
|
183
|
+
if (fs.existsSync(vizStartPath)) {
|
|
184
|
+
try {
|
|
185
|
+
const startMs = new Date(fs.readFileSync(vizStartPath, 'utf8').trim()).getTime();
|
|
186
|
+
const mins = Math.round((Date.now() - startMs) / 60000);
|
|
187
|
+
vizDuration = mins > 60 ? Math.floor(mins / 60) + 'h ' + (mins % 60) + 'm' : mins + 'm';
|
|
188
|
+
} catch (_) {}
|
|
189
|
+
}
|
|
190
|
+
if (fs.existsSync(seclogPath)) {
|
|
191
|
+
try {
|
|
192
|
+
const secEvents = fs.readFileSync(seclogPath, 'utf8').split('\n').filter(Boolean)
|
|
193
|
+
.map(l => { try { return JSON.parse(l); } catch (_) { return null; } }).filter(Boolean);
|
|
194
|
+
vizBlocks = secEvents.filter(e => e.level === 'block').length;
|
|
195
|
+
vizWarnings = secEvents.filter(e => e.level === 'warn').length;
|
|
196
|
+
} catch (_) {}
|
|
197
|
+
}
|
|
198
|
+
const payload = JSON.stringify({ type: 'session-summary', duration: vizDuration, blocks: vizBlocks, warnings: vizWarnings });
|
|
199
|
+
const vReq = require('http').request(
|
|
200
|
+
{ hostname: '127.0.0.1', port: vPort, path: '/event', method: 'POST',
|
|
201
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } },
|
|
202
|
+
() => {}
|
|
203
|
+
);
|
|
204
|
+
vReq.setTimeout(1500, () => vReq.destroy());
|
|
205
|
+
vReq.on('error', () => {});
|
|
206
|
+
vReq.end(payload);
|
|
207
|
+
} catch (_v) {}
|
|
208
|
+
}
|
|
209
|
+
|
|
176
210
|
// ── Clean ALL session temp files ─────────────────────────────────────────────
|
|
177
211
|
const sid = process.ppid || process.pid;
|
|
178
212
|
const tempPatterns = [
|
|
@@ -206,6 +206,22 @@ try {
|
|
|
206
206
|
|
|
207
207
|
console.log('This pipeline is NON-NEGOTIABLE. Do not skip steps. Do not start coding before Step 1 completes.');
|
|
208
208
|
console.log('--- END PIPELINE ---');
|
|
209
|
+
|
|
210
|
+
// ── Visualizer event (opt-in) ──
|
|
211
|
+
if (process.env.AZCLAUDE_VISUALIZER) {
|
|
212
|
+
try {
|
|
213
|
+
const vPort = parseInt(process.env.AZCLAUDE_VISUALIZER, 10) || 8765;
|
|
214
|
+
const payload = JSON.stringify({ type: 'pipeline-start', intents: intents, tier: tier, tierLabel: tierLabel });
|
|
215
|
+
const vReq = require('http').request(
|
|
216
|
+
{ hostname: '127.0.0.1', port: vPort, path: '/event', method: 'POST',
|
|
217
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) } },
|
|
218
|
+
() => {}
|
|
219
|
+
);
|
|
220
|
+
vReq.setTimeout(1500, () => vReq.destroy());
|
|
221
|
+
vReq.on('error', () => {});
|
|
222
|
+
vReq.end(payload);
|
|
223
|
+
} catch (_v) {}
|
|
224
|
+
}
|
|
209
225
|
}
|
|
210
226
|
}
|
|
211
227
|
} catch (_) {}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* AZCLAUDE — Visualizer event relay hook
|
|
5
|
+
* Registered for events the other hooks don't cover:
|
|
6
|
+
* Notification, SubagentStart, SubagentStop, SessionStart, SessionEnd, PostToolUseFailure
|
|
7
|
+
* Reads stdin JSON, POSTs to the visualizer server. Fire-and-forget.
|
|
8
|
+
* Only runs when AZCLAUDE_VISUALIZER env var is set.
|
|
9
|
+
* 1500ms hard timeout — never blocks Claude Code.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Gate: exit immediately if visualizer not enabled
|
|
13
|
+
if (!process.env.AZCLAUDE_VISUALIZER) process.exit(0);
|
|
14
|
+
|
|
15
|
+
const http = require('http');
|
|
16
|
+
|
|
17
|
+
const PORT = (() => {
|
|
18
|
+
const n = parseInt(process.env.AZCLAUDE_VISUALIZER, 10);
|
|
19
|
+
return (n > 1 && n < 65536) ? n : 8765;
|
|
20
|
+
})();
|
|
21
|
+
|
|
22
|
+
// Hard safety net
|
|
23
|
+
setTimeout(() => process.exit(0), 1500);
|
|
24
|
+
|
|
25
|
+
let input = '';
|
|
26
|
+
process.stdin.setEncoding('utf8');
|
|
27
|
+
|
|
28
|
+
process.stdin.on('data', chunk => { input += chunk; });
|
|
29
|
+
|
|
30
|
+
process.stdin.on('end', () => {
|
|
31
|
+
if (!input.trim()) process.exit(0);
|
|
32
|
+
|
|
33
|
+
// Validate JSON
|
|
34
|
+
try { JSON.parse(input); } catch { process.exit(0); }
|
|
35
|
+
|
|
36
|
+
const req = http.request({
|
|
37
|
+
hostname: '127.0.0.1',
|
|
38
|
+
port: PORT,
|
|
39
|
+
path: '/event',
|
|
40
|
+
method: 'POST',
|
|
41
|
+
headers: {
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'Content-Length': Buffer.byteLength(input),
|
|
44
|
+
},
|
|
45
|
+
timeout: 1200,
|
|
46
|
+
}, (res) => {
|
|
47
|
+
res.resume();
|
|
48
|
+
res.on('end', () => process.exit(0));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
req.on('error', () => process.exit(0));
|
|
52
|
+
req.on('timeout', () => { req.destroy(); process.exit(0); });
|
|
53
|
+
|
|
54
|
+
req.write(input);
|
|
55
|
+
req.end();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
process.stdin.on('error', () => process.exit(0));
|