@osfactory/har 0.14.0 → 0.15.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 (26) hide show
  1. package/dist/index.js +829 -718
  2. package/dist/prompts/system-authoring.md +1 -1
  3. package/dist/templates/adaptation-prompt-init.md +1 -1
  4. package/dist/templates/cursor-rule.mdc.template +3 -3
  5. package/dist/templates/har-boilerplate/README.md +1 -1
  6. package/dist/templates/har-boilerplate/agent-cli.sh +1 -1
  7. package/dist/templates/har-boilerplate/agent-slot.sh +38 -1
  8. package/dist/templates/har-boilerplate/gitignore.template +15 -0
  9. package/dist/templates/har-boilerplate/harness.env +2 -1
  10. package/dist/templates/har-boilerplate/launch.sh +3 -2
  11. package/dist/templates/har-boilerplate/verify.sh +2 -1
  12. package/dist/templates/har-boilerplate-cli/agent-cli.sh +2 -2
  13. package/dist/templates/har-boilerplate-cli/agent-slot.sh +38 -1
  14. package/dist/templates/har-boilerplate-cli/gitignore.template +15 -0
  15. package/dist/templates/har-boilerplate-cli/launch.sh +3 -2
  16. package/dist/templates/har-boilerplate-cli/verify.sh +2 -1
  17. package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +57 -0
  18. package/dist/templates/har-boilerplate-ios/agent-cli.sh +2 -2
  19. package/dist/templates/har-boilerplate-ios/agent-slot.sh +38 -1
  20. package/dist/templates/har-boilerplate-ios/gitignore.template +16 -0
  21. package/dist/templates/har-boilerplate-ios/launch.sh +1 -0
  22. package/dist/templates/har-boilerplate-ios/verify.sh +2 -1
  23. package/dist/templates/stage-templates/custom-stage-skeleton.sh +2 -1
  24. package/dist/templates/stage-templates/playwright/.har/stages/browser-e2e.sh +2 -1
  25. package/dist/templates/stage-templates/rocketsim/.har/stages/rocketsim-flows.sh +2 -1
  26. package/package.json +1 -1
@@ -127,7 +127,7 @@ Document ports in `.har/README.md` and configure them in `.har/harness.env`. Res
127
127
 
128
128
  CLI and iOS profiles typically have no per-slot app ports; optional backends still use the shared-infra model.
129
129
 
130
- Set slot limits in `.har/stages.json` (`agentSlots`) and `.har/harness.env` (`HARNESS_AGENT_SLOT_MIN` / `HARNESS_AGENT_SLOT_MAX`) based on machine capacity.
130
+ Set slot limits in `.har/stages.json` (`agentSlots`) based on machine capacity. `har env maintain --finalize` syncs legacy `HARNESS_AGENT_SLOT_*` exports in `harness.env`.
131
131
 
132
132
  ### Do not
133
133
 
@@ -153,7 +153,7 @@ Document and configure ports in `.har/harness.env` and `.har/README.md`. Use the
153
153
  | Mailpit | `HARNESS_MAILPIT_*_PORT_DEFAULT` | Scan configured ranges |
154
154
  | Headless browser | `HARNESS_BROWSER_PORT_DEFAULT` | Scan configured ranges |
155
155
 
156
- Set slot limits in `.har/stages.json` (`agentSlots`) and `.har/harness.env` (`HARNESS_AGENT_SLOT_MIN` / `HARNESS_AGENT_SLOT_MAX`) based on machine capacity.
156
+ Set slot limits in `.har/stages.json` (`agentSlots`) based on machine capacity. `har env maintain --finalize` syncs legacy `HARNESS_AGENT_SLOT_*` exports in `harness.env`.
157
157
 
158
158
  **Port / infra checklist:**
159
159
 
@@ -15,8 +15,8 @@ work around it with ad-hoc commands.
15
15
 
16
16
  ## Before making changes
17
17
 
