@osfactory/har 0.5.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.
Files changed (36) hide show
  1. package/README.md +2 -0
  2. package/dist/index.js +1817 -651
  3. package/dist/prompts/system-authoring.md +27 -2
  4. package/dist/templates/adaptation-prompt-init.md +60 -5
  5. package/dist/templates/adaptation-prompt-maintain.md +7 -4
  6. package/dist/templates/har-boilerplate/CLAUDE.agent.md +5 -3
  7. package/dist/templates/har-boilerplate/README.md +51 -9
  8. package/dist/templates/har-boilerplate/agent-cli.sh +72 -26
  9. package/dist/templates/har-boilerplate/agent-slot.sh +351 -0
  10. package/dist/templates/har-boilerplate/attach.sh +7 -1
  11. package/dist/templates/har-boilerplate/ecosystem.agent.template.cjs +3 -1
  12. package/dist/templates/har-boilerplate/env.template +4 -1
  13. package/dist/templates/har-boilerplate/harness.env +32 -0
  14. package/dist/templates/har-boilerplate/launch.sh +167 -120
  15. package/dist/templates/har-boilerplate/preflight.sh +41 -0
  16. package/dist/templates/har-boilerplate/provision-toolchain.sh +285 -0
  17. package/dist/templates/har-boilerplate/setup-infra.sh +87 -11
  18. package/dist/templates/har-boilerplate/teardown.sh +2 -1
  19. package/dist/templates/har-boilerplate/verify.sh +91 -11
  20. package/dist/templates/har-boilerplate-cli/CLAUDE.agent.md +5 -2
  21. package/dist/templates/har-boilerplate-cli/README.md +40 -6
  22. package/dist/templates/har-boilerplate-cli/agent-cli.sh +1 -1
  23. package/dist/templates/har-boilerplate-cli/agent-slot.sh +331 -0
  24. package/dist/templates/har-boilerplate-cli/harness.env +13 -0
  25. package/dist/templates/har-boilerplate-cli/launch.sh +140 -95
  26. package/dist/templates/har-boilerplate-cli/preflight.sh +37 -0
  27. package/dist/templates/har-boilerplate-cli/provision-toolchain.sh +285 -0
  28. package/dist/templates/har-boilerplate-cli/setup-infra.sh +87 -11
  29. package/dist/templates/har-boilerplate-cli/verify.sh +93 -12
  30. package/dist/templates/har-boilerplate-ios/README.md +29 -2
  31. package/dist/templates/har-boilerplate-ios/harness.env +6 -1
  32. package/dist/templates/har-boilerplate-ios/launch.sh +8 -13
  33. package/dist/templates/har-boilerplate-ios/provision-toolchain.sh +285 -0
  34. package/dist/templates/har-boilerplate-ios/verify.sh +20 -20
  35. package/package.json +1 -1
  36. package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +0 -57
@@ -79,7 +79,7 @@ fi
79
79
  # whose .gitignore doesn't know about har (applies to all worktrees too).
80
80
  GIT_EXCLUDE="$(git -C "$REPO_ROOT" rev-parse --git-common-dir 2>/dev/null)/info/exclude"
81
81
  if [ -n "$GIT_EXCLUDE" ] && [ -d "$(dirname "$GIT_EXCLUDE")" ]; then
82
- for pattern in '.env.agent.*' 'ecosystem.agent.*.config.cjs'; do
82
+ for pattern in '.env.agent.*' 'ecosystem.agent.*.config.cjs' '.har/venv'; do
83
83
  grep -qxF "$pattern" "$GIT_EXCLUDE" 2>/dev/null || echo "$pattern" >> "$GIT_EXCLUDE"
84
84
  done
85
85
  fi
@@ -134,18 +134,13 @@ SLOT_STATUS="starting" \
134
134
  write_slot_registry
135
135
  REGISTRY_WRITTEN=true
136
136
 
