great-cto 3.63.5 → 3.64.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "great-cto",
3
3
  "description": "You already have the agent. This is everything around it. great_cto runs Claude Code as a pipeline of 72 specialist agents \u2014 an independent model checks each stage before the next builds on it, spending caps refuse rather than warn, and three decisions stay yours: what gets built, how, and whether it ships.",
4
- "version": "3.63.5",
4
+ "version": "3.64.0",
5
5
  "author": {
6
6
  "name": "Alexander Velikiy",
7
7
  "url": "https://hashnode.com/@Greatcto"
@@ -3480,6 +3480,7 @@ h1, h2, h3, h4 { font-weight: 600; font-family: var(--sans); }
3480
3480
  <div class="nav-views-label" id="nav-views-label" hidden>Views</div>
3481
3481
  <!-- Fleet filters share the row pattern, but stay buttons, not destinations. -->
3482
3482
  <div class="nav-views" hidden>
3483
+ <div class="nav-view-item" id="nav-view-project" role="button" tabindex="0" onclick="setFleetView('project')" onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();setFleetView('project')}">Project focus</div>
3483
3484
  <div class="nav-view-item" id="nav-view-needs" role="button" tabindex="0" onclick="setFleetView('needs')" onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();setFleetView('needs')}">Needs attention</div>
3484
3485
  <div class="nav-view-item" id="nav-view-expensive" role="button" tabindex="0" onclick="setFleetView('expensive')" onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();setFleetView('expensive')}">Expensive grants</div>
3485
3486
  <div class="nav-view-item" id="nav-view-never" role="button" tabindex="0" onclick="setFleetView('never')" onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();setFleetView('never')}">Never observed</div>
@@ -3795,6 +3796,7 @@ h1, h2, h3, h4 { font-weight: 600; font-family: var(--sans); }
3795
3796
  <section aria-label="Fleet summary" class="fleet-title-row">
3796
3797
  <h1 class="page-title" id="fleet-view-title" style="margin:0">Fleet</h1>
3797
3798
  </section>
3799
+ <p id="fleet-focus-note" class="muted" role="status"></p>
3798
3800
 
3799
3801
  <!-- §3.1 Fleet controls -->
3800
3802
  <section aria-label="Fleet controls" class="fleet-controls-row">