18
- 1. **Launch your slot FIRST — before editing any file.** Use `har_launch_environment` with `agentId: 1` (MCP), `har env launch 1`, or `./.har/launch.sh 1`. Launch always creates a **fresh session worktree** from the current HEAD and returns its **work dir**.
19
- 2. **Make ALL file edits under the returned work dir — never in the main checkout.** The work dir looks like `~/worktrees/<base-branch>-<sha4>-har-agent-<id>-<rand4>` (recorded in `.har/slots/agent-<id>.json`). Edits there hot-reload in the running slot; use `./.har/agent-cli.sh <id> restart` if a change doesn't take.
18
+ 1. **Launch your slot FIRST — before editing any file.** Use `har_launch_environment` with `agentId: 1` (MCP) or `har env launch 1`. Launch always creates a **fresh session worktree** from the current HEAD and returns its **work dir**.
19
+ 2. **Make ALL file edits under the returned work dir — never in the main checkout.** The work dir looks like `~/worktrees/<base-branch>-<sha4>-har-agent-<id>-<rand4>` (recorded in `.har/slots/agent-<id>.json`). Edits there hot-reload in the running slot; use `har env restart <id>` or `./.har/agent-cli.sh <id> restart` if a change doesn't take.
20
20
  3. Read [AGENT.md](./AGENT.md) at the repo root
21
21
  4. Read [.har/README.md](./.har/README.md) and [.har/stages.json](./.har/stages.json)
22
22
  5. After launch, read [.har/CLAUDE.agent.md](./.har/CLAUDE.agent.md) for slot URLs and definition of done
@@ -26,7 +26,7 @@ Relaunching a slot **replaces** its previous session (the old branch is kept). R
26
26
  ### Slot safety (read before launch)
27
27
 
28
28
  - **One slot ≈ one task** — do not share slot 1 across unrelated chats; use slot 2+ for parallel work.
29
- - **Call `har_get_status` / `./.har/agent-cli.sh <id> status`** before launch when a slot may be occupied.
29
+ - **Call `har_get_status` / `har env status`** before launch when a slot may be occupied.
30
30
  - **Never** set `force`/`confirmReplace` without the user explicitly approving replacement.
31
31
  - **Commit early and often** in the session worktree — teardown keeps the branch, not uncommitted work.
32
32
  - **Gitignored paths are ephemeral** (`state/`, `runs/`, local clones) — they are lost when the worktree is removed.
@@ -115,7 +115,7 @@ Always use `./.har/agent-cli.sh <id> ...` — never hardcoded ports.
115
115
 
116
116
  Each agent slot gets isolated app ports. Defaults follow `BASE + (AGENT_ID × HARNESS_PORT_STEP)`; when a default is busy, `launch.sh` scans the slot lane (`STEP` increments) and writes the resolved ports to `.env.agent.<id>` and `.har/slots/agent-<id>.json`.
117
117
 
118
- Configure how many slots your machine can run in parallel in `stages.json` (`agentSlots`) and `harness.env` (`HARNESS_AGENT_SLOT_MIN` / `HARNESS_AGENT_SLOT_MAX`). Keep both in sync.
118
+ Configure how many slots your machine can run in parallel in `.har/stages.json` (`agentSlots`). Bash scripts and the CLI read that first; `harness.env` keeps legacy `HARNESS_AGENT_SLOT_*` exports in sync via `har env maintain --finalize`.
119
119
 
120
120
  | Service | Agent 1 (default) | Agent 2 (default) |
121
121
  |---------|-------------------|-------------------|
