@winspan/claude-forge 8.2.0 → 8.11.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.
Files changed (73) hide show
  1. package/README.md +64 -5
  2. package/dist/claudemd/convention-extractor.js +3 -3
  3. package/dist/claudemd/convention-extractor.js.map +1 -1
  4. package/dist/cli/commands/init.d.ts.map +1 -1
  5. package/dist/cli/commands/init.js +1 -0
  6. package/dist/cli/commands/init.js.map +1 -1
  7. package/dist/cli/commands/rules.d.ts +8 -0
  8. package/dist/cli/commands/rules.d.ts.map +1 -0
  9. package/dist/cli/commands/rules.js +89 -0
  10. package/dist/cli/commands/rules.js.map +1 -0
  11. package/dist/cli/commands/stats.d.ts +8 -0
  12. package/dist/cli/commands/stats.d.ts.map +1 -0
  13. package/dist/cli/commands/stats.js +79 -0
  14. package/dist/cli/commands/stats.js.map +1 -0
  15. package/dist/cli/commands/template.d.ts +8 -0
  16. package/dist/cli/commands/template.d.ts.map +1 -0
  17. package/dist/cli/commands/template.js +68 -0
  18. package/dist/cli/commands/template.js.map +1 -0
  19. package/dist/cli/index.js +6 -0
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/core/storage/sqlite.d.ts +25 -0
  22. package/dist/core/storage/sqlite.d.ts.map +1 -1
  23. package/dist/core/storage/sqlite.js +26 -0
  24. package/dist/core/storage/sqlite.js.map +1 -1
  25. package/dist/core/types.d.ts +3 -0
  26. package/dist/core/types.d.ts.map +1 -1
  27. package/dist/daemon/handlers/pre-tool-use.d.ts +6 -1
  28. package/dist/daemon/handlers/pre-tool-use.d.ts.map +1 -1
  29. package/dist/daemon/handlers/pre-tool-use.js +45 -46
  30. package/dist/daemon/handlers/pre-tool-use.js.map +1 -1
  31. package/dist/daemon/handlers/user-prompt.d.ts.map +1 -1
  32. package/dist/daemon/handlers/user-prompt.js +8 -3
  33. package/dist/daemon/handlers/user-prompt.js.map +1 -1
  34. package/dist/daemon/index.d.ts.map +1 -1
  35. package/dist/daemon/index.js +34 -2
  36. package/dist/daemon/index.js.map +1 -1
  37. package/dist/engine/conventions/basic-security.yaml +15 -0
  38. package/dist/engine/conventions/database-safety.yaml +74 -0
  39. package/dist/engine/conventions/docker-safety.yaml +69 -0
  40. package/dist/engine/conventions/git-safety.yaml +12 -0
  41. package/dist/engine/conventions/go-best-practices.yaml +84 -0
  42. package/dist/engine/conventions/python-best-practices.yaml +96 -0
  43. package/dist/engine/conventions/react-best-practices.yaml +96 -0
  44. package/dist/engine/dsl/parser.d.ts.map +1 -1
  45. package/dist/engine/dsl/parser.js +7 -1
  46. package/dist/engine/dsl/parser.js.map +1 -1
  47. package/dist/engine/dsl/types.d.ts +26 -1
  48. package/dist/engine/dsl/types.d.ts.map +1 -1
  49. package/dist/engine/rule-engine.d.ts +2 -1
  50. package/dist/engine/rule-engine.d.ts.map +1 -1
  51. package/dist/engine/rule-engine.js +56 -20
  52. package/dist/engine/rule-engine.js.map +1 -1
  53. package/dist/skills/matcher.d.ts +17 -1
  54. package/dist/skills/matcher.d.ts.map +1 -1
  55. package/dist/skills/matcher.js +92 -2
  56. package/dist/skills/matcher.js.map +1 -1
  57. package/dist/skills/registry.d.ts +26 -5
  58. package/dist/skills/registry.d.ts.map +1 -1
  59. package/dist/skills/registry.js +100 -10
  60. package/dist/skills/registry.js.map +1 -1
  61. package/dist/skills/semantic-matcher.d.ts +58 -0
  62. package/dist/skills/semantic-matcher.d.ts.map +1 -0
  63. package/dist/skills/semantic-matcher.js +189 -0
  64. package/dist/skills/semantic-matcher.js.map +1 -0
  65. package/dist/templates/template-manager.d.ts +52 -0
  66. package/dist/templates/template-manager.d.ts.map +1 -0
  67. package/dist/templates/template-manager.js +129 -0
  68. package/dist/templates/template-manager.js.map +1 -0
  69. package/dist/web/server.d.ts.map +1 -1
  70. package/dist/web/server.js +129 -2
  71. package/dist/web/server.js.map +1 -1
  72. package/dist/web/static/index.html +337 -0
  73. package/package.json +1 -1
