@osfactory/har 0.6.0 → 0.7.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.
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env bash
2
+ # Launch readiness gate for CLI/library harnesses (occupied slot only).
3
+ # Usage: ./.har/preflight.sh <agent-id> [--replace] [--force]
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
8
+
9
+ # shellcheck source=/dev/null
10
+ source "$SCRIPT_DIR/harness.env"
11
+ # shellcheck source=/dev/null
12
+ source "$SCRIPT_DIR/agent-slot.sh"
13
+
14
+ AGENT_ID="${1:-}"
15
+ FORCE=false
16
+ REPLACE=false
17
+
18
+ for arg in "$@"; do
19
+ case "$arg" in
20
+ --replace) REPLACE=true ;;
21
+ --force) FORCE=true ;;
22
+ esac
23
+ done
24
+
25
+ if [[ -z "$AGENT_ID" ]]; then
26
+ echo "Usage: $0 <agent-id> [--replace] [--force]" >&2
27
+ exit 1
28
+ fi
29
+
30
+ validate_agent_id "$AGENT_ID"
31
+
32
+ if har_launch_preflight "$AGENT_ID" "$FORCE" "$REPLACE"; then
33
+ echo "Slot ${AGENT_ID}: ready to launch."
34
+ exit 0
35
+ fi
36
+
37
+ exit $?
@@ -11,26 +11,101 @@ set -euo pipefail
11
11
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
12
  REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
13
13
  COMPOSE_FILE="$SCRIPT_DIR/docker-compose.agent.yml"
14
+ INFRA_STATE="$SCRIPT_DIR/state/infra.env"
14
15
 
15
16
  # shellcheck source=/dev/null
16
17
  source "$SCRIPT_DIR/harness.env"
18
+ # shellcheck source=/dev/null
19
+ source "$SCRIPT_DIR/agent-slot.sh"
17
20
 
18
21
  COMPOSE_PROJECT="har-${HARNESS_PROJECT_NAME}"
19
- DB_PORT="${AGENT_DB_PORT:-15432}"
20
22
  PSQL="har_pg psql -d postgres"
21
23
 
22
24
  log() { echo "==> $*" >&2; }
23
25
 