@@ -116,7 +116,7 @@ process.stdin.on('end', () => {
116
116
  echo " API: http://localhost:${API_PORT}"
117
117
  else
118
118
  echo "No active environment for agent ${AGENT_ID}"
119
- echo " Run: ./.har/launch.sh ${AGENT_ID}"
119
+ har_suggest_launch "$AGENT_ID"
120
120
  fi
121
121
  ;;
122
122
 
@@ -5,13 +5,50 @@
5
5
  # source "$SCRIPT_DIR/agent-slot.sh"
6
6
  # validate_agent_id "$AGENT_ID"
7
7
 
8
+ # Canonical slot limits live in stages.json (agentSlots); harness.env is legacy fallback.
9
+ har_load_agent_slot_limits() {
10
+ local registry="${SCRIPT_DIR}/stages.json"
11
+ if [[ -f "$registry" ]]; then
12
+ local parsed
13
+ parsed="$(node -e '
14
+ try {
15
+ const slots = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")).agentSlots;
16
+ if (slots && Number.isInteger(slots.min) && Number.isInteger(slots.max)) {
17
+ process.stdout.write(String(slots.min) + " " + String(slots.max));
18
+ }
19
+ } catch {}
20
+ ' "$registry" 2>/dev/null || true)"
21
+ if [[ -n "$parsed" ]]; then
22
+ HARNESS_AGENT_SLOT_MIN="${parsed%% *}"
23
+ HARNESS_AGENT_SLOT_MAX="${parsed#* }"
24
+ export HARNESS_AGENT_SLOT_MIN HARNESS_AGENT_SLOT_MAX
25
+ return 0
26
+ fi
27
+ fi
28
+ }
29
+
30
+ har_suggest_launch() {
31
+ local id="$1"
32
+ echo " Launch: har env launch ${id} # or har_launch_environment (MCP)" >&2
33
+ echo " Fallback: ./.har/launch.sh ${id} # when har CLI/MCP unavailable" >&2
34
+ }
35
+
36
+ har_suggest_status() {
37
+ local id="${1:-}"
38
+ echo " Status: har env status # or har_get_status (MCP)" >&2
39
+ if [[ -n "$id" ]]; then
40
+ echo " Fallback: ./.har/agent-cli.sh ${id} status" >&2
41
+ fi
42
+ }
43
+
8
44
  validate_agent_id() {
9
45
  local id="${1:-}"
46
+ har_load_agent_slot_limits
10
47
  local min="${HARNESS_AGENT_SLOT_MIN:-1}"
11
48
  local max="${HARNESS_AGENT_SLOT_MAX:-}"
12
49
 
13
50
  if [[ -z "$max" ]]; then
14
- echo "Error: HARNESS_AGENT_SLOT_MAX is not set in harness.env" >&2
51
+ echo "Error: configure agentSlots in .har/stages.json or HARNESS_AGENT_SLOT_MAX in harness.env" >&2
15
52
  exit 1
16
53
  fi
17
54
 
@@ -0,0 +1,15 @@
1
+ # Ephemeral harness output — safe to delete
2
+ logs/
3
+ runs/
4
+ validations/
5
+ artifacts/
6
+ state/
7
+ maintain/
8
+ ADAPT-PROMPT.md
9
+ AGENT.md.proposed
10
+ AGENT.md.proposed.meta.json
11
+ slots/
12
+
13
+ # Generated by launch.sh (also listed in repo-root .gitignore)
14
+ .env.agent.*
15
+ ecosystem.agent.*.config.cjs
@@ -42,7 +42,8 @@ export HARNESS_MAILPIT_SMTP_PORT_DEFAULT=11025
42
42
  export HARNESS_MAILPIT_SMTP_PORT_SCAN_START=11025
43
43
  export HARNESS_MAILPIT_SMTP_PORT_SCAN_END=11099
44
44
 
45
- # Agent slot limits — set based on what your machine can run in parallel
45
+ # Agent slot limits — canonical source: .har/stages.json (agentSlots).
46
+ # Legacy fallback below; har env maintain --finalize syncs these from stages.json.
46
47
  export HARNESS_AGENT_SLOT_MIN=1
47
48
  export HARNESS_AGENT_SLOT_MAX=5
48
49
 
@@ -35,6 +35,7 @@ for arg in "$@"; do
35
35
  done
36
36
 
37
37
  if [[ -z "$AGENT_ID" ]]; then
38
+ har_load_agent_slot_limits
38
39
  echo "Usage: $0 <agent-id> [--no-worktree] [--claude] [--replace] [--force] [--resume] [--purpose=label]" >&2
39
40
  echo " agent-id must be between ${HARNESS_AGENT_SLOT_MIN} and ${HARNESS_AGENT_SLOT_MAX}" >&2
40
41
  exit 1
@@ -78,7 +79,7 @@ if [ "$RESUME" = true ]; then
78
79
  write_slot_registry
79
80
  log " Work dir: ${WORK_DIR}"
80
81
  log " Env file: ${ENV_FILE}"
81
- log " Recovery: ./.har/launch.sh ${AGENT_ID} --resume"
82
+ log " Recovery: har env launch ${AGENT_ID} --resume # or ./.har/launch.sh ${AGENT_ID} --resume"
82
83
  fi
83
84
  }
84
85
  trap mark_slot_failed EXIT
@@ -186,7 +187,7 @@ if [ "$RESUME" != true ]; then
186
187
  write_slot_registry
187
188
  log " Work dir: ${WORK_DIR}"
188
189
  log " Env file: ${ENV_FILE}"
189
- log " Recovery: ./.har/launch.sh ${AGENT_ID} --resume"
190
+ log " Recovery: har env launch ${AGENT_ID} --resume # or ./.har/launch.sh ${AGENT_ID} --resume"
190
191
  fi
191
192
  }
192
193
  trap mark_slot_failed EXIT
@@ -30,7 +30,8 @@ validate_agent_id "$AGENT_ID"
30
30
  API_PORT=$(( HARNESS_API_BASE_PORT + AGENT_ID * 10 ))
31
31
 
32
32
  ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
33
- echo "No .env.agent.${AGENT_ID} found. Run: ./.har/launch.sh ${AGENT_ID}" >&2
33
+ echo "No .env.agent.${AGENT_ID} found." >&2
34
+ har_suggest_launch "$AGENT_ID" >&2
34
35
  exit 1
35
36
  }
