@unimatrix27/ralph-harness 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +89 -0
- package/README.md +401 -0
- package/dist/bin/ralph-bootstrap-aws.d.ts +3 -0
- package/dist/bin/ralph-bootstrap-aws.d.ts.map +1 -0
- package/dist/bin/ralph-bootstrap-aws.js +43 -0
- package/dist/bin/ralph-bootstrap-aws.js.map +1 -0
- package/dist/bin/ralph-fire.d.ts +3 -0
- package/dist/bin/ralph-fire.d.ts.map +1 -0
- package/dist/bin/ralph-fire.js +59 -0
- package/dist/bin/ralph-fire.js.map +1 -0
- package/dist/bin/ralph-gsm.d.ts +3 -0
- package/dist/bin/ralph-gsm.d.ts.map +1 -0
- package/dist/bin/ralph-gsm.js +93 -0
- package/dist/bin/ralph-gsm.js.map +1 -0
- package/dist/bin/ralph-orchestrate.d.ts +3 -0
- package/dist/bin/ralph-orchestrate.d.ts.map +1 -0
- package/dist/bin/ralph-orchestrate.js +20 -0
- package/dist/bin/ralph-orchestrate.js.map +1 -0
- package/dist/bin/ralph-sync-credential.d.ts +3 -0
- package/dist/bin/ralph-sync-credential.d.ts.map +1 -0
- package/dist/bin/ralph-sync-credential.js +44 -0
- package/dist/bin/ralph-sync-credential.js.map +1 -0
- package/dist/bin/ralph-sync-github-pat.d.ts +3 -0
- package/dist/bin/ralph-sync-github-pat.d.ts.map +1 -0
- package/dist/bin/ralph-sync-github-pat.js +93 -0
- package/dist/bin/ralph-sync-github-pat.js.map +1 -0
- package/dist/bin/ralph-tail-logs.d.ts +3 -0
- package/dist/bin/ralph-tail-logs.d.ts.map +1 -0
- package/dist/bin/ralph-tail-logs.js +72 -0
- package/dist/bin/ralph-tail-logs.js.map +1 -0
- package/dist/bin/ralph-validate-config.d.ts +3 -0
- package/dist/bin/ralph-validate-config.d.ts.map +1 -0
- package/dist/bin/ralph-validate-config.js +41 -0
- package/dist/bin/ralph-validate-config.js.map +1 -0
- package/dist/lib/aws-bootstrap.d.ts +53 -0
- package/dist/lib/aws-bootstrap.d.ts.map +1 -0
- package/dist/lib/aws-bootstrap.js +438 -0
- package/dist/lib/aws-bootstrap.js.map +1 -0
- package/dist/lib/aws-clients.d.ts +17 -0
- package/dist/lib/aws-clients.d.ts.map +1 -0
- package/dist/lib/aws-clients.js +25 -0
- package/dist/lib/aws-clients.js.map +1 -0
- package/dist/lib/claude-runner.d.ts +21 -0
- package/dist/lib/claude-runner.d.ts.map +1 -0
- package/dist/lib/claude-runner.js +101 -0
- package/dist/lib/claude-runner.js.map +1 -0
- package/dist/lib/credential-syncer.d.ts +27 -0
- package/dist/lib/credential-syncer.d.ts.map +1 -0
- package/dist/lib/credential-syncer.js +116 -0
- package/dist/lib/credential-syncer.js.map +1 -0
- package/dist/lib/ec2-orchestrator.d.ts +38 -0
- package/dist/lib/ec2-orchestrator.d.ts.map +1 -0
- package/dist/lib/ec2-orchestrator.js +469 -0
- package/dist/lib/ec2-orchestrator.js.map +1 -0
- package/dist/lib/env-loader.d.ts +18 -0
- package/dist/lib/env-loader.d.ts.map +1 -0
- package/dist/lib/env-loader.js +120 -0
- package/dist/lib/env-loader.js.map +1 -0
- package/dist/lib/fire-launcher.d.ts +59 -0
- package/dist/lib/fire-launcher.d.ts.map +1 -0
- package/dist/lib/fire-launcher.js +320 -0
- package/dist/lib/fire-launcher.js.map +1 -0
- package/dist/lib/gh-runner.d.ts +13 -0
- package/dist/lib/gh-runner.d.ts.map +1 -0
- package/dist/lib/gh-runner.js +50 -0
- package/dist/lib/gh-runner.js.map +1 -0
- package/dist/lib/github-state-mutator.d.ts +11 -0
- package/dist/lib/github-state-mutator.d.ts.map +1 -0
- package/dist/lib/github-state-mutator.js +179 -0
- package/dist/lib/github-state-mutator.js.map +1 -0
- package/dist/lib/phase-result-schemas.d.ts +88 -0
- package/dist/lib/phase-result-schemas.d.ts.map +1 -0
- package/dist/lib/phase-result-schemas.js +180 -0
- package/dist/lib/phase-result-schemas.js.map +1 -0
- package/dist/lib/post-hoc-agent-stuck-checker.d.ts +26 -0
- package/dist/lib/post-hoc-agent-stuck-checker.d.ts.map +1 -0
- package/dist/lib/post-hoc-agent-stuck-checker.js +142 -0
- package/dist/lib/post-hoc-agent-stuck-checker.js.map +1 -0
- package/dist/lib/prompt-renderer.d.ts +4 -0
- package/dist/lib/prompt-renderer.d.ts.map +1 -0
- package/dist/lib/prompt-renderer.js +30 -0
- package/dist/lib/prompt-renderer.js.map +1 -0
- package/dist/lib/security-runner.d.ts +7 -0
- package/dist/lib/security-runner.d.ts.map +1 -0
- package/dist/lib/security-runner.js +53 -0
- package/dist/lib/security-runner.js.map +1 -0
- package/dist/lib/structured-log-emitter.d.ts +53 -0
- package/dist/lib/structured-log-emitter.d.ts.map +1 -0
- package/dist/lib/structured-log-emitter.js +122 -0
- package/dist/lib/structured-log-emitter.js.map +1 -0
- package/dist/lib/target-config-schema.d.ts +28 -0
- package/dist/lib/target-config-schema.d.ts.map +1 -0
- package/dist/lib/target-config-schema.js +157 -0
- package/dist/lib/target-config-schema.js.map +1 -0
- package/dist/lib/user-data-renderer.d.ts +20 -0
- package/dist/lib/user-data-renderer.d.ts.map +1 -0
- package/dist/lib/user-data-renderer.js +75 -0
- package/dist/lib/user-data-renderer.js.map +1 -0
- package/lib/cloud-init/system-setup.sh +338 -0
- package/package.json +55 -0
- package/prompts/discovery.md +182 -0
- package/prompts/implementation.md +161 -0
- package/prompts/review.md +135 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-config-schema.js","sourceRoot":"","sources":["../../src/lib/target-config-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const MODULE_PREFIX = "user-data-renderer";
|
|
2
|
+
export declare const USER_DATA_CAP_BYTES = 16384;
|
|
3
|
+
export declare class RawSizeExceededError extends Error {
|
|
4
|
+
readonly bytes: number;
|
|
5
|
+
constructor(bytes: number);
|
|
6
|
+
}
|
|
7
|
+
export interface UserDataInput {
|
|
8
|
+
targetRepo: string;
|
|
9
|
+
harnessVersion: string;
|
|
10
|
+
awsRegion: string;
|
|
11
|
+
logGroup: string;
|
|
12
|
+
githubTokenSsmKey: string;
|
|
13
|
+
claudeOauthSsmKey: string;
|
|
14
|
+
agentStuckLabel: string;
|
|
15
|
+
extraEnv?: Readonly<Record<string, string>>;
|
|
16
|
+
packageName?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function shellSingleQuote(value: string): string;
|
|
19
|
+
export declare function renderUserData(input: UserDataInput): string;
|
|
20
|
+
//# sourceMappingURL=user-data-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-data-renderer.d.ts","sourceRoot":"","sources":["../../src/lib/user-data-renderer.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,aAAa,uBAAuB,CAAC;AAIlD,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAE1C,qBAAa,oBAAqB,SAAQ,KAAK;aACjB,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;CAM1C;AAED,MAAM,WAAW,aAAa;IAE5B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IAGxB,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAG5C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAqC3D"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// user-data-renderer — renders the small inline bash stub that EC2 receives
|
|
2
|
+
// as user-data. Iteration 1 bundled the entire bash harness (`fire-launcher`
|
|
3
|
+
// + `ec2-orchestrator` + `cloud-init/bootstrap`) inline, which forced gzip
|
|
4
|
+
// compression to fit under the 16 KiB cap. Iteration 2 ships the harness via
|
|
5
|
+
// npm; the user-data shrinks to ~15 lines that install Node 24, install the
|
|
6
|
+
// harness package, then `exec ralph-orchestrate`.
|
|
7
|
+
//
|
|
8
|
+
// Cap-check: EC2's user-data cap is 16,384 bytes on the *raw* decoded
|
|
9
|
+
// payload — NOT on the base64 wire form, NOT on the gzipped bytes. PR #20
|
|
10
|
+
// and #21 (iteration 1) checked the gzipped size against this dimension,
|
|
11
|
+
// which let oversized payloads slip through when gzip happened to compress
|
|
12
|
+
// well. We check the raw rendered bytes here; the new stub is well under
|
|
13
|
+
// the cap so a `RawSizeExceeded` throw should be the equivalent of an
|
|
14
|
+
// assertion failure rather than a regular operating condition.
|
|
15
|
+
//
|
|
16
|
+
// Public surface:
|
|
17
|
+
// renderUserData(input) — returns the rendered bash string
|
|
18
|
+
// USER_DATA_CAP_BYTES — the EC2 16 KiB cap (raw bytes)
|
|
19
|
+
// RawSizeExceededError — thrown when the rendered output exceeds the cap
|
|
20
|
+
export const MODULE_PREFIX = "user-data-renderer";
|
|
21
|
+
// EC2 caps user-data at 16,384 raw decoded bytes. cf.
|
|
22
|
+
// docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html
|
|
23
|
+
export const USER_DATA_CAP_BYTES = 16_384;
|
|
24
|
+
export class RawSizeExceededError extends Error {
|
|
25
|
+
bytes;
|
|
26
|
+
constructor(bytes) {
|
|
27
|
+
super(`${MODULE_PREFIX}: rendered user-data is ${bytes} bytes, exceeds the EC2 cap of ${USER_DATA_CAP_BYTES} raw bytes`);
|
|
28
|
+
this.bytes = bytes;
|
|
29
|
+
this.name = "RawSizeExceededError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const DEFAULT_PACKAGE_NAME = "@unimatrix27/ralph-harness";
|
|
33
|
+
// shellSingleQuote — wrap a value in POSIX single quotes, escaping any
|
|
34
|
+
// embedded `'` as `'\''`. Single-quoted strings are safe against every
|
|
35
|
+
// other shell metacharacter.
|
|
36
|
+
export function shellSingleQuote(value) {
|
|
37
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
38
|
+
}
|
|
39
|
+
export function renderUserData(input) {
|
|
40
|
+
const pkg = input.packageName ?? DEFAULT_PACKAGE_NAME;
|
|
41
|
+
// Build the export block deterministically — sorted keys keep the
|
|
42
|
+
// snapshot test stable across object literal reorders.
|
|
43
|
+
const baseEnv = {
|
|
44
|
+
RALPH_TARGET_REPO: input.targetRepo,
|
|
45
|
+
RALPH_AWS_REGION: input.awsRegion,
|
|
46
|
+
RALPH_LOG_GROUP: input.logGroup,
|
|
47
|
+
RALPH_GITHUB_TOKEN_SSM_KEY: input.githubTokenSsmKey,
|
|
48
|
+
RALPH_CLAUDE_OAUTH_SSM_KEY: input.claudeOauthSsmKey,
|
|
49
|
+
RALPH_AGENT_STUCK_LABEL: input.agentStuckLabel,
|
|
50
|
+
RALPH_HARNESS_VERSION: input.harnessVersion,
|
|
51
|
+
};
|
|
52
|
+
const merged = { ...baseEnv, ...(input.extraEnv ?? {}) };
|
|
53
|
+
const sortedKeys = Object.keys(merged).sort();
|
|
54
|
+
const exports = sortedKeys
|
|
55
|
+
.map((k) => `export ${k}=${shellSingleQuote(merged[k])}`)
|
|
56
|
+
.join("\n");
|
|
57
|
+
// 15-line target — keep this tight. Anything heavyweight goes in
|
|
58
|
+
// `lib/cloud-init/system-setup.sh` (shipped inside the npm package and
|
|
59
|
+
// invoked by `ralph-orchestrate` as its first step).
|
|
60
|
+
const stub = `#!/bin/bash
|
|
61
|
+
set -euo pipefail
|
|
62
|
+
exec > >(tee -a /var/log/ralph-user-data.log) 2>&1
|
|
63
|
+
${exports}
|
|
64
|
+
curl -fsSL https://rpm.nodesource.com/setup_24.x | bash -
|
|
65
|
+
dnf install -y nodejs git jq awscli
|
|
66
|
+
npm install -g ${pkg}@${input.harnessVersion}
|
|
67
|
+
exec ralph-orchestrate
|
|
68
|
+
`;
|
|
69
|
+
const bytes = Buffer.byteLength(stub, "utf8");
|
|
70
|
+
if (bytes > USER_DATA_CAP_BYTES) {
|
|
71
|
+
throw new RawSizeExceededError(bytes);
|
|
72
|
+
}
|
|
73
|
+
return stub;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=user-data-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-data-renderer.js","sourceRoot":"","sources":["../../src/lib/user-data-renderer.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,4EAA4E;AAC5E,kDAAkD;AAClD,EAAE;AACF,sEAAsE;AACtE,0EAA0E;AAC1E,yEAAyE;AACzE,2EAA2E;AAC3E,yEAAyE;AACzE,sEAAsE;AACtE,+DAA+D;AAC/D,EAAE;AACF,kBAAkB;AAClB,oEAAoE;AACpE,kEAAkE;AAClE,mFAAmF;AAEnF,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAElD,sDAAsD;AACtD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAE1C,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACjB;IAA5B,YAA4B,KAAa;QACvC,KAAK,CACH,GAAG,aAAa,2BAA2B,KAAK,kCAAkC,mBAAmB,YAAY,CAClH,CAAC;QAHwB,UAAK,GAAL,KAAK,CAAQ;QAIvC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAmBD,MAAM,oBAAoB,GAAG,4BAA4B,CAAC;AAE1D,uEAAuE;AACvE,uEAAuE;AACvE,6BAA6B;AAC7B,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAoB;IACjD,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,IAAI,oBAAoB,CAAC;IACtD,kEAAkE;IAClE,uDAAuD;IACvD,MAAM,OAAO,GAA2B;QACtC,iBAAiB,EAAE,KAAK,CAAC,UAAU;QACnC,gBAAgB,EAAE,KAAK,CAAC,SAAS;QACjC,eAAe,EAAE,KAAK,CAAC,QAAQ;QAC/B,0BAA0B,EAAE,KAAK,CAAC,iBAAiB;QACnD,0BAA0B,EAAE,KAAK,CAAC,iBAAiB;QACnD,uBAAuB,EAAE,KAAK,CAAC,eAAe;QAC9C,qBAAqB,EAAE,KAAK,CAAC,cAAc;KAC5C,CAAC;IACF,MAAM,MAAM,GAA2B,EAAE,GAAG,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;IACjF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAG,UAAU;SACvB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;SACzD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,iEAAiE;IACjE,uEAAuE;IACvE,qDAAqD;IACrD,MAAM,IAAI,GAAG;;;EAGb,OAAO;;;iBAGQ,GAAG,IAAI,KAAK,CAAC,cAAc;;CAE3C,CAAC;IAEA,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,KAAK,GAAG,mBAAmB,EAAE,CAAC;QAChC,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# system-setup.sh — slice 5 OS-level setup. Runs as the first step of
|
|
4
|
+
# `ralph-orchestrate` on the EC2 worker, AFTER the user-data stub has
|
|
5
|
+
# installed Node + git + jq + awscli + the harness package.
|
|
6
|
+
#
|
|
7
|
+
# Scope (intentionally OS-level only — everything else is in TS):
|
|
8
|
+
# 1. start the amazon-cloudwatch-agent so /var/log/ralph.log streams
|
|
9
|
+
# live to CloudWatch (every ~5s) — survives force-termination
|
|
10
|
+
# 2. install gh, .NET 10 SDK, Docker, and the claude CLI
|
|
11
|
+
# 3. fetch GitHub PAT and Claude OAuth credential from SSM SecureString
|
|
12
|
+
# into mode-0600 files
|
|
13
|
+
# 4. clone the target repo on its resolved default branch
|
|
14
|
+
# 5. safety guards (default branch, clean working tree, origin matches
|
|
15
|
+
# RALPH_TARGET_REPO)
|
|
16
|
+
# 6. configure claude MCPs (serena, morph-mcp, context7, github,
|
|
17
|
+
# sequential-thinking; `memory` excluded)
|
|
18
|
+
# 7. validate .ralph/config.yaml via `ralph-validate-config`
|
|
19
|
+
# 8. write RALPH_WORK_DIR / RALPH_DEFAULT_BRANCH / RALPH_CONFIG /
|
|
20
|
+
# RALPH_LAUNCH_TAG to /tmp/ralph/setup.env so the TS orchestrator
|
|
21
|
+
# picks them up after this subprocess exits
|
|
22
|
+
#
|
|
23
|
+
# Inputs (env, set by ralph-fire's user-data stub):
|
|
24
|
+
# RALPH_TARGET_REPO required, owner/repo
|
|
25
|
+
# RALPH_AWS_REGION required, e.g. eu-central-1
|
|
26
|
+
# RALPH_GITHUB_TOKEN_SSM_KEY SSM SecureString name for the GitHub PAT
|
|
27
|
+
# RALPH_CLAUDE_OAUTH_SSM_KEY SSM SecureString name for the OAuth cred
|
|
28
|
+
# RALPH_LOG_GROUP CloudWatch log group
|
|
29
|
+
#
|
|
30
|
+
# Output: /tmp/ralph/setup.env (KEY=VALUE per line) — read by ralph-orchestrate
|
|
31
|
+
# after this script exits.
|
|
32
|
+
|
|
33
|
+
set -uo pipefail
|
|
34
|
+
|
|
35
|
+
: "${HOME:=/root}"
|
|
36
|
+
export HOME
|
|
37
|
+
|
|
38
|
+
# claude CLI refuses --permission-mode bypassPermissions when running as
|
|
39
|
+
# root unless IS_SANDBOX=1. cloud-init runs as root and the orchestrator
|
|
40
|
+
# needs the bypass. The throwaway EC2 (scoped IAM, no SSH, ≤75-min
|
|
41
|
+
# lifetime) is the sandbox this knob exists for.
|
|
42
|
+
export IS_SANDBOX=1
|
|
43
|
+
|
|
44
|
+
: "${RALPH_LOG_GROUP:=/ralph/main}"
|
|
45
|
+
: "${RALPH_GITHUB_TOKEN_SSM_KEY:=/ralph/github-pat}"
|
|
46
|
+
: "${RALPH_CLAUDE_OAUTH_SSM_KEY:=/ralph/claude-oauth-credential}"
|
|
47
|
+
|
|
48
|
+
LOG_FILE="/var/log/ralph.log"
|
|
49
|
+
: > "$LOG_FILE" 2>/dev/null || true
|
|
50
|
+
|
|
51
|
+
# ---- IMDSv2 + metadata -------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
setup__md_token=$(curl -fsS -m 5 -X PUT \
|
|
54
|
+
"http://169.254.169.254/latest/api/token" \
|
|
55
|
+
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600" 2>/dev/null || true)
|
|
56
|
+
|
|
57
|
+
setup__md() {
|
|
58
|
+
curl -fsS -m 5 \
|
|
59
|
+
-H "X-aws-ec2-metadata-token: ${setup__md_token}" \
|
|
60
|
+
"http://169.254.169.254/latest/meta-data/$1" 2>/dev/null || true
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
INSTANCE_ID=$(setup__md instance-id)
|
|
64
|
+
REGION="${RALPH_AWS_REGION:-$(setup__md placement/region)}"
|
|
65
|
+
LOG_STREAM="${INSTANCE_ID:-unknown-instance}"
|
|
66
|
+
|
|
67
|
+
# Per-launch identifier embedded by the implementation call as an HTML
|
|
68
|
+
# comment in the PR body so the launcher can correlate post-hoc when the
|
|
69
|
+
# instance was hard-killed before recording state. Defaults to the
|
|
70
|
+
# instance id; falls back to a timestamp+pid pair if IMDS is unreachable.
|
|
71
|
+
RALPH_LAUNCH_TAG="${INSTANCE_ID:-$(date -u +%s)-$$}"
|
|
72
|
+
export RALPH_LAUNCH_TAG
|
|
73
|
+
|
|
74
|
+
setup__info() { printf 'system-setup: %s\n' "$*"; }
|
|
75
|
+
setup__err() { printf 'system-setup: error: %s\n' "$*" >&2; }
|
|
76
|
+
|
|
77
|
+
# Pulls a SecureString parameter, decrypts under the role's permitted KMS
|
|
78
|
+
# alias, prints the value to stdout. Caller redirects to a 0600 file.
|
|
79
|
+
setup__ssm_get() {
|
|
80
|
+
local name="$1"
|
|
81
|
+
aws --region "$REGION" ssm get-parameter \
|
|
82
|
+
--name "$name" \
|
|
83
|
+
--with-decryption \
|
|
84
|
+
--query 'Parameter.Value' \
|
|
85
|
+
--output text
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# ---- live log streaming via amazon-cloudwatch-agent --------------------------
|
|
89
|
+
|
|
90
|
+
setup__start_cwagent() {
|
|
91
|
+
setup__info "PHASE_START phase=cwagent stream=${LOG_STREAM}"
|
|
92
|
+
if ! dnf -y -q --allowerasing install amazon-cloudwatch-agent >/dev/null 2>&1; then
|
|
93
|
+
setup__err "amazon-cloudwatch-agent install failed; live log streaming disabled"
|
|
94
|
+
return 0
|
|
95
|
+
fi
|
|
96
|
+
local cfg=/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/ralph.json
|
|
97
|
+
install -d -m 755 "$(dirname "$cfg")"
|
|
98
|
+
cat > "$cfg" <<JSON
|
|
99
|
+
{
|
|
100
|
+
"agent": { "run_as_user": "root" },
|
|
101
|
+
"logs": {
|
|
102
|
+
"force_flush_interval": 5,
|
|
103
|
+
"logs_collected": {
|
|
104
|
+
"files": {
|
|
105
|
+
"collect_list": [
|
|
106
|
+
{
|
|
107
|
+
"file_path": "${LOG_FILE}",
|
|
108
|
+
"log_group_name": "${RALPH_LOG_GROUP}",
|
|
109
|
+
"log_stream_name": "${LOG_STREAM}",
|
|
110
|
+
"timezone": "UTC"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"file_path": "/var/log/cloud-init-output.log",
|
|
114
|
+
"log_group_name": "${RALPH_LOG_GROUP}",
|
|
115
|
+
"log_stream_name": "${LOG_STREAM}-cloud-init",
|
|
116
|
+
"timezone": "UTC"
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
JSON
|
|
124
|
+
if /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
|
|
125
|
+
-a fetch-config -m ec2 -c "file:${cfg}" -s >/dev/null 2>&1; then
|
|
126
|
+
setup__info "PHASE_END phase=cwagent"
|
|
127
|
+
else
|
|
128
|
+
setup__err "amazon-cloudwatch-agent failed to start; live log streaming disabled"
|
|
129
|
+
fi
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# ---- install OS deps (gh, .NET 10, Docker, claude) ---------------------------
|
|
133
|
+
|
|
134
|
+
setup__install_deps() {
|
|
135
|
+
setup__info "PHASE_START phase=install-deps"
|
|
136
|
+
|
|
137
|
+
# gh CLI — official rpm repo.
|
|
138
|
+
dnf -y -q config-manager --add-repo \
|
|
139
|
+
https://cli.github.com/packages/rpm/gh-cli.repo >/dev/null
|
|
140
|
+
dnf -y -q --allowerasing install gh >/dev/null
|
|
141
|
+
|
|
142
|
+
# Docker — required by the github MCP container.
|
|
143
|
+
dnf -y -q --allowerasing install docker >/dev/null
|
|
144
|
+
systemctl enable --now docker >/dev/null 2>&1 || true
|
|
145
|
+
|
|
146
|
+
# uv (astral) — used by serena.
|
|
147
|
+
if ! command -v uv >/dev/null 2>&1; then
|
|
148
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh >/dev/null 2>&1 || true
|
|
149
|
+
export PATH="/root/.local/bin:${HOME}/.local/bin:${PATH}"
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# .NET 10 SDK via dotnet-install.sh.
|
|
153
|
+
if ! command -v dotnet >/dev/null 2>&1; then
|
|
154
|
+
curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh
|
|
155
|
+
chmod +x /tmp/dotnet-install.sh
|
|
156
|
+
/tmp/dotnet-install.sh --channel 10.0 \
|
|
157
|
+
--install-dir /usr/share/dotnet >/dev/null
|
|
158
|
+
ln -sf /usr/share/dotnet/dotnet /usr/local/bin/dotnet
|
|
159
|
+
rm -f /tmp/dotnet-install.sh
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
# claude CLI (npm global).
|
|
163
|
+
npm install -g @anthropic-ai/claude-code >/dev/null
|
|
164
|
+
|
|
165
|
+
setup__info "PHASE_END phase=install-deps"
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# ---- fetch secrets from SSM --------------------------------------------------
|
|
169
|
+
|
|
170
|
+
setup__fetch_secrets() {
|
|
171
|
+
setup__info "PHASE_START phase=fetch-secrets"
|
|
172
|
+
|
|
173
|
+
local pat_dir="${HOME}/.ralph"
|
|
174
|
+
install -d -m 700 "$pat_dir"
|
|
175
|
+
local pat_file="${pat_dir}/github-pat"
|
|
176
|
+
if ! setup__ssm_get "$RALPH_GITHUB_TOKEN_SSM_KEY" > "$pat_file"; then
|
|
177
|
+
setup__err "could not fetch GitHub PAT from ${RALPH_GITHUB_TOKEN_SSM_KEY}"
|
|
178
|
+
return 1
|
|
179
|
+
fi
|
|
180
|
+
chmod 600 "$pat_file"
|
|
181
|
+
if ! gh auth login --with-token < "$pat_file" >/dev/null 2>&1; then
|
|
182
|
+
setup__err "gh auth login failed"
|
|
183
|
+
return 1
|
|
184
|
+
fi
|
|
185
|
+
if ! gh auth setup-git >/dev/null 2>&1; then
|
|
186
|
+
setup__err "gh auth setup-git failed"
|
|
187
|
+
return 1
|
|
188
|
+
fi
|
|
189
|
+
GH_TOKEN="$(<"$pat_file")"
|
|
190
|
+
GITHUB_PERSONAL_ACCESS_TOKEN="$GH_TOKEN"
|
|
191
|
+
export GH_TOKEN GITHUB_PERSONAL_ACCESS_TOKEN
|
|
192
|
+
|
|
193
|
+
local cred_dir="${HOME}/.claude"
|
|
194
|
+
install -d -m 700 "$cred_dir"
|
|
195
|
+
local cred_file="${cred_dir}/.credentials.json"
|
|
196
|
+
if ! setup__ssm_get "$RALPH_CLAUDE_OAUTH_SSM_KEY" > "$cred_file"; then
|
|
197
|
+
setup__err "could not fetch OAuth credential from ${RALPH_CLAUDE_OAUTH_SSM_KEY}"
|
|
198
|
+
return 1
|
|
199
|
+
fi
|
|
200
|
+
chmod 600 "$cred_file"
|
|
201
|
+
|
|
202
|
+
setup__info "PHASE_END phase=fetch-secrets"
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# ---- fresh clone of target on resolved default branch ------------------------
|
|
206
|
+
|
|
207
|
+
setup__clone_target() {
|
|
208
|
+
setup__info "PHASE_START phase=clone-target target=${RALPH_TARGET_REPO}"
|
|
209
|
+
if [[ -z "${RALPH_TARGET_REPO:-}" ]]; then
|
|
210
|
+
setup__err "RALPH_TARGET_REPO is required"
|
|
211
|
+
return 2
|
|
212
|
+
fi
|
|
213
|
+
local default_branch
|
|
214
|
+
default_branch=$(gh repo view "$RALPH_TARGET_REPO" \
|
|
215
|
+
--json defaultBranchRef \
|
|
216
|
+
--jq '.defaultBranchRef.name')
|
|
217
|
+
if [[ -z "$default_branch" ]]; then
|
|
218
|
+
setup__err "could not resolve default branch for ${RALPH_TARGET_REPO}"
|
|
219
|
+
return 1
|
|
220
|
+
fi
|
|
221
|
+
local work_dir
|
|
222
|
+
work_dir="$(mktemp -d -t ralph-work-XXXXXX)"
|
|
223
|
+
if ! git clone --depth 1 --branch "$default_branch" \
|
|
224
|
+
"https://github.com/${RALPH_TARGET_REPO}.git" "$work_dir" \
|
|
225
|
+
>/dev/null 2>&1; then
|
|
226
|
+
setup__err "git clone of ${RALPH_TARGET_REPO} failed"
|
|
227
|
+
return 1
|
|
228
|
+
fi
|
|
229
|
+
RALPH_WORK_DIR="$work_dir"
|
|
230
|
+
RALPH_DEFAULT_BRANCH="$default_branch"
|
|
231
|
+
export RALPH_WORK_DIR RALPH_DEFAULT_BRANCH
|
|
232
|
+
cd "$RALPH_WORK_DIR"
|
|
233
|
+
setup__info "PHASE_END phase=clone-target branch=${default_branch} dir=${RALPH_WORK_DIR}"
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
# ---- safety guards -----------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
setup__safety_guards() {
|
|
239
|
+
setup__info "PHASE_START phase=safety-guards"
|
|
240
|
+
cd "${RALPH_WORK_DIR:?work dir required}"
|
|
241
|
+
|
|
242
|
+
local current_branch
|
|
243
|
+
current_branch=$(git rev-parse --abbrev-ref HEAD)
|
|
244
|
+
if [[ "$current_branch" != "$RALPH_DEFAULT_BRANCH" ]]; then
|
|
245
|
+
setup__err "post-clone branch is ${current_branch}, expected ${RALPH_DEFAULT_BRANCH}"
|
|
246
|
+
return 1
|
|
247
|
+
fi
|
|
248
|
+
|
|
249
|
+
if [[ -n "$(git status --porcelain)" ]]; then
|
|
250
|
+
setup__err "fresh clone has uncommitted state — refusing to continue"
|
|
251
|
+
return 1
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
local origin
|
|
255
|
+
origin=$(git remote get-url origin)
|
|
256
|
+
if [[ "$origin" != *"${RALPH_TARGET_REPO}"* ]]; then
|
|
257
|
+
setup__err "origin (${origin}) does not match RALPH_TARGET_REPO (${RALPH_TARGET_REPO})"
|
|
258
|
+
return 1
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
setup__info "PHASE_END phase=safety-guards"
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# ---- configure claude MCPs (memory excluded) ---------------------------------
|
|
265
|
+
|
|
266
|
+
setup__configure_mcps() {
|
|
267
|
+
setup__info "PHASE_START phase=configure-mcps"
|
|
268
|
+
claude mcp add serena -- \
|
|
269
|
+
uvx --from git+https://github.com/oraios/serena serena-mcp-server \
|
|
270
|
+
>/dev/null 2>&1 || true
|
|
271
|
+
claude mcp add morph-mcp -- \
|
|
272
|
+
npx -y @morph-labs/morph-mcp \
|
|
273
|
+
>/dev/null 2>&1 || true
|
|
274
|
+
claude mcp add context7 -- \
|
|
275
|
+
npx -y @upstash/context7-mcp \
|
|
276
|
+
>/dev/null 2>&1 || true
|
|
277
|
+
claude mcp add github -- \
|
|
278
|
+
docker run -i --rm \
|
|
279
|
+
-e GITHUB_PERSONAL_ACCESS_TOKEN \
|
|
280
|
+
ghcr.io/github/github-mcp-server \
|
|
281
|
+
>/dev/null 2>&1 || true
|
|
282
|
+
claude mcp add sequential-thinking -- \
|
|
283
|
+
npx -y @modelcontextprotocol/server-sequential-thinking \
|
|
284
|
+
>/dev/null 2>&1 || true
|
|
285
|
+
setup__info "PHASE_END phase=configure-mcps"
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
# ---- validate target config via ralph-validate-config ------------------------
|
|
289
|
+
|
|
290
|
+
setup__validate_config() {
|
|
291
|
+
setup__info "PHASE_START phase=validate-config"
|
|
292
|
+
local cfg="${RALPH_WORK_DIR}/.ralph/config.yaml"
|
|
293
|
+
if [[ ! -f "$cfg" ]]; then
|
|
294
|
+
setup__err "${RALPH_TARGET_REPO} is missing .ralph/config.yaml — refusing to continue"
|
|
295
|
+
return 2
|
|
296
|
+
fi
|
|
297
|
+
if ! ralph-validate-config "$cfg" >/dev/null; then
|
|
298
|
+
setup__err "${cfg} failed schema validation"
|
|
299
|
+
return 2
|
|
300
|
+
fi
|
|
301
|
+
RALPH_CONFIG="$cfg"
|
|
302
|
+
export RALPH_CONFIG
|
|
303
|
+
setup__info "PHASE_END phase=validate-config config=${cfg}"
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
# ---- write setup.env for ralph-orchestrate -----------------------------------
|
|
307
|
+
|
|
308
|
+
setup__write_env_file() {
|
|
309
|
+
install -d -m 755 /tmp/ralph
|
|
310
|
+
cat > /tmp/ralph/setup.env <<EOF
|
|
311
|
+
RALPH_WORK_DIR=${RALPH_WORK_DIR}
|
|
312
|
+
RALPH_DEFAULT_BRANCH=${RALPH_DEFAULT_BRANCH}
|
|
313
|
+
RALPH_CONFIG=${RALPH_CONFIG}
|
|
314
|
+
RALPH_LAUNCH_TAG=${RALPH_LAUNCH_TAG}
|
|
315
|
+
EOF
|
|
316
|
+
chmod 644 /tmp/ralph/setup.env
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# ---- main --------------------------------------------------------------------
|
|
320
|
+
|
|
321
|
+
setup__main() {
|
|
322
|
+
local now
|
|
323
|
+
now=$(date -u +%FT%TZ)
|
|
324
|
+
setup__info "ralph-harness slice 5 system-setup"
|
|
325
|
+
setup__info "instance=${INSTANCE_ID} region=${REGION} ts=${now}"
|
|
326
|
+
setup__info "target=${RALPH_TARGET_REPO:-unset} log_group=${RALPH_LOG_GROUP} log_stream=${LOG_STREAM}"
|
|
327
|
+
|
|
328
|
+
setup__start_cwagent
|
|
329
|
+
setup__install_deps || return $?
|
|
330
|
+
setup__fetch_secrets || return $?
|
|
331
|
+
setup__clone_target || return $?
|
|
332
|
+
setup__safety_guards || return $?
|
|
333
|
+
setup__configure_mcps || return $?
|
|
334
|
+
setup__validate_config || return $?
|
|
335
|
+
setup__write_env_file
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
setup__main 2>&1 | tee -a "$LOG_FILE"
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unimatrix27/ralph-harness",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Throwaway-EC2 loop that picks one ready-for-agent GitHub issue, implements it, opens a PR, runs one auto-review pass, then terminates.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"ralph-bootstrap-aws": "dist/bin/ralph-bootstrap-aws.js",
|
|
11
|
+
"ralph-fire": "dist/bin/ralph-fire.js",
|
|
12
|
+
"ralph-gsm": "dist/bin/ralph-gsm.js",
|
|
13
|
+
"ralph-orchestrate": "dist/bin/ralph-orchestrate.js",
|
|
14
|
+
"ralph-sync-credential": "dist/bin/ralph-sync-credential.js",
|
|
15
|
+
"ralph-sync-github-pat": "dist/bin/ralph-sync-github-pat.js",
|
|
16
|
+
"ralph-tail-logs": "dist/bin/ralph-tail-logs.js",
|
|
17
|
+
"ralph-validate-config": "dist/bin/ralph-validate-config.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/",
|
|
21
|
+
"lib/cloud-init/",
|
|
22
|
+
"prompts/",
|
|
23
|
+
"README.md",
|
|
24
|
+
"CONTRIBUTING.md"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@aws-sdk/client-cloudwatch-logs": "^3.700.0",
|
|
33
|
+
"@aws-sdk/client-ec2": "^3.700.0",
|
|
34
|
+
"@aws-sdk/client-iam": "^3.700.0",
|
|
35
|
+
"@aws-sdk/client-kms": "^3.700.0",
|
|
36
|
+
"@aws-sdk/client-ssm": "^3.700.0",
|
|
37
|
+
"@aws-sdk/client-sts": "^3.700.0",
|
|
38
|
+
"yaml": "^2.8.4",
|
|
39
|
+
"zod": "^4.4.3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^24.0.0",
|
|
43
|
+
"tsx": "^4.19.0",
|
|
44
|
+
"typescript": "^5.6.0",
|
|
45
|
+
"vitest": "^2.1.0"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/unimatrix27/ralph-harness.git"
|
|
53
|
+
},
|
|
54
|
+
"license": "MIT"
|
|
55
|
+
}
|