@osfactory/har 0.9.0 → 0.11.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/README.md +43 -2
- package/dist/index.js +1240 -586
- package/dist/templates/agent-skills/har-maintain.md +36 -0
- package/dist/templates/agent-skills/har-wt.md +47 -0
- package/dist/templates/agent-skills/setup-har.md +70 -0
- package/dist/templates/agent-skills/skills.manifest.json +48 -0
- package/dist/templates/claude-worktree-guard.sh.template +38 -0
- package/dist/templates/har-boilerplate/CLAUDE.agent.md +4 -2
- package/dist/templates/har-boilerplate/STAGES.md +91 -0
- package/dist/templates/har-boilerplate/agent-slot.sh +35 -6
- package/dist/templates/har-boilerplate/stages/README.sh +7 -5
- package/dist/templates/har-boilerplate/verify.sh +9 -2
- package/dist/templates/har-boilerplate-cli/CLAUDE.agent.md +3 -1
- package/dist/templates/har-boilerplate-cli/STAGES.md +91 -0
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +35 -6
- package/dist/templates/har-boilerplate-cli/stages/README.sh +7 -5
- package/dist/templates/har-boilerplate-cli/verify.sh +9 -2
- package/dist/templates/har-boilerplate-ios/CLAUDE.agent.md +2 -0
- package/dist/templates/har-boilerplate-ios/STAGES.md +91 -0
- package/dist/templates/har-boilerplate-ios/agent-slot.sh +35 -6
- package/dist/templates/har-boilerplate-ios/stages/README.sh +6 -7
- package/dist/templates/har-boilerplate-ios/verify.sh +9 -3
- package/dist/templates/stage-templates/custom-stage-skeleton.sh +65 -0
- package/dist/templates/stage-templates/playwright/template.manifest.json +9 -1
- package/dist/templates/stage-templates/rocketsim/template.manifest.json +2 -1
- package/package.json +1 -1
|
@@ -35,6 +35,8 @@ seeded data, or a simulator flow, document it here and wire the smoke into
|
|
|
35
35
|
|
|
36
36
|
Quick loop: MCP `har_run_verification`, `har env verify ${AGENT_ID}`, or `./.har/verify.sh ${AGENT_ID}`
|
|
37
37
|
|
|
38
|
+
Stages are the harness's single vocabulary for checks: templates and custom stages compile to generic kinds in `.har/stages.json`, and you interact with them only through the registry (`har_run_stage`, `verify`), never stack-specific tooling. Authoring guide: `.har/STAGES.md`.
|
|
39
|
+
|
|
38
40
|
## Project commands
|
|
39
41
|
|
|
40
42
|
```bash
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# HAR Stages — authoring guide
|
|
2
|
+
|
|
3
|
+
Stages are the harness's single vocabulary for runnable checks and lifecycle
|
|
4
|
+
actions. Everything — shipped templates (`playwright`, `rocketsim`), your
|
|
5
|
+
project's test/lint commands, bespoke validation scripts — registers in
|
|
6
|
+
`.har/stages.json` with the same schema, and agents interact with stages only
|
|
7
|
+
through that registry (CLI `har env verify`, MCP `har_run_stage` /
|
|
8
|
+
`har_run_verification`), never through stack-specific tooling.
|
|
9
|
+
|
|
10
|
+
## The registry: `.har/stages.json`
|
|
11
|
+
|
|
12
|
+
```jsonc
|
|
13
|
+
{
|
|
14
|
+
"verificationStages": ["typecheck", "unit-tests", "api-health", "browser-e2e"],
|
|
15
|
+
"stages": [
|
|
16
|
+
{
|
|
17
|
+
"id": "browser-e2e", // stable, shell-friendly slug
|
|
18
|
+
"kind": "test", // setup | launch | verify | test | inspect | reset | teardown | custom
|
|
19
|
+
"description": "Playwright E2E",
|
|
20
|
+
"script": "stages/browser-e2e.sh", // relative to .har/ — OR use "command"
|
|
21
|
+
"requiresAgentId": true, // default true for test/verify/custom kinds
|
|
22
|
+
"artifacts": [{ "path": ".har/artifacts/browser-e2e", "kind": "directory" }]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "unit-tests-fast",
|
|
26
|
+
"kind": "test",
|
|
27
|
+
"command": "npm test -- --agent {agentId}" // {agentId} is substituted at run time
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Optional stage fields: `cwd` (working directory), `env` (extra env vars),
|
|
34
|
+
`group`, `acceptsArgs` (extra CLI args the stage accepts, e.g. `["--full"]`).
|
|
35
|
+
|
|
36
|
+
## Two ways to define a stage
|
|
37
|
+
|
|
38
|
+
**Command stages** — the default for simple checks (`npm test`, `swiftlint`,
|
|
39
|
+
`make check`). One JSON entry, zero files:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
har env add-stage unit-tests-fast --custom --kind test --command "npm test" --verification
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Script stages** — for anything that needs the slot's env, ports, or
|
|
46
|
+
artifacts. Scaffold a contract-compliant skeleton:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
har env add-stage db-integrity --custom --script --description "Check DB invariants"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
then implement the TODO block in `.har/stages/db-integrity.sh`.
|
|
53
|
+
|
|
54
|
+
## The stage script contract
|
|
55
|
+
|
|
56
|
+
Every script under `.har/stages/` must:
|
|
57
|
+
|
|
58
|
+
1. Source `harness.env` and `agent-slot.sh` from `.har/`.
|
|
59
|
+
2. Take the agent slot id as `$1` (validate with `validate_agent_id`); extra
|
|
60
|
+
args may follow.
|
|
61
|
+
3. Load the slot env via `resolve_agent_env_file` and run checks from the
|
|
62
|
+
agent's work dir (`resolve_agent_work_dir`).
|
|
63
|
+
4. Write artifacts (reports, screenshots, logs) under `.har/artifacts/<id>/`.
|
|
64
|
+
5. Print **only** the normalized JSON result object on stdout
|
|
65
|
+
(`status`, `stageId`, `agent_id`, `total_ms`, …); log progress to stderr.
|
|
66
|
+
6. Exit with the real status code (0 = pass).
|
|
67
|
+
|
|
68
|
+
The scaffolded skeleton implements all of this — replace its TODO block.
|
|
69
|
+
|
|
70
|
+
## Verification membership
|
|
71
|
+
|
|
72
|
+
Listing a stage id in `verificationStages` is what includes it in
|
|
73
|
+
`har env verify <id> --full`. Ids that match a registered stage run via their
|
|
74
|
+
script/command; ids without a registry entry (e.g. `typecheck`, `api-health`)
|
|
75
|
+
are inline steps owned by `.har/verify.sh`. Lifecycle kinds
|
|
76
|
+
(`setup`/`launch`/`reset`/`teardown`/`inspect`) and `verify` itself never run
|
|
77
|
+
as part of verification, even if listed.
|
|
78
|
+
|
|
79
|
+
## Commit gate
|
|
80
|
+
|
|
81
|
+
The registry also holds the optional `commitGate` config (installed via
|
|
82
|
+
`har hooks install`): `{ "commitGate": { "mode": "block" | "warn", "scope":
|
|
83
|
+
"worktrees" | "all" } }` controls whether unverified change batches may be
|
|
84
|
+
committed.
|
|
85
|
+
|
|
86
|
+
## Shipped stage templates
|
|
87
|
+
|
|
88
|
+
`har env add-stage --list` shows available templates; `har env add-stage
|
|
89
|
+
playwright` (web) or `har env add-stage rocketsim` (iOS) installs one. A
|
|
90
|
+
template is just packaging: it copies files, merges `package.json` fragments,
|
|
91
|
+
and registers stages through the exact same registry as `--custom`.
|
|
@@ -311,14 +311,43 @@ escape_step_output() {
|
|
|
311
311
|
printf '%s' "$1" | node -e "let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const s=d.trim().split('\n').slice(0,50).join('\n');process.stdout.write(JSON.stringify(s))})" 2>/dev/null || echo '""'
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
-
#
|
|
315
|
-
|
|
314
|
+
# Emit "<id>\t<command>" for each registered stage listed in stages.json
|
|
315
|
+
# verificationStages (used by verify --full). Ids without a matching registered
|
|
316
|
+
# stage are inline verify.sh steps and skipped here; lifecycle stages
|
|
317
|
+
# (setup/launch/reset/teardown/inspect) and the verify stage itself never run.
|
|
318
|
+
# Authoring contract: .har/STAGES.md
|
|
319
|
+
list_registered_verification_stage_commands() {
|
|
316
320
|
local script_dir="$1"
|
|
317
321
|
local agent_id="$2"
|
|
318
|
-
local
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
+
local registry="$script_dir/stages.json"
|
|
323
|
+
[ -f "$registry" ] || return 0
|
|
324
|
+
HAR_STAGE_REGISTRY="$registry" HAR_SCRIPT_DIR="$script_dir" HAR_AGENT_ID="$agent_id" node <<'NODE' 2>/dev/null || true
|
|
325
|
+
const fs = require('fs');
|
|
326
|
+
const { HAR_STAGE_REGISTRY, HAR_SCRIPT_DIR, HAR_AGENT_ID } = process.env;
|
|
327
|
+
const shq = (s) => "'" + String(s).replace(/'/g, "'\\''") + "'";
|
|
328
|
+
let reg;
|
|
329
|
+
try { reg = JSON.parse(fs.readFileSync(HAR_STAGE_REGISTRY, 'utf8')); } catch { process.exit(0); }
|
|
330
|
+
const ids = Array.isArray(reg.verificationStages) ? reg.verificationStages : [];
|
|
331
|
+
const stages = Array.isArray(reg.stages) ? reg.stages : [];
|
|
332
|
+
const runnable = new Set(['test', 'custom']);
|
|
333
|
+
for (const id of ids) {
|
|
334
|
+
const stage = stages.find((s) => s && s.id === id);
|
|
335
|
+
if (!stage || stage.id === 'verify' || !runnable.has(stage.kind)) continue;
|
|
336
|
+
const needsAgent = stage.requiresAgentId !== false;
|
|
337
|
+
let cmd;
|
|
338
|
+
if (stage.script) {
|
|
339
|
+
cmd = shq(HAR_SCRIPT_DIR + '/' + stage.script) + (needsAgent ? ' ' + shq(HAR_AGENT_ID) : '');
|
|
340
|
+
} else if (stage.command) {
|
|
341
|
+
cmd = stage.command.split('{agentId}').join(HAR_AGENT_ID);
|
|
342
|
+
} else {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (stage.cwd) cmd = 'cd ' + shq(stage.cwd) + ' && ' + cmd;
|
|
346
|
+
const env = stage.env && typeof stage.env === 'object' ? stage.env : {};
|
|
347
|
+
const prefix = Object.entries(env).map(([k, v]) => k + '=' + shq(v)).join(' ');
|
|
348
|
+
process.stdout.write(id + '\t' + (prefix ? prefix + ' ' : '') + cmd + '\n');
|
|
349
|
+
}
|
|
350
|
+
NODE
|
|
322
351
|
}
|
|
323
352
|
|
|
324
353
|
# Optional project-owned "agent usable" smoke beyond health.
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
# Example: ./.har/stages/rocketsim-flows.sh <agent-id>
|
|
2
|
+
# Per-stage scripts live here (e.g. ./.har/stages/browser-e2e.sh <agent-id>).
|
|
4
3
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
4
|
+
# Read .har/STAGES.md for the authoring guide: the stage script contract,
|
|
5
|
+
# command vs script stages, and how verificationStages controls verify --full.
|
|
7
6
|
#
|
|
8
|
-
#
|
|
9
|
-
# har env add-stage
|
|
7
|
+
# Scaffold a new one with:
|
|
8
|
+
# har env add-stage <id> --custom --script
|
|
10
9
|
|
|
11
|
-
echo "Add stage scripts under .har/stages/ and register them in stages.json." >&2
|
|
10
|
+
echo "Add stage scripts under .har/stages/ and register them in stages.json — see .har/STAGES.md." >&2
|
|
12
11
|
exit 1
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
# Usage: ./.har/verify.sh <agent-id> [--full]
|
|
6
6
|
#
|
|
7
7
|
# Quick (default): build smoke (compile-only)
|
|
8
|
-
# Full (--full): + unit tests, lint (SwiftLint),
|
|
8
|
+
# Full (--full): + unit tests, lint (SwiftLint), and every registered stage
|
|
9
|
+
# in stages.json verificationStages (see .har/STAGES.md)
|
|
9
10
|
# Step lists are examples — not exhaustive. Adapt commands to this repo's stack.
|
|
10
11
|
set -euo pipefail
|
|
11
12
|
|
|
@@ -150,8 +151,13 @@ if [ -n "$FULL" ]; then
|
|
|
150
151
|
|
|
151
152
|
run_step "readiness" "run_readiness_if_configured \"$AGENT_ID\"" || true
|
|
152
153
|
|
|
153
|
-
#
|
|
154
|
-
|
|
154
|
+
# Registered verification stages from .har/stages.json (see .har/STAGES.md).
|
|
155
|
+
# Every stage listed in verificationStages with a registered script/command
|
|
156
|
+
# runs here -- stage templates and custom stages alike.
|
|
157
|
+
while IFS=$'\t' read -r STAGE_ID STAGE_CMD; do
|
|
158
|
+
[ -n "$STAGE_ID" ] || continue
|
|
159
|
+
run_step "$STAGE_ID" "$STAGE_CMD" || true
|
|
160
|
+
done < <(list_registered_verification_stage_commands "$SCRIPT_DIR" "$AGENT_ID")
|
|
155
161
|
fi
|
|
156
162
|
|
|
157
163
|
END_TOTAL=$(now_ms)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# __STAGE_DESCRIPTION__
|
|
3
|
+
# Custom HAR stage: __STAGE_ID__ (kind: __STAGE_KIND__)
|
|
4
|
+
#
|
|
5
|
+
# Stage script contract (full reference: .har/STAGES.md):
|
|
6
|
+
# - stdout: a single JSON result object (status, stageId, agent_id, ...)
|
|
7
|
+
# - stderr: human-readable progress
|
|
8
|
+
# - $1: agent slot id; extra args may follow
|
|
9
|
+
# - artifacts: write reports/screenshots/logs under .har/artifacts/__STAGE_ID__/
|
|
10
|
+
# - exit code: the real status (0 = pass)
|
|
11
|
+
#
|
|
12
|
+
# Usage: ./.har/stages/__STAGE_ID__.sh <agent-id> [extra args...]
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
HARNESS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
17
|
+
REPO_ROOT="$(cd "$HARNESS_DIR/.." && pwd)"
|
|
18
|
+
|
|
19
|
+
# shellcheck source=/dev/null
|
|
20
|
+
source "$HARNESS_DIR/harness.env"
|
|
21
|
+
# shellcheck source=/dev/null
|
|
22
|
+
source "$HARNESS_DIR/agent-slot.sh"
|
|
23
|
+
|
|
24
|
+
AGENT_ID="${1:?Usage: __STAGE_ID__.sh <agent-id> [extra args...]}"
|
|
25
|
+
validate_agent_id "$AGENT_ID"
|
|
26
|
+
|
|
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
|
|
29
|
+
exit 1
|
|
30
|
+
}
|
|
31
|
+
set -a
|
|
32
|
+
# shellcheck source=/dev/null
|
|
33
|
+
source "$ENV_FILE"
|
|
34
|
+
set +a
|
|
35
|
+
|
|
36
|
+
WORK_DIR="$(resolve_agent_work_dir "$ENV_FILE")"
|
|
37
|
+
ARTIFACTS_DIR="$HARNESS_DIR/artifacts/__STAGE_ID__"
|
|
38
|
+
mkdir -p "$ARTIFACTS_DIR"
|
|
39
|
+
|
|
40
|
+
echo "==> [__STAGE_ID__ agent-${AGENT_ID}] running in ${WORK_DIR}" >&2
|
|
41
|
+
START=$(now_ms)
|
|
42
|
+
|
|
43
|
+
# ── TODO: implement the stage ────────────────────────────────────────────────
|
|
44
|
+
# Run your checks from $WORK_DIR (the agent's isolated checkout); the slot's
|
|
45
|
+
# ports and env are loaded from $ENV_FILE. Save artifacts to $ARTIFACTS_DIR.
|
|
46
|
+
set +e
|
|
47
|
+
OUTPUT=$(cd "$WORK_DIR" && echo "TODO: implement .har/stages/__STAGE_ID__.sh" && false)
|
|
48
|
+
EXIT_CODE=$?
|
|
49
|
+
set -e
|
|
50
|
+
|
|
51
|
+
END=$(now_ms)
|
|
52
|
+
STATUS="fail"
|
|
53
|
+
[ "$EXIT_CODE" = "0" ] && STATUS="pass"
|
|
54
|
+
OUTPUT_JSON=$(escape_step_output "$OUTPUT")
|
|
55
|
+
|
|
56
|
+
node -e "process.stdout.write(JSON.stringify({
|
|
57
|
+
status: '$STATUS',
|
|
58
|
+
stageId: '__STAGE_ID__',
|
|
59
|
+
kind: '__STAGE_KIND__',
|
|
60
|
+
agent_id: $AGENT_ID,
|
|
61
|
+
total_ms: $(( END - START )),
|
|
62
|
+
output: $OUTPUT_JSON
|
|
63
|
+
}, null, 2) + '\n');"
|
|
64
|
+
|
|
65
|
+
exit "$EXIT_CODE"
|
|
@@ -40,5 +40,13 @@
|
|
|
40
40
|
],
|
|
41
41
|
"merge": {
|
|
42
42
|
"package.json": "package.fragment.json"
|
|
43
|
-
}
|
|
43
|
+
},
|
|
44
|
+
"nextSteps": [
|
|
45
|
+
"npm install",
|
|
46
|
+
"npx playwright install",
|
|
47
|
+
"./.har/launch.sh 1",
|
|
48
|
+
"./.har/stages/browser-e2e.sh 1",
|
|
49
|
+
"npx playwright show-report .har/artifacts/browser-e2e/playwright-report"
|
|
50
|
+
],
|
|
51
|
+
"docsPath": ".har/stages/PLAYWRIGHT.md"
|
|
44
52
|
}
|