36
37
 
@@ -25,7 +25,7 @@ resolve_work_dir() {
25
25
  local env_file
26
26
  env_file="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
27
27
  echo "No active environment for agent ${AGENT_ID}" >&2
28
- echo " Run: ./.har/launch.sh ${AGENT_ID}" >&2
28
+ har_suggest_launch "$AGENT_ID"
29
29
  exit 1
30
30
  }
31
31
  # shellcheck source=/dev/null
@@ -54,7 +54,7 @@ case "$COMMAND" in
54
54
  [ -n "$WT" ] && echo " Git: $(slot_dirty_summary "$WT")"
55
55
  else
56
56
  echo "No active environment for agent ${AGENT_ID}"
57
- echo " Run: ./.har/launch.sh ${AGENT_ID}"
57
+ har_suggest_launch "$AGENT_ID"
58
58
  fi
59
59
  ;;
60
60
 
@@ -5,13 +5,50 @@
5
5
  # source "$SCRIPT_DIR/agent-slot.sh"
6
6
  # validate_agent_id "$AGENT_ID"
7
7
 
8
+ # Canonical slot limits live in stages.json (agentSlots); harness.env is legacy fallback.
9
+ har_load_agent_slot_limits() {
10
+ local registry="${SCRIPT_DIR}/stages.json"
11
+ if [[ -f "$registry" ]]; then
12
+ local parsed
13
+ parsed="$(node -e '
14
+ try {
15
+ const slots = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")).agentSlots;
16
+ if (slots && Number.isInteger(slots.min) && Number.isInteger(slots.max)) {
17
+ process.stdout.write(String(slots.min) + " " + String(slots.max));
18
+ }
19
+ } catch {}
20
+ ' "$registry" 2>/dev/null || true)"
21
+ if [[ -n "$parsed" ]]; then
22
+ HARNESS_AGENT_SLOT_MIN="${parsed%% *}"
23
+ HARNESS_AGENT_SLOT_MAX="${parsed#* }"
24
+ export HARNESS_AGENT_SLOT_MIN HARNESS_AGENT_SLOT_MAX
25
+ return 0
26
+ fi
27
+ fi
28
+ }
29
+
30
+ har_suggest_launch() {
31
+ local id="$1"
32
+ echo " Launch: har env launch ${id} # or har_launch_environment (MCP)" >&2
33
+ echo " Fallback: ./.har/launch.sh ${id} # when har CLI/MCP unavailable" >&2
34
+ }
35
+
36
+ har_suggest_status() {
37
+ local id="${1:-}"
38
+ echo " Status: har env status # or har_get_status (MCP)" >&2
39
+ if [[ -n "$id" ]]; then
40
+ echo " Fallback: ./.har/agent-cli.sh ${id} status" >&2
41
+ fi
42
+ }
43
+
8
44
  validate_agent_id() {
9
45
  local id="${1:-}"
46
+ har_load_agent_slot_limits
10
47
  local min="${HARNESS_AGENT_SLOT_MIN:-1}"
11
48
  local max="${HARNESS_AGENT_SLOT_MAX:-}"
12
49
 
13
50
  if [[ -z "$max" ]]; then
14
- echo "Error: HARNESS_AGENT_SLOT_MAX is not set in harness.env" >&2
51
+ echo "Error: configure agentSlots in .har/stages.json or HARNESS_AGENT_SLOT_MAX in harness.env" >&2
15
52
  exit 1
16
53
  fi
17
54
 
@@ -0,0 +1,15 @@
1
+ # Ephemeral harness output — safe to delete
2
+ logs/
3
+ runs/
4
+ validations/
5
+ artifacts/
6
+ state/
7
+ maintain/
8
+ ADAPT-PROMPT.md
9
+ AGENT.md.proposed
10
+ AGENT.md.proposed.meta.json
11
+ slots/
12
+
13
+ # Generated by launch.sh (also listed in repo-root .gitignore)
14
+ .env.agent.*
15
+ ecosystem.agent.*.config.cjs
@@ -33,6 +33,7 @@ for arg in "$@"; do
33
33
  done
34
34
 
35
35
  if [[ -z "$AGENT_ID" ]]; then
36
+ har_load_agent_slot_limits
36
37
  echo "Usage: $0 <agent-id> [--no-worktree] [--replace] [--force] [--resume] [--purpose=label]" >&2
37
38
  echo " agent-id must be between ${HARNESS_AGENT_SLOT_MIN} and ${HARNESS_AGENT_SLOT_MAX}" >&2
38
39
  exit 1
@@ -74,7 +75,7 @@ if [ "$RESUME" = true ]; then
74
75
  write_slot_registry
75
76
  log " Work dir: ${WORK_DIR}"
76
77
  log " Env file: ${ENV_FILE}"
77
- log " Recovery: ./.har/launch.sh ${AGENT_ID} --resume"
78
+ log " Recovery: har env launch ${AGENT_ID} --resume # or ./.har/launch.sh ${AGENT_ID} --resume"
78
79
  fi
79
80
  }