@@ -4,6 +4,7 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Claude Forge Dashboard</title>
7
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
7
8
  <style>
8
9
  * { margin: 0; padding: 0; box-sizing: border-box; }
9
10
  :root {
@@ -65,12 +66,20 @@
65
66
  .dot-red { background: var(--red); box-shadow: 0 0 6px var(--red); }
66
67
  @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
67
68
  .fade-in { animation: fadeIn 0.3s ease-out; }
69
+ .chart-container { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.5rem; }
70
+ .chart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem; margin-bottom: 1.5rem; }
71
+ .search-box { width: 100%; padding: 0.625rem 1rem; background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); font-size: 0.875rem; margin-bottom: 1rem; transition: all 0.2s; }
72
+ .search-box:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
73
+ .rule-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.25rem; margin-bottom: 0.75rem; cursor: pointer; transition: all 0.2s; }
74
+ .rule-card:hover { border-color: var(--accent); box-shadow: 0 0 20px var(--accent-glow); transform: translateY(-1px); }
75
+ .tag { display: inline-block; padding: 2px 8px; border-radius: 4px; font-size: 0.7rem; background: var(--bg-secondary); color: var(--text-muted); margin-right: 0.25rem; }
68
76
  </style>
69
77
  </head>
70
78
  <body>
71
79
  <nav class="nav">
72
80
  <span class="logo">Claude Forge</span>
73
81
  <a onclick="showPage('dashboard')" class="active" id="nav-dashboard">Dashboard</a>
82
+ <a onclick="showPage('stats')" id="nav-stats">Stats</a>
74
83
  <a onclick="showPage('events')" id="nav-events">Events</a>
75
84
  <a onclick="showPage('injections')" id="nav-injections">Injections</a>
76
85
  <a onclick="showPage('live')" id="nav-live">Live</a>
@@ -106,9 +115,29 @@
106
115
  <div id="task-detail"></div>
107
116
  </div>
108
117
 
118
+ <!-- Stats -->
119
+ <div id="page-stats" class="page">
120
+ <h1>Statistics</h1>
121
+ <div class="chart-grid">
122
+ <div class="chart-container">
123
+ <h3 style="margin-bottom:1rem">Tool Usage Distribution</h3>
124
+ <canvas id="chart-tool-usage"></canvas>
125
+ </div>
126
+ <div class="chart-container">
127
+ <h3 style="margin-bottom:1rem">Decision Levels</h3>
128
+ <canvas id="chart-decision-levels"></canvas>
129
+ </div>
130
+ </div>
131
+ <div class="chart-container">
132
+ <h3 style="margin-bottom:1rem">7-Day Activity Trend</h3>
133
+ <canvas id="chart-daily-activity"></canvas>
134
+ </div>
135
+ </div>
136
+
109
137
  <!-- Events -->
110
138
  <div id="page-events" class="page">
111
139
  <h1>Events</h1>
140
+ <input type="text" class="search-box" id="events-search" placeholder="Search events by type, tool, or project..." onkeyup="filterEvents()">
112
141
  <button class="refresh" onclick="loadEvents()">Refresh</button>
113
142
  <table id="events-table">
114
143
  <thead><tr><th>Time</th><th>Type</th><th>Tool</th><th>Project</th></tr></thead>
@@ -119,12 +148,23 @@
119
148
  <!-- Rules -->
120
149
  <div id="page-rules" class="page">
