@blogic-cz/agent-tools 0.14.45 → 0.14.46

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blogic-cz/agent-tools",
3
- "version": "0.14.45",
3
+ "version": "0.14.46",
4
4
  "description": "CLI tools for AI coding agent workflows — GitHub, database, Kubernetes, Azure DevOps, logs, sessions, and audit",
5
5
  "keywords": [
6
6
  "agent",
@@ -64,16 +64,21 @@ const sqlCommand = Command.make(
64
64
  ),
65
65
  ),
66
66
  sql: Flag.string("sql").pipe(Flag.withDescription("SQL query to execute")),
67
+ limit: Flag.optional(Flag.integer("limit")).pipe(
68
+ Flag.withDescription(
69
+ "Max rows to return (default 50). Use 0 for no cap. Prefer a SQL LIMIT for large tables.",
70
+ ),
71
+ ),
67
72
  format: formatOption,
68
73
  profile: Flag.optional(Flag.string("profile")).pipe(
69
74
  Flag.withDescription("Database profile name from agent-tools.json5 (if multiple configured)"),
70
75
  ),
71
76
  },
72
- ({ env, sql, format }) =>
77
+ ({ env, sql, limit, format }) =>
73
78
  Effect.gen(function* () {
74
79
  const resolvedEnv = yield* resolveEnv(env);
75
80
  const db = yield* DbService;
76
- const result = yield* db.executeQuery(resolvedEnv, sql);
81
+ const result = yield* db.executeQuery(resolvedEnv, sql, Option.getOrUndefined(limit));
77
82
  yield* Console.log(formatOutput(result, format));
78
83
  }),
79
84
  ).pipe(Command.withDescription("Execute a SQL query"));
@@ -59,7 +59,11 @@ export { buildApiProbeArgs } from "#shared/k8s-probe";
59
59
  export class DbService extends Context.Service<
60
60
  DbService,
61
61
  {
62
- readonly executeQuery: (env: string, sql: string) => Effect.Effect<QueryResult, DbError>;
62
+ readonly executeQuery: (
63
+ env: string,
64
+ sql: string,
65
+ limit?: number,
66
+ ) => Effect.Effect<QueryResult, DbError>;
63
67
  readonly executeSchemaQuery: (
64
68
  env: string,
65
69
  mode: SchemaMode,
@@ -83,7 +87,8 @@ export class DbService extends Context.Service<
83
87
  environment: env,
84
88
  });
85
89
  return {
86
- executeQuery: (env: string, _sql: string) => Effect.fail(noConfigError(env)),
90
+ executeQuery: (env: string, _sql: string, _limit?: number) =>
91
+ Effect.fail(noConfigError(env)),
87
92
  executeSchemaQuery: (env: string, _mode: SchemaMode, _table?: string) =>
88
93
  Effect.fail(noConfigError(env)),
89
94
  };
@@ -468,6 +473,7 @@ export class DbService extends Context.Service<
468
473
  password: string,
469
474
  startTimeMs: number,
470
475
  applyTransform = false,
476
+ limit?: number,
471
477
  ) {
472
478
  const selectSql = sql.trim().replace(/;\s*$/, "");
473
479
  const wrappedSql = `SELECT json_agg(t) FROM (${selectSql}) t;`;
@@ -532,7 +538,7 @@ export class DbService extends Context.Service<
532
538
  });
533
539
 
534
540
  const transformed = applyTransform
535
- ? transformQueryResult(rawData)
541
+ ? transformQueryResult(rawData, limit)
536
542
  : {
537
543
  data: rawData,
538
544
  showing: rawData.length,
@@ -720,6 +726,7 @@ export class DbService extends Context.Service<
720
726
  const executeQuery = Effect.fn("DbService.executeQuery")(function* (
721
727
  env: string,
722
728
  sql: string,
729
+ limit?: number,
723
730
  ) {
724
731
  const config = yield* getConfigForEnv(env);
725
732
  const startTimeMs = yield* Clock.currentTimeMillis;
@@ -753,7 +760,7 @@ export class DbService extends Context.Service<
753
760
 
754
761
  const queryEffect = mutation
755
762
  ? executeMutationQuery(resolvedConfig, sql, password, Number(startTimeMs))
756
- : executeSelectQuery(resolvedConfig, sql, password, Number(startTimeMs), true);
763
+ : executeSelectQuery(resolvedConfig, sql, password, Number(startTimeMs), true, limit);
757
764
 
758
765
  return yield* runWithVpnPrerequisites(
759
766
  resolvedConfig.port,
@@ -22,12 +22,17 @@ function truncateValue(value: unknown): unknown {
22
22
  return `${value.slice(0, MAX_VALUE_LENGTH)}...`;
23
23
  }
24
24
 
25
- export function transformQueryResult(data: Record<string, unknown>[]): TransformResult {
25
+ export function transformQueryResult(
26
+ data: Record<string, unknown>[],
27
+ // limit 0 (or negative) means "no row cap".
28
+ limit: number = DEFAULT_ROW_LIMIT,
29
+ ): TransformResult {
26
30
  const withoutEmptyColumns = stripEmptyColumns(data);
27
31
  const truncatedValues = withoutEmptyColumns.map((record) =>
28
32
  Object.fromEntries(Object.entries(record).map(([key, value]) => [key, truncateValue(value)])),
29
33
  );
30
- const { rows, truncated, total, showing } = truncateRows(truncatedValues, DEFAULT_ROW_LIMIT);
34
+ const effectiveLimit = limit > 0 ? limit : Number.POSITIVE_INFINITY;
35
+ const { rows, truncated, total, showing } = truncateRows(truncatedValues, effectiveLimit);
31
36
 
32
37
  return {
33
38
  data: rows,