@growthagent/ci 0.2.0 → 0.4.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/dist/cli.js +39 -16
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
5
|
-
import { cpSync, existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
-
import
|
|
5
|
+
import { cpSync, existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
6
|
+
import path5 from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
|
|
9
9
|
// ../github/src/app.ts
|
|
@@ -235,6 +235,28 @@ function validatePatch(patch, limits = DEFAULT_PATCH_LIMITS) {
|
|
|
235
235
|
return { ok: true, report: { files, bytes, addedLines } };
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
+
// src/provider-config.ts
|
|
239
|
+
import { mkdtempSync as mkdtempSync2, writeFileSync } from "node:fs";
|
|
240
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
241
|
+
import path4 from "node:path";
|
|
242
|
+
var RUN_TOKEN_ENV = "GX_RUN_TOKEN";
|
|
243
|
+
function writeGoogleProviderConfig(model) {
|
|
244
|
+
const gateway = (process.env.GX_GATEWAY_URL ?? "").replace(/\/$/, "");
|
|
245
|
+
const dir = mkdtempSync2(path4.join(tmpdir3(), "growth-agent-pi-"));
|
|
246
|
+
const config = {
|
|
247
|
+
providers: {
|
|
248
|
+
"growthagent-google": {
|
|
249
|
+
baseUrl: `${gateway}/v1beta`,
|
|
250
|
+
api: "google-generative-ai",
|
|
251
|
+
apiKey: `$${RUN_TOKEN_ENV}`,
|
|
252
|
+
models: [{ id: model, name: model, input: ["text"], contextWindow: 1e6 }]
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
writeFileSync(path4.join(dir, "models.json"), JSON.stringify(config, null, 2));
|
|
257
|
+
return dir;
|
|
258
|
+
}
|
|
259
|
+
|
|
238
260
|
// src/trust.ts
|
|
239
261
|
var TRUSTED_APP_LOGIN = "growth-agent[bot]";
|
|
240
262
|
function authorIsTrusted(issue, extraLogins = []) {
|
|
@@ -340,11 +362,11 @@ function buildPrompt(fields, briefing) {
|
|
|
340
362
|
}
|
|
341
363
|
|
|
342
364
|
// src/cli.ts
|
|
343
|
-
var HERE =
|
|
365
|
+
var HERE = path5.dirname(fileURLToPath(import.meta.url));
|
|
344
366
|
var PATCH_FILE = "growth-agent.patch";
|
|
345
367
|
function assetsDir() {
|
|
346
|
-
const packaged =
|
|
347
|
-
return existsSync2(packaged) ? packaged :
|
|
368
|
+
const packaged = path5.join(HERE, "assets", "skills");
|
|
369
|
+
return existsSync2(packaged) ? packaged : path5.join(HERE, "..", "assets", "skills");
|
|
348
370
|
}
|
|
349
371
|
function sh(cmd, args, opts = {}) {
|
|
350
372
|
const r = spawnSync(cmd, args, { encoding: "utf8", stdio: ["inherit", "pipe", "inherit"] });
|
|
@@ -471,28 +493,25 @@ async function implement() {
|
|
|
471
493
|
console.log(
|
|
472
494
|
meta.kind === "instrumentation" ? `\u25B8 instrumentation request #${issue.number}` : `\u25B8 change request #${issue.number} \u2014 flag ${meta.flagKey} on ${meta.surface}`
|
|
473
495
|
);
|
|
474
|
-
const skillsDir =
|
|
496
|
+
const skillsDir = path5.resolve(process.cwd(), ".pi", "skills");
|
|
475
497
|
mkdirSync(skillsDir, { recursive: true });
|
|
476
498
|
cpSync(assetsDir(), skillsDir, { recursive: true });
|
|
477
499
|
const prompt = buildPrompt(meta, extractBriefing(issue.body));
|
|
478
500
|
const provider = process.env.GX_CI_PROVIDER ?? "anthropic";
|
|
479
501
|
const model = process.env.GX_CI_MODEL ?? (provider === "google" ? "gemini-3.7-flash" : "claude-opus-5");
|
|
480
|
-
if (provider === "google") {
|
|
481
|
-
console.log(
|
|
482
|
-
"\u25B8 NOTE: GX_CI_PROVIDER=google routes model traffic directly to Google on your own GEMINI_API_KEY. It is billed by Google to you and is not metered by Growth Agent."
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
502
|
const session = await openSession();
|
|
486
503
|
if (!session.ok) {
|
|
487
504
|
console.error(`Refusing to run the model: ${session.reason}`);
|
|
488
505
|
return 1;
|
|
489
506
|
}
|
|
490
|
-
|
|
507
|
+
const piProvider = provider === "google" ? "growthagent-google" : provider;
|
|
508
|
+
const piConfigDir = provider === "google" ? writeGoogleProviderConfig(model) : null;
|
|
509
|
+
console.log(`\u25B8 running pi (${piProvider}/${model})`);
|
|
491
510
|
let piStatus;
|
|
492
511
|
try {
|
|
493
512
|
const pi = spawnSync(
|
|
494
513
|
"pi",
|
|
495
|
-
["-p", prompt, "--provider",
|
|
514
|
+
["-p", prompt, "--provider", piProvider, "--model", model, "--thinking", "high"],
|
|
496
515
|
{
|
|
497
516
|
stdio: ["ignore", "inherit", "inherit"],
|
|
498
517
|
env: {
|
|
@@ -501,8 +520,12 @@ async function implement() {
|
|
|
501
520
|
ANTHROPIC_BASE_URL: process.env.GX_GATEWAY_URL ?? process.env.ANTHROPIC_BASE_URL,
|
|
502
521
|
ANTHROPIC_API_KEY: session.token,
|
|
503
522
|
// The long-lived credential must not survive into the model's
|
|
504
|
-
// environment, whatever else it might read there.
|
|
505
|
-
|
|
523
|
+
// environment, whatever else it might read there. Nor may a raw
|
|
524
|
+
// provider key: everything is spent through the run token.
|
|
525
|
+
GROWTH_AGENT_TOKEN: "",
|
|
526
|
+
GEMINI_API_KEY: "",
|
|
527
|
+
// Only set for the Google path; pi keeps its own default otherwise.
|
|
528
|
+
...piConfigDir ? { PI_CODING_AGENT_DIR: piConfigDir, [RUN_TOKEN_ENV]: session.token } : {}
|
|
506
529
|
}
|
|
507
530
|
}
|
|
508
531
|
);
|
|
@@ -522,7 +545,7 @@ async function implement() {
|
|
|
522
545
|
console.error("pi made no changes \u2014 nothing to open a PR for");
|
|
523
546
|
return 2;
|
|
524
547
|
}
|
|
525
|
-
|
|
548
|
+
writeFileSync2(PATCH_FILE, patch + "\n", "utf8");
|
|
526
549
|
const verdict = validatePatch(patch);
|
|
527
550
|
if (!verdict.ok) {
|
|
528
551
|
console.error(`The produced patch was refused: ${verdict.reason}`);
|