121
150
  <h1>Rules</h1>
151
+ <input type="text" class="search-box" id="rules-search" placeholder="Search rules by name, category, or tags..." onkeyup="filterRules()">
122
152
  <div id="rules-list"></div>
123
153
  </div>
124
154
 
155
+ <!-- Rule Detail -->
156
+ <div id="page-rule-detail" class="page">
157
+ <div style="display:flex;align-items:center;gap:0.75rem;margin-bottom:1.5rem">
158
+ <button class="btn" onclick="showPage('rules')">← Back to Rules</button>
159
+ <h1 style="margin-bottom:0" id="rule-detail-title">Rule Detail</h1>
160
+ </div>
161
+ <div id="rule-detail"></div>
162
+ </div>
163
+
125
164
  <!-- Injections -->
126
165
  <div id="page-injections" class="page">
127
166
  <h1>Injections</h1>
167
+ <input type="text" class="search-box" id="injections-search" placeholder="Search injections by type or content..." onkeyup="filterInjections()">
128
168
  <div style="margin-bottom:1rem;display:flex;gap:0.5rem;align-items:center">
129
169
  <select id="inj-session" class="refresh" onchange="loadInjections()"><option value="">All Sessions</option></select>
130
170
  <select id="inj-handler" class="refresh" onchange="loadInjections()">
