@osfactory/har 0.64.2 → 1.0.0-rc.2
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/dist/index.js +15751 -6548
- package/dist/prompts/system-authoring.md +155 -0
- package/dist/templates/adaptation-prompt-init.md +67 -43
- package/dist/templates/adaptation-prompt-maintain.md +38 -38
- package/dist/templates/adaptation-prompt-plugin.md +40 -0
- package/dist/templates/agent-skills/har-maintain.md +2 -2
- package/dist/templates/agent-skills/setup-har.md +6 -4
- package/dist/templates/cursor-rule.mdc.template +3 -3
- package/dist/templates/har-boilerplate/docker-compose.agent.yml +1 -1
- package/dist/templates/har-boilerplate/harness.env +11 -155
- package/dist/templates/har-boilerplate/stages.json +51 -2
- package/dist/templates/har-boilerplate-cli/docker-compose.agent.yml +1 -1
- package/dist/templates/har-boilerplate-cli/harness.env +12 -138
- package/dist/templates/har-boilerplate-cli/stages.json +42 -2
- package/dist/templates/har-boilerplate-ios/harness.env +10 -126
- package/dist/templates/har-boilerplate-ios/stages.json +42 -2
- package/dist/templates/migration-prompt.md +54 -0
- package/dist/templates/plugins/custom-stage-skeleton.sh +11 -20
- package/dist/templates/plugins/gitleaks/.github/workflows/gitleaks.yml +1 -1
- package/dist/templates/plugins/gitleaks/.har/stages/GITLEAKS.md +1 -1
- package/dist/templates/plugins/gitleaks/.har/stages/secrets-scan.sh +8 -23
- package/dist/templates/plugins/gitleaks/README.md +1 -1
- package/dist/templates/plugins/gitleaks/template.manifest.json +20 -5
- package/dist/templates/plugins/kerno/.github/workflows/kerno.yml +1 -1
- package/dist/templates/plugins/kerno/.har/stages/backend-validation.sh +8 -23
- package/dist/templates/plugins/kerno/README.md +1 -1
- package/dist/templates/plugins/kerno/template.manifest.json +20 -9
- package/dist/templates/plugins/local-plugin-skeleton/README.md +46 -0
- package/dist/templates/plugins/playwright/.har/stages/browser-e2e.sh +8 -23
- package/dist/templates/plugins/playwright/template.manifest.json +36 -13
- package/dist/templates/plugins/rocketsim/.har/stages/rocketsim-flows.sh +8 -23
- package/dist/templates/plugins/rocketsim/template.manifest.json +20 -8
- package/dist/templates/plugins/semgrep/.har/stages/sast.sh +10 -26
- package/dist/templates/plugins/semgrep/README.md +1 -1
- package/dist/templates/plugins/semgrep/template.manifest.json +16 -7
- package/dist/templates/plugins/trivy/.har/stages/vuln-scan.sh +8 -23
- package/dist/templates/plugins/trivy/README.md +1 -1
- package/dist/templates/plugins/trivy/template.manifest.json +20 -8
- package/dist/templates/{har-boilerplate-cli/CLAUDE.agent.md → profiles/cli/docs/claude-agent/definition-of-done.md} +0 -42
- package/dist/templates/profiles/cli/docs/claude-agent/do-not.md +6 -0
- package/dist/templates/profiles/cli/docs/claude-agent/environment.md +12 -0
- package/dist/templates/profiles/cli/docs/claude-agent/project-commands.md +10 -0
- package/dist/templates/profiles/cli/docs/claude-agent/readiness.md +6 -0
- package/dist/templates/profiles/cli/docs/readme/for-coding-agents.md +9 -0
- package/dist/templates/profiles/cli/docs/readme/intro.md +7 -0
- package/dist/templates/profiles/cli/docs/readme/port-shared-services-cli-profile.md +25 -0
- package/dist/templates/profiles/cli/docs/readme/quick-start.md +24 -0
- package/dist/templates/profiles/cli/docs/readme/verification-contract.md +22 -0
- package/dist/templates/profiles/cli/docs/readme/what-s-in-here.md +27 -0
- package/dist/templates/profiles/cli/profile.manifest.json +56 -1
- package/dist/templates/profiles/default/docs/claude-agent/definition-of-done.md +24 -0
- package/dist/templates/profiles/default/docs/claude-agent/do-not.md +10 -0
- package/dist/templates/profiles/default/docs/claude-agent/environment.md +19 -0
- package/dist/templates/profiles/default/docs/claude-agent/project-commands.md +10 -0
- package/dist/templates/profiles/default/docs/claude-agent/readiness.md +12 -0
- package/dist/templates/profiles/default/docs/readme/architecture.md +11 -0
- package/dist/templates/profiles/default/docs/readme/for-coding-agents.md +9 -0
- package/dist/templates/profiles/default/docs/readme/intro.md +7 -0
- package/dist/templates/profiles/default/docs/readme/port-shared-services.md +41 -0
- package/dist/templates/profiles/default/docs/readme/quick-start.md +24 -0
- package/dist/templates/profiles/default/docs/readme/readiness-layers.md +16 -0
- package/dist/templates/profiles/default/docs/readme/verification-contract.md +17 -0
- package/dist/templates/profiles/default/docs/readme/what-s-in-here.md +28 -0
- package/dist/templates/profiles/default/profile.manifest.json +62 -1
- package/dist/templates/profiles/ios/docs/claude-agent/definition-of-done.md +23 -0
- package/dist/templates/profiles/ios/docs/claude-agent/do-not.md +6 -0
- package/dist/templates/profiles/ios/docs/claude-agent/environment.md +14 -0
- package/dist/templates/profiles/ios/docs/claude-agent/intro.md +3 -0
- package/dist/templates/profiles/ios/docs/claude-agent/project-commands.md +21 -0
- package/dist/templates/profiles/ios/docs/claude-agent/readiness.md +6 -0
- package/dist/templates/profiles/ios/docs/claude-agent/user-flow-validation-rocketsim.md +11 -0
- package/dist/templates/profiles/ios/docs/readme/configuration.md +7 -0
- package/dist/templates/profiles/ios/docs/readme/intro.md +7 -0
- package/dist/templates/profiles/ios/docs/readme/port-shared-services-ios-profile.md +25 -0
- package/dist/templates/profiles/ios/docs/readme/quick-start.md +22 -0
- package/dist/templates/profiles/ios/docs/readme/simulators.md +45 -0
- package/dist/templates/profiles/ios/docs/readme/user-flow-validation.md +9 -0
- package/dist/templates/profiles/ios/docs/readme/verification-contract.md +13 -0
- package/dist/templates/profiles/ios/docs/readme/what-s-in-here.md +27 -0
- package/dist/templates/profiles/ios/profile.manifest.json +59 -3
- package/dist/templates/runtime-bundles/pm2-runtime/attach.sh +8 -15
- package/dist/templates/runtime-bundles/pm2-runtime/env.template +1 -1
- package/dist/templates/runtime-bundles/pm2-runtime/stages/api-health.sh +9 -0
- package/dist/templates/runtime-bundles/shared-kernel/STAGES.md +32 -18
- package/dist/templates/runtime-bundles/shared-kernel/agent-cli.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/launch.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/lib/verify-runner.mjs +129 -0
- package/dist/templates/runtime-bundles/shared-kernel/preflight.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/setup-infra.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/stages/README.sh +1 -1
- package/dist/templates/runtime-bundles/shared-kernel/stages/readiness.sh +14 -0
- package/dist/templates/runtime-bundles/shared-kernel/teardown.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/verify.sh +35 -0
- package/dist/templates/shared-docs/claude-agent/intro.md +3 -0
- package/dist/templates/shared-docs/readme/maintaining-this-harness.md +14 -0
- package/dist/templates/shared-docs/readme/run-history.md +5 -0
- package/dist/templates/shared-docs/readme/session-lifecycle.md +20 -0
- package/package.json +1 -1
- package/dist/templates/har-boilerplate/CLAUDE.agent.md +0 -83
- package/dist/templates/har-boilerplate/README.md +0 -199
- package/dist/templates/har-boilerplate/STAGES.md +0 -99
- package/dist/templates/har-boilerplate/agent-cli.sh +0 -225
- package/dist/templates/har-boilerplate/agent-slot.sh +0 -850
- package/dist/templates/har-boilerplate/attach.sh +0 -22
- package/dist/templates/har-boilerplate/ecosystem.agent.template.cjs +0 -52
- package/dist/templates/har-boilerplate/env.template +0 -40
- package/dist/templates/har-boilerplate/launch.sh +0 -323
- package/dist/templates/har-boilerplate/preflight.sh +0 -32
- package/dist/templates/har-boilerplate/provision-toolchain.sh +0 -766
- package/dist/templates/har-boilerplate/setup-infra.sh +0 -178
- package/dist/templates/har-boilerplate/stages/README.sh +0 -11
- package/dist/templates/har-boilerplate/teardown.sh +0 -87
- package/dist/templates/har-boilerplate/verify.sh +0 -249
- package/dist/templates/har-boilerplate-cli/README.md +0 -157
- package/dist/templates/har-boilerplate-cli/STAGES.md +0 -99
- package/dist/templates/har-boilerplate-cli/agent-cli.sh +0 -160
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +0 -832
- package/dist/templates/har-boilerplate-cli/launch.sh +0 -216
- package/dist/templates/har-boilerplate-cli/preflight.sh +0 -28
- package/dist/templates/har-boilerplate-cli/provision-toolchain.sh +0 -766
- package/dist/templates/har-boilerplate-cli/setup-infra.sh +0 -178
- package/dist/templates/har-boilerplate-cli/stages/README.sh +0 -11
- package/dist/templates/har-boilerplate-cli/teardown.sh +0 -66
- package/dist/templates/har-boilerplate-cli/verify.sh +0 -210
- package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +0 -63
- package/dist/templates/har-boilerplate-ios/CLAUDE.agent.md +0 -90
- package/dist/templates/har-boilerplate-ios/README.md +0 -173
- package/dist/templates/har-boilerplate-ios/STAGES.md +0 -99
- package/dist/templates/har-boilerplate-ios/agent-cli.sh +0 -149
- package/dist/templates/har-boilerplate-ios/agent-slot.sh +0 -479
- package/dist/templates/har-boilerplate-ios/launch.sh +0 -206
- package/dist/templates/har-boilerplate-ios/provision-toolchain.sh +0 -766
- package/dist/templates/har-boilerplate-ios/setup-infra.sh +0 -112
- package/dist/templates/har-boilerplate-ios/simulator.sh +0 -492
- package/dist/templates/har-boilerplate-ios/stages/README.sh +0 -11
- package/dist/templates/har-boilerplate-ios/teardown.sh +0 -68
- package/dist/templates/har-boilerplate-ios/verify.sh +0 -185
- package/dist/templates/runtime-bundles/pm2-runtime/README.md +0 -4
- package/dist/templates/runtime-bundles/shared-kernel/README.md +0 -3
- package/dist/templates/runtime-bundles/shared-kernel/provision-toolchain.sh +0 -766
- package/dist/templates/runtime-bundles/xcode-sim/README.md +0 -4
- 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 $?
|