26
+ har_compose_service_running() {
27
+ local service="$1"
28
+ docker ps --filter "name=${COMPOSE_PROJECT}-${service}-1" --format '{{.Names}}' 2>/dev/null \
29
+ | grep -q "^${COMPOSE_PROJECT}-${service}-1\$"
30
+ }
31
+
32
+ har_resolve_infra_port() {
33
+ local var_name="$1"
34
+ local default_port="$2"
35
+ local scan_start="$3"
36
+ local scan_end="$4"
37
+ local service="${5:-}"
38
+ local current="${!var_name:-}"
39
+
40
+ if [ -n "$current" ] && { ! port_in_use "$current" || { [ -n "$service" ] && har_compose_service_running "$service"; }; }; then
41
+ echo "$current"
42
+ return 0
43
+ fi
44
+ har_allocate_port "$default_port" "$scan_start" "$scan_end"
45
+ }
46
+
47
+ mkdir -p "$(dirname "$INFRA_STATE")"
48
+ if [ -f "$INFRA_STATE" ]; then
49
+ # shellcheck source=/dev/null
50
+ source "$INFRA_STATE"
51
+ fi
52
+
53
+ DB_PORT="$(har_resolve_infra_port AGENT_DB_PORT \
54
+ "${HARNESS_DB_PORT_DEFAULT:-15432}" \
55
+ "${HARNESS_DB_PORT_SCAN_START:-15432}" \
56
+ "${HARNESS_DB_PORT_SCAN_END:-15499}" \
57
+ db)"
58
+ MINIO_PORT="$(har_resolve_infra_port AGENT_MINIO_PORT \
59
+ "${HARNESS_MINIO_PORT_DEFAULT:-19000}" \
60
+ "${HARNESS_MINIO_PORT_SCAN_START:-19000}" \
61
+ "${HARNESS_MINIO_PORT_SCAN_END:-19099}" \
62
+ minio)"
63
+ MINIO_CONSOLE_PORT="$(har_resolve_infra_port AGENT_MINIO_CONSOLE_PORT \
64
+ "${HARNESS_MINIO_CONSOLE_PORT_DEFAULT:-19001}" \
65
+ "${HARNESS_MINIO_CONSOLE_PORT_SCAN_START:-19001}" \
66
+ "${HARNESS_MINIO_CONSOLE_PORT_SCAN_END:-19099}")"
67
+ BROWSER_PORT="$(har_resolve_infra_port AGENT_BROWSER_PORT \
68
+ "${HARNESS_BROWSER_PORT_DEFAULT:-13001}" \
69
+ "${HARNESS_BROWSER_PORT_SCAN_START:-13001}" \
70
+ "${HARNESS_BROWSER_PORT_SCAN_END:-13099}" \
71
+ headless-browser)"
72
+ MAILPIT_WEB_PORT="$(har_resolve_infra_port AGENT_MAILPIT_WEB_PORT \
73
+ "${HARNESS_MAILPIT_WEB_PORT_DEFAULT:-18025}" \
74
+ "${HARNESS_MAILPIT_WEB_PORT_SCAN_START:-18025}" \
75
+ "${HARNESS_MAILPIT_WEB_PORT_SCAN_END:-18099}" \
76
+ mailpit)"
77
+ MAILPIT_SMTP_PORT="$(har_resolve_infra_port AGENT_MAILPIT_SMTP_PORT \
78
+ "${HARNESS_MAILPIT_SMTP_PORT_DEFAULT:-11025}" \
79
+ "${HARNESS_MAILPIT_SMTP_PORT_SCAN_START:-11025}" \
80
+ "${HARNESS_MAILPIT_SMTP_PORT_SCAN_END:-11099}")"
81
+
82
+ export AGENT_DB_PORT="$DB_PORT"
83
+ export AGENT_MINIO_PORT="$MINIO_PORT"
84
+ export AGENT_MINIO_CONSOLE_PORT="$MINIO_CONSOLE_PORT"
85
+ export AGENT_BROWSER_PORT="$BROWSER_PORT"
86
+ export AGENT_MAILPIT_WEB_PORT="$MAILPIT_WEB_PORT"
87
+ export AGENT_MAILPIT_SMTP_PORT="$MAILPIT_SMTP_PORT"
88
+
89
+ cat > "$INFRA_STATE" <<EOF
90
+ # Persisted by setup-infra.sh — host ports for shared docker compose services.
91
+ export AGENT_DB_PORT=${DB_PORT}
92
+ export AGENT_MINIO_PORT=${MINIO_PORT}
93
+ export AGENT_MINIO_CONSOLE_PORT=${MINIO_CONSOLE_PORT}
94
+ export AGENT_BROWSER_PORT=${BROWSER_PORT}
95
+ export AGENT_MAILPIT_WEB_PORT=${MAILPIT_WEB_PORT}
96
+ export AGENT_MAILPIT_SMTP_PORT=${MAILPIT_SMTP_PORT}
97
+ EOF
98
+
24
99
  SERVICES="${HARNESS_INFRA_SERVICES:-}"
25
100
 
26
101
  if [ -n "$SERVICES" ]; then
27
102
  log "Starting shared infrastructure (project: $COMPOSE_PROJECT): $SERVICES"
28
103
  AGENT_DB_PORT="$DB_PORT" \
29
- AGENT_MINIO_PORT="${AGENT_MINIO_PORT:-19000}" \
30
- AGENT_MINIO_CONSOLE_PORT="${AGENT_MINIO_CONSOLE_PORT:-19001}" \
31
- AGENT_BROWSER_PORT="${AGENT_BROWSER_PORT:-13001}" \
32
- AGENT_MAILPIT_WEB_PORT="${AGENT_MAILPIT_WEB_PORT:-18025}" \
33
- AGENT_MAILPIT_SMTP_PORT="${AGENT_MAILPIT_SMTP_PORT:-11025}" \
104
+ AGENT_MINIO_PORT="$MINIO_PORT" \
105
+ AGENT_MINIO_CONSOLE_PORT="$MINIO_CONSOLE_PORT" \
106
+ AGENT_BROWSER_PORT="$BROWSER_PORT" \
107
+ AGENT_MAILPIT_WEB_PORT="$MAILPIT_WEB_PORT" \
108
+ AGENT_MAILPIT_SMTP_PORT="$MAILPIT_SMTP_PORT" \
34
109
  docker compose -p "$COMPOSE_PROJECT" -f "$COMPOSE_FILE" up -d $SERVICES
