@blogic-cz/agent-tools 0.14.50 → 0.14.53
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/package.json +1 -1
- package/src/db-tool/index.ts +84 -1
- package/src/gh-tool/pr/review.ts +10 -8
package/package.json
CHANGED
package/src/db-tool/index.ts
CHANGED
|
@@ -144,11 +144,94 @@ const envsCommand = Command.make(
|
|
|
144
144
|
Command.withDescription("List configured database environments and the default (no network)"),
|
|
145
145
|
);
|
|
146
146
|
|
|
147
|
+
const ACTIVITY_SQL = `SELECT pid, usename AS "user", state,
|
|
148
|
+
date_trunc('second', now() - xact_start) AS xact_age,
|
|
149
|
+
date_trunc('second', now() - query_start) AS query_age,
|
|
150
|
+
wait_event_type, wait_event, left(query, 200) AS query
|
|
151
|
+
FROM pg_stat_activity
|
|
152
|
+
WHERE pid <> pg_backend_pid() AND state IS NOT NULL
|
|
153
|
+
ORDER BY xact_start ASC NULLS LAST`;
|
|
154
|
+
|
|
155
|
+
const LOCKS_SQL = `SELECT blocking.pid AS blocking_pid, blocking.usename AS blocking_user,
|
|
156
|
+
left(blocking.query, 150) AS blocking_query,
|
|
157
|
+
blocked.pid AS blocked_pid, blocked.usename AS blocked_user,
|
|
158
|
+
left(blocked.query, 150) AS blocked_query
|
|
159
|
+
FROM pg_stat_activity blocked
|
|
160
|
+
JOIN pg_stat_activity blocking ON blocking.pid = ANY(pg_blocking_pids(blocked.pid))
|
|
161
|
+
ORDER BY blocking.pid, blocked.pid`;
|
|
162
|
+
|
|
163
|
+
const GRANTS_SQL = `SELECT grantee, table_schema AS schema, 'table' AS kind, table_name AS object,
|
|
164
|
+
string_agg(privilege_type, ', ' ORDER BY privilege_type) AS privileges
|
|
165
|
+
FROM information_schema.role_table_grants
|
|
166
|
+
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
|
|
167
|
+
GROUP BY grantee, table_schema, table_name
|
|
168
|
+
UNION ALL
|
|
169
|
+
SELECT grantee, object_schema AS schema, 'sequence' AS kind, object_name AS object,
|
|
170
|
+
string_agg(privilege_type, ', ' ORDER BY privilege_type) AS privileges
|
|
171
|
+
FROM information_schema.role_usage_grants
|
|
172
|
+
WHERE object_type = 'SEQUENCE' AND object_schema NOT IN ('pg_catalog', 'information_schema')
|
|
173
|
+
GROUP BY grantee, object_schema, object_name
|
|
174
|
+
ORDER BY grantee, schema, kind, object`;
|
|
175
|
+
|
|
176
|
+
const makeDiagnosticCommand = (name: string, description: string, sql: string) =>
|
|
177
|
+
Command.make(
|
|
178
|
+
name,
|
|
179
|
+
{
|
|
180
|
+
env: Flag.optional(Flag.string("env")).pipe(
|
|
181
|
+
Flag.withDescription(
|
|
182
|
+
"Target database environment name (e.g. local, test, prod). Falls back to defaultEnvironment in config.",
|
|
183
|
+
),
|
|
184
|
+
),
|
|
185
|
+
limit: Flag.optional(Flag.integer("limit")).pipe(
|
|
186
|
+
Flag.withDescription("Max rows to return (default 50). Use 0 for no cap."),
|
|
187
|
+
),
|
|
188
|
+
format: formatOption,
|
|
189
|
+
profile: Flag.optional(Flag.string("profile")).pipe(
|
|
190
|
+
Flag.withDescription(
|
|
191
|
+
"Database profile name from agent-tools.json5 (if multiple configured)",
|
|
192
|
+
),
|
|
193
|
+
),
|
|
194
|
+
},
|
|
195
|
+
({ env, limit, format }) =>
|
|
196
|
+
Effect.gen(function* () {
|
|
197
|
+
const resolvedEnv = yield* resolveEnv(env);
|
|
198
|
+
const db = yield* DbService;
|
|
199
|
+
const result = yield* db.executeQuery(resolvedEnv, sql, Option.getOrUndefined(limit));
|
|
200
|
+
yield* Console.log(formatOutput(result, format));
|
|
201
|
+
}),
|
|
202
|
+
).pipe(Command.withDescription(description));
|
|
203
|
+
|
|
204
|
+
const activityCommand = makeDiagnosticCommand(
|
|
205
|
+
"activity",
|
|
206
|
+
"Show live sessions from pg_stat_activity (state, transaction/query age, wait event), longest-running first",
|
|
207
|
+
ACTIVITY_SQL,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const locksCommand = makeDiagnosticCommand(
|
|
211
|
+
"locks",
|
|
212
|
+
"Show blocking chains (blocker -> blocked) from pg_blocking_pids + pg_stat_activity",
|
|
213
|
+
LOCKS_SQL,
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const grantsCommand = makeDiagnosticCommand(
|
|
217
|
+
"grants",
|
|
218
|
+
"Show per-role table/sequence privileges by schema (excludes system schemas)",
|
|
219
|
+
GRANTS_SQL,
|
|
220
|
+
);
|
|
221
|
+
|
|
147
222
|
const commandsCommand = makeSchemaCommand(() => mainCommand);
|
|
148
223
|
|
|
149
224
|
const mainCommand = Command.make("db-tool", {}).pipe(
|
|
150
225
|
Command.withDescription("Database Query Tool for Coding Agents"),
|
|
151
|
-
Command.withSubcommands([
|
|
226
|
+
Command.withSubcommands([
|
|
227
|
+
sqlCommand,
|
|
228
|
+
schemaCommand,
|
|
229
|
+
activityCommand,
|
|
230
|
+
locksCommand,
|
|
231
|
+
grantsCommand,
|
|
232
|
+
envsCommand,
|
|
233
|
+
commandsCommand,
|
|
234
|
+
]),
|
|
152
235
|
);
|
|
153
236
|
|
|
154
237
|
const cli = Command.run(mainCommand, {
|
package/src/gh-tool/pr/review.ts
CHANGED
|
@@ -437,14 +437,16 @@ export const fetchReviews = Effect.fn("pr.fetchReviews")(function* (
|
|
|
437
437
|
"Failed to parse response",
|
|
438
438
|
);
|
|
439
439
|
|
|
440
|
-
let reviews: PullRequestReview[] = raw
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
440
|
+
let reviews: PullRequestReview[] = raw
|
|
441
|
+
.map((review) => ({
|
|
442
|
+
id: review.id,
|
|
443
|
+
author: review.user?.login ?? "unknown",
|
|
444
|
+
state: review.state,
|
|
445
|
+
body: review.body ?? "",
|
|
446
|
+
submittedAt: (review.submitted_at ?? null) as IsoTimestamp | null,
|
|
447
|
+
url: review.html_url,
|
|
448
|
+
}))
|
|
449
|
+
.filter((review) => !(review.state === "COMMENTED" && review.body.trim() === ""));
|
|
448
450
|
|
|
449
451
|
if (author !== null) {
|
|
450
452
|
const authorFilter = author.toLowerCase();
|