137
- if [ -f "$WORK_DIR/package.json" ]; then
138
- log "Installing dependencies..."
139
- (cd "$WORK_DIR" && npm install --silent)
140
- elif [ -f "$WORK_DIR/go.mod" ]; then
141
- log "Go module detected in work dir (run go mod download if needed)"
142
- fi
143
-
144
- # Monorepo: file:/workspace deps may resolve modules from the repo root — install there too
145
- if [ -n "${REL_PREFIX:-}" ] && [ -f "$WORKTREE_DIR/package.json" ] && [ ! -d "$WORKTREE_DIR/node_modules" ]; then
146
- log "Installing monorepo root dependencies in $WORKTREE_DIR..."
147
- (cd "$WORKTREE_DIR" && npm install --silent)
148
- fi
137
+ log "Provisioning toolchain (see harness.env: HARNESS_ECOSYSTEM, HARNESS_INSTALL_CMD)..."
138
+ HAR_WORK_DIR="$WORK_DIR" \
139
+ HAR_ENV_FILE="$ENV_FILE" \
140
+ HAR_WORKTREE_DIR="${WORKTREE_DIR:-}" \
141
+ HAR_REL_PREFIX="${REL_PREFIX:-}" \
142
+ HAR_AGENT_ID="$AGENT_ID" \
143
+ "$SCRIPT_DIR/provision-toolchain.sh"
149
144
 
150
145
  # Record the session in the slot registry — the source of truth for where
151
146
  # this slot's code lives (status/verify/teardown resolve through it).