@@ -165,6 +205,7 @@ function showPage(name) {
165
205
  if (page) page.classList.add('active');
166
206
  if (nav) nav.classList.add('active');
167
207
  if (name === 'dashboard') { loadStatus(); loadSessions(); }
208
+ if (name === 'stats') loadStats();
168
209
  if (name === 'events') loadEvents();
169
210
  if (name === 'injections') loadInjections();
170
211
  if (name === 'rules') loadRules();
@@ -656,6 +697,302 @@ function clearLive() { document.getElementById('live-events').innerHTML = ''; }
656
697
  loadStatus();
657
698
  loadSessions();
658
699
 
700
+ // ========== Stats Page with Chart.js ==========
701
+ let statsCharts = {};
702
+
703
+ async function loadStats() {
704
+ try {
705
+ const res = await fetch(API + '/api/stats');
706
+ const stats = await res.json();
707
+
708
+ // Tool Usage Chart (Doughnut)
709
+ const toolCtx = document.getElementById('chart-tool-usage');
710
+ if (statsCharts.toolUsage) statsCharts.toolUsage.destroy();
711
+ statsCharts.toolUsage = new Chart(toolCtx, {
712
+ type: 'doughnut',
713
+ data: {
714
+ labels: Object.keys(stats.toolUsage),
715
+ datasets: [{
716
+ data: Object.values(stats.toolUsage),
717
+ backgroundColor: ['#818cf8', '#34d399', '#fbbf24', '#f87171', '#60a5fa', '#a78bfa']
718
+ }]
719
+ },
720
+ options: {
721
+ responsive: true,
722
+ plugins: {
723
+ legend: { labels: { color: '#e2e8f0' } }
724
+ }
725
+ }
726
+ });
727
+
728
+ // Decision Levels Chart (Bar)
729
+ const decisionCtx = document.getElementById('chart-decision-levels');
730
+ if (statsCharts.decisionLevels) statsCharts.decisionLevels.destroy();
731
+ statsCharts.decisionLevels = new Chart(decisionCtx, {
732
+ type: 'bar',
733
+ data: {
734
+ labels: Object.keys(stats.decisionLevels),
735
+ datasets: [{
736
+ label: 'Count',
737
+ data: Object.values(stats.decisionLevels),
738
+ backgroundColor: '#818cf8'
739
+ }]
740
+ },
741
+ options: {
742
+ responsive: true,
743
+ plugins: {
744
+ legend: { labels: { color: '#e2e8f0' } }
745
+ },
746
+ scales: {
747
+ y: { ticks: { color: '#94a3b8' }, grid: { color: '#1e293b' } },
748
+ x: { ticks: { color: '#94a3b8' }, grid: { color: '#1e293b' } }
749
+ }
750
+ }
751
+ });
752
+
753
+ // Daily Activity Chart (Line)
754
+ const activityCtx = document.getElementById('chart-daily-activity');
755
+ if (statsCharts.dailyActivity) statsCharts.dailyActivity.destroy();
756
+ statsCharts.dailyActivity = new Chart(activityCtx, {
757
+ type: 'line',
758
+ data: {
759
+ labels: stats.dailyActivity.map(d => d.date),
760
+ datasets: [{
761
+ label: 'Events',
762
+ data: stats.dailyActivity.map(d => d.count),
763
+ borderColor: '#818cf8',
764
+ backgroundColor: 'rgba(129,140,248,0.1)',
765
+ tension: 0.3
766
+ }]
767
+ },
768
+ options: {
769
+ responsive: true,
770
+ plugins: {
771
+ legend: { labels: { color: '#e2e8f0' } }
772
+ },
773
+ scales: {
774
+ y: { ticks: { color: '#94a3b8' }, grid: { color: '#1e293b' } },
775
+ x: { ticks: { color: '#94a3b8' }, grid: { color: '#1e293b' } }
776
+ }
777
+ }
778
+ });
779
+ } catch (err) {
780
+ console.error('Failed to load stats:', err);
781
+ }
782
+ }
783
+
784
+ // ========== Search and Filter Functions ==========
785
+ let allEvents = [];
786
+ let allRules = [];
787
+ let allInjections = [];
788
+
789
+ async function loadEvents() {
790
+ try {
791
+ const res = await fetch(API + '/api/events?limit=50');
792
+ allEvents = await res.json();
793
+ renderEvents(allEvents);
794
+ } catch {
795
+ document.getElementById('events-body').innerHTML = '<tr><td colspan="4" class="empty">Failed to load</td></tr>';
796
+ }
797
+ }
798
+
799
+ function renderEvents(events) {
800
+ if (events.length === 0) {
801
+ document.getElementById('events-body').innerHTML = '<tr><td colspan="4" class="empty">No events</td></tr>';
802
+ return;
803
+ }
804
+ document.getElementById('events-body').innerHTML = events.map(e => {
805
+ const time = parseTime(e.timestamp).toLocaleTimeString();
806
+ const badge = e.hook_type === 'PreToolUse' ? 'info' : e.hook_type === 'Stop' ? 'warn' : 'allow';
807
+ return `<tr>
808
+ <td>${time}</td>
809
+ <td><span class="badge badge-${badge}">${e.hook_type}</span></td>
810
+ <td>${e.tool_name || '—'}</td>
811
+ <td>${(e.project_path || '').split('/').pop()}</td>
812
+ </tr>`;
813
+ }).join('');
814
+ }
815
+
816
+ function filterEvents() {
817
+ const query = document.getElementById('events-search').value.toLowerCase();
818
+ const filtered = allEvents.filter(e =>
819
+ (e.hook_type || '').toLowerCase().includes(query) ||
820
+ (e.tool_name || '').toLowerCase().includes(query) ||
821
+ (e.project_path || '').toLowerCase().includes(query)
822
+ );
823
+ renderEvents(filtered);
824
+ }
825
+
826
+ async function loadRules() {
827
+ try {
828
+ const res = await fetch(API + '/api/rules');
829
+ const rulesData = await res.json();
830
+ allRules = [];
831
+
832
+ Object.entries(rulesData).forEach(([id, conv]) => {
833
+ (conv.rules || []).forEach(rule => {
834
+ allRules.push({ ...rule, conventionId: id, conventionName: conv.name });
835
+ });
836
+ });
837
+
838
+ renderRules(allRules);
839
+ } catch {
840
+ document.getElementById('rules-list').innerHTML = '<div class="empty">Failed to load</div>';
841
+ }
842
+ }
843
+
844
+ function renderRules(rules) {
845
+ if (rules.length === 0) {
846
+ document.getElementById('rules-list').innerHTML = '<div class="empty">No rules loaded</div>';
847
+ return;
848
+ }
849
+
850
+ document.getElementById('rules-list').innerHTML = rules.map((rule, idx) => {
851
+ const tags = (rule.tags || []).map(t => `<span class="tag">${t}</span>`).join('');
852
+ return `<div class="rule-card fade-in" onclick="loadRuleDetail(${idx})">
853
+ <div style="display:flex;justify-content:space-between;align-items:start">
854
+ <div style="flex:1">
855
+ <div style="font-size:0.75rem;color:var(--text-dim);margin-bottom:0.25rem">${rule.conventionName || rule.conventionId}</div>
856
+ <h3 style="margin-bottom:0.5rem">${rule.name || 'Unnamed Rule'}</h3>
857
+ <div style="font-size:0.85rem;color:var(--text-muted);margin-bottom:0.5rem">${(rule.description || '').slice(0, 100)}</div>
858
+ <div style="margin-top:0.5rem">${tags}</div>
859
+ </div>
860
+ <span style="color:var(--accent);font-size:1.5rem">→</span>
861
+ </div>
862
+ </div>`;
863
+ }).join('');
864
+ }
865
+
866
+ function filterRules() {
867
+ const query = document.getElementById('rules-search').value.toLowerCase();
868
+ const filtered = allRules.filter(r =>
869
+ (r.name || '').toLowerCase().includes(query) ||
870
+ (r.description || '').toLowerCase().includes(query) ||
871
+ (r.category || '').toLowerCase().includes(query) ||
872
+ (r.tags || []).some(t => t.toLowerCase().includes(query))
873
+ );
874
+ renderRules(filtered);
875
+ }
876
+
877
+ async function loadInjections() {
878
+ try {
879
+ const session = document.getElementById('inj-session').value;
880
+ const handler = document.getElementById('inj-handler').value;
881
+ let url = API + '/api/injections?limit=50';
882
+ if (session) url += '&session=' + session;
883
+ if (handler) url += '&handler=' + handler;
884
+ const res = await fetch(url);
885
+ allInjections = await res.json();
886
+
887
+ const sessRes = await fetch(API + '/api/sessions?limit=10');
888
+ const sessions = await sessRes.json();
889
+ const sessSelect = document.getElementById('inj-session');
890
+ if (sessSelect.options.length === 1) {
891
+ sessions.forEach(s => {
892
+ const opt = document.createElement('option');
893
+ opt.value = s.session_id;
894
+ opt.textContent = s.session_id.slice(0, 8);
895
+ sessSelect.appendChild(opt);
896
+ });
897
+ }
898
+
899
+ renderInjections(allInjections);
900
+ } catch {
901
+ document.getElementById('injections-list').innerHTML = '<div class="empty">Failed to load</div>';
902
+ }
903
+ }
904
+
905
+ function renderInjections(injections) {
906
+ if (injections.length === 0) {
907
+ document.getElementById('injections-list').innerHTML = '<div class="empty">No injections found</div>';
908
+ return;
909
+ }
910
+
911
+ document.getElementById('injections-list').innerHTML = injections.map(inj => {
912
+ const time = parseTime(inj.timestamp).toLocaleString();
913
+ const shortSession = inj.session_id.slice(0, 8);
914
+ const preview = inj.content.slice(0, 150);
915
+ return `<div class="inj-card fade-in">
916
+ <div style="display:flex;justify-content:space-between;margin-bottom:0.5rem">
917
+ <span class="badge badge-info">${inj.injection_type}</span>
918
+ <span style="font-size:0.75rem;color:var(--text-dim)">${time}</span>
919
+ </div>
920
+ <div style="font-size:0.8rem;color:var(--text-muted);margin-bottom:0.5rem">
921
+ Session: ${shortSession} · Handler: ${inj.source_handler}
922
+ </div>
923
+ <details>
924
+ <summary style="cursor:pointer;font-size:0.85rem;color:var(--accent)">Preview: ${preview}...</summary>
925
+ <pre style="margin-top:0.5rem;font-size:0.75rem;background:var(--bg-secondary);padding:0.75rem;border-radius:6px;white-space:pre-wrap;max-height:400px;overflow-y:auto">${inj.content}</pre>
926
+ </details>
927
+ </div>`;
928
+ }).join('');
929
+ }
930
+
931
+ function filterInjections() {
932
+ const query = document.getElementById('injections-search').value.toLowerCase();
933
+ const filtered = allInjections.filter(inj =>
934
+ (inj.injection_type || '').toLowerCase().includes(query) ||
935
+ (inj.content || '').toLowerCase().includes(query) ||
936
+ (inj.source_handler || '').toLowerCase().includes(query)
937
+ );
938
+ renderInjections(filtered);
939
+ }
940
+
941
+ // ========== Rule Detail Page ==========
942
+ function loadRuleDetail(ruleIdx) {
943
+ if (!allRules[ruleIdx]) return;
944
+
945
+ showPage('rule-detail');
946
+ const rule = allRules[ruleIdx];
947
+
948
+ document.getElementById('rule-detail-title').textContent = rule.name || 'Unnamed Rule';
949
+
950
+ const tags = (rule.tags || []).map(t => `<span class="tag">${t}</span>`).join('');
951
+ const docRef = rule.doc_ref ? `<a href="${rule.doc_ref}" target="_blank" style="color:var(--accent)">${rule.doc_ref}</a>` : 'N/A';
952
+
953
+ let html = `
954
+ <div class="card fade-in" style="margin-bottom:1.5rem">
955
+ <div style="font-size:0.85rem;color:var(--text-dim);margin-bottom:0.5rem">Convention: ${rule.conventionName || rule.conventionId}</div>
956
+ <h2 style="margin-bottom:1rem">${rule.name || 'Unnamed Rule'}</h2>
957
+ <div style="margin-bottom:1rem">${tags}</div>
958
+ <div style="font-size:0.95rem;color:var(--text-muted);line-height:1.6">${rule.description || 'No description'}</div>
959
+ </div>
960
+ `;
961
+
962
+ html += `<div class="card fade-in" style="margin-bottom:1rem">
963
+ <h3 style="margin-bottom:1rem">Rule Details</h3>
964
+ <div style="margin-bottom:0.75rem">
965
+ <div style="font-size:0.85rem;font-weight:600;color:var(--text-muted)">Category</div>
966
+ <div style="font-size:0.95rem">${rule.category || 'N/A'}</div>
967
+ </div>
968
+ <div style="margin-bottom:0.75rem">
969
+ <div style="font-size:0.85rem;font-weight:600;color:var(--text-muted)">When Condition</div>
970
+ <pre style="font-size:0.85rem;background:var(--bg-secondary);padding:0.75rem;border-radius:6px;overflow-x:auto">${rule.when || 'N/A'}</pre>
971
+ </div>
972
+ <div style="margin-bottom:0.75rem">
973
+ <div style="font-size:0.85rem;font-weight:600;color:var(--text-muted)">Action</div>
974
+ <div style="font-size:0.95rem">${rule.action || 'N/A'}</div>
975
+ </div>
976
+ <div style="margin-bottom:0.75rem">
977
+ <div style="font-size:0.85rem;font-weight:600;color:var(--text-muted)">Message</div>
978
+ <div style="font-size:0.95rem">${rule.message || 'N/A'}</div>
979
+ </div>
980
+ <div>
981
+ <div style="font-size:0.85rem;font-weight:600;color:var(--text-muted)">Documentation</div>
982
+ <div style="font-size:0.95rem">${docRef}</div>
983
+ </div>
984
+ </div>`;
985
+
986
+ if (rule.operator_guidance) {
987
+ html += `<div class="card fade-in" style="border-left:3px solid var(--accent)">
988
+ <h3 style="margin-bottom:1rem">Operator Guidance</h3>
989
+ <div style="font-size:0.95rem;color:var(--text-muted);line-height:1.6;white-space:pre-wrap">${rule.operator_guidance}</div>
990
+ </div>`;
991
+ }
992
+
993
+ document.getElementById('rule-detail').innerHTML = html;
994
+ }
995
+
659
996
  </script>
660
997
  </body>
661
998
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@winspan/claude-forge",
3
- "version": "8.2.0",
3
+ "version": "8.11.0",
4
4
  "description": "SDLC intelligent orchestration engine for Claude Code",
5
5
  "main": "dist/cli/index.js",
6
6
  "type": "module",