@blogic-cz/agent-tools 1.14.5 → 1.15.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/README.md +3 -11
- package/dist/api-tool/main.d.ts +6 -1
- package/dist/api-tool/main.d.ts.map +1 -1
- package/dist/audit-tool/main.d.ts +6 -1
- package/dist/audit-tool/main.d.ts.map +1 -1
- package/dist/az-tool/main.d.ts +6 -1
- package/dist/az-tool/main.d.ts.map +1 -1
- package/dist/azdo-tool/main.d.ts +6 -1
- package/dist/azdo-tool/main.d.ts.map +1 -1
- package/dist/credential-guard/registry.d.ts.map +1 -1
- package/dist/db-tool/main.d.ts +8 -1
- package/dist/db-tool/main.d.ts.map +1 -1
- package/dist/db-tool/service.d.ts +1 -0
- package/dist/db-tool/service.d.ts.map +1 -1
- package/dist/gh-tool/main.d.ts +4 -1
- package/dist/gh-tool/main.d.ts.map +1 -1
- package/dist/gh-tool/pr/commands.d.ts +1 -0
- package/dist/gh-tool/pr/commands.d.ts.map +1 -1
- package/dist/gh-tool/read/pulls.d.ts +44 -0
- package/dist/gh-tool/read/pulls.d.ts.map +1 -1
- package/dist/gh-tool/read/reads.d.ts +22 -0
- package/dist/gh-tool/read/reads.d.ts.map +1 -1
- package/dist/gh-tool/read/store.d.ts +4 -1
- package/dist/gh-tool/read/store.d.ts.map +1 -1
- package/dist/k8s-tool/main.d.ts +8 -1
- package/dist/k8s-tool/main.d.ts.map +1 -1
- package/dist/logs-tool/main.d.ts +4 -0
- package/dist/logs-tool/main.d.ts.map +1 -1
- package/dist/observability-tool/main.d.ts +6 -1
- package/dist/observability-tool/main.d.ts.map +1 -1
- package/dist/session-tool/main.d.ts +4 -0
- package/dist/session-tool/main.d.ts.map +1 -1
- package/dist/shared/secret-env.d.ts +9 -0
- package/dist/shared/secret-env.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/api-tool/index.ts +1 -1
- package/src/api-tool/main.ts +19 -6
- package/src/audit-tool/index.ts +1 -1
- package/src/audit-tool/main.ts +13 -4
- package/src/az-tool/index.ts +1 -1
- package/src/az-tool/main.ts +10 -4
- package/src/azdo-tool/index.ts +1 -1
- package/src/azdo-tool/main.ts +13 -4
- package/src/credential-guard/registry.ts +93 -3
- package/src/db-tool/index.ts +1 -1
- package/src/db-tool/main.ts +10 -4
- package/src/db-tool/service.ts +6 -1
- package/src/gh-tool/index.ts +1 -1
- package/src/gh-tool/main.ts +5 -4
- package/src/gh-tool/pr/commands.ts +35 -2
- package/src/gh-tool/read/pulls.ts +178 -0
- package/src/gh-tool/read/reads.ts +10 -1
- package/src/gh-tool/read/store.ts +8 -2
- package/src/k8s-tool/index.ts +1 -1
- package/src/k8s-tool/main.ts +10 -4
- package/src/logs-tool/index.ts +1 -1
- package/src/logs-tool/main.ts +13 -4
- package/src/observability-tool/index.ts +1 -1
- package/src/observability-tool/main.ts +10 -2
- package/src/session-tool/index.ts +1 -1
- package/src/session-tool/main.ts +10 -13
- package/src/shared/secret-env.ts +108 -88
package/src/azdo-tool/main.ts
CHANGED
|
@@ -184,7 +184,7 @@ EXAMPLES:
|
|
|
184
184
|
|
|
185
185
|
const commandsCommand = makeSchemaCommand(() => mainCommand);
|
|
186
186
|
|
|
187
|
-
const mainCommand = Command.make("azdo-tool", {}).pipe(
|
|
187
|
+
export const mainCommand = Command.make("azdo-tool", {}).pipe(
|
|
188
188
|
Command.withDescription(
|
|
189
189
|
`Azure DevOps Tool for Coding Agents (READ-ONLY)
|
|
190
190
|
|
|
@@ -219,6 +219,15 @@ const program = withRedactedOutput(withAudit("azdo", cli)).pipe(
|
|
|
219
219
|
Effect.tapCause(renderCauseToStderr),
|
|
220
220
|
);
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
export const runMain = () =>
|
|
223
|
+
BunRuntime.runMain(program, {
|
|
224
|
+
disableErrorReporting: true,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
export const runProgram = (args: readonly string[]) =>
|
|
228
|
+
withRedactedOutput(
|
|
229
|
+
withAudit(
|
|
230
|
+
"azdo",
|
|
231
|
+
Command.runWith(mainCommand, { version: VERSION, renderErrors: false })(args),
|
|
232
|
+
),
|
|
233
|
+
).pipe(Effect.provide(MainLayer), Effect.tapCause(renderCauseToStderr));
|
|
@@ -1164,6 +1164,78 @@ export const EXECUTABLES: readonly ExecutableEntry[] = [
|
|
|
1164
1164
|
operands: [path],
|
|
1165
1165
|
startup: ["JAVA_TOOL_OPTIONS", "JDK_JAVA_OPTIONS", "CLASSPATH", "_JAVA_OPTIONS", "JAVA_HOME"],
|
|
1166
1166
|
},
|
|
1167
|
+
{
|
|
1168
|
+
name: "hc",
|
|
1169
|
+
rejectsAbbreviations: true,
|
|
1170
|
+
options: {
|
|
1171
|
+
...flags("--json", "--help", "-h", "--version", "-V", "--skill", "--licenses"),
|
|
1172
|
+
},
|
|
1173
|
+
operands: [data],
|
|
1174
|
+
subcommands: {
|
|
1175
|
+
...Object.fromEntries(
|
|
1176
|
+
[
|
|
1177
|
+
"get",
|
|
1178
|
+
"keys",
|
|
1179
|
+
"interrupt",
|
|
1180
|
+
"attach",
|
|
1181
|
+
"kill",
|
|
1182
|
+
"rm",
|
|
1183
|
+
"label",
|
|
1184
|
+
"keep",
|
|
1185
|
+
"ls",
|
|
1186
|
+
"read",
|
|
1187
|
+
"wait",
|
|
1188
|
+
"templates",
|
|
1189
|
+
"events",
|
|
1190
|
+
"schema",
|
|
1191
|
+
"connect",
|
|
1192
|
+
"server",
|
|
1193
|
+
].map((name) => [
|
|
1194
|
+
name,
|
|
1195
|
+
{
|
|
1196
|
+
operands: [data],
|
|
1197
|
+
options: {
|
|
1198
|
+
...flags("--all", "--off", "--wait", "--force"),
|
|
1199
|
+
"--lines": arg(data),
|
|
1200
|
+
"--output": arg(data),
|
|
1201
|
+
"--children": arg(data),
|
|
1202
|
+
"--timeout": arg(data),
|
|
1203
|
+
},
|
|
1204
|
+
},
|
|
1205
|
+
]),
|
|
1206
|
+
),
|
|
1207
|
+
send: {
|
|
1208
|
+
operands: [data, path],
|
|
1209
|
+
options: {
|
|
1210
|
+
...flags("--force", "--json", "--wait"),
|
|
1211
|
+
"--if": arg(data),
|
|
1212
|
+
"--timeout": arg(data),
|
|
1213
|
+
},
|
|
1214
|
+
},
|
|
1215
|
+
run: {
|
|
1216
|
+
operands: [data],
|
|
1217
|
+
options: {
|
|
1218
|
+
...flags("--bg", "--outlive-parent", "--no-parent", "--no-notify", "--rm", "--keep"),
|
|
1219
|
+
"--name": arg(data),
|
|
1220
|
+
"--cwd": arg(path),
|
|
1221
|
+
"--on": arg(data),
|
|
1222
|
+
"--label": arg(data),
|
|
1223
|
+
"--parent": arg(data),
|
|
1224
|
+
"--timeout": arg(data),
|
|
1225
|
+
},
|
|
1226
|
+
},
|
|
1227
|
+
exec: {
|
|
1228
|
+
operands: [data],
|
|
1229
|
+
options: {
|
|
1230
|
+
...flags("-i", "--stdin"),
|
|
1231
|
+
"--cwd": arg(path),
|
|
1232
|
+
"--on": arg(data),
|
|
1233
|
+
"--env": { roles: [data], issue: unknown("hc environment override") },
|
|
1234
|
+
"--timeout": arg(data),
|
|
1235
|
+
},
|
|
1236
|
+
},
|
|
1237
|
+
},
|
|
1238
|
+
},
|
|
1167
1239
|
{
|
|
1168
1240
|
name: "herdr",
|
|
1169
1241
|
options: {
|
|
@@ -4231,7 +4303,11 @@ function classifyInvocation(
|
|
|
4231
4303
|
}
|
|
4232
4304
|
const a = argv[position];
|
|
4233
4305
|
if (a === undefined) {
|
|
4234
|
-
if (
|
|
4306
|
+
if (
|
|
4307
|
+
["env", "forward", "timeout", "xargs"].includes(entry.semantics ?? "") ||
|
|
4308
|
+
(entry.name === "hc" &&
|
|
4309
|
+
(mode === entry.subcommands?.run || mode === entry.subcommands?.exec))
|
|
4310
|
+
)
|
|
4235
4311
|
issues.push({
|
|
4236
4312
|
kind: "missing-knowledge",
|
|
4237
4313
|
rule: "opaque-executable",
|
|
@@ -4457,8 +4533,8 @@ function classifyInvocation(
|
|
|
4457
4533
|
(attached ?? argv[position + 1]) === undefined
|
|
4458
4534
|
)
|
|
4459
4535
|
issues.push(unknown("Bun option operand is not literal"));
|
|
4460
|
-
if (entry.name
|
|
4461
|
-
if (cwdOperands.length) issues.push(unknown(
|
|
4536
|
+
if (["bun", "hc"].includes(entry.name) && optionName === "--cwd") {
|
|
4537
|
+
if (cwdOperands.length) issues.push(unknown(`repeated ${entry.name} working directory`));
|
|
4462
4538
|
cwdOperands.push({
|
|
4463
4539
|
index: attached === undefined ? position + 1 : position,
|
|
4464
4540
|
...(attached !== undefined ? { literal: attached } : {}),
|
|
@@ -4581,6 +4657,18 @@ function classifyInvocation(
|
|
|
4581
4657
|
position++;
|
|
4582
4658
|
continue;
|
|
4583
4659
|
}
|
|
4660
|
+
if (
|
|
4661
|
+
entry.name === "hc" &&
|
|
4662
|
+
(mode === entry.subcommands?.run || mode === entry.subcommands?.exec)
|
|
4663
|
+
) {
|
|
4664
|
+
if (mode === entry.subcommands?.run && position === argv.length - 1) {
|
|
4665
|
+
roles.push({ index: position, role: code("bash") });
|
|
4666
|
+
roles.push({ index: position, role: path });
|
|
4667
|
+
issues.push(...unknownOperandIssues([a]));
|
|
4668
|
+
codeSeen = true;
|
|
4669
|
+
} else child(position);
|
|
4670
|
+
break;
|
|
4671
|
+
}
|
|
4584
4672
|
if (entry.name === "git" && mode === entry.subcommands?.bisect?.subcommands?.run) {
|
|
4585
4673
|
child(position);
|
|
4586
4674
|
break;
|
|
@@ -4669,6 +4757,8 @@ function classifyInvocation(
|
|
|
4669
4757
|
if (effect && effect !== "none") issues.push(effect);
|
|
4670
4758
|
if (!positional.length && !children.length && !codeSeen && entry.bare) issues.push(entry.bare);
|
|
4671
4759
|
roles.push(...optionRoles);
|
|
4760
|
+
if (entry.name === "hc" && mode === entry.subcommands?.send)
|
|
4761
|
+
issues.push(...unknownOperandIssues(positional.slice(1).map((index) => argv[index])));
|
|
4672
4762
|
const operands =
|
|
4673
4763
|
(filterOption && ["sed", "awk"].includes(entry.semantics ?? "")) ||
|
|
4674
4764
|
(filterOption &&
|
package/src/db-tool/index.ts
CHANGED
package/src/db-tool/main.ts
CHANGED
|
@@ -225,7 +225,7 @@ const grantsCommand = makeDiagnosticCommand(
|
|
|
225
225
|
|
|
226
226
|
const commandsCommand = makeSchemaCommand(() => mainCommand);
|
|
227
227
|
|
|
228
|
-
const mainCommand = Command.make("db-tool", {}).pipe(
|
|
228
|
+
export const mainCommand = Command.make("db-tool", {}).pipe(
|
|
229
229
|
Command.withDescription("Database Query Tool for Coding Agents"),
|
|
230
230
|
Command.withSubcommands([
|
|
231
231
|
sqlCommand,
|
|
@@ -261,6 +261,12 @@ const program = withRedactedOutput(withAudit("db", cli)).pipe(
|
|
|
261
261
|
Effect.tapCause(renderCauseToStderr),
|
|
262
262
|
);
|
|
263
263
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
export const runMain = () =>
|
|
265
|
+
BunRuntime.runMain(program, {
|
|
266
|
+
disableErrorReporting: true,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
export const runProgram = (args: readonly string[]) =>
|
|
270
|
+
withRedactedOutput(
|
|
271
|
+
withAudit("db", Command.runWith(mainCommand, { version: VERSION, renderErrors: false })(args)),
|
|
272
|
+
).pipe(Effect.provide(MainLayer), Effect.tapCause(renderCauseToStderr));
|
package/src/db-tool/service.ts
CHANGED
|
@@ -133,6 +133,10 @@ export function isFullyReadOnly(
|
|
|
133
133
|
// Re-exported from the shared probe so existing `#db/service` consumers keep working.
|
|
134
134
|
export { buildApiProbeArgs } from "#shared/k8s-probe";
|
|
135
135
|
|
|
136
|
+
export const DbGuardianInProcess = Context.Reference<boolean>("@agent-tools/DbGuardianInProcess", {
|
|
137
|
+
defaultValue: () => false,
|
|
138
|
+
});
|
|
139
|
+
|
|
136
140
|
export class DbService extends Context.Service<
|
|
137
141
|
DbService,
|
|
138
142
|
{
|
|
@@ -156,6 +160,7 @@ export class DbService extends Context.Service<
|
|
|
156
160
|
const sqlClient = yield* DbSqlClient;
|
|
157
161
|
const secretEnvResolver = yield* SecretEnvResolver;
|
|
158
162
|
const agentToolsConfig = yield* ConfigService;
|
|
163
|
+
const runGuardianInProcess = yield* DbGuardianInProcess;
|
|
159
164
|
const dbConfig = yield* DbConfigService;
|
|
160
165
|
|
|
161
166
|
if (!dbConfig) {
|
|
@@ -364,7 +369,7 @@ export class DbService extends Context.Service<
|
|
|
364
369
|
prerequisiteConfig,
|
|
365
370
|
(command, _label) => executeShellCommand(command),
|
|
366
371
|
effect,
|
|
367
|
-
{ tryWithoutPrerequisites: true },
|
|
372
|
+
{ tryWithoutPrerequisites: true, runGuardianInProcess },
|
|
368
373
|
).pipe(
|
|
369
374
|
Effect.mapError((error) =>
|
|
370
375
|
isPrerequisiteRunError(error)
|
package/src/gh-tool/index.ts
CHANGED
package/src/gh-tool/main.ts
CHANGED
|
@@ -222,7 +222,7 @@ const gistCommand = Command.make("gist", {}).pipe(
|
|
|
222
222
|
|
|
223
223
|
const commandsCommand = makeSchemaCommand(() => mainCommand);
|
|
224
224
|
|
|
225
|
-
const mainCommand = Command.make("gh-tool", {}).pipe(
|
|
225
|
+
export const mainCommand = Command.make("gh-tool", {}).pipe(
|
|
226
226
|
Command.withDescription(
|
|
227
227
|
`GitHub CLI Tool for Coding Agents
|
|
228
228
|
|
|
@@ -307,6 +307,7 @@ const observed = Effect.gen(function* () {
|
|
|
307
307
|
});
|
|
308
308
|
const program = observed.pipe(Effect.provide(MainLayer), Effect.tapCause(renderCauseToStderr));
|
|
309
309
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
310
|
+
export const runMain = () =>
|
|
311
|
+
BunRuntime.runMain(program, {
|
|
312
|
+
disableErrorReporting: true,
|
|
313
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { reads, writes } from "#gh/read/index";
|
|
1
|
+
import { reads, resolveRepo, writes } from "#gh/read/index";
|
|
2
2
|
import { repoSlug } from "#gh/read/keys";
|
|
3
3
|
import { Command, Flag, Param } from "effect/cli";
|
|
4
4
|
import { Console, Effect, Option } from "effect";
|
|
@@ -511,6 +511,28 @@ const compactReviewTriage = (
|
|
|
511
511
|
visibleOpenThreadIds: result.visibleOpenThreads.map((thread) => thread.threadId),
|
|
512
512
|
});
|
|
513
513
|
|
|
514
|
+
const fetchReviewTriageSummary = Effect.fn("pr.fetchReviewTriageSummary")(function* (pr: number) {
|
|
515
|
+
const repo = yield* resolveRepo(null);
|
|
516
|
+
return yield* reads
|
|
517
|
+
.prReviewTriageSummary(repo, pr)
|
|
518
|
+
.pipe(Effect.map((result) => ({ pr, ...result })));
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
const fetchReviewTriageSummaryBatch = Effect.fn("pr.fetchReviewTriageSummaryBatch")(function* (
|
|
522
|
+
prs: readonly number[],
|
|
523
|
+
) {
|
|
524
|
+
return yield* Effect.forEach(
|
|
525
|
+
prs,
|
|
526
|
+
(pr) =>
|
|
527
|
+
fetchReviewTriageSummary(pr).pipe(
|
|
528
|
+
Effect.catch((error) =>
|
|
529
|
+
Effect.succeed({ pr, error: error instanceof Error ? error.message : String(error) }),
|
|
530
|
+
),
|
|
531
|
+
),
|
|
532
|
+
{ concurrency: 5 },
|
|
533
|
+
);
|
|
534
|
+
});
|
|
535
|
+
|
|
514
536
|
export const fetchReviewTriageBatch = Effect.fn("pr.fetchReviewTriageBatch")(function* (
|
|
515
537
|
prs: readonly number[],
|
|
516
538
|
) {
|
|
@@ -1835,12 +1857,23 @@ export const prReviewTriageBatchCommand = Command.make(
|
|
|
1835
1857
|
format: formatOption,
|
|
1836
1858
|
prs: Flag.String("prs").pipe(Flag.withDescription("Comma-separated PR numbers")),
|
|
1837
1859
|
repo: repoOption,
|
|
1860
|
+
summary: Flag.Boolean("summary").pipe(
|
|
1861
|
+
Flag.withDescription(
|
|
1862
|
+
"Fetch only PR state, review thread counts, and check names and buckets",
|
|
1863
|
+
),
|
|
1864
|
+
Flag.withDefault(false),
|
|
1865
|
+
),
|
|
1838
1866
|
},
|
|
1839
|
-
({ format, prs, repo }) =>
|
|
1867
|
+
({ format, prs, repo, summary }) =>
|
|
1840
1868
|
withRepo(
|
|
1841
1869
|
repo,
|
|
1842
1870
|
Effect.gen(function* () {
|
|
1843
1871
|
const numbers = yield* parsePrNumbers(prs);
|
|
1872
|
+
if (summary) {
|
|
1873
|
+
const results = yield* fetchReviewTriageSummaryBatch(numbers);
|
|
1874
|
+
yield* logFormatted(results, format);
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1844
1877
|
const results = yield* Effect.all(
|
|
1845
1878
|
numbers.map((prNumber) => fetchReviewTriage(prNumber)),
|
|
1846
1879
|
{ concurrency: "unbounded" },
|
|
@@ -278,6 +278,184 @@ export const prChecks = Effect.fn("reads.prChecks")(function* (
|
|
|
278
278
|
});
|
|
279
279
|
});
|
|
280
280
|
|
|
281
|
+
const PR_REVIEW_TRIAGE_SUMMARY_QUERY = `
|
|
282
|
+
query($owner: String!, $name: String!, $pr: Int!, $after: String) {
|
|
283
|
+
repository(owner: $owner, name: $name) {
|
|
284
|
+
pullRequest(number: $pr) {
|
|
285
|
+
number
|
|
286
|
+
title
|
|
287
|
+
state
|
|
288
|
+
isDraft
|
|
289
|
+
baseRefName
|
|
290
|
+
reviewDecision
|
|
291
|
+
mergeable
|
|
292
|
+
reviewRequests(first: 100) {
|
|
293
|
+
nodes {
|
|
294
|
+
requestedReviewer {
|
|
295
|
+
... on User { login }
|
|
296
|
+
... on Team { slug }
|
|
297
|
+
... on Bot { login }
|
|
298
|
+
... on EnterpriseTeam { name }
|
|
299
|
+
... on Mannequin { login }
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
reviewThreads(first: 100, after: $after) {
|
|
304
|
+
nodes {
|
|
305
|
+
isResolved
|
|
306
|
+
comments(first: 2) {
|
|
307
|
+
nodes { replyTo { id } }
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
pageInfo { hasNextPage endCursor }
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
`;
|
|
316
|
+
|
|
317
|
+
const PR_REVIEW_THREAD_COUNTS_QUERY = `
|
|
318
|
+
query($owner: String!, $name: String!, $pr: Int!, $after: String) {
|
|
319
|
+
repository(owner: $owner, name: $name) {
|
|
320
|
+
pullRequest(number: $pr) {
|
|
321
|
+
reviewThreads(first: 100, after: $after) {
|
|
322
|
+
nodes {
|
|
323
|
+
isResolved
|
|
324
|
+
comments(first: 2) {
|
|
325
|
+
nodes { replyTo { id } }
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
pageInfo { hasNextPage endCursor }
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
`;
|
|
334
|
+
|
|
335
|
+
type PrReviewTriageSummaryPage = {
|
|
336
|
+
readonly repository: {
|
|
337
|
+
readonly pullRequest: {
|
|
338
|
+
readonly number: number;
|
|
339
|
+
readonly title: string;
|
|
340
|
+
readonly state: string;
|
|
341
|
+
readonly isDraft: boolean;
|
|
342
|
+
readonly baseRefName: string;
|
|
343
|
+
readonly reviewDecision: string | null;
|
|
344
|
+
readonly mergeable: "MERGEABLE" | "CONFLICTING" | "UNKNOWN";
|
|
345
|
+
readonly reviewRequests: {
|
|
346
|
+
readonly nodes: ReadonlyArray<{
|
|
347
|
+
readonly requestedReviewer: {
|
|
348
|
+
readonly login?: string;
|
|
349
|
+
readonly slug?: string;
|
|
350
|
+
readonly name?: string;
|
|
351
|
+
} | null;
|
|
352
|
+
}>;
|
|
353
|
+
};
|
|
354
|
+
readonly reviewThreads: {
|
|
355
|
+
readonly nodes: ReadonlyArray<{
|
|
356
|
+
readonly isResolved: boolean;
|
|
357
|
+
readonly comments: {
|
|
358
|
+
readonly nodes: ReadonlyArray<{ readonly replyTo: { readonly id: string } | null }>;
|
|
359
|
+
};
|
|
360
|
+
}>;
|
|
361
|
+
readonly pageInfo: { readonly hasNextPage: boolean; readonly endCursor: string | null };
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
};
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
export type PrReviewTriageSummary = {
|
|
368
|
+
readonly info: {
|
|
369
|
+
readonly number: number;
|
|
370
|
+
readonly title: string;
|
|
371
|
+
readonly state: string;
|
|
372
|
+
readonly isDraft: boolean;
|
|
373
|
+
readonly baseRefName: string;
|
|
374
|
+
readonly reviewDecision: string;
|
|
375
|
+
readonly mergeable: "MERGEABLE" | "CONFLICTING" | "UNKNOWN";
|
|
376
|
+
readonly reviewRequests: ReadonlyArray<{ readonly login: string }>;
|
|
377
|
+
};
|
|
378
|
+
readonly summary: {
|
|
379
|
+
readonly unresolvedReviewThreadsCount: number;
|
|
380
|
+
readonly unrepliedReviewThreadsCount: number;
|
|
381
|
+
};
|
|
382
|
+
readonly checks: ReadonlyArray<{ readonly name: string; readonly bucket: string }>;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
export const prReviewTriageSummary = Effect.fn("reads.prReviewTriageSummary")(function* (
|
|
386
|
+
repo: RepoRef,
|
|
387
|
+
pr: number,
|
|
388
|
+
) {
|
|
389
|
+
const gh = yield* GitHubService;
|
|
390
|
+
const variables = { owner: repo.owner, name: repo.name, pr, after: null as string | null };
|
|
391
|
+
const first = (yield* gh.runGraphQL(
|
|
392
|
+
PR_REVIEW_TRIAGE_SUMMARY_QUERY,
|
|
393
|
+
variables,
|
|
394
|
+
)) as PrReviewTriageSummaryPage;
|
|
395
|
+
const firstPage = first.repository.pullRequest;
|
|
396
|
+
let unresolvedReviewThreadsCount = 0;
|
|
397
|
+
let unrepliedReviewThreadsCount = 0;
|
|
398
|
+
const countThreads = (
|
|
399
|
+
threads: PrReviewTriageSummaryPage["repository"]["pullRequest"]["reviewThreads"]["nodes"],
|
|
400
|
+
) => {
|
|
401
|
+
for (const thread of threads) {
|
|
402
|
+
if (!thread.isResolved) unresolvedReviewThreadsCount++;
|
|
403
|
+
if (!thread.comments.nodes.some((comment) => comment.replyTo !== null))
|
|
404
|
+
unrepliedReviewThreadsCount++;
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
countThreads(firstPage.reviewThreads.nodes);
|
|
408
|
+
|
|
409
|
+
let pageInfo = firstPage.reviewThreads.pageInfo;
|
|
410
|
+
while (pageInfo.hasNextPage && pageInfo.endCursor !== null) {
|
|
411
|
+
const response = (yield* gh.runGraphQL(PR_REVIEW_THREAD_COUNTS_QUERY, {
|
|
412
|
+
...variables,
|
|
413
|
+
after: pageInfo.endCursor,
|
|
414
|
+
})) as PrReviewTriageSummaryPage;
|
|
415
|
+
const pullRequest = response.repository.pullRequest;
|
|
416
|
+
countThreads(pullRequest.reviewThreads.nodes);
|
|
417
|
+
pageInfo = pullRequest.reviewThreads.pageInfo;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const checks = yield* gh
|
|
421
|
+
.runGhJson<ReadonlyArray<{ readonly name: string; readonly bucket: string }>>([
|
|
422
|
+
"pr",
|
|
423
|
+
"checks",
|
|
424
|
+
String(pr),
|
|
425
|
+
"--repo",
|
|
426
|
+
repoSlug(repo),
|
|
427
|
+
"--json",
|
|
428
|
+
"name,bucket",
|
|
429
|
+
])
|
|
430
|
+
.pipe(
|
|
431
|
+
Effect.catchTag("GitHubCommandError", (error) =>
|
|
432
|
+
/no checks reported/i.test(`${error.message}\n${error.stderr}`)
|
|
433
|
+
? Effect.succeed([])
|
|
434
|
+
: Effect.fail(error),
|
|
435
|
+
),
|
|
436
|
+
);
|
|
437
|
+
const reviewRequests = firstPage.reviewRequests.nodes.flatMap(({ requestedReviewer }) => {
|
|
438
|
+
if (requestedReviewer === null) return [];
|
|
439
|
+
const login = requestedReviewer.login ?? requestedReviewer.slug ?? requestedReviewer.name;
|
|
440
|
+
return login === undefined ? [] : [{ login }];
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
return {
|
|
444
|
+
info: {
|
|
445
|
+
number: firstPage.number,
|
|
446
|
+
title: firstPage.title,
|
|
447
|
+
state: firstPage.state,
|
|
448
|
+
isDraft: firstPage.isDraft,
|
|
449
|
+
baseRefName: firstPage.baseRefName,
|
|
450
|
+
reviewDecision: firstPage.reviewDecision ?? "",
|
|
451
|
+
mergeable: firstPage.mergeable,
|
|
452
|
+
reviewRequests,
|
|
453
|
+
},
|
|
454
|
+
summary: { unresolvedReviewThreadsCount, unrepliedReviewThreadsCount },
|
|
455
|
+
checks,
|
|
456
|
+
};
|
|
457
|
+
});
|
|
458
|
+
|
|
281
459
|
const movedHead = (pr: number) =>
|
|
282
460
|
new GitHubCommandError({
|
|
283
461
|
command: `gh-tool pr checks --pr ${pr}`,
|
|
@@ -6,7 +6,15 @@ import { cachedRead, ReadCache } from "./cache";
|
|
|
6
6
|
import { OPS } from "./classes";
|
|
7
7
|
import { repoSlug } from "./keys";
|
|
8
8
|
import { issueView, issueList, issueComments } from "./issues";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
prView,
|
|
11
|
+
prList,
|
|
12
|
+
prChecks,
|
|
13
|
+
prHead,
|
|
14
|
+
prBody,
|
|
15
|
+
checkSignal,
|
|
16
|
+
prReviewTriageSummary,
|
|
17
|
+
} from "./pulls";
|
|
10
18
|
import { prComments, prReviews, reviewThreads, lastHumanReviewer } from "./reviews";
|
|
11
19
|
import { reviewGuards } from "./review-guards";
|
|
12
20
|
import type { RepoRef, RunFilter } from "./keys";
|
|
@@ -375,6 +383,7 @@ export const reads = {
|
|
|
375
383
|
prView,
|
|
376
384
|
prList,
|
|
377
385
|
prChecks,
|
|
386
|
+
prReviewTriageSummary,
|
|
378
387
|
prHead,
|
|
379
388
|
prBody,
|
|
380
389
|
checkSignal,
|
|
@@ -87,11 +87,13 @@ export class FileStore {
|
|
|
87
87
|
private constructor(
|
|
88
88
|
readonly directory: string,
|
|
89
89
|
readonly identity: string,
|
|
90
|
+
private readonly contentionTimeoutMs: number,
|
|
90
91
|
) {}
|
|
91
92
|
|
|
92
93
|
static async open(
|
|
93
94
|
identity: string,
|
|
94
95
|
directory = process.env["GH_TOOL_CACHE_DIR"] ?? defaultCacheDirectory(),
|
|
96
|
+
options: { contentionTimeoutMs?: number } = {},
|
|
95
97
|
): Promise<FileStore> {
|
|
96
98
|
const uid = process.getuid?.();
|
|
97
99
|
if (uid === undefined) throw new Error("Cache ownership cannot be verified");
|
|
@@ -116,7 +118,11 @@ export class FileStore {
|
|
|
116
118
|
await checkDirectory(path);
|
|
117
119
|
}),
|
|
118
120
|
);
|
|
119
|
-
const store = new FileStore(
|
|
121
|
+
const store = new FileStore(
|
|
122
|
+
join(directory, "gh-read-v1"),
|
|
123
|
+
identity,
|
|
124
|
+
options.contentionTimeoutMs ?? 2000,
|
|
125
|
+
);
|
|
120
126
|
await mkdir(store.ghCacheDirectory, { recursive: true, mode: 0o700 });
|
|
121
127
|
await checkDirectory(store.ghCacheDirectory);
|
|
122
128
|
await store.readClock();
|
|
@@ -226,7 +232,7 @@ export class FileStore {
|
|
|
226
232
|
}
|
|
227
233
|
},
|
|
228
234
|
25,
|
|
229
|
-
|
|
235
|
+
this.contentionTimeoutMs,
|
|
230
236
|
);
|
|
231
237
|
try {
|
|
232
238
|
return await body();
|
package/src/k8s-tool/index.ts
CHANGED
package/src/k8s-tool/main.ts
CHANGED
|
@@ -457,7 +457,7 @@ const topCommand = Command.make(
|
|
|
457
457
|
|
|
458
458
|
const commandsCommand = makeSchemaCommand(() => mainCommand);
|
|
459
459
|
|
|
460
|
-
const mainCommand = Command.make("k8s-tool", {}).pipe(
|
|
460
|
+
export const mainCommand = Command.make("k8s-tool", {}).pipe(
|
|
461
461
|
Command.withDescription("Kubernetes CLI Tool for Coding Agents"),
|
|
462
462
|
Command.withSubcommands([
|
|
463
463
|
kubectlCommand,
|
|
@@ -486,6 +486,12 @@ const program = withRedactedOutput(withAudit("k8s", cli)).pipe(
|
|
|
486
486
|
Effect.tapCause(renderCauseToStderr),
|
|
487
487
|
);
|
|
488
488
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
489
|
+
export const runMain = () =>
|
|
490
|
+
BunRuntime.runMain(program, {
|
|
491
|
+
disableErrorReporting: true,
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
export const runProgram = (args: readonly string[]) =>
|
|
495
|
+
withRedactedOutput(
|
|
496
|
+
withAudit("k8s", Command.runWith(mainCommand, { version: VERSION, renderErrors: false })(args)),
|
|
497
|
+
).pipe(Effect.provide(MainLayer), Effect.tapCause(renderCauseToStderr));
|
package/src/logs-tool/index.ts
CHANGED
package/src/logs-tool/main.ts
CHANGED
|
@@ -221,7 +221,7 @@ const readCommand = Command.make(
|
|
|
221
221
|
|
|
222
222
|
const commandsCommand = makeSchemaCommand(() => mainCommand);
|
|
223
223
|
|
|
224
|
-
const mainCommand = Command.make("logs-tool", {}).pipe(
|
|
224
|
+
export const mainCommand = Command.make("logs-tool", {}).pipe(
|
|
225
225
|
Command.withDescription("Application Logs Tool for Coding Agents"),
|
|
226
226
|
Command.withSubcommands([listCommand, readCommand, commandsCommand]),
|
|
227
227
|
);
|
|
@@ -249,6 +249,15 @@ const program = withRedactedOutput(withAudit("logs", cli)).pipe(
|
|
|
249
249
|
Effect.tapCause(renderCauseToStderr),
|
|
250
250
|
);
|
|
251
251
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
252
|
+
export const runMain = () =>
|
|
253
|
+
BunRuntime.runMain(program, {
|
|
254
|
+
disableErrorReporting: true,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
export const runProgram = (args: readonly string[]) =>
|
|
258
|
+
withRedactedOutput(
|
|
259
|
+
withAudit(
|
|
260
|
+
"logs",
|
|
261
|
+
Command.runWith(mainCommand, { version: VERSION, renderErrors: false })(args),
|
|
262
|
+
),
|
|
263
|
+
).pipe(Effect.provide(MainLayer), Effect.tapCause(renderCauseToStderr));
|
|
@@ -16,7 +16,7 @@ import { traceCommand } from "./trace";
|
|
|
16
16
|
|
|
17
17
|
const commandsCommand = makeSchemaCommand(() => mainCommand);
|
|
18
18
|
|
|
19
|
-
const mainCommand = Command.make("observability-tool", {}).pipe(
|
|
19
|
+
export const mainCommand = Command.make("observability-tool", {}).pipe(
|
|
20
20
|
Command.withDescription(
|
|
21
21
|
"LGTM observability queries — Tempo traces, Loki logs, Prometheus metrics",
|
|
22
22
|
),
|
|
@@ -37,4 +37,12 @@ const program = withRedactedOutput(withAudit("observability", cli)).pipe(
|
|
|
37
37
|
Effect.tapCause(renderCauseToStderr),
|
|
38
38
|
);
|
|
39
39
|
|
|
40
|
-
BunRuntime.runMain(program, { disableErrorReporting: true });
|
|
40
|
+
export const runMain = () => BunRuntime.runMain(program, { disableErrorReporting: true });
|
|
41
|
+
|
|
42
|
+
export const runProgram = (args: readonly string[]) =>
|
|
43
|
+
withRedactedOutput(
|
|
44
|
+
withAudit(
|
|
45
|
+
"observability",
|
|
46
|
+
Command.runWith(mainCommand, { version: VERSION, renderErrors: false })(args),
|
|
47
|
+
),
|
|
48
|
+
).pipe(Effect.provide(MainLayer), Effect.tapCause(renderCauseToStderr));
|