@osfactory/har 0.64.1 → 1.0.0-rc.1

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.
Files changed (141) hide show
  1. package/dist/index.js +15981 -6646
  2. package/dist/prompts/system-authoring.md +155 -0
  3. package/dist/templates/adaptation-prompt-init.md +67 -43
  4. package/dist/templates/adaptation-prompt-maintain.md +38 -38
  5. package/dist/templates/agent-skills/har-maintain.md +2 -2
  6. package/dist/templates/agent-skills/setup-har.md +6 -4
  7. package/dist/templates/cursor-rule.mdc.template +3 -3
  8. package/dist/templates/har-boilerplate/docker-compose.agent.yml +1 -1
  9. package/dist/templates/har-boilerplate/harness.env +11 -155
  10. package/dist/templates/har-boilerplate/stages.json +51 -2
  11. package/dist/templates/har-boilerplate-cli/docker-compose.agent.yml +1 -1
  12. package/dist/templates/har-boilerplate-cli/harness.env +12 -138
  13. package/dist/templates/har-boilerplate-cli/stages.json +42 -2
  14. package/dist/templates/har-boilerplate-ios/harness.env +10 -126
  15. package/dist/templates/har-boilerplate-ios/stages.json +42 -2
  16. package/dist/templates/migration-prompt.md +54 -0
  17. package/dist/templates/plugins/custom-stage-skeleton.sh +11 -20
  18. package/dist/templates/plugins/gitleaks/.github/workflows/gitleaks.yml +1 -1
  19. package/dist/templates/plugins/gitleaks/.har/stages/GITLEAKS.md +1 -1
  20. package/dist/templates/plugins/gitleaks/.har/stages/secrets-scan.sh +8 -23
  21. package/dist/templates/plugins/gitleaks/README.md +1 -1
  22. package/dist/templates/plugins/gitleaks/template.manifest.json +20 -5
  23. package/dist/templates/plugins/kerno/.github/workflows/kerno.yml +1 -1
  24. package/dist/templates/plugins/kerno/.har/stages/backend-validation.sh +8 -23
  25. package/dist/templates/plugins/kerno/README.md +1 -1
  26. package/dist/templates/plugins/kerno/template.manifest.json +20 -9
  27. package/dist/templates/plugins/local-plugin-skeleton/README.md +46 -0
  28. package/dist/templates/plugins/playwright/.har/stages/browser-e2e.sh +8 -23
  29. package/dist/templates/plugins/playwright/template.manifest.json +36 -13
  30. package/dist/templates/plugins/rocketsim/.har/stages/rocketsim-flows.sh +8 -23
  31. package/dist/templates/plugins/rocketsim/template.manifest.json +20 -8
  32. package/dist/templates/plugins/semgrep/.har/stages/sast.sh +10 -26
  33. package/dist/templates/plugins/semgrep/README.md +1 -1
  34. package/dist/templates/plugins/semgrep/template.manifest.json +16 -7
  35. package/dist/templates/plugins/trivy/.har/stages/vuln-scan.sh +8 -23
  36. package/dist/templates/plugins/trivy/README.md +1 -1
  37. package/dist/templates/plugins/trivy/template.manifest.json +20 -8
  38. package/dist/templates/{har-boilerplate-cli/CLAUDE.agent.md → profiles/cli/docs/claude-agent/definition-of-done.md} +0 -42
  39. package/dist/templates/profiles/cli/docs/claude-agent/do-not.md +6 -0
  40. package/dist/templates/profiles/cli/docs/claude-agent/environment.md +12 -0
  41. package/dist/templates/profiles/cli/docs/claude-agent/project-commands.md +10 -0
  42. package/dist/templates/profiles/cli/docs/claude-agent/readiness.md +6 -0
  43. package/dist/templates/profiles/cli/docs/readme/for-coding-agents.md +9 -0
  44. package/dist/templates/profiles/cli/docs/readme/intro.md +7 -0
  45. package/dist/templates/profiles/cli/docs/readme/port-shared-services-cli-profile.md +25 -0
  46. package/dist/templates/profiles/cli/docs/readme/quick-start.md +24 -0
  47. package/dist/templates/profiles/cli/docs/readme/verification-contract.md +22 -0
  48. package/dist/templates/profiles/cli/docs/readme/what-s-in-here.md +27 -0
  49. package/dist/templates/profiles/cli/profile.manifest.json +56 -1
  50. package/dist/templates/profiles/default/docs/claude-agent/definition-of-done.md +24 -0
  51. package/dist/templates/profiles/default/docs/claude-agent/do-not.md +10 -0
  52. package/dist/templates/profiles/default/docs/claude-agent/environment.md +19 -0
  53. package/dist/templates/profiles/default/docs/claude-agent/project-commands.md +10 -0
  54. package/dist/templates/profiles/default/docs/claude-agent/readiness.md +12 -0
  55. package/dist/templates/profiles/default/docs/readme/architecture.md +11 -0
  56. package/dist/templates/profiles/default/docs/readme/for-coding-agents.md +9 -0
  57. package/dist/templates/profiles/default/docs/readme/intro.md +7 -0
  58. package/dist/templates/profiles/default/docs/readme/port-shared-services.md +41 -0
  59. package/dist/templates/profiles/default/docs/readme/quick-start.md +24 -0
  60. package/dist/templates/profiles/default/docs/readme/readiness-layers.md +16 -0
  61. package/dist/templates/profiles/default/docs/readme/verification-contract.md +17 -0
  62. package/dist/templates/profiles/default/docs/readme/what-s-in-here.md +28 -0
  63. package/dist/templates/profiles/default/profile.manifest.json +62 -1
  64. package/dist/templates/profiles/ios/docs/claude-agent/definition-of-done.md +23 -0
  65. package/dist/templates/profiles/ios/docs/claude-agent/do-not.md +6 -0
  66. package/dist/templates/profiles/ios/docs/claude-agent/environment.md +14 -0
  67. package/dist/templates/profiles/ios/docs/claude-agent/intro.md +3 -0
  68. package/dist/templates/profiles/ios/docs/claude-agent/project-commands.md +21 -0
  69. package/dist/templates/profiles/ios/docs/claude-agent/readiness.md +6 -0
  70. package/dist/templates/profiles/ios/docs/claude-agent/user-flow-validation-rocketsim.md +11 -0
  71. package/dist/templates/profiles/ios/docs/readme/configuration.md +7 -0
  72. package/dist/templates/profiles/ios/docs/readme/intro.md +7 -0
  73. package/dist/templates/profiles/ios/docs/readme/port-shared-services-ios-profile.md +25 -0
  74. package/dist/templates/profiles/ios/docs/readme/quick-start.md +22 -0
  75. package/dist/templates/profiles/ios/docs/readme/simulators.md +45 -0
  76. package/dist/templates/profiles/ios/docs/readme/user-flow-validation.md +9 -0
  77. package/dist/templates/profiles/ios/docs/readme/verification-contract.md +13 -0
  78. package/dist/templates/profiles/ios/docs/readme/what-s-in-here.md +27 -0
  79. package/dist/templates/profiles/ios/profile.manifest.json +59 -3
  80. package/dist/templates/runtime-bundles/pm2-runtime/attach.sh +8 -15
  81. package/dist/templates/runtime-bundles/pm2-runtime/env.template +1 -1
  82. package/dist/templates/runtime-bundles/pm2-runtime/stages/api-health.sh +9 -0
  83. package/dist/templates/runtime-bundles/shared-kernel/STAGES.md +32 -18
  84. package/dist/templates/runtime-bundles/shared-kernel/agent-cli.sh +35 -0
  85. package/dist/templates/runtime-bundles/shared-kernel/launch.sh +35 -0
  86. package/dist/templates/runtime-bundles/shared-kernel/lib/verify-runner.mjs +129 -0
  87. package/dist/templates/runtime-bundles/shared-kernel/preflight.sh +35 -0
  88. package/dist/templates/runtime-bundles/shared-kernel/setup-infra.sh +35 -0
  89. package/dist/templates/runtime-bundles/shared-kernel/stages/README.sh +1 -1
  90. package/dist/templates/runtime-bundles/shared-kernel/stages/readiness.sh +14 -0
  91. package/dist/templates/runtime-bundles/shared-kernel/teardown.sh +35 -0
  92. package/dist/templates/runtime-bundles/shared-kernel/verify.sh +35 -0
  93. package/dist/templates/shared-docs/claude-agent/intro.md +3 -0
  94. package/dist/templates/shared-docs/readme/maintaining-this-harness.md +14 -0
  95. package/dist/templates/shared-docs/readme/run-history.md +5 -0
  96. package/dist/templates/shared-docs/readme/session-lifecycle.md +20 -0
  97. package/package.json +1 -1
  98. package/dist/templates/har-boilerplate/CLAUDE.agent.md +0 -83
  99. package/dist/templates/har-boilerplate/README.md +0 -199
  100. package/dist/templates/har-boilerplate/STAGES.md +0 -99
  101. package/dist/templates/har-boilerplate/agent-cli.sh +0 -225
  102. package/dist/templates/har-boilerplate/agent-slot.sh +0 -850
  103. package/dist/templates/har-boilerplate/attach.sh +0 -22
  104. package/dist/templates/har-boilerplate/ecosystem.agent.template.cjs +0 -52
  105. package/dist/templates/har-boilerplate/env.template +0 -40
  106. package/dist/templates/har-boilerplate/launch.sh +0 -323
  107. package/dist/templates/har-boilerplate/preflight.sh +0 -32
  108. package/dist/templates/har-boilerplate/provision-toolchain.sh +0 -766
  109. package/dist/templates/har-boilerplate/setup-infra.sh +0 -178
  110. package/dist/templates/har-boilerplate/stages/README.sh +0 -11
  111. package/dist/templates/har-boilerplate/teardown.sh +0 -87
  112. package/dist/templates/har-boilerplate/verify.sh +0 -249
  113. package/dist/templates/har-boilerplate-cli/README.md +0 -157
  114. package/dist/templates/har-boilerplate-cli/STAGES.md +0 -99
  115. package/dist/templates/har-boilerplate-cli/agent-cli.sh +0 -160
  116. package/dist/templates/har-boilerplate-cli/agent-slot.sh +0 -832
  117. package/dist/templates/har-boilerplate-cli/launch.sh +0 -216
  118. package/dist/templates/har-boilerplate-cli/preflight.sh +0 -28
  119. package/dist/templates/har-boilerplate-cli/provision-toolchain.sh +0 -766
  120. package/dist/templates/har-boilerplate-cli/setup-infra.sh +0 -178
  121. package/dist/templates/har-boilerplate-cli/stages/README.sh +0 -11
  122. package/dist/templates/har-boilerplate-cli/teardown.sh +0 -66
  123. package/dist/templates/har-boilerplate-cli/verify.sh +0 -210
  124. package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +0 -63
  125. package/dist/templates/har-boilerplate-ios/CLAUDE.agent.md +0 -90
  126. package/dist/templates/har-boilerplate-ios/README.md +0 -173
  127. package/dist/templates/har-boilerplate-ios/STAGES.md +0 -99
  128. package/dist/templates/har-boilerplate-ios/agent-cli.sh +0 -149
  129. package/dist/templates/har-boilerplate-ios/agent-slot.sh +0 -479
  130. package/dist/templates/har-boilerplate-ios/launch.sh +0 -206
  131. package/dist/templates/har-boilerplate-ios/provision-toolchain.sh +0 -766
  132. package/dist/templates/har-boilerplate-ios/setup-infra.sh +0 -112
  133. package/dist/templates/har-boilerplate-ios/simulator.sh +0 -492
  134. package/dist/templates/har-boilerplate-ios/stages/README.sh +0 -11
  135. package/dist/templates/har-boilerplate-ios/teardown.sh +0 -68
  136. package/dist/templates/har-boilerplate-ios/verify.sh +0 -185
  137. package/dist/templates/runtime-bundles/pm2-runtime/README.md +0 -4
  138. package/dist/templates/runtime-bundles/shared-kernel/README.md +0 -3
  139. package/dist/templates/runtime-bundles/shared-kernel/provision-toolchain.sh +0 -766
  140. package/dist/templates/runtime-bundles/xcode-sim/README.md +0 -4
  141. package/dist/templates/runtime-bundles/xcode-sim/simulator.sh +0 -492
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Attach to the tmux session for an agent.
3
- #
4
- # Usage: ./.har/attach.sh <agent-id>
5
- set -euo pipefail
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- # shellcheck source=/dev/null
9
- source "$SCRIPT_DIR/harness.env"
10
- # shellcheck source=/dev/null
11
- source "$SCRIPT_DIR/agent-slot.sh"
12
-
13
- AGENT_ID="${1:?Usage: attach.sh <agent-id>}"
14
- SESSION="$(har_tmux_session "$AGENT_ID")"
15
-
16
- if ! tmux has-session -t "$SESSION" 2>/dev/null; then
17
- echo "No tmux session found: $SESSION" >&2
18
- echo "Launch with: ./.har/launch.sh ${AGENT_ID} --claude" >&2
19
- exit 1
20
- fi
21
-
22
- exec tmux attach -t "$SESSION"
@@ -1,52 +0,0 @@
1
- /**
2
- * PM2 Ecosystem Configuration for Agent ${AGENT_ID}
3
- *
4
- * Auto-generated by launch.sh — do not edit manually.
5
- * Customize ecosystem.agent.template.cjs in .har/ to change processes.
6
- */
7
-
8
- // launch.sh writes this file (and .env.agent.N) to the work dir root,
9
- // so __dirname IS the work dir — repo root or the agent's git worktree.
10
- const fs = require('fs');
11
- const path = require('path');
12
-
13
- const agentEnvPath = path.resolve(__dirname, '.env.agent.${AGENT_ID}');
14
- const env = {};
15
- try {
16
- for (const line of fs.readFileSync(agentEnvPath, 'utf8').split('\n')) {
17
- const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/);
18
- if (m && !line.trimStart().startsWith('#')) env[m[1]] = m[2].replace(/^["']|["']$/g, '');
19
- }
20
- } catch {}
21
-
22
- module.exports = {
23
- apps: [
24
- // TODO: Replace with the PRIMARY application's dev processes — the ONE app
25
- // agents modify (HARNESS_PRIMARY_APP in harness.env). In a monolith or
26
- // monorepo with several services, do NOT start them all here: supporting
27
- // services the agent depends on but does not change run ONCE for all slots,
28
- // either as compose services in docker-compose.agent.yml or via an optional
29
- // .har/ecosystem.shared.config.cjs (started by setup-infra.sh, processes
30
- // named "har-shared-<name>", fixed ports). A primary app may still need two
31
- // processes (e.g. api + frontend) — add one entry per process.
32
- // Example Node dev process. Replace with this repo's actual primary app
33
- // command (Rails, Django, Go, Java, etc. should not keep this npm entry).
34
- {
35
- name: 'har-${HARNESS_PROJECT_NAME}-agent-${AGENT_ID}-api',
36
- script: 'npm',
37
- args: 'run dev',
38
- interpreter: 'none',
39
- cwd: __dirname,
40
- env: {
41
- ...env,
42
- NODE_ENV: 'development',
43
- PORT: env.API_PORT || env.PORT,
44
- },
45
- watch: false,
46
- autorestart: true,
47
- kill_timeout: 5000,
48
- merge_logs: true,
49
- time: true,
50
- },
51
- ],
52
- };
@@ -1,40 +0,0 @@
1
- # Agent environment — generated by launch.sh from env.template
2
- # DO NOT EDIT — regenerated on every launch
3
- AGENT_ID=${AGENT_ID}
4
-
5
- # Ports (allocated at launch — may differ from BASE + AGENT_ID × STEP when busy)
6
- PORT=${API_PORT}
7
- FE_PORT=${FE_PORT}
8
- API_PORT=${API_PORT}
9
- DEBUG_PORT=${DEBUG_PORT}
10
-
11
- # PostgreSQL
12
- PGHOST=localhost
13
- PGPORT=${DB_PORT}
14
- PGDATABASE=agent_${AGENT_ID}
15
- PGUSER=postgres
16
- PGPASSWORD=password
17
- DATABASE_URL=postgresql://postgres:password@localhost:${DB_PORT}/agent_${AGENT_ID}
18
-
19
- # Application
20
- NODE_ENV=development
21
- SITE_URL=http://localhost:${API_PORT}
22
- CORS_ORIGIN=http://localhost:${FE_PORT}
23
-
24
- # MinIO / S3 (if enabled)
25
- S3_ENDPOINT=http://localhost:${MINIO_PORT}
26
- S3_ACCESS_KEY=minioadmin
27
- S3_SECRET_KEY=minioadmin
28
- S3_BUCKET=agent-${AGENT_ID}
29
- S3_REGION=us-east-1
30
- S3_FORCE_PATH_STYLE=true
31
-
32
- # Headless browser (if enabled)
33
- HEADLESS_BROWSER_URL=http://localhost:${BROWSER_PORT}
34
-
35
- # Toolchain paths — appended by provision-toolchain.sh during launch
36
- # NODE_BIN= NPM_BIN= PYTHON_BIN= VIRTUAL_ENV= GO_BIN= CARGO_BIN= JAVA_HOME=
37
-
38
- # Mail (if enabled)
39
- SMTP_HOST=localhost
40
- SMTP_PORT=11025
@@ -1,323 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Launches a single agent instance with isolated ports, database, and PM2 processes.
3
- # Every launch starts a FRESH session: any previous session for the slot is torn
4
- # down (its branch is kept) and a new suffixed worktree is created from HEAD.
5
- # Occupied slots always block: run ./.har/teardown.sh (or complete it) first, then relaunch.
6
- #
7
- # Usage: ./.har/launch.sh <agent-id> [--no-worktree] [--claude] [--resume]
8
- set -euo pipefail
9
-
10
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
- REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
12
-
13
- # shellcheck source=/dev/null
14
- source "$SCRIPT_DIR/harness.env"
15
- # shellcheck source=/dev/null
16
- source "$SCRIPT_DIR/agent-slot.sh"
17
-
18
- AGENT_ID="${1:-}"
19
- USE_WORKTREE="${HARNESS_USE_WORKTREE:-true}"
20
- USE_CLAUDE=false
21
- RESUME=false
22
- WORK_UNIT_ID="${HAR_WORK_UNIT_ID:-}"
23
- ATTEMPT_ID="${HAR_ATTEMPT_ID:-}"
24
-
25
- for arg in "$@"; do
26
- case "$arg" in
27
- --no-worktree) USE_WORKTREE=false ;;
28
- --worktree) USE_WORKTREE=true ;;
29
- --claude) USE_CLAUDE=true ;;
30
- --resume) RESUME=true ;;
31
- --work-id=*) WORK_UNIT_ID="${arg#*=}" ;;
32
- --attempt-id=*) ATTEMPT_ID="${arg#*=}" ;;
33
- esac
34
- done
35
-
36
- if [[ -n "$WORK_UNIT_ID" && -z "$ATTEMPT_ID" ]]; then
37
- ATTEMPT_ID="$(node -e 'process.stdout.write(require("crypto").randomUUID())')"
38
- fi
39
- export SLOT_WORK_UNIT_ID="$WORK_UNIT_ID"
40
- export SLOT_ATTEMPT_ID="$ATTEMPT_ID"
41
-
42
- if [[ -z "$AGENT_ID" ]]; then
43
- har_load_agent_slot_limits
44
- echo "Usage: $0 <agent-id> [--no-worktree] [--claude] [--resume]" >&2
45
- echo " agent-id must be between ${HARNESS_AGENT_SLOT_MIN} and ${HARNESS_AGENT_SLOT_MAX}" >&2
46
- exit 1
47
- fi
48
-
49
- validate_agent_id "$AGENT_ID"
50
-
51
- log() { echo "==> [agent-$AGENT_ID] $*" >&2; }
52
-
53
- WORK_DIR="$REPO_ROOT"
54
- WORKTREE_DIR=""
55
- BRANCH=""
56
- SUFFIX=""
57
- BASE_BRANCH=""
58
- BASE_COMMIT=""
59
- ENV_FILE=""
60
- REGISTRY_WRITTEN=false
61
-
62
- if [ "$RESUME" = true ]; then
63
- har_launch_preflight "$AGENT_ID" true || exit $?
64
- eval "$(har_resume_session_assignments "$AGENT_ID")"
65
- REGISTRY_WRITTEN=true
66
- mark_slot_failed() {
67
- local exit_code="$?"
68
- if [ "$exit_code" != "0" ] && [ "$REGISTRY_WRITTEN" = true ]; then
69
- log "Resume failed. Recording failed slot state..."
70
- set +e
71
- SLOT_AGENT_ID="$AGENT_ID" \
72
- SLOT_MODE="$([ "$USE_WORKTREE" = true ] && echo worktree || echo root)" \
73
- SLOT_WORK_DIR="$WORK_DIR" \
74
- SLOT_SUFFIX="${SUFFIX:-}" \
75
- SLOT_WORKTREE_PATH="${WORKTREE_DIR:-}" \
76
- SLOT_BRANCH="${BRANCH:-}" \
77
- SLOT_BASE_BRANCH="${BASE_BRANCH:-}" \
78
- SLOT_BASE_COMMIT="${BASE_COMMIT:-}" \
79
- SLOT_PORTS_JSON="{\"frontend\":${FE_PORT},\"api\":${API_PORT},\"debug\":${DEBUG_PORT},\"db\":${DB_PORT}}" \
80
- SLOT_PREVIEW_URLS_JSON="{\"frontend\":\"http://localhost:${FE_PORT}\",\"api\":\"http://localhost:${API_PORT}\"}" \
81
- SLOT_STATUS="failed" \
82
- SLOT_LAST_ERROR="launch.sh --resume exited with code ${exit_code}" \
83
- write_slot_registry
84
- log " Work dir: ${WORK_DIR}"
85
- log " Env file: ${ENV_FILE}"
86
- log " Recovery: har env launch ${AGENT_ID} --resume # or ./.har/launch.sh ${AGENT_ID} --resume"
87
- fi
88
- }
89
- trap mark_slot_failed EXIT
90
- else
91
- # Preflight before worktree/install — ports, foreign PM2, Docker, occupied slot.
92
- # Occupied slots always block here: teardown/complete first, then relaunch.
93
- har_launch_preflight "$AGENT_ID" || exit $?
94
- fi
95
-
96
- if har_harness_uses_pm2; then
97
- log "Ports: frontend=$FE_PORT api=$API_PORT debug=$DEBUG_PORT"
98
- fi
99
-
100
- # Ensure shared infra is running (persists host ports in .har/state/infra.env).
101
- "$SCRIPT_DIR/setup-infra.sh"
102
- har_load_infra_state
103
- DB_PORT="${AGENT_DB_PORT:-${HARNESS_DB_PORT_DEFAULT:-15432}}"
104
- MINIO_PORT="${AGENT_MINIO_PORT:-${HARNESS_MINIO_PORT_DEFAULT:-19000}}"
105
- BROWSER_PORT="${AGENT_BROWSER_PORT:-${HARNESS_BROWSER_PORT_DEFAULT:-13001}}"
106
-
107
- # Clone agent database from template
108
- if har_infra_enabled db && [ -n "${HARNESS_TEMPLATE_DB:-}" ]; then
109
- AGENT_DB="agent_${AGENT_ID}"
110
- PSQL="har_pg psql -d postgres"
111
- if $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '$AGENT_DB'" | grep -q 1; then
112
- log "Database '$AGENT_DB' already exists."
113
- else
114
- log "Creating database '$AGENT_DB' from template..."
115
- $PSQL -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$HARNESS_TEMPLATE_DB' AND pid <> pg_backend_pid()" >/dev/null 2>&1 || true
116
- har_pg createdb -T "$HARNESS_TEMPLATE_DB" "$AGENT_DB"
117
- log "Database '$AGENT_DB' created."
118
- fi
119
- fi
120
-
121
- # Create MinIO bucket
122
- if har_infra_enabled minio; then
123
- MINIO_BUCKET="agent-${AGENT_ID}"
124
- HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X PUT \
125
- -u "minioadmin:minioadmin" \
126
- "http://localhost:${MINIO_PORT}/${MINIO_BUCKET}/" 2>/dev/null) || true
127
- log "MinIO bucket '$MINIO_BUCKET' ready (HTTP $HTTP_STATUS)."
128
- fi
129
-
130
- # Session worktree (default — use --no-worktree to work in repo root).
131
- if [ "$RESUME" != true ]; then
132
- # Name encodes what the session is based on: <base-branch>-<sha4>-har-agent-<id>-<rand4>.
133
- WORK_DIR="$REPO_ROOT"
134
- WORKTREE_DIR=""
135
- BRANCH=""
136
- SUFFIX=""
137
- BASE_BRANCH="$(git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "detached")"
138
- BASE_COMMIT="$(git -C "$REPO_ROOT" rev-parse HEAD 2>/dev/null || true)"
139
- if [ "$USE_WORKTREE" = true ]; then
140
- SHORT_SHA="$(git -C "$REPO_ROOT" rev-parse --short=4 HEAD)"
141
- SUFFIX="$(LC_ALL=C tr -dc 'a-z0-9' </dev/urandom 2>/dev/null | head -c 4 || true)"
142
- [ -n "$SUFFIX" ] || SUFFIX="$(printf '%04d' $(( RANDOM % 10000 )))"
143
- SESSION_NAME="${BASE_BRANCH//\//-}-${SHORT_SHA}-har-agent-${AGENT_ID}-${SUFFIX}"
144
- BRANCH="$SESSION_NAME"
145
- WORKTREE_DIR="$HOME/worktrees/${SESSION_NAME}"
146
- log "Creating session worktree at $WORKTREE_DIR (branch $BRANCH)..."
147
- git -C "$REPO_ROOT" worktree add "$WORKTREE_DIR" -b "$BRANCH"
148
- REL_PREFIX="$(git -C "$REPO_ROOT" rev-parse --show-prefix 2>/dev/null || true)"
149
- WORK_DIR="${WORKTREE_DIR%/}/${REL_PREFIX}"
150
- WORK_DIR="${WORK_DIR%/}"
151
- else
152
- log "Using repo root (worktree disabled)"
153
- REL_PREFIX="$(git -C "$REPO_ROOT" rev-parse --show-prefix 2>/dev/null || true)"
154
- fi
155
-
156
- GIT_EXCLUDE="$(git -C "$REPO_ROOT" rev-parse --git-common-dir 2>/dev/null)/info/exclude"
157
- if [ -n "$GIT_EXCLUDE" ] && [ -d "$(dirname "$GIT_EXCLUDE")" ]; then
158
- for pattern in '.env.agent.*' 'ecosystem.agent.*.config.cjs' '.har/venv'; do
159
- grep -qxF "$pattern" "$GIT_EXCLUDE" 2>/dev/null || echo "$pattern" >> "$GIT_EXCLUDE"
160
- done
161
- fi
162
-
163
- ENV_FILE="$WORK_DIR/.env.agent.${AGENT_ID}"
164
- log "Generating $ENV_FILE..."
165
- har_regenerate_agent_env_file "$AGENT_ID" "$WORK_DIR" "$ENV_FILE"
166
-
167
- REGISTRY_WRITTEN=false
168
- mark_slot_failed() {
169
- local exit_code="$?"
170
- if [ "$exit_code" != "0" ] && [ "$REGISTRY_WRITTEN" = true ]; then
171
- log "Launch failed after creating the session. Recording failed slot state..."
172
- set +e
173
- SLOT_AGENT_ID="$AGENT_ID" \
174
- SLOT_MODE="$([ "$USE_WORKTREE" = true ] && echo worktree || echo root)" \
175
- SLOT_WORK_DIR="$WORK_DIR" \
176
- SLOT_SUFFIX="${SUFFIX:-}" \
177
- SLOT_WORKTREE_PATH="${WORKTREE_DIR:-}" \
178
- SLOT_BRANCH="${BRANCH:-}" \
179
- SLOT_BASE_BRANCH="${BASE_BRANCH:-}" \
180
- SLOT_BASE_COMMIT="${BASE_COMMIT:-}" \
181
- SLOT_PORTS_JSON="{\"frontend\":${FE_PORT},\"api\":${API_PORT},\"debug\":${DEBUG_PORT},\"db\":${DB_PORT}}" \
182
- SLOT_PREVIEW_URLS_JSON="{\"frontend\":\"http://localhost:${FE_PORT}\",\"api\":\"http://localhost:${API_PORT}\"}" \
183
- SLOT_STATUS="failed" \
184
- SLOT_LAST_ERROR="launch.sh exited with code ${exit_code}" \
185
- write_slot_registry
186
- log " Work dir: ${WORK_DIR}"
187
- log " Env file: ${ENV_FILE}"
188
- log " Recovery: har env launch ${AGENT_ID} --resume # or ./.har/launch.sh ${AGENT_ID} --resume"
189
- fi
190
- }
191
- trap mark_slot_failed EXIT
192
-
193
- SLOT_AGENT_ID="$AGENT_ID" \
194
- SLOT_MODE="$([ "$USE_WORKTREE" = true ] && echo worktree || echo root)" \
195
- SLOT_WORK_DIR="$WORK_DIR" \
196
- SLOT_SUFFIX="${SUFFIX:-}" \
197
- SLOT_WORKTREE_PATH="${WORKTREE_DIR:-}" \
198
- SLOT_BRANCH="${BRANCH:-}" \
199
- SLOT_BASE_BRANCH="${BASE_BRANCH:-}" \
200
- SLOT_BASE_COMMIT="${BASE_COMMIT:-}" \
201
- SLOT_PORTS_JSON="{\"frontend\":${FE_PORT},\"api\":${API_PORT},\"debug\":${DEBUG_PORT},\"db\":${DB_PORT}}" \
202
- SLOT_PREVIEW_URLS_JSON="{\"frontend\":\"http://localhost:${FE_PORT}\",\"api\":\"http://localhost:${API_PORT}\"}" \
203
- SLOT_STATUS="starting" \
204
- write_slot_registry
205
- REGISTRY_WRITTEN=true
206
- else
207
- REL_PREFIX="$(git -C "$REPO_ROOT" rev-parse --show-prefix 2>/dev/null || true)"
208
- log "Resuming session at ${WORK_DIR}"
209
- har_regenerate_agent_env_file "$AGENT_ID" "$WORK_DIR" "$ENV_FILE"
210
- SLOT_AGENT_ID="$AGENT_ID" \
211
- SLOT_MODE="$([ "$USE_WORKTREE" = true ] && echo worktree || echo root)" \
212
- SLOT_WORK_DIR="$WORK_DIR" \
213
- SLOT_SUFFIX="${SUFFIX:-}" \
214
- SLOT_WORKTREE_PATH="${WORKTREE_DIR:-}" \
215
- SLOT_BRANCH="${BRANCH:-}" \
216
- SLOT_BASE_BRANCH="${BASE_BRANCH:-}" \
217
- SLOT_BASE_COMMIT="${BASE_COMMIT:-}" \
218
- SLOT_PORTS_JSON="{\"frontend\":${FE_PORT},\"api\":${API_PORT},\"debug\":${DEBUG_PORT},\"db\":${DB_PORT}}" \
219
- SLOT_PREVIEW_URLS_JSON="{\"frontend\":\"http://localhost:${FE_PORT}\",\"api\":\"http://localhost:${API_PORT}\"}" \
220
- SLOT_STATUS="starting" \
221
- write_slot_registry
222
- fi
223
-
224
- if [ "$RESUME" = true ] && har_toolchain_ready "$WORK_DIR"; then
225
- log "Toolchain already provisioned — skipping install."
226
- else
227
- log "Provisioning toolchain (see harness.env: HARNESS_ECOSYSTEM, HARNESS_INSTALL_CMD)..."
228
- HAR_WORK_DIR="$WORK_DIR" \
229
- HAR_ENV_FILE="$ENV_FILE" \
230
- HAR_WORKTREE_DIR="${WORKTREE_DIR:-}" \
231
- HAR_REL_PREFIX="${REL_PREFIX:-}" \
232
- HAR_AGENT_ID="$AGENT_ID" \
233
- "$SCRIPT_DIR/provision-toolchain.sh"
234
- fi
235
-
236
- if [ -n "${HARNESS_DB_MINIMAL_BOOTSTRAP_CMD:-}" ]; then
237
- log "Running minimal data bootstrap..."
238
- (cd "$WORK_DIR" && set -a && . "$ENV_FILE" && set +a && eval "$HARNESS_DB_MINIMAL_BOOTSTRAP_CMD")
239
- fi
240
-
241
- # Generate PM2 ecosystem config
242
- ECOSYSTEM_FILE="$WORK_DIR/ecosystem.agent.${AGENT_ID}.config.cjs"
243
- log "Generating $ECOSYSTEM_FILE..."
244
- AGENT_ID="$AGENT_ID" \
245
- HARNESS_PROJECT_NAME="$HARNESS_PROJECT_NAME" \
246
- FE_PORT="$FE_PORT" \
247
- DEBUG_PORT="$DEBUG_PORT" \
248
- envsubst '${AGENT_ID} ${HARNESS_PROJECT_NAME} ${FE_PORT} ${DEBUG_PORT}' \
249
- < "$SCRIPT_DIR/ecosystem.agent.template.cjs" > "$ECOSYSTEM_FILE"
250
-
251
- PM2_REGEX="$(har_pm2_delete_regex "$AGENT_ID")"
252
- # Stop existing processes for this agent (project-scoped — never touch other harnesses).
253
- $(har_pkg_exec) pm2 delete "$PM2_REGEX" 2>/dev/null || true
254
-
255
- # Start PM2 processes
256
- log "Starting PM2 processes..."
257
- cd "$WORK_DIR"
258
- $(har_pkg_exec) pm2 start "$ECOSYSTEM_FILE"
259
- $(har_pkg_exec) pm2 save --force >/dev/null 2>&1 || true
260
-
261
- # Health check
262
- if [ -n "${HARNESS_HEALTH_CHECK_PATH:-}" ]; then
263
- HEALTH_URL="http://localhost:${API_PORT}${HARNESS_HEALTH_CHECK_PATH}"
264
- log "Waiting for health check at $HEALTH_URL..."
265
- TIMEOUT=60
266
- ELAPSED=0
267
- while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
268
- HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_URL" 2>/dev/null) || true
269
- if [ "$HTTP_CODE" = "200" ]; then
270
- log "Health check passed!"
271
- break
272
- fi
273
- sleep 2
274
- ELAPSED=$((ELAPSED + 2))
275
- done
276
- if [ "$ELAPSED" -ge "$TIMEOUT" ]; then
277
- log "Warning: Health check did not pass within ${TIMEOUT}s."
278
- log "Check logs: ./.har/agent-cli.sh $AGENT_ID logs"
279
- fi
280
- fi
281
-
282
- # Record the session in the slot registry — the source of truth for where
283
- # this slot's code lives (status/verify/teardown resolve through it).
284
- SLOT_AGENT_ID="$AGENT_ID" \
285
- SLOT_MODE="$([ "$USE_WORKTREE" = true ] && echo worktree || echo root)" \
286
- SLOT_WORK_DIR="$WORK_DIR" \
287
- SLOT_SUFFIX="${SUFFIX:-}" \
288
- SLOT_WORKTREE_PATH="${WORKTREE_DIR:-}" \
289
- SLOT_BRANCH="${BRANCH:-}" \
290
- SLOT_BASE_BRANCH="${BASE_BRANCH:-}" \
291
- SLOT_BASE_COMMIT="${BASE_COMMIT:-}" \
292
- SLOT_PORTS_JSON="{\"frontend\":${FE_PORT},\"api\":${API_PORT},\"debug\":${DEBUG_PORT},\"db\":${DB_PORT}}" \
293
- SLOT_PREVIEW_URLS_JSON="{\"frontend\":\"http://localhost:${FE_PORT}\",\"api\":\"http://localhost:${API_PORT}\"}" \
294
- SLOT_STATUS="active" \
295
- write_slot_registry
296
-
297
- # Launch Claude Code in tmux (optional)
298
- if [ "$USE_CLAUDE" = true ]; then
299
- TMUX_SESSION="$(har_tmux_session "$AGENT_ID")"
300
- if tmux has-session -t "$TMUX_SESSION" 2>/dev/null; then
301
- tmux kill-session -t "$TMUX_SESSION"
302
- fi
303
- tmux new-session -d -s "$TMUX_SESSION" -c "$WORK_DIR" \
304
- "set -a; [ -f '$ENV_FILE' ] && . '$ENV_FILE'; set +a; exec claude"
305
- log "Claude session: tmux attach -t $TMUX_SESSION"
306
- fi
307
-
308
- echo ""
309
- log "Agent $AGENT_ID is ready!"
310
- log ""
311
- log " WORK DIR (make ALL file edits under this path — never the main checkout):"
312
- log " ${WORK_DIR}"
313
- if [ "$USE_WORKTREE" = true ]; then
314
- log " Branch: ${BRANCH} (based on ${BASE_BRANCH} @ ${BASE_COMMIT})"
315
- fi
316
- log " Frontend: http://localhost:${FE_PORT}"
317
- log " API: http://localhost:${API_PORT}"
318
- har_infra_enabled db && log " Database: agent_${AGENT_ID} @ localhost:${DB_PORT}"
319
- log ""
320
- log " Edits under the work dir hot-reload in the running slot;"
321
- log " use ./.har/agent-cli.sh $AGENT_ID restart if a change doesn't take."
322
- log " Verify: ./.har/verify.sh $AGENT_ID"
323
- log " Teardown: ./.har/teardown.sh $AGENT_ID (keeps the branch)"
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Launch readiness gate — run before launch.sh or standalone.
3
- # Usage: ./.har/preflight.sh <agent-id>
4
- # JSON: har env preflight <id> --json
5
- set -euo pipefail
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
9
-
10
- # shellcheck source=/dev/null
11
- source "$SCRIPT_DIR/harness.env"
12
- # shellcheck source=/dev/null
13
- source "$SCRIPT_DIR/agent-slot.sh"
14
-
15
- AGENT_ID="${1:-}"
16
-
17
- if [[ -z "$AGENT_ID" ]]; then
18
- echo "Usage: $0 <agent-id>" >&2
19
- exit 1
20
- fi
21
-
22
- validate_agent_id "$AGENT_ID"
23
-
24
- if har_launch_preflight "$AGENT_ID"; then
25
- echo "Slot ${AGENT_ID}: ready to launch."
26
- if har_harness_uses_pm2; then
27
- echo " Ports: frontend=${FE_PORT} api=${API_PORT} debug=${DEBUG_PORT}"
28
- fi
29
- exit 0
30
- fi
31
-
32
- exit $?