@walwal-harness/cli 6.1.6 → 7.1.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/HR-Resource/academic-academic-anthropologist/SKILL.md +142 -0
- package/HR-Resource/academic-academic-geographer/SKILL.md +144 -0
- package/HR-Resource/academic-academic-historian/SKILL.md +140 -0
- package/HR-Resource/academic-academic-narratologist/SKILL.md +135 -0
- package/HR-Resource/academic-academic-psychologist/SKILL.md +135 -0
- package/HR-Resource/brick-office/SKILL.md +20 -0
- package/HR-Resource/cdo/SKILL.md +33 -0
- package/HR-Resource/ceo/SKILL.md +36 -0
- package/HR-Resource/coo/SKILL.md +36 -0
- package/HR-Resource/cqo/SKILL.md +33 -0
- package/HR-Resource/cto/SKILL.md +36 -0
- package/HR-Resource/design-design-brand-guardian/SKILL.md +339 -0
- package/HR-Resource/design-design-image-prompt-engineer/SKILL.md +253 -0
- package/HR-Resource/design-design-inclusive-visuals-specialist/SKILL.md +88 -0
- package/HR-Resource/design-design-ui-designer/SKILL.md +400 -0
- package/HR-Resource/design-design-ux-architect/SKILL.md +486 -0
- package/HR-Resource/design-design-ux-researcher/SKILL.md +346 -0
- package/HR-Resource/design-design-visual-storyteller/SKILL.md +166 -0
- package/HR-Resource/design-design-whimsy-injector/SKILL.md +455 -0
- package/HR-Resource/engineering-engineering-ai-data-remediation-engineer/SKILL.md +227 -0
- package/HR-Resource/engineering-engineering-ai-engineer/SKILL.md +163 -0
- package/HR-Resource/engineering-engineering-autonomous-optimization-architect/SKILL.md +124 -0
- package/HR-Resource/engineering-engineering-backend-architect/SKILL.md +252 -0
- package/HR-Resource/engineering-engineering-cms-developer/SKILL.md +553 -0
- package/HR-Resource/engineering-engineering-code-reviewer/SKILL.md +93 -0
- package/HR-Resource/engineering-engineering-codebase-onboarding-engineer/SKILL.md +190 -0
- package/HR-Resource/engineering-engineering-data-engineer/SKILL.md +323 -0
- package/HR-Resource/engineering-engineering-database-optimizer/SKILL.md +193 -0
- package/HR-Resource/engineering-engineering-devops-automator/SKILL.md +393 -0
- package/HR-Resource/engineering-engineering-email-intelligence-engineer/SKILL.md +370 -0
- package/HR-Resource/engineering-engineering-embedded-firmware-engineer/SKILL.md +190 -0
- package/HR-Resource/engineering-engineering-feishu-integration-developer/SKILL.md +615 -0
- package/HR-Resource/engineering-engineering-filament-optimization-specialist/SKILL.md +300 -0
- package/HR-Resource/engineering-engineering-frontend-developer/SKILL.md +242 -0
- package/HR-Resource/engineering-engineering-git-workflow-master/SKILL.md +101 -0
- package/HR-Resource/engineering-engineering-incident-response-commander/SKILL.md +461 -0
- package/HR-Resource/engineering-engineering-minimal-change-engineer/SKILL.md +224 -0
- package/HR-Resource/engineering-engineering-mobile-app-builder/SKILL.md +510 -0
- package/HR-Resource/engineering-engineering-rapid-prototyper/SKILL.md +479 -0
- package/HR-Resource/engineering-engineering-security-engineer/SKILL.md +321 -0
- package/HR-Resource/engineering-engineering-senior-developer/SKILL.md +193 -0
- package/HR-Resource/engineering-engineering-software-architect/SKILL.md +98 -0
- package/HR-Resource/engineering-engineering-solidity-smart-contract-engineer/SKILL.md +539 -0
- package/HR-Resource/engineering-engineering-sre/SKILL.md +107 -0
- package/HR-Resource/engineering-engineering-technical-writer/SKILL.md +410 -0
- package/HR-Resource/engineering-engineering-threat-detection-engineer/SKILL.md +551 -0
- package/HR-Resource/engineering-engineering-voice-ai-integration-engineer/SKILL.md +578 -0
- package/HR-Resource/engineering-engineering-wechat-mini-program-developer/SKILL.md +367 -0
- package/HR-Resource/finance-finance-bookkeeper-controller/SKILL.md +277 -0
- package/HR-Resource/finance-finance-financial-analyst/SKILL.md +251 -0
- package/HR-Resource/finance-finance-fpa-analyst/SKILL.md +280 -0
- package/HR-Resource/finance-finance-investment-researcher/SKILL.md +289 -0
- package/HR-Resource/finance-finance-tax-strategist/SKILL.md +256 -0
- package/HR-Resource/game-development-blender-blender-addon-engineer/SKILL.md +251 -0
- package/HR-Resource/game-development-game-audio-engineer/SKILL.md +281 -0
- package/HR-Resource/game-development-game-designer/SKILL.md +184 -0
- package/HR-Resource/game-development-godot-godot-gameplay-scripter/SKILL.md +351 -0
- package/HR-Resource/game-development-godot-godot-multiplayer-engineer/SKILL.md +314 -0
- package/HR-Resource/game-development-godot-godot-shader-developer/SKILL.md +283 -0
- package/HR-Resource/game-development-level-designer/SKILL.md +225 -0
- package/HR-Resource/game-development-narrative-designer/SKILL.md +260 -0
- package/HR-Resource/game-development-roblox-studio-roblox-avatar-creator/SKILL.md +314 -0
- package/HR-Resource/game-development-roblox-studio-roblox-experience-designer/SKILL.md +322 -0
- package/HR-Resource/game-development-roblox-studio-roblox-systems-scripter/SKILL.md +342 -0
- package/HR-Resource/game-development-technical-artist/SKILL.md +246 -0
- package/HR-Resource/game-development-unity-unity-architect/SKILL.md +288 -0
- package/HR-Resource/game-development-unity-unity-editor-tool-developer/SKILL.md +327 -0
- package/HR-Resource/game-development-unity-unity-multiplayer-engineer/SKILL.md +338 -0
- package/HR-Resource/game-development-unity-unity-shader-graph-artist/SKILL.md +286 -0
- package/HR-Resource/game-development-unreal-engine-unreal-multiplayer-architect/SKILL.md +330 -0
- package/HR-Resource/game-development-unreal-engine-unreal-systems-engineer/SKILL.md +327 -0
- package/HR-Resource/game-development-unreal-engine-unreal-technical-artist/SKILL.md +273 -0
- package/HR-Resource/game-development-unreal-engine-unreal-world-builder/SKILL.md +290 -0
- package/HR-Resource/hiring/SKILL.md +28 -0
- package/HR-Resource/index.json +747 -0
- package/HR-Resource/integrations-mcp-memory-backend-architect-with-memory/SKILL.md +264 -0
- package/HR-Resource/marketing-marketing-agentic-search-optimizer/SKILL.md +328 -0
- package/HR-Resource/marketing-marketing-ai-citation-strategist/SKILL.md +187 -0
- package/HR-Resource/marketing-marketing-app-store-optimizer/SKILL.md +338 -0
- package/HR-Resource/marketing-marketing-baidu-seo-specialist/SKILL.md +243 -0
- package/HR-Resource/marketing-marketing-bilibili-content-strategist/SKILL.md +216 -0
- package/HR-Resource/marketing-marketing-book-co-author/SKILL.md +127 -0
- package/HR-Resource/marketing-marketing-carousel-growth-engine/SKILL.md +216 -0
- package/HR-Resource/marketing-marketing-china-ecommerce-operator/SKILL.md +300 -0
- package/HR-Resource/marketing-marketing-china-market-localization-strategist/SKILL.md +300 -0
- package/HR-Resource/marketing-marketing-content-creator/SKILL.md +71 -0
- package/HR-Resource/marketing-marketing-cross-border-ecommerce/SKILL.md +276 -0
- package/HR-Resource/marketing-marketing-douyin-strategist/SKILL.md +166 -0
- package/HR-Resource/marketing-marketing-growth-hacker/SKILL.md +71 -0
- package/HR-Resource/marketing-marketing-instagram-curator/SKILL.md +130 -0
- package/HR-Resource/marketing-marketing-kuaishou-strategist/SKILL.md +240 -0
- package/HR-Resource/marketing-marketing-linkedin-content-creator/SKILL.md +230 -0
- package/HR-Resource/marketing-marketing-livestream-commerce-coach/SKILL.md +322 -0
- package/HR-Resource/marketing-marketing-podcast-strategist/SKILL.md +294 -0
- package/HR-Resource/marketing-marketing-private-domain-operator/SKILL.md +325 -0
- package/HR-Resource/marketing-marketing-reddit-community-builder/SKILL.md +140 -0
- package/HR-Resource/marketing-marketing-seo-specialist/SKILL.md +338 -0
- package/HR-Resource/marketing-marketing-short-video-editing-coach/SKILL.md +429 -0
- package/HR-Resource/marketing-marketing-social-media-strategist/SKILL.md +142 -0
- package/HR-Resource/marketing-marketing-tiktok-strategist/SKILL.md +142 -0
- package/HR-Resource/marketing-marketing-twitter-engager/SKILL.md +143 -0
- package/HR-Resource/marketing-marketing-video-optimization-specialist/SKILL.md +136 -0
- package/HR-Resource/marketing-marketing-wechat-official-account/SKILL.md +162 -0
- package/HR-Resource/marketing-marketing-weibo-strategist/SKILL.md +257 -0
- package/HR-Resource/marketing-marketing-xiaohongshu-specialist/SKILL.md +155 -0
- package/HR-Resource/marketing-marketing-zhihu-strategist/SKILL.md +179 -0
- package/HR-Resource/ops/SKILL.md +46 -0
- package/HR-Resource/paid-media-paid-media-auditor/SKILL.md +88 -0
- package/HR-Resource/paid-media-paid-media-creative-strategist/SKILL.md +88 -0
- package/HR-Resource/paid-media-paid-media-paid-social-strategist/SKILL.md +88 -0
- package/HR-Resource/paid-media-paid-media-ppc-strategist/SKILL.md +88 -0
- package/HR-Resource/paid-media-paid-media-programmatic-buyer/SKILL.md +88 -0
- package/HR-Resource/paid-media-paid-media-search-query-analyst/SKILL.md +88 -0
- package/HR-Resource/paid-media-paid-media-tracking-specialist/SKILL.md +88 -0
- package/HR-Resource/product-product-behavioral-nudge-engine/SKILL.md +97 -0
- package/HR-Resource/product-product-feedback-synthesizer/SKILL.md +136 -0
- package/HR-Resource/product-product-manager/SKILL.md +486 -0
- package/HR-Resource/product-product-sprint-prioritizer/SKILL.md +171 -0
- package/HR-Resource/product-product-trend-researcher/SKILL.md +176 -0
- package/HR-Resource/project-management-project-management-experiment-tracker/SKILL.md +215 -0
- package/HR-Resource/project-management-project-management-jira-workflow-steward/SKILL.md +247 -0
- package/HR-Resource/project-management-project-management-project-shepherd/SKILL.md +211 -0
- package/HR-Resource/project-management-project-management-studio-operations/SKILL.md +217 -0
- package/HR-Resource/project-management-project-management-studio-producer/SKILL.md +220 -0
- package/HR-Resource/project-management-project-manager-senior/SKILL.md +152 -0
- package/HR-Resource/resource-manager/SKILL.md +23 -0
- package/HR-Resource/sales-sales-account-strategist/SKILL.md +244 -0
- package/HR-Resource/sales-sales-coach/SKILL.md +288 -0
- package/HR-Resource/sales-sales-deal-strategist/SKILL.md +197 -0
- package/HR-Resource/sales-sales-discovery-coach/SKILL.md +242 -0
- package/HR-Resource/sales-sales-engineer/SKILL.md +199 -0
- package/HR-Resource/sales-sales-outbound-strategist/SKILL.md +218 -0
- package/HR-Resource/sales-sales-pipeline-analyst/SKILL.md +284 -0
- package/HR-Resource/sales-sales-proposal-strategist/SKILL.md +234 -0
- package/HR-Resource/spatial-computing-macos-spatial-metal-engineer/SKILL.md +354 -0
- package/HR-Resource/spatial-computing-terminal-integration-specialist/SKILL.md +87 -0
- package/HR-Resource/spatial-computing-visionos-spatial-engineer/SKILL.md +71 -0
- package/HR-Resource/spatial-computing-xr-cockpit-interaction-specialist/SKILL.md +49 -0
- package/HR-Resource/spatial-computing-xr-immersive-developer/SKILL.md +49 -0
- package/HR-Resource/spatial-computing-xr-interface-architect/SKILL.md +49 -0
- package/HR-Resource/specialized-accounts-payable-agent/SKILL.md +202 -0
- package/HR-Resource/specialized-agentic-identity-trust/SKILL.md +404 -0
- package/HR-Resource/specialized-agents-orchestrator/SKILL.md +384 -0
- package/HR-Resource/specialized-automation-governance-architect/SKILL.md +233 -0
- package/HR-Resource/specialized-blockchain-security-auditor/SKILL.md +480 -0
- package/HR-Resource/specialized-compliance-auditor/SKILL.md +175 -0
- package/HR-Resource/specialized-corporate-training-designer/SKILL.md +209 -0
- package/HR-Resource/specialized-customer-service/SKILL.md +415 -0
- package/HR-Resource/specialized-data-consolidation-agent/SKILL.md +77 -0
- package/HR-Resource/specialized-government-digital-presales-consultant/SKILL.md +380 -0
- package/HR-Resource/specialized-healthcare-customer-service/SKILL.md +406 -0
- package/HR-Resource/specialized-healthcare-marketing-compliance/SKILL.md +412 -0
- package/HR-Resource/specialized-hospitality-guest-services/SKILL.md +620 -0
- package/HR-Resource/specialized-hr-onboarding/SKILL.md +468 -0
- package/HR-Resource/specialized-identity-graph-operator/SKILL.md +277 -0
- package/HR-Resource/specialized-language-translator/SKILL.md +281 -0
- package/HR-Resource/specialized-legal-billing-time-tracking/SKILL.md +586 -0
- package/HR-Resource/specialized-legal-client-intake/SKILL.md +509 -0
- package/HR-Resource/specialized-legal-document-review/SKILL.md +471 -0
- package/HR-Resource/specialized-loan-officer-assistant/SKILL.md +572 -0
- package/HR-Resource/specialized-lsp-index-engineer/SKILL.md +331 -0
- package/HR-Resource/specialized-real-estate-buyer-seller/SKILL.md +613 -0
- package/HR-Resource/specialized-recruitment-specialist/SKILL.md +526 -0
- package/HR-Resource/specialized-report-distribution-agent/SKILL.md +82 -0
- package/HR-Resource/specialized-retail-customer-returns/SKILL.md +583 -0
- package/HR-Resource/specialized-sales-data-extraction-agent/SKILL.md +84 -0
- package/HR-Resource/specialized-sales-outreach/SKILL.md +442 -0
- package/HR-Resource/specialized-specialized-chief-of-staff/SKILL.md +296 -0
- package/HR-Resource/specialized-specialized-civil-engineer/SKILL.md +373 -0
- package/HR-Resource/specialized-specialized-cultural-intelligence-strategist/SKILL.md +105 -0
- package/HR-Resource/specialized-specialized-developer-advocate/SKILL.md +334 -0
- package/HR-Resource/specialized-specialized-document-generator/SKILL.md +72 -0
- package/HR-Resource/specialized-specialized-french-consulting-market/SKILL.md +209 -0
- package/HR-Resource/specialized-specialized-korean-business-navigator/SKILL.md +233 -0
- package/HR-Resource/specialized-specialized-mcp-builder/SKILL.md +265 -0
- package/HR-Resource/specialized-specialized-model-qa/SKILL.md +505 -0
- package/HR-Resource/specialized-specialized-salesforce-architect/SKILL.md +197 -0
- package/HR-Resource/specialized-specialized-workflow-architect/SKILL.md +614 -0
- package/HR-Resource/specialized-study-abroad-advisor/SKILL.md +299 -0
- package/HR-Resource/specialized-supply-chain-strategist/SKILL.md +599 -0
- package/HR-Resource/specialized-zk-steward/SKILL.md +228 -0
- package/HR-Resource/support-support-analytics-reporter/SKILL.md +382 -0
- package/HR-Resource/support-support-executive-summary-generator/SKILL.md +229 -0
- package/HR-Resource/support-support-finance-tracker/SKILL.md +459 -0
- package/HR-Resource/support-support-infrastructure-maintainer/SKILL.md +635 -0
- package/HR-Resource/support-support-legal-compliance-checker/SKILL.md +605 -0
- package/HR-Resource/support-support-support-responder/SKILL.md +602 -0
- package/HR-Resource/testing-testing-accessibility-auditor/SKILL.md +333 -0
- package/HR-Resource/testing-testing-api-tester/SKILL.md +323 -0
- package/HR-Resource/testing-testing-evidence-collector/SKILL.md +227 -0
- package/HR-Resource/testing-testing-performance-benchmarker/SKILL.md +285 -0
- package/HR-Resource/testing-testing-reality-checker/SKILL.md +253 -0
- package/HR-Resource/testing-testing-test-results-analyzer/SKILL.md +322 -0
- package/HR-Resource/testing-testing-tool-evaluator/SKILL.md +411 -0
- package/HR-Resource/testing-testing-workflow-optimizer/SKILL.md +467 -0
- package/assets/templates/config.json +36 -2
- package/bin/init.js +207 -109
- package/commands/goal.md +25 -0
- package/commands/hot-fix.md +25 -0
- package/commands/play-harness.md +22 -0
- package/commands/release-harness.md +22 -0
- package/commands/stop-harness.md +21 -0
- package/conventions/README.md +14 -88
- package/conventions/brick-office.md +5 -0
- package/conventions/cdo.md +6 -0
- package/conventions/ceo.md +9 -0
- package/conventions/coo.md +6 -0
- package/conventions/cqo.md +6 -23
- package/conventions/cto.md +5 -23
- package/conventions/hiring.md +7 -0
- package/conventions/ops.md +9 -0
- package/conventions/resource-manager.md +6 -0
- package/conventions/shared.md +29 -58
- package/gotchas/README.md +14 -82
- package/gotchas/brick-office.md +9 -0
- package/gotchas/cdo.md +9 -0
- package/gotchas/ceo.md +9 -0
- package/gotchas/coo.md +9 -0
- package/gotchas/cqo.md +6 -19
- package/gotchas/cto.md +6 -19
- package/gotchas/hiring.md +9 -0
- package/gotchas/ops.md +17 -0
- package/gotchas/resource-manager.md +9 -0
- package/gotchas/shared.md +13 -0
- package/package.json +11 -17
- package/scripts/harness-runtime-stop.sh +58 -0
- package/scripts/harness-service-ops-monitor.sh +160 -16
- package/scripts/harness-stop.sh +18 -0
- package/scripts/harness-worker-evidence-validate.sh +59 -0
- package/scripts/import-agency-agents.js +102 -0
- package/scripts/play.sh +104 -0
- package/scripts/release.sh +89 -0
- package/conventions/conductor.md +0 -24
- package/conventions/coo-developer.md +0 -24
- package/conventions/dispatcher.md +0 -24
- package/conventions/documentationer.md +0 -24
- package/conventions/evaluator-architecture.md +0 -24
- package/conventions/evaluator-code-quality.md +0 -24
- package/conventions/evaluator-functional.md +0 -24
- package/conventions/evaluator-security.md +0 -24
- package/conventions/evaluator-visual.md +0 -24
- package/conventions/generator-backend.md +0 -24
- package/conventions/generator-designer.md +0 -24
- package/conventions/generator-devops.md +0 -24
- package/conventions/generator-frontend.md +0 -24
- package/conventions/meeting-manager.md +0 -24
- package/conventions/planner.md +0 -24
- package/conventions/service-ops.md +0 -24
- package/gotchas/conductor.md +0 -38
- package/gotchas/coo-developer.md +0 -22
- package/gotchas/dispatcher.md +0 -38
- package/gotchas/documentationer.md +0 -22
- package/gotchas/evaluator-architecture.md +0 -22
- package/gotchas/evaluator-code-quality.md +0 -22
- package/gotchas/evaluator-functional.md +0 -22
- package/gotchas/evaluator-security.md +0 -22
- package/gotchas/evaluator-visual.md +0 -22
- package/gotchas/generator-backend-laravel.md +0 -19
- package/gotchas/generator-backend.md +0 -22
- package/gotchas/generator-designer.md +0 -22
- package/gotchas/generator-devops.md +0 -22
- package/gotchas/generator-frontend.md +0 -22
- package/gotchas/meeting-manager.md +0 -30
- package/gotchas/planner.md +0 -22
- package/gotchas/service-ops.md +0 -30
- package/skills/_shared/dynamic-registration.md +0 -120
- package/skills/brainstorming/SKILL.md +0 -220
- package/skills/brainstorming/references/attribution.md +0 -109
- package/skills/brainstorming/references/spec-document-reviewer-prompt.md +0 -49
- package/skills/brainstorming/references/visual-companion.md +0 -287
- package/skills/brainstorming/scripts/frame-template.html +0 -214
- package/skills/brainstorming/scripts/helper.js +0 -88
- package/skills/brainstorming/scripts/server.cjs +0 -354
- package/skills/brainstorming/scripts/start-server.sh +0 -148
- package/skills/brainstorming/scripts/stop-server.sh +0 -56
- package/skills/conductor/SKILL.md +0 -336
- package/skills/coo-developer/SKILL.md +0 -72
- package/skills/cqo/SKILL.md +0 -146
- package/skills/cto/SKILL.md +0 -141
- package/skills/dispatcher/SKILL.md +0 -298
- package/skills/dispatcher/persona-ceo.md +0 -169
- package/skills/dispatcher/references/convention-flow.md +0 -111
- package/skills/dispatcher/references/gotcha-flow.md +0 -79
- package/skills/dispatcher/references/initialization.md +0 -53
- package/skills/dispatcher/references/pipeline-definitions.md +0 -151
- package/skills/documentationer/SKILL.md +0 -92
- package/skills/evaluator-architecture/SKILL.md +0 -173
- package/skills/evaluator-code-quality/SKILL.md +0 -218
- package/skills/evaluator-code-quality/references/scoring-rubric.md +0 -104
- package/skills/evaluator-functional/SKILL.md +0 -271
- package/skills/evaluator-functional/references/ia-compliance.md +0 -37
- package/skills/evaluator-functional/references/playwright-tools.md +0 -43
- package/skills/evaluator-functional/references/scoring-rubric.md +0 -52
- package/skills/evaluator-security/SKILL.md +0 -172
- package/skills/evaluator-visual/SKILL.md +0 -165
- package/skills/evaluator-visual/references/responsive-checklist.md +0 -44
- package/skills/evaluator-visual/references/scoring-rubric.md +0 -59
- package/skills/generator-backend/SKILL.md +0 -153
- package/skills/generator-backend/references/nestjs-msa-patterns.md +0 -69
- package/skills/generator-backend/references/sprint-contract-be.md +0 -32
- package/skills/generator-designer/SKILL.md +0 -219
- package/skills/generator-devops/SKILL.md +0 -201
- package/skills/generator-frontend/SKILL.md +0 -155
- package/skills/generator-frontend/references/_web-react-legacy/ai-forbidden-patterns.md +0 -89
- package/skills/generator-frontend/references/_web-react-legacy/component-patterns.md +0 -52
- package/skills/generator-frontend/references/_web-react-legacy/design-system-rules.md +0 -139
- package/skills/generator-frontend/references/_web-react-legacy/vercel-best-practices.md +0 -54
- package/skills/meeting-manager/SKILL.md +0 -419
- package/skills/planner/SKILL.md +0 -243
- package/skills/planner/hr-onboard.md +0 -134
- package/skills/planner/hr-recruit.md +0 -99
- package/skills/planner/persona-coo-hr.md +0 -182
- package/skills/planner/references/api-contract-schema.md +0 -34
- package/skills/planner/references/fe-stack-detection.md +0 -164
- package/skills/planner/references/ia-map-guide.md +0 -31
- package/skills/planner/references/plan-template.md +0 -51
- package/skills/service-ops/SKILL.md +0 -295
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# harness-runtime-stop.sh — Stop walwal harness play/release runtime mode.
|
|
3
|
+
|
|
4
|
+
set -uo pipefail
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
7
|
+
source "$SCRIPT_DIR/lib/harness-render-progress.sh"
|
|
8
|
+
|
|
9
|
+
PROJECT_ROOT="$(resolve_harness_root "${HARNESS_PROJECT_ROOT:-.}")" || exit 1
|
|
10
|
+
HARNESS_DIR="$PROJECT_ROOT/.harness"
|
|
11
|
+
PROGRESS="$HARNESS_DIR/progress.json"
|
|
12
|
+
CONFIG="$HARNESS_DIR/config.json"
|
|
13
|
+
RUNTIME_DIR="$HARNESS_DIR/runtime"
|
|
14
|
+
|
|
15
|
+
[ -d "$HARNESS_DIR" ] || { echo "ERROR: .harness/ not found" >&2; exit 1; }
|
|
16
|
+
[ -f "$PROGRESS" ] || { echo "ERROR: .harness/progress.json not found" >&2; exit 1; }
|
|
17
|
+
[ -f "$CONFIG" ] || { echo "ERROR: .harness/config.json not found" >&2; exit 1; }
|
|
18
|
+
command -v jq >/dev/null 2>&1 || { echo "ERROR: jq is required" >&2; exit 1; }
|
|
19
|
+
|
|
20
|
+
MODE_FILE="$RUNTIME_DIR/harness-mode"
|
|
21
|
+
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
22
|
+
stopped=0
|
|
23
|
+
|
|
24
|
+
for pid_file in "$RUNTIME_DIR/play.pid" "$RUNTIME_DIR/release.pid"; do
|
|
25
|
+
[ -f "$pid_file" ] || continue
|
|
26
|
+
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
|
27
|
+
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
28
|
+
kill "$pid" 2>/dev/null || true
|
|
29
|
+
sleep 1
|
|
30
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
31
|
+
kill -9 "$pid" 2>/dev/null || true
|
|
32
|
+
fi
|
|
33
|
+
stopped=$((stopped + 1))
|
|
34
|
+
fi
|
|
35
|
+
rm -f "$pid_file"
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
rm -f "$MODE_FILE"
|
|
39
|
+
|
|
40
|
+
tmp_config="$(mktemp)"
|
|
41
|
+
jq '
|
|
42
|
+
.runtime.build.live = false |
|
|
43
|
+
.runtime.production.live = false
|
|
44
|
+
' "$CONFIG" > "$tmp_config" && mv "$tmp_config" "$CONFIG" || rm -f "$tmp_config"
|
|
45
|
+
|
|
46
|
+
tmp="$(mktemp)"
|
|
47
|
+
jq --arg ts "$ts" --arg reason "$*" '
|
|
48
|
+
.runtime_state.mode = "stopped" |
|
|
49
|
+
.runtime_state.stopped_at = $ts |
|
|
50
|
+
.runtime_state.stop_reason = $reason |
|
|
51
|
+
.runtime_state.pid = null |
|
|
52
|
+
.service_ops.requested_mode = null |
|
|
53
|
+
.service_ops.monitor.stream_active = false |
|
|
54
|
+
.runtime.build.live = false |
|
|
55
|
+
.runtime.production.live = false
|
|
56
|
+
' "$PROGRESS" > "$tmp" && mv "$tmp" "$PROGRESS" || rm -f "$tmp"
|
|
57
|
+
|
|
58
|
+
echo "stopped runtime processes: $stopped"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# harness-service-ops-monitor.sh — deterministic Service-Ops production check
|
|
3
3
|
#
|
|
4
|
-
# Reads .harness/config.json runtime.
|
|
4
|
+
# Reads .env plus .harness/config.json runtime.build.commands[] and
|
|
5
|
+
# runtime.production.services[] and writes:
|
|
5
6
|
# - progress.json.service_ops.health[]
|
|
6
7
|
# - progress.json.service_ops.monitor.last_check
|
|
7
8
|
# - .harness/actions/ops-report-hourly-<timestamp>.md
|
|
@@ -26,6 +27,29 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
26
27
|
|
|
27
28
|
mkdir -p "$ACTIONS_DIR" "$OPS_DIR"
|
|
28
29
|
|
|
30
|
+
ENV_FILE="$PROJECT_ROOT/.env"
|
|
31
|
+
env_base_port=""
|
|
32
|
+
if [ -f "$ENV_FILE" ]; then
|
|
33
|
+
env_base_port="$(grep -E '^HARNESS_BASE_PORT=[0-9]' "$ENV_FILE" 2>/dev/null | tail -1 | cut -d= -f2- | tr -d '"' || true)"
|
|
34
|
+
fi
|
|
35
|
+
config_base_port="$(jq -r 'if .runtime.ports.base == null then "" else (.runtime.ports.base|tostring) end' "$CONFIG" 2>/dev/null || true)"
|
|
36
|
+
base_port="${env_base_port:-$config_base_port}"
|
|
37
|
+
|
|
38
|
+
if [ -z "$base_port" ]; then
|
|
39
|
+
echo "ERROR: HARNESS_BASE_PORT is not set." >&2
|
|
40
|
+
echo "" >&2
|
|
41
|
+
echo " CEO must agree on a {xx}000 base port with the Owner and add it to .env:" >&2
|
|
42
|
+
echo " HARNESS_BASE_PORT=3000" >&2
|
|
43
|
+
echo "" >&2
|
|
44
|
+
echo " OPS cannot monitor ports without a declared base. Set the value and re-run." >&2
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
range_size="$(jq -r '.runtime.ports.range_size // 1000' "$CONFIG" 2>/dev/null || echo 1000)"
|
|
49
|
+
range_max=$((base_port + range_size - 1))
|
|
50
|
+
|
|
51
|
+
build_live=$(jq -r '.runtime.build.live // false' "$CONFIG" 2>/dev/null || echo false)
|
|
52
|
+
build_count=$(jq -r '(.runtime.build.commands // []) | length' "$CONFIG" 2>/dev/null || echo 0)
|
|
29
53
|
live=$(jq -r '.runtime.production.live // false' "$CONFIG" 2>/dev/null || echo false)
|
|
30
54
|
service_count=$(jq -r '(.runtime.production.services // []) | length' "$CONFIG" 2>/dev/null || echo 0)
|
|
31
55
|
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
@@ -74,11 +98,83 @@ log_summary_json() {
|
|
|
74
98
|
'{configured:true, exists:true, path:$path, recent_errors:$errors, last_line:$last}'
|
|
75
99
|
}
|
|
76
100
|
|
|
101
|
+
port_drift() {
|
|
102
|
+
local port="$1"
|
|
103
|
+
if [ -z "$port" ] || [ "$port" = "null" ]; then
|
|
104
|
+
echo "missing"
|
|
105
|
+
elif [ "$port" -lt "$base_port" ] || [ "$port" -gt "$range_max" ]; then
|
|
106
|
+
echo "outside_base_range"
|
|
107
|
+
else
|
|
108
|
+
echo "ok"
|
|
109
|
+
fi
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
build_results_file="$(mktemp)"
|
|
113
|
+
: > "$build_results_file"
|
|
114
|
+
if [ "$build_live" = "true" ] && [ "${build_count:-0}" -gt 0 ]; then
|
|
115
|
+
b=0
|
|
116
|
+
while [ "$b" -lt "$build_count" ]; do
|
|
117
|
+
cmd_cfg="$(jq -c ".runtime.build.commands[$b]" "$CONFIG")"
|
|
118
|
+
name="$(jq -r '.name // ("build-" + (input_line_number|tostring))' <<<"$cmd_cfg")"
|
|
119
|
+
cwd="$(jq -r '.cwd // "."' <<<"$cmd_cfg")"
|
|
120
|
+
command_text="$(jq -r '.command // empty' <<<"$cmd_cfg")"
|
|
121
|
+
expected_port="$(jq -r '.expected_port // empty' <<<"$cmd_cfg")"
|
|
122
|
+
log_path="$(jq -r '.log_path // empty' <<<"$cmd_cfg")"
|
|
123
|
+
owner="$(jq -r '.owner // "cto"' <<<"$cmd_cfg")"
|
|
124
|
+
drift="$(port_drift "$expected_port")"
|
|
125
|
+
|
|
126
|
+
port_state="not_configured"
|
|
127
|
+
if [ -n "$expected_port" ]; then
|
|
128
|
+
if tcp_check "127.0.0.1" "$expected_port"; then port_state="listening"; else port_state="down"; fi
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
log_json="$(log_summary_json "$log_path")"
|
|
132
|
+
status="ok"
|
|
133
|
+
if [ "$drift" != "ok" ]; then
|
|
134
|
+
status="port_drift"
|
|
135
|
+
elif [ -n "$expected_port" ] && [ "$port_state" != "listening" ]; then
|
|
136
|
+
status="down"
|
|
137
|
+
elif [ "$(jq -r '.configured and (.exists|not)' <<<"$log_json")" = "true" ]; then
|
|
138
|
+
status="log_missing"
|
|
139
|
+
elif [ "$(jq -r '.recent_errors // 0' <<<"$log_json")" -gt 0 ]; then
|
|
140
|
+
status="warn"
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
jq -n \
|
|
144
|
+
--arg ts "$ts" \
|
|
145
|
+
--arg name "$name" \
|
|
146
|
+
--arg cwd "$cwd" \
|
|
147
|
+
--arg command "$command_text" \
|
|
148
|
+
--arg expected_port "$expected_port" \
|
|
149
|
+
--arg owner "$owner" \
|
|
150
|
+
--arg port_state "$port_state" \
|
|
151
|
+
--arg port_drift "$drift" \
|
|
152
|
+
--arg status "$status" \
|
|
153
|
+
--argjson log "$log_json" \
|
|
154
|
+
'{
|
|
155
|
+
ts:$ts,
|
|
156
|
+
name:$name,
|
|
157
|
+
cwd:$cwd,
|
|
158
|
+
command:$command,
|
|
159
|
+
expected_port:(if $expected_port == "" or $expected_port == "null" then null else ($expected_port|tonumber?) end),
|
|
160
|
+
owner:$owner,
|
|
161
|
+
port_state:$port_state,
|
|
162
|
+
port_drift:$port_drift,
|
|
163
|
+
log:$log,
|
|
164
|
+
status:$status
|
|
165
|
+
}' >> "$build_results_file"
|
|
166
|
+
b=$((b + 1))
|
|
167
|
+
done
|
|
168
|
+
fi
|
|
169
|
+
build_results_json="$(jq -s '.' "$build_results_file")"
|
|
170
|
+
rm -f "$build_results_file"
|
|
171
|
+
|
|
77
172
|
if [ "$live" != "true" ] || [ "${service_count:-0}" -eq 0 ]; then
|
|
78
|
-
jq --arg ts "$ts" --arg report "$report_rel" '
|
|
173
|
+
jq --arg ts "$ts" --arg report "$report_rel" --argjson build "$build_results_json" '
|
|
79
174
|
.service_ops.monitor.last_check = $ts |
|
|
80
175
|
.service_ops.monitor.stream_active = false |
|
|
81
176
|
.service_ops.monitor.last_report = $report |
|
|
177
|
+
.service_ops.build = $build |
|
|
82
178
|
.service_ops.health = [] |
|
|
83
179
|
.service_ops.incident.open = [] |
|
|
84
180
|
.service_ops.incident.signature = "" |
|
|
@@ -95,10 +191,24 @@ if [ "$live" != "true" ] || [ "${service_count:-0}" -eq 0 ]; then
|
|
|
95
191
|
echo ""
|
|
96
192
|
echo "- ts: $ts"
|
|
97
193
|
echo "- production.live: $live"
|
|
194
|
+
echo "- build.live: $build_live"
|
|
195
|
+
echo "- base_port: $base_port"
|
|
98
196
|
echo "- services: $service_count"
|
|
197
|
+
echo "- build_commands: $build_count"
|
|
99
198
|
echo "- verdict: NO_PRODUCTION_SERVICES"
|
|
100
199
|
echo ""
|
|
101
|
-
echo "
|
|
200
|
+
echo "## Build Environments"
|
|
201
|
+
echo ""
|
|
202
|
+
echo "| Build | Command | Expected Port | Logs | Status |"
|
|
203
|
+
echo "|---|---|---:|---|---|"
|
|
204
|
+
jq -r '.[] |
|
|
205
|
+
"| \(.name) | `\(.command)` | " +
|
|
206
|
+
((.expected_port // "n/a")|tostring) + " " + .port_state + " " + .port_drift +
|
|
207
|
+
" | " +
|
|
208
|
+
(if (.log.configured|not) then "not configured" elif (.log.exists|not) then "missing" else ((.log.recent_errors|tostring) + " recent errors") end) +
|
|
209
|
+
" | \(.status) |"' <<<"$build_results_json"
|
|
210
|
+
echo ""
|
|
211
|
+
echo "No production service endpoints are configured. Owner+CEO+CTO must define runtime.production.services[] before OPS can monitor live servers."
|
|
102
212
|
} > "$report_path"
|
|
103
213
|
echo "$report_rel"
|
|
104
214
|
exit 0
|
|
@@ -111,14 +221,20 @@ i=0
|
|
|
111
221
|
while [ "$i" -lt "$service_count" ]; do
|
|
112
222
|
svc="$(jq -c ".runtime.production.services[$i]" "$CONFIG")"
|
|
113
223
|
name="$(jq -r '.name // ("service-" + (input_line_number|tostring))' <<<"$svc")"
|
|
224
|
+
environment="$(jq -r '.environment // "unknown"' <<<"$svc")"
|
|
114
225
|
host="$(jq -r '.host // "127.0.0.1"' <<<"$svc")"
|
|
115
226
|
port="$(jq -r '.port // empty' <<<"$svc")"
|
|
116
227
|
health_path="$(jq -r '.health_path // empty' <<<"$svc")"
|
|
117
228
|
expected_status="$(jq -r '.expected_status // 200' <<<"$svc")"
|
|
118
229
|
log_path="$(jq -r '.log_path // empty' <<<"$svc")"
|
|
230
|
+
owner="$(jq -r '.owner // "cto"' <<<"$svc")"
|
|
231
|
+
source="$(jq -r '.source // "owner-provided"' <<<"$svc")"
|
|
232
|
+
drift="$(port_drift "$port")"
|
|
119
233
|
|
|
120
234
|
port_state="unknown"
|
|
121
|
-
if [ -
|
|
235
|
+
if [ -z "$port" ] || [ "$port" = "null" ]; then
|
|
236
|
+
port_state="not_configured"
|
|
237
|
+
elif tcp_check "$host" "$port"; then
|
|
122
238
|
port_state="listening"
|
|
123
239
|
else
|
|
124
240
|
port_state="down"
|
|
@@ -136,7 +252,9 @@ while [ "$i" -lt "$service_count" ]; do
|
|
|
136
252
|
log_json="$(log_summary_json "$log_path")"
|
|
137
253
|
|
|
138
254
|
status="ok"
|
|
139
|
-
if [ "$
|
|
255
|
+
if [ "$drift" != "ok" ]; then
|
|
256
|
+
status="port_drift"
|
|
257
|
+
elif [ "$port_state" != "listening" ]; then
|
|
140
258
|
status="down"
|
|
141
259
|
elif [ "$health_ok" = "false" ]; then
|
|
142
260
|
status="degraded"
|
|
@@ -149,6 +267,7 @@ while [ "$i" -lt "$service_count" ]; do
|
|
|
149
267
|
jq -n \
|
|
150
268
|
--arg ts "$ts" \
|
|
151
269
|
--arg name "$name" \
|
|
270
|
+
--arg environment "$environment" \
|
|
152
271
|
--arg host "$host" \
|
|
153
272
|
--arg port "$port" \
|
|
154
273
|
--arg port_state "$port_state" \
|
|
@@ -158,12 +277,16 @@ while [ "$i" -lt "$service_count" ]; do
|
|
|
158
277
|
--arg health_status "$health_status" \
|
|
159
278
|
--arg health_ok "$health_ok" \
|
|
160
279
|
--arg status "$status" \
|
|
280
|
+
--arg owner "$owner" \
|
|
281
|
+
--arg source "$source" \
|
|
282
|
+
--arg port_drift "$drift" \
|
|
161
283
|
--argjson log "$log_json" \
|
|
162
284
|
'{
|
|
163
285
|
ts:$ts,
|
|
164
286
|
name:$name,
|
|
287
|
+
environment:$environment,
|
|
165
288
|
host:$host,
|
|
166
|
-
port:($port|tonumber?),
|
|
289
|
+
port:(if $port == "" or $port == "null" then null else ($port|tonumber?) end),
|
|
167
290
|
port_state:$port_state,
|
|
168
291
|
health_path:(if $health_path == "" or $health_path == "null" then null else $health_path end),
|
|
169
292
|
health_url:(if $health_url == "" then null else $health_url end),
|
|
@@ -171,6 +294,9 @@ while [ "$i" -lt "$service_count" ]; do
|
|
|
171
294
|
health_status:(if $health_status == "null" then null else ($health_status|tonumber?) end),
|
|
172
295
|
health_ok:(if $health_ok == "true" then true elif $health_ok == "false" then false else null end),
|
|
173
296
|
log:$log,
|
|
297
|
+
owner:$owner,
|
|
298
|
+
source:$source,
|
|
299
|
+
port_drift:$port_drift,
|
|
174
300
|
status:$status
|
|
175
301
|
}' >> "$results_file"
|
|
176
302
|
i=$((i + 1))
|
|
@@ -179,19 +305,20 @@ done
|
|
|
179
305
|
results_json="$(jq -s '.' "$results_file")"
|
|
180
306
|
rm -f "$results_file"
|
|
181
307
|
|
|
182
|
-
down_count="$(jq '[.[] | select(.status == "down" or .status == "degraded")] | length' <<<"$results_json")"
|
|
183
|
-
warn_count="$(jq '[.[] | select(.status == "warn" or .status == "log_missing")] | length' <<<"$results_json")"
|
|
308
|
+
down_count="$(jq '[.[] | select(.status == "down" or .status == "degraded" or (.status == "port_drift" and .port_drift != "missing"))] | length' <<<"$results_json")"
|
|
309
|
+
warn_count="$(jq '[.[] | select(.status == "warn" or .status == "log_missing" or (.status == "port_drift" and .port_drift == "missing"))] | length' <<<"$results_json")"
|
|
184
310
|
ok_count="$(jq '[.[] | select(.status == "ok")] | length' <<<"$results_json")"
|
|
311
|
+
build_warn_count="$(jq '[.[] | select(.status != "ok")] | length' <<<"$build_results_json")"
|
|
185
312
|
verdict="OK"
|
|
186
|
-
if [ "$down_count" -gt 0 ]; then verdict="INCIDENT"; elif [ "$warn_count" -gt 0 ]; then verdict="WARN"; fi
|
|
313
|
+
if [ "$down_count" -gt 0 ]; then verdict="INCIDENT"; elif [ "$warn_count" -gt 0 ] || [ "$build_warn_count" -gt 0 ]; then verdict="WARN"; fi
|
|
187
314
|
|
|
188
315
|
incidents_json="$(jq '
|
|
189
|
-
[ .[] | select(.status == "down" or .status == "degraded") |
|
|
316
|
+
[ .[] | select(.status == "down" or .status == "degraded" or (.status == "port_drift" and .port_drift != "missing")) |
|
|
190
317
|
{
|
|
191
318
|
id: ("OPS-" + (.name | ascii_upcase | gsub("[^A-Z0-9]+";"-"))),
|
|
192
319
|
dept: "Operations",
|
|
193
320
|
severity: (if .status == "down" then "critical" else "high" end),
|
|
194
|
-
message: (.name + " " + .status + " (" + .host + ":" + (.port|tostring) + ")"),
|
|
321
|
+
message: (.name + " " + .status + " (" + .environment + " " + .host + ":" + (.port|tostring) + ")"),
|
|
195
322
|
ts: .ts
|
|
196
323
|
}
|
|
197
324
|
]' <<<"$results_json")"
|
|
@@ -221,12 +348,13 @@ elif [ "$down_count" -eq 0 ] && [ "$warn_count" -eq 0 ]; then
|
|
|
221
348
|
close_candidate=true
|
|
222
349
|
fi
|
|
223
350
|
|
|
224
|
-
jq --arg ts "$ts" --arg report "$report_rel" --arg signature "$incident_signature" --argjson repeat "$repeat_count" --argjson recovery "$recovery_required" --argjson partial "$partial_recovery" --argjson close_candidate "$close_candidate" --argjson health "$results_json" --argjson incidents "$incidents_json" --argjson warn "$warn_count" --argjson alert "$down_count" '
|
|
351
|
+
jq --arg ts "$ts" --arg report "$report_rel" --arg signature "$incident_signature" --argjson repeat "$repeat_count" --argjson recovery "$recovery_required" --argjson partial "$partial_recovery" --argjson close_candidate "$close_candidate" --argjson build "$build_results_json" --argjson health "$results_json" --argjson incidents "$incidents_json" --argjson warn "$warn_count" --argjson alert "$down_count" '
|
|
225
352
|
.service_ops.monitor.stream_active = false |
|
|
226
353
|
.service_ops.monitor.last_check = $ts |
|
|
227
354
|
.service_ops.monitor.last_report = $report |
|
|
228
355
|
.service_ops.monitor.warns_this_sprint = ((.service_ops.monitor.warns_this_sprint // 0) + $warn) |
|
|
229
356
|
.service_ops.monitor.alerts_this_sprint = ((.service_ops.monitor.alerts_this_sprint // 0) + $alert) |
|
|
357
|
+
.service_ops.build = $build |
|
|
230
358
|
.service_ops.health = $health |
|
|
231
359
|
.service_ops.incident.open = $incidents |
|
|
232
360
|
.service_ops.incident.signature = $signature |
|
|
@@ -243,7 +371,10 @@ jq --arg ts "$ts" --arg report "$report_rel" --arg signature "$incident_signatur
|
|
|
243
371
|
echo ""
|
|
244
372
|
echo "- ts: $ts"
|
|
245
373
|
echo "- production.live: true"
|
|
374
|
+
echo "- build.live: $build_live"
|
|
375
|
+
echo "- base_port: $base_port"
|
|
246
376
|
echo "- services: $service_count"
|
|
377
|
+
echo "- build_commands: $build_count"
|
|
247
378
|
echo "- verdict: $verdict"
|
|
248
379
|
echo "- ok: $ok_count"
|
|
249
380
|
echo "- warnings: $warn_count"
|
|
@@ -254,10 +385,23 @@ jq --arg ts "$ts" --arg report "$report_rel" --arg signature "$incident_signatur
|
|
|
254
385
|
echo "- partial_recovery: $partial_recovery"
|
|
255
386
|
echo "- close_candidate: $close_candidate"
|
|
256
387
|
echo ""
|
|
257
|
-
echo "
|
|
258
|
-
echo "
|
|
388
|
+
echo "## Build Environments"
|
|
389
|
+
echo ""
|
|
390
|
+
echo "| Build | Command | Expected Port | Logs | Status |"
|
|
391
|
+
echo "|---|---|---:|---|---|"
|
|
392
|
+
jq -r '.[] |
|
|
393
|
+
"| \(.name) | `\(.command)` | " +
|
|
394
|
+
((.expected_port // "n/a")|tostring) + " " + .port_state + " " + .port_drift +
|
|
395
|
+
" | " +
|
|
396
|
+
(if (.log.configured|not) then "not configured" elif (.log.exists|not) then "missing" else ((.log.recent_errors|tostring) + " recent errors") end) +
|
|
397
|
+
" | \(.status) |"' <<<"$build_results_json"
|
|
398
|
+
echo ""
|
|
399
|
+
echo "## Service Environments"
|
|
400
|
+
echo ""
|
|
401
|
+
echo "| Service | Env | Port | Health | Logs | Status |"
|
|
402
|
+
echo "|---|---|---:|---|---|---|"
|
|
259
403
|
jq -r '.[] |
|
|
260
|
-
"| \(.name) | \(.host)
|
|
404
|
+
"| \(.name) | \(.environment) | \(.host):" + ((.port // "n/a")|tostring) + " \(.port_state) \(.port_drift) | " +
|
|
261
405
|
(if .health_path == null then "n/a" else ((.health_status // "000")|tostring) + " expected " + ((.expected_status // 200)|tostring) end) +
|
|
262
406
|
" | " +
|
|
263
407
|
(if (.log.configured|not) then "not configured" elif (.log.exists|not) then "missing" else ((.log.recent_errors|tostring) + " recent errors") end) +
|
|
@@ -266,7 +410,7 @@ jq --arg ts "$ts" --arg report "$report_rel" --arg signature "$incident_signatur
|
|
|
266
410
|
echo "## Raw"
|
|
267
411
|
echo ""
|
|
268
412
|
echo '```json'
|
|
269
|
-
jq
|
|
413
|
+
jq -n --argjson build "$build_results_json" --argjson services "$results_json" '{build:$build, services:$services}'
|
|
270
414
|
echo '```'
|
|
271
415
|
} > "$report_path"
|
|
272
416
|
|
package/scripts/harness-stop.sh
CHANGED
|
@@ -22,11 +22,29 @@ command -v jq >/dev/null 2>&1 || exit 0
|
|
|
22
22
|
|
|
23
23
|
PROGRESS="$CWD/.harness/progress.json"
|
|
24
24
|
CONFIG="$CWD/.harness/config.json"
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
25
26
|
|
|
26
27
|
# Opt-out
|
|
27
28
|
AUTO_CHAIN=$(jq -r '.behavior.auto_chain_on_stop // true' "$CONFIG" 2>/dev/null || echo "true")
|
|
28
29
|
if [ "$AUTO_CHAIN" != "true" ]; then exit 0; fi
|
|
29
30
|
|
|
31
|
+
# CXX direct-execution guard:
|
|
32
|
+
# If a mission has CXX documents but no worker reports, block the stop so the
|
|
33
|
+
# company loop must hire/dispatch workers instead of ending with CXX-only work.
|
|
34
|
+
if [ -x "$SCRIPT_DIR/harness-worker-evidence-validate.sh" ]; then
|
|
35
|
+
WORKER_EVIDENCE_JSON=$("$SCRIPT_DIR/harness-worker-evidence-validate.sh" "$CWD" json 2>/dev/null || true)
|
|
36
|
+
WORKER_EVIDENCE_OK=$(echo "$WORKER_EVIDENCE_JSON" | jq -r 'if has("ok") then .ok else true end' 2>/dev/null || echo true)
|
|
37
|
+
if [ "$WORKER_EVIDENCE_OK" != "true" ]; then
|
|
38
|
+
REASON=$(echo "$WORKER_EVIDENCE_JSON" | jq -r '
|
|
39
|
+
"CXX 직접 실행 차단: " +
|
|
40
|
+
([.violations[] | "\(.mission) has CXX docs without worker reports: \(.docs | join(","))"] | join("; ")) +
|
|
41
|
+
". harness-hiring/resource-manager로 전문 worker를 고용 또는 배정하고 .harness/documents/{mission}/workers/{worker-name}.md 를 남긴 뒤 계속하라."
|
|
42
|
+
' 2>/dev/null || echo "CXX 직접 실행 차단: worker report가 없는 mission이 있습니다. hired worker 보고서를 먼저 생성하세요.")
|
|
43
|
+
jq -nc --arg reason "$REASON" '{decision:"block", reason:$reason}'
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
fi
|
|
47
|
+
|
|
30
48
|
# 무한루프 방지: 한 sprint 안에서 stop_chain_count 가 상한을 넘으면 중단
|
|
31
49
|
STOP_CHAIN_MAX=$(jq -r '.behavior.auto_chain_max_per_sprint // 200' "$CONFIG" 2>/dev/null || echo 200)
|
|
32
50
|
STOP_CHAIN_COUNT=$(jq -r '.conductor.stop_chain_count // 0' "$PROGRESS" 2>/dev/null || echo 0)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# harness-worker-evidence-validate.sh — block CXX direct execution without worker reports
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
PROJECT_ROOT="${1:-.}"
|
|
6
|
+
DOC_ROOT="$PROJECT_ROOT/.harness/documents"
|
|
7
|
+
|
|
8
|
+
[ -d "$DOC_ROOT" ] || exit 0
|
|
9
|
+
|
|
10
|
+
mode="${2:-text}"
|
|
11
|
+
violations=()
|
|
12
|
+
|
|
13
|
+
has_worker_report() {
|
|
14
|
+
local mission_dir="$1"
|
|
15
|
+
find "$mission_dir/workers" -maxdepth 1 -type f -name '*.md' 2>/dev/null | grep -q .
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
for mission_dir in "$DOC_ROOT"/*; do
|
|
19
|
+
[ -d "$mission_dir" ] || continue
|
|
20
|
+
mission_name="$(basename "$mission_dir")"
|
|
21
|
+
|
|
22
|
+
cxx_docs=()
|
|
23
|
+
for cxx in coo cdo cto cqo ops; do
|
|
24
|
+
cxx_path="$mission_dir/$cxx.md"
|
|
25
|
+
[ -s "$cxx_path" ] || continue
|
|
26
|
+
cxx_docs+=("$cxx.md")
|
|
27
|
+
done
|
|
28
|
+
|
|
29
|
+
[ "${#cxx_docs[@]}" -gt 0 ] || continue
|
|
30
|
+
if ! has_worker_report "$mission_dir"; then
|
|
31
|
+
violations+=("$mission_name:${cxx_docs[*]}")
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
|
|
35
|
+
if [ "${#violations[@]}" -eq 0 ]; then
|
|
36
|
+
if [ "$mode" = "json" ]; then
|
|
37
|
+
jq -nc '{ok:true, violations:[]}'
|
|
38
|
+
fi
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
if [ "$mode" = "json" ]; then
|
|
43
|
+
printf '%s\n' "${violations[@]}" | jq -Rcs '
|
|
44
|
+
split("\n")[:-1]
|
|
45
|
+
| map(capture("(?<mission>[^:]+):(?<docs>.*)") | .docs = (.docs | split(" ")))
|
|
46
|
+
| {ok:false, violations:.}
|
|
47
|
+
'
|
|
48
|
+
else
|
|
49
|
+
echo "CXX worker evidence violation:"
|
|
50
|
+
for violation in "${violations[@]}"; do
|
|
51
|
+
mission="${violation%%:*}"
|
|
52
|
+
docs="${violation#*:}"
|
|
53
|
+
echo "- mission: $mission"
|
|
54
|
+
echo " cxx_docs: $docs"
|
|
55
|
+
echo " required: at least one .harness/documents/$mission/workers/{worker-name}.md report"
|
|
56
|
+
done
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
exit 1
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const sourceRoot = process.argv[2] || '/Users/ted/Downloads/agency-agents-main';
|
|
7
|
+
const targetRoot = process.argv[3] || path.resolve(process.cwd(), 'HR-Resource');
|
|
8
|
+
|
|
9
|
+
function walk(dir, out = []) {
|
|
10
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
11
|
+
const full = path.join(dir, entry.name);
|
|
12
|
+
if (entry.isDirectory()) walk(full, out);
|
|
13
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) out.push(full);
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function slugify(value) {
|
|
19
|
+
return value
|
|
20
|
+
.toLowerCase()
|
|
21
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
22
|
+
.replace(/^-+|-+$/g, '');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseFrontmatter(content) {
|
|
26
|
+
const match = /^---\n([\s\S]*?)\n---\n?/.exec(content);
|
|
27
|
+
if (!match) return null;
|
|
28
|
+
const frontmatter = match[1];
|
|
29
|
+
const fields = {};
|
|
30
|
+
for (const line of frontmatter.split('\n')) {
|
|
31
|
+
const m = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line);
|
|
32
|
+
if (m) fields[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
33
|
+
}
|
|
34
|
+
return { frontmatter, fields, body: content.slice(match[0].length) };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function hasAgentShape(parsed) {
|
|
38
|
+
return Boolean(parsed && parsed.fields.name && parsed.fields.description);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function convertFile(file) {
|
|
42
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
43
|
+
const parsed = parseFrontmatter(content);
|
|
44
|
+
if (!hasAgentShape(parsed)) return null;
|
|
45
|
+
|
|
46
|
+
const sourceRel = path.relative(sourceRoot, file);
|
|
47
|
+
const sourceSlug = slugify(sourceRel.replace(/\.md$/, ''));
|
|
48
|
+
const agentName = slugify(parsed.fields.name);
|
|
49
|
+
const skillName = sourceSlug || agentName;
|
|
50
|
+
const destDir = path.join(targetRoot, skillName);
|
|
51
|
+
const dest = path.join(destDir, 'SKILL.md');
|
|
52
|
+
|
|
53
|
+
const description = parsed.fields.description.replace(/"/g, '\\"');
|
|
54
|
+
const body = parsed.body.replace(/^# /, `# ${parsed.fields.name}\n\n`);
|
|
55
|
+
const skill = [
|
|
56
|
+
'---',
|
|
57
|
+
`name: ${skillName}`,
|
|
58
|
+
`description: "${description}"`,
|
|
59
|
+
'model: sonnet',
|
|
60
|
+
'disable-model-invocation: false',
|
|
61
|
+
'---',
|
|
62
|
+
'',
|
|
63
|
+
'<!--',
|
|
64
|
+
`Imported from agency-agents: ${sourceRel}`,
|
|
65
|
+
'Original frontmatter:',
|
|
66
|
+
parsed.frontmatter,
|
|
67
|
+
'-->',
|
|
68
|
+
'',
|
|
69
|
+
body.trim(),
|
|
70
|
+
'',
|
|
71
|
+
'## Harness Operating Contract',
|
|
72
|
+
'',
|
|
73
|
+
'- You are a hireable HR-Resource worker, not a CXX executive.',
|
|
74
|
+
'- Work only after a CXX assigns a mission through `/hiring` and `/resource-manager` wiring.',
|
|
75
|
+
'- Start each assignment from fresh context.',
|
|
76
|
+
'- Record mission output in `.harness/documents/{mission_name}/workers/{name}.md` unless the requester specifies another mission document.',
|
|
77
|
+
'- Follow DDD boundaries for domain, application, infrastructure, and interface decisions.',
|
|
78
|
+
''
|
|
79
|
+
].join('\n');
|
|
80
|
+
|
|
81
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
82
|
+
fs.writeFileSync(dest, skill);
|
|
83
|
+
return { sourceRel, skillName };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const converted = [];
|
|
87
|
+
for (const file of walk(sourceRoot)) {
|
|
88
|
+
const result = convertFile(file);
|
|
89
|
+
if (result) converted.push(result);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
converted.sort((a, b) => a.skillName.localeCompare(b.skillName));
|
|
93
|
+
const index = {
|
|
94
|
+
source: sourceRoot,
|
|
95
|
+
imported_at: new Date().toISOString(),
|
|
96
|
+
count: converted.length,
|
|
97
|
+
resources: converted
|
|
98
|
+
};
|
|
99
|
+
fs.mkdirSync(targetRoot, { recursive: true });
|
|
100
|
+
fs.writeFileSync(path.join(targetRoot, 'index.json'), JSON.stringify(index, null, 2) + '\n');
|
|
101
|
+
|
|
102
|
+
console.log(`Imported ${converted.length} agency agents into ${targetRoot}`);
|
package/scripts/play.sh
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# play.sh — Start walwal harness play build mode.
|
|
3
|
+
|
|
4
|
+
set -uo pipefail
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
7
|
+
source "$SCRIPT_DIR/lib/harness-render-progress.sh"
|
|
8
|
+
|
|
9
|
+
PROJECT_ROOT="$(resolve_harness_root "${HARNESS_PROJECT_ROOT:-.}")" || exit 1
|
|
10
|
+
HARNESS_DIR="$PROJECT_ROOT/.harness"
|
|
11
|
+
CONFIG="$HARNESS_DIR/config.json"
|
|
12
|
+
PROGRESS="$HARNESS_DIR/progress.json"
|
|
13
|
+
RUNTIME_DIR="$HARNESS_DIR/runtime"
|
|
14
|
+
LOG_DIR="$HARNESS_DIR/logs/$(date -u +%Y-%m-%d)"
|
|
15
|
+
|
|
16
|
+
[ -d "$HARNESS_DIR" ] || { echo "ERROR: .harness/ not found" >&2; exit 1; }
|
|
17
|
+
[ -f "$PROGRESS" ] || { echo "ERROR: .harness/progress.json not found" >&2; exit 1; }
|
|
18
|
+
[ -f "$CONFIG" ] || { echo "ERROR: .harness/config.json not found" >&2; exit 1; }
|
|
19
|
+
command -v jq >/dev/null 2>&1 || { echo "ERROR: jq is required" >&2; exit 1; }
|
|
20
|
+
|
|
21
|
+
mkdir -p "$RUNTIME_DIR" "$LOG_DIR"
|
|
22
|
+
|
|
23
|
+
MODE_FILE="$RUNTIME_DIR/harness-mode"
|
|
24
|
+
PID_FILE="$RUNTIME_DIR/play.pid"
|
|
25
|
+
LOG_FILE="$LOG_DIR/play-harness.log"
|
|
26
|
+
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
27
|
+
ENV_FILE="$PROJECT_ROOT/.env"
|
|
28
|
+
|
|
29
|
+
active_mode=""
|
|
30
|
+
[ -f "$MODE_FILE" ] && active_mode="$(cat "$MODE_FILE" 2>/dev/null || true)"
|
|
31
|
+
if [ -n "$active_mode" ] && [ "$active_mode" != "play" ]; then
|
|
32
|
+
echo "ERROR: $active_mode mode is active. Run /stop-harness before /play-harness." >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
if [ -f "$PID_FILE" ]; then
|
|
37
|
+
old_pid="$(cat "$PID_FILE" 2>/dev/null || true)"
|
|
38
|
+
if [ -n "$old_pid" ] && kill -0 "$old_pid" 2>/dev/null; then
|
|
39
|
+
echo "ERROR: play mode is already active with pid $old_pid" >&2
|
|
40
|
+
exit 2
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
cmd="$(jq -r '.runtime.play.command // empty' "$CONFIG" 2>/dev/null || true)"
|
|
45
|
+
if [ -z "$cmd" ] || [ "$cmd" = "null" ]; then
|
|
46
|
+
cmd="$(jq -r '.runtime.build.commands[0].command // empty' "$CONFIG" 2>/dev/null || true)"
|
|
47
|
+
fi
|
|
48
|
+
[ -n "$cmd" ] || { echo "ERROR: runtime.play.command or runtime.build.commands[0].command must be configured" >&2; exit 1; }
|
|
49
|
+
|
|
50
|
+
cwd="$(jq -r '.runtime.play.cwd // .runtime.build.commands[0].cwd // "."' "$CONFIG" 2>/dev/null || echo ".")"
|
|
51
|
+
run_dir="$PROJECT_ROOT/$cwd"
|
|
52
|
+
[ -d "$run_dir" ] || { echo "ERROR: play cwd does not exist: $cwd" >&2; exit 1; }
|
|
53
|
+
|
|
54
|
+
env_base_port=""
|
|
55
|
+
if [ -f "$ENV_FILE" ]; then
|
|
56
|
+
env_base_port="$(grep -E '^HARNESS_BASE_PORT=[0-9]' "$ENV_FILE" 2>/dev/null | tail -1 | cut -d= -f2- | tr -d '"' || true)"
|
|
57
|
+
fi
|
|
58
|
+
config_base_port="$(jq -r 'if .runtime.ports.base == null then "" else (.runtime.ports.base|tostring) end' "$CONFIG" 2>/dev/null || true)"
|
|
59
|
+
base_port="${env_base_port:-$config_base_port}"
|
|
60
|
+
|
|
61
|
+
(
|
|
62
|
+
cd "$run_dir" || exit 1
|
|
63
|
+
nohup bash -lc "$cmd $*" >> "$LOG_FILE" 2>&1 &
|
|
64
|
+
echo "$!"
|
|
65
|
+
) > "$RUNTIME_DIR/play.pid.tmp"
|
|
66
|
+
pid="$(cat "$RUNTIME_DIR/play.pid.tmp" 2>/dev/null || true)"
|
|
67
|
+
rm -f "$RUNTIME_DIR/play.pid.tmp"
|
|
68
|
+
[ -n "$pid" ] || { echo "ERROR: failed to start play command" >&2; exit 1; }
|
|
69
|
+
|
|
70
|
+
printf '%s\n' "play" > "$MODE_FILE"
|
|
71
|
+
printf '%s\n' "$pid" > "$PID_FILE"
|
|
72
|
+
|
|
73
|
+
tmp_config="$(mktemp)"
|
|
74
|
+
jq --arg log "$LOG_FILE" --arg cmd "$cmd" --arg cwd "$cwd" --arg base "$base_port" '
|
|
75
|
+
.runtime.build.live = true |
|
|
76
|
+
.runtime.production.live = false |
|
|
77
|
+
.runtime.build.commands[0].command = ((.runtime.build.commands[0].command // $cmd) | if . == "" then $cmd else . end) |
|
|
78
|
+
.runtime.build.commands[0].cwd = ((.runtime.build.commands[0].cwd // $cwd) | if . == "" then $cwd else . end) |
|
|
79
|
+
.runtime.build.commands[0].log_path = $log |
|
|
80
|
+
if ($base | length) > 0 then
|
|
81
|
+
.runtime.ports.base = (($base|tonumber?) // .runtime.ports.base) |
|
|
82
|
+
.runtime.build.commands[0].expected_port = ((.runtime.build.commands[0].expected_port // (($base|tonumber?) // null)))
|
|
83
|
+
else
|
|
84
|
+
.
|
|
85
|
+
end
|
|
86
|
+
' "$CONFIG" > "$tmp_config" && mv "$tmp_config" "$CONFIG" || rm -f "$tmp_config"
|
|
87
|
+
|
|
88
|
+
tmp="$(mktemp)"
|
|
89
|
+
jq --arg ts "$ts" --arg pid "$pid" --arg log "$LOG_FILE" --arg cmd "$cmd" '
|
|
90
|
+
.runtime_state.mode = "play" |
|
|
91
|
+
.runtime_state.started_at = $ts |
|
|
92
|
+
.runtime_state.pid = ($pid|tonumber) |
|
|
93
|
+
.runtime_state.log_path = $log |
|
|
94
|
+
.runtime_state.command = $cmd |
|
|
95
|
+
.service_ops.requested_mode = "monitor" |
|
|
96
|
+
.service_ops.monitor.stream_active = true |
|
|
97
|
+
.runtime.build.live = true |
|
|
98
|
+
.runtime.production.live = false
|
|
99
|
+
' "$PROGRESS" > "$tmp" && mv "$tmp" "$PROGRESS" || rm -f "$tmp"
|
|
100
|
+
|
|
101
|
+
ops_report="$(bash "$SCRIPT_DIR/harness-service-ops-monitor.sh" "$PROJECT_ROOT" 2>/dev/null || true)"
|
|
102
|
+
echo "play pid: $pid"
|
|
103
|
+
echo "play log: $LOG_FILE"
|
|
104
|
+
[ -n "$ops_report" ] && echo "ops report: $ops_report"
|