@@ -0,0 +1,285 @@
1
+ #!/usr/bin/env bash
2
+ # Provision the project toolchain and append resolved paths to .env.agent.<id>.
3
+ # Called from launch.sh after the agent env file is created.
4
+ #
5
+ # Configure in harness.env:
6
+ # HARNESS_ECOSYSTEM — auto (default) | node | python | go | rust | java | ruby | ios | none
7
+ # HARNESS_INSTALL_CMD — optional override (eval in HAR_WORK_DIR)
8
+ # Ecosystem-specific optional overrides:
9
+ # HARNESS_PYTHON_VENV_DIR — Python venv path relative to HAR_WORK_DIR (default: .har/venv)
10
+ #
11
+ # Required env from caller: HAR_WORK_DIR, HAR_ENV_FILE
12
+ # Optional: HAR_WORKTREE_DIR, HAR_REL_PREFIX, HAR_AGENT_ID (for logging)
13
+ set -euo pipefail
14
+
15
+ : "${HAR_WORK_DIR:?HAR_WORK_DIR is required}"
16
+ : "${HAR_ENV_FILE:?HAR_ENV_FILE is required}"
17
+
18
+ HAR_WORKTREE_DIR="${HAR_WORKTREE_DIR:-}"
19
+ HAR_REL_PREFIX="${HAR_REL_PREFIX:-}"
20
+ HAR_AGENT_ID="${HAR_AGENT_ID:-}"
21
+
22
+ pt_log() {
23
+ if [ -n "$HAR_AGENT_ID" ]; then
24
+ echo "==> [agent-${HAR_AGENT_ID}] toolchain: $*" >&2
25
+ else
26
+ echo "==> [provision-toolchain] $*" >&2
27
+ fi
28
+ }
29
+
30
+ append_env() {
31
+ local key="$1"
32
+ local value="$2"
33
+ printf '%s=%s\n' "$key" "$value" >> "$HAR_ENV_FILE"
34
+ }
35
+
36
+ append_path_prefix() {
37
+ local prefix="$1"
38
+ [ -n "$prefix" ] && [ -d "$prefix" ] || return 0
39
+ append_env "PATH" "${prefix}:${PATH:-$PATH}"
40
+ }
41
+
42
+ detect_ecosystem() {
43
+ local dir="$1"
44
+ local configured="${HARNESS_ECOSYSTEM:-auto}"
45
+ if [ -n "$configured" ] && [ "$configured" != "auto" ]; then
46
+ echo "$configured"
47
+ return
48
+ fi
49
+ if [ -f "$dir/package.json" ]; then echo node; return; fi
50
+ if [ -f "$dir/pyproject.toml" ] || [ -f "$dir/setup.py" ] || [ -f "$dir/setup.cfg" ] \
51
+ || [ -f "$dir/requirements.txt" ] || [ -f "$dir/Pipfile" ]; then
52
+ echo python
53
+ return
54
+ fi
55
+ if [ -f "$dir/go.mod" ]; then echo go; return; fi
56
+ if [ -f "$dir/Cargo.toml" ]; then echo rust; return; fi
57
+ if [ -f "$dir/pom.xml" ] || [ -f "$dir/build.gradle" ] || [ -f "$dir/build.gradle.kts" ]; then
58
+ echo java
59
+ return
60
+ fi
61
+ if [ -f "$dir/Gemfile" ]; then echo ruby; return; fi
62
+ if [ -n "${HARNESS_XCODE_SCHEME:-}" ] || [ -n "${HARNESS_XCODE_PROJECT:-}" ] \
63
+ || [ -n "${HARNESS_XCODE_WORKSPACE:-}" ]; then
64
+ echo ios
65
+ return
66
+ fi
67
+ echo none
68
+ }
69
+
70
+ run_install_cmd() {
71
+ local dir="$1"
72
+ if [ -n "${HARNESS_INSTALL_CMD:-}" ]; then
73
+ pt_log "Running HARNESS_INSTALL_CMD..."
74
+ (cd "$dir" && eval "$HARNESS_INSTALL_CMD")
75
+ return
76
+ fi
77
+ return 1
78
+ }
79
+
80
+ provision_node() {
81
+ local dir="$1"
82
+ local npm_bin="npm"
83
+ local node_bin="node"
84
+
85
+ if ! run_install_cmd "$dir"; then
86
+ pt_log "Installing Node dependencies..."
87
+ if [ -f "$dir/pnpm-lock.yaml" ] && command -v pnpm >/dev/null 2>&1; then
88
+ (cd "$dir" && pnpm install --silent)
89
+ npm_bin="pnpm"
90
+ elif [ -f "$dir/yarn.lock" ] && command -v yarn >/dev/null 2>&1; then
91
+ (cd "$dir" && yarn install --silent)
92
+ npm_bin="yarn"
93
+ else
94
+ (cd "$dir" && npm install --silent)
95
+ fi
96
+ fi
97
+
98
+ if command -v node >/dev/null 2>&1; then
99
+ node_bin="$(command -v node)"
100
+ fi
101
+ if [ "$npm_bin" = "npm" ] && command -v npm >/dev/null 2>&1; then
102
+ npm_bin="$(command -v npm)"
103
+ fi
104
+
105
+ append_env "HARNESS_ECOSYSTEM" "node"
106
+ append_env "NODE_BIN" "$node_bin"
107
+ append_env "NPM_BIN" "$npm_bin"
108
+ append_path_prefix "$dir/node_modules/.bin"
109
+ }
110
+
111
+ provision_python() {
112
+ local dir="$1"
113
+ local venv_rel="${HARNESS_PYTHON_VENV_DIR:-.har/venv}"
114
+ local venv_dir="$dir/$venv_rel"
115
+ local python_bin="python3"
116
+
117
+ if ! command -v python3 >/dev/null 2>&1; then
118
+ pt_log "python3 not found on PATH — skipping venv provisioning"
119
+ append_env "HARNESS_ECOSYSTEM" "python"
120
+ append_env "PYTHON_BIN" "${PYTHON_BIN:-python3}"
121
+ return
122
+ fi
123
+
124
+ if [ ! -d "$venv_dir" ]; then
125
+ pt_log "Creating Python venv at $venv_rel..."
126
+ if ! python3 -m venv "$venv_dir"; then
127
+ rm -rf "$venv_dir"
128
+ pt_log "python3 -m venv failed (on Debian/Ubuntu install python3-venv) — using system python3"
129
+ append_env "HARNESS_ECOSYSTEM" "python"
130
+ append_env "PYTHON_BIN" "$(command -v python3)"
131
+ return
132
+ fi
133
+ fi
134
+
135
+ if [ ! -x "$venv_dir/bin/python" ]; then
136
+ pt_log "Python venv at $venv_rel is missing or broken — using system python3"
137
+ append_env "HARNESS_ECOSYSTEM" "python"
138
+ append_env "PYTHON_BIN" "$(command -v python3)"
139
+ return
140
+ fi
141
+
142
+ python_bin="$venv_dir/bin/python"
143
+ # shellcheck disable=SC1091
144
+ source "$venv_dir/bin/activate"
145
+
146
+ if ! run_install_cmd "$dir"; then
147
+ pt_log "Installing Python dependencies..."
148
+ if [ -f "$dir/pyproject.toml" ]; then
149
+ (cd "$dir" && pip install -q -e ".[dev]" 2>/dev/null) || (cd "$dir" && pip install -q -e .)
150
+ elif [ -f "$dir/requirements.txt" ]; then
151
+ (cd "$dir" && pip install -q -r requirements.txt)
152
+ elif [ -f "$dir/setup.py" ] || [ -f "$dir/setup.cfg" ]; then
153
+ (cd "$dir" && pip install -q -e .)
154
+ elif [ -f "$dir/Pipfile" ] && command -v pipenv >/dev/null 2>&1; then
155
+ (cd "$dir" && pipenv install --dev)
156
+ python_bin="$(cd "$dir" && pipenv --py)"
157
+ fi
158
+ fi
159
+
160
+ append_env "HARNESS_ECOSYSTEM" "python"
161
+ append_env "PYTHON_BIN" "$python_bin"
162
+ append_env "VIRTUAL_ENV" "$venv_dir"
163
+ append_path_prefix "$venv_dir/bin"
164
+ }
165
+
166
+ provision_go() {
167
+ local dir="$1"
168
+ if ! run_install_cmd "$dir"; then
169
+ if command -v go >/dev/null 2>&1; then
170
+ pt_log "Downloading Go modules..."
171
+ (cd "$dir" && go mod download)
172
+ else
173
+ pt_log "go not found on PATH — record paths only"
174
+ fi
175
+ fi
176
+ append_env "HARNESS_ECOSYSTEM" "go"
177
+ append_env "GO_BIN" "$(command -v go 2>/dev/null || echo go)"
178
+ if [ -n "${GOPATH:-}" ]; then append_env "GOPATH" "$GOPATH"; fi
179
+ if [ -n "${GOROOT:-}" ]; then append_env "GOROOT" "$GOROOT"; fi
180
+ }
181
+
182
+ provision_rust() {
183
+ local dir="$1"
184
+ if ! run_install_cmd "$dir"; then
185
+ if command -v cargo >/dev/null 2>&1; then
186
+ pt_log "Fetching Rust dependencies..."
187
+ (cd "$dir" && cargo fetch)
188
+ else
189
+ pt_log "cargo not found on PATH — record paths only"
190
+ fi
191
+ fi
192
+ append_env "HARNESS_ECOSYSTEM" "rust"
193
+ append_env "CARGO_BIN" "$(command -v cargo 2>/dev/null || echo cargo)"
194
+ append_env "RUSTC_BIN" "$(command -v rustc 2>/dev/null || echo rustc)"
195
+ }
196
+
197
+ provision_java() {
198
+ local dir="$1"
199
+ run_install_cmd "$dir" || true
200
+ append_env "HARNESS_ECOSYSTEM" "java"
201
+ if [ -n "${JAVA_HOME:-}" ]; then
202
+ append_env "JAVA_HOME" "$JAVA_HOME"
203
+ append_path_prefix "$JAVA_HOME/bin"
204
+ fi
205
+ if command -v mvn >/dev/null 2>&1; then
206
+ append_env "MVN_BIN" "$(command -v mvn)"
207
+ elif [ -f "$dir/gradlew" ]; then
208
+ append_env "GRADLE_BIN" "$dir/gradlew"
209
+ elif command -v gradle >/dev/null 2>&1; then
210
+ append_env "GRADLE_BIN" "$(command -v gradle)"
211
+ fi
212
+ }
213
+
214
+ provision_ruby() {
215
+ local dir="$1"
216
+ if ! run_install_cmd "$dir"; then
217
+ if command -v bundle >/dev/null 2>&1; then
218
+ pt_log "Installing Ruby gems..."
219
+ (cd "$dir" && bundle install --quiet)
220
+ else
221
+ pt_log "bundle not found on PATH — record paths only"
222
+ fi
223
+ fi
224
+ append_env "HARNESS_ECOSYSTEM" "ruby"
225
+ append_env "RUBY_BIN" "$(command -v ruby 2>/dev/null || echo ruby)"
226
+ append_env "BUNDLE_BIN" "$(command -v bundle 2>/dev/null || echo bundle)"
227
+ append_path_prefix "$dir/vendor/bundle/bin"
228
+ }
229
+
230
+ provision_ios() {
231
+ local dir="$1"
232
+ run_install_cmd "$dir" || true
233
+ append_env "HARNESS_ECOSYSTEM" "ios"
234
+ append_env "XCODEBUILD_BIN" "$(command -v xcodebuild 2>/dev/null || echo xcodebuild)"
235
+ if [ -n "${HARNESS_XCODE_SCHEME:-}" ]; then
236
+ append_env "HARNESS_XCODE_SCHEME" "$HARNESS_XCODE_SCHEME"
237
+ fi
238
+ if [ -n "${HARNESS_SIMULATOR_NAME:-}" ]; then
239
+ append_env "HARNESS_SIMULATOR_NAME" "$HARNESS_SIMULATOR_NAME"
240
+ fi
241
+ if [ -n "${HARNESS_BUNDLE_ID:-}" ]; then
242
+ append_env "HARNESS_BUNDLE_ID" "$HARNESS_BUNDLE_ID"
243
+ fi
244
+ if [ -n "${DEVELOPER_DIR:-}" ]; then
245
+ append_env "DEVELOPER_DIR" "$DEVELOPER_DIR"
246
+ fi
247
+ }
248
+
249
+ provision_monorepo_root() {
250
+ [ -n "$HAR_REL_PREFIX" ] || return 0
251
+ [ -n "$HAR_WORKTREE_DIR" ] || return 0
252
+ [ -f "$HAR_WORKTREE_DIR/package.json" ] || return 0
253
+ [ -d "$HAR_WORKTREE_DIR/node_modules" ] && return 0
254
+ pt_log "Installing monorepo root dependencies in $HAR_WORKTREE_DIR..."
255
+ (cd "$HAR_WORKTREE_DIR" && npm install --silent)
256
+ }
257
+
258
+ provision_ecosystem() {
259
+ local dir="$1"
260
+ local ecosystem
261
+ ecosystem="$(detect_ecosystem "$dir")"
262
+ pt_log "Toolchain ecosystem: ${ecosystem} (work dir: ${dir})"
263
+
264
+ case "$ecosystem" in
265
+ node) provision_node "$dir" ;;
266
+ python) provision_python "$dir" ;;
267
+ go) provision_go "$dir" ;;
268
+ rust) provision_rust "$dir" ;;
269
+ java) provision_java "$dir" ;;
270
+ ruby) provision_ruby "$dir" ;;
271
+ ios) provision_ios "$dir" ;;
272
+ none)
273
+ if run_install_cmd "$dir"; then
274
+ append_env "HARNESS_ECOSYSTEM" "custom"
275
+ else
276
+ pt_log "No ecosystem manifest detected — set HARNESS_ECOSYSTEM or HARNESS_INSTALL_CMD in harness.env"
277
+ append_env "HARNESS_ECOSYSTEM" "none"
278
+ fi
279
+ ;;
280
+ esac
281
+ }
282
+
283
+ append_env "HARNESS_TOOLCHAIN_PROVISIONED" "true"
284
+ provision_ecosystem "$HAR_WORK_DIR"
285
+ provision_monorepo_root
@@ -83,7 +83,7 @@ run_step() {
83
83
  start=$(now_ms)
84
84
 
85
85
  set +e
86
- output=$(cd "$WORK_DIR" && eval "$cmd" 2>&1)
86
+ output=$(cd "$WORK_DIR" && set -a && . "$ENV_FILE" && set +a && eval "$cmd" 2>&1)
87
87
  exit_code=$?
88
88
  set -e
89
89
 
@@ -115,34 +115,34 @@ process.stdout.write(JSON.stringify(arr));
115
115
  fi
116
116
  }
