@resolveio/server-lib 22.3.33 → 22.3.34
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/package.json +137 -137
- package/util/ai-runner-qa-tools.d.ts +1 -0
- package/util/ai-runner-qa-tools.js +139 -0
- package/util/ai-runner-qa-tools.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,139 +1,139 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
2
|
+
"name": "@resolveio/server-lib",
|
|
3
|
+
"version": "22.3.34",
|
|
4
|
+
"description": "",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"package": "./build_package.sh",
|
|
7
|
+
"library": "node_modules/gulp/bin/gulp.js watch:dist",
|
|
8
|
+
"server": "./start_server.sh",
|
|
9
|
+
"postserver": "node_modules/gulp/bin/gulp.js mongo-stop",
|
|
10
|
+
"build-prod": "node_modules/gulp/bin/gulp.js build-prod",
|
|
11
|
+
"dependency-test": "node --require ts-node/register tests/subscription-dependency-context.test.ts",
|
|
12
|
+
"subscription-invalidation-test": "node --require ts-node/register tests/subscription-manager-invalidation.test.ts",
|
|
13
|
+
"subscription-connect-race-test": "node --require ts-node/register tests/subscription-connect-race.test.ts",
|
|
14
|
+
"error-reporter-test": "node --require ts-node/register tests/error-reporter.test.ts",
|
|
15
|
+
"ai-assistant-utils-test": "node --require ts-node/register tests/ai-assistant-utils.test.ts",
|
|
16
|
+
"ai-assistant-routing-eval-test": "node --require ts-node/register tests/ai-assistant-routing-eval.test.ts",
|
|
17
|
+
"ai-assistant-preflight-matrix": "node --require ts-node/register tests/ai-assistant-preflight-matrix.ts",
|
|
18
|
+
"ai-assistant-snf-live-eval": "node --require ts-node/register tests/ai-assistant-snf-live-eval.ts",
|
|
19
|
+
"ai-assistant-openai-e2e": "node --require ts-node/register tests/ai-assistant-openai-e2e.ts",
|
|
20
|
+
"ai-assistant-openai-e2e:wo-this-week-customer": "AI_ASSISTANT_E2E_CASES=wo_this_week_customer_summary node --require ts-node/register tests/ai-assistant-openai-e2e.ts",
|
|
21
|
+
"ai-assistant-openai-e2e:wo-this-week-customer:soak": "AI_ASSISTANT_E2E_CASES=wo_this_week_customer_summary AI_ASSISTANT_E2E_REPEAT=50 node --require ts-node/register tests/ai-assistant-openai-e2e.ts",
|
|
22
|
+
"ai-assistant-openai-git-e2e": "node --require ts-node/register tests/ai-assistant-openai-git-e2e.ts",
|
|
23
|
+
"ai-assistant-eval-triage": "node --require ts-node/register tests/ai-assistant-eval-triage.ts",
|
|
24
|
+
"ai-assistant-data-parity-e2e": "node --require ts-node/register tests/ai-assistant-data-parity-e2e.ts",
|
|
25
|
+
"ai-assistant-corpus-build": "node --require ts-node/register tests/ai-assistant-corpus-build.ts",
|
|
26
|
+
"ai-assistant-corpus-replay-e2e": "node --require ts-node/register tests/ai-assistant-corpus-replay-e2e.ts",
|
|
27
|
+
"method-publication-generator-test": "node --require ts-node/register tests/method-publication-generator.test.ts",
|
|
28
|
+
"ai-assistant-nightly-eval": "npm run ai-assistant-corpus-build && npm run ai-assistant-data-parity-e2e && npm run ai-assistant-corpus-replay-e2e && npm run ai-assistant-eval-triage"
|
|
29
|
+
},
|
|
30
|
+
"author": "",
|
|
31
|
+
"license": "ISC",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=22.0.0 <23"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@aws-sdk/client-s3": "3.1043.0",
|
|
37
|
+
"@aws-sdk/client-sesv2": "3.1043.0",
|
|
38
|
+
"@aws-sdk/s3-request-presigner": "3.1043.0",
|
|
39
|
+
"@openai/codex-sdk": "0.128.0",
|
|
40
|
+
"async": "3.2.6",
|
|
41
|
+
"axios": "1.16.0",
|
|
42
|
+
"clone": "2.1.2",
|
|
43
|
+
"cron": "4.4.0",
|
|
44
|
+
"deep-diff": "1.0.2",
|
|
45
|
+
"deep-object-diff": "1.1.9",
|
|
46
|
+
"exceljs": "4.4.0",
|
|
47
|
+
"express": "5.2.1",
|
|
48
|
+
"express-xml-bodyparser": "0.4.1",
|
|
49
|
+
"handlebars": "4.7.9",
|
|
50
|
+
"imap": "0.8.19",
|
|
51
|
+
"js-tiktoken": "1.0.21",
|
|
52
|
+
"json2csv": "6.0.0-alpha.2",
|
|
53
|
+
"jsonwebtoken": "9.0.3",
|
|
54
|
+
"jwt-decode": "4.0.0",
|
|
55
|
+
"moment-timezone": "0.6.2",
|
|
56
|
+
"mongodb": "7.2.0",
|
|
57
|
+
"msgpackr": "2.0.1",
|
|
58
|
+
"node-cache": "5.1.2",
|
|
59
|
+
"node-google-timezone": "0.1.1",
|
|
60
|
+
"nodemailer": "8.0.7",
|
|
61
|
+
"path": "0.12.7",
|
|
62
|
+
"pdf-lib": "1.17.1",
|
|
63
|
+
"pm2": "7.0.1",
|
|
64
|
+
"puppeteer": "24.43.0",
|
|
65
|
+
"rus-diff": "1.1.0",
|
|
66
|
+
"rxjs": "7.8.2",
|
|
67
|
+
"scmp": "2.1.0",
|
|
68
|
+
"sift": "17.1.3",
|
|
69
|
+
"simpl-schema": "1.12.0",
|
|
70
|
+
"string_score": "0.1.22",
|
|
71
|
+
"string-similarity": "4.0.4",
|
|
72
|
+
"twilio": "6.0.1",
|
|
73
|
+
"ws": "8.20.0",
|
|
74
|
+
"xlsx": "0.18.5"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@types/express": "5.0.6",
|
|
78
|
+
"@types/handlebars": "4.1.0",
|
|
79
|
+
"@types/jsonwebtoken": "9.0.10",
|
|
80
|
+
"@types/nodemailer": "8.0.0",
|
|
81
|
+
"@types/ws": "8.18.1",
|
|
82
|
+
"@typescript-eslint/eslint-plugin": "8.59.2",
|
|
83
|
+
"@typescript-eslint/parser": "8.59.2",
|
|
84
|
+
"del": "3.0.0",
|
|
85
|
+
"eslint": "10.3.0",
|
|
86
|
+
"eslint-plugin-promise": "7.3.0",
|
|
87
|
+
"gulp": "5.0.1",
|
|
88
|
+
"gulp-if": "3.0.0",
|
|
89
|
+
"gulp-nodemon": "2.5.0",
|
|
90
|
+
"gulp-rename": "2.1.0",
|
|
91
|
+
"gulp-shell": "0.8.0",
|
|
92
|
+
"gulp-sourcemaps": "3.0.0",
|
|
93
|
+
"gulp-typescript": "5.0.1",
|
|
94
|
+
"gulp-uglify": "3.0.2",
|
|
95
|
+
"gulp-zip": "6.1.0",
|
|
96
|
+
"mkdirs": "1.0.0",
|
|
97
|
+
"ts-node": "10.9.2",
|
|
98
|
+
"typescript": "5.9.3"
|
|
99
|
+
},
|
|
100
|
+
"peerDependencies": {
|
|
101
|
+
"@aws-sdk/client-s3": "3.1043.0",
|
|
102
|
+
"@aws-sdk/client-sesv2": "3.1043.0",
|
|
103
|
+
"@aws-sdk/s3-request-presigner": "3.1043.0",
|
|
104
|
+
"@openai/codex-sdk": "0.128.0",
|
|
105
|
+
"axios": "1.16.0",
|
|
106
|
+
"body-parser": "2.2.0",
|
|
107
|
+
"clone": "2.1.2",
|
|
108
|
+
"cron": "4.4.0",
|
|
109
|
+
"deep-diff": "1.0.2",
|
|
110
|
+
"deep-object-diff": "1.1.9",
|
|
111
|
+
"exceljs": "4.4.0",
|
|
112
|
+
"express": "5.2.1",
|
|
113
|
+
"express-xml-bodyparser": "0.4.1",
|
|
114
|
+
"handlebars": "4.7.9",
|
|
115
|
+
"imap": "0.8.19",
|
|
116
|
+
"js-tiktoken": "1.0.21",
|
|
117
|
+
"json2csv": "6.0.0-alpha.2",
|
|
118
|
+
"jsonwebtoken": "9.0.3",
|
|
119
|
+
"jwt-decode": "4.0.0",
|
|
120
|
+
"moment-timezone": "0.6.2",
|
|
121
|
+
"mongodb": "7.2.0",
|
|
122
|
+
"msgpackr": "2.0.1",
|
|
123
|
+
"node-cache": "5.1.2",
|
|
124
|
+
"node-google-timezone": "0.1.1",
|
|
125
|
+
"nodemailer": "8.0.7",
|
|
126
|
+
"path": "0.12.7",
|
|
127
|
+
"pdf-lib": "1.17.1",
|
|
128
|
+
"pm2": "7.0.1",
|
|
129
|
+
"puppeteer": "24.43.0",
|
|
130
|
+
"rus-diff": "1.1.0",
|
|
131
|
+
"scmp": "2.1.0",
|
|
132
|
+
"simpl-schema": "1.12.0",
|
|
133
|
+
"string_score": "0.1.22",
|
|
134
|
+
"string-similarity": "4.0.4",
|
|
135
|
+
"twilio": "6.0.1",
|
|
136
|
+
"ws": "8.20.0",
|
|
137
|
+
"xlsx": "0.18.5"
|
|
138
|
+
}
|
|
139
139
|
}
|
|
@@ -12,4 +12,5 @@ export interface ResolveIORunnerQaToolBundleOptions {
|
|
|
12
12
|
export declare function buildResolveIORunnerQaEnvScript(options?: ResolveIORunnerQaToolBundleOptions): string;
|
|
13
13
|
export declare function buildResolveIORunnerLocalQaScript(): string;
|
|
14
14
|
export declare function buildResolveIORunnerLocalQaStopperScript(): string;
|
|
15
|
+
export declare function buildResolveIORunnerBugfixComparisonQaScript(): string;
|
|
15
16
|
export declare function buildResolveIORunnerQaToolsReadme(options?: ResolveIORunnerQaToolBundleOptions): string;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.buildResolveIORunnerQaEnvScript = buildResolveIORunnerQaEnvScript;
|
|
4
4
|
exports.buildResolveIORunnerLocalQaScript = buildResolveIORunnerLocalQaScript;
|
|
5
5
|
exports.buildResolveIORunnerLocalQaStopperScript = buildResolveIORunnerLocalQaStopperScript;
|
|
6
|
+
exports.buildResolveIORunnerBugfixComparisonQaScript = buildResolveIORunnerBugfixComparisonQaScript;
|
|
6
7
|
exports.buildResolveIORunnerQaToolsReadme = buildResolveIORunnerQaToolsReadme;
|
|
7
8
|
function shellDoubleQuote(value) {
|
|
8
9
|
return String(value || '').replace(/["\\$`]/g, '\\$&');
|
|
@@ -353,6 +354,142 @@ function buildResolveIORunnerLocalQaStopperScript() {
|
|
|
353
354
|
''
|
|
354
355
|
].join('\n');
|
|
355
356
|
}
|
|
357
|
+
function buildResolveIORunnerBugfixComparisonQaScript() {
|
|
358
|
+
return [
|
|
359
|
+
'#!/usr/bin/env bash',
|
|
360
|
+
'set -u',
|
|
361
|
+
'TOOLS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"',
|
|
362
|
+
'source "$TOOLS_DIR/env.sh"',
|
|
363
|
+
'PROJECT_ROOT="${1:-}"',
|
|
364
|
+
'if [ -z "$PROJECT_ROOT" ]; then',
|
|
365
|
+
' echo "Usage: $0 <project-root> [baseline-ref] -- <qa-command...>" >&2',
|
|
366
|
+
' exit 2',
|
|
367
|
+
'fi',
|
|
368
|
+
'shift || true',
|
|
369
|
+
'DEFAULT_BASELINE_REF="${RESOLVEIO_RUNNER_QA_BASELINE_REF:-${RESOLVEIO_SUPPORT_QA_BASELINE_REF:-origin/master}}"',
|
|
370
|
+
'if [ "${1:-}" = "--" ]; then',
|
|
371
|
+
' BASELINE_REF="$DEFAULT_BASELINE_REF"',
|
|
372
|
+
'else',
|
|
373
|
+
' BASELINE_REF="${1:-$DEFAULT_BASELINE_REF}"',
|
|
374
|
+
' if [ "$#" -gt 0 ]; then shift || true; fi',
|
|
375
|
+
'fi',
|
|
376
|
+
'if [ "${1:-}" = "--" ]; then shift; fi',
|
|
377
|
+
'if [ "$#" -eq 0 ]; then',
|
|
378
|
+
' echo "Usage: $0 <project-root> [baseline-ref] -- <qa-command...>" >&2',
|
|
379
|
+
' exit 2',
|
|
380
|
+
'fi',
|
|
381
|
+
'PROJECT_ROOT="$(cd "$PROJECT_ROOT" && pwd)"',
|
|
382
|
+
'REPO_ROOT="$(git -C "$PROJECT_ROOT" rev-parse --show-toplevel)"',
|
|
383
|
+
'PROJECT_REL="$(git -C "$REPO_ROOT" ls-files --full-name "$PROJECT_ROOT" 2>/dev/null | head -1 | xargs dirname 2>/dev/null || true)"',
|
|
384
|
+
'if [ -z "$PROJECT_REL" ] || [ "$PROJECT_REL" = "." ]; then',
|
|
385
|
+
' PROJECT_REL="$(node - "$REPO_ROOT" "$PROJECT_ROOT" <<\'RESOLVEIO_REL\'',
|
|
386
|
+
'const path = require("path");',
|
|
387
|
+
'console.log(path.relative(process.argv[2], process.argv[3]) || ".");',
|
|
388
|
+
'RESOLVEIO_REL',
|
|
389
|
+
' )"',
|
|
390
|
+
'fi',
|
|
391
|
+
'ARTIFACT_DIR="$PROJECT_ROOT/qa-artifacts"',
|
|
392
|
+
'mkdir -p "$ARTIFACT_DIR/baseline" "$ARTIFACT_DIR/candidate"',
|
|
393
|
+
'RESULT_JSON="$ARTIFACT_DIR/bugfix-comparison-result.json"',
|
|
394
|
+
'CANDIDATE_PATCH="$ARTIFACT_DIR/bugfix-candidate.patch"',
|
|
395
|
+
'ORIGINAL_HEAD="$(git -C "$REPO_ROOT" rev-parse HEAD)"',
|
|
396
|
+
'ORIGINAL_BRANCH="$(git -C "$REPO_ROOT" symbolic-ref --short HEAD 2>/dev/null || true)"',
|
|
397
|
+
'QA_COMMAND=("$@")',
|
|
398
|
+
'STOPPER="$TOOLS_DIR/stop-local-qa.sh"',
|
|
399
|
+
'CURRENT_PHASE=""',
|
|
400
|
+
'stop_local_qa() {',
|
|
401
|
+
' "$STOPPER" "$PROJECT_ROOT" >/dev/null 2>&1 || true',
|
|
402
|
+
'}',
|
|
403
|
+
'write_json() {',
|
|
404
|
+
' node - "$RESULT_JSON" "$@" <<\'RESOLVEIO_WRITE_JSON\'',
|
|
405
|
+
'const fs = require("fs");',
|
|
406
|
+
'const [path, status, baselineExit, candidateExit, baselineRef, originalHead, projectRel, note] = process.argv.slice(2);',
|
|
407
|
+
'const payload = {',
|
|
408
|
+
' status,',
|
|
409
|
+
' baseline_ref: baselineRef,',
|
|
410
|
+
' original_head: originalHead,',
|
|
411
|
+
' project: projectRel,',
|
|
412
|
+
' baseline_exit_code: Number(baselineExit),',
|
|
413
|
+
' candidate_exit_code: Number(candidateExit),',
|
|
414
|
+
' code_switch_proven: Number(baselineExit) !== 0 && Number(candidateExit) === 0,',
|
|
415
|
+
' candidate_passed: Number(candidateExit) === 0,',
|
|
416
|
+
' baseline_failed: Number(baselineExit) !== 0,',
|
|
417
|
+
' note,',
|
|
418
|
+
' artifact_dirs: { baseline: "qa-artifacts/baseline", candidate: "qa-artifacts/candidate" },',
|
|
419
|
+
' created_at: new Date().toISOString()',
|
|
420
|
+
'};',
|
|
421
|
+
'fs.writeFileSync(path, JSON.stringify(payload, null, 2));',
|
|
422
|
+
'console.log(JSON.stringify(payload, null, 2));',
|
|
423
|
+
'RESOLVEIO_WRITE_JSON',
|
|
424
|
+
'}',
|
|
425
|
+
'snapshot_phase_artifacts() {',
|
|
426
|
+
' local phase="$1"',
|
|
427
|
+
' mkdir -p "$ARTIFACT_DIR/$phase"',
|
|
428
|
+
' find "$ARTIFACT_DIR" -maxdepth 1 -type f \\( -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" -o -name "*.webp" -o -name "*.json" -o -name "*.txt" -o -name "*.log" -o -name "*.zip" \\) -print0 2>/dev/null | while IFS= read -r -d "" file; do',
|
|
429
|
+
' cp "$file" "$ARTIFACT_DIR/$phase/$(basename "$file")" 2>/dev/null || true',
|
|
430
|
+
' done',
|
|
431
|
+
'}',
|
|
432
|
+
'capture_candidate_patch() {',
|
|
433
|
+
' : > "$CANDIDATE_PATCH"',
|
|
434
|
+
' git -C "$REPO_ROOT" diff --binary -- "$PROJECT_REL" >> "$CANDIDATE_PATCH" || true',
|
|
435
|
+
' git -C "$REPO_ROOT" diff --binary --cached -- "$PROJECT_REL" >> "$CANDIDATE_PATCH" || true',
|
|
436
|
+
'}',
|
|
437
|
+
'checkout_project_from_ref() {',
|
|
438
|
+
' local ref="$1"',
|
|
439
|
+
' git -C "$REPO_ROOT" checkout "$ref" -- "$PROJECT_REL"',
|
|
440
|
+
'}',
|
|
441
|
+
'restore_candidate() {',
|
|
442
|
+
' stop_local_qa',
|
|
443
|
+
' checkout_project_from_ref "$ORIGINAL_HEAD" || true',
|
|
444
|
+
' if [ -s "$CANDIDATE_PATCH" ]; then',
|
|
445
|
+
' git -C "$REPO_ROOT" apply --whitespace=nowarn "$CANDIDATE_PATCH" || true',
|
|
446
|
+
' fi',
|
|
447
|
+
'}',
|
|
448
|
+
'trap restore_candidate EXIT',
|
|
449
|
+
'run_phase() {',
|
|
450
|
+
' local phase="$1"',
|
|
451
|
+
' CURRENT_PHASE="$phase"',
|
|
452
|
+
' stop_local_qa',
|
|
453
|
+
' export RESOLVEIO_RUNNER_QA_PHASE="$phase"',
|
|
454
|
+
' export RESOLVEIO_SUPPORT_QA_PHASE="$phase"',
|
|
455
|
+
' export RESOLVEIO_RUNNER_QA_ARTIFACT_DIR="$ARTIFACT_DIR/$phase"',
|
|
456
|
+
' export RESOLVEIO_SUPPORT_QA_ARTIFACT_DIR="$ARTIFACT_DIR/$phase"',
|
|
457
|
+
' mkdir -p "$ARTIFACT_DIR/$phase"',
|
|
458
|
+
' set +e',
|
|
459
|
+
' (cd "$REPO_ROOT" && "${QA_COMMAND[@]}") 2>&1 | tee "$ARTIFACT_DIR/$phase/qa-command.log"',
|
|
460
|
+
' local rc="${PIPESTATUS[0]}"',
|
|
461
|
+
' set +e',
|
|
462
|
+
' snapshot_phase_artifacts "$phase"',
|
|
463
|
+
' stop_local_qa',
|
|
464
|
+
' return "$rc"',
|
|
465
|
+
'}',
|
|
466
|
+
'echo "ResolveIO bugfix comparison QA preserving candidate diff for $PROJECT_REL"',
|
|
467
|
+
'capture_candidate_patch',
|
|
468
|
+
'stop_local_qa',
|
|
469
|
+
'echo "ResolveIO bugfix comparison QA baseline phase: $BASELINE_REF"',
|
|
470
|
+
'checkout_project_from_ref "$BASELINE_REF"',
|
|
471
|
+
'run_phase baseline',
|
|
472
|
+
'BASELINE_EXIT="$?"',
|
|
473
|
+
'echo "ResolveIO bugfix comparison QA candidate phase: restored workspace candidate"',
|
|
474
|
+
'restore_candidate',
|
|
475
|
+
'run_phase candidate',
|
|
476
|
+
'CANDIDATE_EXIT="$?"',
|
|
477
|
+
'if [ "$CANDIDATE_EXIT" = "0" ] && [ "$BASELINE_EXIT" != "0" ]; then',
|
|
478
|
+
' STATUS="pass"',
|
|
479
|
+
' NOTE="Baseline failed and candidate passed for the same QA command."',
|
|
480
|
+
'elif [ "$CANDIDATE_EXIT" = "0" ]; then',
|
|
481
|
+
' STATUS="inconclusive_baseline_also_passed"',
|
|
482
|
+
' NOTE="Candidate passed, but baseline also passed; the code switch did not prove the bug fix."',
|
|
483
|
+
'else',
|
|
484
|
+
' STATUS="fail_candidate_failed"',
|
|
485
|
+
' NOTE="Candidate failed the QA command."',
|
|
486
|
+
'fi',
|
|
487
|
+
'write_json "$STATUS" "$BASELINE_EXIT" "$CANDIDATE_EXIT" "$BASELINE_REF" "$ORIGINAL_HEAD" "$PROJECT_REL" "$NOTE"',
|
|
488
|
+
'[ "$CANDIDATE_EXIT" = "0" ] || exit "$CANDIDATE_EXIT"',
|
|
489
|
+
'[ "$STATUS" = "pass" ] || exit 8',
|
|
490
|
+
''
|
|
491
|
+
].join('\n');
|
|
492
|
+
}
|
|
356
493
|
function buildResolveIORunnerQaToolsReadme(options) {
|
|
357
494
|
if (options === void 0) { options = {}; }
|
|
358
495
|
var mode = options.mode || 'runner';
|
|
@@ -371,6 +508,7 @@ function buildResolveIORunnerQaToolsReadme(options) {
|
|
|
371
508
|
"source ".concat(toolsDir, "/env.sh"),
|
|
372
509
|
"".concat(toolsDir, "/run-local-qa.sh <project-root>"),
|
|
373
510
|
"node ".concat(toolsDir, "/qa-auth-bootstrap.js <project-root> /target-route"),
|
|
511
|
+
"".concat(toolsDir, "/bugfix-comparison-qa.sh <project-root> origin/master -- bash -lc '<same QA command>'"),
|
|
374
512
|
'```',
|
|
375
513
|
'',
|
|
376
514
|
"This workspace reserves Angular QA client port ".concat(port, "; use `$").concat(clientUrlVar, "` instead of assuming 4200 is free."),
|
|
@@ -379,6 +517,7 @@ function buildResolveIORunnerQaToolsReadme(options) {
|
|
|
379
517
|
"For browser clickthrough work, start the runner once with `".concat(keepaliveVar, "=true ").concat(toolsDir, "/run-local-qa.sh <project-root> &` and reuse `$").concat(clientUrlVar, "` for all login/upload/screenshot retries. Do not restart Angular for auth failures."),
|
|
380
518
|
'Use desktop screenshots at 1920x1080 by default unless the task is explicitly mobile/responsive. Every screenshot must have a customer-facing caption.',
|
|
381
519
|
'For import/export/form-submit/data workflows, prove before/action/after with representative data and a concrete row/count/value assertion.',
|
|
520
|
+
'For bug fixes, use `bugfix-comparison-qa.sh` so baseline/master runs the exact same repro before the candidate/PR run. A passing candidate is not enough unless the comparison result shows baseline failed or the report explicitly explains why the baseline failure could not be reproduced.',
|
|
382
521
|
"Use `$".concat(usernameVar, "` and `$").concat(passwordVar, "` for the local fixture admin account unless ticket/app-specific credentials are provided."),
|
|
383
522
|
'The env file reuses `/var/lib/resolveio/puppeteer`, npm cache, worker-safe Browserslist settings, and Angular cache prep so QA should not download a browser or rebuild cold caches unnecessarily.',
|
|
384
523
|
mode === 'support'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/ai-runner-qa-tools.ts"],"names":[],"mappings":"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","file":"ai-runner-qa-tools.js","sourcesContent":["export interface ResolveIORunnerQaToolBundleOptions {\n\tmode?: 'support' | 'runner';\n\tqaClientPort?: number | string;\n\tdefaultUsername?: string;\n\tdefaultPassword?: string;\n\ttoolsBinPath?: string;\n\tbrowserslistPath?: string;\n\tmongodbBinaryCachePath?: string;\n\ttmpRoot?: string;\n\thomeRoot?: string;\n}\n\nfunction shellDoubleQuote(value: string): string {\n\treturn String(value || '').replace(/[\"\\\\$`]/g, '\\\\$&');\n}\n\nfunction normalizePort(value: number | string | undefined, fallback: string): string {\n\tconst parsed = Number.parseInt(String(value || ''), 10);\n\treturn Number.isFinite(parsed) && parsed > 0 ? String(parsed) : fallback;\n}\n\nfunction envVar(mode: 'support' | 'runner', suffix: string): string {\n\treturn mode === 'support' ? `RESOLVEIO_SUPPORT_QA_${suffix}` : `RESOLVEIO_RUNNER_QA_${suffix}`;\n}\n\nexport function buildResolveIORunnerQaEnvScript(options: ResolveIORunnerQaToolBundleOptions = {}): string {\n\tconst mode = options.mode || 'runner';\n\tconst altMode = mode === 'support' ? 'runner' : 'support';\n\tconst tmpRoot = options.tmpRoot || (mode === 'support' ? '/tmp/resolveio-support-qa' : '/tmp/resolveio-ai-runner-qa');\n\tconst homeRoot = options.homeRoot || `${tmpRoot}/home`;\n\tconst defaultPort = normalizePort(options.qaClientPort, '4200');\n\tconst username = shellDoubleQuote(options.defaultUsername || 'admin');\n\tconst password = shellDoubleQuote(options.defaultPassword || '');\n\tconst toolsBinPath = options.toolsBinPath || '';\n\tconst browserslistPath = options.browserslistPath || '';\n\tconst mongodbBinaryCachePath = options.mongodbBinaryCachePath || '';\n\tconst clientPortVar = envVar(mode, 'CLIENT_PORT');\n\tconst altClientPortVar = envVar(altMode, 'CLIENT_PORT');\n\tconst clientUrlVar = envVar(mode, 'CLIENT_URL');\n\tconst altClientUrlVar = envVar(altMode, 'CLIENT_URL');\n\tconst serverUrlVar = envVar(mode, 'SERVER_URL');\n\tconst altServerUrlVar = envVar(altMode, 'SERVER_URL');\n\tconst usernameVar = envVar(mode, 'USERNAME');\n\tconst altUsernameVar = envVar(altMode, 'USERNAME');\n\tconst passwordVar = envVar(mode, 'PASSWORD');\n\tconst altPasswordVar = envVar(altMode, 'PASSWORD');\n\tconst viewportWidthVar = envVar(mode, 'VIEWPORT_WIDTH');\n\tconst altViewportWidthVar = envVar(altMode, 'VIEWPORT_WIDTH');\n\tconst viewportHeightVar = envVar(mode, 'VIEWPORT_HEIGHT');\n\tconst altViewportHeightVar = envVar(altMode, 'VIEWPORT_HEIGHT');\n\tconst timeoutVar = envVar(mode, 'ANGULAR_STARTUP_TIMEOUT_SECONDS');\n\tconst altTimeoutVar = envVar(altMode, 'ANGULAR_STARTUP_TIMEOUT_SECONDS');\n\tconst prebundleVar = envVar(mode, 'ANGULAR_PREBUNDLE');\n\tconst altPrebundleVar = envVar(altMode, 'ANGULAR_PREBUNDLE');\n\tconst reuseVar = envVar(mode, 'REUSE_RUNNING');\n\tconst altReuseVar = envVar(altMode, 'REUSE_RUNNING');\n\tconst keepaliveVar = envVar(mode, 'KEEPALIVE');\n\tconst altKeepaliveVar = envVar(altMode, 'KEEPALIVE');\n\tconst browserLoopVar = mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_BROWSER' : 'RESOLVEIO_RUNNER_QA_BROWSER';\n\treturn [\n\t\t`export ${mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_TMP' : 'RESOLVEIO_RUNNER_QA_TMP'}=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_TMP' : 'RESOLVEIO_RUNNER_QA_TMP') + ':-' + tmpRoot + '}'}\"`,\n\t\t`export ${mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_HOME' : 'RESOLVEIO_RUNNER_QA_HOME'}=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_HOME' : 'RESOLVEIO_RUNNER_QA_HOME') + ':-' + homeRoot + '}'}\"`,\n\t\t`RESOLVEIO_QA_TMP=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_TMP' : 'RESOLVEIO_RUNNER_QA_TMP') + '}'}\"`,\n\t\t`RESOLVEIO_QA_HOME=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_HOME' : 'RESOLVEIO_RUNNER_QA_HOME') + '}'}\"`,\n\t\t'mkdir -p \"$RESOLVEIO_QA_HOME/.nvm\" \"$RESOLVEIO_QA_TMP/npm-cache\" \"$RESOLVEIO_QA_TMP/mongodb-binaries\" \"$RESOLVEIO_QA_TMP/mongodb-memory-server-core\"',\n\t\t'if [ ! -f \"$RESOLVEIO_QA_HOME/.nvm/nvm.sh\" ]; then',\n\t\t' cat > \"$RESOLVEIO_QA_HOME/.nvm/nvm.sh\" <<\\'RESOLVEIO_NVM_SHIM\\'',\n\t\t'nvm() {',\n\t\t' case \"$1\" in',\n\t\t' use|install|alias) return 0 ;;',\n\t\t' current) node -v 2>/dev/null || true; return 0 ;;',\n\t\t' *) return 0 ;;',\n\t\t' esac',\n\t\t'}',\n\t\t'RESOLVEIO_NVM_SHIM',\n\t\t'fi',\n\t\t'export HOME=\"$RESOLVEIO_QA_HOME\"',\n\t\t'export NVM_DIR=\"$RESOLVEIO_QA_HOME/.nvm\"',\n\t\ttoolsBinPath ? `export PATH=\"${toolsBinPath}:$PATH\"` : '',\n\t\t'export NODE_ENV=development',\n\t\tbrowserslistPath ? `export BROWSERSLIST_CONFIG=\"${browserslistPath}\"` : '',\n\t\t`export ${clientPortVar}=\"${'${' + clientPortVar + ':-${' + altClientPortVar + ':-' + defaultPort + '}}'}\"`,\n\t\t`export ${altClientPortVar}=\"${'${' + altClientPortVar + ':-${' + clientPortVar + '}}'}\"`,\n\t\t`export ${clientUrlVar}=\"${'${' + clientUrlVar + ':-${' + altClientUrlVar + ':-http://localhost:${' + clientPortVar + '}}}'}\"`,\n\t\t`export ${altClientUrlVar}=\"${'${' + altClientUrlVar + ':-${' + clientUrlVar + '}}'}\"`,\n\t\t`export ${serverUrlVar}=\"${'${' + serverUrlVar + ':-${' + altServerUrlVar + ':-http://localhost:8080}}'}\"`,\n\t\t`export ${altServerUrlVar}=\"${'${' + altServerUrlVar + ':-${' + serverUrlVar + '}}'}\"`,\n\t\t'export ADDITIONAL_ALLOWED_ORIGINS=\"${ADDITIONAL_ALLOWED_ORIGINS:-$' + clientUrlVar + '}\"',\n\t\t`export ${viewportWidthVar}=\"${'${' + viewportWidthVar + ':-${' + altViewportWidthVar + ':-1920}}'}\"`,\n\t\t`export ${altViewportWidthVar}=\"${'${' + altViewportWidthVar + ':-${' + viewportWidthVar + '}}'}\"`,\n\t\t`export ${viewportHeightVar}=\"${'${' + viewportHeightVar + ':-${' + altViewportHeightVar + ':-1080}}'}\"`,\n\t\t`export ${altViewportHeightVar}=\"${'${' + altViewportHeightVar + ':-${' + viewportHeightVar + '}}'}\"`,\n\t\t`export ${timeoutVar}=\"${'${' + timeoutVar + ':-${' + altTimeoutVar + ':-900}}'}\"`,\n\t\t`export ${altTimeoutVar}=\"${'${' + altTimeoutVar + ':-${' + timeoutVar + '}}'}\"`,\n\t\t`export ${prebundleVar}=\"${'${' + prebundleVar + ':-${' + altPrebundleVar + ':-false}}'}\"`,\n\t\t`export ${altPrebundleVar}=\"${'${' + altPrebundleVar + ':-${' + prebundleVar + '}}'}\"`,\n\t\t`export ${reuseVar}=\"${'${' + reuseVar + ':-${' + altReuseVar + ':-true}}'}\"`,\n\t\t`export ${altReuseVar}=\"${'${' + altReuseVar + ':-${' + reuseVar + '}}'}\"`,\n\t\t`export ${keepaliveVar}=\"${'${' + keepaliveVar + ':-${' + altKeepaliveVar + ':-false}}'}\"`,\n\t\t`export ${altKeepaliveVar}=\"${'${' + altKeepaliveVar + ':-${' + keepaliveVar + '}}'}\"`,\n\t\t`export ${usernameVar}=\"${'${' + usernameVar + ':-${' + altUsernameVar + ':-' + username + '}}'}\"`,\n\t\t`export ${altUsernameVar}=\"${'${' + altUsernameVar + ':-${' + usernameVar + '}}'}\"`,\n\t\t`export ${passwordVar}=\"${'${' + passwordVar + ':-${' + altPasswordVar + ':-' + password + '}}'}\"`,\n\t\t`export ${altPasswordVar}=\"${'${' + altPasswordVar + ':-${' + passwordVar + '}}'}\"`,\n\t\t'export PUPPETEER_CACHE_DIR=\"${PUPPETEER_CACHE_DIR:-/var/lib/resolveio/puppeteer}\"',\n\t\t'if [ ! -d \"$PUPPETEER_CACHE_DIR\" ] || [ ! -w \"$PUPPETEER_CACHE_DIR\" ]; then',\n\t\t' export PUPPETEER_CACHE_DIR=\"$RESOLVEIO_QA_TMP/puppeteer\"',\n\t\t' mkdir -p \"$PUPPETEER_CACHE_DIR\"',\n\t\t'fi',\n\t\t`for ${browserLoopVar} in \"$PUPPETEER_CACHE_DIR\"/chrome-headless-shell/linux-*/chrome-headless-shell-linux64/chrome-headless-shell \"$PUPPETEER_CACHE_DIR\"/chrome/linux-*/chrome-linux64/chrome; do`,\n\t\t` if [ -x \"$${browserLoopVar}\" ]; then`,\n\t\t` export PUPPETEER_EXECUTABLE_PATH=\"$${browserLoopVar}\"`,\n\t\t` export CHROME_BIN=\"$${browserLoopVar}\"`,\n\t\t' break',\n\t\t' fi',\n\t\t'done',\n\t\t`unset ${browserLoopVar}`,\n\t\t'export NPM_CONFIG_CACHE=\"$RESOLVEIO_QA_TMP/npm-cache\"',\n\t\t'export NPM_CONFIG_PREFER_OFFLINE=true',\n\t\t'export NPM_CONFIG_PRODUCTION=false',\n\t\t'export npm_config_production=false',\n\t\t'export RESOLVEIO_SUPPORT_MONGOMS_PACKAGE_ROOT=\"$RESOLVEIO_QA_TMP/mongodb-memory-server-core\"',\n\t\t'export MONGOMS_DOWNLOAD_DIR=\"$RESOLVEIO_QA_TMP/mongodb-binaries\"',\n\t\tmongodbBinaryCachePath ? `export RESOLVEIO_SUPPORT_SHARED_MONGOMS_DOWNLOAD_DIR=\"${mongodbBinaryCachePath}\"` : '',\n\t\t'export MONGOMS_VERSION=\"${MONGOMS_VERSION:-7.0.14}\"',\n\t\t''\n\t].filter((line) => line !== '').join('\\n');\n}\n\nexport function buildResolveIORunnerLocalQaScript(): string {\n\treturn [\n\t\t'#!/usr/bin/env bash',\n\t\t'set -u',\n\t\t'TOOLS_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"',\n\t\t'source \"$TOOLS_DIR/env.sh\"',\n\t\t'PROJECT_ROOT=\"${1:-$(pwd)}\"',\n\t\t'PROJECT_ROOT=\"$(cd \"$PROJECT_ROOT\" && pwd)\"',\n\t\t'ARTIFACT_DIR=\"$PROJECT_ROOT/qa-artifacts\"',\n\t\t'mkdir -p \"$ARTIFACT_DIR\"',\n\t\t'CLIENT_URL=\"${RESOLVEIO_RUNNER_QA_CLIENT_URL:-${RESOLVEIO_SUPPORT_QA_CLIENT_URL:-http://localhost:${RESOLVEIO_RUNNER_QA_CLIENT_PORT:-${RESOLVEIO_SUPPORT_QA_CLIENT_PORT:-4200}}}}\"',\n\t\t'SERVER_URL=\"${RESOLVEIO_RUNNER_QA_SERVER_URL:-${RESOLVEIO_SUPPORT_QA_SERVER_URL:-http://localhost:8080}}\"',\n\t\t'CLIENT_PORT=\"${RESOLVEIO_RUNNER_QA_CLIENT_PORT:-${RESOLVEIO_SUPPORT_QA_CLIENT_PORT:-4200}}\"',\n\t\t'SERVER_PORT=\"${RESOLVEIO_RUNNER_QA_SERVER_PORT:-${RESOLVEIO_SUPPORT_QA_SERVER_PORT:-8080}}\"',\n\t\t'MONGO_PORT=\"${RESOLVEIO_RUNNER_QA_MONGO_PORT:-${RESOLVEIO_SUPPORT_QA_MONGO_PORT:-3001}}\"',\n\t\t'STARTUP_TIMEOUT=\"${RESOLVEIO_RUNNER_QA_ANGULAR_STARTUP_TIMEOUT_SECONDS:-${RESOLVEIO_SUPPORT_QA_ANGULAR_STARTUP_TIMEOUT_SECONDS:-900}}\"',\n\t\t'ANGULAR_PREBUNDLE=\"${RESOLVEIO_RUNNER_QA_ANGULAR_PREBUNDLE:-${RESOLVEIO_SUPPORT_QA_ANGULAR_PREBUNDLE:-false}}\"',\n\t\t'REUSE_RUNNING=\"${RESOLVEIO_RUNNER_QA_REUSE_RUNNING:-${RESOLVEIO_SUPPORT_QA_REUSE_RUNNING:-true}}\"',\n\t\t'KEEPALIVE=\"${RESOLVEIO_RUNNER_QA_KEEPALIVE:-${RESOLVEIO_SUPPORT_QA_KEEPALIVE:-false}}\"',\n\t\t'SERVER_STABLE_SECONDS=\"${RESOLVEIO_RUNNER_QA_SERVER_STABLE_SECONDS:-${RESOLVEIO_SUPPORT_QA_SERVER_STABLE_SECONDS:-20}}\"',\n\t\t'LOCK_DIR=\"$ARTIFACT_DIR/.qa.lock\"',\n\t\t'SERVER_PID=\"\"',\n\t\t'CLIENT_PID=\"\"',\n\t\t'SERVER_REQUIRED=0',\n\t\t'ANGULAR_PREBUNDLE_ARGS=()',\n\t\t'case \"${ANGULAR_PREBUNDLE,,}\" in',\n\t\t' false|0|no|off) ANGULAR_PREBUNDLE_ARGS=(--prebundle=false) ;;',\n\t\t'esac',\n\t\t'kill_tree() {',\n\t\t' local pid=\"$1\"',\n\t\t' [ -n \"$pid\" ] || return 0',\n\t\t' for child in $(pgrep -P \"$pid\" 2>/dev/null || true); do kill_tree \"$child\"; done',\n\t\t' kill \"$pid\" >/dev/null 2>&1 || true',\n\t\t' sleep 1',\n\t\t' kill -0 \"$pid\" >/dev/null 2>&1 && kill -9 \"$pid\" >/dev/null 2>&1 || true',\n\t\t'}',\n\t\t'cleanup_project_processes() {',\n\t\t' for pid_file in \"$ARTIFACT_DIR/server.pid\" \"$ARTIFACT_DIR/client.pid\"; do',\n\t\t' [ -f \"$pid_file\" ] || continue',\n\t\t' pid=\"$(cat \"$pid_file\" 2>/dev/null || true)\"',\n\t\t' kill_tree \"$pid\"',\n\t\t' rm -f \"$pid_file\"',\n\t\t' done',\n\t\t' if command -v lsof >/dev/null 2>&1; then',\n\t\t' for port in \"$CLIENT_PORT\" \"$SERVER_PORT\" \"$MONGO_PORT\"; do',\n\t\t' [ -n \"$port\" ] || continue',\n\t\t' for pid in $(lsof -ti tcp:\"$port\" 2>/dev/null || true); do kill_tree \"$pid\"; done',\n\t\t' done',\n\t\t' fi',\n\t\t' for pid in $(ps -eo pid=,args= | awk -v root=\"$PROJECT_ROOT\" \\'index($0, root) && $0 ~ /(ng serve|node .*node_modules\\\\/\\\\.bin\\\\/ng|esbuild|npm run client|start_client\\\\.sh|npm run server|start_server\\\\.sh|nodemon|node .*tmp\\\\/index\\\\.js|mongod|mongodb-binaries\\\\/mongod)/ {print $1}\\' 2>/dev/null || true); do',\n\t\t' [ \"$pid\" = \"$$\" ] && continue',\n\t\t' kill_tree \"$pid\"',\n\t\t' done',\n\t\t'}',\n\t\t'cleanup() {',\n\t\t' kill_tree \"$SERVER_PID\"',\n\t\t' kill_tree \"$CLIENT_PID\"',\n\t\t' cleanup_project_processes',\n\t\t' rmdir \"$LOCK_DIR\" >/dev/null 2>&1 || true',\n\t\t'}',\n\t\t'trap cleanup EXIT',\n\t\t'probe_url() { node - \"$1\" <<\\'RESOLVEIO_PROBE\\'',\n\t\t'const http = require(\"http\");',\n\t\t'const https = require(\"https\");',\n\t\t'const url = process.argv[2];',\n\t\t'const mod = /^https:/i.test(url) ? https : http;',\n\t\t'const req = mod.get(url, { timeout: 2500 }, (res) => { res.resume(); process.exit(res.statusCode && res.statusCode < 500 ? 0 : 1); });',\n\t\t'req.on(\"timeout\", () => req.destroy(new Error(\"timeout\")));',\n\t\t'req.on(\"error\", () => process.exit(1));',\n\t\t'RESOLVEIO_PROBE',\n\t\t'}',\n\t\t'truthy() { case \"${1,,}\" in true|1|yes|on) return 0 ;; *) return 1 ;; esac; }',\n\t\t'reuse_running_app_if_ready() {',\n\t\t' truthy \"$REUSE_RUNNING\" || return 1',\n\t\t' [ -d \"$PROJECT_ROOT/server\" ] && SERVER_REQUIRED=1 || SERVER_REQUIRED=0',\n\t\t' probe_url \"$CLIENT_URL\" || return 1',\n\t\t' if [ \"$SERVER_REQUIRED\" = \"1\" ] && ! probe_url \"$SERVER_URL\"; then return 1; fi',\n\t\t' echo \"ResolveIO AI runner QA reusing already-ready local app at $CLIENT_URL\"',\n\t\t' return 0',\n\t\t'}',\n\t\t'log_has_fatal() {',\n\t\t' local file=\"$1\"',\n\t\t' [ -f \"$file\" ] || return 1',\n\t\t' grep -Eiq \"Unhandled Rejection|Cannot read properties of undefined|TypeError|ReferenceError|EADDRINUSE|app crashed|Failed to compile|Error: Cannot find module|NG[0-9]{4}|TS[0-9]{4}\" \"$file\"',\n\t\t'}',\n\t\t'prepare_angular_cache_dirs() {',\n\t\t' [ -d \"$PROJECT_ROOT\" ] || return 0',\n\t\t' mkdir -p \"$PROJECT_ROOT/.angular/cache\" 2>/dev/null || true',\n\t\t' local version=\"\"',\n\t\t' for pkg in \"$PROJECT_ROOT/node_modules/@angular/build/package.json\" \"$PROJECT_ROOT/node_modules/@angular/cli/package.json\" \"$PROJECT_ROOT/node_modules/@angular-devkit/build-angular/package.json\"; do',\n\t\t' if [ -f \"$pkg\" ]; then',\n\t\t' version=\"$(node -e \"try{console.log(require(process.argv[1]).version||\\\\\\\"\\\\\\\")}catch(e){}\" \"$pkg\" 2>/dev/null | head -1)\"',\n\t\t' [ -n \"$version\" ] && break',\n\t\t' fi',\n\t\t' done',\n\t\t' [ -n \"$version\" ] || return 0',\n\t\t' node - \"$PROJECT_ROOT/angular.json\" \"$(basename \"$PROJECT_ROOT\")\" <<\\'RESOLVEIO_ANGULAR_CACHE_PROJECTS\\' | while IFS= read -r project; do',\n\t\t'const fs = require(\"fs\");',\n\t\t'const path = process.argv[2];',\n\t\t'const fallback = process.argv[3];',\n\t\t'const names = new Set([fallback].filter(Boolean));',\n\t\t'try {',\n\t\t' const parsed = JSON.parse(fs.readFileSync(path, \"utf8\"));',\n\t\t' if (parsed.defaultProject) names.add(String(parsed.defaultProject));',\n\t\t' if (parsed.projects && typeof parsed.projects === \"object\") Object.keys(parsed.projects).forEach((name) => names.add(String(name)));',\n\t\t'} catch (error) {}',\n\t\t'for (const name of names) console.log(name.replace(/[^A-Za-z0-9._-]/g, \"_\"));',\n\t\t'RESOLVEIO_ANGULAR_CACHE_PROJECTS',\n\t\t' [ -n \"$project\" ] || continue',\n\t\t' mkdir -p \"$PROJECT_ROOT/.angular/cache/$version/$project/vite\" 2>/dev/null || true',\n\t\t' done',\n\t\t'}',\n\t\t'server_has_started() {',\n\t\t' local file=\"$ARTIFACT_DIR/server.log\"',\n\t\t' [ -f \"$file\" ] || return 1',\n\t\t' grep -Eiq \"nodemon.*starting|node .*tmp/index\\\\.js|Running as Worker|Standalone Node Reaper|listening on|server listening|Server listening|app listening|App listening|Finished .default.\" \"$file\"',\n\t\t'}',\n\t\t'wait_for_server_ready() {',\n\t\t' [ \"$SERVER_REQUIRED\" = \"1\" ] || return 0',\n\t\t' local end=$((SECONDS + STARTUP_TIMEOUT))',\n\t\t' while [ \"$SECONDS\" -lt \"$end\" ]; do',\n\t\t' if log_has_fatal \"$ARTIFACT_DIR/server.log\"; then return 4; fi',\n\t\t' if [ -n \"$SERVER_PID\" ] && ! kill -0 \"$SERVER_PID\" >/dev/null 2>&1; then return 4; fi',\n\t\t' if server_has_started; then',\n\t\t' local stable_until=$((SECONDS + SERVER_STABLE_SECONDS))',\n\t\t' while [ \"$SECONDS\" -lt \"$stable_until\" ]; do if log_has_fatal \"$ARTIFACT_DIR/server.log\"; then return 4; fi; sleep 2; done',\n\t\t' return 0',\n\t\t' fi',\n\t\t' sleep 5',\n\t\t' done',\n\t\t' return 4',\n\t\t'}',\n\t\t'wait_for_client() {',\n\t\t' local end=$((SECONDS + STARTUP_TIMEOUT))',\n\t\t' while [ \"$SECONDS\" -lt \"$end\" ]; do',\n\t\t' if [ -n \"$CLIENT_PID\" ] && ! kill -0 \"$CLIENT_PID\" >/dev/null 2>&1; then return 2; fi',\n\t\t' if log_has_fatal \"$ARTIFACT_DIR/client.log\"; then return 3; fi',\n\t\t' if log_has_fatal \"$ARTIFACT_DIR/server.log\"; then return 4; fi',\n\t\t' if probe_url \"$CLIENT_URL\"; then wait_for_server_ready || return $?; return 0; fi',\n\t\t' sleep 5',\n\t\t' done',\n\t\t' return 1',\n\t\t'}',\n\t\t'if reuse_running_app_if_ready; then exit 0; fi',\n\t\t'if ! mkdir \"$LOCK_DIR\" 2>/dev/null; then',\n\t\t' echo \"ResolveIO AI runner QA lock is already held for $PROJECT_ROOT; cleaning stale local QA processes before retrying.\" | tee \"$ARTIFACT_DIR/runner.log\"',\n\t\t' cleanup_project_processes',\n\t\t' rmdir \"$LOCK_DIR\" >/dev/null 2>&1 || true',\n\t\t' if ! mkdir \"$LOCK_DIR\" 2>/dev/null; then',\n\t\t' echo \"ResolveIO AI runner QA lock is still held for $PROJECT_ROOT after cleanup. Stop the existing QA runner before starting another.\" | tee -a \"$ARTIFACT_DIR/runner.log\"',\n\t\t' exit 6',\n\t\t' fi',\n\t\t'fi',\n\t\t'cleanup_project_processes',\n\t\t'if [ -d \"$PROJECT_ROOT/server\" ]; then',\n\t\t' SERVER_REQUIRED=1',\n\t\t' (cd \"$PROJECT_ROOT/server\" && source \"$TOOLS_DIR/env.sh\" && { npm run server || ./start_server.sh; } 2>&1 | tee \"$ARTIFACT_DIR/server.log\") &',\n\t\t' SERVER_PID=$!',\n\t\t' wait_for_server_ready',\n\t\t' SERVER_RESULT=$?',\n\t\t' if [ \"$SERVER_RESULT\" != \"0\" ]; then echo \"ResolveIO AI runner QA server startup fatal error. See $ARTIFACT_DIR/server.log\"; exit \"$SERVER_RESULT\"; fi',\n\t\t'fi',\n\t\t'CLIENT_HOST=\"${RESOLVEIO_RUNNER_QA_CLIENT_HOST:-${RESOLVEIO_SUPPORT_QA_CLIENT_HOST:-0.0.0.0}}\"',\n\t\t'if [ -x \"$PROJECT_ROOT/node_modules/.bin/ng\" ]; then',\n\t\t' prepare_angular_cache_dirs',\n\t\t' (cd \"$PROJECT_ROOT\" && source \"$TOOLS_DIR/env.sh\" && node --max_old_space_size=8048 ./node_modules/.bin/ng serve --watch --configuration local --host \"$CLIENT_HOST\" --port \"$CLIENT_PORT\" \"${ANGULAR_PREBUNDLE_ARGS[@]}\" 2>&1 | tee \"$ARTIFACT_DIR/client.log\") &',\n\t\t'elif [ -x \"$PROJECT_ROOT/start_client.sh\" ]; then',\n\t\t' (cd \"$PROJECT_ROOT\" && source \"$TOOLS_DIR/env.sh\" && ./start_client.sh 2>&1 | tee \"$ARTIFACT_DIR/client.log\") &',\n\t\t'elif node -e \"const p=require(process.argv[1]); process.exit(p.scripts&&p.scripts.client?0:1)\" \"$PROJECT_ROOT/package.json\" >/dev/null 2>&1; then',\n\t\t' (cd \"$PROJECT_ROOT\" && source \"$TOOLS_DIR/env.sh\" && npm run client 2>&1 | tee \"$ARTIFACT_DIR/client.log\") &',\n\t\t'else',\n\t\t' echo \"ResolveIO AI runner QA cannot find Angular CLI, start_client.sh, or npm client script for $PROJECT_ROOT\" | tee \"$ARTIFACT_DIR/client.log\"',\n\t\t' exit 5',\n\t\t'fi',\n\t\t'CLIENT_PID=$!',\n\t\t'wait_for_client',\n\t\t'RESULT=$?',\n\t\t'case \"$RESULT\" in',\n\t\t' 0)',\n\t\t' echo \"ResolveIO AI runner QA local app ready at $CLIENT_URL\";',\n\t\t' echo \"$SERVER_PID\" > \"$ARTIFACT_DIR/server.pid\";',\n\t\t' echo \"$CLIENT_PID\" > \"$ARTIFACT_DIR/client.pid\";',\n\t\t' if truthy \"$KEEPALIVE\"; then echo \"ResolveIO AI runner QA keepalive enabled; server/client remain running until this process is stopped.\"; wait; fi;',\n\t\t' exit 0',\n\t\t' ;;',\n\t\t' 2) echo \"ResolveIO AI runner QA client process exited before $CLIENT_URL became ready. See $ARTIFACT_DIR/client.log\"; exit 2 ;;',\n\t\t' 3) echo \"ResolveIO AI runner QA client startup fatal error. See $ARTIFACT_DIR/client.log\"; exit 3 ;;',\n\t\t' 4) echo \"ResolveIO AI runner QA server startup fatal error. See $ARTIFACT_DIR/server.log\"; exit 4 ;;',\n\t\t' *) echo \"ResolveIO AI runner QA local app did not become ready at $CLIENT_URL within ${STARTUP_TIMEOUT}s. See $ARTIFACT_DIR/client.log and $ARTIFACT_DIR/server.log\"; exit 1 ;;',\n\t\t'esac',\n\t\t''\n\t].join('\\n');\n}\n\nexport function buildResolveIORunnerLocalQaStopperScript(): string {\n\treturn [\n\t\t'#!/usr/bin/env bash',\n\t\t'set -u',\n\t\t'TOOLS_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"',\n\t\t'source \"$TOOLS_DIR/env.sh\"',\n\t\t'PROJECT_ROOT=\"${1:-$(pwd)}\"',\n\t\t'PROJECT_ROOT=\"$(cd \"$PROJECT_ROOT\" && pwd)\"',\n\t\t'ARTIFACT_DIR=\"$PROJECT_ROOT/qa-artifacts\"',\n\t\t'CLIENT_PORT=\"${RESOLVEIO_RUNNER_QA_CLIENT_PORT:-${RESOLVEIO_SUPPORT_QA_CLIENT_PORT:-4200}}\"',\n\t\t'SERVER_PORT=\"${RESOLVEIO_RUNNER_QA_SERVER_PORT:-${RESOLVEIO_SUPPORT_QA_SERVER_PORT:-8080}}\"',\n\t\t'MONGO_PORT=\"${RESOLVEIO_RUNNER_QA_MONGO_PORT:-${RESOLVEIO_SUPPORT_QA_MONGO_PORT:-3001}}\"',\n\t\t'kill_tree() {',\n\t\t' local pid=\"$1\"',\n\t\t' [ -n \"$pid\" ] || return 0',\n\t\t' kill -0 \"$pid\" >/dev/null 2>&1 || return 0',\n\t\t' for child in $(pgrep -P \"$pid\" 2>/dev/null || true); do kill_tree \"$child\"; done',\n\t\t' kill \"$pid\" >/dev/null 2>&1 || true',\n\t\t' sleep 1',\n\t\t' kill -0 \"$pid\" >/dev/null 2>&1 && kill -9 \"$pid\" >/dev/null 2>&1 || true',\n\t\t'}',\n\t\t'for pid_file in \"$ARTIFACT_DIR/server.pid\" \"$ARTIFACT_DIR/client.pid\"; do',\n\t\t' [ -f \"$pid_file\" ] || continue',\n\t\t' pid=\"$(cat \"$pid_file\" 2>/dev/null || true)\"',\n\t\t' kill_tree \"$pid\"',\n\t\t' rm -f \"$pid_file\"',\n\t\t'done',\n\t\t'if command -v lsof >/dev/null 2>&1; then',\n\t\t' for port in \"$CLIENT_PORT\" \"$SERVER_PORT\" \"$MONGO_PORT\"; do',\n\t\t' [ -n \"$port\" ] || continue',\n\t\t' for pid in $(lsof -ti tcp:\"$port\" 2>/dev/null || true); do kill_tree \"$pid\"; done',\n\t\t' done',\n\t\t'fi',\n\t\t'for pid in $(ps -eo pid=,args= | awk -v root=\"$PROJECT_ROOT\" \\'index($0, root) && $0 ~ /(ng serve|node .*node_modules\\\\/\\\\.bin\\\\/ng|esbuild|npm run client|start_client\\\\.sh|npm run server|start_server\\\\.sh|nodemon|node .*tmp\\\\/index\\\\.js|mongod|mongodb-binaries\\\\/mongod)/ {print $1}\\' 2>/dev/null || true); do',\n\t\t' [ \"$pid\" = \"$$\" ] && continue',\n\t\t' kill_tree \"$pid\"',\n\t\t'done',\n\t\t'rmdir \"$ARTIFACT_DIR/.qa.lock\" >/dev/null 2>&1 || true',\n\t\t'echo \"ResolveIO AI runner QA local app stopped for $PROJECT_ROOT\"',\n\t\t''\n\t].join('\\n');\n}\n\nexport function buildResolveIORunnerQaToolsReadme(options: ResolveIORunnerQaToolBundleOptions = {}): string {\n\tconst mode = options.mode || 'runner';\n\tconst toolsDir = mode === 'support' ? '.resolveio-support-tools' : '.resolveio-ai-runner-tools';\n\tconst port = normalizePort(options.qaClientPort, '4200');\n\tconst clientUrlVar = envVar(mode, 'CLIENT_URL');\n\tconst keepaliveVar = envVar(mode, 'KEEPALIVE');\n\tconst usernameVar = envVar(mode, 'USERNAME');\n\tconst passwordVar = envVar(mode, 'PASSWORD');\n\treturn [\n\t\t`# ResolveIO ${mode === 'support' ? 'Support' : 'AI Runner'} Local QA Tools`,\n\t\t'',\n\t\t'These scripts are generated by `@resolveio/server-lib` and are shared by support tickets, AICoder app-builder runs, and AI-terminal runs.',\n\t\t'',\n\t\t'```bash',\n\t\t`source ${toolsDir}/env.sh`,\n\t\t`${toolsDir}/run-local-qa.sh <project-root>`,\n\t\t`node ${toolsDir}/qa-auth-bootstrap.js <project-root> /target-route`,\n\t\t'```',\n\t\t'',\n\t\t`This workspace reserves Angular QA client port ${port}; use \\`$${clientUrlVar}\\` instead of assuming 4200 is free.`,\n\t\t'The local QA runner starts server/client, polls the reserved client URL, writes `qa-artifacts/server.log` and `qa-artifacts/client.log`, and fails fast on fatal startup/runtime errors.',\n\t\t'The shared auth bootstrap calls `/login`, then `/accessToken`, clears service workers/cache/IndexedDB/local storage for the exact localhost client origin, seeds `refreshToken`, `accessToken`, `user`, and `lastURL`, and writes `qa-artifacts/auth-bootstrap-result.json` plus a ready/failure screenshot.',\n\t\t`For browser clickthrough work, start the runner once with \\`${keepaliveVar}=true ${toolsDir}/run-local-qa.sh <project-root> &\\` and reuse \\`$${clientUrlVar}\\` for all login/upload/screenshot retries. Do not restart Angular for auth failures.`,\n\t\t'Use desktop screenshots at 1920x1080 by default unless the task is explicitly mobile/responsive. Every screenshot must have a customer-facing caption.',\n\t\t'For import/export/form-submit/data workflows, prove before/action/after with representative data and a concrete row/count/value assertion.',\n\t\t`Use \\`$${usernameVar}\\` and \\`$${passwordVar}\\` for the local fixture admin account unless ticket/app-specific credentials are provided.`,\n\t\t'The env file reuses `/var/lib/resolveio/puppeteer`, npm cache, worker-safe Browserslist settings, and Angular cache prep so QA should not download a browser or rebuild cold caches unnecessarily.',\n\t\tmode === 'support'\n\t\t\t? 'Support workspaces also stage local `mongod` and `mongosh` wrappers so app server scripts can start MongoDB when the worker image does not have MongoDB installed.'\n\t\t\t: '',\n\t\t''\n\t].filter((line) => line !== '').join('\\n');\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/util/ai-runner-qa-tools.ts"],"names":[],"mappings":"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","file":"ai-runner-qa-tools.js","sourcesContent":["export interface ResolveIORunnerQaToolBundleOptions {\n\tmode?: 'support' | 'runner';\n\tqaClientPort?: number | string;\n\tdefaultUsername?: string;\n\tdefaultPassword?: string;\n\ttoolsBinPath?: string;\n\tbrowserslistPath?: string;\n\tmongodbBinaryCachePath?: string;\n\ttmpRoot?: string;\n\thomeRoot?: string;\n}\n\nfunction shellDoubleQuote(value: string): string {\n\treturn String(value || '').replace(/[\"\\\\$`]/g, '\\\\$&');\n}\n\nfunction normalizePort(value: number | string | undefined, fallback: string): string {\n\tconst parsed = Number.parseInt(String(value || ''), 10);\n\treturn Number.isFinite(parsed) && parsed > 0 ? String(parsed) : fallback;\n}\n\nfunction envVar(mode: 'support' | 'runner', suffix: string): string {\n\treturn mode === 'support' ? `RESOLVEIO_SUPPORT_QA_${suffix}` : `RESOLVEIO_RUNNER_QA_${suffix}`;\n}\n\nexport function buildResolveIORunnerQaEnvScript(options: ResolveIORunnerQaToolBundleOptions = {}): string {\n\tconst mode = options.mode || 'runner';\n\tconst altMode = mode === 'support' ? 'runner' : 'support';\n\tconst tmpRoot = options.tmpRoot || (mode === 'support' ? '/tmp/resolveio-support-qa' : '/tmp/resolveio-ai-runner-qa');\n\tconst homeRoot = options.homeRoot || `${tmpRoot}/home`;\n\tconst defaultPort = normalizePort(options.qaClientPort, '4200');\n\tconst username = shellDoubleQuote(options.defaultUsername || 'admin');\n\tconst password = shellDoubleQuote(options.defaultPassword || '');\n\tconst toolsBinPath = options.toolsBinPath || '';\n\tconst browserslistPath = options.browserslistPath || '';\n\tconst mongodbBinaryCachePath = options.mongodbBinaryCachePath || '';\n\tconst clientPortVar = envVar(mode, 'CLIENT_PORT');\n\tconst altClientPortVar = envVar(altMode, 'CLIENT_PORT');\n\tconst clientUrlVar = envVar(mode, 'CLIENT_URL');\n\tconst altClientUrlVar = envVar(altMode, 'CLIENT_URL');\n\tconst serverUrlVar = envVar(mode, 'SERVER_URL');\n\tconst altServerUrlVar = envVar(altMode, 'SERVER_URL');\n\tconst usernameVar = envVar(mode, 'USERNAME');\n\tconst altUsernameVar = envVar(altMode, 'USERNAME');\n\tconst passwordVar = envVar(mode, 'PASSWORD');\n\tconst altPasswordVar = envVar(altMode, 'PASSWORD');\n\tconst viewportWidthVar = envVar(mode, 'VIEWPORT_WIDTH');\n\tconst altViewportWidthVar = envVar(altMode, 'VIEWPORT_WIDTH');\n\tconst viewportHeightVar = envVar(mode, 'VIEWPORT_HEIGHT');\n\tconst altViewportHeightVar = envVar(altMode, 'VIEWPORT_HEIGHT');\n\tconst timeoutVar = envVar(mode, 'ANGULAR_STARTUP_TIMEOUT_SECONDS');\n\tconst altTimeoutVar = envVar(altMode, 'ANGULAR_STARTUP_TIMEOUT_SECONDS');\n\tconst prebundleVar = envVar(mode, 'ANGULAR_PREBUNDLE');\n\tconst altPrebundleVar = envVar(altMode, 'ANGULAR_PREBUNDLE');\n\tconst reuseVar = envVar(mode, 'REUSE_RUNNING');\n\tconst altReuseVar = envVar(altMode, 'REUSE_RUNNING');\n\tconst keepaliveVar = envVar(mode, 'KEEPALIVE');\n\tconst altKeepaliveVar = envVar(altMode, 'KEEPALIVE');\n\tconst browserLoopVar = mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_BROWSER' : 'RESOLVEIO_RUNNER_QA_BROWSER';\n\treturn [\n\t\t`export ${mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_TMP' : 'RESOLVEIO_RUNNER_QA_TMP'}=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_TMP' : 'RESOLVEIO_RUNNER_QA_TMP') + ':-' + tmpRoot + '}'}\"`,\n\t\t`export ${mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_HOME' : 'RESOLVEIO_RUNNER_QA_HOME'}=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_HOME' : 'RESOLVEIO_RUNNER_QA_HOME') + ':-' + homeRoot + '}'}\"`,\n\t\t`RESOLVEIO_QA_TMP=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_TMP' : 'RESOLVEIO_RUNNER_QA_TMP') + '}'}\"`,\n\t\t`RESOLVEIO_QA_HOME=\"${'${' + (mode === 'support' ? 'RESOLVEIO_SUPPORT_QA_HOME' : 'RESOLVEIO_RUNNER_QA_HOME') + '}'}\"`,\n\t\t'mkdir -p \"$RESOLVEIO_QA_HOME/.nvm\" \"$RESOLVEIO_QA_TMP/npm-cache\" \"$RESOLVEIO_QA_TMP/mongodb-binaries\" \"$RESOLVEIO_QA_TMP/mongodb-memory-server-core\"',\n\t\t'if [ ! -f \"$RESOLVEIO_QA_HOME/.nvm/nvm.sh\" ]; then',\n\t\t' cat > \"$RESOLVEIO_QA_HOME/.nvm/nvm.sh\" <<\\'RESOLVEIO_NVM_SHIM\\'',\n\t\t'nvm() {',\n\t\t' case \"$1\" in',\n\t\t' use|install|alias) return 0 ;;',\n\t\t' current) node -v 2>/dev/null || true; return 0 ;;',\n\t\t' *) return 0 ;;',\n\t\t' esac',\n\t\t'}',\n\t\t'RESOLVEIO_NVM_SHIM',\n\t\t'fi',\n\t\t'export HOME=\"$RESOLVEIO_QA_HOME\"',\n\t\t'export NVM_DIR=\"$RESOLVEIO_QA_HOME/.nvm\"',\n\t\ttoolsBinPath ? `export PATH=\"${toolsBinPath}:$PATH\"` : '',\n\t\t'export NODE_ENV=development',\n\t\tbrowserslistPath ? `export BROWSERSLIST_CONFIG=\"${browserslistPath}\"` : '',\n\t\t`export ${clientPortVar}=\"${'${' + clientPortVar + ':-${' + altClientPortVar + ':-' + defaultPort + '}}'}\"`,\n\t\t`export ${altClientPortVar}=\"${'${' + altClientPortVar + ':-${' + clientPortVar + '}}'}\"`,\n\t\t`export ${clientUrlVar}=\"${'${' + clientUrlVar + ':-${' + altClientUrlVar + ':-http://localhost:${' + clientPortVar + '}}}'}\"`,\n\t\t`export ${altClientUrlVar}=\"${'${' + altClientUrlVar + ':-${' + clientUrlVar + '}}'}\"`,\n\t\t`export ${serverUrlVar}=\"${'${' + serverUrlVar + ':-${' + altServerUrlVar + ':-http://localhost:8080}}'}\"`,\n\t\t`export ${altServerUrlVar}=\"${'${' + altServerUrlVar + ':-${' + serverUrlVar + '}}'}\"`,\n\t\t'export ADDITIONAL_ALLOWED_ORIGINS=\"${ADDITIONAL_ALLOWED_ORIGINS:-$' + clientUrlVar + '}\"',\n\t\t`export ${viewportWidthVar}=\"${'${' + viewportWidthVar + ':-${' + altViewportWidthVar + ':-1920}}'}\"`,\n\t\t`export ${altViewportWidthVar}=\"${'${' + altViewportWidthVar + ':-${' + viewportWidthVar + '}}'}\"`,\n\t\t`export ${viewportHeightVar}=\"${'${' + viewportHeightVar + ':-${' + altViewportHeightVar + ':-1080}}'}\"`,\n\t\t`export ${altViewportHeightVar}=\"${'${' + altViewportHeightVar + ':-${' + viewportHeightVar + '}}'}\"`,\n\t\t`export ${timeoutVar}=\"${'${' + timeoutVar + ':-${' + altTimeoutVar + ':-900}}'}\"`,\n\t\t`export ${altTimeoutVar}=\"${'${' + altTimeoutVar + ':-${' + timeoutVar + '}}'}\"`,\n\t\t`export ${prebundleVar}=\"${'${' + prebundleVar + ':-${' + altPrebundleVar + ':-false}}'}\"`,\n\t\t`export ${altPrebundleVar}=\"${'${' + altPrebundleVar + ':-${' + prebundleVar + '}}'}\"`,\n\t\t`export ${reuseVar}=\"${'${' + reuseVar + ':-${' + altReuseVar + ':-true}}'}\"`,\n\t\t`export ${altReuseVar}=\"${'${' + altReuseVar + ':-${' + reuseVar + '}}'}\"`,\n\t\t`export ${keepaliveVar}=\"${'${' + keepaliveVar + ':-${' + altKeepaliveVar + ':-false}}'}\"`,\n\t\t`export ${altKeepaliveVar}=\"${'${' + altKeepaliveVar + ':-${' + keepaliveVar + '}}'}\"`,\n\t\t`export ${usernameVar}=\"${'${' + usernameVar + ':-${' + altUsernameVar + ':-' + username + '}}'}\"`,\n\t\t`export ${altUsernameVar}=\"${'${' + altUsernameVar + ':-${' + usernameVar + '}}'}\"`,\n\t\t`export ${passwordVar}=\"${'${' + passwordVar + ':-${' + altPasswordVar + ':-' + password + '}}'}\"`,\n\t\t`export ${altPasswordVar}=\"${'${' + altPasswordVar + ':-${' + passwordVar + '}}'}\"`,\n\t\t'export PUPPETEER_CACHE_DIR=\"${PUPPETEER_CACHE_DIR:-/var/lib/resolveio/puppeteer}\"',\n\t\t'if [ ! -d \"$PUPPETEER_CACHE_DIR\" ] || [ ! -w \"$PUPPETEER_CACHE_DIR\" ]; then',\n\t\t' export PUPPETEER_CACHE_DIR=\"$RESOLVEIO_QA_TMP/puppeteer\"',\n\t\t' mkdir -p \"$PUPPETEER_CACHE_DIR\"',\n\t\t'fi',\n\t\t`for ${browserLoopVar} in \"$PUPPETEER_CACHE_DIR\"/chrome-headless-shell/linux-*/chrome-headless-shell-linux64/chrome-headless-shell \"$PUPPETEER_CACHE_DIR\"/chrome/linux-*/chrome-linux64/chrome; do`,\n\t\t` if [ -x \"$${browserLoopVar}\" ]; then`,\n\t\t` export PUPPETEER_EXECUTABLE_PATH=\"$${browserLoopVar}\"`,\n\t\t` export CHROME_BIN=\"$${browserLoopVar}\"`,\n\t\t' break',\n\t\t' fi',\n\t\t'done',\n\t\t`unset ${browserLoopVar}`,\n\t\t'export NPM_CONFIG_CACHE=\"$RESOLVEIO_QA_TMP/npm-cache\"',\n\t\t'export NPM_CONFIG_PREFER_OFFLINE=true',\n\t\t'export NPM_CONFIG_PRODUCTION=false',\n\t\t'export npm_config_production=false',\n\t\t'export RESOLVEIO_SUPPORT_MONGOMS_PACKAGE_ROOT=\"$RESOLVEIO_QA_TMP/mongodb-memory-server-core\"',\n\t\t'export MONGOMS_DOWNLOAD_DIR=\"$RESOLVEIO_QA_TMP/mongodb-binaries\"',\n\t\tmongodbBinaryCachePath ? `export RESOLVEIO_SUPPORT_SHARED_MONGOMS_DOWNLOAD_DIR=\"${mongodbBinaryCachePath}\"` : '',\n\t\t'export MONGOMS_VERSION=\"${MONGOMS_VERSION:-7.0.14}\"',\n\t\t''\n\t].filter((line) => line !== '').join('\\n');\n}\n\nexport function buildResolveIORunnerLocalQaScript(): string {\n\treturn [\n\t\t'#!/usr/bin/env bash',\n\t\t'set -u',\n\t\t'TOOLS_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"',\n\t\t'source \"$TOOLS_DIR/env.sh\"',\n\t\t'PROJECT_ROOT=\"${1:-$(pwd)}\"',\n\t\t'PROJECT_ROOT=\"$(cd \"$PROJECT_ROOT\" && pwd)\"',\n\t\t'ARTIFACT_DIR=\"$PROJECT_ROOT/qa-artifacts\"',\n\t\t'mkdir -p \"$ARTIFACT_DIR\"',\n\t\t'CLIENT_URL=\"${RESOLVEIO_RUNNER_QA_CLIENT_URL:-${RESOLVEIO_SUPPORT_QA_CLIENT_URL:-http://localhost:${RESOLVEIO_RUNNER_QA_CLIENT_PORT:-${RESOLVEIO_SUPPORT_QA_CLIENT_PORT:-4200}}}}\"',\n\t\t'SERVER_URL=\"${RESOLVEIO_RUNNER_QA_SERVER_URL:-${RESOLVEIO_SUPPORT_QA_SERVER_URL:-http://localhost:8080}}\"',\n\t\t'CLIENT_PORT=\"${RESOLVEIO_RUNNER_QA_CLIENT_PORT:-${RESOLVEIO_SUPPORT_QA_CLIENT_PORT:-4200}}\"',\n\t\t'SERVER_PORT=\"${RESOLVEIO_RUNNER_QA_SERVER_PORT:-${RESOLVEIO_SUPPORT_QA_SERVER_PORT:-8080}}\"',\n\t\t'MONGO_PORT=\"${RESOLVEIO_RUNNER_QA_MONGO_PORT:-${RESOLVEIO_SUPPORT_QA_MONGO_PORT:-3001}}\"',\n\t\t'STARTUP_TIMEOUT=\"${RESOLVEIO_RUNNER_QA_ANGULAR_STARTUP_TIMEOUT_SECONDS:-${RESOLVEIO_SUPPORT_QA_ANGULAR_STARTUP_TIMEOUT_SECONDS:-900}}\"',\n\t\t'ANGULAR_PREBUNDLE=\"${RESOLVEIO_RUNNER_QA_ANGULAR_PREBUNDLE:-${RESOLVEIO_SUPPORT_QA_ANGULAR_PREBUNDLE:-false}}\"',\n\t\t'REUSE_RUNNING=\"${RESOLVEIO_RUNNER_QA_REUSE_RUNNING:-${RESOLVEIO_SUPPORT_QA_REUSE_RUNNING:-true}}\"',\n\t\t'KEEPALIVE=\"${RESOLVEIO_RUNNER_QA_KEEPALIVE:-${RESOLVEIO_SUPPORT_QA_KEEPALIVE:-false}}\"',\n\t\t'SERVER_STABLE_SECONDS=\"${RESOLVEIO_RUNNER_QA_SERVER_STABLE_SECONDS:-${RESOLVEIO_SUPPORT_QA_SERVER_STABLE_SECONDS:-20}}\"',\n\t\t'LOCK_DIR=\"$ARTIFACT_DIR/.qa.lock\"',\n\t\t'SERVER_PID=\"\"',\n\t\t'CLIENT_PID=\"\"',\n\t\t'SERVER_REQUIRED=0',\n\t\t'ANGULAR_PREBUNDLE_ARGS=()',\n\t\t'case \"${ANGULAR_PREBUNDLE,,}\" in',\n\t\t' false|0|no|off) ANGULAR_PREBUNDLE_ARGS=(--prebundle=false) ;;',\n\t\t'esac',\n\t\t'kill_tree() {',\n\t\t' local pid=\"$1\"',\n\t\t' [ -n \"$pid\" ] || return 0',\n\t\t' for child in $(pgrep -P \"$pid\" 2>/dev/null || true); do kill_tree \"$child\"; done',\n\t\t' kill \"$pid\" >/dev/null 2>&1 || true',\n\t\t' sleep 1',\n\t\t' kill -0 \"$pid\" >/dev/null 2>&1 && kill -9 \"$pid\" >/dev/null 2>&1 || true',\n\t\t'}',\n\t\t'cleanup_project_processes() {',\n\t\t' for pid_file in \"$ARTIFACT_DIR/server.pid\" \"$ARTIFACT_DIR/client.pid\"; do',\n\t\t' [ -f \"$pid_file\" ] || continue',\n\t\t' pid=\"$(cat \"$pid_file\" 2>/dev/null || true)\"',\n\t\t' kill_tree \"$pid\"',\n\t\t' rm -f \"$pid_file\"',\n\t\t' done',\n\t\t' if command -v lsof >/dev/null 2>&1; then',\n\t\t' for port in \"$CLIENT_PORT\" \"$SERVER_PORT\" \"$MONGO_PORT\"; do',\n\t\t' [ -n \"$port\" ] || continue',\n\t\t' for pid in $(lsof -ti tcp:\"$port\" 2>/dev/null || true); do kill_tree \"$pid\"; done',\n\t\t' done',\n\t\t' fi',\n\t\t' for pid in $(ps -eo pid=,args= | awk -v root=\"$PROJECT_ROOT\" \\'index($0, root) && $0 ~ /(ng serve|node .*node_modules\\\\/\\\\.bin\\\\/ng|esbuild|npm run client|start_client\\\\.sh|npm run server|start_server\\\\.sh|nodemon|node .*tmp\\\\/index\\\\.js|mongod|mongodb-binaries\\\\/mongod)/ {print $1}\\' 2>/dev/null || true); do',\n\t\t' [ \"$pid\" = \"$$\" ] && continue',\n\t\t' kill_tree \"$pid\"',\n\t\t' done',\n\t\t'}',\n\t\t'cleanup() {',\n\t\t' kill_tree \"$SERVER_PID\"',\n\t\t' kill_tree \"$CLIENT_PID\"',\n\t\t' cleanup_project_processes',\n\t\t' rmdir \"$LOCK_DIR\" >/dev/null 2>&1 || true',\n\t\t'}',\n\t\t'trap cleanup EXIT',\n\t\t'probe_url() { node - \"$1\" <<\\'RESOLVEIO_PROBE\\'',\n\t\t'const http = require(\"http\");',\n\t\t'const https = require(\"https\");',\n\t\t'const url = process.argv[2];',\n\t\t'const mod = /^https:/i.test(url) ? https : http;',\n\t\t'const req = mod.get(url, { timeout: 2500 }, (res) => { res.resume(); process.exit(res.statusCode && res.statusCode < 500 ? 0 : 1); });',\n\t\t'req.on(\"timeout\", () => req.destroy(new Error(\"timeout\")));',\n\t\t'req.on(\"error\", () => process.exit(1));',\n\t\t'RESOLVEIO_PROBE',\n\t\t'}',\n\t\t'truthy() { case \"${1,,}\" in true|1|yes|on) return 0 ;; *) return 1 ;; esac; }',\n\t\t'reuse_running_app_if_ready() {',\n\t\t' truthy \"$REUSE_RUNNING\" || return 1',\n\t\t' [ -d \"$PROJECT_ROOT/server\" ] && SERVER_REQUIRED=1 || SERVER_REQUIRED=0',\n\t\t' probe_url \"$CLIENT_URL\" || return 1',\n\t\t' if [ \"$SERVER_REQUIRED\" = \"1\" ] && ! probe_url \"$SERVER_URL\"; then return 1; fi',\n\t\t' echo \"ResolveIO AI runner QA reusing already-ready local app at $CLIENT_URL\"',\n\t\t' return 0',\n\t\t'}',\n\t\t'log_has_fatal() {',\n\t\t' local file=\"$1\"',\n\t\t' [ -f \"$file\" ] || return 1',\n\t\t' grep -Eiq \"Unhandled Rejection|Cannot read properties of undefined|TypeError|ReferenceError|EADDRINUSE|app crashed|Failed to compile|Error: Cannot find module|NG[0-9]{4}|TS[0-9]{4}\" \"$file\"',\n\t\t'}',\n\t\t'prepare_angular_cache_dirs() {',\n\t\t' [ -d \"$PROJECT_ROOT\" ] || return 0',\n\t\t' mkdir -p \"$PROJECT_ROOT/.angular/cache\" 2>/dev/null || true',\n\t\t' local version=\"\"',\n\t\t' for pkg in \"$PROJECT_ROOT/node_modules/@angular/build/package.json\" \"$PROJECT_ROOT/node_modules/@angular/cli/package.json\" \"$PROJECT_ROOT/node_modules/@angular-devkit/build-angular/package.json\"; do',\n\t\t' if [ -f \"$pkg\" ]; then',\n\t\t' version=\"$(node -e \"try{console.log(require(process.argv[1]).version||\\\\\\\"\\\\\\\")}catch(e){}\" \"$pkg\" 2>/dev/null | head -1)\"',\n\t\t' [ -n \"$version\" ] && break',\n\t\t' fi',\n\t\t' done',\n\t\t' [ -n \"$version\" ] || return 0',\n\t\t' node - \"$PROJECT_ROOT/angular.json\" \"$(basename \"$PROJECT_ROOT\")\" <<\\'RESOLVEIO_ANGULAR_CACHE_PROJECTS\\' | while IFS= read -r project; do',\n\t\t'const fs = require(\"fs\");',\n\t\t'const path = process.argv[2];',\n\t\t'const fallback = process.argv[3];',\n\t\t'const names = new Set([fallback].filter(Boolean));',\n\t\t'try {',\n\t\t' const parsed = JSON.parse(fs.readFileSync(path, \"utf8\"));',\n\t\t' if (parsed.defaultProject) names.add(String(parsed.defaultProject));',\n\t\t' if (parsed.projects && typeof parsed.projects === \"object\") Object.keys(parsed.projects).forEach((name) => names.add(String(name)));',\n\t\t'} catch (error) {}',\n\t\t'for (const name of names) console.log(name.replace(/[^A-Za-z0-9._-]/g, \"_\"));',\n\t\t'RESOLVEIO_ANGULAR_CACHE_PROJECTS',\n\t\t' [ -n \"$project\" ] || continue',\n\t\t' mkdir -p \"$PROJECT_ROOT/.angular/cache/$version/$project/vite\" 2>/dev/null || true',\n\t\t' done',\n\t\t'}',\n\t\t'server_has_started() {',\n\t\t' local file=\"$ARTIFACT_DIR/server.log\"',\n\t\t' [ -f \"$file\" ] || return 1',\n\t\t' grep -Eiq \"nodemon.*starting|node .*tmp/index\\\\.js|Running as Worker|Standalone Node Reaper|listening on|server listening|Server listening|app listening|App listening|Finished .default.\" \"$file\"',\n\t\t'}',\n\t\t'wait_for_server_ready() {',\n\t\t' [ \"$SERVER_REQUIRED\" = \"1\" ] || return 0',\n\t\t' local end=$((SECONDS + STARTUP_TIMEOUT))',\n\t\t' while [ \"$SECONDS\" -lt \"$end\" ]; do',\n\t\t' if log_has_fatal \"$ARTIFACT_DIR/server.log\"; then return 4; fi',\n\t\t' if [ -n \"$SERVER_PID\" ] && ! kill -0 \"$SERVER_PID\" >/dev/null 2>&1; then return 4; fi',\n\t\t' if server_has_started; then',\n\t\t' local stable_until=$((SECONDS + SERVER_STABLE_SECONDS))',\n\t\t' while [ \"$SECONDS\" -lt \"$stable_until\" ]; do if log_has_fatal \"$ARTIFACT_DIR/server.log\"; then return 4; fi; sleep 2; done',\n\t\t' return 0',\n\t\t' fi',\n\t\t' sleep 5',\n\t\t' done',\n\t\t' return 4',\n\t\t'}',\n\t\t'wait_for_client() {',\n\t\t' local end=$((SECONDS + STARTUP_TIMEOUT))',\n\t\t' while [ \"$SECONDS\" -lt \"$end\" ]; do',\n\t\t' if [ -n \"$CLIENT_PID\" ] && ! kill -0 \"$CLIENT_PID\" >/dev/null 2>&1; then return 2; fi',\n\t\t' if log_has_fatal \"$ARTIFACT_DIR/client.log\"; then return 3; fi',\n\t\t' if log_has_fatal \"$ARTIFACT_DIR/server.log\"; then return 4; fi',\n\t\t' if probe_url \"$CLIENT_URL\"; then wait_for_server_ready || return $?; return 0; fi',\n\t\t' sleep 5',\n\t\t' done',\n\t\t' return 1',\n\t\t'}',\n\t\t'if reuse_running_app_if_ready; then exit 0; fi',\n\t\t'if ! mkdir \"$LOCK_DIR\" 2>/dev/null; then',\n\t\t' echo \"ResolveIO AI runner QA lock is already held for $PROJECT_ROOT; cleaning stale local QA processes before retrying.\" | tee \"$ARTIFACT_DIR/runner.log\"',\n\t\t' cleanup_project_processes',\n\t\t' rmdir \"$LOCK_DIR\" >/dev/null 2>&1 || true',\n\t\t' if ! mkdir \"$LOCK_DIR\" 2>/dev/null; then',\n\t\t' echo \"ResolveIO AI runner QA lock is still held for $PROJECT_ROOT after cleanup. Stop the existing QA runner before starting another.\" | tee -a \"$ARTIFACT_DIR/runner.log\"',\n\t\t' exit 6',\n\t\t' fi',\n\t\t'fi',\n\t\t'cleanup_project_processes',\n\t\t'if [ -d \"$PROJECT_ROOT/server\" ]; then',\n\t\t' SERVER_REQUIRED=1',\n\t\t' (cd \"$PROJECT_ROOT/server\" && source \"$TOOLS_DIR/env.sh\" && { npm run server || ./start_server.sh; } 2>&1 | tee \"$ARTIFACT_DIR/server.log\") &',\n\t\t' SERVER_PID=$!',\n\t\t' wait_for_server_ready',\n\t\t' SERVER_RESULT=$?',\n\t\t' if [ \"$SERVER_RESULT\" != \"0\" ]; then echo \"ResolveIO AI runner QA server startup fatal error. See $ARTIFACT_DIR/server.log\"; exit \"$SERVER_RESULT\"; fi',\n\t\t'fi',\n\t\t'CLIENT_HOST=\"${RESOLVEIO_RUNNER_QA_CLIENT_HOST:-${RESOLVEIO_SUPPORT_QA_CLIENT_HOST:-0.0.0.0}}\"',\n\t\t'if [ -x \"$PROJECT_ROOT/node_modules/.bin/ng\" ]; then',\n\t\t' prepare_angular_cache_dirs',\n\t\t' (cd \"$PROJECT_ROOT\" && source \"$TOOLS_DIR/env.sh\" && node --max_old_space_size=8048 ./node_modules/.bin/ng serve --watch --configuration local --host \"$CLIENT_HOST\" --port \"$CLIENT_PORT\" \"${ANGULAR_PREBUNDLE_ARGS[@]}\" 2>&1 | tee \"$ARTIFACT_DIR/client.log\") &',\n\t\t'elif [ -x \"$PROJECT_ROOT/start_client.sh\" ]; then',\n\t\t' (cd \"$PROJECT_ROOT\" && source \"$TOOLS_DIR/env.sh\" && ./start_client.sh 2>&1 | tee \"$ARTIFACT_DIR/client.log\") &',\n\t\t'elif node -e \"const p=require(process.argv[1]); process.exit(p.scripts&&p.scripts.client?0:1)\" \"$PROJECT_ROOT/package.json\" >/dev/null 2>&1; then',\n\t\t' (cd \"$PROJECT_ROOT\" && source \"$TOOLS_DIR/env.sh\" && npm run client 2>&1 | tee \"$ARTIFACT_DIR/client.log\") &',\n\t\t'else',\n\t\t' echo \"ResolveIO AI runner QA cannot find Angular CLI, start_client.sh, or npm client script for $PROJECT_ROOT\" | tee \"$ARTIFACT_DIR/client.log\"',\n\t\t' exit 5',\n\t\t'fi',\n\t\t'CLIENT_PID=$!',\n\t\t'wait_for_client',\n\t\t'RESULT=$?',\n\t\t'case \"$RESULT\" in',\n\t\t' 0)',\n\t\t' echo \"ResolveIO AI runner QA local app ready at $CLIENT_URL\";',\n\t\t' echo \"$SERVER_PID\" > \"$ARTIFACT_DIR/server.pid\";',\n\t\t' echo \"$CLIENT_PID\" > \"$ARTIFACT_DIR/client.pid\";',\n\t\t' if truthy \"$KEEPALIVE\"; then echo \"ResolveIO AI runner QA keepalive enabled; server/client remain running until this process is stopped.\"; wait; fi;',\n\t\t' exit 0',\n\t\t' ;;',\n\t\t' 2) echo \"ResolveIO AI runner QA client process exited before $CLIENT_URL became ready. See $ARTIFACT_DIR/client.log\"; exit 2 ;;',\n\t\t' 3) echo \"ResolveIO AI runner QA client startup fatal error. See $ARTIFACT_DIR/client.log\"; exit 3 ;;',\n\t\t' 4) echo \"ResolveIO AI runner QA server startup fatal error. See $ARTIFACT_DIR/server.log\"; exit 4 ;;',\n\t\t' *) echo \"ResolveIO AI runner QA local app did not become ready at $CLIENT_URL within ${STARTUP_TIMEOUT}s. See $ARTIFACT_DIR/client.log and $ARTIFACT_DIR/server.log\"; exit 1 ;;',\n\t\t'esac',\n\t\t''\n\t].join('\\n');\n}\n\nexport function buildResolveIORunnerLocalQaStopperScript(): string {\n\treturn [\n\t\t'#!/usr/bin/env bash',\n\t\t'set -u',\n\t\t'TOOLS_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"',\n\t\t'source \"$TOOLS_DIR/env.sh\"',\n\t\t'PROJECT_ROOT=\"${1:-$(pwd)}\"',\n\t\t'PROJECT_ROOT=\"$(cd \"$PROJECT_ROOT\" && pwd)\"',\n\t\t'ARTIFACT_DIR=\"$PROJECT_ROOT/qa-artifacts\"',\n\t\t'CLIENT_PORT=\"${RESOLVEIO_RUNNER_QA_CLIENT_PORT:-${RESOLVEIO_SUPPORT_QA_CLIENT_PORT:-4200}}\"',\n\t\t'SERVER_PORT=\"${RESOLVEIO_RUNNER_QA_SERVER_PORT:-${RESOLVEIO_SUPPORT_QA_SERVER_PORT:-8080}}\"',\n\t\t'MONGO_PORT=\"${RESOLVEIO_RUNNER_QA_MONGO_PORT:-${RESOLVEIO_SUPPORT_QA_MONGO_PORT:-3001}}\"',\n\t\t'kill_tree() {',\n\t\t' local pid=\"$1\"',\n\t\t' [ -n \"$pid\" ] || return 0',\n\t\t' kill -0 \"$pid\" >/dev/null 2>&1 || return 0',\n\t\t' for child in $(pgrep -P \"$pid\" 2>/dev/null || true); do kill_tree \"$child\"; done',\n\t\t' kill \"$pid\" >/dev/null 2>&1 || true',\n\t\t' sleep 1',\n\t\t' kill -0 \"$pid\" >/dev/null 2>&1 && kill -9 \"$pid\" >/dev/null 2>&1 || true',\n\t\t'}',\n\t\t'for pid_file in \"$ARTIFACT_DIR/server.pid\" \"$ARTIFACT_DIR/client.pid\"; do',\n\t\t' [ -f \"$pid_file\" ] || continue',\n\t\t' pid=\"$(cat \"$pid_file\" 2>/dev/null || true)\"',\n\t\t' kill_tree \"$pid\"',\n\t\t' rm -f \"$pid_file\"',\n\t\t'done',\n\t\t'if command -v lsof >/dev/null 2>&1; then',\n\t\t' for port in \"$CLIENT_PORT\" \"$SERVER_PORT\" \"$MONGO_PORT\"; do',\n\t\t' [ -n \"$port\" ] || continue',\n\t\t' for pid in $(lsof -ti tcp:\"$port\" 2>/dev/null || true); do kill_tree \"$pid\"; done',\n\t\t' done',\n\t\t'fi',\n\t\t'for pid in $(ps -eo pid=,args= | awk -v root=\"$PROJECT_ROOT\" \\'index($0, root) && $0 ~ /(ng serve|node .*node_modules\\\\/\\\\.bin\\\\/ng|esbuild|npm run client|start_client\\\\.sh|npm run server|start_server\\\\.sh|nodemon|node .*tmp\\\\/index\\\\.js|mongod|mongodb-binaries\\\\/mongod)/ {print $1}\\' 2>/dev/null || true); do',\n\t\t' [ \"$pid\" = \"$$\" ] && continue',\n\t\t' kill_tree \"$pid\"',\n\t\t'done',\n\t\t'rmdir \"$ARTIFACT_DIR/.qa.lock\" >/dev/null 2>&1 || true',\n\t\t'echo \"ResolveIO AI runner QA local app stopped for $PROJECT_ROOT\"',\n\t\t''\n\t].join('\\n');\n}\n\nexport function buildResolveIORunnerBugfixComparisonQaScript(): string {\n\treturn [\n\t\t'#!/usr/bin/env bash',\n\t\t'set -u',\n\t\t'TOOLS_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"',\n\t\t'source \"$TOOLS_DIR/env.sh\"',\n\t\t'PROJECT_ROOT=\"${1:-}\"',\n\t\t'if [ -z \"$PROJECT_ROOT\" ]; then',\n\t\t' echo \"Usage: $0 <project-root> [baseline-ref] -- <qa-command...>\" >&2',\n\t\t' exit 2',\n\t\t'fi',\n\t\t'shift || true',\n\t\t'DEFAULT_BASELINE_REF=\"${RESOLVEIO_RUNNER_QA_BASELINE_REF:-${RESOLVEIO_SUPPORT_QA_BASELINE_REF:-origin/master}}\"',\n\t\t'if [ \"${1:-}\" = \"--\" ]; then',\n\t\t' BASELINE_REF=\"$DEFAULT_BASELINE_REF\"',\n\t\t'else',\n\t\t' BASELINE_REF=\"${1:-$DEFAULT_BASELINE_REF}\"',\n\t\t' if [ \"$#\" -gt 0 ]; then shift || true; fi',\n\t\t'fi',\n\t\t'if [ \"${1:-}\" = \"--\" ]; then shift; fi',\n\t\t'if [ \"$#\" -eq 0 ]; then',\n\t\t' echo \"Usage: $0 <project-root> [baseline-ref] -- <qa-command...>\" >&2',\n\t\t' exit 2',\n\t\t'fi',\n\t\t'PROJECT_ROOT=\"$(cd \"$PROJECT_ROOT\" && pwd)\"',\n\t\t'REPO_ROOT=\"$(git -C \"$PROJECT_ROOT\" rev-parse --show-toplevel)\"',\n\t\t'PROJECT_REL=\"$(git -C \"$REPO_ROOT\" ls-files --full-name \"$PROJECT_ROOT\" 2>/dev/null | head -1 | xargs dirname 2>/dev/null || true)\"',\n\t\t'if [ -z \"$PROJECT_REL\" ] || [ \"$PROJECT_REL\" = \".\" ]; then',\n\t\t' PROJECT_REL=\"$(node - \"$REPO_ROOT\" \"$PROJECT_ROOT\" <<\\'RESOLVEIO_REL\\'',\n\t\t'const path = require(\"path\");',\n\t\t'console.log(path.relative(process.argv[2], process.argv[3]) || \".\");',\n\t\t'RESOLVEIO_REL',\n\t\t' )\"',\n\t\t'fi',\n\t\t'ARTIFACT_DIR=\"$PROJECT_ROOT/qa-artifacts\"',\n\t\t'mkdir -p \"$ARTIFACT_DIR/baseline\" \"$ARTIFACT_DIR/candidate\"',\n\t\t'RESULT_JSON=\"$ARTIFACT_DIR/bugfix-comparison-result.json\"',\n\t\t'CANDIDATE_PATCH=\"$ARTIFACT_DIR/bugfix-candidate.patch\"',\n\t\t'ORIGINAL_HEAD=\"$(git -C \"$REPO_ROOT\" rev-parse HEAD)\"',\n\t\t'ORIGINAL_BRANCH=\"$(git -C \"$REPO_ROOT\" symbolic-ref --short HEAD 2>/dev/null || true)\"',\n\t\t'QA_COMMAND=(\"$@\")',\n\t\t'STOPPER=\"$TOOLS_DIR/stop-local-qa.sh\"',\n\t\t'CURRENT_PHASE=\"\"',\n\t\t'stop_local_qa() {',\n\t\t' \"$STOPPER\" \"$PROJECT_ROOT\" >/dev/null 2>&1 || true',\n\t\t'}',\n\t\t'write_json() {',\n\t\t' node - \"$RESULT_JSON\" \"$@\" <<\\'RESOLVEIO_WRITE_JSON\\'',\n\t\t'const fs = require(\"fs\");',\n\t\t'const [path, status, baselineExit, candidateExit, baselineRef, originalHead, projectRel, note] = process.argv.slice(2);',\n\t\t'const payload = {',\n\t\t' status,',\n\t\t' baseline_ref: baselineRef,',\n\t\t' original_head: originalHead,',\n\t\t' project: projectRel,',\n\t\t' baseline_exit_code: Number(baselineExit),',\n\t\t' candidate_exit_code: Number(candidateExit),',\n\t\t' code_switch_proven: Number(baselineExit) !== 0 && Number(candidateExit) === 0,',\n\t\t' candidate_passed: Number(candidateExit) === 0,',\n\t\t' baseline_failed: Number(baselineExit) !== 0,',\n\t\t' note,',\n\t\t' artifact_dirs: { baseline: \"qa-artifacts/baseline\", candidate: \"qa-artifacts/candidate\" },',\n\t\t' created_at: new Date().toISOString()',\n\t\t'};',\n\t\t'fs.writeFileSync(path, JSON.stringify(payload, null, 2));',\n\t\t'console.log(JSON.stringify(payload, null, 2));',\n\t\t'RESOLVEIO_WRITE_JSON',\n\t\t'}',\n\t\t'snapshot_phase_artifacts() {',\n\t\t' local phase=\"$1\"',\n\t\t' mkdir -p \"$ARTIFACT_DIR/$phase\"',\n\t\t' find \"$ARTIFACT_DIR\" -maxdepth 1 -type f \\\\( -name \"*.png\" -o -name \"*.jpg\" -o -name \"*.jpeg\" -o -name \"*.webp\" -o -name \"*.json\" -o -name \"*.txt\" -o -name \"*.log\" -o -name \"*.zip\" \\\\) -print0 2>/dev/null | while IFS= read -r -d \"\" file; do',\n\t\t' cp \"$file\" \"$ARTIFACT_DIR/$phase/$(basename \"$file\")\" 2>/dev/null || true',\n\t\t' done',\n\t\t'}',\n\t\t'capture_candidate_patch() {',\n\t\t' : > \"$CANDIDATE_PATCH\"',\n\t\t' git -C \"$REPO_ROOT\" diff --binary -- \"$PROJECT_REL\" >> \"$CANDIDATE_PATCH\" || true',\n\t\t' git -C \"$REPO_ROOT\" diff --binary --cached -- \"$PROJECT_REL\" >> \"$CANDIDATE_PATCH\" || true',\n\t\t'}',\n\t\t'checkout_project_from_ref() {',\n\t\t' local ref=\"$1\"',\n\t\t' git -C \"$REPO_ROOT\" checkout \"$ref\" -- \"$PROJECT_REL\"',\n\t\t'}',\n\t\t'restore_candidate() {',\n\t\t' stop_local_qa',\n\t\t' checkout_project_from_ref \"$ORIGINAL_HEAD\" || true',\n\t\t' if [ -s \"$CANDIDATE_PATCH\" ]; then',\n\t\t' git -C \"$REPO_ROOT\" apply --whitespace=nowarn \"$CANDIDATE_PATCH\" || true',\n\t\t' fi',\n\t\t'}',\n\t\t'trap restore_candidate EXIT',\n\t\t'run_phase() {',\n\t\t' local phase=\"$1\"',\n\t\t' CURRENT_PHASE=\"$phase\"',\n\t\t' stop_local_qa',\n\t\t' export RESOLVEIO_RUNNER_QA_PHASE=\"$phase\"',\n\t\t' export RESOLVEIO_SUPPORT_QA_PHASE=\"$phase\"',\n\t\t' export RESOLVEIO_RUNNER_QA_ARTIFACT_DIR=\"$ARTIFACT_DIR/$phase\"',\n\t\t' export RESOLVEIO_SUPPORT_QA_ARTIFACT_DIR=\"$ARTIFACT_DIR/$phase\"',\n\t\t' mkdir -p \"$ARTIFACT_DIR/$phase\"',\n\t\t' set +e',\n\t\t' (cd \"$REPO_ROOT\" && \"${QA_COMMAND[@]}\") 2>&1 | tee \"$ARTIFACT_DIR/$phase/qa-command.log\"',\n\t\t' local rc=\"${PIPESTATUS[0]}\"',\n\t\t' set +e',\n\t\t' snapshot_phase_artifacts \"$phase\"',\n\t\t' stop_local_qa',\n\t\t' return \"$rc\"',\n\t\t'}',\n\t\t'echo \"ResolveIO bugfix comparison QA preserving candidate diff for $PROJECT_REL\"',\n\t\t'capture_candidate_patch',\n\t\t'stop_local_qa',\n\t\t'echo \"ResolveIO bugfix comparison QA baseline phase: $BASELINE_REF\"',\n\t\t'checkout_project_from_ref \"$BASELINE_REF\"',\n\t\t'run_phase baseline',\n\t\t'BASELINE_EXIT=\"$?\"',\n\t\t'echo \"ResolveIO bugfix comparison QA candidate phase: restored workspace candidate\"',\n\t\t'restore_candidate',\n\t\t'run_phase candidate',\n\t\t'CANDIDATE_EXIT=\"$?\"',\n\t\t'if [ \"$CANDIDATE_EXIT\" = \"0\" ] && [ \"$BASELINE_EXIT\" != \"0\" ]; then',\n\t\t' STATUS=\"pass\"',\n\t\t' NOTE=\"Baseline failed and candidate passed for the same QA command.\"',\n\t\t'elif [ \"$CANDIDATE_EXIT\" = \"0\" ]; then',\n\t\t' STATUS=\"inconclusive_baseline_also_passed\"',\n\t\t' NOTE=\"Candidate passed, but baseline also passed; the code switch did not prove the bug fix.\"',\n\t\t'else',\n\t\t' STATUS=\"fail_candidate_failed\"',\n\t\t' NOTE=\"Candidate failed the QA command.\"',\n\t\t'fi',\n\t\t'write_json \"$STATUS\" \"$BASELINE_EXIT\" \"$CANDIDATE_EXIT\" \"$BASELINE_REF\" \"$ORIGINAL_HEAD\" \"$PROJECT_REL\" \"$NOTE\"',\n\t\t'[ \"$CANDIDATE_EXIT\" = \"0\" ] || exit \"$CANDIDATE_EXIT\"',\n\t\t'[ \"$STATUS\" = \"pass\" ] || exit 8',\n\t\t''\n\t].join('\\n');\n}\n\nexport function buildResolveIORunnerQaToolsReadme(options: ResolveIORunnerQaToolBundleOptions = {}): string {\n\tconst mode = options.mode || 'runner';\n\tconst toolsDir = mode === 'support' ? '.resolveio-support-tools' : '.resolveio-ai-runner-tools';\n\tconst port = normalizePort(options.qaClientPort, '4200');\n\tconst clientUrlVar = envVar(mode, 'CLIENT_URL');\n\tconst keepaliveVar = envVar(mode, 'KEEPALIVE');\n\tconst usernameVar = envVar(mode, 'USERNAME');\n\tconst passwordVar = envVar(mode, 'PASSWORD');\n\treturn [\n\t\t`# ResolveIO ${mode === 'support' ? 'Support' : 'AI Runner'} Local QA Tools`,\n\t\t'',\n\t\t'These scripts are generated by `@resolveio/server-lib` and are shared by support tickets, AICoder app-builder runs, and AI-terminal runs.',\n\t\t'',\n\t\t'```bash',\n\t\t`source ${toolsDir}/env.sh`,\n\t\t`${toolsDir}/run-local-qa.sh <project-root>`,\n\t\t`node ${toolsDir}/qa-auth-bootstrap.js <project-root> /target-route`,\n\t\t`${toolsDir}/bugfix-comparison-qa.sh <project-root> origin/master -- bash -lc '<same QA command>'`,\n\t\t'```',\n\t\t'',\n\t\t`This workspace reserves Angular QA client port ${port}; use \\`$${clientUrlVar}\\` instead of assuming 4200 is free.`,\n\t\t'The local QA runner starts server/client, polls the reserved client URL, writes `qa-artifacts/server.log` and `qa-artifacts/client.log`, and fails fast on fatal startup/runtime errors.',\n\t\t'The shared auth bootstrap calls `/login`, then `/accessToken`, clears service workers/cache/IndexedDB/local storage for the exact localhost client origin, seeds `refreshToken`, `accessToken`, `user`, and `lastURL`, and writes `qa-artifacts/auth-bootstrap-result.json` plus a ready/failure screenshot.',\n\t\t`For browser clickthrough work, start the runner once with \\`${keepaliveVar}=true ${toolsDir}/run-local-qa.sh <project-root> &\\` and reuse \\`$${clientUrlVar}\\` for all login/upload/screenshot retries. Do not restart Angular for auth failures.`,\n\t\t'Use desktop screenshots at 1920x1080 by default unless the task is explicitly mobile/responsive. Every screenshot must have a customer-facing caption.',\n\t\t'For import/export/form-submit/data workflows, prove before/action/after with representative data and a concrete row/count/value assertion.',\n\t\t'For bug fixes, use `bugfix-comparison-qa.sh` so baseline/master runs the exact same repro before the candidate/PR run. A passing candidate is not enough unless the comparison result shows baseline failed or the report explicitly explains why the baseline failure could not be reproduced.',\n\t\t`Use \\`$${usernameVar}\\` and \\`$${passwordVar}\\` for the local fixture admin account unless ticket/app-specific credentials are provided.`,\n\t\t'The env file reuses `/var/lib/resolveio/puppeteer`, npm cache, worker-safe Browserslist settings, and Angular cache prep so QA should not download a browser or rebuild cold caches unnecessarily.',\n\t\tmode === 'support'\n\t\t\t? 'Support workspaces also stage local `mongod` and `mongosh` wrappers so app server scripts can start MongoDB when the worker image does not have MongoDB installed.'\n\t\t\t: '',\n\t\t''\n\t].filter((line) => line !== '').join('\\n');\n}\n"]}
|