opencode-magi 0.0.0-dev-20260519083157 → 0.0.0-dev-20260519084318
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/config/validate.js
CHANGED
|
@@ -475,7 +475,7 @@ async function validateAuth(config, exec, errors) {
|
|
|
475
475
|
}
|
|
476
476
|
async function fetchPermissions(config, exec, account) {
|
|
477
477
|
const token = (await exec(`gh auth token${ghHostOption(config)} --user ${JSON.stringify(account)}`)).trim();
|
|
478
|
-
const raw = await exec(`
|
|
478
|
+
const raw = await exec(`gh api${ghHostOption(config)} repos/${config.github?.owner}/${config.github?.repo} --jq .permissions`, { env: { GH_TOKEN: token } });
|
|
479
479
|
return JSON.parse(raw);
|
|
480
480
|
}
|
|
481
481
|
async function validateRepositoryPermissions(config, exec, errors, warnings) {
|
package/dist/github/commands.js
CHANGED
|
@@ -80,6 +80,9 @@ export function ghHostOption(repository) {
|
|
|
80
80
|
export async function ghToken(exec, repository, account) {
|
|
81
81
|
return (await exec(`gh auth token${ghHostOption(repository)} --user ${shellQuote(account)}`)).trim();
|
|
82
82
|
}
|
|
83
|
+
function ghTokenEnv(token) {
|
|
84
|
+
return { env: { GH_TOKEN: token } };
|
|
85
|
+
}
|
|
83
86
|
export async function fetchPullRequest(exec, repository, pr) {
|
|
84
87
|
const json = await exec(`gh pr view ${pr} --repo ${shellQuote(repoSpecifier(repository))} --json number,title,url,isDraft,baseRefOid,headRefOid,baseRefName,headRefName,headRepository,headRepositoryOwner`);
|
|
85
88
|
return JSON.parse(json);
|
|
@@ -247,14 +250,14 @@ export async function removeBranch(exec, branch) {
|
|
|
247
250
|
}
|
|
248
251
|
export async function postApproval(exec, repository, pr, account) {
|
|
249
252
|
const token = await ghToken(exec, repository, account);
|
|
250
|
-
return exec(`
|
|
253
|
+
return exec(`gh pr review ${pr} --repo ${shellQuote(repoSpecifier(repository))} --approve`, ghTokenEnv(token));
|
|
251
254
|
}
|
|
252
255
|
export async function postCloseComment(exec, repository, pr, account, body) {
|
|
253
256
|
const token = await ghToken(exec, repository, account);
|
|
254
257
|
const payloadPath = join(tmpdir(), `magi-close-${process.pid}-${Date.now()}.json`);
|
|
255
258
|
await writeFile(payloadPath, JSON.stringify({ body, event: "COMMENT" }));
|
|
256
259
|
try {
|
|
257
|
-
return await exec(`
|
|
260
|
+
return await exec(`gh api${ghHostOption(repository)} repos/${repository.github.owner}/${repository.github.repo}/pulls/${pr}/reviews --method POST --input ${shellQuote(payloadPath)} --jq .html_url`, ghTokenEnv(token));
|
|
258
261
|
}
|
|
259
262
|
finally {
|
|
260
263
|
await rm(payloadPath, { force: true });
|
|
@@ -285,7 +288,7 @@ export async function postChangesRequested(exec, repository, pr, account, findin
|
|
|
285
288
|
event: "REQUEST_CHANGES",
|
|
286
289
|
}));
|
|
287
290
|
try {
|
|
288
|
-
return await exec(`
|
|
291
|
+
return await exec(`gh api${ghHostOption(repository)} repos/${repository.github.owner}/${repository.github.repo}/pulls/${pr}/reviews --method POST --input ${shellQuote(payloadPath)} --jq .html_url`, ghTokenEnv(token));
|
|
289
292
|
}
|
|
290
293
|
finally {
|
|
291
294
|
await rm(payloadPath, { force: true });
|
|
@@ -303,7 +306,7 @@ export async function mergePullRequest(exec, repository, pr, account) {
|
|
|
303
306
|
const mergeFlags = repository.merge.mergeQueue
|
|
304
307
|
? ""
|
|
305
308
|
: ` ${methodFlag}${autoFlag}${deleteFlag}`;
|
|
306
|
-
return exec(`
|
|
309
|
+
return exec(`gh pr merge ${pr} --repo ${shellQuote(repoSpecifier(repository))}${mergeFlags}`, ghTokenEnv(token));
|
|
307
310
|
}
|
|
308
311
|
export async function fetchPullRequestMergeStatus(exec, repository, pr) {
|
|
309
312
|
const json = await exec(`gh pr view ${pr} --repo ${shellQuote(repoSpecifier(repository))} --json state,mergeStateStatus,autoMergeRequest`);
|
|
@@ -322,12 +325,23 @@ export async function waitForMergeQueue(exec, repository, pr, intervalMs = 30_00
|
|
|
322
325
|
}
|
|
323
326
|
export async function closePullRequest(exec, repository, pr, account) {
|
|
324
327
|
const token = await ghToken(exec, repository, account);
|
|
325
|
-
return exec(`
|
|
328
|
+
return exec(`gh pr close ${pr} --repo ${shellQuote(repoSpecifier(repository))}`, ghTokenEnv(token));
|
|
326
329
|
}
|
|
327
330
|
export async function pushHead(exec, repository, worktreePath, account, head) {
|
|
328
331
|
const token = await ghToken(exec, repository, account);
|
|
329
332
|
const url = repositoryGitUrl(repository, head.owner, head.repo);
|
|
330
|
-
await exec(`git
|
|
333
|
+
await exec(`git push ${shellQuote(url)} ${shellQuote(`HEAD:refs/heads/${head.ref}`)}`, {
|
|
334
|
+
cwd: worktreePath,
|
|
335
|
+
env: {
|
|
336
|
+
GIT_CONFIG_COUNT: "2",
|
|
337
|
+
GIT_CONFIG_KEY_0: "credential.helper",
|
|
338
|
+
GIT_CONFIG_KEY_1: "credential.helper",
|
|
339
|
+
GIT_CONFIG_VALUE_0: "",
|
|
340
|
+
GIT_CONFIG_VALUE_1: "!f() { echo username=x-access-token; echo password=$GIT_PASSWORD; }; f",
|
|
341
|
+
GIT_PASSWORD: token,
|
|
342
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
343
|
+
},
|
|
344
|
+
});
|
|
331
345
|
}
|
|
332
346
|
export async function configureGitIdentity(exec, worktreePath, identity) {
|
|
333
347
|
if (identity.name) {
|
|
@@ -392,7 +406,7 @@ export async function postReply(exec, repository, pr, account, commentId, body)
|
|
|
392
406
|
const payloadPath = join(tmpdir(), `magi-reply-${process.pid}-${Date.now()}-${commentId}.json`);
|
|
393
407
|
await writeFile(payloadPath, JSON.stringify({ body }));
|
|
394
408
|
try {
|
|
395
|
-
return await exec(`
|
|
409
|
+
return await exec(`gh api${ghHostOption(repository)} repos/${repository.github.owner}/${repository.github.repo}/pulls/${pr}/comments/${commentId}/replies --method POST --input ${shellQuote(payloadPath)} --jq .html_url`, ghTokenEnv(token));
|
|
396
410
|
}
|
|
397
411
|
finally {
|
|
398
412
|
await rm(payloadPath, { force: true });
|
|
@@ -401,5 +415,5 @@ export async function postReply(exec, repository, pr, account, commentId, body)
|
|
|
401
415
|
export async function resolveThread(exec, repository, account, threadId) {
|
|
402
416
|
const token = await ghToken(exec, repository, account);
|
|
403
417
|
const query = `mutation($threadId: ID!) { resolveReviewThread(input: { threadId: $threadId }) { thread { id } } }`;
|
|
404
|
-
await exec(`
|
|
418
|
+
await exec(`gh api${ghHostOption(repository)} graphql -f query=${shellQuote(query)} -F threadId=${shellQuote(threadId)}`, ghTokenEnv(token));
|
|
405
419
|
}
|
|
@@ -20,6 +20,14 @@ function createRunId() {
|
|
|
20
20
|
function now() {
|
|
21
21
|
return new Date().toISOString();
|
|
22
22
|
}
|
|
23
|
+
export function redactSecrets(value) {
|
|
24
|
+
return value
|
|
25
|
+
.replace(/\b(GH_TOKEN|GITHUB_TOKEN|GH_ENTERPRISE_TOKEN)=('[^']*'|"[^"]*"|\S+)/g, "$1=<redacted>")
|
|
26
|
+
.replace(/(password=)([^;'\s]+)/g, "$1<redacted>");
|
|
27
|
+
}
|
|
28
|
+
function errorMessage(error) {
|
|
29
|
+
return redactSecrets(error instanceof Error ? error.message : String(error));
|
|
30
|
+
}
|
|
23
31
|
function isActiveStatus(status) {
|
|
24
32
|
return (status === "blocked" ||
|
|
25
33
|
status === "preparing" ||
|
|
@@ -927,7 +935,7 @@ export class MagiRunManager {
|
|
|
927
935
|
}
|
|
928
936
|
if (input.event.type === "session.error") {
|
|
929
937
|
agent.status = "failed";
|
|
930
|
-
agent.error = JSON.stringify(input.event.properties?.error ?? "session error");
|
|
938
|
+
agent.error = redactSecrets(JSON.stringify(input.event.properties?.error ?? "session error"));
|
|
931
939
|
markUpdated(true);
|
|
932
940
|
dirty = true;
|
|
933
941
|
}
|
|
@@ -1226,7 +1234,7 @@ export class MagiRunManager {
|
|
|
1226
1234
|
if (progress.type === "ci_classifier_failed") {
|
|
1227
1235
|
const classifier = state.ciClassifiers?.[progress.reviewer];
|
|
1228
1236
|
if (classifier) {
|
|
1229
|
-
classifier.error = progress.error;
|
|
1237
|
+
classifier.error = redactSecrets(progress.error);
|
|
1230
1238
|
classifier.status = "failed";
|
|
1231
1239
|
classifier.lastUpdate = now();
|
|
1232
1240
|
}
|
|
@@ -1282,7 +1290,7 @@ export class MagiRunManager {
|
|
|
1282
1290
|
if (!reviewer)
|
|
1283
1291
|
return;
|
|
1284
1292
|
reviewer.status = "failed";
|
|
1285
|
-
reviewer.error = progress.error;
|
|
1293
|
+
reviewer.error = redactSecrets(progress.error);
|
|
1286
1294
|
reviewer.lastUpdate = now();
|
|
1287
1295
|
}
|
|
1288
1296
|
if (progress.type === "reviewer_completed") {
|
|
@@ -1328,7 +1336,7 @@ export class MagiRunManager {
|
|
|
1328
1336
|
await this.notify(state, `**CI classifier ${progress.reviewer}** completed for ${prMarkdownLink(state)}: ${progress.classification} - ${progress.reason}`);
|
|
1329
1337
|
}
|
|
1330
1338
|
if (progress.type === "ci_classifier_failed") {
|
|
1331
|
-
await this.notify(state, `**CI classifier ${progress.reviewer}** failed for ${prMarkdownLink(state)}: ${progress.error}`);
|
|
1339
|
+
await this.notify(state, `**CI classifier ${progress.reviewer}** failed for ${prMarkdownLink(state)}: ${redactSecrets(progress.error)}`);
|
|
1332
1340
|
}
|
|
1333
1341
|
if (progress.type === "worktree_created") {
|
|
1334
1342
|
await this.notify(state, `Worktree is ready for ${prMarkdownLink(state)}.`);
|
|
@@ -1344,7 +1352,7 @@ export class MagiRunManager {
|
|
|
1344
1352
|
}
|
|
1345
1353
|
if (progress.type === "reviewer_failed") {
|
|
1346
1354
|
await this.notify(state, reviewerFailureText({
|
|
1347
|
-
error: progress.error,
|
|
1355
|
+
error: redactSecrets(progress.error),
|
|
1348
1356
|
pr: prMarkdownLink(state),
|
|
1349
1357
|
repairAttempts: state.reviewers[progress.reviewer]?.repairAttempts ?? 0,
|
|
1350
1358
|
reviewer: progress.reviewer,
|
|
@@ -1451,7 +1459,7 @@ export class MagiRunManager {
|
|
|
1451
1459
|
}
|
|
1452
1460
|
if (progress.type === "editor_failed") {
|
|
1453
1461
|
editor.status = "failed";
|
|
1454
|
-
editor.error = progress.error;
|
|
1462
|
+
editor.error = redactSecrets(progress.error);
|
|
1455
1463
|
editor.lastUpdate = now();
|
|
1456
1464
|
}
|
|
1457
1465
|
if (progress.type === "editor_completed") {
|
|
@@ -1475,7 +1483,7 @@ export class MagiRunManager {
|
|
|
1475
1483
|
}
|
|
1476
1484
|
if (progress.type === "editor_failed") {
|
|
1477
1485
|
await this.notify(state, editorFailureText({
|
|
1478
|
-
error: progress.error,
|
|
1486
|
+
error: redactSecrets(progress.error),
|
|
1479
1487
|
pr: prMarkdownLink(state),
|
|
1480
1488
|
repairAttempts: state.editor?.repairAttempts ?? 0,
|
|
1481
1489
|
}));
|
|
@@ -1493,7 +1501,7 @@ export class MagiRunManager {
|
|
|
1493
1501
|
state.status = "failed";
|
|
1494
1502
|
state.phase = "failed";
|
|
1495
1503
|
state.completedAt = now();
|
|
1496
|
-
state.error =
|
|
1504
|
+
state.error = errorMessage(error);
|
|
1497
1505
|
if (state.editor?.status === "pending" ||
|
|
1498
1506
|
state.editor?.status === "running" ||
|
|
1499
1507
|
state.editor?.status === "repairing" ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-magi",
|
|
3
|
-
"version": "0.0.0-dev-
|
|
3
|
+
"version": "0.0.0-dev-20260519084318",
|
|
4
4
|
"description": "Multi-agent PR review and merge orchestration plugin for OpenCode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Hirotomo Yamada <hirotomo.yamada@avap.co.jp>",
|