@osfactory/har 0.61.1 → 0.61.3
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 +72 -21
- package/dist/templates/har-boilerplate/agent-slot.sh +23 -0
- package/dist/templates/har-boilerplate/ecosystem.agent.template.cjs +8 -2
- package/dist/templates/har-boilerplate/verify.sh +6 -19
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +23 -0
- package/dist/templates/har-boilerplate-cli/verify.sh +4 -10
- package/dist/templates/har-boilerplate-ios/agent-slot.sh +23 -0
- package/dist/templates/har-boilerplate-ios/verify.sh +4 -10
- package/dist/templates/runtime-bundles/pm2-runtime/ecosystem.agent.template.cjs +8 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28779,12 +28779,10 @@ function run(command2, options = {}) {
|
|
|
28779
28779
|
};
|
|
28780
28780
|
}
|
|
28781
28781
|
}
|
|
28782
|
-
function runScript(scriptPath, args = [], options = {}) {
|
|
28783
|
-
return runScriptCapture(scriptPath, args, { ...options, stream: true });
|
|
28784
|
-
}
|
|
28785
28782
|
function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
28786
28783
|
const stream = options.stream ?? false;
|
|
28787
|
-
const
|
|
28784
|
+
const echoStdout = stream && (options.streamStdout ?? true);
|
|
28785
|
+
const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
|
|
28788
28786
|
return new Promise((resolve51) => {
|
|
28789
28787
|
const proc = (0, import_child_process.spawn)("bash", [scriptPath, ...args], {
|
|
28790
28788
|
...spawnOptions,
|
|
@@ -28794,7 +28792,7 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
28794
28792
|
let stderr = "";
|
|
28795
28793
|
proc.stdout?.on("data", (d) => {
|
|
28796
28794
|
stdout += d;
|
|
28797
|
-
if (
|
|
28795
|
+
if (echoStdout) process.stdout.write(d);
|
|
28798
28796
|
});
|
|
28799
28797
|
proc.stderr?.on("data", (d) => {
|
|
28800
28798
|
stderr += d;
|
|
@@ -28805,7 +28803,8 @@ function runScriptCapture(scriptPath, args = [], options = {}) {
|
|
|
28805
28803
|
}
|
|
28806
28804
|
function runShellCommand(command2, options = {}) {
|
|
28807
28805
|
const stream = options.stream ?? false;
|
|
28808
|
-
const
|
|
28806
|
+
const echoStdout = stream && (options.streamStdout ?? true);
|
|
28807
|
+
const { stream: _stream, streamStdout: _streamStdout, ...spawnOptions } = options;
|
|
28809
28808
|
return new Promise((resolve51) => {
|
|
28810
28809
|
const proc = (0, import_child_process.spawn)("bash", ["-lc", command2], {
|
|
28811
28810
|
...spawnOptions,
|
|
@@ -28815,7 +28814,7 @@ function runShellCommand(command2, options = {}) {
|
|
|
28815
28814
|
let stderr = "";
|
|
28816
28815
|
proc.stdout?.on("data", (d) => {
|
|
28817
28816
|
stdout += d;
|
|
28818
|
-
if (
|
|
28817
|
+
if (echoStdout) process.stdout.write(d);
|
|
28819
28818
|
});
|
|
28820
28819
|
proc.stderr?.on("data", (d) => {
|
|
28821
28820
|
stderr += d;
|
|
@@ -29090,6 +29089,18 @@ function parseVerificationResult(stdout) {
|
|
|
29090
29089
|
const parsed = VerificationResultSchema.safeParse(json);
|
|
29091
29090
|
return parsed.success ? parsed.data : null;
|
|
29092
29091
|
}
|
|
29092
|
+
function slimVerificationResult(verification) {
|
|
29093
|
+
if (!verification) return null;
|
|
29094
|
+
return {
|
|
29095
|
+
...verification,
|
|
29096
|
+
stages: verification.stages.map((stage) => {
|
|
29097
|
+
if (!stage.pass || stage.output === void 0) return stage;
|
|
29098
|
+
const rest = { ...stage };
|
|
29099
|
+
delete rest.output;
|
|
29100
|
+
return rest;
|
|
29101
|
+
})
|
|
29102
|
+
};
|
|
29103
|
+
}
|
|
29093
29104
|
function buildStageResult(input) {
|
|
29094
29105
|
const verification = input.verification ?? parseVerificationResult(input.stdout) ?? void 0;
|
|
29095
29106
|
const parsedStageResult = StageResultSchema.safeParse(extractJsonFromOutput(input.stdout));
|
|
@@ -29287,16 +29298,18 @@ function buildExecutionPlan(repoPath, stage, options) {
|
|
|
29287
29298
|
env: mergedEnv
|
|
29288
29299
|
};
|
|
29289
29300
|
}
|
|
29290
|
-
async function executePlan(plan,
|
|
29291
|
-
const spawnOptions = {
|
|
29301
|
+
async function executePlan(plan, options) {
|
|
29302
|
+
const spawnOptions = {
|
|
29303
|
+
cwd: plan.cwd,
|
|
29304
|
+
env: plan.env,
|
|
29305
|
+
stream: !options.capture,
|
|
29306
|
+
streamStdout: options.streamStdout
|
|
29307
|
+
};
|
|
29292
29308
|
if (plan.mode === "shell" && plan.shellCommand) {
|
|
29293
|
-
return runShellCommand(plan.shellCommand,
|
|
29309
|
+
return runShellCommand(plan.shellCommand, spawnOptions);
|
|
29294
29310
|
}
|
|
29295
29311
|
if (plan.scriptPath) {
|
|
29296
|
-
|
|
29297
|
-
return runScriptCapture(plan.scriptPath, plan.args, spawnOptions);
|
|
29298
|
-
}
|
|
29299
|
-
return runScript(plan.scriptPath, plan.args, spawnOptions);
|
|
29312
|
+
return runScriptCapture(plan.scriptPath, plan.args, spawnOptions);
|
|
29300
29313
|
}
|
|
29301
29314
|
throw new Error("Invalid stage execution plan");
|
|
29302
29315
|
}
|
|
@@ -29328,7 +29341,10 @@ var init_local_executor = __esm({
|
|
|
29328
29341
|
const plan = buildExecutionPlan(repoPath, stage, options);
|
|
29329
29342
|
const capture = options.capture ?? ctx.capture ?? true;
|
|
29330
29343
|
const started = Date.now();
|
|
29331
|
-
const result = await executePlan(plan,
|
|
29344
|
+
const result = await executePlan(plan, {
|
|
29345
|
+
capture,
|
|
29346
|
+
streamStdout: stage.kind !== "verify"
|
|
29347
|
+
});
|
|
29332
29348
|
const durationMs = Date.now() - started;
|
|
29333
29349
|
const verification = stage.kind === "verify" ? parseVerificationResult(result.stdout) : void 0;
|
|
29334
29350
|
const previewUrls = stage.kind === "launch" && result.code === 0 && options.agentId !== void 0 ? computePreviewUrls(repoPath, options.agentId) : void 0;
|
|
@@ -73264,6 +73280,7 @@ function writeOnboardingPreferences(overrides) {
|
|
|
73264
73280
|
// src/cli/commands/env.ts
|
|
73265
73281
|
init_schema2();
|
|
73266
73282
|
init_validation();
|
|
73283
|
+
init_results();
|
|
73267
73284
|
init_logging();
|
|
73268
73285
|
|
|
73269
73286
|
// src/cli/help-text.ts
|
|
@@ -73511,7 +73528,11 @@ var envCommand = {
|
|
|
73511
73528
|
).command(
|
|
73512
73529
|
"verify <id>",
|
|
73513
73530
|
"Run verification suite for an agent",
|
|
73514
|
-
(y) => y.positional("id", { type: "number", describe: "Agent slot id (see .har/stages.json agentSlots)" }).option("repo", { type: "string", default: "." }).option("full", { type: "boolean", default: false }),
|
|
73531
|
+
(y) => y.positional("id", { type: "number", describe: "Agent slot id (see .har/stages.json agentSlots)" }).option("repo", { type: "string", default: "." }).option("full", { type: "boolean", default: false }).option("json", {
|
|
73532
|
+
type: "boolean",
|
|
73533
|
+
default: false,
|
|
73534
|
+
describe: "Structured JSON (passing steps omit output; default is progress only)"
|
|
73535
|
+
}),
|
|
73515
73536
|
handleVerify
|
|
73516
73537
|
).command(
|
|
73517
73538
|
"teardown <id>",
|
|
@@ -73976,9 +73997,26 @@ async function handleVerify(argv) {
|
|
|
73976
73997
|
repoPath: repo,
|
|
73977
73998
|
agentId,
|
|
73978
73999
|
full: argv.full,
|
|
73979
|
-
capture:
|
|
74000
|
+
capture: Boolean(argv.json)
|
|
73980
74001
|
});
|
|
73981
|
-
if (
|
|
74002
|
+
if (argv.json) {
|
|
74003
|
+
const payload = slimVerificationResult(result.verification) ?? {
|
|
74004
|
+
status: result.code === 0 ? "pass" : "fail",
|
|
74005
|
+
agent_id: agentId,
|
|
74006
|
+
stages: []
|
|
74007
|
+
};
|
|
74008
|
+
process.stdout.write(JSON.stringify(payload, null, 2) + "\n");
|
|
74009
|
+
return finishCommand(result.code);
|
|
74010
|
+
}
|
|
74011
|
+
if (result.verification) {
|
|
74012
|
+
const failed = result.verification.stages.filter((stage) => !stage.pass).map((stage) => stage.name);
|
|
74013
|
+
const elapsed = result.verification.total_ms != null ? ` (${result.verification.total_ms}ms)` : "";
|
|
74014
|
+
if (failed.length > 0) {
|
|
74015
|
+
error(`Verification failed: ${failed.join(", ")}${elapsed}`);
|
|
74016
|
+
} else {
|
|
74017
|
+
success(`Verification ${result.verification.status}${elapsed}`);
|
|
74018
|
+
}
|
|
74019
|
+
}
|
|
73982
74020
|
return finishCommand(result.code);
|
|
73983
74021
|
}
|
|
73984
74022
|
async function handleTeardown(argv) {
|
|
@@ -82495,6 +82533,7 @@ function objectJsonSchema(properties, required2) {
|
|
|
82495
82533
|
}
|
|
82496
82534
|
|
|
82497
82535
|
// src/mcp/server.ts
|
|
82536
|
+
init_results();
|
|
82498
82537
|
init_validation();
|
|
82499
82538
|
|
|
82500
82539
|
// src/mcp/schemas.ts
|
|
@@ -82780,7 +82819,7 @@ var HAR_MCP_TOOLS = [
|
|
|
82780
82819
|
},
|
|
82781
82820
|
{
|
|
82782
82821
|
name: "har_run_verification",
|
|
82783
|
-
description: "Run the project verification pipeline for an agent slot.",
|
|
82822
|
+
description: "Run the project verification pipeline for an agent slot. Returns status, timing, and failed-step output (passing steps omit logs; stdout is not the raw JSON dump).",
|
|
82784
82823
|
inputSchema: objectJsonSchema(
|
|
82785
82824
|
{
|
|
82786
82825
|
repo: repoJsonProperty,
|
|
@@ -83006,7 +83045,14 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
83006
83045
|
capture: true,
|
|
83007
83046
|
trigger: "mcp"
|
|
83008
83047
|
});
|
|
83009
|
-
return jsonContent(
|
|
83048
|
+
return jsonContent(
|
|
83049
|
+
RunVerificationOutputSchema.parse({
|
|
83050
|
+
code: result.code,
|
|
83051
|
+
stdout: "",
|
|
83052
|
+
stderr: result.stderr,
|
|
83053
|
+
verification: slimVerificationResult(result.verification)
|
|
83054
|
+
})
|
|
83055
|
+
);
|
|
83010
83056
|
}
|
|
83011
83057
|
case "har_get_status": {
|
|
83012
83058
|
const agentIdRaw = args.agentId;
|
|
@@ -83052,7 +83098,12 @@ async function handleMcpToolCall(toolName, args, defaultRepo = ".") {
|
|
|
83052
83098
|
capture: true,
|
|
83053
83099
|
trigger: "mcp"
|
|
83054
83100
|
});
|
|
83055
|
-
return jsonContent(
|
|
83101
|
+
return jsonContent(
|
|
83102
|
+
CompleteEnvironmentOutputSchema.parse({
|
|
83103
|
+
...result,
|
|
83104
|
+
verification: slimVerificationResult(result.verification)
|
|
83105
|
+
})
|
|
83106
|
+
);
|
|
83056
83107
|
}
|
|
83057
83108
|
case "har_list_artifacts": {
|
|
83058
83109
|
const input = ListArtifactsInputSchema.parse({ ...args, repo });
|
|
@@ -776,6 +776,29 @@ escape_step_output() {
|
|
|
776
776
|
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 '""'
|
|
777
777
|
}
|
|
778
778
|
|
|
779
|
+
# Append one verify.sh step to RESULTS_JSON (caller global).
|
|
780
|
+
# Passing steps omit output — it already appeared as ✓ on stderr.
|
|
781
|
+
record_step_result() {
|
|
782
|
+
local name="$1"
|
|
783
|
+
local pass_bool="$2"
|
|
784
|
+
local elapsed="$3"
|
|
785
|
+
local output="${4:-}"
|
|
786
|
+
local step_json
|
|
787
|
+
if [ "$pass_bool" = "true" ]; then
|
|
788
|
+
step_json=$(NAME="$name" MS="$elapsed" node -e 'process.stdout.write(JSON.stringify({name:process.env.NAME,pass:true,ms:Number(process.env.MS)}))' 2>/dev/null) || return 0
|
|
789
|
+
else
|
|
790
|
+
local escaped
|
|
791
|
+
escaped=$(escape_step_output "$output")
|
|
792
|
+
step_json=$(NAME="$name" MS="$elapsed" node -e "process.stdout.write(JSON.stringify({name:process.env.NAME,pass:false,ms:Number(process.env.MS),output:$escaped}))" 2>/dev/null) || return 0
|
|
793
|
+
fi
|
|
794
|
+
RESULTS_JSON=$(echo "$RESULTS_JSON" | node -e "
|
|
795
|
+
const fs = require('fs');
|
|
796
|
+
const arr = JSON.parse(fs.readFileSync('/dev/stdin','utf8'));
|
|
797
|
+
arr.push($step_json);
|
|
798
|
+
process.stdout.write(JSON.stringify(arr));
|
|
799
|
+
" 2>/dev/null || echo "$RESULTS_JSON")
|
|
800
|
+
}
|
|
801
|
+
|
|
779
802
|
# Emit "<id>\t<command>" for each registered stage listed in stages.json
|
|
780
803
|
# verificationStages (used by verify --full). Ids without a matching registered
|
|
781
804
|
# stage are inline verify.sh steps and skipped here; lifecycle stages
|
|
@@ -7,11 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
// launch.sh writes this file (and .env.agent.N) to the work dir root,
|
|
9
9
|
// so __dirname IS the work dir — repo root or the agent's git worktree.
|
|
10
|
+
const fs = require('fs');
|
|
10
11
|
const path = require('path');
|
|
11
|
-
const dotenv = require('dotenv');
|
|
12
12
|
|
|
13
13
|
const agentEnvPath = path.resolve(__dirname, '.env.agent.${AGENT_ID}');
|
|
14
|
-
const env =
|
|
14
|
+
const env = {};
|
|
15
|
+
try {
|
|
16
|
+
for (const line of fs.readFileSync(agentEnvPath, 'utf8').split('\n')) {
|
|
17
|
+
const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/);
|
|
18
|
+
if (m && !line.trimStart().startsWith('#')) env[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
19
|
+
}
|
|
20
|
+
} catch {}
|
|
15
21
|
|
|
16
22
|
module.exports = {
|
|
17
23
|
apps: [
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Progressive verification pipeline for an agent environment.
|
|
3
|
-
# Outputs JSON to stdout, human-readable progress to stderr.
|
|
3
|
+
# Outputs JSON to stdout (machine contract), human-readable progress to stderr.
|
|
4
|
+
# Passing steps omit `output`. `har env verify` streams progress only.
|
|
4
5
|
#
|
|
5
6
|
# Usage: ./.har/verify.sh <agent-id> [--full]
|
|
6
7
|
#
|
|
@@ -73,7 +74,7 @@ run_step() {
|
|
|
73
74
|
end=$(now_ms)
|
|
74
75
|
elapsed=$(( end - start ))
|
|
75
76
|
|
|
76
|
-
local pass_bool
|
|
77
|
+
local pass_bool
|
|
77
78
|
if [ "$exit_code" = "0" ]; then
|
|
78
79
|
echo "✓ (${elapsed}ms)" >&2
|
|
79
80
|
pass_bool="true"
|
|
@@ -84,14 +85,7 @@ run_step() {
|
|
|
84
85
|
OVERALL_PASS=false
|
|
85
86
|
fi
|
|
86
87
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
RESULTS_JSON=$(echo "$RESULTS_JSON" | node -e "
|
|
90
|
-
const fs = require('fs');
|
|
91
|
-
let arr = JSON.parse(fs.readFileSync('/dev/stdin','utf8'));
|
|
92
|
-
arr.push({name:'$name',pass:$pass_bool,ms:$elapsed,output:$step_output_escaped});
|
|
93
|
-
process.stdout.write(JSON.stringify(arr));
|
|
94
|
-
" 2>/dev/null || echo "$RESULTS_JSON")
|
|
88
|
+
record_step_result "$name" "$pass_bool" "$elapsed" "$output"
|
|
95
89
|
|
|
96
90
|
if [ "$pass_bool" = "false" ] && [ -z "$FULL" ]; then
|
|
97
91
|
return 1
|
|
@@ -114,7 +108,7 @@ run_http_step() {
|
|
|
114
108
|
end=$(now_ms)
|
|
115
109
|
elapsed=$(( end - start ))
|
|
116
110
|
|
|
117
|
-
local pass_bool
|
|
111
|
+
local pass_bool
|
|
118
112
|
if [ "$exit_code" = "0" ]; then
|
|
119
113
|
echo "✓ (${elapsed}ms)" >&2
|
|
120
114
|
pass_bool="true"
|
|
@@ -124,14 +118,7 @@ run_http_step() {
|
|
|
124
118
|
OVERALL_PASS=false
|
|
125
119
|
fi
|
|
126
120
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
RESULTS_JSON=$(echo "$RESULTS_JSON" | node -e "
|
|
130
|
-
const fs = require('fs');
|
|
131
|
-
let arr = JSON.parse(fs.readFileSync('/dev/stdin','utf8'));
|
|
132
|
-
arr.push({name:'$name',pass:$pass_bool,ms:$elapsed,output:$step_output_escaped});
|
|
133
|
-
process.stdout.write(JSON.stringify(arr));
|
|
134
|
-
" 2>/dev/null || echo "$RESULTS_JSON")
|
|
121
|
+
record_step_result "$name" "$pass_bool" "$elapsed" "$output"
|
|
135
122
|
|
|
136
123
|
if [ "$pass_bool" = "false" ] && [ -z "$FULL" ]; then
|
|
137
124
|
return 1
|
|
@@ -758,6 +758,29 @@ escape_step_output() {
|
|
|
758
758
|
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 '""'
|
|
759
759
|
}
|
|
760
760
|
|
|
761
|
+
# Append one verify.sh step to RESULTS_JSON (caller global).
|
|
762
|
+
# Passing steps omit output — it already appeared as ✓ on stderr.
|
|
763
|
+
record_step_result() {
|
|
764
|
+
local name="$1"
|
|
765
|
+
local pass_bool="$2"
|
|
766
|
+
local elapsed="$3"
|
|
767
|
+
local output="${4:-}"
|
|
768
|
+
local step_json
|
|
769
|
+
if [ "$pass_bool" = "true" ]; then
|
|
770
|
+
step_json=$(NAME="$name" MS="$elapsed" node -e 'process.stdout.write(JSON.stringify({name:process.env.NAME,pass:true,ms:Number(process.env.MS)}))' 2>/dev/null) || return 0
|
|
771
|
+
else
|
|
772
|
+
local escaped
|
|
773
|
+
escaped=$(escape_step_output "$output")
|
|
774
|
+
step_json=$(NAME="$name" MS="$elapsed" node -e "process.stdout.write(JSON.stringify({name:process.env.NAME,pass:false,ms:Number(process.env.MS),output:$escaped}))" 2>/dev/null) || return 0
|
|
775
|
+
fi
|
|
776
|
+
RESULTS_JSON=$(echo "$RESULTS_JSON" | node -e "
|
|
777
|
+
const fs = require('fs');
|
|
778
|
+
const arr = JSON.parse(fs.readFileSync('/dev/stdin','utf8'));
|
|
779
|
+
arr.push($step_json);
|
|
780
|
+
process.stdout.write(JSON.stringify(arr));
|
|
781
|
+
" 2>/dev/null || echo "$RESULTS_JSON")
|
|
782
|
+
}
|
|
783
|
+
|
|
761
784
|
# Emit "<id>\t<command>" for each registered stage listed in stages.json
|
|
762
785
|
# verificationStages (used by verify --full). Ids without a matching registered
|
|
763
786
|
# stage are inline verify.sh steps and skipped here; lifecycle stages
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Verification pipeline for CLI/library repos.
|
|
3
|
-
# Outputs JSON to stdout, human-readable progress to stderr.
|
|
3
|
+
# Outputs JSON to stdout (machine contract), human-readable progress to stderr.
|
|
4
|
+
# Passing steps omit `output`. `har env verify` streams progress only.
|
|
4
5
|
#
|
|
5
6
|
# Usage: ./.har/verify.sh <agent-id> [--full]
|
|
6
7
|
#
|
|
@@ -70,7 +71,7 @@ run_step() {
|
|
|
70
71
|
end=$(now_ms)
|
|
71
72
|
elapsed=$(( end - start ))
|
|
72
73
|
|
|
73
|
-
local pass_bool
|
|
74
|
+
local pass_bool
|
|
74
75
|
if [ "$exit_code" = "0" ]; then
|
|
75
76
|
echo "✓ (${elapsed}ms)" >&2
|
|
76
77
|
pass_bool="true"
|
|
@@ -81,14 +82,7 @@ run_step() {
|
|
|
81
82
|
OVERALL_PASS=false
|
|
82
83
|
fi
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
RESULTS_JSON=$(echo "$RESULTS_JSON" | node -e "
|
|
87
|
-
const fs = require('fs');
|
|
88
|
-
let arr = JSON.parse(fs.readFileSync('/dev/stdin','utf8'));
|
|
89
|
-
arr.push({name:'$name',pass:$pass_bool,ms:$elapsed,output:$step_output_escaped});
|
|
90
|
-
process.stdout.write(JSON.stringify(arr));
|
|
91
|
-
" 2>/dev/null || echo "$RESULTS_JSON")
|
|
85
|
+
record_step_result "$name" "$pass_bool" "$elapsed" "$output"
|
|
92
86
|
|
|
93
87
|
if [ "$pass_bool" = "false" ] && [ -z "$FULL" ]; then
|
|
94
88
|
return 1
|
|
@@ -405,6 +405,29 @@ escape_step_output() {
|
|
|
405
405
|
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 '""'
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
+
# Append one verify.sh step to RESULTS_JSON (caller global).
|
|
409
|
+
# Passing steps omit output — it already appeared as ✓ on stderr.
|
|
410
|
+
record_step_result() {
|
|
411
|
+
local name="$1"
|
|
412
|
+
local pass_bool="$2"
|
|
413
|
+
local elapsed="$3"
|
|
414
|
+
local output="${4:-}"
|
|
415
|
+
local step_json
|
|
416
|
+
if [ "$pass_bool" = "true" ]; then
|
|
417
|
+
step_json=$(NAME="$name" MS="$elapsed" node -e 'process.stdout.write(JSON.stringify({name:process.env.NAME,pass:true,ms:Number(process.env.MS)}))' 2>/dev/null) || return 0
|
|
418
|
+
else
|
|
419
|
+
local escaped
|
|
420
|
+
escaped=$(escape_step_output "$output")
|
|
421
|
+
step_json=$(NAME="$name" MS="$elapsed" node -e "process.stdout.write(JSON.stringify({name:process.env.NAME,pass:false,ms:Number(process.env.MS),output:$escaped}))" 2>/dev/null) || return 0
|
|
422
|
+
fi
|
|
423
|
+
RESULTS_JSON=$(echo "$RESULTS_JSON" | node -e "
|
|
424
|
+
const fs = require('fs');
|
|
425
|
+
const arr = JSON.parse(fs.readFileSync('/dev/stdin','utf8'));
|
|
426
|
+
arr.push($step_json);
|
|
427
|
+
process.stdout.write(JSON.stringify(arr));
|
|
428
|
+
" 2>/dev/null || echo "$RESULTS_JSON")
|
|
429
|
+
}
|
|
430
|
+
|
|
408
431
|
# Emit "<id>\t<command>" for each registered stage listed in stages.json
|
|
409
432
|
# verificationStages (used by verify --full). Ids without a matching registered
|
|
410
433
|
# stage are inline verify.sh steps and skipped here; lifecycle stages
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Verification pipeline for iOS mobile app repos — build and test with xcodebuild.
|
|
3
|
-
# Outputs JSON to stdout, human-readable progress to stderr.
|
|
3
|
+
# Outputs JSON to stdout (machine contract), human-readable progress to stderr.
|
|
4
|
+
# Passing steps omit `output`. `har env verify` streams progress only.
|
|
4
5
|
#
|
|
5
6
|
# Usage: ./.har/verify.sh <agent-id> [--full]
|
|
6
7
|
#
|
|
@@ -92,7 +93,7 @@ run_step() {
|
|
|
92
93
|
end=$(now_ms)
|
|
93
94
|
elapsed=$(( end - start ))
|
|
94
95
|
|
|
95
|
-
local pass_bool
|
|
96
|
+
local pass_bool
|
|
96
97
|
if [ "$exit_code" = "0" ]; then
|
|
97
98
|
echo "✓ (${elapsed}ms)" >&2
|
|
98
99
|
pass_bool="true"
|
|
@@ -103,14 +104,7 @@ run_step() {
|
|
|
103
104
|
OVERALL_PASS=false
|
|
104
105
|
fi
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
RESULTS_JSON=$(echo "$RESULTS_JSON" | node -e "
|
|
109
|
-
const fs = require('fs');
|
|
110
|
-
let arr = JSON.parse(fs.readFileSync('/dev/stdin','utf8'));
|
|
111
|
-
arr.push({name:'$name',pass:$pass_bool,ms:$elapsed,output:$step_output_escaped});
|
|
112
|
-
process.stdout.write(JSON.stringify(arr));
|
|
113
|
-
" 2>/dev/null || echo "$RESULTS_JSON")
|
|
107
|
+
record_step_result "$name" "$pass_bool" "$elapsed" "$output"
|
|
114
108
|
|
|
115
109
|
if [ "$pass_bool" = "false" ] && [ -z "$FULL" ]; then
|
|
116
110
|
return 1
|
|
@@ -7,11 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
// launch.sh writes this file (and .env.agent.N) to the work dir root,
|
|
9
9
|
// so __dirname IS the work dir — repo root or the agent's git worktree.
|
|
10
|
+
const fs = require('fs');
|
|
10
11
|
const path = require('path');
|
|
11
|
-
const dotenv = require('dotenv');
|
|
12
12
|
|
|
13
13
|
const agentEnvPath = path.resolve(__dirname, '.env.agent.${AGENT_ID}');
|
|
14
|
-
const env =
|
|
14
|
+
const env = {};
|
|
15
|
+
try {
|
|
16
|
+
for (const line of fs.readFileSync(agentEnvPath, 'utf8').split('\n')) {
|
|
17
|
+
const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/);
|
|
18
|
+
if (m && !line.trimStart().startsWith('#')) env[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
19
|
+
}
|
|
20
|
+
} catch {}
|
|
15
21
|
|
|
16
22
|
module.exports = {
|
|
17
23
|
apps: [
|