35
110
  else
36
111
  log "No shared infra services enabled in harness.env (HARNESS_INFRA_SERVICES)"
@@ -85,18 +160,19 @@ fi
85
160
  # Shared app services — supporting services of a monolith/monorepo that agents
86
161
  # depend on but do not modify. Started ONCE on fixed ports, shared by all slots.
87
162
  # Create .har/ecosystem.shared.config.cjs (PM2 format, processes named
88
- # "har-shared-<name>") only when the primary app needs sibling services running.
163
+ # "har-${HARNESS_PROJECT_NAME}-shared-<name>") only when the primary app needs
164
+ # sibling services running.
89
165
  SHARED_ECOSYSTEM="$SCRIPT_DIR/ecosystem.shared.config.cjs"
90
166
  if [ -f "$SHARED_ECOSYSTEM" ]; then
91
167
  log "Starting shared app services from ecosystem.shared.config.cjs..."
92
168
  (cd "$REPO_ROOT" && npx --yes pm2 startOrReload "$SHARED_ECOSYSTEM" >/dev/null)
93
- log "Shared app services running (pm2 ls | grep har-shared-)."
169
+ log "Shared app services running (pm2 ls | grep har-${HARNESS_PROJECT_NAME}-shared-)."
94
170
  fi
95
171
 
96
172
  echo ""
97
173
  log "Infrastructure is ready."
98
174
  har_infra_enabled db && log " PostgreSQL: localhost:$DB_PORT"
99
- har_infra_enabled minio && log " MinIO: http://localhost:${AGENT_MINIO_CONSOLE_PORT:-19001}"
100
- har_infra_enabled headless-browser && log " Browser: http://localhost:${AGENT_BROWSER_PORT:-13001}"
101
- har_infra_enabled mailpit && log " Mailpit: http://localhost:${AGENT_MAILPIT_WEB_PORT:-18025}"
175
+ har_infra_enabled minio && log " MinIO: http://localhost:${MINIO_CONSOLE_PORT}"
176
+ har_infra_enabled headless-browser && log " Browser: http://localhost:${BROWSER_PORT}"
177
+ har_infra_enabled mailpit && log " Mailpit: http://localhost:${MAILPIT_WEB_PORT}"
102
178
  exit 0
@@ -85,6 +85,32 @@ Edit **`harness.env`** to set:
85
85
  - `HARNESS_SIMULATOR_NAME` — target simulator (must be listed in `xcrun simctl list devices`)
86
86
  - `HARNESS_BUNDLE_ID` — app bundle identifier
87
87
 
88
+ ## Port & shared services (iOS profile)
89
+
90
+ Pure iOS apps have **no per-slot TCP ports** — agents build and run on a shared iOS Simulator. Optional backend containers (mock API, etc.) use the same shared-infra model as other profiles.
91
+
92
+ ### Port allocation
93
+
94
+ | Layer | Scope | Rule | On conflict |
95
+ |-------|-------|------|-------------|
96
+ | Optional backend (compose) | Per machine | `HARNESS_*_PORT_DEFAULT` for that service | Scan configured ranges in `harness.env` |
97
+ | iOS Simulator | Shared | No harness port — one booted simulator for all slots | N/A |
98
+
99
+ When your app talks to a local backend, read the resolved host port from `.env.agent.<id>` (set by `setup-infra.sh`) — never hardcode `15432` or similar in tests or flow scripts.
100
+
101
+ ### Shared vs per-slot
102
+
103
+ | Resource | Model | Configuration |
104
+ |----------|-------|---------------|
105
+ | iOS Simulator | One booted simulator shared by all slots | `HARNESS_SIMULATOR_NAME`, `setup-infra.sh` |
106
+ | Optional backend | One shared compose service | `HARNESS_INFRA_SERVICES` (e.g. `"mock-server"`) |
107
+ | Application code | Isolated git worktree per slot | `HARNESS_USE_WORKTREE=true` |
108
+
109
+ ### Do not
110
+
111
+ - Hardcode backend ports in RocketSim flows or unit tests — read from agent env
112
+ - Run raw `docker compose` for harness infrastructure — use `setup-infra.sh`
113
+
88
114
  ## Session lifecycle