117
117
 
118
- # Quick (default): compile-only — catches syntax errors and missing symbols
119
- run_step "build" "xcodebuild build \
118
+ # Quick (default): compile-only — use XCODEBUILD_BIN from .env.agent.<id> (written by launch)
119
+ run_step "build" '${XCODEBUILD_BIN:-xcodebuild} build \
120
120
  ${XC_FLAGS} \
121
- -scheme \"${XC_SCHEME}\" \
122
- -destination \"${XC_DESTINATION}\" \
123
- -derivedDataPath \"${XC_DERIVED}\" \
121
+ -scheme "${XC_SCHEME}" \
122
+ -destination "${XC_DESTINATION}" \
123
+ -derivedDataPath "${XC_DERIVED}" \
124
124
  CODE_SIGNING_ALLOWED=NO \
125
- | xcbeautify 2>/dev/null || xcodebuild build \
125
+ | xcbeautify 2>/dev/null || ${XCODEBUILD_BIN:-xcodebuild} build \
126
126
  ${XC_FLAGS} \
127
- -scheme \"${XC_SCHEME}\" \
128
- -destination \"${XC_DESTINATION}\" \
129
- -derivedDataPath \"${XC_DERIVED}\" \
130
- CODE_SIGNING_ALLOWED=NO" || { [ -z "$FULL" ] && true; }
127
+ -scheme "${XC_SCHEME}" \
128
+ -destination "${XC_DESTINATION}" \
129
+ -derivedDataPath "${XC_DERIVED}" \
130
+ CODE_SIGNING_ALLOWED=NO' || { [ -z "$FULL" ] && true; }
131
131
 
