shipwright-cli 3.2.0 → 3.3.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/.claude/agents/code-reviewer.md +2 -0
- package/.claude/agents/devops-engineer.md +2 -0
- package/.claude/agents/doc-fleet-agent.md +2 -0
- package/.claude/agents/pipeline-agent.md +2 -0
- package/.claude/agents/shell-script-specialist.md +2 -0
- package/.claude/agents/test-specialist.md +2 -0
- package/.claude/hooks/agent-crash-capture.sh +32 -0
- package/.claude/hooks/post-tool-use.sh +3 -2
- package/.claude/hooks/pre-tool-use.sh +35 -3
- package/README.md +4 -4
- package/claude-code/hooks/config-change.sh +18 -0
- package/claude-code/hooks/instructions-reloaded.sh +7 -0
- package/claude-code/hooks/worktree-create.sh +25 -0
- package/claude-code/hooks/worktree-remove.sh +20 -0
- package/config/code-constitution.json +130 -0
- package/dashboard/middleware/auth.ts +134 -0
- package/dashboard/middleware/constants.ts +21 -0
- package/dashboard/public/index.html +2 -6
- package/dashboard/public/styles.css +100 -97
- package/dashboard/routes/auth.ts +38 -0
- package/dashboard/server.ts +66 -25
- package/dashboard/services/config.ts +26 -0
- package/dashboard/services/db.ts +118 -0
- package/dashboard/src/canvas/pixel-agent.ts +298 -0
- package/dashboard/src/canvas/pixel-sprites.ts +440 -0
- package/dashboard/src/canvas/shipyard-effects.ts +367 -0
- package/dashboard/src/canvas/shipyard-scene.ts +616 -0
- package/dashboard/src/canvas/submarine-layout.ts +267 -0
- package/dashboard/src/components/header.ts +8 -7
- package/dashboard/src/core/router.ts +1 -0
- package/dashboard/src/design/submarine-theme.ts +253 -0
- package/dashboard/src/main.ts +2 -0
- package/dashboard/src/types/api.ts +2 -1
- package/dashboard/src/views/activity.ts +2 -1
- package/dashboard/src/views/shipyard.ts +39 -0
- package/dashboard/types/index.ts +166 -0
- package/docs/plans/2026-02-28-compound-audit-and-shipyard-design.md +186 -0
- package/docs/plans/2026-02-28-skipper-shipwright-implementation-plan.md +1182 -0
- package/docs/plans/2026-02-28-skipper-shipwright-integration-design.md +531 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-design.md +298 -0
- package/docs/plans/2026-03-01-ai-powered-skill-injection-plan.md +1109 -0
- package/docs/plans/2026-03-01-capabilities-cleanup-plan.md +658 -0
- package/docs/plans/2026-03-01-clean-architecture-plan.md +924 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-design.md +191 -0
- package/docs/plans/2026-03-01-compound-audit-cascade-plan.md +921 -0
- package/docs/plans/2026-03-01-deep-integration-plan.md +851 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-design.md +145 -0
- package/docs/plans/2026-03-01-pipeline-audit-trail-plan.md +770 -0
- package/docs/plans/2026-03-01-refined-depths-brand-design.md +382 -0
- package/docs/plans/2026-03-01-refined-depths-implementation.md +599 -0
- package/docs/plans/2026-03-01-skipper-kernel-integration-design.md +203 -0
- package/docs/plans/2026-03-01-unified-platform-design.md +272 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-design.md +189 -0
- package/docs/plans/2026-03-07-claude-code-feature-integration-plan.md +1165 -0
- package/docs/research/BACKLOG_QUICK_REFERENCE.md +352 -0
- package/docs/research/CUTTING_EDGE_RESEARCH_2026.md +546 -0
- package/docs/research/RESEARCH_INDEX.md +439 -0
- package/docs/research/RESEARCH_SOURCES.md +440 -0
- package/docs/research/RESEARCH_SUMMARY.txt +275 -0
- package/docs/superpowers/specs/2026-03-10-pipeline-quality-revolution-design.md +341 -0
- package/package.json +2 -2
- package/scripts/lib/adaptive-model.sh +427 -0
- package/scripts/lib/adaptive-timeout.sh +316 -0
- package/scripts/lib/audit-trail.sh +309 -0
- package/scripts/lib/auto-recovery.sh +471 -0
- package/scripts/lib/bandit-selector.sh +431 -0
- package/scripts/lib/bootstrap.sh +104 -2
- package/scripts/lib/causal-graph.sh +455 -0
- package/scripts/lib/compat.sh +126 -0
- package/scripts/lib/compound-audit.sh +337 -0
- package/scripts/lib/constitutional.sh +454 -0
- package/scripts/lib/context-budget.sh +359 -0
- package/scripts/lib/convergence.sh +594 -0
- package/scripts/lib/cost-optimizer.sh +634 -0
- package/scripts/lib/daemon-adaptive.sh +10 -0
- package/scripts/lib/daemon-dispatch.sh +106 -17
- package/scripts/lib/daemon-failure.sh +34 -4
- package/scripts/lib/daemon-patrol.sh +23 -2
- package/scripts/lib/daemon-poll-github.sh +361 -0
- package/scripts/lib/daemon-poll-health.sh +299 -0
- package/scripts/lib/daemon-poll.sh +27 -611
- package/scripts/lib/daemon-state.sh +112 -66
- package/scripts/lib/daemon-triage.sh +10 -0
- package/scripts/lib/dod-scorecard.sh +442 -0
- package/scripts/lib/error-actionability.sh +300 -0
- package/scripts/lib/formal-spec.sh +461 -0
- package/scripts/lib/helpers.sh +177 -4
- package/scripts/lib/intent-analysis.sh +409 -0
- package/scripts/lib/loop-convergence.sh +350 -0
- package/scripts/lib/loop-iteration.sh +682 -0
- package/scripts/lib/loop-progress.sh +48 -0
- package/scripts/lib/loop-restart.sh +185 -0
- package/scripts/lib/memory-effectiveness.sh +506 -0
- package/scripts/lib/mutation-executor.sh +352 -0
- package/scripts/lib/outcome-feedback.sh +521 -0
- package/scripts/lib/pipeline-cli.sh +336 -0
- package/scripts/lib/pipeline-commands.sh +1216 -0
- package/scripts/lib/pipeline-detection.sh +100 -2
- package/scripts/lib/pipeline-execution.sh +897 -0
- package/scripts/lib/pipeline-github.sh +28 -3
- package/scripts/lib/pipeline-intelligence-compound.sh +431 -0
- package/scripts/lib/pipeline-intelligence-scoring.sh +407 -0
- package/scripts/lib/pipeline-intelligence-skip.sh +181 -0
- package/scripts/lib/pipeline-intelligence.sh +100 -1136
- package/scripts/lib/pipeline-quality-bash-compat.sh +182 -0
- package/scripts/lib/pipeline-quality-checks.sh +17 -715
- package/scripts/lib/pipeline-quality-gates.sh +563 -0
- package/scripts/lib/pipeline-stages-build.sh +730 -0
- package/scripts/lib/pipeline-stages-delivery.sh +965 -0
- package/scripts/lib/pipeline-stages-intake.sh +1133 -0
- package/scripts/lib/pipeline-stages-monitor.sh +407 -0
- package/scripts/lib/pipeline-stages-review.sh +1022 -0
- package/scripts/lib/pipeline-stages.sh +59 -2929
- package/scripts/lib/pipeline-state.sh +36 -5
- package/scripts/lib/pipeline-util.sh +487 -0
- package/scripts/lib/policy-learner.sh +438 -0
- package/scripts/lib/process-reward.sh +493 -0
- package/scripts/lib/project-detect.sh +649 -0
- package/scripts/lib/quality-profile.sh +334 -0
- package/scripts/lib/recruit-commands.sh +885 -0
- package/scripts/lib/recruit-learning.sh +739 -0
- package/scripts/lib/recruit-roles.sh +648 -0
- package/scripts/lib/reward-aggregator.sh +458 -0
- package/scripts/lib/rl-optimizer.sh +362 -0
- package/scripts/lib/root-cause.sh +427 -0
- package/scripts/lib/scope-enforcement.sh +445 -0
- package/scripts/lib/session-restart.sh +493 -0
- package/scripts/lib/skill-memory.sh +300 -0
- package/scripts/lib/skill-registry.sh +775 -0
- package/scripts/lib/spec-driven.sh +476 -0
- package/scripts/lib/test-helpers.sh +18 -7
- package/scripts/lib/test-holdout.sh +429 -0
- package/scripts/lib/test-optimizer.sh +511 -0
- package/scripts/shipwright-file-suggest.sh +45 -0
- package/scripts/skills/adversarial-quality.md +61 -0
- package/scripts/skills/api-design.md +44 -0
- package/scripts/skills/architecture-design.md +50 -0
- package/scripts/skills/brainstorming.md +43 -0
- package/scripts/skills/data-pipeline.md +44 -0
- package/scripts/skills/deploy-safety.md +64 -0
- package/scripts/skills/documentation.md +38 -0
- package/scripts/skills/frontend-design.md +45 -0
- package/scripts/skills/generated/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/.gitkeep +0 -0
- package/scripts/skills/generated/_refinements/adversarial-quality.patch.md +3 -0
- package/scripts/skills/generated/_refinements/architecture-design.patch.md +3 -0
- package/scripts/skills/generated/_refinements/brainstorming.patch.md +3 -0
- package/scripts/skills/generated/cli-version-management.md +29 -0
- package/scripts/skills/generated/collection-system-validation.md +99 -0
- package/scripts/skills/generated/large-scale-c-refactoring-coordination.md +97 -0
- package/scripts/skills/generated/pattern-matching-similarity-scoring.md +195 -0
- package/scripts/skills/generated/test-parallelization-detection.md +65 -0
- package/scripts/skills/observability.md +79 -0
- package/scripts/skills/performance.md +48 -0
- package/scripts/skills/pr-quality.md +49 -0
- package/scripts/skills/product-thinking.md +43 -0
- package/scripts/skills/security-audit.md +49 -0
- package/scripts/skills/systematic-debugging.md +40 -0
- package/scripts/skills/testing-strategy.md +47 -0
- package/scripts/skills/two-stage-review.md +52 -0
- package/scripts/skills/validation-thoroughness.md +55 -0
- package/scripts/sw +9 -3
- package/scripts/sw-activity.sh +9 -2
- package/scripts/sw-adaptive.sh +2 -1
- package/scripts/sw-adversarial.sh +2 -1
- package/scripts/sw-architecture-enforcer.sh +3 -1
- package/scripts/sw-auth.sh +12 -2
- package/scripts/sw-autonomous.sh +5 -1
- package/scripts/sw-changelog.sh +4 -1
- package/scripts/sw-checkpoint.sh +2 -1
- package/scripts/sw-ci.sh +5 -1
- package/scripts/sw-cleanup.sh +4 -26
- package/scripts/sw-code-review.sh +10 -4
- package/scripts/sw-connect.sh +2 -1
- package/scripts/sw-context.sh +2 -1
- package/scripts/sw-cost.sh +48 -3
- package/scripts/sw-daemon.sh +66 -9
- package/scripts/sw-dashboard.sh +3 -1
- package/scripts/sw-db.sh +59 -16
- package/scripts/sw-decide.sh +8 -2
- package/scripts/sw-decompose.sh +360 -17
- package/scripts/sw-deps.sh +4 -1
- package/scripts/sw-developer-simulation.sh +4 -1
- package/scripts/sw-discovery.sh +325 -2
- package/scripts/sw-doc-fleet.sh +4 -1
- package/scripts/sw-docs-agent.sh +3 -1
- package/scripts/sw-docs.sh +2 -1
- package/scripts/sw-doctor.sh +453 -2
- package/scripts/sw-dora.sh +4 -1
- package/scripts/sw-durable.sh +4 -3
- package/scripts/sw-e2e-orchestrator.sh +17 -16
- package/scripts/sw-eventbus.sh +7 -1
- package/scripts/sw-evidence.sh +364 -12
- package/scripts/sw-feedback.sh +550 -9
- package/scripts/sw-fix.sh +20 -1
- package/scripts/sw-fleet-discover.sh +6 -2
- package/scripts/sw-fleet-viz.sh +4 -1
- package/scripts/sw-fleet.sh +5 -1
- package/scripts/sw-github-app.sh +16 -3
- package/scripts/sw-github-checks.sh +3 -2
- package/scripts/sw-github-deploy.sh +3 -2
- package/scripts/sw-github-graphql.sh +18 -7
- package/scripts/sw-guild.sh +5 -1
- package/scripts/sw-heartbeat.sh +5 -30
- package/scripts/sw-hello.sh +67 -0
- package/scripts/sw-hygiene.sh +6 -1
- package/scripts/sw-incident.sh +265 -1
- package/scripts/sw-init.sh +18 -2
- package/scripts/sw-instrument.sh +10 -2
- package/scripts/sw-intelligence.sh +42 -6
- package/scripts/sw-jira.sh +5 -1
- package/scripts/sw-launchd.sh +2 -1
- package/scripts/sw-linear.sh +4 -1
- package/scripts/sw-logs.sh +4 -1
- package/scripts/sw-loop.sh +432 -1128
- package/scripts/sw-memory.sh +356 -2
- package/scripts/sw-mission-control.sh +6 -1
- package/scripts/sw-model-router.sh +481 -26
- package/scripts/sw-otel.sh +13 -4
- package/scripts/sw-oversight.sh +14 -5
- package/scripts/sw-patrol-meta.sh +334 -0
- package/scripts/sw-pipeline-composer.sh +5 -1
- package/scripts/sw-pipeline-vitals.sh +2 -1
- package/scripts/sw-pipeline.sh +53 -2664
- package/scripts/sw-pm.sh +12 -5
- package/scripts/sw-pr-lifecycle.sh +2 -1
- package/scripts/sw-predictive.sh +7 -1
- package/scripts/sw-prep.sh +185 -2
- package/scripts/sw-ps.sh +5 -25
- package/scripts/sw-public-dashboard.sh +15 -3
- package/scripts/sw-quality.sh +2 -1
- package/scripts/sw-reaper.sh +8 -25
- package/scripts/sw-recruit.sh +156 -2303
- package/scripts/sw-regression.sh +19 -12
- package/scripts/sw-release-manager.sh +3 -1
- package/scripts/sw-release.sh +4 -1
- package/scripts/sw-remote.sh +3 -1
- package/scripts/sw-replay.sh +7 -1
- package/scripts/sw-retro.sh +158 -1
- package/scripts/sw-review-rerun.sh +3 -1
- package/scripts/sw-scale.sh +10 -3
- package/scripts/sw-security-audit.sh +6 -1
- package/scripts/sw-self-optimize.sh +6 -3
- package/scripts/sw-session.sh +9 -3
- package/scripts/sw-setup.sh +3 -1
- package/scripts/sw-stall-detector.sh +406 -0
- package/scripts/sw-standup.sh +15 -7
- package/scripts/sw-status.sh +3 -1
- package/scripts/sw-strategic.sh +4 -1
- package/scripts/sw-stream.sh +7 -1
- package/scripts/sw-swarm.sh +18 -6
- package/scripts/sw-team-stages.sh +13 -6
- package/scripts/sw-templates.sh +5 -29
- package/scripts/sw-testgen.sh +7 -1
- package/scripts/sw-tmux-pipeline.sh +4 -1
- package/scripts/sw-tmux-role-color.sh +2 -0
- package/scripts/sw-tmux-status.sh +1 -1
- package/scripts/sw-tmux.sh +3 -1
- package/scripts/sw-trace.sh +3 -1
- package/scripts/sw-tracker-github.sh +3 -0
- package/scripts/sw-tracker-jira.sh +3 -0
- package/scripts/sw-tracker-linear.sh +3 -0
- package/scripts/sw-tracker.sh +3 -1
- package/scripts/sw-triage.sh +2 -1
- package/scripts/sw-upgrade.sh +3 -1
- package/scripts/sw-ux.sh +5 -2
- package/scripts/sw-webhook.sh +3 -1
- package/scripts/sw-widgets.sh +3 -1
- package/scripts/sw-worktree.sh +15 -3
- package/scripts/test-skill-injection.sh +1233 -0
- package/templates/pipelines/autonomous.json +27 -3
- package/templates/pipelines/cost-aware.json +34 -8
- package/templates/pipelines/deployed.json +12 -0
- package/templates/pipelines/enterprise.json +12 -0
- package/templates/pipelines/fast.json +6 -0
- package/templates/pipelines/full.json +27 -3
- package/templates/pipelines/hotfix.json +6 -0
- package/templates/pipelines/standard.json +12 -0
- package/templates/pipelines/tdd.json +12 -0
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
You are a code review specialist for the Shipwright project. Your job is to review shell scripts, GitHub Actions workflows, and configuration files for correctness, security, and adherence to project conventions.
|
|
4
4
|
|
|
5
|
+
**Model Guidance**: Use Opus 4.6 for thorough architectural reviews. Set `maxTurns: 2` to prevent context bloat during iterative reviews. Use `worktree: true` for parallel code review runs.
|
|
6
|
+
|
|
5
7
|
## Review Checklist
|
|
6
8
|
|
|
7
9
|
### Bash 3.2 Compatibility (Blockers)
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
You are a DevOps and CI/CD specialist for the Shipwright project. You work on GitHub Actions workflows, deployment pipelines, infrastructure automation, and operational tooling.
|
|
4
4
|
|
|
5
|
+
**Model Guidance**: Use Opus 4.6 for complex infrastructure changes. Use `worktree: true` to isolate concurrent infrastructure updates. Set `maxTurns: 2` for exploratory work.
|
|
6
|
+
|
|
5
7
|
## GitHub Actions Workflows
|
|
6
8
|
|
|
7
9
|
Workflows live in `.github/workflows/` with the `shipwright-*.yml` naming prefix:
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
You are a specialized agent in the Shipwright documentation fleet. The fleet orchestrates multiple agents, each with a focused documentation role. Your specific role is assigned at spawn time.
|
|
4
4
|
|
|
5
|
+
**Model Guidance**: Use Sonnet 4.6 for documentation work. Use `background: true` for parallel doc fleet agents (audit, refactor, enhance). Set `maxTurns: 2` per role to focus on specialized tasks.
|
|
6
|
+
|
|
5
7
|
## Fleet Roles
|
|
6
8
|
|
|
7
9
|
### 1. Doc Architect (leader)
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
You are an autonomous agent running inside the Shipwright delivery pipeline's build stage. You were spawned by `shipwright loop`, which was called by `shipwright pipeline` during the build stage.
|
|
4
4
|
|
|
5
|
+
**Model Guidance**: Use Opus 4.6 for complex builds, Sonnet 4.6 for standard features, and Haiku for simple bug fixes. For background tasks (long-running test suites), set `background: true` and allow pre-approved tool permissions.
|
|
6
|
+
|
|
5
7
|
## Your Context
|
|
6
8
|
|
|
7
9
|
Your goal comes from the **enriched goal** assembled by the pipeline, which includes:
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
You are a shell script development specialist for the Shipwright project — an autonomous delivery platform built entirely in Bash (37+ scripts, 25,000+ lines).
|
|
4
4
|
|
|
5
|
+
**Model Guidance**: Use Sonnet 4.6 for script development. For long-running test harnesses, use `background: true` with pre-approved permissions.
|
|
6
|
+
|
|
5
7
|
## Bash 3.2 Compatibility (CRITICAL)
|
|
6
8
|
|
|
7
9
|
Shipwright must run on macOS default Bash 3.2. The following are **forbidden**:
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
You are a test development specialist for the Shipwright project. The project has 90+ test suites (see `package.json` scripts.test and the AUTO:test-suites table in `.claude/CLAUDE.md`), all written in Bash following a consistent harness pattern.
|
|
4
4
|
|
|
5
|
+
**Model Guidance**: Use Sonnet 4.6 for test development. Use `background: true` and `maxTurns: 3` for long test runs to prevent context bloat.
|
|
6
|
+
|
|
5
7
|
## Test Harness Conventions
|
|
6
8
|
|
|
7
9
|
### File Structure
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: Capture diagnostics when a Skipper agent crashes
|
|
3
|
+
# Trigger: Post-tool-use on Bash failures that look like agent crashes
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Read stdin for tool result context
|
|
8
|
+
INPUT="$(cat)"
|
|
9
|
+
|
|
10
|
+
# Check if this looks like an agent crash
|
|
11
|
+
if echo "$INPUT" | grep -qi "panic\|segfault\|killed\|oom\|fatal\|crash"; then
|
|
12
|
+
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
|
13
|
+
CRASH_DIR="${HOME}/.shipwright/crash-reports"
|
|
14
|
+
mkdir -p "$CRASH_DIR"
|
|
15
|
+
|
|
16
|
+
REPORT_FILE="${CRASH_DIR}/crash_${TIMESTAMP}.json"
|
|
17
|
+
|
|
18
|
+
# Capture diagnostics
|
|
19
|
+
cat > "$REPORT_FILE" << EOF
|
|
20
|
+
{
|
|
21
|
+
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
22
|
+
"working_directory": "$(pwd)",
|
|
23
|
+
"git_branch": "$(git branch --show-current 2>/dev/null || echo 'unknown')",
|
|
24
|
+
"git_commit": "$(git rev-parse HEAD 2>/dev/null || echo 'unknown')",
|
|
25
|
+
"error_context": $(echo "$INPUT" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()[:2000]))" 2>/dev/null || echo '"capture_failed"'),
|
|
26
|
+
"pipeline_state": "$(cat .claude/pipeline-state.md 2>/dev/null | head -20 | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null || echo '"none"')",
|
|
27
|
+
"recent_commits": "$(git log --oneline -5 2>/dev/null | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))" 2>/dev/null || echo '"none"')"
|
|
28
|
+
}
|
|
29
|
+
EOF
|
|
30
|
+
|
|
31
|
+
echo "Crash report saved to $REPORT_FILE" >&2
|
|
32
|
+
fi
|
|
@@ -19,8 +19,9 @@ if [[ "$tool_name" == "Bash" ]] && [[ "${exit_code:-0}" != "0" ]]; then
|
|
|
19
19
|
# Classify error type
|
|
20
20
|
error_type="unknown"
|
|
21
21
|
case "$error_snippet" in
|
|
22
|
-
*"
|
|
23
|
-
*"
|
|
22
|
+
*"syntax"*|*"parse error"*) error_type="syntax" ;;
|
|
23
|
+
*"unexpected token"*|*"unexpected end"*) error_type="syntax" ;;
|
|
24
|
+
*"test"*|*"FAIL"*|*"assert"*|*"expect"*) error_type="test" ;;
|
|
24
25
|
*"not found"*|*"No such"*|*"ENOENT"*) error_type="missing" ;;
|
|
25
26
|
*"permission"*|*"denied"*|*"EACCES"*) error_type="permission" ;;
|
|
26
27
|
*"timeout"*|*"timed out"*|*"ETIMEDOUT"*) error_type="timeout" ;;
|
|
@@ -1,14 +1,46 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Hook: PreToolUse —
|
|
2
|
+
# Hook: PreToolUse — Security checks and context injection
|
|
3
3
|
# Triggered before Write/Edit tools
|
|
4
4
|
|
|
5
5
|
# Read tool input from stdin (JSON)
|
|
6
6
|
input=$(cat)
|
|
7
7
|
|
|
8
|
-
# Extract
|
|
8
|
+
# Extract tool name and file path
|
|
9
|
+
tool_name=$(echo "$input" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
9
10
|
file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
11
|
+
new_string=$(echo "$input" | jq -r '.tool_input.new_string // empty' 2>/dev/null)
|
|
12
|
+
tool_input=$(echo "$input" | jq -r '.tool_input // empty' 2>/dev/null)
|
|
10
13
|
|
|
11
|
-
#
|
|
14
|
+
# Security check: Block git push --no-verify (bypasses pre-commit hooks)
|
|
15
|
+
if echo "$tool_input" | grep -qE 'git\s+push.*--no-verify'; then
|
|
16
|
+
echo '{"message":"Blocked: git push --no-verify bypasses safety checks. Remove --no-verify flag."}'
|
|
17
|
+
exit 2
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Security check: Detect secrets being written to non-secret files
|
|
21
|
+
if [[ "$tool_name" == "Edit" || "$tool_name" == "Write" ]]; then
|
|
22
|
+
# Sensitive files that should not be added to version control
|
|
23
|
+
if [[ ! "$file_path" =~ (\.env|\.secret|secret|credential|key|token|private) ]]; then
|
|
24
|
+
# Check for common secret patterns
|
|
25
|
+
secret_patterns="sk-ant-|ANTHROPIC_API_KEY|GITHUB_TOKEN|OPENAI_API_KEY|AWS_SECRET|DATABASE_URL|PRIVATE_KEY|api_key|BEGIN RSA PRIVATE KEY|BEGIN PRIVATE KEY"
|
|
26
|
+
|
|
27
|
+
if echo "$new_string" | grep -qE "$secret_patterns"; then
|
|
28
|
+
cat << "SECURITY_WARNING"
|
|
29
|
+
⚠️ SECURITY WARNING: Secret pattern detected in non-secret file
|
|
30
|
+
|
|
31
|
+
The content being written to this file contains a potential secret.
|
|
32
|
+
File: $file_path
|
|
33
|
+
|
|
34
|
+
Sensitive data should NEVER be committed to version control.
|
|
35
|
+
|
|
36
|
+
If this is intentional (e.g., example code), please review carefully.
|
|
37
|
+
SECURITY_WARNING
|
|
38
|
+
exit 2
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# Shell script context injection
|
|
12
44
|
if [[ "$file_path" == *.sh ]]; then
|
|
13
45
|
cat << 'REMINDER'
|
|
14
46
|
SHIPWRIGHT SHELL RULES:
|
package/README.md
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
<a href="https://github.com/sethdford/shipwright/actions/workflows/test.yml"><img src="https://github.com/sethdford/shipwright/actions/workflows/test.yml/badge.svg" alt="Tests"></a>
|
|
14
14
|
<a href="https://github.com/sethdford/shipwright/actions/workflows/shipwright-pipeline.yml"><img src="https://github.com/sethdford/shipwright/actions/workflows/shipwright-pipeline.yml/badge.svg" alt="Pipeline"></a>
|
|
15
15
|
<img src="https://img.shields.io/badge/tests-141_suites_passing-4ade80?style=flat-square" alt="141 suites">
|
|
16
|
-
<img src="https://img.shields.io/badge/version-3.
|
|
16
|
+
<img src="https://img.shields.io/badge/version-3.3.0-00d4ff?style=flat-square" alt="v3.3.0">
|
|
17
17
|
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="MIT License">
|
|
18
|
-
<img src="https://img.shields.io/badge/bash-3.2%2B-
|
|
18
|
+
<img src="https://img.shields.io/badge/bash-3.2%2B-555a66?style=flat-square" alt="Bash 3.2+">
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
21
|
---
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
- [Shipwright Builds Itself](#shipwright-builds-itself)
|
|
26
26
|
- [Code Factory Pattern](#code-factory-pattern)
|
|
27
|
-
- [What's New in v3.
|
|
27
|
+
- [What's New in v3.3.0](#whats-new-in-v330)
|
|
28
28
|
- [How It Works](#how-it-works)
|
|
29
29
|
- [Install](#install)
|
|
30
30
|
- [Quick Start](#quick-start)
|
|
@@ -109,7 +109,7 @@ shipwright incident gap sla
|
|
|
109
109
|
|
|
110
110
|
---
|
|
111
111
|
|
|
112
|
-
## What's New in v3.
|
|
112
|
+
## What's New in v3.3.0
|
|
113
113
|
|
|
114
114
|
**Code Factory pattern** — deterministic, risk-aware agent delivery with machine-verifiable evidence:
|
|
115
115
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: ConfigChange — notify daemon of config updates
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
input=$(cat)
|
|
6
|
+
|
|
7
|
+
# Log config change event
|
|
8
|
+
mkdir -p "$HOME/.shipwright" 2>/dev/null || true
|
|
9
|
+
echo "{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"config.changed\",\"detail\":$(echo "$input" | jq -c '.' 2>/dev/null || echo '{}')}" >> "$HOME/.shipwright/events.jsonl" 2>/dev/null || true
|
|
10
|
+
|
|
11
|
+
# Signal running daemon to reload config (if PID file exists)
|
|
12
|
+
pid_file="$HOME/.shipwright/daemon.pid"
|
|
13
|
+
if [[ -f "$pid_file" ]]; then
|
|
14
|
+
daemon_pid=$(cat "$pid_file" 2>/dev/null || true)
|
|
15
|
+
if [[ -n "$daemon_pid" ]] && kill -0 "$daemon_pid" 2>/dev/null; then
|
|
16
|
+
kill -USR1 "$daemon_pid" 2>/dev/null || true
|
|
17
|
+
fi
|
|
18
|
+
fi
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: InstructionsLoaded (matcher: "compact")
|
|
3
|
+
# After auto-compaction, log reload event for observability
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
mkdir -p "$HOME/.shipwright" 2>/dev/null || true
|
|
7
|
+
echo "{\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"type\":\"instructions.reloaded\",\"trigger\":\"compaction\"}" >> "$HOME/.shipwright/events.jsonl" 2>/dev/null || true
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: WorktreeCreate — auto-setup worktree for pipeline agents
|
|
3
|
+
# Copies essential config into new worktrees so agents inherit settings
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
# Read hook input from stdin (JSON with worktree details)
|
|
7
|
+
input=$(cat)
|
|
8
|
+
worktree_path=$(echo "$input" | jq -r '.worktree_path // empty' 2>/dev/null || true)
|
|
9
|
+
|
|
10
|
+
[[ -z "$worktree_path" ]] && exit 0
|
|
11
|
+
|
|
12
|
+
# Copy daemon config if it exists
|
|
13
|
+
src_root=$(git rev-parse --show-toplevel 2>/dev/null || true)
|
|
14
|
+
if [[ -n "$src_root" ]]; then
|
|
15
|
+
src_config="$src_root/.claude/daemon-config.json"
|
|
16
|
+
if [[ -f "$src_config" ]]; then
|
|
17
|
+
mkdir -p "$worktree_path/.claude" 2>/dev/null || true
|
|
18
|
+
cp "$src_config" "$worktree_path/.claude/daemon-config.json" 2>/dev/null || true
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Copy pipeline artifacts directory structure
|
|
22
|
+
if [[ -d "$src_root/.claude/pipeline-artifacts" ]]; then
|
|
23
|
+
mkdir -p "$worktree_path/.claude/pipeline-artifacts" 2>/dev/null || true
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Hook: WorktreeRemove — clean up state for removed worktree agents
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
input=$(cat)
|
|
6
|
+
worktree_path=$(echo "$input" | jq -r '.worktree_path // empty' 2>/dev/null || true)
|
|
7
|
+
|
|
8
|
+
[[ -z "$worktree_path" ]] && exit 0
|
|
9
|
+
|
|
10
|
+
# Clean up heartbeat files associated with this worktree
|
|
11
|
+
heartbeat_dir="$HOME/.shipwright/heartbeats"
|
|
12
|
+
if [[ -d "$heartbeat_dir" ]]; then
|
|
13
|
+
for hb in "$heartbeat_dir"/*.json; do
|
|
14
|
+
[[ -f "$hb" ]] || continue
|
|
15
|
+
hb_path=$(jq -r '.worktree // empty' "$hb" 2>/dev/null || true)
|
|
16
|
+
if [[ "$hb_path" == "$worktree_path" ]]; then
|
|
17
|
+
rm -f "$hb"
|
|
18
|
+
fi
|
|
19
|
+
done
|
|
20
|
+
fi
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0",
|
|
3
|
+
"description": "Constitutional principles for autonomous code self-critique",
|
|
4
|
+
"principles": {
|
|
5
|
+
"security": [
|
|
6
|
+
{
|
|
7
|
+
"id": "SEC-001",
|
|
8
|
+
"rule": "No hardcoded secrets, API keys, or passwords",
|
|
9
|
+
"severity": "critical",
|
|
10
|
+
"check": "grep -nE '(password|api_key|secret_key|api_secret|auth_token)\\s*=\\s*[\"'\"'\"']' {file}"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"id": "SEC-002",
|
|
14
|
+
"rule": "All user inputs must be validated before use",
|
|
15
|
+
"severity": "critical"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"id": "SEC-003",
|
|
19
|
+
"rule": "No eval() or exec() with dynamic content",
|
|
20
|
+
"severity": "critical",
|
|
21
|
+
"check": "grep -nE '\\beval\\b.*\\$|\\bexec\\b.*\\$' {file}"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"id": "SEC-004",
|
|
25
|
+
"rule": "No SQL string concatenation — use parameterized queries",
|
|
26
|
+
"severity": "high"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"id": "SEC-005",
|
|
30
|
+
"rule": "No shell injection via unquoted variables in commands",
|
|
31
|
+
"severity": "critical",
|
|
32
|
+
"check": "grep -nE '\\$\\{?[A-Za-z_]+\\}?[^\"'\"'\"']' {file}"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"error_handling": [
|
|
36
|
+
{
|
|
37
|
+
"id": "ERR-001",
|
|
38
|
+
"rule": "No empty catch blocks — all errors must be handled or re-thrown",
|
|
39
|
+
"severity": "high",
|
|
40
|
+
"check": "grep -nE 'catch\\s*\\([^)]*\\)\\s*\\{\\s*\\}' {file}"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "ERR-002",
|
|
44
|
+
"rule": "Error messages must be descriptive — no generic 'Error occurred'",
|
|
45
|
+
"severity": "medium",
|
|
46
|
+
"check": "grep -niE '(error occurred|something went wrong|an error happened)' {file}"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"id": "ERR-003",
|
|
50
|
+
"rule": "Return values from commands must be checked",
|
|
51
|
+
"severity": "high"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "ERR-004",
|
|
55
|
+
"rule": "No silent failures — failed operations must log or propagate errors",
|
|
56
|
+
"severity": "medium"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"quality": [
|
|
60
|
+
{
|
|
61
|
+
"id": "QUA-001",
|
|
62
|
+
"rule": "Functions should be under 100 lines",
|
|
63
|
+
"severity": "medium"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "QUA-002",
|
|
67
|
+
"rule": "No TODO/FIXME/HACK comments in production code",
|
|
68
|
+
"severity": "low",
|
|
69
|
+
"check": "grep -nE '(TODO|FIXME|HACK|XXX)' {file}"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "QUA-003",
|
|
73
|
+
"rule": "No magic numbers — use named constants",
|
|
74
|
+
"severity": "low"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "QUA-004",
|
|
78
|
+
"rule": "No duplicate code blocks over 10 lines",
|
|
79
|
+
"severity": "medium"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "QUA-005",
|
|
83
|
+
"rule": "No console.log or print statements left in production code",
|
|
84
|
+
"severity": "low",
|
|
85
|
+
"check": "grep -nE '\\bconsole\\.log\\b|\\bprint\\(' {file}"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"testing": [
|
|
89
|
+
{
|
|
90
|
+
"id": "TST-001",
|
|
91
|
+
"rule": "New functions must have corresponding tests",
|
|
92
|
+
"severity": "high"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "TST-002",
|
|
96
|
+
"rule": "Tests must cover error and edge cases, not just happy path",
|
|
97
|
+
"severity": "medium"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "TST-003",
|
|
101
|
+
"rule": "No test-only code in production files",
|
|
102
|
+
"severity": "medium",
|
|
103
|
+
"check": "grep -nE '(if.*TEST|ifdef.*TEST|IS_TEST)' {file}"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "TST-004",
|
|
107
|
+
"rule": "Test assertions must be specific — no assertTrue(result) without message",
|
|
108
|
+
"severity": "low"
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"performance": [
|
|
112
|
+
{
|
|
113
|
+
"id": "PRF-001",
|
|
114
|
+
"rule": "All database queries must have .limit() or LIMIT clause",
|
|
115
|
+
"severity": "high"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "PRF-002",
|
|
119
|
+
"rule": "No unbounded loops over external data",
|
|
120
|
+
"severity": "medium"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "PRF-003",
|
|
124
|
+
"rule": "Avoid synchronous file I/O in hot paths",
|
|
125
|
+
"severity": "medium",
|
|
126
|
+
"check": "grep -nE 'readFileSync|writeFileSync' {file}"
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { join, extname } from "path";
|
|
2
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync, renameSync } from "fs";
|
|
3
|
+
import type { Session, AuthMode } from "../types/index.js";
|
|
4
|
+
import { SESSION_TTL_MS } from "./constants.js";
|
|
5
|
+
|
|
6
|
+
// Auth Config
|
|
7
|
+
const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID || "";
|
|
8
|
+
const GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET || "";
|
|
9
|
+
const GITHUB_PAT = process.env.GITHUB_PAT || "";
|
|
10
|
+
const DASHBOARD_REPO = process.env.DASHBOARD_REPO || "";
|
|
11
|
+
const SESSION_SECRET = process.env.SESSION_SECRET || crypto.randomUUID();
|
|
12
|
+
|
|
13
|
+
const HOME = process.env.HOME || "";
|
|
14
|
+
const SESSIONS_FILE = join(HOME, ".shipwright", "sessions.json");
|
|
15
|
+
|
|
16
|
+
export const sessions = new Map<string, Session>();
|
|
17
|
+
|
|
18
|
+
export function createSession(data: Omit<Session, "expiresAt">): string {
|
|
19
|
+
const sessionId = crypto.randomUUID();
|
|
20
|
+
sessions.set(sessionId, {
|
|
21
|
+
...data,
|
|
22
|
+
expiresAt: Date.now() + SESSION_TTL_MS,
|
|
23
|
+
});
|
|
24
|
+
saveSessions();
|
|
25
|
+
return sessionId;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getSession(req: Request): Session | null {
|
|
29
|
+
const cookie = req.headers.get("cookie");
|
|
30
|
+
if (!cookie) return null;
|
|
31
|
+
|
|
32
|
+
const match = cookie.match(/fleet_session=([^;]+)/);
|
|
33
|
+
if (!match) return null;
|
|
34
|
+
|
|
35
|
+
const sessionId = match[1];
|
|
36
|
+
const session = sessions.get(sessionId);
|
|
37
|
+
if (!session) return null;
|
|
38
|
+
|
|
39
|
+
if (Date.now() > session.expiresAt) {
|
|
40
|
+
sessions.delete(sessionId);
|
|
41
|
+
saveSessions();
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return session;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function getSessionFromCookie(cookie: string | null): Session | null {
|
|
49
|
+
if (!cookie) return null;
|
|
50
|
+
const match = cookie.match(/fleet_session=([^;]+)/);
|
|
51
|
+
if (!match) return null;
|
|
52
|
+
const session = sessions.get(match[1]);
|
|
53
|
+
if (!session || Date.now() > session.expiresAt) return null;
|
|
54
|
+
return session;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function sessionCookie(sessionId: string): string {
|
|
58
|
+
return `fleet_session=${sessionId}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${Math.floor(SESSION_TTL_MS / 1000)}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function isLocalConnection(req: Request): boolean {
|
|
62
|
+
const host = req.headers.get("host") || "";
|
|
63
|
+
return (
|
|
64
|
+
host.startsWith("localhost:") ||
|
|
65
|
+
host.startsWith("127.0.0.1:") ||
|
|
66
|
+
host.startsWith("[::1]:")
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function clearSessionCookie(): string {
|
|
71
|
+
return "fleet_session=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function loadSessions(): void {
|
|
75
|
+
try {
|
|
76
|
+
if (existsSync(SESSIONS_FILE)) {
|
|
77
|
+
const data = JSON.parse(readFileSync(SESSIONS_FILE, "utf-8"));
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
if (data && typeof data === "object") {
|
|
80
|
+
for (const [id, sess] of Object.entries(data)) {
|
|
81
|
+
const s = sess as Session;
|
|
82
|
+
if (s.expiresAt > now) {
|
|
83
|
+
sessions.set(id, s);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch {
|
|
89
|
+
/* start fresh */
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function saveSessions(): void {
|
|
94
|
+
const dir = join(HOME, ".shipwright");
|
|
95
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
96
|
+
const obj: Record<string, Session> = {};
|
|
97
|
+
for (const [id, sess] of sessions) {
|
|
98
|
+
obj[id] = sess;
|
|
99
|
+
}
|
|
100
|
+
const tmp = SESSIONS_FILE + ".tmp";
|
|
101
|
+
writeFileSync(tmp, JSON.stringify(obj, null, 2));
|
|
102
|
+
renameSync(tmp, SESSIONS_FILE);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function getAuthMode(): AuthMode {
|
|
106
|
+
if (GITHUB_CLIENT_ID && GITHUB_CLIENT_SECRET && DASHBOARD_REPO)
|
|
107
|
+
return "oauth";
|
|
108
|
+
if (GITHUB_PAT && DASHBOARD_REPO) return "pat";
|
|
109
|
+
return "none";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function isAuthEnabled(): boolean {
|
|
113
|
+
return getAuthMode() !== "none";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function isPublicRoute(pathname: string): boolean {
|
|
117
|
+
return (
|
|
118
|
+
pathname === "/login" ||
|
|
119
|
+
pathname.startsWith("/auth/") ||
|
|
120
|
+
pathname === "/api/health" ||
|
|
121
|
+
pathname === "/api/ws-status" ||
|
|
122
|
+
pathname.startsWith("/api/join/") ||
|
|
123
|
+
pathname.startsWith("/api/connect/") ||
|
|
124
|
+
pathname === "/api/team" ||
|
|
125
|
+
pathname === "/api/team/activity" ||
|
|
126
|
+
pathname === "/api/team/invite" ||
|
|
127
|
+
pathname.startsWith("/api/team/invite/") ||
|
|
128
|
+
pathname === "/api/claim" ||
|
|
129
|
+
pathname === "/api/claim/release" ||
|
|
130
|
+
pathname === "/api/webhook/ci"
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export { SESSION_SECRET, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_PAT, DASHBOARD_REPO };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Shared constants and configuration
|
|
2
|
+
export const CORS_HEADERS = {
|
|
3
|
+
"Access-Control-Allow-Origin": "*",
|
|
4
|
+
"Access-Control-Allow-Methods": "GET, POST, PATCH, DELETE, OPTIONS",
|
|
5
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const WS_PUSH_INTERVAL_MS = 2000;
|
|
9
|
+
export const MAX_WS_CLIENTS = 50;
|
|
10
|
+
export const WS_CONNECTION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
11
|
+
|
|
12
|
+
export const SESSION_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
13
|
+
export const ALLOWED_PERMISSIONS = ["admin", "write"];
|
|
14
|
+
|
|
15
|
+
// ANSI color codes
|
|
16
|
+
export const CYAN = "\x1b[38;2;0;212;255m";
|
|
17
|
+
export const GREEN = "\x1b[38;2;74;222;128m";
|
|
18
|
+
export const BOLD = "\x1b[1m";
|
|
19
|
+
export const DIM = "\x1b[2m";
|
|
20
|
+
export const ULINE = "\x1b[4m";
|
|
21
|
+
export const RESET = "\x1b[0m";
|
|
@@ -4,12 +4,6 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Fleet Command — Shipwright</title>
|
|
7
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
-
<link
|
|
10
|
-
href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500;700&family=Plus+Jakarta+Sans:wght@300;400;500;600;700&display=swap"
|
|
11
|
-
rel="stylesheet"
|
|
12
|
-
/>
|
|
13
7
|
<link rel="stylesheet" href="styles.css" />
|
|
14
8
|
<link
|
|
15
9
|
rel="icon"
|
|
@@ -113,6 +107,7 @@
|
|
|
113
107
|
<button class="tab-btn" data-tab="fleet-map">Map</button>
|
|
114
108
|
<button class="tab-btn" data-tab="pipeline-theater">Theater</button>
|
|
115
109
|
<button class="tab-btn" data-tab="agent-cockpit">Cockpit</button>
|
|
110
|
+
<button class="tab-btn" data-tab="shipyard">Shipyard</button>
|
|
116
111
|
<div class="tab-indicator" id="tab-indicator"></div>
|
|
117
112
|
</div>
|
|
118
113
|
</nav>
|
|
@@ -1032,6 +1027,7 @@
|
|
|
1032
1027
|
<div class="tab-panel" id="panel-fleet-map"></div>
|
|
1033
1028
|
<div class="tab-panel" id="panel-pipeline-theater"></div>
|
|
1034
1029
|
<div class="tab-panel" id="panel-agent-cockpit"></div>
|
|
1030
|
+
<div class="tab-panel" id="panel-shipyard"></div>
|
|
1035
1031
|
|
|
1036
1032
|
<script src="dist/main.js"></script>
|
|
1037
1033
|
</body>
|