Skip to content

Commit 5d4ac1c

Browse files
committed
Merge remote-tracking branch 'origin/main' into development
2 parents 71370cf + fc19a8d commit 5d4ac1c

4 files changed

Lines changed: 79 additions & 18 deletions

File tree

.claude/hooks/update-dashboard-stage.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,15 @@ jq \
7474
active: true,
7575
severity: $severity,
7676
context: $context,
77-
stage: $stage
77+
stage: $stage,
78+
gate: (
79+
if ($stage | ascii_downcase | test("validation|sign.?off|awaiting|gate"))
80+
then { waiting: true, label: ($stage + " — sign-off required"), since: $now }
81+
elif (.agents[$id].deploynope.gate.waiting // false)
82+
then null
83+
else (.agents[$id].deploynope.gate // null)
84+
end
85+
)
7886
}
7987
}
8088
' "$STATE_FILE" > "$STATE_FILE.tmp" 2>/dev/null && mv "$STATE_FILE.tmp" "$STATE_FILE"

dashboard/index.html

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,13 @@
161161
display: flex;
162162
align-items: center;
163163
gap: 0.75rem;
164-
margin-bottom: 0.5rem;
164+
margin-bottom: 0.25rem;
165+
}
166+
.agent-meta-row {
167+
display: flex;
168+
align-items: center;
169+
gap: 0.75rem;
170+
margin-bottom: 0.4rem;
165171
flex-wrap: wrap;
166172
}
167173
.agent-name {
@@ -223,14 +229,11 @@
223229

224230
/* ── Gate Banner ── */
225231
.gate-banner {
226-
background: rgba(210, 153, 34, 0.08);
227-
border: 1px solid rgba(210, 153, 34, 0.25);
228-
border-radius: 0;
229-
padding: 0.4rem 0.6rem;
230232
display: flex;
231233
align-items: center;
232234
gap: 0.4rem;
233-
font-size: 0.7rem;
235+
font-size: 0.65rem;
236+
font-family: 'SF Mono', 'Fira Code', monospace;
234237
margin-bottom: 0.4rem;
235238
}
236239
.gate-banner .gate-text { color: #d29922; font-weight: 500; }
@@ -408,7 +411,6 @@ <h2>Activity</h2>
408411

409412
if (target === config.prodBranch || target === 'main' || target === 'master') return 'production';
410413
if (target === config.stagingBranch || target === 'staging') return 'staging';
411-
if (branch === config.prodBranch || branch === 'main' || branch === 'master') return 'production';
412414
if (branch === config.stagingBranch || branch === 'staging') return 'staging';
413415
return 'feature';
414416
}
@@ -465,11 +467,12 @@ <h2>Activity</h2>
465467

466468
// Header summary
467469
const activeCount = agents.filter(a => !a.stale).length;
468-
const warningCount = 0; // Future: count agents without DeployNOPE active
470+
const gateCount = agents.filter(a => !a.stale && (a.deploynope || {}).gate && a.deploynope.gate.waiting).length;
471+
const warningCount = gateCount;
469472
const dot = document.getElementById('connection-dot');
470473
dot.className = 'status-dot' + (warningCount > 0 ? ' warning' : '');
471474
document.getElementById('header-summary').textContent =
472-
(warningCount > 0 ? warningCount + ' warning' + (warningCount > 1 ? 's' : '') + ' \u00b7 ' : '') +
475+
(gateCount > 0 ? gateCount + ' gate' + (gateCount > 1 ? 's' : '') + ' waiting \u00b7 ' : '') +
473476
activeCount + ' agent' + (activeCount !== 1 ? 's' : '');
474477

475478
// Build a set of repos that have staging claimed (per-repo staging lock)
@@ -498,25 +501,47 @@ <h2>Activity</h2>
498501
const stage = inferStage(agent);
499502
const name = inferName(agent);
500503
const target = agent.target || '';
501-
const staleClass = agent.stale ? ' stale' : '';
502-
const tagClass = agent.stale ? 'idle' : stage;
503-
const tagText = agent.stale ? 'STALE' : stageLabel(agent);
504+
const gate = (agent.deploynope || {}).gate;
505+
const gateWaiting = gate && gate.waiting;
506+
const hasGate = (agent.deploynope || {}).gate && agent.deploynope.gate.waiting;
507+
const treatAsStale = agent.stale && !hasGate;
508+
const staleClass = treatAsStale ? ' stale' : '';
509+
const tagClass = treatAsStale ? 'idle' : stage;
510+
const tagText = treatAsStale ? 'STALE' : stageLabel(agent);
511+
512+
const isStaging = agent.repo && stagingByRepo.hasOwnProperty(agent.repo) && stagingByRepo[agent.repo] === agent.id;
513+
const lockIcon = isStaging ? '\uD83D\uDD12 ' : '';
504514

505-
let inner = '<div class="agent-header">';
506-
inner += '<span class="agent-name">' + escapeHtml(name) + '</span>';
507515
var ghIcon = '<svg class="meta-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>';
508516
var branchIcon = '<svg class="meta-icon" viewBox="0 0 16 16" fill="currentColor"><path d="M11.75 2.5a.75.75 0 100 1.5.75.75 0 000-1.5zm-2.25.75a2.25 2.25 0 113 2.122V6A2.5 2.5 0 0110 8.5H6a1 1 0 00-1 1v1.128a2.251 2.251 0 11-1.5 0V5.372a2.25 2.25 0 111.5 0v1.836A2.492 2.492 0 016 7h4a1 1 0 001-1v-.628A2.25 2.25 0 019.5 3.25zM4.25 12a.75.75 0 100 1.5.75.75 0 000-1.5zM3.5 3.25a.75.75 0 111.5 0 .75.75 0 01-1.5 0z"/></svg>';
517+
518+
let inner = '<div class="agent-header">';
519+
inner += '<span class="agent-name">' + escapeHtml(name) + '</span>';
520+
inner += '<span class="agent-tag ' + tagClass + '">' + lockIcon + tagText + '</span>';
521+
inner += '</div>';
522+
523+
inner += '<div class="agent-meta-row">';
509524
inner += '<span class="agent-meta">' + ghIcon + escapeHtml(agent.repo || '') + '</span>';
510525
if (agent.branch && target) {
511526
inner += '<span class="agent-meta">' + branchIcon + escapeHtml(agent.branch) + ' <span class="agent-branch-arrow">&rarr;</span> ' + escapeHtml(target) + '</span>';
512527
} else if (agent.branch) {
513528
inner += '<span class="agent-meta">' + branchIcon + escapeHtml(agent.branch) + '</span>';
514529
}
515-
const isStaging = agent.repo && stagingByRepo.hasOwnProperty(agent.repo) && stagingByRepo[agent.repo] === agent.id;
516-
const lockIcon = isStaging ? '\uD83D\uDD12 ' : '';
517-
inner += '<span class="agent-tag ' + tagClass + '">' + lockIcon + tagText + '</span>';
530+
var prodBranch = (agent.config || {}).prodBranch || 'main';
531+
var onProd = (agent.branch === prodBranch || agent.branch === 'main' || agent.branch === 'master');
532+
if (onProd && stage !== 'production') {
533+
inner += '<span class="agent-meta" style="color:#f85149;">checked out on ' + escapeHtml(agent.branch) + '</span>';
534+
}
518535
inner += '</div>';
519536

537+
// Gate banner
538+
if (gateWaiting) {
539+
inner += '<div class="gate-banner">' +
540+
'<span class="gate-text">' + escapeHtml(gate.label || 'Waiting for sign-off') + '</span>' +
541+
(gate.since ? '<span style="margin-left:auto;font-size:0.6rem;color:#8b949e;">' + timeAgo(gate.since) + '</span>' : '') +
542+
'</div>';
543+
}
544+
520545
// Last action
521546
if (agent.lastAction) {
522547
inner += '<div class="last-action"><code>' + escapeHtml(shortCommand(agent.lastAction.command || '')) + '</code> ' + timeAgo(agent.lastAction.timestamp) + '</div>';

dashboard/scan.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ scan_repo() {
7777

7878
# Determine target from branch context
7979
local TARGET=""
80+
local ON_STAGING="false"
8081
if [ "$BRANCH" = "${STAGING_BRANCH:-staging}" ]; then
8182
TARGET="$BRANCH"
83+
ON_STAGING="true"
8284
elif [ "$BRANCH" = "${PROD_BRANCH:-main}" ] || [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
8385
TARGET="$BRANCH"
8486
fi
@@ -97,6 +99,7 @@ scan_repo() {
9799
--arg stagingBranch "$STAGING_BRANCH" \
98100
--arg devBranch "$DEV_BRANCH" \
99101
--arg label "$LABEL" \
102+
--arg onStaging "$ON_STAGING" \
100103
'
101104
.agents[$id] = {
102105
id: $id,
@@ -113,6 +116,13 @@ scan_repo() {
113116
stagingBranch: $stagingBranch,
114117
devBranch: $devBranch
115118
} end),
119+
deploynope: (if $onStaging == "true" then {
120+
active: true,
121+
severity: "⚠️",
122+
context: $version,
123+
stage: "Staging Validation",
124+
gate: { waiting: true, label: "Staging Validation — sign-off required", since: $now }
125+
} else null end),
116126
lastAction: {
117127
type: "scan",
118128
command: $lastCommit,

releases/2.18.0.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"version": "2.18.0",
3+
"type": "feature",
4+
"timestamp": "2026-03-24T00:00:00Z",
5+
"deployer": "Tim Simms",
6+
"backend": null,
7+
"frontend": {
8+
"sha": "5ce5f178427773c30c83bcf8f884cf57970eed3b",
9+
"branch": "deploynope-dashboard",
10+
"repo": "SimTimms/deploynope",
11+
"githubReleaseUrl": "https://github.com/SimTimms/deploynope/releases/tag/v2.18.0"
12+
},
13+
"jiraTickets": [],
14+
"confluencePageUrl": null,
15+
"previousVersion": "2.17.0",
16+
"status": "deployed",
17+
"rollback": null
18+
}

0 commit comments

Comments
 (0)