89
115
 
90
116
  Every `launch` starts a **fresh session**: a new git worktree from the current HEAD at
@@ -33,8 +33,9 @@ export HARNESS_IOS_DESTINATION="platform=iOS Simulator,name=${HARNESS_SIMULATOR_
33
33
  export HARNESS_SWIFTLINT_CMD="${HARNESS_SWIFTLINT_CMD:-swiftlint}"
34
34
 
35
35
  # ── Infrastructure ────────────────────────────────────────────────────────────
36
- # No Docker infra for pure iOS apps. Set a service name here (space-separated)
36
+ # No Docker infra for pure iOS apps. Set service names here (space-separated)
37
37
  # only if your app needs a local backend container (e.g. a mock server).
38
+ # When enabled, add matching HARNESS_*_PORT_DEFAULT / SCAN_* vars for each service.
38
39
  export HARNESS_INFRA_SERVICES=""
39
40
 
40
41
  # Returns 0 when a shared infra service is enabled: har_infra_enabled mock-server
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "LLM-powered CLI for reproducible agent development environments",
5
5
  "keywords": [
6
6
  "har",
@@ -1,57 +0,0 @@
1
- # Adapt this iOS harness to the project
2
-
3
- You are adapting a freshly scaffolded iOS mobile app harness. Read the existing repo
4
- structure, then make the changes listed below. Commit when done.
5
-
6
- ## 1 — Read before editing
7
-
8
- - `AGENT.md` at the repo root (overview and do-nots)
9
- - `.har/README.md` (harness index)
10
- - `.har/harness.env` (all config vars)
11
- - `.har/stages.json` (stage registry)
12
- - Root of the repo: look for `*.xcworkspace`, `*.xcodeproj`, `Podfile`, `Package.swift`
13
-
14
- ## 2 — Set Xcode project config in `.har/harness.env`
15
-
16
- | Variable | What to set |
17
- |----------|-------------|
18
- | `HARNESS_XCODE_WORKSPACE` | Relative path to `.xcworkspace` (e.g. `MyApp.xcworkspace`). Use when CocoaPods or a workspace is present. Leave empty otherwise. |
19
- | `HARNESS_XCODE_PROJECT` | Relative path to `.xcodeproj` (e.g. `MyApp.xcodeproj`). Only set when no workspace. |
20
- | `HARNESS_XCODE_SCHEME` | Name of the shared Xcode scheme (must be marked Shared in Xcode → Product → Scheme → Manage Schemes). |
21
- | `HARNESS_SIMULATOR_NAME` | Display name exactly as shown in `xcrun simctl list devices` (e.g. `iPhone 16`). |
22
- | `HARNESS_BUNDLE_ID` | App bundle identifier from the Xcode target (e.g. `com.example.myapp`). |
23
-
24
- Run `./.har/setup-infra.sh` after editing to confirm the simulator boots.
25
-
26
- ## 3 — Verify `.har/verify.sh` builds and tests correctly
27
-
28
- Run `./.har/launch.sh 1`, then `./.har/verify.sh 1`.
29
-
30
- Common adaptations:
31
- - If the project uses a custom test plan, add `-testPlan MyTests` to the `xcodebuild test` invocation.
32
- - If SwiftLint is not used, remove or comment out the `lint` step.
33
- - If there are UI tests that require a running app, move them to a RocketSim flow (`har env add-stage rocketsim`) rather than xcodebuild tests.
34
-
35
- ## 4 — Add the RocketSim stage template (recommended)
36
-
37
- ```bash
38
- har env add-stage rocketsim
39
- ```
40
-
41
- Then adapt `flows/example-smoke.sh` to navigate to your app's main screen and verify it loads.
42
- Read `.har/stages/ROCKETSIM.md` for the full authoring guide.
43
-
44
- ## 5 — Update `AGENT.md` (repo root)
45
-
46
- Replace the TODO section with:
47
- - Which Xcode scheme and simulator are used
48
- - How to run unit tests manually
49
- - How to add a new RocketSim user flow
50
-
51
- ## 6 — Verify everything passes
52
-
53
- ```bash
54
- ./.har/verify.sh 1 --full
55
- ```
56
-
57
- All steps should return ✓. Commit the adapted harness in the session worktree.