shipwright-cli 2.3.0 → 2.4.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/README.md +82 -20
- package/config/policy.json +160 -2
- package/config/policy.schema.json +162 -1
- package/dashboard/public/index.html +1 -1
- package/dashboard/src/core/api.test.ts +362 -0
- package/dashboard/src/core/router.test.ts +266 -0
- package/dashboard/src/core/state.test.ts +235 -0
- package/dashboard/src/core/ws.test.ts +216 -0
- package/dashboard/src/design/icons.test.ts +105 -0
- package/dashboard/src/design/tokens.test.ts +204 -0
- package/dashboard/tsconfig.json +1 -1
- package/dashboard/vitest.config.ts +27 -0
- package/package.json +23 -4
- package/scripts/lib/pipeline-stages.sh +59 -0
- package/scripts/sw +1 -1
- package/scripts/sw-activity.sh +1 -1
- package/scripts/sw-adaptive.sh +1 -1
- package/scripts/sw-adversarial.sh +1 -1
- package/scripts/sw-architecture-enforcer.sh +1 -1
- package/scripts/sw-auth.sh +1 -1
- package/scripts/sw-autonomous.sh +230 -13
- package/scripts/sw-changelog.sh +1 -1
- package/scripts/sw-checkpoint.sh +1 -1
- package/scripts/sw-ci.sh +1 -1
- package/scripts/sw-cleanup.sh +1 -1
- package/scripts/sw-code-review.sh +1 -1
- package/scripts/sw-connect.sh +1 -1
- package/scripts/sw-context.sh +1 -1
- package/scripts/sw-cost.sh +1 -1
- package/scripts/sw-daemon.sh +1 -1
- package/scripts/sw-dashboard.sh +1 -1
- package/scripts/sw-db.sh +1 -1
- package/scripts/sw-decompose.sh +1 -1
- package/scripts/sw-deps.sh +1 -1
- package/scripts/sw-developer-simulation.sh +1 -1
- package/scripts/sw-discovery.sh +1 -1
- package/scripts/sw-doc-fleet.sh +1 -1
- package/scripts/sw-docs-agent.sh +1 -1
- package/scripts/sw-docs.sh +1 -1
- package/scripts/sw-doctor.sh +1 -1
- package/scripts/sw-dora.sh +1 -1
- package/scripts/sw-durable.sh +1 -1
- package/scripts/sw-e2e-orchestrator.sh +1 -1
- package/scripts/sw-eventbus.sh +1 -1
- package/scripts/sw-evidence.sh +664 -0
- package/scripts/sw-feedback.sh +1 -1
- package/scripts/sw-fix.sh +1 -1
- package/scripts/sw-fleet-discover.sh +1 -1
- package/scripts/sw-fleet-viz.sh +1 -1
- package/scripts/sw-fleet.sh +1 -1
- package/scripts/sw-github-app.sh +1 -1
- package/scripts/sw-github-checks.sh +1 -1
- package/scripts/sw-github-deploy.sh +1 -1
- package/scripts/sw-github-graphql.sh +1 -1
- package/scripts/sw-guild.sh +1 -1
- package/scripts/sw-heartbeat.sh +1 -1
- package/scripts/sw-hygiene.sh +1 -1
- package/scripts/sw-incident.sh +244 -1
- package/scripts/sw-init.sh +1 -1
- package/scripts/sw-instrument.sh +1 -1
- package/scripts/sw-intelligence.sh +1 -1
- package/scripts/sw-jira.sh +1 -1
- package/scripts/sw-launchd.sh +1 -1
- package/scripts/sw-linear.sh +1 -1
- package/scripts/sw-logs.sh +1 -1
- package/scripts/sw-loop.sh +1 -1
- package/scripts/sw-memory.sh +1 -1
- package/scripts/sw-mission-control.sh +1 -1
- package/scripts/sw-model-router.sh +1 -1
- package/scripts/sw-otel.sh +1 -1
- package/scripts/sw-oversight.sh +1 -1
- package/scripts/sw-pipeline-composer.sh +1 -1
- package/scripts/sw-pipeline-vitals.sh +1 -1
- package/scripts/sw-pipeline.sh +1 -1
- package/scripts/sw-pm.sh +1 -1
- package/scripts/sw-pr-lifecycle.sh +177 -5
- package/scripts/sw-predictive.sh +1 -1
- package/scripts/sw-prep.sh +1 -1
- package/scripts/sw-ps.sh +1 -1
- package/scripts/sw-public-dashboard.sh +1 -1
- package/scripts/sw-quality.sh +1 -1
- package/scripts/sw-reaper.sh +1 -1
- package/scripts/sw-regression.sh +1 -1
- package/scripts/sw-release-manager.sh +1 -1
- package/scripts/sw-release.sh +1 -1
- package/scripts/sw-remote.sh +1 -1
- package/scripts/sw-replay.sh +1 -1
- package/scripts/sw-retro.sh +4 -1
- package/scripts/sw-review-rerun.sh +220 -0
- package/scripts/sw-scale.sh +1 -1
- package/scripts/sw-security-audit.sh +1 -1
- package/scripts/sw-self-optimize.sh +99 -1
- package/scripts/sw-session.sh +1 -1
- package/scripts/sw-setup.sh +1 -1
- package/scripts/sw-standup.sh +1 -1
- package/scripts/sw-status.sh +1 -1
- package/scripts/sw-strategic.sh +1 -1
- package/scripts/sw-stream.sh +1 -1
- package/scripts/sw-swarm.sh +1 -1
- package/scripts/sw-team-stages.sh +1 -1
- package/scripts/sw-templates.sh +1 -1
- package/scripts/sw-testgen.sh +1 -1
- package/scripts/sw-tmux-pipeline.sh +1 -1
- package/scripts/sw-tmux.sh +1 -1
- package/scripts/sw-trace.sh +1 -1
- package/scripts/sw-tracker.sh +1 -1
- package/scripts/sw-triage.sh +198 -11
- package/scripts/sw-upgrade.sh +1 -1
- package/scripts/sw-ux.sh +1 -1
- package/scripts/sw-webhook.sh +1 -1
- package/scripts/sw-widgets.sh +1 -1
- package/scripts/sw-worktree.sh +1 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
colors,
|
|
4
|
+
fonts,
|
|
5
|
+
typeScale,
|
|
6
|
+
spacing,
|
|
7
|
+
radius,
|
|
8
|
+
shadows,
|
|
9
|
+
duration,
|
|
10
|
+
easing,
|
|
11
|
+
zIndex,
|
|
12
|
+
STAGES,
|
|
13
|
+
STAGE_SHORT,
|
|
14
|
+
STAGE_COLORS,
|
|
15
|
+
STAGE_HEX,
|
|
16
|
+
} from "./tokens";
|
|
17
|
+
import type { StageName } from "./tokens";
|
|
18
|
+
|
|
19
|
+
describe("Design Tokens", () => {
|
|
20
|
+
describe("colors", () => {
|
|
21
|
+
it("has all background colors", () => {
|
|
22
|
+
expect(colors.bg).toHaveProperty("abyss");
|
|
23
|
+
expect(colors.bg).toHaveProperty("deep");
|
|
24
|
+
expect(colors.bg).toHaveProperty("ocean");
|
|
25
|
+
expect(colors.bg).toHaveProperty("surface");
|
|
26
|
+
expect(colors.bg).toHaveProperty("foam");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("has accent colors as valid hex/rgba", () => {
|
|
30
|
+
expect(colors.accent.cyan).toMatch(/^#[0-9a-f]{6}$/i);
|
|
31
|
+
expect(colors.accent.purple).toMatch(/^#[0-9a-f]{6}$/i);
|
|
32
|
+
expect(colors.accent.blue).toMatch(/^#[0-9a-f]{6}$/i);
|
|
33
|
+
expect(colors.accent.cyanGlow).toMatch(/^rgba\(/);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("has semantic colors", () => {
|
|
37
|
+
expect(colors.semantic.success).toMatch(/^#/);
|
|
38
|
+
expect(colors.semantic.warning).toMatch(/^#/);
|
|
39
|
+
expect(colors.semantic.error).toMatch(/^#/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("has text colors", () => {
|
|
43
|
+
expect(colors.text.primary).toMatch(/^#/);
|
|
44
|
+
expect(colors.text.secondary).toMatch(/^#/);
|
|
45
|
+
expect(colors.text.muted).toMatch(/^#/);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe("fonts", () => {
|
|
50
|
+
it("defines display, body, and mono font stacks", () => {
|
|
51
|
+
expect(fonts.display).toContain("serif");
|
|
52
|
+
expect(fonts.body).toContain("sans-serif");
|
|
53
|
+
expect(fonts.mono).toContain("monospace");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("typeScale", () => {
|
|
58
|
+
it("has all scale levels", () => {
|
|
59
|
+
const levels = [
|
|
60
|
+
"display",
|
|
61
|
+
"heading",
|
|
62
|
+
"title",
|
|
63
|
+
"body",
|
|
64
|
+
"caption",
|
|
65
|
+
"tiny",
|
|
66
|
+
"mono",
|
|
67
|
+
"monoSm",
|
|
68
|
+
];
|
|
69
|
+
for (const level of levels) {
|
|
70
|
+
const entry = typeScale[level as keyof typeof typeScale];
|
|
71
|
+
expect(entry).toHaveProperty("size");
|
|
72
|
+
expect(entry).toHaveProperty("weight");
|
|
73
|
+
expect(entry).toHaveProperty("family");
|
|
74
|
+
expect(entry.size).toBeGreaterThan(0);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("sizes are ordered display > heading > title > body > caption > tiny", () => {
|
|
79
|
+
expect(typeScale.display.size).toBeGreaterThan(typeScale.heading.size);
|
|
80
|
+
expect(typeScale.heading.size).toBeGreaterThan(typeScale.title.size);
|
|
81
|
+
expect(typeScale.title.size).toBeGreaterThan(typeScale.body.size);
|
|
82
|
+
expect(typeScale.body.size).toBeGreaterThan(typeScale.caption.size);
|
|
83
|
+
expect(typeScale.caption.size).toBeGreaterThan(typeScale.tiny.size);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe("spacing", () => {
|
|
88
|
+
it("defines a spacing scale", () => {
|
|
89
|
+
expect(spacing[0]).toBe(0);
|
|
90
|
+
expect(spacing[1]).toBe(4);
|
|
91
|
+
expect(spacing[2]).toBe(8);
|
|
92
|
+
expect(spacing[4]).toBe(16);
|
|
93
|
+
expect(spacing[8]).toBe(32);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("has increasing values", () => {
|
|
97
|
+
const keys = Object.keys(spacing)
|
|
98
|
+
.map(Number)
|
|
99
|
+
.sort((a, b) => a - b);
|
|
100
|
+
for (let i = 1; i < keys.length; i++) {
|
|
101
|
+
expect(spacing[keys[i]]).toBeGreaterThanOrEqual(spacing[keys[i - 1]]);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe("radius", () => {
|
|
107
|
+
it("has sm < md < lg < xl < full", () => {
|
|
108
|
+
expect(radius.sm).toBeLessThan(radius.md);
|
|
109
|
+
expect(radius.md).toBeLessThan(radius.lg);
|
|
110
|
+
expect(radius.lg).toBeLessThan(radius.xl);
|
|
111
|
+
expect(radius.xl).toBeLessThan(radius.full);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("shadows", () => {
|
|
116
|
+
it("has glow shadows for each semantic color", () => {
|
|
117
|
+
expect(shadows.glow.cyan).toContain("rgba");
|
|
118
|
+
expect(shadows.glow.purple).toContain("rgba");
|
|
119
|
+
expect(shadows.glow.success).toContain("rgba");
|
|
120
|
+
expect(shadows.glow.error).toContain("rgba");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("has an elevated shadow", () => {
|
|
124
|
+
expect(shadows.elevated).toContain("rgba");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("duration", () => {
|
|
129
|
+
it("has increasing animation durations", () => {
|
|
130
|
+
expect(duration.fast).toBeLessThan(duration.base);
|
|
131
|
+
expect(duration.base).toBeLessThan(duration.slow);
|
|
132
|
+
expect(duration.slow).toBeLessThan(duration.glacial);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe("easing", () => {
|
|
137
|
+
it("defines easing curves", () => {
|
|
138
|
+
expect(easing.default).toBe("ease");
|
|
139
|
+
expect(easing.smooth).toContain("cubic-bezier");
|
|
140
|
+
expect(easing.spring).toContain("cubic-bezier");
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe("zIndex", () => {
|
|
145
|
+
it("has increasing z-index values", () => {
|
|
146
|
+
expect(zIndex.base).toBeLessThan(zIndex.dropdown);
|
|
147
|
+
expect(zIndex.dropdown).toBeLessThan(zIndex.sticky);
|
|
148
|
+
expect(zIndex.sticky).toBeLessThan(zIndex.overlay);
|
|
149
|
+
expect(zIndex.overlay).toBeLessThan(zIndex.modal);
|
|
150
|
+
expect(zIndex.modal).toBeLessThan(zIndex.toast);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe("STAGES", () => {
|
|
155
|
+
it("defines the pipeline stage sequence", () => {
|
|
156
|
+
expect(STAGES).toHaveLength(11);
|
|
157
|
+
expect(STAGES[0]).toBe("intake");
|
|
158
|
+
expect(STAGES[STAGES.length - 1]).toBe("monitor");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("includes all expected stages", () => {
|
|
162
|
+
const expected = [
|
|
163
|
+
"intake",
|
|
164
|
+
"plan",
|
|
165
|
+
"design",
|
|
166
|
+
"build",
|
|
167
|
+
"test",
|
|
168
|
+
"review",
|
|
169
|
+
"compound_quality",
|
|
170
|
+
"pr",
|
|
171
|
+
"merge",
|
|
172
|
+
"deploy",
|
|
173
|
+
"monitor",
|
|
174
|
+
];
|
|
175
|
+
expect([...STAGES]).toEqual(expected);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe("STAGE_SHORT", () => {
|
|
180
|
+
it("maps every stage to a short code", () => {
|
|
181
|
+
for (const stage of STAGES) {
|
|
182
|
+
expect(STAGE_SHORT[stage]).toBeDefined();
|
|
183
|
+
expect(STAGE_SHORT[stage].length).toBeLessThanOrEqual(3);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe("STAGE_COLORS", () => {
|
|
189
|
+
it("has a color class for each stage", () => {
|
|
190
|
+
expect(STAGE_COLORS).toHaveLength(STAGES.length);
|
|
191
|
+
for (const cls of STAGE_COLORS) {
|
|
192
|
+
expect(cls).toMatch(/^c-/);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe("STAGE_HEX", () => {
|
|
198
|
+
it("maps every stage to a hex color", () => {
|
|
199
|
+
for (const stage of STAGES) {
|
|
200
|
+
expect(STAGE_HEX[stage]).toMatch(/^#[0-9a-f]{6}$/i);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
package/dashboard/tsconfig.json
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
environment: "happy-dom",
|
|
6
|
+
root: "./dashboard",
|
|
7
|
+
include: ["src/**/*.test.ts"],
|
|
8
|
+
globals: true,
|
|
9
|
+
coverage: {
|
|
10
|
+
provider: "v8",
|
|
11
|
+
reporter: ["text", "json-summary"],
|
|
12
|
+
include: ["src/**/*.ts"],
|
|
13
|
+
exclude: ["src/**/*.test.ts", "src/types/**"],
|
|
14
|
+
thresholds: {
|
|
15
|
+
statements: 60,
|
|
16
|
+
branches: 50,
|
|
17
|
+
functions: 60,
|
|
18
|
+
lines: 60,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
resolve: {
|
|
23
|
+
alias: {
|
|
24
|
+
"@": "./dashboard/src",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shipwright-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Orchestrate autonomous Claude Code agent teams in tmux",
|
|
5
5
|
"bin": {
|
|
6
6
|
"shipwright": "./scripts/sw",
|
|
@@ -33,9 +33,24 @@
|
|
|
33
33
|
"dashboard:build": "bun build dashboard/src/main.ts --target=browser --outdir=dashboard/public/dist --sourcemap=linked",
|
|
34
34
|
"dashboard:watch": "bun build dashboard/src/main.ts --target=browser --outdir=dashboard/public/dist --sourcemap=linked --watch",
|
|
35
35
|
"dashboard:prod": "bun build dashboard/src/main.ts --target=browser --outdir=dashboard/public/dist --minify",
|
|
36
|
-
"test": "
|
|
36
|
+
"dashboard:test": "vitest run --config dashboard/vitest.config.ts",
|
|
37
|
+
"dashboard:test:watch": "vitest --config dashboard/vitest.config.ts",
|
|
38
|
+
"dashboard:test:coverage": "vitest run --config dashboard/vitest.config.ts --coverage",
|
|
39
|
+
"test": "bash scripts/sw-agi-roadmap-test.sh && bash scripts/sw-activity-test.sh && bash scripts/sw-adaptive-test.sh && bash scripts/sw-adversarial-test.sh && bash scripts/sw-architecture-enforcer-test.sh && bash scripts/sw-auth-test.sh && bash scripts/sw-autonomous-test.sh && bash scripts/sw-changelog-test.sh && bash scripts/sw-checkpoint-test.sh && bash scripts/sw-ci-test.sh && bash scripts/sw-cleanup-test.sh && bash scripts/sw-code-review-test.sh && bash scripts/sw-connect-test.sh && bash scripts/sw-context-test.sh && bash scripts/sw-cost-test.sh && bash scripts/sw-daemon-test.sh && bash scripts/sw-dashboard-test.sh && bash scripts/sw-db-test.sh && bash scripts/sw-decompose-test.sh && bash scripts/sw-deps-test.sh && bash scripts/sw-developer-simulation-test.sh && bash scripts/sw-discovery-test.sh && bash scripts/sw-doc-fleet-test.sh && bash scripts/sw-docs-agent-test.sh && bash scripts/sw-docs-test.sh && bash scripts/sw-doctor-test.sh && bash scripts/sw-dora-test.sh && bash scripts/sw-durable-test.sh && bash scripts/sw-e2e-orchestrator-test.sh && bash scripts/sw-eventbus-test.sh && bash scripts/sw-feedback-test.sh && bash scripts/sw-fix-test.sh && bash scripts/sw-fleet-discover-test.sh && bash scripts/sw-fleet-test.sh && bash scripts/sw-fleet-viz-test.sh && bash scripts/sw-frontier-test.sh && bash scripts/sw-github-app-test.sh && bash scripts/sw-github-checks-test.sh && bash scripts/sw-github-deploy-test.sh && bash scripts/sw-github-graphql-test.sh && bash scripts/sw-guild-test.sh && bash scripts/sw-heartbeat-test.sh && bash scripts/sw-hygiene-test.sh && bash scripts/sw-incident-test.sh && bash scripts/sw-init-test.sh && bash scripts/sw-instrument-test.sh && bash scripts/sw-intelligence-test.sh && bash scripts/sw-jira-test.sh && bash scripts/sw-launchd-test.sh && bash scripts/sw-linear-test.sh && bash scripts/sw-logs-test.sh && bash scripts/sw-loop-test.sh && bash scripts/sw-memory-test.sh && bash scripts/sw-mission-control-test.sh && bash scripts/sw-model-router-test.sh && bash scripts/sw-otel-test.sh && bash scripts/sw-oversight-test.sh && bash scripts/sw-patrol-meta-test.sh && bash scripts/sw-pipeline-composer-test.sh && bash scripts/sw-pipeline-test.sh && bash scripts/sw-pipeline-vitals-test.sh && bash scripts/sw-pm-test.sh && bash scripts/sw-pr-lifecycle-test.sh && bash scripts/sw-predictive-test.sh && bash scripts/sw-prep-test.sh && bash scripts/sw-ps-test.sh && bash scripts/sw-public-dashboard-test.sh && bash scripts/sw-quality-test.sh && bash scripts/sw-reaper-test.sh && bash scripts/sw-recruit-test.sh && bash scripts/sw-regression-test.sh && bash scripts/sw-release-manager-test.sh && bash scripts/sw-release-test.sh && bash scripts/sw-remote-test.sh && bash scripts/sw-replay-test.sh && bash scripts/sw-retro-test.sh && bash scripts/sw-scale-test.sh && bash scripts/sw-security-audit-test.sh && bash scripts/sw-self-optimize-test.sh && bash scripts/sw-session-test.sh && bash scripts/sw-setup-test.sh && bash scripts/sw-standup-test.sh && bash scripts/sw-status-test.sh && bash scripts/sw-strategic-test.sh && bash scripts/sw-stream-test.sh && bash scripts/sw-swarm-test.sh && bash scripts/sw-team-stages-test.sh && bash scripts/sw-templates-test.sh && bash scripts/sw-testgen-test.sh && bash scripts/sw-tmux-pipeline-test.sh && bash scripts/sw-tmux-test.sh && bash scripts/sw-trace-test.sh && bash scripts/sw-tracker-test.sh && bash scripts/sw-triage-test.sh && bash scripts/sw-upgrade-test.sh && bash scripts/sw-ux-test.sh && bash scripts/sw-webhook-test.sh && bash scripts/sw-widgets-test.sh && bash scripts/sw-worktree-test.sh && bash scripts/sw-policy-e2e-test.sh && bash scripts/sw-e2e-smoke-test.sh && bash scripts/sw-dashboard-e2e-test.sh",
|
|
37
40
|
"test:smoke": "bash scripts/sw-e2e-smoke-test.sh",
|
|
38
|
-
"test:integration": "bash scripts/sw-e2e-integration-test.sh"
|
|
41
|
+
"test:integration": "bash scripts/sw-e2e-integration-test.sh",
|
|
42
|
+
"harness:evidence:capture": "bash scripts/sw-evidence.sh capture",
|
|
43
|
+
"harness:evidence:verify": "bash scripts/sw-evidence.sh verify",
|
|
44
|
+
"harness:evidence:pre-pr": "bash scripts/sw-evidence.sh pre-pr",
|
|
45
|
+
"harness:evidence:capture:browser": "bash scripts/sw-evidence.sh capture browser",
|
|
46
|
+
"harness:evidence:capture:api": "bash scripts/sw-evidence.sh capture api",
|
|
47
|
+
"harness:evidence:capture:database": "bash scripts/sw-evidence.sh capture database",
|
|
48
|
+
"harness:evidence:capture:cli": "bash scripts/sw-evidence.sh capture cli",
|
|
49
|
+
"harness:ui:capture-browser-evidence": "bash scripts/sw-evidence.sh capture browser",
|
|
50
|
+
"harness:ui:verify-browser-evidence": "bash scripts/sw-evidence.sh verify",
|
|
51
|
+
"harness:ui:pre-pr": "bash scripts/sw-evidence.sh pre-pr browser",
|
|
52
|
+
"harness:risk-tier": "bash scripts/sw-pr-lifecycle.sh risk-tier",
|
|
53
|
+
"harness:policy-gate": "bash scripts/sw-pr-lifecycle.sh policy-gate"
|
|
39
54
|
},
|
|
40
55
|
"keywords": [
|
|
41
56
|
"claude",
|
|
@@ -57,7 +72,11 @@
|
|
|
57
72
|
"node": ">=20"
|
|
58
73
|
},
|
|
59
74
|
"devDependencies": {
|
|
75
|
+
"@testing-library/dom": "^10.4.1",
|
|
60
76
|
"bun-types": "^1.3.9",
|
|
61
|
-
"
|
|
77
|
+
"happy-dom": "^20.6.1",
|
|
78
|
+
"jsdom": "^28.1.0",
|
|
79
|
+
"typescript": "^5.9.3",
|
|
80
|
+
"vitest": "^4.0.18"
|
|
62
81
|
}
|
|
63
82
|
}
|
|
@@ -1761,6 +1761,60 @@ stage_merge() {
|
|
|
1761
1761
|
return 0
|
|
1762
1762
|
fi
|
|
1763
1763
|
|
|
1764
|
+
# ── Oversight gate: merge block on verdict (diff + review criticals + goal) ──
|
|
1765
|
+
if [[ -x "$SCRIPT_DIR/sw-oversight.sh" ]] && [[ "${SKIP_GATES:-false}" != "true" ]]; then
|
|
1766
|
+
local merge_diff_file="${ARTIFACTS_DIR}/review-diff.patch"
|
|
1767
|
+
local merge_review_file="${ARTIFACTS_DIR}/review.md"
|
|
1768
|
+
if [[ ! -s "$merge_diff_file" ]]; then
|
|
1769
|
+
git diff "${BASE_BRANCH}...${GIT_BRANCH}" > "$merge_diff_file" 2>/dev/null || \
|
|
1770
|
+
git diff HEAD~5 > "$merge_diff_file" 2>/dev/null || true
|
|
1771
|
+
fi
|
|
1772
|
+
if [[ -s "$merge_diff_file" ]]; then
|
|
1773
|
+
local _merge_critical _merge_sec _merge_blocking _merge_reject
|
|
1774
|
+
_merge_critical=$(grep -ciE '\*\*\[?Critical\]?\*\*' "$merge_review_file" 2>/dev/null || echo "0")
|
|
1775
|
+
_merge_sec=$(grep -ciE '\*\*\[?Security\]?\*\*' "$merge_review_file" 2>/dev/null || echo "0")
|
|
1776
|
+
_merge_blocking=$((${_merge_critical:-0} + ${_merge_sec:-0}))
|
|
1777
|
+
[[ "$_merge_blocking" -gt 0 ]] && _merge_reject="Review found ${_merge_blocking} critical/security issue(s)"
|
|
1778
|
+
if ! bash "$SCRIPT_DIR/sw-oversight.sh" gate --diff "$merge_diff_file" --description "${GOAL:-Pipeline merge}" --reject-if "${_merge_reject:-}" >/dev/null 2>&1; then
|
|
1779
|
+
error "Oversight gate rejected — blocking merge"
|
|
1780
|
+
emit_event "merge.oversight_blocked" "issue=${ISSUE_NUMBER:-0}"
|
|
1781
|
+
log_stage "merge" "BLOCKED: oversight gate rejected"
|
|
1782
|
+
return 1
|
|
1783
|
+
fi
|
|
1784
|
+
fi
|
|
1785
|
+
fi
|
|
1786
|
+
|
|
1787
|
+
# ── Approval gates: block if merge requires approval and pending for this issue ──
|
|
1788
|
+
local ag_file="${HOME}/.shipwright/approval-gates.json"
|
|
1789
|
+
if [[ -f "$ag_file" ]] && [[ "${SKIP_GATES:-false}" != "true" ]]; then
|
|
1790
|
+
local ag_enabled ag_stages ag_pending_merge ag_issue_num
|
|
1791
|
+
ag_enabled=$(jq -r '.enabled // false' "$ag_file" 2>/dev/null || echo "false")
|
|
1792
|
+
ag_stages=$(jq -r '.stages // [] | if type == "array" then .[] else empty end' "$ag_file" 2>/dev/null || true)
|
|
1793
|
+
ag_issue_num=$(echo "${ISSUE_NUMBER:-0}" | awk '{print $1+0}')
|
|
1794
|
+
if [[ "$ag_enabled" == "true" ]] && echo "$ag_stages" | grep -qx "merge" 2>/dev/null; then
|
|
1795
|
+
local ha_file="${ARTIFACTS_DIR}/human-approval.txt"
|
|
1796
|
+
local ha_approved="false"
|
|
1797
|
+
if [[ -f "$ha_file" ]]; then
|
|
1798
|
+
ha_approved=$(jq -r --arg stage "merge" 'select(.stage == $stage) | .approved // false' "$ha_file" 2>/dev/null || echo "false")
|
|
1799
|
+
fi
|
|
1800
|
+
if [[ "$ha_approved" != "true" ]]; then
|
|
1801
|
+
ag_pending_merge=$(jq -r --argjson issue "$ag_issue_num" --arg stage "merge" \
|
|
1802
|
+
'[.pending[]? | select(.issue == $issue and .stage == $stage)] | length' "$ag_file" 2>/dev/null || echo "0")
|
|
1803
|
+
if [[ "${ag_pending_merge:-0}" -eq 0 ]]; then
|
|
1804
|
+
local req_at tmp_ag
|
|
1805
|
+
req_at=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || true)
|
|
1806
|
+
tmp_ag=$(mktemp "${HOME}/.shipwright/approval-gates.json.XXXXXX" 2>/dev/null || mktemp)
|
|
1807
|
+
jq --argjson issue "$ag_issue_num" --arg stage "merge" --arg requested "${req_at}" \
|
|
1808
|
+
'.pending += [{"issue": $issue, "stage": $stage, "requested_at": $requested}]' "$ag_file" > "$tmp_ag" 2>/dev/null && mv "$tmp_ag" "$ag_file" || rm -f "$tmp_ag"
|
|
1809
|
+
fi
|
|
1810
|
+
info "Merge requires approval — awaiting human approval via dashboard"
|
|
1811
|
+
emit_event "merge.approval_pending" "issue=${ISSUE_NUMBER:-0}"
|
|
1812
|
+
log_stage "merge" "BLOCKED: approval gate pending"
|
|
1813
|
+
return 1
|
|
1814
|
+
fi
|
|
1815
|
+
fi
|
|
1816
|
+
fi
|
|
1817
|
+
|
|
1764
1818
|
# ── Branch Protection Check ──
|
|
1765
1819
|
if type gh_branch_protection &>/dev/null 2>&1 && [[ -n "$REPO_OWNER" && -n "$REPO_NAME" ]]; then
|
|
1766
1820
|
local protection_json
|
|
@@ -2472,6 +2526,11 @@ _Created automatically by \`shipwright pipeline\` monitor stage_" 2>/dev/null ||
|
|
|
2472
2526
|
|
|
2473
2527
|
success "Post-deploy monitoring clean (${total_errors} errors in ${duration_minutes}m)"
|
|
2474
2528
|
|
|
2529
|
+
# Proactive feedback collection: always collect deploy logs for trend analysis
|
|
2530
|
+
if [[ -f "$deploy_log_file" ]] && [[ -s "$deploy_log_file" ]] && [[ -x "$SCRIPT_DIR/sw-feedback.sh" ]]; then
|
|
2531
|
+
(cd "$PROJECT_ROOT" && ARTIFACTS_DIR="$ARTIFACTS_DIR" bash "$SCRIPT_DIR/sw-feedback.sh" collect "$deploy_log_file" 2>/dev/null) || true
|
|
2532
|
+
fi
|
|
2533
|
+
|
|
2475
2534
|
if [[ -n "$ISSUE_NUMBER" ]]; then
|
|
2476
2535
|
gh_comment_issue "$ISSUE_NUMBER" "✅ **Post-deploy monitoring passed** — ${duration_minutes}m, ${total_errors} errors" 2>/dev/null || true
|
|
2477
2536
|
fi
|
package/scripts/sw
CHANGED
package/scripts/sw-activity.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="2.
|
|
9
|
+
VERSION="2.4.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-adaptive.sh
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
set -euo pipefail
|
|
7
7
|
trap 'echo "ERROR: $BASH_SOURCE:$LINENO exited with status $?" >&2' ERR
|
|
8
8
|
|
|
9
|
-
VERSION="2.
|
|
9
|
+
VERSION="2.4.0"
|
|
10
10
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
11
|
|
|
12
12
|
# ─── Cross-platform compatibility ──────────────────────────────────────────
|
package/scripts/sw-auth.sh
CHANGED