Skip to content

Commit d74e169

Browse files
haasonsaasgithub-actions[bot]cursoragent
authored
chore: sync public mirror from internal (#810)
* chore: sync public mirror from internal * Fix pre-commit hook on macOS bash * Address public mirror review findings * [maestro] Fix review workflow inference and audit output * fix: restore review workflow guardrails * Route installer package override through metadata * Format learned guidelines mirror files * fix: avoid P0/P1 review audit false positives * fix: harden cleanup and review coverage checks * fix: preserve review audit severity and cleanup timeout * [maestro] preserve Gemini CLI workflow env vars --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 4037f58 commit d74e169

38 files changed

Lines changed: 3135 additions & 113 deletions

.husky/pre-commit

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,17 @@ fi
1212
# Run Composer Guardian (secrets + CI hygiene) before heavier tasks.
1313
bash "$ROOT/scripts/guardian.sh" --trigger pre-commit
1414
15-
bun run bun:lint && bun run build && bun run bun:compile
15+
STAGED_FORMAT_FILES=()
16+
while IFS= read -r staged_file; do
17+
STAGED_FORMAT_FILES+=("$staged_file")
18+
done < <(
19+
git diff --cached --name-only --diff-filter=ACMR |
20+
grep -E "\\.(ts|tsx|js|jsx|mjs|cjs|json|jsonc|css|md|yml|yaml)$" || true
21+
)
22+
23+
if [ "${#STAGED_FORMAT_FILES[@]}" -gt 0 ]; then
24+
bunx biome check "${STAGED_FORMAT_FILES[@]}"
25+
else
26+
echo "No staged Biome-supported files to check."
27+
fi
1628
'

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@
119119
"ci:plan": "node scripts/plan-ci-checks.mjs",
120120
"pr:ready": "node scripts/pr-ready-to-merge.mjs",
121121
"pr:feedback": "node scripts/pr-feedback-audit.mjs",
122-
"review:unresolved-threads": "node scripts/pr-feedback-audit.mjs --recent-days 3 --check",
122+
"review:unresolved-threads": "node scripts/pr-feedback-audit.mjs --recent-days 3 --check --min-severity none",
123123
"review:feedback-dashboard": "node scripts/pr-feedback-dashboard.mjs --repo evalops/maestro-internal --recent-days 3 --limit 50",
124124
"verify:runtime-deps": "node scripts/check-runtime-deps.js && node scripts/check-docker-runtime-workspaces.mjs && node scripts/check-packed-bundled-workspaces.mjs",
125125
"tui": "npm run cli",

packages/github-agent/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ export { GitHubAuth } from "./github/auth.js";
3434
export { GitHubApiClient } from "./github/client.js";
3535
export { GitHubReporter, type TaskProgress } from "./github/reporter.js";
3636
export { GitHubWebhookServer } from "./webhooks/server.js";
37+
export {
38+
MAESTRO_REVIEW_WORKFLOW_PATH,
39+
buildMaestroReviewWorkflow,
40+
writeMaestroReviewWorkflow,
41+
type MaestroReviewWorkflowOptions,
42+
} from "./workflows/maestro-review-workflow.js";
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
2+
import { tmpdir } from "node:os";
3+
import { join } from "node:path";
4+
import { afterEach, describe, expect, it } from "vitest";
5+
import {
6+
MAESTRO_REVIEW_WORKFLOW_PATH,
7+
buildMaestroReviewWorkflow,
8+
writeMaestroReviewWorkflow,
9+
} from "../index.js";
10+
11+
const tempDirs: string[] = [];
12+
13+
afterEach(() => {
14+
for (const dir of tempDirs.splice(0)) {
15+
rmSync(dir, { force: true, recursive: true });
16+
}
17+
});
18+
19+
describe("maestro review workflow generator", () => {
20+
it("emits a pull_request workflow that runs maestro exec and comments", () => {
21+
const yaml = buildMaestroReviewWorkflow();
22+
expect(yaml).toContain("name: Maestro Code Review");
23+
expect(yaml).toContain("on:\n pull_request:");
24+
expect(yaml).toContain("pull-requests: write");
25+
expect(yaml).toContain(
26+
'export MAESTRO_MERGE_BASE_SHA="$(git merge-base "${MAESTRO_BASE_SHA}" "${MAESTRO_HEAD_SHA}")"',
27+
);
28+
expect(yaml).toContain(
29+
"maestro exec --provider 'anthropic' --output-last-message review.md",
30+
);
31+
expect(yaml).toContain(
32+
"from merge base ${MAESTRO_MERGE_BASE_SHA} to ${MAESTRO_HEAD_SHA}",
33+
);
34+
expect(yaml).toContain("gh pr comment");
35+
expect(yaml).toContain('node-version: "20"');
36+
expect(yaml).toContain("npm install -g 'maestro@latest'");
37+
expect(yaml).toContain("GITHUB_PERSONAL_ACCESS_TOKEN: ${{ github.token }}");
38+
expect(yaml).toContain(
39+
[
40+
'gh pr comment "${MAESTRO_PR_NUMBER}" --edit-last --body-file review.md || \\',
41+
' gh pr comment "${MAESTRO_PR_NUMBER}" --body-file review.md',
42+
].join("\n"),
43+
);
44+
});
45+
46+
it("reads the default package override at build time", () => {
47+
const previous = process.env.MAESTRO_PACKAGE_NAME;
48+
try {
49+
process.env.MAESTRO_PACKAGE_NAME = "@example/from-env";
50+
expect(buildMaestroReviewWorkflow()).toContain(
51+
"npm install -g '@example/from-env@latest'",
52+
);
53+
} finally {
54+
if (previous === undefined) {
55+
delete process.env.MAESTRO_PACKAGE_NAME;
56+
} else {
57+
process.env.MAESTRO_PACKAGE_NAME = previous;
58+
}
59+
}
60+
});
61+
62+
it("is deterministic for the same options", () => {
63+
expect(buildMaestroReviewWorkflow({ model: "claude-opus-4-8" })).toBe(
64+
buildMaestroReviewWorkflow({ model: "claude-opus-4-8" }),
65+
);
66+
});
67+
68+
it("threads model, version, node, and api-key-secret options", () => {
69+
const yaml = buildMaestroReviewWorkflow({
70+
provider: "anthropic",
71+
model: "claude-opus-4-8",
72+
maestroPackage: "@example/maestro",
73+
maestroVersion: "1.2.3",
74+
nodeVersion: "22",
75+
apiKeySecretName: "MODEL_API_KEY",
76+
});
77+
expect(yaml).toContain(
78+
"maestro exec --provider 'anthropic' --model 'claude-opus-4-8'",
79+
);
80+
expect(yaml).toContain("npm install -g '@example/maestro@1.2.3'");
81+
expect(yaml).toContain('node-version: "22"');
82+
expect(yaml).toContain("ANTHROPIC_API_KEY: ${{ secrets.MODEL_API_KEY }}");
83+
});
84+
85+
it("maps provider secret names to Maestro runtime env names", () => {
86+
expect(buildMaestroReviewWorkflow({ provider: "openai" })).toContain(
87+
"OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}",
88+
);
89+
expect(
90+
buildMaestroReviewWorkflow({
91+
provider: "openai",
92+
apiKeySecretName: "maestro_OpenAI_review_key",
93+
}),
94+
).toContain("OPENAI_API_KEY: ${{ secrets.maestro_OpenAI_review_key }}");
95+
expect(
96+
buildMaestroReviewWorkflow({
97+
provider: "custom-provider",
98+
apiKeyEnvName: "CUSTOM_PROVIDER_API_KEY",
99+
apiKeySecretName: "CUSTOM_PROVIDER_REVIEW_SECRET",
100+
}),
101+
).toContain(
102+
"CUSTOM_PROVIDER_API_KEY: ${{ secrets.CUSTOM_PROVIDER_REVIEW_SECRET }}",
103+
);
104+
});
105+
106+
it("omits the model flag when no model is given", () => {
107+
expect(buildMaestroReviewWorkflow()).toContain(
108+
"maestro exec --provider 'anthropic' --output-last-message",
109+
);
110+
expect(buildMaestroReviewWorkflow()).not.toContain("--model");
111+
});
112+
113+
it("infers a provider from the configured API key env var", () => {
114+
expect(
115+
buildMaestroReviewWorkflow({ apiKeySecretName: "OPENAI_API_KEY" }),
116+
).toContain("maestro exec --provider 'openai' --output-last-message");
117+
expect(
118+
buildMaestroReviewWorkflow({ apiKeyEnvName: "OPENAI_API_KEY" }),
119+
).toContain("maestro exec --provider 'openai' --output-last-message");
120+
expect(
121+
buildMaestroReviewWorkflow({
122+
apiKeyEnvName: "OPENAI_API_KEY",
123+
apiKeySecretName: "CUSTOM_REVIEW_SECRET",
124+
}),
125+
).toContain("maestro exec --provider 'openai' --output-last-message");
126+
});
127+
128+
it("keeps Gemini CLI token env names when inferring the provider", () => {
129+
const yaml = buildMaestroReviewWorkflow({
130+
apiKeySecretName: "GOOGLE_GEMINI_CLI_TOKEN",
131+
});
132+
const antigravityYaml = buildMaestroReviewWorkflow({
133+
apiKeySecretName: "GOOGLE_ANTIGRAVITY_TOKEN",
134+
});
135+
expect(yaml).toContain(
136+
"GOOGLE_GEMINI_CLI_TOKEN: ${{ secrets.GOOGLE_GEMINI_CLI_TOKEN }}",
137+
);
138+
expect(yaml).toContain(
139+
"maestro exec --provider 'google-gemini-cli' --output-last-message",
140+
);
141+
expect(antigravityYaml).toContain(
142+
"GOOGLE_ANTIGRAVITY_TOKEN: ${{ secrets.GOOGLE_ANTIGRAVITY_TOKEN }}",
143+
);
144+
expect(antigravityYaml).toContain(
145+
"maestro exec --provider 'google-antigravity' --output-last-message",
146+
);
147+
});
148+
149+
it("quotes shell-interpreted option values", () => {
150+
const yaml = buildMaestroReviewWorkflow({
151+
model: "foo'; echo nope",
152+
maestroPackage: "@example/maestro",
153+
maestroVersion: "1.2.3-beta.1",
154+
});
155+
156+
expect(yaml).toContain("--model 'foo'\\''; echo nope'");
157+
expect(yaml).toContain("npm install -g '@example/maestro@1.2.3-beta.1'");
158+
});
159+
160+
it("rejects unsafe workflow structure values", () => {
161+
expect(() =>
162+
buildMaestroReviewWorkflow({ apiKeySecretName: "BAD-NAME" }),
163+
).toThrow("apiKeySecretName");
164+
expect(() =>
165+
buildMaestroReviewWorkflow({ apiKeyEnvName: "BAD-NAME" }),
166+
).toThrow("apiKeyEnvName");
167+
expect(() =>
168+
buildMaestroReviewWorkflow({ model: "safe\necho unsafe" }),
169+
).toThrow("model");
170+
});
171+
172+
it("writes the workflow to the conventional path", () => {
173+
const repoRoot = mkdtempSync(join(tmpdir(), "maestro-review-"));
174+
tempDirs.push(repoRoot);
175+
const written = writeMaestroReviewWorkflow(repoRoot);
176+
expect(written).toBe(join(repoRoot, MAESTRO_REVIEW_WORKFLOW_PATH));
177+
expect(readFileSync(written, "utf8")).toContain(
178+
"name: Maestro Code Review",
179+
);
180+
});
181+
});

0 commit comments

Comments
 (0)