132
132
  if [ -n "$FULL" ]; then
133
133
  # Full: project-specific checks — add/remove/reorder steps for this repo.
134
- run_step "unit-tests" "xcodebuild test \
134
+ run_step "unit-tests" '${XCODEBUILD_BIN:-xcodebuild} test \
135
135
  ${XC_FLAGS} \
136
- -scheme \"${XC_SCHEME}\" \
137
- -destination \"${XC_DESTINATION}\" \
138
- -derivedDataPath \"${XC_DERIVED}\" \
136
+ -scheme "${XC_SCHEME}" \
137
+ -destination "${XC_DESTINATION}" \
138
+ -derivedDataPath "${XC_DERIVED}" \
139
139
  CODE_SIGNING_ALLOWED=NO \
140
- | xcbeautify 2>/dev/null || xcodebuild test \
140
+ | xcbeautify 2>/dev/null || ${XCODEBUILD_BIN:-xcodebuild} test \
141
141
  ${XC_FLAGS} \
142
- -scheme \"${XC_SCHEME}\" \
143
- -destination \"${XC_DESTINATION}\" \
144
- -derivedDataPath \"${XC_DERIVED}\" \
145
- CODE_SIGNING_ALLOWED=NO" || true
142
+ -scheme "${XC_SCHEME}" \
143
+ -destination "${XC_DESTINATION}" \
144
+ -derivedDataPath "${XC_DERIVED}" \
145
+ CODE_SIGNING_ALLOWED=NO' || true
146
146
 
147
147
  # SwiftLint — optional, skip gracefully when not installed
148
148
  run_step "lint" "command -v \"${HARNESS_SWIFTLINT_CMD:-swiftlint}\" >/dev/null 2>&1 && \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.5.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.