80
81
  trap mark_slot_failed EXIT
@@ -145,7 +146,7 @@ if [ "$RESUME" != true ]; then
145
146
  write_slot_registry
146
147
  log " Work dir: ${WORK_DIR}"
147
148
  log " Env file: ${ENV_FILE}"
148
- log " Recovery: ./.har/launch.sh ${AGENT_ID} --resume"
149
+ log " Recovery: har env launch ${AGENT_ID} --resume # or ./.har/launch.sh ${AGENT_ID} --resume"
149
150
  fi
150
151
  }
151
152
  trap mark_slot_failed EXIT
@@ -28,7 +28,8 @@ done
28
28
  validate_agent_id "$AGENT_ID"
29
29
 
30
30
  ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
31
- echo "No .env.agent.${AGENT_ID} found. Run: ./.har/launch.sh ${AGENT_ID}" >&2
31
+ echo "No .env.agent.${AGENT_ID} found." >&2
32
+ har_suggest_launch "$AGENT_ID" >&2
32
33
  exit 1
33
34
  }
34
35
 
@@ -0,0 +1,57 @@
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.
@@ -23,7 +23,7 @@ resolve_work_dir() {
23
23
  local env_file
24
24
  env_file="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
25
25
  echo "No active environment for agent ${AGENT_ID}" >&2
26
- echo " Run: ./.har/launch.sh ${AGENT_ID}" >&2
26
+ har_suggest_launch "$AGENT_ID"
27
27
  exit 1
28
28
  }
29
29
  # shellcheck source=/dev/null
@@ -46,7 +46,7 @@ case "$COMMAND" in
46
46
  echo " Bundle ID: ${HARNESS_BUNDLE_ID:-not set}"
47
47
  else
48
48
  echo "No active environment for agent ${AGENT_ID}"
49
- echo " Run: ./.har/launch.sh ${AGENT_ID}"
49
+ har_suggest_launch "$AGENT_ID"
50
50
  fi
51
51
  ;;
52
52
 
@@ -5,13 +5,50 @@
5
5
  # source "$SCRIPT_DIR/agent-slot.sh"
6
6
  # validate_agent_id "$AGENT_ID"
7
7
 
