claude-autopm 3.22.2 → 3.23.1
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/autopm/.claude/commands/pm:epic-decompose.md +51 -33
- package/autopm/.claude/commands/pm:prd-new.md +41 -9
- package/autopm/.claude/rules/issue-structure.xml +12 -3
- package/autopm/.claude/scripts/pm/dashboard-serve.js +162 -24
- package/autopm/.claude/templates/issue.xml +33 -0
- package/package.json +1 -1
- package/packages/plugin-pm/plugin.json +9 -0
- package/packages/plugin-pm/rules/issue-structure.xml +56 -0
|
@@ -321,66 +321,84 @@ Creating task 002 (Database schema):
|
|
|
321
321
|
✓ Created
|
|
322
322
|
```
|
|
323
323
|
|
|
324
|
-
### 4.
|
|
324
|
+
### 4. MANDATORY: Read Issue Template Before Creating Tasks
|
|
325
|
+
|
|
326
|
+
**CRITICAL**: Before creating ANY task, read the issue template:
|
|
327
|
+
```
|
|
328
|
+
Read .claude/templates/issue.xml
|
|
329
|
+
Read .claude/rules/issue-structure.xml
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Every task file MUST include ALL required sections from `issue.xml`. Missing sections = auto-reject.
|
|
333
|
+
|
|
334
|
+
### 5. Task File Format with Frontmatter
|
|
325
335
|
For each task, create a file with this exact structure:
|
|
326
336
|
|
|
327
337
|
```markdown
|
|
328
338
|
---
|
|
329
339
|
name: [Task Title]
|
|
330
340
|
status: open
|
|
341
|
+
priority: [critical/high/medium/low]
|
|
342
|
+
effort: [S/M/L/XL]
|
|
331
343
|
created: [Current ISO date/time]
|
|
332
344
|
updated: [Current ISO date/time]
|
|
333
|
-
assigned_agent: .claude/agents/{category}/{agent-name}.md
|
|
334
|
-
agent_context:
|
|
345
|
+
assigned_agent: .claude/agents/{category}/{agent-name}.md
|
|
346
|
+
agent_context:
|
|
335
347
|
framework: [framework_name]
|
|
336
348
|
language: [language_name]
|
|
337
|
-
approach: [implementation_approach]
|
|
338
349
|
github: [Will be updated when synced to GitHub]
|
|
339
|
-
depends_on: []
|
|
340
|
-
parallel: true
|
|
341
|
-
conflicts_with: []
|
|
350
|
+
depends_on: []
|
|
351
|
+
parallel: true
|
|
352
|
+
conflicts_with: []
|
|
342
353
|
---
|
|
343
354
|
|
|
344
355
|
# Task: [Task Title]
|
|
345
356
|
|
|
346
|
-
##
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
## ⚠️ TDD Requirements
|
|
350
|
-
**This project uses Test-Driven Development. You MUST:**
|
|
351
|
-
1. 🔴 RED: Write failing test first
|
|
352
|
-
2. 🟢 GREEN: Write minimal code to make test pass
|
|
353
|
-
3. 🔵 REFACTOR: Clean up code while keeping tests green
|
|
357
|
+
## Goal
|
|
358
|
+
[One sentence: WHAT this task delivers and WHY it matters]
|
|
354
359
|
|
|
355
|
-
|
|
360
|
+
## Context
|
|
361
|
+
[WHY this task exists — what triggered it, what currently works/doesn't,
|
|
362
|
+
what must be in place first. Include specific file paths, URLs, services.]
|
|
356
363
|
|
|
357
364
|
## Acceptance Criteria
|
|
358
|
-
- [ ] Specific criterion 1
|
|
359
|
-
- [ ] Specific criterion 2
|
|
360
|
-
- [ ] Specific criterion 3
|
|
365
|
+
- [ ] Specific, measurable criterion 1
|
|
366
|
+
- [ ] Specific, measurable criterion 2
|
|
367
|
+
- [ ] Specific, measurable criterion 3
|
|
361
368
|
|
|
362
|
-
##
|
|
363
|
-
-
|
|
364
|
-
-
|
|
365
|
-
- Code locations/files affected
|
|
369
|
+
## Affected Files
|
|
370
|
+
- `path/to/file.ts` — [what changes]
|
|
371
|
+
- `path/to/test.ts` — [new test file]
|
|
366
372
|
|
|
367
|
-
##
|
|
368
|
-
-
|
|
369
|
-
-
|
|
373
|
+
## Related Issues
|
|
374
|
+
- depends on #NNN — [why]
|
|
375
|
+
- blocks #NNN — [why]
|
|
376
|
+
- (or "None" if standalone)
|
|
370
377
|
|
|
371
|
-
##
|
|
372
|
-
|
|
373
|
-
-
|
|
374
|
-
-
|
|
378
|
+
## Verification Steps
|
|
379
|
+
[Concrete commands to verify this task is done:]
|
|
380
|
+
- `npm test -- --filter=feature` → all pass
|
|
381
|
+
- `curl http://localhost:3000/api/endpoint` → 200
|
|
382
|
+
- `kubectl get pods -n app` → Running
|
|
375
383
|
|
|
376
384
|
## Definition of Done
|
|
377
385
|
- [ ] Tests written FIRST (RED phase)
|
|
378
386
|
- [ ] Code implemented (GREEN phase)
|
|
379
387
|
- [ ] Code refactored (REFACTOR phase)
|
|
380
388
|
- [ ] All tests passing
|
|
381
|
-
- [ ]
|
|
382
|
-
- [ ]
|
|
383
|
-
|
|
389
|
+
- [ ] Verification steps confirmed
|
|
390
|
+
- [ ] PR approved and merged
|
|
391
|
+
|
|
392
|
+
## ⚠️ TDD Requirements
|
|
393
|
+
1. 🔴 RED: Write failing test first
|
|
394
|
+
2. 🟢 GREEN: Write minimal code to make test pass
|
|
395
|
+
3. 🔵 REFACTOR: Clean up code while keeping tests green
|
|
396
|
+
|
|
397
|
+
## Technical Constraints
|
|
398
|
+
[Stack, patterns, prohibitions — optional but recommended]
|
|
399
|
+
|
|
400
|
+
## Out of Scope
|
|
401
|
+
[What NOT to touch — prevents AI from "improving" neighbors]
|
|
384
402
|
```
|
|
385
403
|
|
|
386
404
|
### 3. Task Naming Convention
|
|
@@ -356,18 +356,50 @@ Parse the arguments to detect the mode:
|
|
|
356
356
|
- [Internal systems or components]
|
|
357
357
|
- [Third-party libraries or tools]
|
|
358
358
|
|
|
359
|
-
##
|
|
360
|
-
###
|
|
361
|
-
|
|
359
|
+
## Architecture Design
|
|
360
|
+
### Component Tree
|
|
361
|
+
[Map out the key new files/modules/components that will be created:]
|
|
362
|
+
```
|
|
363
|
+
src/
|
|
364
|
+
├── feature/
|
|
365
|
+
│ ├── Component.tsx
|
|
366
|
+
│ ├── hooks/useFeature.ts
|
|
367
|
+
│ └── utils/helpers.ts
|
|
368
|
+
```
|
|
362
369
|
|
|
363
|
-
###
|
|
364
|
-
|
|
370
|
+
### Data Flow
|
|
371
|
+
[How data moves through the system for this feature:]
|
|
372
|
+
- User action → API endpoint → Service → Database → Response
|
|
365
373
|
|
|
366
|
-
###
|
|
367
|
-
|
|
374
|
+
### State Management
|
|
375
|
+
[New state needed — stores, context, caching strategy]
|
|
368
376
|
|
|
369
|
-
|
|
370
|
-
|
|
377
|
+
## Implementation Plan
|
|
378
|
+
### Phase 1: Analyze (before writing code)
|
|
379
|
+
- [ ] Read existing codebase patterns
|
|
380
|
+
- [ ] Identify integration points
|
|
381
|
+
- [ ] Confirm architecture with stakeholder
|
|
382
|
+
|
|
383
|
+
### Phase 2: Foundation
|
|
384
|
+
- [ ] Database migrations / models
|
|
385
|
+
- [ ] Core API endpoints (backend)
|
|
386
|
+
- [ ] Base component scaffolding (frontend)
|
|
387
|
+
|
|
388
|
+
### Phase 3: Core Features
|
|
389
|
+
- [ ] [Main feature implementation]
|
|
390
|
+
- [ ] [Integration with existing systems]
|
|
391
|
+
|
|
392
|
+
### Phase 4: Polish & Release
|
|
393
|
+
- [ ] [Testing — unit, integration, e2e]
|
|
394
|
+
- [ ] [Documentation]
|
|
395
|
+
- [ ] [Deployment]
|
|
396
|
+
|
|
397
|
+
### Quick Win Path
|
|
398
|
+
[Minimum viable subset that works end-to-end in 1-3 days:]
|
|
399
|
+
- Day 1: [smallest vertical slice]
|
|
400
|
+
- Day 2: [connect to real data]
|
|
401
|
+
- Day 3: [basic UI showing results]
|
|
402
|
+
[This path gives a working demo before full implementation]
|
|
371
403
|
|
|
372
404
|
## Risks and Mitigation
|
|
373
405
|
### Technical Risks
|
|
@@ -6,13 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
<template>
|
|
8
8
|
<section name="goal" required="true">One sentence: WHAT and WHY</section>
|
|
9
|
-
<section name="context" required="true">
|
|
9
|
+
<section name="context" required="true">
|
|
10
|
+
WHY this issue exists — problem background, current state, dependencies, environment.
|
|
11
|
+
Must answer: what triggered this, what works/doesn't, what must exist first.
|
|
12
|
+
</section>
|
|
10
13
|
<section name="acceptance-criteria" required="true">Measurable checkboxes, not prose</section>
|
|
11
|
-
<section name="technical-constraints" required="false">Stack, patterns, prohibitions</section>
|
|
12
14
|
<section name="affected-files" required="true">Exact file paths with change description</section>
|
|
15
|
+
<section name="related-issues" required="true">depends on / blocks / related to #NNN, or "None"</section>
|
|
16
|
+
<section name="verification" required="true">Concrete commands to verify (curl, kubectl, npm test, etc.)</section>
|
|
17
|
+
<section name="definition-of-done" required="true">Quality gate checkboxes — tests, deploy, PR merged</section>
|
|
18
|
+
<section name="constraints" required="false">Stack, patterns, prohibitions</section>
|
|
13
19
|
<section name="out-of-scope" required="false">What NOT to touch</section>
|
|
14
20
|
<section name="suggested-approach" required="false">Brief implementation strategy</section>
|
|
15
|
-
<section name="definition-of-done" required="false">Quality gates (tests, lint, coverage)</section>
|
|
16
21
|
</template>
|
|
17
22
|
|
|
18
23
|
<title-convention>
|
|
@@ -40,8 +45,12 @@
|
|
|
40
45
|
</key-principles>
|
|
41
46
|
|
|
42
47
|
<violations enforcement="auto-reject">
|
|
48
|
+
<violation>Creating issues without Context section (why it exists, current state)</violation>
|
|
43
49
|
<violation>Creating issues without Acceptance Criteria</violation>
|
|
44
50
|
<violation>Creating issues without Affected Files section</violation>
|
|
51
|
+
<violation>Creating issues without Verification Steps</violation>
|
|
52
|
+
<violation>Creating issues without Definition of Done</violation>
|
|
45
53
|
<violation>Vague goal without concrete deliverable</violation>
|
|
54
|
+
<violation>Missing Related Issues (must list links or "None")</violation>
|
|
46
55
|
</violations>
|
|
47
56
|
</rule>
|
|
@@ -400,7 +400,7 @@ function renderHTML() {
|
|
|
400
400
|
border: 1px solid #30363d; border-radius: 8px; overflow: hidden;
|
|
401
401
|
}
|
|
402
402
|
.diagram-split .code-pane {
|
|
403
|
-
|
|
403
|
+
width: 30%; display: flex; flex-direction: column; min-width: 150px; flex-shrink: 0;
|
|
404
404
|
}
|
|
405
405
|
.diagram-split .code-pane .pane-header {
|
|
406
406
|
background: #161b22; padding: 6px 12px; font-size: 11px; color: #8b949e;
|
|
@@ -411,8 +411,13 @@ function renderHTML() {
|
|
|
411
411
|
font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; font-size: 13px;
|
|
412
412
|
line-height: 1.5; resize: none; outline: none; tab-size: 2;
|
|
413
413
|
}
|
|
414
|
+
.diagram-split .split-handle {
|
|
415
|
+
width: 5px; cursor: col-resize; background: #30363d; flex-shrink: 0;
|
|
416
|
+
transition: background 0.15s;
|
|
417
|
+
}
|
|
418
|
+
.diagram-split .split-handle:hover, .diagram-split .split-handle.dragging { background: #58a6ff; }
|
|
414
419
|
.diagram-split .preview-pane {
|
|
415
|
-
flex: 1; display: flex; flex-direction: column; background: #161b22; min-width:
|
|
420
|
+
flex: 1; display: flex; flex-direction: column; background: #161b22; min-width: 200px;
|
|
416
421
|
}
|
|
417
422
|
.diagram-split .preview-pane .pane-header {
|
|
418
423
|
background: #161b22; padding: 6px 12px; font-size: 11px; color: #8b949e;
|
|
@@ -429,6 +434,23 @@ function renderHTML() {
|
|
|
429
434
|
.panzoom-hint {
|
|
430
435
|
position: absolute; bottom: 8px; right: 12px; color: #484f58; font-size: 10px; pointer-events: none; z-index: 1;
|
|
431
436
|
}
|
|
437
|
+
/* Diagram card actions */
|
|
438
|
+
.diagram-grid-item .card-actions {
|
|
439
|
+
display: flex; gap: 6px; margin-top: 8px; border-top: 1px solid #21262d; padding-top: 8px;
|
|
440
|
+
}
|
|
441
|
+
.diagram-grid-item .card-actions button {
|
|
442
|
+
background: #21262d; color: #8b949e; border: 1px solid #30363d;
|
|
443
|
+
padding: 3px 10px; border-radius: 4px; cursor: pointer; font-size: 11px;
|
|
444
|
+
}
|
|
445
|
+
.diagram-grid-item .card-actions button:hover { background: #30363d; color: #c9d1d9; }
|
|
446
|
+
.diagram-grid-item .card-actions .btn-remove { color: #f85149; }
|
|
447
|
+
.diagram-grid-item .card-actions .btn-remove:hover { background: #3d1116; border-color: #f85149; }
|
|
448
|
+
/* Fullscreen editor */
|
|
449
|
+
.diagram-editor.fullscreen {
|
|
450
|
+
position: fixed; inset: 0; z-index: 998; background: #0d1117;
|
|
451
|
+
padding: 12px; display: flex; flex-direction: column;
|
|
452
|
+
}
|
|
453
|
+
.diagram-editor.fullscreen .diagram-split { min-height: 0; flex: 1; }
|
|
432
454
|
</style>
|
|
433
455
|
</head>
|
|
434
456
|
<body>
|
|
@@ -562,7 +584,27 @@ function renderHTML() {
|
|
|
562
584
|
<!-- Diagram list view -->
|
|
563
585
|
<div id="diagram-list-view">
|
|
564
586
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
|
|
565
|
-
<p class="desc" style="margin:0;">
|
|
587
|
+
<p class="desc" style="margin:0;">Project diagrams stored in <code>.claude/pm/diagrams/</code></p>
|
|
588
|
+
<button class="btn" onclick="showNewDiagramForm()">+ New Diagram</button>
|
|
589
|
+
</div>
|
|
590
|
+
<!-- New diagram form (hidden by default) -->
|
|
591
|
+
<div id="new-diagram-form" class="card" style="display:none;margin-bottom:16px;">
|
|
592
|
+
<div class="row">
|
|
593
|
+
<div><label>Name (slug)</label><input type="text" id="new-diagram-name" placeholder="e.g. frontend, backend, database"></div>
|
|
594
|
+
<div><label>Type</label><select id="new-diagram-type">
|
|
595
|
+
<option value="architecture">architecture</option>
|
|
596
|
+
<option value="modules">modules</option>
|
|
597
|
+
<option value="data-flow">data-flow</option>
|
|
598
|
+
<option value="dependencies">dependencies</option>
|
|
599
|
+
<option value="custom">custom</option>
|
|
600
|
+
</select></div>
|
|
601
|
+
</div>
|
|
602
|
+
<label>Description</label>
|
|
603
|
+
<input type="text" id="new-diagram-desc" placeholder="e.g. Frontend React component tree">
|
|
604
|
+
<div style="margin-top:12px;">
|
|
605
|
+
<button class="btn" onclick="createNewDiagram()">Create</button>
|
|
606
|
+
<button class="btn" style="background:#21262d;margin-left:6px;" onclick="hideNewDiagramForm()">Cancel</button>
|
|
607
|
+
</div>
|
|
566
608
|
</div>
|
|
567
609
|
<div id="diagram-grid" class="diagram-grid"></div>
|
|
568
610
|
</div>
|
|
@@ -572,19 +614,20 @@ function renderHTML() {
|
|
|
572
614
|
<div class="left">
|
|
573
615
|
<button class="btn-back" onclick="closeDiagramEditor()">← Back</button>
|
|
574
616
|
<strong id="editor-diagram-name" style="color:#c9d1d9;font-size:14px;"></strong>
|
|
575
|
-
<span id="editor-diagram-meta" style="color:#8b949e;font-size:11px;"></span>
|
|
576
617
|
<span id="editor-unsaved" style="color:#d29922;font-size:11px;display:none;">● unsaved</span>
|
|
577
618
|
</div>
|
|
578
619
|
<div class="right">
|
|
579
620
|
<button onclick="downloadCurrentDiagram()">↓ .mmd</button>
|
|
621
|
+
<button onclick="toggleEditorFullscreen()">⤢ Fullscreen</button>
|
|
580
622
|
<button class="btn-save" onclick="saveDiagram()">Save</button>
|
|
581
623
|
</div>
|
|
582
624
|
</div>
|
|
583
|
-
<div class="diagram-split">
|
|
584
|
-
<div class="code-pane">
|
|
625
|
+
<div class="diagram-split" id="diagram-split">
|
|
626
|
+
<div class="code-pane" id="code-pane">
|
|
585
627
|
<div class="pane-header"><span>Mermaid Source</span></div>
|
|
586
628
|
<textarea id="diagram-code" spellcheck="false"></textarea>
|
|
587
629
|
</div>
|
|
630
|
+
<div class="split-handle" id="split-handle"></div>
|
|
588
631
|
<div class="preview-pane">
|
|
589
632
|
<div class="pane-header">
|
|
590
633
|
<span>Preview</span>
|
|
@@ -654,16 +697,10 @@ function renderDiagramsTab() {
|
|
|
654
697
|
fetch('/api/diagrams', { headers: { 'Authorization': 'Bearer ' + TOKEN } })
|
|
655
698
|
.then(r => r.json())
|
|
656
699
|
.then(data => {
|
|
657
|
-
// Merge system-generated + project diagrams into one list
|
|
658
700
|
allDiagrams = [];
|
|
659
|
-
if (data.epicFlowHasData) {
|
|
660
|
-
allDiagrams.push({ name: 'epic-flow', content: data.epicFlow, type: 'system', meta: 'PRD → Epic → Tasks' });
|
|
661
|
-
}
|
|
662
|
-
allDiagrams.push({ name: 'plugins', content: data.pluginGraph, type: 'system', meta: 'Plugin dependencies' });
|
|
663
|
-
allDiagrams.push({ name: 'agents', content: data.agentTree, type: 'system', meta: 'Agent selection tree' });
|
|
664
701
|
if (data.projectDiagrams) {
|
|
665
702
|
data.projectDiagrams.forEach(d => {
|
|
666
|
-
allDiagrams.push({ name: d.name, content: d.content, type:
|
|
703
|
+
allDiagrams.push({ name: d.name, content: d.content, type: d.type || 'custom' });
|
|
667
704
|
});
|
|
668
705
|
}
|
|
669
706
|
renderDiagramGrid();
|
|
@@ -675,49 +712,112 @@ function renderDiagramGrid() {
|
|
|
675
712
|
const grid = document.getElementById('diagram-grid');
|
|
676
713
|
grid.textContent = '';
|
|
677
714
|
if (allDiagrams.length === 0) {
|
|
678
|
-
|
|
715
|
+
const msg = document.createElement('p');
|
|
716
|
+
msg.className = 'desc';
|
|
717
|
+
msg.textContent = 'No diagrams yet. Click "+ New Diagram" or run /pm:diagram-new <name>.';
|
|
718
|
+
grid.appendChild(msg);
|
|
679
719
|
return;
|
|
680
720
|
}
|
|
681
721
|
allDiagrams.forEach(d => {
|
|
682
722
|
const item = document.createElement('div');
|
|
683
723
|
item.className = 'diagram-grid-item';
|
|
684
|
-
item.setAttribute('role', 'button');
|
|
685
724
|
item.setAttribute('tabindex', '0');
|
|
686
|
-
item.onclick = function() { openDiagramEditor(d.name); };
|
|
687
|
-
item.onkeydown = function(e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openDiagramEditor(d.name); } };
|
|
688
725
|
const h4 = document.createElement('h4');
|
|
689
726
|
h4.textContent = d.name;
|
|
690
727
|
const meta = document.createElement('div');
|
|
691
728
|
meta.className = 'diagram-meta';
|
|
692
|
-
meta.textContent = d.type
|
|
729
|
+
meta.textContent = d.type;
|
|
693
730
|
const preview = document.createElement('div');
|
|
694
731
|
preview.className = 'diagram-preview';
|
|
695
732
|
const pre = document.createElement('pre');
|
|
696
733
|
pre.className = 'mermaid';
|
|
697
734
|
pre.textContent = d.content;
|
|
698
735
|
preview.appendChild(pre);
|
|
736
|
+
// Action buttons
|
|
737
|
+
const actions = document.createElement('div');
|
|
738
|
+
actions.className = 'card-actions';
|
|
739
|
+
const editBtn = document.createElement('button');
|
|
740
|
+
editBtn.textContent = 'Edit';
|
|
741
|
+
editBtn.onclick = function(e) { e.stopPropagation(); openDiagramEditor(d.name); };
|
|
742
|
+
const dlBtn = document.createElement('button');
|
|
743
|
+
dlBtn.textContent = '↓ .mmd';
|
|
744
|
+
dlBtn.onclick = function(e) { e.stopPropagation(); downloadDiagram(d.name, d.content); };
|
|
745
|
+
const rmBtn = document.createElement('button');
|
|
746
|
+
rmBtn.textContent = 'Remove';
|
|
747
|
+
rmBtn.className = 'btn-remove';
|
|
748
|
+
rmBtn.onclick = function(e) { e.stopPropagation(); removeDiagram(d.name); };
|
|
749
|
+
actions.appendChild(editBtn);
|
|
750
|
+
actions.appendChild(dlBtn);
|
|
751
|
+
actions.appendChild(rmBtn);
|
|
699
752
|
item.appendChild(h4);
|
|
700
753
|
item.appendChild(meta);
|
|
701
754
|
item.appendChild(preview);
|
|
755
|
+
item.appendChild(actions);
|
|
756
|
+
// Click card body (not actions) opens editor
|
|
757
|
+
item.onclick = function(e) { if (!e.target.closest('.card-actions')) openDiagramEditor(d.name); };
|
|
758
|
+
item.onkeydown = function(e) {
|
|
759
|
+
if (e.target && e.target.closest('.card-actions')) return;
|
|
760
|
+
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openDiagramEditor(d.name); }
|
|
761
|
+
};
|
|
702
762
|
grid.appendChild(item);
|
|
703
763
|
});
|
|
704
|
-
// Render mini previews
|
|
705
764
|
if (typeof mermaid !== 'undefined' && mermaid.run) {
|
|
706
765
|
mermaid.run({ nodes: grid.querySelectorAll('.mermaid') });
|
|
707
766
|
}
|
|
708
767
|
}
|
|
709
768
|
|
|
769
|
+
// New diagram form
|
|
770
|
+
function showNewDiagramForm() { document.getElementById('new-diagram-form').style.display = ''; }
|
|
771
|
+
function hideNewDiagramForm() { document.getElementById('new-diagram-form').style.display = 'none'; }
|
|
772
|
+
|
|
773
|
+
async function createNewDiagram() {
|
|
774
|
+
const name = document.getElementById('new-diagram-name').value.trim().replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
775
|
+
if (!name) { toast('Name is required', false); return; }
|
|
776
|
+
if (allDiagrams.find(d => d.name === name)) { toast('Diagram "' + name + '" already exists', false); return; }
|
|
777
|
+
const type = document.getElementById('new-diagram-type').value;
|
|
778
|
+
const desc = document.getElementById('new-diagram-desc').value.trim();
|
|
779
|
+
const template = 'graph TD\\n A[' + esc(desc || name) + ']';
|
|
780
|
+
try {
|
|
781
|
+
await api('POST', '/api/diagrams/' + encodeURIComponent(name), { content: template, type: type, description: desc });
|
|
782
|
+
hideNewDiagramForm();
|
|
783
|
+
document.getElementById('new-diagram-name').value = '';
|
|
784
|
+
document.getElementById('new-diagram-desc').value = '';
|
|
785
|
+
diagramsLoaded = false;
|
|
786
|
+
renderDiagramsTab();
|
|
787
|
+
toast('Diagram "' + name + '" created', true);
|
|
788
|
+
} catch (e) { /* api() already shows toast */ }
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
async function removeDiagram(name) {
|
|
792
|
+
if (!confirm('Remove diagram "' + name + '"?')) return;
|
|
793
|
+
try {
|
|
794
|
+
await api('DELETE', '/api/diagrams/' + encodeURIComponent(name));
|
|
795
|
+
allDiagrams = allDiagrams.filter(d => d.name !== name);
|
|
796
|
+
renderDiagramGrid();
|
|
797
|
+
toast('Diagram removed', true);
|
|
798
|
+
} catch (e) { /* api() already shows toast */ }
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function downloadDiagram(name, content) {
|
|
802
|
+
const safeName = name.replace(/[^a-zA-Z0-9_-]/g, '_') + '.mmd';
|
|
803
|
+
const blob = new Blob([content], { type: 'text/plain' });
|
|
804
|
+
const a = document.createElement('a');
|
|
805
|
+
const url = URL.createObjectURL(blob);
|
|
806
|
+
a.href = url; a.download = safeName; a.style.display = 'none';
|
|
807
|
+
document.body.appendChild(a);
|
|
808
|
+
try { a.click(); } finally { document.body.removeChild(a); setTimeout(function() { URL.revokeObjectURL(url); }, 100); }
|
|
809
|
+
}
|
|
810
|
+
|
|
710
811
|
function openDiagramEditor(name) {
|
|
711
812
|
const d = allDiagrams.find(x => x.name === name);
|
|
712
813
|
if (!d) return;
|
|
713
814
|
currentDiagramName = name;
|
|
714
815
|
currentDiagramSaved = d.content;
|
|
715
816
|
document.getElementById('editor-diagram-name').textContent = name;
|
|
716
|
-
document.getElementById('editor-diagram-meta').textContent = d.type === 'system' ? '(system — read-only)' : '';
|
|
717
817
|
document.getElementById('editor-unsaved').style.display = 'none';
|
|
718
818
|
const codeEl = document.getElementById('diagram-code');
|
|
719
819
|
codeEl.value = d.content;
|
|
720
|
-
codeEl.readOnly =
|
|
820
|
+
codeEl.readOnly = false;
|
|
721
821
|
document.getElementById('diagram-list-view').style.display = 'none';
|
|
722
822
|
document.getElementById('diagram-editor-view').classList.add('active');
|
|
723
823
|
renderPreview(d.content);
|
|
@@ -726,11 +826,19 @@ function openDiagramEditor(name) {
|
|
|
726
826
|
function closeDiagramEditor() {
|
|
727
827
|
clearTimeout(previewDebounce); previewDebounce = null;
|
|
728
828
|
if (panzoomInstance) { panzoomInstance.dispose(); panzoomInstance = null; }
|
|
729
|
-
document.getElementById('diagram-editor-view')
|
|
829
|
+
const editor = document.getElementById('diagram-editor-view');
|
|
830
|
+
editor.classList.remove('active', 'fullscreen');
|
|
730
831
|
document.getElementById('diagram-list-view').style.display = '';
|
|
731
832
|
currentDiagramName = null;
|
|
732
833
|
}
|
|
733
834
|
|
|
835
|
+
function toggleEditorFullscreen() {
|
|
836
|
+
document.getElementById('diagram-editor-view').classList.toggle('fullscreen');
|
|
837
|
+
// Re-render preview to fit new size
|
|
838
|
+
if (panzoomInstance) { panzoomInstance.dispose(); panzoomInstance = null; }
|
|
839
|
+
setTimeout(function() { renderPreview(document.getElementById('diagram-code').value); }, 100);
|
|
840
|
+
}
|
|
841
|
+
|
|
734
842
|
function renderPreview(source) {
|
|
735
843
|
const container = document.getElementById('diagram-preview-render');
|
|
736
844
|
container.textContent = '';
|
|
@@ -761,6 +869,35 @@ function resetPanZoom() {
|
|
|
761
869
|
}
|
|
762
870
|
}
|
|
763
871
|
|
|
872
|
+
// Resizable split handle
|
|
873
|
+
(function() {
|
|
874
|
+
const handle = document.getElementById('split-handle');
|
|
875
|
+
const codePane = document.getElementById('code-pane');
|
|
876
|
+
const split = document.getElementById('diagram-split');
|
|
877
|
+
if (!handle || !codePane || !split) return;
|
|
878
|
+
let dragging = false;
|
|
879
|
+
handle.addEventListener('mousedown', function(e) {
|
|
880
|
+
e.preventDefault();
|
|
881
|
+
dragging = true;
|
|
882
|
+
handle.classList.add('dragging');
|
|
883
|
+
document.body.style.cursor = 'col-resize';
|
|
884
|
+
document.body.style.userSelect = 'none';
|
|
885
|
+
});
|
|
886
|
+
document.addEventListener('mousemove', function(e) {
|
|
887
|
+
if (!dragging) return;
|
|
888
|
+
const rect = split.getBoundingClientRect();
|
|
889
|
+
const pct = Math.min(70, Math.max(10, ((e.clientX - rect.left) / rect.width) * 100));
|
|
890
|
+
codePane.style.width = pct + '%';
|
|
891
|
+
});
|
|
892
|
+
document.addEventListener('mouseup', function() {
|
|
893
|
+
if (!dragging) return;
|
|
894
|
+
dragging = false;
|
|
895
|
+
handle.classList.remove('dragging');
|
|
896
|
+
document.body.style.cursor = '';
|
|
897
|
+
document.body.style.userSelect = '';
|
|
898
|
+
});
|
|
899
|
+
})();
|
|
900
|
+
|
|
764
901
|
// Live preview on code change
|
|
765
902
|
document.addEventListener('DOMContentLoaded', function() {
|
|
766
903
|
const codeEl = document.getElementById('diagram-code');
|
|
@@ -776,7 +913,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
776
913
|
async function saveDiagram() {
|
|
777
914
|
if (!currentDiagramName) return;
|
|
778
915
|
const d = allDiagrams.find(x => x.name === currentDiagramName);
|
|
779
|
-
if (d && d.type === 'system') { toast('System diagrams are read-only', false); return; }
|
|
780
916
|
const content = document.getElementById('diagram-code').value;
|
|
781
917
|
try {
|
|
782
918
|
await api('POST', '/api/diagrams/' + encodeURIComponent(currentDiagramName), { content: content });
|
|
@@ -787,7 +923,7 @@ async function saveDiagram() {
|
|
|
787
923
|
diagramsLoaded = false;
|
|
788
924
|
toast('Diagram saved', true);
|
|
789
925
|
} catch (e) {
|
|
790
|
-
|
|
926
|
+
/* api() already shows toast */
|
|
791
927
|
}
|
|
792
928
|
}
|
|
793
929
|
|
|
@@ -1273,6 +1409,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
1273
1409
|
let meta = {};
|
|
1274
1410
|
try { meta = JSON.parse(fs.readFileSync(metaPath, 'utf8')); } catch {}
|
|
1275
1411
|
meta.name = meta.name || name;
|
|
1412
|
+
if (typeof body.type === 'string') meta.type = body.type.slice(0, 50);
|
|
1413
|
+
if (typeof body.description === 'string') meta.description = body.description.slice(0, 500);
|
|
1276
1414
|
meta.updated = new Date().toISOString().replace(/\\.\\d{3}Z$/, 'Z');
|
|
1277
1415
|
if (!meta.created) meta.created = meta.updated;
|
|
1278
1416
|
fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2), 'utf8');
|
|
@@ -7,14 +7,42 @@
|
|
|
7
7
|
<field name="assignee" type="string" default=""/>
|
|
8
8
|
<field name="created" type="datetime" auto="true"/>
|
|
9
9
|
<field name="updated" type="datetime" auto="true"/>
|
|
10
|
+
<field name="priority" type="enum" values="critical,high,medium,low" default="medium"/>
|
|
11
|
+
<field name="effort" type="enum" values="S,M,L,XL" default="M"/>
|
|
10
12
|
<field name="started" type="datetime"/>
|
|
11
13
|
<field name="completed" type="datetime"/>
|
|
12
14
|
</frontmatter>
|
|
13
15
|
|
|
14
16
|
<sections>
|
|
15
17
|
<section name="goal" heading="Goal" required="true">One sentence: WHAT and WHY</section>
|
|
18
|
+
<section name="context" heading="Context" required="true">
|
|
19
|
+
Why this issue exists. Include:
|
|
20
|
+
- Problem background — what triggered this (bug report, user request, architectural gap)
|
|
21
|
+
- Current state — what works now, what doesn't, relevant infrastructure/config
|
|
22
|
+
- Dependencies — what must exist first (images, services, DNS, other issues)
|
|
23
|
+
- Access/environment — how to reproduce, where to verify (cluster, URL, CI)
|
|
24
|
+
</section>
|
|
16
25
|
<section name="acceptance-criteria" heading="Acceptance Criteria" required="true">Measurable checkboxes</section>
|
|
17
26
|
<section name="affected-files" heading="Affected Files" required="true">Exact file paths with change description</section>
|
|
27
|
+
<section name="related-issues" heading="Related Issues" required="true">
|
|
28
|
+
Links to blocking/blocked/related issues:
|
|
29
|
+
- depends on #NNN — must be done first
|
|
30
|
+
- blocks #NNN — this unblocks other work
|
|
31
|
+
- related to #NNN — shares context
|
|
32
|
+
- Write "None" if truly standalone
|
|
33
|
+
</section>
|
|
34
|
+
<section name="verification" heading="Verification Steps" required="true">
|
|
35
|
+
Concrete commands to verify the work is done. Examples:
|
|
36
|
+
- curl https://app.example.com → 200
|
|
37
|
+
- kubectl get pods -n app → Running
|
|
38
|
+
- npm test -- --filter=feature → pass
|
|
39
|
+
</section>
|
|
40
|
+
<section name="definition-of-done" heading="Definition of Done" required="true">
|
|
41
|
+
Checklist of quality gates that MUST pass before closing:
|
|
42
|
+
- [ ] Tests pass (unit, integration)
|
|
43
|
+
- [ ] Deployed to staging/verified
|
|
44
|
+
- [ ] PR approved and merged
|
|
45
|
+
</section>
|
|
18
46
|
<section name="constraints" heading="Technical Constraints" required="false">Stack, patterns, prohibitions</section>
|
|
19
47
|
<section name="out-of-scope" heading="Out of Scope" required="false">What NOT to touch</section>
|
|
20
48
|
<section name="approach" heading="Suggested Approach" required="false">Brief implementation strategy</section>
|
|
@@ -22,6 +50,11 @@
|
|
|
22
50
|
|
|
23
51
|
<validation>
|
|
24
52
|
<rule>goal must be non-empty</rule>
|
|
53
|
+
<rule>context must be non-empty</rule>
|
|
54
|
+
<rule>acceptance-criteria must be non-empty</rule>
|
|
55
|
+
<rule>related-issues must be non-empty</rule>
|
|
56
|
+
<rule>verification must be non-empty</rule>
|
|
57
|
+
<rule>definition-of-done must be non-empty</rule>
|
|
25
58
|
<rule>at least 1 acceptance criterion checkbox (- [ ])</rule>
|
|
26
59
|
</validation>
|
|
27
60
|
</template>
|
package/package.json
CHANGED
|
@@ -844,6 +844,15 @@
|
|
|
844
844
|
"description": "Provider-agnostic PM workflows"
|
|
845
845
|
}
|
|
846
846
|
},
|
|
847
|
+
"rules": [
|
|
848
|
+
{
|
|
849
|
+
"name": "issue-structure",
|
|
850
|
+
"file": "rules/issue-structure.xml",
|
|
851
|
+
"description": "Enforces standard issue structure with required sections",
|
|
852
|
+
"priority": "high",
|
|
853
|
+
"appliesTo": ["issue-create", "epic-decompose"]
|
|
854
|
+
}
|
|
855
|
+
],
|
|
847
856
|
"dependencies": [],
|
|
848
857
|
"peerPlugins": [
|
|
849
858
|
"@claudeautopm/plugin-core"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<rule id="issue-structure" priority="high" enforcement="required">
|
|
2
|
+
<description>
|
|
3
|
+
Every GitHub issue created by ClaudeAutoPM MUST follow the standard structure.
|
|
4
|
+
Issues without proper structure waste AI tokens and lead to scope creep.
|
|
5
|
+
</description>
|
|
6
|
+
|
|
7
|
+
<template>
|
|
8
|
+
<section name="goal" required="true">One sentence: WHAT and WHY</section>
|
|
9
|
+
<section name="context" required="true">
|
|
10
|
+
WHY this issue exists — problem background, current state, dependencies, environment.
|
|
11
|
+
Must answer: what triggered this, what works/doesn't, what must exist first.
|
|
12
|
+
</section>
|
|
13
|
+
<section name="acceptance-criteria" required="true">Measurable checkboxes, not prose</section>
|
|
14
|
+
<section name="affected-files" required="true">Exact file paths with change description</section>
|
|
15
|
+
<section name="related-issues" required="true">depends on / blocks / related to #NNN, or "None"</section>
|
|
16
|
+
<section name="verification" required="true">Concrete commands to verify (curl, kubectl, npm test, etc.)</section>
|
|
17
|
+
<section name="definition-of-done" required="true">Quality gate checkboxes — tests, deploy, PR merged</section>
|
|
18
|
+
<section name="constraints" required="false">Stack, patterns, prohibitions</section>
|
|
19
|
+
<section name="out-of-scope" required="false">What NOT to touch</section>
|
|
20
|
+
<section name="suggested-approach" required="false">Brief implementation strategy</section>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<title-convention>
|
|
24
|
+
<format>[type][scope] Imperative description</format>
|
|
25
|
+
<types>feat, fix, refactor, chore, test, docs, ci</types>
|
|
26
|
+
<examples>
|
|
27
|
+
<example>[feat][agent] Add retry logic to ResearcherAgent</example>
|
|
28
|
+
<example>[fix][api] Handle timeout in /ingest endpoint</example>
|
|
29
|
+
<example>[refactor][db] Extract VectorStore interface</example>
|
|
30
|
+
<example>[test][plugin] Add PluginManager install scenario tests</example>
|
|
31
|
+
</examples>
|
|
32
|
+
</title-convention>
|
|
33
|
+
|
|
34
|
+
<labels>
|
|
35
|
+
<label-group name="type">feature, bug, refactor, chore</label-group>
|
|
36
|
+
<label-group name="effort">S, M, L, XL</label-group>
|
|
37
|
+
<label-group name="ai-ready">true — issue is well-structured for AI execution</label-group>
|
|
38
|
+
</labels>
|
|
39
|
+
|
|
40
|
+
<key-principles>
|
|
41
|
+
<principle>Acceptance Criteria over narrative — AI understands checkboxes better than prose</principle>
|
|
42
|
+
<principle>Explicit scope always — say what NOT to touch or AI will "improve" neighbors</principle>
|
|
43
|
+
<principle>Name files, classes, functions — AI should not guess project structure</principle>
|
|
44
|
+
<principle>Link related issues — dependencies and blockers must be visible</principle>
|
|
45
|
+
</key-principles>
|
|
46
|
+
|
|
47
|
+
<violations enforcement="auto-reject">
|
|
48
|
+
<violation>Creating issues without Context section (why it exists, current state)</violation>
|
|
49
|
+
<violation>Creating issues without Acceptance Criteria</violation>
|
|
50
|
+
<violation>Creating issues without Affected Files section</violation>
|
|
51
|
+
<violation>Creating issues without Verification Steps</violation>
|
|
52
|
+
<violation>Creating issues without Definition of Done</violation>
|
|
53
|
+
<violation>Vague goal without concrete deliverable</violation>
|
|
54
|
+
<violation>Missing Related Issues (must list links or "None")</violation>
|
|
55
|
+
</violations>
|
|
56
|
+
</rule>
|