@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.
- package/dist/index.js +829 -718
- package/dist/prompts/system-authoring.md +1 -1
- package/dist/templates/adaptation-prompt-init.md +1 -1
- package/dist/templates/cursor-rule.mdc.template +3 -3
- package/dist/templates/har-boilerplate/README.md +1 -1
- package/dist/templates/har-boilerplate/agent-cli.sh +1 -1
- package/dist/templates/har-boilerplate/agent-slot.sh +38 -1
- package/dist/templates/har-boilerplate/gitignore.template +15 -0
- package/dist/templates/har-boilerplate/harness.env +2 -1
- package/dist/templates/har-boilerplate/launch.sh +3 -2
- package/dist/templates/har-boilerplate/verify.sh +2 -1
- package/dist/templates/har-boilerplate-cli/agent-cli.sh +2 -2
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +38 -1
- package/dist/templates/har-boilerplate-cli/gitignore.template +15 -0
- package/dist/templates/har-boilerplate-cli/launch.sh +3 -2
- package/dist/templates/har-boilerplate-cli/verify.sh +2 -1
- package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +57 -0
- package/dist/templates/har-boilerplate-ios/agent-cli.sh +2 -2
- package/dist/templates/har-boilerplate-ios/agent-slot.sh +38 -1
- package/dist/templates/har-boilerplate-ios/gitignore.template +16 -0
- package/dist/templates/har-boilerplate-ios/launch.sh +1 -0
- package/dist/templates/har-boilerplate-ios/verify.sh +2 -1
- package/dist/templates/stage-templates/custom-stage-skeleton.sh +2 -1
- package/dist/templates/stage-templates/playwright/.har/stages/browser-e2e.sh +2 -1
- package/dist/templates/stage-templates/rocketsim/.har/stages/rocketsim-flows.sh +2 -1
- 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`)
|
|
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`)
|
|
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)
|
|
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` /
|
|
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
|
|
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
|
|---------|-------------------|-------------------|
|
|
@@ -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:
|
|
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 —
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
45
|
+
echo "No .env.agent.${AGENT_ID} found." >&2
|
|
46
|
+
har_suggest_launch "$AGENT_ID" >&2
|
|
46
47
|
exit 1
|
|
47
48
|
}
|
|
48
49
|
|