@hstm-labs/forge-run 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/executor.d.ts +39 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +137 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/run-verify-stage.d.ts +29 -0
- package/dist/run-verify-stage.d.ts.map +1 -0
- package/dist/run-verify-stage.js +94 -0
- package/dist/run-verify-stage.js.map +1 -0
- package/dist/script-updater.d.ts +39 -0
- package/dist/script-updater.d.ts.map +1 -0
- package/dist/script-updater.js +87 -0
- package/dist/script-updater.js.map +1 -0
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @hstm-labs/forge-run
|
|
2
|
+
|
|
3
|
+
Post-deliver stage that updates root `package.json` scripts and optionally runs the dev stack for verification.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
- **Script updates**: Add or fill in `infra:up`, `db:create`, `db:seed`, `build`, `start`, and `run:all` so the delivered project has a consistent dev workflow.
|
|
8
|
+
- **Optional execute**: When `config.runVerify.execute` is true, run the script sequence and HTTP health checks (for CI or local smoke tests).
|
|
9
|
+
|
|
10
|
+
## Auth mode (Keycloak vs local users)
|
|
11
|
+
|
|
12
|
+
Run-verify supports two auth modes so dev deployment matches how the application authenticates users:
|
|
13
|
+
|
|
14
|
+
- **`authMode: 'oidc'`** — Application uses an IdP (OIDC/OAuth) and has a local user table that caches IdP data plus app-specific values. For dev, we include **Keycloak** (or another IdP) in the deployment and seed it with users that **match the users seeded in the database**. Use this when the app relies on IdP for authentication and you want to test the full flow (Keycloak + DB users aligned).
|
|
15
|
+
- **`authMode: 'local'`** (or unset) — Application only supports authentication with application-owned users (local users table, no IdP). Keycloak is **not** included in the dev deployment. Use this when there is no IdP and users exist only in the app DB.
|
|
16
|
+
|
|
17
|
+
Set in `forge.config.json`:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"runVerify": {
|
|
22
|
+
"execute": true,
|
|
23
|
+
"authMode": "oidc"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When `authMode` is `'oidc'`, the stage adds scripts `keycloak:up` and `keycloak:seed` and uses a `run:all` order: infra up → keycloak seed → db create → db seed → build → start. The Keycloak seed step should align users with those from `db:seed` (same identities/attributes). When `authMode` is `'local'` or omitted, no Keycloak scripts are added.
|
|
29
|
+
|
|
30
|
+
## Config
|
|
31
|
+
|
|
32
|
+
| Option | Type | Description |
|
|
33
|
+
|--------|------|-------------|
|
|
34
|
+
| `runVerify.execute` | boolean | If true, run script sequence and health checks after updating scripts. |
|
|
35
|
+
| `runVerify.healthUrls` | string[] | URLs to GET for health checks (default: localhost:3000/health). |
|
|
36
|
+
| `runVerify.authMode` | `'oidc'` \| `'local'` | IdP + Keycloak in dev vs local users only; see above. |
|
|
37
|
+
|
|
38
|
+
## Public API
|
|
39
|
+
|
|
40
|
+
- `RunVerifyStage` — Pipeline stage (depends on `deliver`).
|
|
41
|
+
- `updatePackageJsonScripts(rootDir, layoutName, authMode?)` — Add default scripts to root `package.json`.
|
|
42
|
+
- `getDefaultScriptsForLayout(layoutName, authMode?)` — Get script map for a layout and optional auth mode.
|
|
43
|
+
- `runScript`, `runScriptSequence`, `healthCheck`, `healthCheckWithRetry` — Execution helpers.
|
|
44
|
+
- Types: `RunVerifyReport`, `ScriptRunResult`, `HealthCheckResult`, `RunVerifyAuthMode`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run npm/pnpm scripts and perform HTTP health checks.
|
|
3
|
+
*/
|
|
4
|
+
import type { ScriptRunResult, HealthCheckResult } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Run a single npm script in the given directory.
|
|
7
|
+
*
|
|
8
|
+
* @param cwd - Working directory (project root)
|
|
9
|
+
* @param scriptName - Script name (e.g. 'infra:up', 'db:create')
|
|
10
|
+
* @param timeoutMs - Max time to wait
|
|
11
|
+
* @returns Script run result
|
|
12
|
+
*/
|
|
13
|
+
export declare function runScript(cwd: string, scriptName: string, timeoutMs?: number): Promise<ScriptRunResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Run a sequence of scripts in order; stop on first failure.
|
|
16
|
+
*
|
|
17
|
+
* @param cwd - Project root
|
|
18
|
+
* @param scriptNames - Script names in order
|
|
19
|
+
* @param timeoutMs - Timeout per script
|
|
20
|
+
* @returns Array of results (one per script run)
|
|
21
|
+
*/
|
|
22
|
+
export declare function runScriptSequence(cwd: string, scriptNames: string[], timeoutMs?: number): Promise<ScriptRunResult[]>;
|
|
23
|
+
/**
|
|
24
|
+
* Perform a single HTTP GET health check.
|
|
25
|
+
*
|
|
26
|
+
* @param url - URL to request (e.g. http://localhost:3000/health)
|
|
27
|
+
* @returns Health check result
|
|
28
|
+
*/
|
|
29
|
+
export declare function healthCheck(url: string): Promise<HealthCheckResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Perform health checks with retries and delay (for services that may not be up yet).
|
|
32
|
+
*
|
|
33
|
+
* @param urls - URLs to check
|
|
34
|
+
* @param retries - Number of retries per URL
|
|
35
|
+
* @param delayMs - Delay between retries
|
|
36
|
+
* @returns Array of final health check results
|
|
37
|
+
*/
|
|
38
|
+
export declare function healthCheckWithRetry(urls: string[], retries?: number, delayMs?: number): Promise<HealthCheckResult[]>;
|
|
39
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAOrE;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAkC,GAC5C,OAAO,CAAC,eAAe,CAAC,CA6C1B;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,GAAE,MAAkC,GAC5C,OAAO,CAAC,eAAe,EAAE,CAAC,CAU5B;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA6BzE;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,MAA6B,EACtC,OAAO,GAAE,MAAoC,GAC5C,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAkB9B"}
|
package/dist/executor.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run npm/pnpm scripts and perform HTTP health checks.
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
const DEFAULT_SCRIPT_TIMEOUT_MS = 120_000;
|
|
6
|
+
const HEALTH_CHECK_TIMEOUT_MS = 10_000;
|
|
7
|
+
const HEALTH_CHECK_RETRIES = 10;
|
|
8
|
+
const HEALTH_CHECK_RETRY_DELAY_MS = 2000;
|
|
9
|
+
/**
|
|
10
|
+
* Run a single npm script in the given directory.
|
|
11
|
+
*
|
|
12
|
+
* @param cwd - Working directory (project root)
|
|
13
|
+
* @param scriptName - Script name (e.g. 'infra:up', 'db:create')
|
|
14
|
+
* @param timeoutMs - Max time to wait
|
|
15
|
+
* @returns Script run result
|
|
16
|
+
*/
|
|
17
|
+
export function runScript(cwd, scriptName, timeoutMs = DEFAULT_SCRIPT_TIMEOUT_MS) {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
const start = Date.now();
|
|
20
|
+
const child = spawn('npm', ['run', scriptName], {
|
|
21
|
+
cwd,
|
|
22
|
+
shell: true,
|
|
23
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
24
|
+
});
|
|
25
|
+
let stderr = '';
|
|
26
|
+
child.stderr?.on('data', (chunk) => {
|
|
27
|
+
stderr += chunk.toString();
|
|
28
|
+
});
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
child.kill('SIGTERM');
|
|
31
|
+
resolve({
|
|
32
|
+
script: scriptName,
|
|
33
|
+
ok: false,
|
|
34
|
+
stderr: stderr || 'Timeout',
|
|
35
|
+
durationMs: Date.now() - start,
|
|
36
|
+
});
|
|
37
|
+
}, timeoutMs);
|
|
38
|
+
child.on('close', (code) => {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
resolve({
|
|
41
|
+
script: scriptName,
|
|
42
|
+
ok: code === 0,
|
|
43
|
+
...(code !== undefined && code !== null ? { exitCode: code } : {}),
|
|
44
|
+
...(stderr ? { stderr } : {}),
|
|
45
|
+
durationMs: Date.now() - start,
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
child.on('error', (err) => {
|
|
49
|
+
clearTimeout(timer);
|
|
50
|
+
resolve({
|
|
51
|
+
script: scriptName,
|
|
52
|
+
ok: false,
|
|
53
|
+
stderr: err.message,
|
|
54
|
+
durationMs: Date.now() - start,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run a sequence of scripts in order; stop on first failure.
|
|
61
|
+
*
|
|
62
|
+
* @param cwd - Project root
|
|
63
|
+
* @param scriptNames - Script names in order
|
|
64
|
+
* @param timeoutMs - Timeout per script
|
|
65
|
+
* @returns Array of results (one per script run)
|
|
66
|
+
*/
|
|
67
|
+
export async function runScriptSequence(cwd, scriptNames, timeoutMs = DEFAULT_SCRIPT_TIMEOUT_MS) {
|
|
68
|
+
const results = [];
|
|
69
|
+
for (const name of scriptNames) {
|
|
70
|
+
const result = await runScript(cwd, name, timeoutMs);
|
|
71
|
+
results.push(result);
|
|
72
|
+
if (!result.ok) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Perform a single HTTP GET health check.
|
|
80
|
+
*
|
|
81
|
+
* @param url - URL to request (e.g. http://localhost:3000/health)
|
|
82
|
+
* @returns Health check result
|
|
83
|
+
*/
|
|
84
|
+
export async function healthCheck(url) {
|
|
85
|
+
const start = Date.now();
|
|
86
|
+
try {
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timeout = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);
|
|
89
|
+
const res = await fetch(url, {
|
|
90
|
+
signal: controller.signal,
|
|
91
|
+
headers: { Accept: 'application/json' },
|
|
92
|
+
});
|
|
93
|
+
clearTimeout(timeout);
|
|
94
|
+
const responseMs = Date.now() - start;
|
|
95
|
+
return {
|
|
96
|
+
url,
|
|
97
|
+
ok: res.ok,
|
|
98
|
+
statusCode: res.status,
|
|
99
|
+
responseMs,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
const responseMs = Date.now() - start;
|
|
104
|
+
return {
|
|
105
|
+
url,
|
|
106
|
+
ok: false,
|
|
107
|
+
error: err instanceof Error ? err.message : String(err),
|
|
108
|
+
responseMs,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Perform health checks with retries and delay (for services that may not be up yet).
|
|
114
|
+
*
|
|
115
|
+
* @param urls - URLs to check
|
|
116
|
+
* @param retries - Number of retries per URL
|
|
117
|
+
* @param delayMs - Delay between retries
|
|
118
|
+
* @returns Array of final health check results
|
|
119
|
+
*/
|
|
120
|
+
export async function healthCheckWithRetry(urls, retries = HEALTH_CHECK_RETRIES, delayMs = HEALTH_CHECK_RETRY_DELAY_MS) {
|
|
121
|
+
const results = [];
|
|
122
|
+
for (const url of urls) {
|
|
123
|
+
let last;
|
|
124
|
+
for (let i = 0; i < retries; i++) {
|
|
125
|
+
last = await healthCheck(url);
|
|
126
|
+
if (last.ok) {
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
if (i < retries - 1) {
|
|
130
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
results.push(last ?? { url, ok: false, error: 'No attempt' });
|
|
134
|
+
}
|
|
135
|
+
return results;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hstm-labs/forge-run — Post-deliver run and verify stage.
|
|
3
|
+
*
|
|
4
|
+
* Updates package.json scripts (infra:up, db:create, db:seed, build, start)
|
|
5
|
+
* and optionally runs the stack and verifies services are responding.
|
|
6
|
+
*/
|
|
7
|
+
export { RunVerifyStage } from './run-verify-stage.js';
|
|
8
|
+
export { updatePackageJsonScripts, getDefaultScriptsForLayout, type RunVerifyAuthMode, } from './script-updater.js';
|
|
9
|
+
export { runScript, runScriptSequence, healthCheck, healthCheckWithRetry, } from './executor.js';
|
|
10
|
+
export type { RunVerifyReport, ScriptRunResult, HealthCheckResult, } from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,KAAK,iBAAiB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,oBAAoB,GACrB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,eAAe,EACf,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hstm-labs/forge-run — Post-deliver run and verify stage.
|
|
3
|
+
*
|
|
4
|
+
* Updates package.json scripts (infra:up, db:create, db:seed, build, start)
|
|
5
|
+
* and optionally runs the stack and verifies services are responding.
|
|
6
|
+
*/
|
|
7
|
+
export { RunVerifyStage } from './run-verify-stage.js';
|
|
8
|
+
export { updatePackageJsonScripts, getDefaultScriptsForLayout, } from './script-updater.js';
|
|
9
|
+
export { runScript, runScriptSequence, healthCheck, healthCheckWithRetry, } from './executor.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,wBAAwB,EACxB,0BAA0B,GAE3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,oBAAoB,GACrB,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunVerifyStage — pipeline stage after deliver that updates package.json
|
|
3
|
+
* scripts (infra:up, db:create, db:seed, build, start) and optionally runs
|
|
4
|
+
* the stack and verifies services are responding.
|
|
5
|
+
*
|
|
6
|
+
* Order when executing: infra up → [keycloak:seed when authMode=oidc] →
|
|
7
|
+
* db create → db seed → build → start → health checks.
|
|
8
|
+
*
|
|
9
|
+
* When config.runVerify.authMode is 'oidc', Keycloak is included (scripts and
|
|
10
|
+
* execute sequence) so dev can test IdP auth with users seeded in Keycloak
|
|
11
|
+
* that match DB-seeded users. When 'local', only app-owned users; no Keycloak.
|
|
12
|
+
*/
|
|
13
|
+
import type { StageName } from '@hstm-labs/forge-common';
|
|
14
|
+
import type { PipelineStage, PipelineStageInput, PipelineStageOutput, PipelineContext } from '@hstm-labs/forge-core';
|
|
15
|
+
/**
|
|
16
|
+
* Pipeline stage that runs after deliver: updates root package.json scripts
|
|
17
|
+
* for infra, db, seed, build, and start; optionally executes the sequence
|
|
18
|
+
* and verifies services via health checks.
|
|
19
|
+
*
|
|
20
|
+
* Enable execution by setting config.runVerify.execute to true and
|
|
21
|
+
* optionally config.runVerify.healthUrls (defaults to localhost:3000).
|
|
22
|
+
*/
|
|
23
|
+
export declare class RunVerifyStage implements PipelineStage {
|
|
24
|
+
readonly name: StageName;
|
|
25
|
+
readonly dependsOn: StageName[];
|
|
26
|
+
readonly requiresLLM = false;
|
|
27
|
+
execute(_input: PipelineStageInput, context: PipelineContext): Promise<PipelineStageOutput>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=run-verify-stage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-verify-stage.d.ts","sourceRoot":"","sources":["../src/run-verify-stage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAY/B;;;;;;;GAOG;AACH,qBAAa,cAAe,YAAW,aAAa;IAClD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAgB;IACxC,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,CAAe;IAC9C,QAAQ,CAAC,WAAW,SAAS;IAEvB,OAAO,CACX,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,mBAAmB,CAAC;CA+EhC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RunVerifyStage — pipeline stage after deliver that updates package.json
|
|
3
|
+
* scripts (infra:up, db:create, db:seed, build, start) and optionally runs
|
|
4
|
+
* the stack and verifies services are responding.
|
|
5
|
+
*
|
|
6
|
+
* Order when executing: infra up → [keycloak:seed when authMode=oidc] →
|
|
7
|
+
* db create → db seed → build → start → health checks.
|
|
8
|
+
*
|
|
9
|
+
* When config.runVerify.authMode is 'oidc', Keycloak is included (scripts and
|
|
10
|
+
* execute sequence) so dev can test IdP auth with users seeded in Keycloak
|
|
11
|
+
* that match DB-seeded users. When 'local', only app-owned users; no Keycloak.
|
|
12
|
+
*/
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
15
|
+
import { hashContent } from '@hstm-labs/forge-common';
|
|
16
|
+
import { updatePackageJsonScripts } from './script-updater.js';
|
|
17
|
+
import { runScriptSequence, healthCheckWithRetry, } from './executor.js';
|
|
18
|
+
/** Default health check URLs when execute is enabled and none configured. */
|
|
19
|
+
const DEFAULT_HEALTH_URLS = ['http://localhost:3000/health', 'http://localhost:3000'];
|
|
20
|
+
/**
|
|
21
|
+
* Pipeline stage that runs after deliver: updates root package.json scripts
|
|
22
|
+
* for infra, db, seed, build, and start; optionally executes the sequence
|
|
23
|
+
* and verifies services via health checks.
|
|
24
|
+
*
|
|
25
|
+
* Enable execution by setting config.runVerify.execute to true and
|
|
26
|
+
* optionally config.runVerify.healthUrls (defaults to localhost:3000).
|
|
27
|
+
*/
|
|
28
|
+
export class RunVerifyStage {
|
|
29
|
+
name = 'run-verify';
|
|
30
|
+
dependsOn = ['deliver'];
|
|
31
|
+
requiresLLM = false;
|
|
32
|
+
async execute(_input, context) {
|
|
33
|
+
const rootDir = context.workspace.rootDir;
|
|
34
|
+
const layoutName = context.config.layout ?? 'standard';
|
|
35
|
+
const report = {
|
|
36
|
+
runId: context.runId,
|
|
37
|
+
scriptsUpdated: false,
|
|
38
|
+
scriptsAdded: [],
|
|
39
|
+
executed: false,
|
|
40
|
+
success: true,
|
|
41
|
+
generatedAt: new Date().toISOString(),
|
|
42
|
+
};
|
|
43
|
+
const runConfig = context.config.runVerify;
|
|
44
|
+
const authMode = runConfig?.authMode;
|
|
45
|
+
// 1. Update root package.json scripts (if present); include Keycloak when authMode=oidc
|
|
46
|
+
if (existsSync(join(rootDir, 'package.json'))) {
|
|
47
|
+
report.scriptsAdded = updatePackageJsonScripts(rootDir, layoutName, authMode);
|
|
48
|
+
report.scriptsUpdated = report.scriptsAdded.length > 0;
|
|
49
|
+
}
|
|
50
|
+
// 2. Optionally run infra → [keycloak:seed if oidc] → db → seed → build → start and health checks
|
|
51
|
+
const shouldExecute = runConfig?.execute === true;
|
|
52
|
+
const healthUrls = runConfig?.healthUrls?.length
|
|
53
|
+
? runConfig.healthUrls
|
|
54
|
+
: DEFAULT_HEALTH_URLS;
|
|
55
|
+
if (shouldExecute) {
|
|
56
|
+
report.executed = true;
|
|
57
|
+
const sequence = authMode === 'oidc'
|
|
58
|
+
? ['infra:up', 'keycloak:seed', 'db:create', 'db:seed', 'build', 'start']
|
|
59
|
+
: ['infra:up', 'db:create', 'db:seed', 'build', 'start'];
|
|
60
|
+
const stepResults = await runScriptSequence(rootDir, sequence);
|
|
61
|
+
report.stepResults = stepResults;
|
|
62
|
+
const allStepsOk = stepResults.every((r) => r.ok);
|
|
63
|
+
if (allStepsOk) {
|
|
64
|
+
const checks = await healthCheckWithRetry(healthUrls);
|
|
65
|
+
report.healthChecks = checks;
|
|
66
|
+
report.success = checks.every((c) => c.ok);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
report.success = false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// 3. Write report artifact
|
|
73
|
+
const outputDir = join(context.workspace.forgeDir, 'runs', context.runId, 'stages', 'run-verify', 'artifacts');
|
|
74
|
+
mkdirSync(outputDir, { recursive: true });
|
|
75
|
+
const reportPath = 'run-verify-report.json';
|
|
76
|
+
const reportJson = JSON.stringify(report, null, 2);
|
|
77
|
+
writeFileSync(join(outputDir, reportPath), reportJson, 'utf-8');
|
|
78
|
+
const artifacts = [
|
|
79
|
+
{
|
|
80
|
+
filePath: reportPath,
|
|
81
|
+
content: reportJson,
|
|
82
|
+
contentHash: hashContent(reportJson),
|
|
83
|
+
sizeBytes: Buffer.byteLength(reportJson, 'utf-8'),
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
return {
|
|
87
|
+
artifacts,
|
|
88
|
+
data: {
|
|
89
|
+
runVerify: report,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=run-verify-stage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-verify-stage.js","sourceRoot":"","sources":["../src/run-verify-stage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAUtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EACL,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,6EAA6E;AAC7E,MAAM,mBAAmB,GAAG,CAAC,8BAA8B,EAAE,uBAAuB,CAAC,CAAC;AAEtF;;;;;;;GAOG;AACH,MAAM,OAAO,cAAc;IAChB,IAAI,GAAc,YAAY,CAAC;IAC/B,SAAS,GAAgB,CAAC,SAAS,CAAC,CAAC;IACrC,WAAW,GAAG,KAAK,CAAC;IAE7B,KAAK,CAAC,OAAO,CACX,MAA0B,EAC1B,OAAwB;QAExB,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC;QAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,UAAU,CAAC;QAEvD,MAAM,MAAM,GAAoB;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,cAAc,EAAE,KAAK;YACrB,YAAY,EAAE,EAAE;YAChB,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC;QAEF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,SAEpB,CAAC;QACd,MAAM,QAAQ,GAAG,SAAS,EAAE,QAAQ,CAAC;QAErC,wFAAwF;QACxF,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAC9C,MAAM,CAAC,YAAY,GAAG,wBAAwB,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC9E,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;QACzD,CAAC;QAED,kGAAkG;QAClG,MAAM,aAAa,GAAG,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;QAClD,MAAM,UAAU,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM;YAC9C,CAAC,CAAC,SAAS,CAAC,UAAU;YACtB,CAAC,CAAC,mBAAmB,CAAC;QAExB,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;YACvB,MAAM,QAAQ,GACZ,QAAQ,KAAK,MAAM;gBACjB,CAAC,CAAC,CAAC,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC;gBACzE,CAAC,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7D,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAC/D,MAAM,CAAC,WAAW,GAAG,WAAW,CAAC;YAEjC,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAClD,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAC;gBACtD,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC;gBAC7B,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;YACzB,CAAC;QACH,CAAC;QAED,2BAA2B;QAC3B,MAAM,SAAS,GAAG,IAAI,CACpB,OAAO,CAAC,SAAS,CAAC,QAAQ,EAC1B,MAAM,EACN,OAAO,CAAC,KAAK,EACb,QAAQ,EACR,YAAY,EACZ,WAAW,CACZ,CAAC;QACF,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,UAAU,GAAG,wBAAwB,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACnD,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAEhE,MAAM,SAAS,GAAoB;YACjC;gBACE,QAAQ,EAAE,UAAU;gBACpB,OAAO,EAAE,UAAU;gBACnB,WAAW,EAAE,WAAW,CAAC,UAAU,CAAC;gBACpC,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,OAAO,CAAC;aAClD;SACF,CAAC;QAEF,OAAO;YACL,SAAS;YACT,IAAI,EAAE;gBACJ,SAAS,EAAE,MAAM;aAClB;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update root package.json with scripts for infra, db, seed, build, and start.
|
|
3
|
+
*
|
|
4
|
+
* Ensures the delivered project has consistent script names so run-verify
|
|
5
|
+
* (or the user) can run: infra:up → [keycloak:seed when OIDC] → db:create →
|
|
6
|
+
* db:seed → build → start.
|
|
7
|
+
*
|
|
8
|
+
* When authMode is 'oidc', Keycloak-related scripts are added so dev can deploy
|
|
9
|
+
* Keycloak and seed it with users that match DB-seeded users (IdP + local user
|
|
10
|
+
* cache). When authMode is 'local', only application-owned users; no Keycloak.
|
|
11
|
+
*/
|
|
12
|
+
import type { ProjectLayoutName } from '@hstm-labs/forge-common';
|
|
13
|
+
/** Auth mode for dev: IdP (OIDC/OAuth + Keycloak) vs local users only. */
|
|
14
|
+
export type RunVerifyAuthMode = 'oidc' | 'local';
|
|
15
|
+
/**
|
|
16
|
+
* Propose scripts for the given layout and optional auth mode.
|
|
17
|
+
*
|
|
18
|
+
* When authMode is 'oidc', adds keycloak:up, keycloak:seed and uses run:all
|
|
19
|
+
* that includes Keycloak seed before db. When 'local' or undefined, no Keycloak.
|
|
20
|
+
*
|
|
21
|
+
* @param layoutName - Project layout (standard, monorepo, scalable-monorepo)
|
|
22
|
+
* @param authMode - 'oidc' to include Keycloak for IdP apps; 'local' or undefined for app-only users
|
|
23
|
+
* @returns Scripts to add or merge
|
|
24
|
+
*/
|
|
25
|
+
export declare function getDefaultScriptsForLayout(layoutName: ProjectLayoutName, authMode?: RunVerifyAuthMode | undefined): Record<string, string>;
|
|
26
|
+
/**
|
|
27
|
+
* Update or add scripts to the root package.json at rootDir.
|
|
28
|
+
* Only adds script keys that are missing; does not overwrite existing.
|
|
29
|
+
*
|
|
30
|
+
* When authMode is 'oidc', adds keycloak:up and keycloak:seed and run:all
|
|
31
|
+
* includes Keycloak. When 'local' or undefined, no Keycloak scripts.
|
|
32
|
+
*
|
|
33
|
+
* @param rootDir - Project root (delivered project)
|
|
34
|
+
* @param layoutName - Project layout for layout-specific defaults
|
|
35
|
+
* @param authMode - 'oidc' to include Keycloak for IdP; 'local' or undefined for local users only
|
|
36
|
+
* @returns List of script names that were added
|
|
37
|
+
*/
|
|
38
|
+
export declare function updatePackageJsonScripts(rootDir: string, layoutName: ProjectLayoutName, authMode?: RunVerifyAuthMode | undefined): string[];
|
|
39
|
+
//# sourceMappingURL=script-updater.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-updater.d.ts","sourceRoot":"","sources":["../src/script-updater.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,OAAO,CAAC;AAuBjD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,iBAAiB,EAC7B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,SAAS,GACvC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,iBAAiB,EAC7B,QAAQ,CAAC,EAAE,iBAAiB,GAAG,SAAS,GACvC,MAAM,EAAE,CA4BV"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update root package.json with scripts for infra, db, seed, build, and start.
|
|
3
|
+
*
|
|
4
|
+
* Ensures the delivered project has consistent script names so run-verify
|
|
5
|
+
* (or the user) can run: infra:up → [keycloak:seed when OIDC] → db:create →
|
|
6
|
+
* db:seed → build → start.
|
|
7
|
+
*
|
|
8
|
+
* When authMode is 'oidc', Keycloak-related scripts are added so dev can deploy
|
|
9
|
+
* Keycloak and seed it with users that match DB-seeded users (IdP + local user
|
|
10
|
+
* cache). When authMode is 'local', only application-owned users; no Keycloak.
|
|
11
|
+
*/
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
14
|
+
import { getLayout } from '@hstm-labs/forge-common';
|
|
15
|
+
const DEFAULT_SCRIPTS = {
|
|
16
|
+
'infra:up': 'docker compose -f infra/docker/compose.dev.yml up -d 2>/dev/null || docker compose up -d',
|
|
17
|
+
'db:create': 'npx prisma migrate deploy 2>/dev/null || echo "No Prisma; add db create command"',
|
|
18
|
+
'db:seed': 'node scripts/seed.js 2>/dev/null || npm run seed 2>/dev/null || echo "Add seed script"',
|
|
19
|
+
build: 'echo "Add workspace build (e.g. pnpm run build)"',
|
|
20
|
+
start: 'echo "Add workspace start (e.g. pnpm run start)"',
|
|
21
|
+
'run:all': 'npm run infra:up && npm run db:create && npm run db:seed && npm run build && npm run start',
|
|
22
|
+
};
|
|
23
|
+
/** Scripts added only when authMode is 'oidc' (Keycloak deploy + seed to match DB users). */
|
|
24
|
+
const OIDC_SCRIPTS = {
|
|
25
|
+
'keycloak:up': 'docker compose -f infra/docker/compose.dev.yml up -d keycloak 2>/dev/null || echo "Add Keycloak service to compose"',
|
|
26
|
+
'keycloak:seed': 'node scripts/seed-keycloak.js 2>/dev/null || echo "Add Keycloak user seed (align with db:seed users)"',
|
|
27
|
+
'run:all': 'npm run infra:up && npm run keycloak:seed && npm run db:create && npm run db:seed && npm run build && npm run start',
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Propose scripts for the given layout and optional auth mode.
|
|
31
|
+
*
|
|
32
|
+
* When authMode is 'oidc', adds keycloak:up, keycloak:seed and uses run:all
|
|
33
|
+
* that includes Keycloak seed before db. When 'local' or undefined, no Keycloak.
|
|
34
|
+
*
|
|
35
|
+
* @param layoutName - Project layout (standard, monorepo, scalable-monorepo)
|
|
36
|
+
* @param authMode - 'oidc' to include Keycloak for IdP apps; 'local' or undefined for app-only users
|
|
37
|
+
* @returns Scripts to add or merge
|
|
38
|
+
*/
|
|
39
|
+
export function getDefaultScriptsForLayout(layoutName, authMode) {
|
|
40
|
+
const layout = getLayout(layoutName);
|
|
41
|
+
const scripts = {
|
|
42
|
+
...DEFAULT_SCRIPTS,
|
|
43
|
+
...(authMode === 'oidc' ? OIDC_SCRIPTS : {}),
|
|
44
|
+
};
|
|
45
|
+
if (layout.name === 'scalable-monorepo' || layout.name === 'monorepo') {
|
|
46
|
+
scripts.build = 'turbo run build';
|
|
47
|
+
scripts.start = 'turbo run start';
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
scripts.build = 'pnpm run build 2>/dev/null || npm run build';
|
|
51
|
+
scripts.start = 'pnpm run start 2>/dev/null || npm run start';
|
|
52
|
+
}
|
|
53
|
+
return scripts;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Update or add scripts to the root package.json at rootDir.
|
|
57
|
+
* Only adds script keys that are missing; does not overwrite existing.
|
|
58
|
+
*
|
|
59
|
+
* When authMode is 'oidc', adds keycloak:up and keycloak:seed and run:all
|
|
60
|
+
* includes Keycloak. When 'local' or undefined, no Keycloak scripts.
|
|
61
|
+
*
|
|
62
|
+
* @param rootDir - Project root (delivered project)
|
|
63
|
+
* @param layoutName - Project layout for layout-specific defaults
|
|
64
|
+
* @param authMode - 'oidc' to include Keycloak for IdP; 'local' or undefined for local users only
|
|
65
|
+
* @returns List of script names that were added
|
|
66
|
+
*/
|
|
67
|
+
export function updatePackageJsonScripts(rootDir, layoutName, authMode) {
|
|
68
|
+
const pkgPath = join(rootDir, 'package.json');
|
|
69
|
+
if (!existsSync(pkgPath)) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const raw = readFileSync(pkgPath, 'utf-8');
|
|
73
|
+
const pkg = JSON.parse(raw);
|
|
74
|
+
const existing = pkg.scripts ?? {};
|
|
75
|
+
const defaults = getDefaultScriptsForLayout(layoutName, authMode);
|
|
76
|
+
const added = [];
|
|
77
|
+
for (const [name, value] of Object.entries(defaults)) {
|
|
78
|
+
if (existing[name] === undefined || existing[name] === '') {
|
|
79
|
+
existing[name] = value;
|
|
80
|
+
added.push(name);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
pkg.scripts = existing;
|
|
84
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
85
|
+
return added;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=script-updater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script-updater.js","sourceRoot":"","sources":["../src/script-updater.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAKpD,MAAM,eAAe,GAA2B;IAC9C,UAAU,EACR,0FAA0F;IAC5F,WAAW,EAAE,kFAAkF;IAC/F,SAAS,EAAE,wFAAwF;IACnG,KAAK,EAAE,kDAAkD;IACzD,KAAK,EAAE,kDAAkD;IACzD,SAAS,EACP,4FAA4F;CAC/F,CAAC;AAEF,6FAA6F;AAC7F,MAAM,YAAY,GAA2B;IAC3C,aAAa,EACX,qHAAqH;IACvH,eAAe,EACb,uGAAuG;IACzG,SAAS,EACP,qHAAqH;CACxH,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,UAA6B,EAC7B,QAAwC;IAExC,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,OAAO,GAA2B;QACtC,GAAG,eAAe;QAClB,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;IAEF,IAAI,MAAM,CAAC,IAAI,KAAK,mBAAmB,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACtE,OAAO,CAAC,KAAK,GAAG,iBAAiB,CAAC;QAClC,OAAO,CAAC,KAAK,GAAG,iBAAiB,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,GAAG,6CAA6C,CAAC;QAC9D,OAAO,CAAC,KAAK,GAAG,6CAA6C,CAAC;IAChE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAe,EACf,UAA6B,EAC7B,QAAwC;IAExC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAKzB,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,0BAA0B,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAClE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;YAC1D,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,GAAG,CAAC,OAAO,GAAG,QAAQ,CAAC;IACvB,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IACrE,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the run-verify stage: script updates, execution, and health checks.
|
|
3
|
+
*/
|
|
4
|
+
/** Result of a single health check. */
|
|
5
|
+
export interface HealthCheckResult {
|
|
6
|
+
/** URL checked. */
|
|
7
|
+
url: string;
|
|
8
|
+
/** Whether the check succeeded. */
|
|
9
|
+
ok: boolean;
|
|
10
|
+
/** HTTP status code (if applicable). */
|
|
11
|
+
statusCode?: number;
|
|
12
|
+
/** Error message if failed. */
|
|
13
|
+
error?: string;
|
|
14
|
+
/** Response time in ms (if applicable). */
|
|
15
|
+
responseMs?: number;
|
|
16
|
+
}
|
|
17
|
+
/** Result of running a single script (e.g. infra:up, db:create). */
|
|
18
|
+
export interface ScriptRunResult {
|
|
19
|
+
script: string;
|
|
20
|
+
ok: boolean;
|
|
21
|
+
exitCode?: number;
|
|
22
|
+
stderr?: string;
|
|
23
|
+
durationMs: number;
|
|
24
|
+
}
|
|
25
|
+
/** Report produced by the run-verify stage. */
|
|
26
|
+
export interface RunVerifyReport {
|
|
27
|
+
runId: string;
|
|
28
|
+
/** Whether script updates were applied. */
|
|
29
|
+
scriptsUpdated: boolean;
|
|
30
|
+
/** Scripts added or updated (key = script name). */
|
|
31
|
+
scriptsAdded: string[];
|
|
32
|
+
/** Whether the execute sequence was run. */
|
|
33
|
+
executed: boolean;
|
|
34
|
+
/** Results of each step when executed (infra:up, db:create, db:seed, build, start). */
|
|
35
|
+
stepResults?: ScriptRunResult[];
|
|
36
|
+
/** Health check results when executed. */
|
|
37
|
+
healthChecks?: HealthCheckResult[];
|
|
38
|
+
/** Overall success (all health checks passed when executed). */
|
|
39
|
+
success: boolean;
|
|
40
|
+
generatedAt: string;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,uCAAuC;AACvC,MAAM,WAAW,iBAAiB;IAChC,mBAAmB;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,+CAA+C;AAC/C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,cAAc,EAAE,OAAO,CAAC;IACxB,oDAAoD;IACpD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,4CAA4C;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,uFAAuF;IACvF,WAAW,CAAC,EAAE,eAAe,EAAE,CAAC;IAChC,0CAA0C;IAC1C,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,gEAAgE;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hstm-labs/forge-run",
|
|
3
|
+
"version": "0.1.11",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"prepublishOnly": "npm run build"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@hstm-labs/forge-common": "0.1.11",
|
|
20
|
+
"@hstm-labs/forge-core": "0.1.11"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^25.2.3"
|
|
24
|
+
}
|
|
25
|
+
}
|