8
+ # Canonical slot limits live in stages.json (agentSlots); harness.env is legacy fallback.
9
+ har_load_agent_slot_limits() {
10
+ local registry="${SCRIPT_DIR}/stages.json"
11
+ if [[ -f "$registry" ]]; then
12
+ local parsed
13
+ parsed="$(node -e '
14
+ try {
15
+ const slots = JSON.parse(require("fs").readFileSync(process.argv[1], "utf8")).agentSlots;
16
+ if (slots && Number.isInteger(slots.min) && Number.isInteger(slots.max)) {
17
+ process.stdout.write(String(slots.min) + " " + String(slots.max));
18
+ }
19
+ } catch {}
20
+ ' "$registry" 2>/dev/null || true)"
21
+ if [[ -n "$parsed" ]]; then
22
+ HARNESS_AGENT_SLOT_MIN="${parsed%% *}"
23
+ HARNESS_AGENT_SLOT_MAX="${parsed#* }"
24
+ export HARNESS_AGENT_SLOT_MIN HARNESS_AGENT_SLOT_MAX
25
+ return 0
26
+ fi
27
+ fi
28
+ }
29
+
30
+ har_suggest_launch() {
31
+ local id="$1"
32
+ echo " Launch: har env launch ${id} # or har_launch_environment (MCP)" >&2
33
+ echo " Fallback: ./.har/launch.sh ${id} # when har CLI/MCP unavailable" >&2
34
+ }
35
+
36
+ har_suggest_status() {
37
+ local id="${1:-}"
38
+ echo " Status: har env status # or har_get_status (MCP)" >&2
39
+ if [[ -n "$id" ]]; then
40
+ echo " Fallback: ./.har/agent-cli.sh ${id} status" >&2
41
+ fi
42
+ }
43
+
8
44
  validate_agent_id() {
9
45
  local id="${1:-}"
46
+ har_load_agent_slot_limits
10
47
  local min="${HARNESS_AGENT_SLOT_MIN:-1}"
11
48
  local max="${HARNESS_AGENT_SLOT_MAX:-}"
12
49
 
13
50
  if [[ -z "$max" ]]; then
14
- echo "Error: HARNESS_AGENT_SLOT_MAX is not set in harness.env" >&2
51
+ echo "Error: configure agentSlots in .har/stages.json or HARNESS_AGENT_SLOT_MAX in harness.env" >&2
15
52
  exit 1
16
53
  fi
17
54
 
@@ -0,0 +1,16 @@
1
+ # Ephemeral harness output — safe to delete
2
+ logs/
3
+ runs/
4
+ validations/
5
+ artifacts/
6
+ AGENT.md.proposed
7
+ AGENT.md.proposed.meta.json
8
+ maintain/
9
+ ADAPT-PROMPT.md
10
+ slots/
11
+
12
+ # Generated by launch.sh
13
+ .env.agent.*
14
+
15
+ # Xcode build artifacts (harness-specific DerivedData)
16
+ build/DerivedData
@@ -31,6 +31,7 @@ for arg in "$@"; do
31
31
  done
32
32
 
33
33
  if [[ -z "$AGENT_ID" ]]; then
34
+ har_load_agent_slot_limits
34
35
  echo "Usage: $0 <agent-id> [--no-worktree] [--replace] [--force] [--purpose=label]" >&2
35
36
  echo " agent-id must be between ${HARNESS_AGENT_SLOT_MIN} and ${HARNESS_AGENT_SLOT_MAX}" >&2
36
37
  exit 1
@@ -28,7 +28,8 @@ done
28
28
  validate_agent_id "$AGENT_ID"
29
29
 
30
30
  ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
31
- echo "No .env.agent.${AGENT_ID} found. Run: ./.har/launch.sh ${AGENT_ID}" >&2
31
+ echo "No .env.agent.${AGENT_ID} found." >&2
32
+ har_suggest_launch "$AGENT_ID" >&2
32
33
  exit 1
33
34
  }
34
35
 
@@ -25,7 +25,8 @@ AGENT_ID="${1:?Usage: __STAGE_ID__.sh <agent-id> [extra args...]}"
25
25
  validate_agent_id "$AGENT_ID"
26
26
 
27
27
  ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
28
- echo "No .env.agent.${AGENT_ID} found. Run: ./.har/launch.sh ${AGENT_ID}" >&2
28
+ echo "No .env.agent.${AGENT_ID} found." >&2
29
+ har_suggest_launch "$AGENT_ID" >&2
29
30
  exit 1
30
31
  }
31
32
  set -a
@@ -21,7 +21,8 @@ validate_agent_id "$AGENT_ID"
21
21
  log() { echo "==> [browser-e2e agent-$AGENT_ID] $*" >&2; }
22
22
 
23
23
  ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
24
- echo "No .env.agent.${AGENT_ID} found. Run: ./.har/launch.sh ${AGENT_ID}" >&2
24
+ echo "No .env.agent.${AGENT_ID} found." >&2
25
+ har_suggest_launch "$AGENT_ID" >&2
25
26
  exit 1
26
27
  }
27
28
 
@@ -42,7 +42,8 @@ fi
42
42
 
43
43
  # ── Resolve agent env ─────────────────────────────────────────────────────────
44
44
  ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
45
- echo "No .env.agent.${AGENT_ID} found. Run: ./.har/launch.sh ${AGENT_ID}" >&2
45
+ echo "No .env.agent.${AGENT_ID} found." >&2
46
+ har_suggest_launch "$AGENT_ID" >&2
46
47
  exit 1
47
48
  }
48
49
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "LLM-powered CLI for reproducible agent development environments",
5
5
  "keywords": [
6
6
  "har",