@@ -9463,13 +9465,10 @@ const fleetState = {
9463
9465
  agents: [],
9464
9466
  summary: null,
9465
9467
  legacy_count: 0,
9466
- // Default: hide never-run / retired agents. 35 installed → ~10 actually
9467
- // doing work on most projects; showing all 35 by default is noise.
9468
- // User flips activity to `all` to see the full installation.
9468
+ // View membership is distinct from optional activity filters.
9469
9469
  filters: { domain: 'all', activity: 'all', health: 'all' },
9470
- // Five saved views, and only five (DESIGN §5): the default is the subset
9471
- // nobody has judged yet, not the roster.
9472
- view: 'needs',
9470
+ // Presentation only: dispatch and required-reviewer policy are unchanged.
9471
+ view: 'project',
9473
9472
  search: '',
9474
9473
  sort: 'runs_30d',
9475
9474
  drawerSlug: null,
@@ -9479,15 +9478,32 @@ const fleetState = {
9479
9478
  // Reviewers this project requires (/api/required-reviewers) — gate:ship refuses
9480
9479
  // while one has no verdict.
9481
9480
  required: null,
9481
+ requiredScope: null,
9482
+ requiredRequest: 0,
9483
+ rosterRequest: 0,
9484
+ rosterScope: null,
9482
9485
  };
9486
+ const FLEET_CORE_ROLES = new Set([
9487
+ 'product-owner', 'architect', 'pm', 'senior-dev', 'code-reviewer',
9488
+ 'qa-engineer', 'security-officer', 'devops',
9489
+ ]);
9490
+ function fleetRequirementsKnown() {
9491
+ return fleetState.requiredScope === pqs() && fleetState.required?.state === 'read'
9492
+ && Array.isArray(fleetState.required.reviewers);
9493
+ }
9483
9494
  function requiredOf(slug) {
9484
9495
  const r = fleetState.required;
9485
- return r && r.state === 'read' ? (r.reviewers || []).find((x) => x.agent === slug) || null : null;
9496
+ return fleetRequirementsKnown() ? r.reviewers.find((x) => x.agent === slug) || null : null;
9486
9497
  }
9487
9498
  async function refreshRequiredReviewers() {
9488
- const r = await api(`/api/required-reviewers${pqs()}`);
9489
- if (!r) return;
9499
+ const scope = pqs(), request = ++fleetState.requiredRequest;
9500
+ fleetState.required = null;
9501
+ fleetState.requiredScope = null;
9502
+ renderFleetList();
9503
+ const r = await api(`/api/required-reviewers${scope}`);
9504
+ if (request !== fleetState.requiredRequest || scope !== pqs()) return;
9490
9505
  fleetState.required = r;
9506
+ fleetState.requiredScope = scope;
9491
9507
  renderFleetList();
9492
9508
  }
9493
9509
 
@@ -9507,10 +9523,16 @@ async function refreshAgentUsage() {
9507
9523
  }
9508
9524
 
9509
9525
  async function refreshAgentsInstalled() {
9526
+ const scope = pqs(), request = ++fleetState.rosterRequest;
9527
+ if (fleetState.rosterScope !== scope) {
9528
+ fleetState.agents = [];
9529
+ fleetState.summary = null;
9530
+ fleetState.rosterScope = scope;
9531
+ }
9510
9532
  refreshAgentUsage();
9511
9533
  refreshRequiredReviewers();
9512
- const data = await api(`/api/agents-installed${pqs()}`);
9513
- if (!data) return;
9534
+ const data = await api(`/api/agents-installed${scope}`);
9535
+ if (!data || request !== fleetState.rosterRequest || scope !== pqs()) return;
9514
9536
  fleetState.agents = data.agents || [];
9515
9537
  fleetState.summary = data.summary || null;
9516
9538
  // If this project has no verdicts at all, show all agents (not just 'used').
@@ -9534,6 +9556,7 @@ async function refreshAgentsInstalled() {
9534
9556
 
9535
9557
 
9536
9558
  const FLEET_VIEWS = [
9559
+ ['project', 'Project focus'],
9537
9560
  ['needs', 'Needs attention'], ['expensive', 'Expensive grants'], ['never', 'Never observed'], ['all', 'All agents'], ['retired', 'Retired'],
9538
9561
  ];
9539
9562
  // What "needs attention" means, in one place: failing, an unjudged posture, a
@@ -9548,6 +9571,11 @@ function agentNeedsAttention(a) {
9548
9571
  || String(a.budget?.state || '').startsWith('over');
9549
9572
  }
9550
9573
  function inFleetView(a, view) {
9574
+ if (view === 'project') {
9575
+ // An unavailable policy is not evidence that a specialist is unnecessary.
9576
+ if (!fleetRequirementsKnown()) return !a.retired;
9577
+ return !!requiredOf(a.slug) || (!a.retired && FLEET_CORE_ROLES.has(a.slug));
9578
+ }
9551
9579
  if (view === 'retired') return !!a.retired;
9552
9580
  if (a.retired) return false;
9553
9581
  if (view === 'needs') return agentNeedsAttention(a);
@@ -9568,6 +9596,16 @@ function setFleetView(view) {
9568
9596
  // a count, because "2" would read as two new items.
9569
9597
  function renderFleetViews() {
9570
9598
  const agents = fleetState.agents || [];
9599
+ const note = document.getElementById('fleet-focus-note');
9600
+ if (note) {
9601
+ note.hidden = fleetState.view !== 'project';
9602
+ const attention = agents.filter(a => inFleetView(a, 'needs')).length;
9603
+ const missing = fleetRequirementsKnown()
9604
+ ? fleetState.required.reviewers.filter(r => !agents.some(a => a.slug === r.agent)).map(r => r.agent) : [];
9605
+ note.textContent = fleetRequirementsKnown()
9606
+ ? `Core roles and this project's required reviewers. ${missing.length} required reviewer(s) missing from the installed catalog${missing.length ? ': ' + missing.join(', ') : ''}. ${attention} installed agent(s) need attention across the full catalog; open Needs attention. Display only, not an execution plan or proof of expertise.`
9607
+ : 'Project reviewer requirements are unknown; showing the installed catalog rather than hiding specialists. Display only; execution policy is unchanged.';
9608
+ }
9571
9609
  for (const [key, label] of FLEET_VIEWS) {
9572
9610
  const el = document.getElementById(`nav-view-${key}`);
9573
9611
  if (!el) continue;
@@ -9601,7 +9639,7 @@ function applyFleetFilters(agents) {
9601
9639
  if (activity === 'idle' && (a.runs_30d > 0 || a.runs_total === 0)) return false;
9602
9640
  if (activity === 'never' && a.runs_total > 0) return false;
9603
9641
  if (activity === 'retired' && !a.retired) return false;
9604
- if (activity !== 'retired' && a.retired) return false;
9642
+ if (activity !== 'retired' && a.retired && !(fleetState.view === 'project' && requiredOf(a.slug))) return false;
9605
9643
  if (health === 'ok' && a.health === 'failing') return false;
9606
9644
  if (health === 'failing' && a.health !== 'failing') return false;
9607
9645
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "3.63.5",
3
+ "version": "3.64.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",