@deepagents/text2sql 1.0.0 → 2.1.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 +36 -10
- package/dist/bin/sql.js +182 -86
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ npm install mysql2 # MySQL / MariaDB
|
|
|
26
26
|
npm install @google-cloud/bigquery # BigQuery
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
Requires Node.js LTS
|
|
29
|
+
Requires Node.js LTS
|
|
30
30
|
|
|
31
31
|
## Quick Start
|
|
32
32
|
|
|
@@ -95,10 +95,9 @@ Text2SQL works with any model provider supported by the [Vercel AI SDK](https://
|
|
|
95
95
|
|
|
96
96
|
## Building a Conversational Agent
|
|
97
97
|
|
|
98
|
-
`Text2Sql`
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
`@deepagents/context`:
|
|
98
|
+
`Text2Sql` owns SQL generation and schema indexing, but you own the chat loop.
|
|
99
|
+
Build the agent by composing a `ContextEngine`, a sandbox, and `agent` +
|
|
100
|
+
`chat` from `@deepagents/context`:
|
|
102
101
|
|
|
103
102
|
```typescript
|
|
104
103
|
import {
|
|
@@ -123,6 +122,14 @@ const context = new ContextEngine({
|
|
|
123
122
|
|
|
124
123
|
const sandbox = await createContainerTool({
|
|
125
124
|
installers: [npm('@deepagents/text2sql', { ensureRuntime: true })],
|
|
125
|
+
volumes: [
|
|
126
|
+
{
|
|
127
|
+
type: 'bind',
|
|
128
|
+
hostPath: process.cwd(),
|
|
129
|
+
containerPath: '/workspace',
|
|
130
|
+
readOnly: true,
|
|
131
|
+
},
|
|
132
|
+
],
|
|
126
133
|
env: {
|
|
127
134
|
TEXT2SQL_ADAPTERS: '/workspace/text2sql-adapters.ts',
|
|
128
135
|
},
|
|
@@ -154,6 +161,10 @@ for await (const chunk of stream) {
|
|
|
154
161
|
}
|
|
155
162
|
```
|
|
156
163
|
|
|
164
|
+
The `/workspace/text2sql-adapters.ts` module must exist in the sandbox and
|
|
165
|
+
default-export your adapter map. Mount your project into `/workspace` (as above)
|
|
166
|
+
or upload/write that module before you call `sql index` or `chat()`.
|
|
167
|
+
|
|
157
168
|
`instructions()` returns the SQL-flavored system fragments (policies, workflows,
|
|
158
169
|
clarifications, style guides) — spread them into `context.set()` alongside the
|
|
159
170
|
schema fragments returned by `sql index`. Add or replace them with your
|
|
@@ -162,11 +173,25 @@ own domain fragments as needed.
|
|
|
162
173
|
## Advanced: SQL CLI in Sandboxes
|
|
163
174
|
|
|
164
175
|
`sql validate <db> "..."` and `sql run <db> "..."` are real commands from the
|
|
165
|
-
`@deepagents/text2sql` package. `sql index
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
176
|
+
`@deepagents/text2sql` package. `sql index` writes schema fragments plus
|
|
177
|
+
progress events for chat setup, indexing all configured adapters by default
|
|
178
|
+
(same as `--all`) unless adapter names are provided.
|
|
179
|
+
|
|
180
|
+
Install the package inside the sandbox and set `TEXT2SQL_ADAPTERS` to a module
|
|
181
|
+
whose default export is `Record<string, Adapter>`. Missing `sql` means the
|
|
182
|
+
sandbox was not prepared correctly.
|
|
183
|
+
|
|
184
|
+
`sql index` output details:
|
|
185
|
+
|
|
186
|
+
- `stdout`: JSON manifest with `fragmentsPath`, `eventsPath`, adapters, and
|
|
187
|
+
fragment count.
|
|
188
|
+
- `--verbose pretty` or `--verbose json`: mirrors progress events to `stderr`
|
|
189
|
+
while keeping `stdout` as the manifest.
|
|
190
|
+
- `--out-dir <path>`: writes artifacts under that path (default:
|
|
191
|
+
`$TEXT2SQL_OUT_DIR` or `./sql`).
|
|
192
|
+
|
|
193
|
+
Set `TEXT2SQL_INDEX_VERSION` to manage cache invalidation across runs. Cache
|
|
194
|
+
keys are `index-<version>-<adapter>`, so bump the version when schema changes.
|
|
170
195
|
|
|
171
196
|
Spread `createSqlCommandHooks({ adapters })` into `createBashTool()` or
|
|
172
197
|
`createContainerTool()` for model-driven bash calls. The before hook preserves
|
|
@@ -339,6 +364,7 @@ Full documentation available at [januarylabs.github.io/deepagents](https://janua
|
|
|
339
364
|
|
|
340
365
|
- [Getting Started](https://januarylabs.github.io/deepagents/docs/text2sql/getting-started)
|
|
341
366
|
- [Generate SQL](https://januarylabs.github.io/deepagents/docs/text2sql/to-sql)
|
|
367
|
+
- [Agent + SQLite Store Recipe](https://januarylabs.github.io/deepagents/docs/text2sql/recipes/agent-sqlite-store)
|
|
342
368
|
- [Teach the System](https://januarylabs.github.io/deepagents/docs/text2sql/teach-the-system)
|
|
343
369
|
- [Build Conversations](https://januarylabs.github.io/deepagents/docs/text2sql/build-conversations)
|
|
344
370
|
- [Grounding](https://januarylabs.github.io/deepagents/docs/text2sql/grounding)
|
package/dist/bin/sql.js
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
import { cac } from "cac";
|
|
5
5
|
|
|
6
6
|
// packages/text2sql/src/bin/command.ts
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
var OUT_DIR_OPTION = {
|
|
9
|
+
flag: "--out-dir <path>",
|
|
10
|
+
description: "Output directory (default: $TEXT2SQL_OUT_DIR or ./sql)"
|
|
11
|
+
};
|
|
12
|
+
function resolveOutputDir(ctx, options) {
|
|
13
|
+
const explicit = typeof options.outDir === "string" ? options.outDir : void 0;
|
|
14
|
+
return path.resolve(ctx.cwd, explicit ?? ctx.env.TEXT2SQL_OUT_DIR ?? "./sql");
|
|
15
|
+
}
|
|
7
16
|
var CommandError = class extends Error {
|
|
8
17
|
command;
|
|
9
18
|
exitCode;
|
|
@@ -13,15 +22,11 @@ var CommandError = class extends Error {
|
|
|
13
22
|
this.command = command;
|
|
14
23
|
this.exitCode = exitCode;
|
|
15
24
|
}
|
|
16
|
-
toResult() {
|
|
17
|
-
return {
|
|
18
|
-
stdout: "",
|
|
19
|
-
stderr: `sql ${this.command}: ${this.message}
|
|
20
|
-
`,
|
|
21
|
-
exitCode: this.exitCode
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
25
|
};
|
|
26
|
+
function renderCommandError(error, stderr) {
|
|
27
|
+
stderr.write(`sql ${error.command}: ${error.message}
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
25
30
|
function errorMessage(error) {
|
|
26
31
|
return error instanceof Error ? error.message : String(error);
|
|
27
32
|
}
|
|
@@ -73,9 +78,15 @@ var SqlQueryCommand = class extends SqlCommand {
|
|
|
73
78
|
};
|
|
74
79
|
|
|
75
80
|
// packages/text2sql/src/bin/commands/index.ts
|
|
76
|
-
import {
|
|
77
|
-
import {
|
|
78
|
-
|
|
81
|
+
import { constants, createWriteStream } from "node:fs";
|
|
82
|
+
import {
|
|
83
|
+
mkdir,
|
|
84
|
+
open,
|
|
85
|
+
stat,
|
|
86
|
+
writeFile as writeFile2
|
|
87
|
+
} from "node:fs/promises";
|
|
88
|
+
import * as path3 from "node:path";
|
|
89
|
+
import { finished } from "node:stream/promises";
|
|
79
90
|
import { v7 } from "uuid";
|
|
80
91
|
|
|
81
92
|
// packages/text2sql/src/lib/adapter-index.ts
|
|
@@ -186,12 +197,12 @@ import { createHash } from "node:crypto";
|
|
|
186
197
|
import { existsSync } from "node:fs";
|
|
187
198
|
import { readFile, writeFile } from "node:fs/promises";
|
|
188
199
|
import { tmpdir } from "node:os";
|
|
189
|
-
import
|
|
200
|
+
import path2 from "node:path";
|
|
190
201
|
var FileCache = class {
|
|
191
202
|
path;
|
|
192
203
|
constructor(watermark, extension = ".txt") {
|
|
193
204
|
const hash = createHash("md5").update(watermark).digest("hex");
|
|
194
|
-
this.path =
|
|
205
|
+
this.path = path2.join(tmpdir(), `text2sql-${hash}${extension}`);
|
|
195
206
|
}
|
|
196
207
|
async get() {
|
|
197
208
|
if (existsSync(this.path)) {
|
|
@@ -369,7 +380,7 @@ var AdapterIndexer = class {
|
|
|
369
380
|
return configured;
|
|
370
381
|
}
|
|
371
382
|
if (this.#version) {
|
|
372
|
-
return `
|
|
383
|
+
return `index-${this.#version}-${name}`;
|
|
373
384
|
}
|
|
374
385
|
return void 0;
|
|
375
386
|
}
|
|
@@ -391,44 +402,82 @@ function errorMessage2(error) {
|
|
|
391
402
|
return error instanceof Error ? error.message : String(error);
|
|
392
403
|
}
|
|
393
404
|
|
|
405
|
+
// packages/text2sql/src/bin/commands/indexing-formatter.ts
|
|
406
|
+
var REDUNDANT_MESSAGE_TYPES = /* @__PURE__ */ new Set([
|
|
407
|
+
"adapter:start",
|
|
408
|
+
"adapter:end"
|
|
409
|
+
]);
|
|
410
|
+
function formatPretty(event) {
|
|
411
|
+
const head = event.adapter ? `${event.type} ${event.adapter}` : event.type;
|
|
412
|
+
const parts = [`[${head}]`];
|
|
413
|
+
if (event.phase) parts.push(`phase=${event.phase}`);
|
|
414
|
+
if (event.table) parts.push(`table=${event.table}`);
|
|
415
|
+
if (typeof event.current === "number" && typeof event.total === "number" && !event.type.endsWith(":start")) {
|
|
416
|
+
parts.push(`${event.current}/${event.total}`);
|
|
417
|
+
}
|
|
418
|
+
if (event.cached) parts.push("cached");
|
|
419
|
+
if (!REDUNDANT_MESSAGE_TYPES.has(event.type)) parts.push(event.message);
|
|
420
|
+
return parts.join(" ");
|
|
421
|
+
}
|
|
422
|
+
|
|
394
423
|
// packages/text2sql/src/bin/commands/index.ts
|
|
395
424
|
var IndexCommand = class extends SqlCommand {
|
|
396
425
|
name = "index";
|
|
397
426
|
description = "Index adapter schemas and write context artifacts";
|
|
398
427
|
args = "[...adapters]";
|
|
399
|
-
usage = "[--all] [adapter ...]";
|
|
400
|
-
helpDisplay = "[--all] [adapter ...]";
|
|
428
|
+
usage = "[--all] [--verbose [pretty|json]] [adapter ...]";
|
|
429
|
+
helpDisplay = "[--all] [--verbose] [adapter ...]";
|
|
401
430
|
options = [
|
|
402
|
-
{ flag: "--all", description: "Index all adapters (default)" }
|
|
431
|
+
{ flag: "--all", description: "Index all adapters (default)" },
|
|
432
|
+
{
|
|
433
|
+
flag: "-v, --verbose [format]",
|
|
434
|
+
description: "Mirror progress events to stderr (format: pretty (default) | json)"
|
|
435
|
+
},
|
|
436
|
+
OUT_DIR_OPTION
|
|
403
437
|
];
|
|
404
438
|
async execute(ctx, args, options) {
|
|
405
439
|
const adapterNames = args[0] ?? [];
|
|
406
440
|
const requested = options.all ? [] : adapterNames;
|
|
407
441
|
const names = this.resolveNames(ctx.adapters, requested);
|
|
408
|
-
const
|
|
442
|
+
const verbose = this.resolveVerbose(options.verbose);
|
|
443
|
+
const outputDir = resolveOutputDir(ctx, options);
|
|
409
444
|
const id = v7();
|
|
410
|
-
const fragmentsPath =
|
|
411
|
-
const
|
|
445
|
+
const fragmentsPath = path3.join(outputDir, `index-${id}.json`);
|
|
446
|
+
const explicitEventsPath = resolveExplicitEventsPath(ctx);
|
|
447
|
+
const eventsPath = explicitEventsPath ?? path3.join(outputDir, `index-${id}.events.ndjson`);
|
|
412
448
|
try {
|
|
413
449
|
await mkdir(outputDir, { recursive: true });
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
onProgress: (event) => appendProgressEvent(eventsPath, event)
|
|
419
|
-
});
|
|
420
|
-
await writeFile2(fragmentsPath, JSON.stringify(fragments, null, 2));
|
|
421
|
-
const manifest = {
|
|
422
|
-
fragmentsPath,
|
|
450
|
+
if (explicitEventsPath) {
|
|
451
|
+
await mkdir(path3.dirname(explicitEventsPath), { recursive: true });
|
|
452
|
+
}
|
|
453
|
+
const eventsStream = await openEventsWriter(
|
|
423
454
|
eventsPath,
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
455
|
+
explicitEventsPath,
|
|
456
|
+
ctx.stderr
|
|
457
|
+
);
|
|
458
|
+
try {
|
|
459
|
+
const indexer = new AdapterIndexer({
|
|
460
|
+
adapters: ctx.adapters,
|
|
461
|
+
version: ctx.env.TEXT2SQL_INDEX_VERSION
|
|
462
|
+
});
|
|
463
|
+
const fragments = await indexer.index({
|
|
464
|
+
adapterNames: names,
|
|
465
|
+
onProgress: createProgressHandler(eventsStream, verbose, ctx.stderr)
|
|
466
|
+
});
|
|
467
|
+
await writeFile2(fragmentsPath, JSON.stringify(fragments, null, 2));
|
|
468
|
+
const manifest = {
|
|
469
|
+
fragmentsPath,
|
|
470
|
+
eventsPath,
|
|
471
|
+
adapters: names,
|
|
472
|
+
fragments: countSchemaFragments(fragments)
|
|
473
|
+
};
|
|
474
|
+
ctx.stdout.write(JSON.stringify(manifest, null, 2) + "\n");
|
|
475
|
+
return 0;
|
|
476
|
+
} finally {
|
|
477
|
+
eventsStream.end();
|
|
478
|
+
await finished(eventsStream).catch(() => {
|
|
479
|
+
});
|
|
480
|
+
}
|
|
432
481
|
} catch (error) {
|
|
433
482
|
this.fail(errorMessage(error));
|
|
434
483
|
}
|
|
@@ -444,15 +493,82 @@ var IndexCommand = class extends SqlCommand {
|
|
|
444
493
|
}
|
|
445
494
|
return names;
|
|
446
495
|
}
|
|
496
|
+
resolveVerbose(value) {
|
|
497
|
+
if (value === void 0 || value === false) return null;
|
|
498
|
+
if (value === true || value === "" || value === "pretty") return "pretty";
|
|
499
|
+
if (value === "json") return "json";
|
|
500
|
+
this.fail(
|
|
501
|
+
`invalid --verbose value "${String(value)}". Expected "pretty" or "json".`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
447
504
|
};
|
|
448
|
-
function
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
JSON.stringify(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
505
|
+
function createProgressHandler(eventsStream, verbose, stderr) {
|
|
506
|
+
return (event) => {
|
|
507
|
+
const stamped = { ...event, timestampMs: event.timestampMs ?? Date.now() };
|
|
508
|
+
const json = JSON.stringify(stamped) + "\n";
|
|
509
|
+
eventsStream.write(json);
|
|
510
|
+
if (verbose === "pretty") stderr.write(formatPretty(stamped) + "\n");
|
|
511
|
+
else if (verbose === "json") stderr.write(json);
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
function resolveExplicitEventsPath(ctx) {
|
|
515
|
+
const explicit = ctx.env.TEXT2SQL_INDEX_EVENTS_PATH?.trim();
|
|
516
|
+
return explicit ? path3.resolve(ctx.cwd, explicit) : null;
|
|
517
|
+
}
|
|
518
|
+
async function openEventsWriter(eventsPath, explicitEventsPath, stderr) {
|
|
519
|
+
const probe = explicitEventsPath ? await probeFifoWriter(explicitEventsPath, stderr) : null;
|
|
520
|
+
const stream = createWriteStream(eventsPath, {
|
|
521
|
+
flags: "a",
|
|
522
|
+
encoding: "utf-8"
|
|
523
|
+
});
|
|
524
|
+
try {
|
|
525
|
+
await waitForOpen(stream);
|
|
526
|
+
return stream;
|
|
527
|
+
} catch (err) {
|
|
528
|
+
stream.destroy();
|
|
529
|
+
throw err;
|
|
530
|
+
} finally {
|
|
531
|
+
await probe?.close().catch(() => {
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
async function probeFifoWriter(eventsPath, stderr) {
|
|
536
|
+
let stats;
|
|
537
|
+
try {
|
|
538
|
+
stats = await stat(eventsPath);
|
|
539
|
+
} catch (err) {
|
|
540
|
+
if (err.code === "ENOENT") return null;
|
|
541
|
+
throw err;
|
|
542
|
+
}
|
|
543
|
+
if (!stats.isFIFO()) return null;
|
|
544
|
+
try {
|
|
545
|
+
return await open(eventsPath, constants.O_WRONLY | constants.O_NONBLOCK);
|
|
546
|
+
} catch (err) {
|
|
547
|
+
if (err.code === "ENXIO") {
|
|
548
|
+
stderr.write(`sql index: waiting for reader on FIFO ${eventsPath}...
|
|
549
|
+
`);
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
throw err;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function waitForOpen(stream) {
|
|
556
|
+
return new Promise((resolve4, reject) => {
|
|
557
|
+
if (!stream.pending) {
|
|
558
|
+
resolve4();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const onOpen = () => {
|
|
562
|
+
stream.off("error", onError);
|
|
563
|
+
resolve4();
|
|
564
|
+
};
|
|
565
|
+
const onError = (err) => {
|
|
566
|
+
stream.off("open", onOpen);
|
|
567
|
+
reject(err);
|
|
568
|
+
};
|
|
569
|
+
stream.once("open", onOpen);
|
|
570
|
+
stream.once("error", onError);
|
|
571
|
+
});
|
|
456
572
|
}
|
|
457
573
|
function countSchemaFragments(fragments) {
|
|
458
574
|
return fragments.reduce((count, adapterFragment) => {
|
|
@@ -468,21 +584,16 @@ function dedupe(values) {
|
|
|
468
584
|
|
|
469
585
|
// packages/text2sql/src/bin/commands/run.ts
|
|
470
586
|
import { mkdir as mkdir2, writeFile as writeFile3 } from "node:fs/promises";
|
|
471
|
-
import * as
|
|
587
|
+
import * as path4 from "node:path";
|
|
472
588
|
import { v7 as v72 } from "uuid";
|
|
473
589
|
var RunCommand = class extends SqlQueryCommand {
|
|
474
590
|
name = "run";
|
|
475
591
|
description = "Execute query against <db> and store results";
|
|
476
592
|
usage = '<db> "SELECT ..." [--out-dir <path>]';
|
|
477
593
|
helpDisplay = '<db> "SELECT ..."';
|
|
478
|
-
options = [
|
|
479
|
-
{
|
|
480
|
-
flag: "--out-dir <path>",
|
|
481
|
-
description: "Directory for `sql run` result files (default: $TEXT2SQL_OUT_DIR or ./sql)"
|
|
482
|
-
}
|
|
483
|
-
];
|
|
594
|
+
options = [OUT_DIR_OPTION];
|
|
484
595
|
async afterValidation(ctx, adapter, sql, options) {
|
|
485
|
-
const outputDir =
|
|
596
|
+
const outputDir = resolveOutputDir(ctx, options);
|
|
486
597
|
let rows;
|
|
487
598
|
try {
|
|
488
599
|
rows = await adapter.execute(sql);
|
|
@@ -492,7 +603,7 @@ var RunCommand = class extends SqlQueryCommand {
|
|
|
492
603
|
if (!Array.isArray(rows)) {
|
|
493
604
|
this.fail("adapter.execute must return an array of rows");
|
|
494
605
|
}
|
|
495
|
-
const outPath =
|
|
606
|
+
const outPath = path4.join(outputDir, `${v72()}.json`);
|
|
496
607
|
try {
|
|
497
608
|
await mkdir2(outputDir, { recursive: true });
|
|
498
609
|
await writeFile3(outPath, JSON.stringify(rows, null, 2));
|
|
@@ -500,22 +611,13 @@ var RunCommand = class extends SqlQueryCommand {
|
|
|
500
611
|
this.fail(errorMessage(error));
|
|
501
612
|
}
|
|
502
613
|
const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
exitCode: 0
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
resolveOutputDir(ctx, options) {
|
|
514
|
-
const explicit = typeof options.outDir === "string" ? options.outDir : void 0;
|
|
515
|
-
return path3.resolve(
|
|
516
|
-
ctx.cwd,
|
|
517
|
-
explicit ?? ctx.env.TEXT2SQL_OUT_DIR ?? "./sql"
|
|
518
|
-
);
|
|
614
|
+
ctx.stdout.write(`results stored in ${outPath}
|
|
615
|
+
`);
|
|
616
|
+
ctx.stdout.write(`columns: ${columns.join(", ") || "(none)"}
|
|
617
|
+
`);
|
|
618
|
+
ctx.stdout.write(`rows: ${rows.length}
|
|
619
|
+
`);
|
|
620
|
+
return 0;
|
|
519
621
|
}
|
|
520
622
|
};
|
|
521
623
|
|
|
@@ -525,8 +627,9 @@ var ValidateCommand = class extends SqlQueryCommand {
|
|
|
525
627
|
description = "Validate query syntax against <db>";
|
|
526
628
|
usage = '<db> "SELECT ..."';
|
|
527
629
|
helpDisplay = '<db> "SELECT ..."';
|
|
528
|
-
async afterValidation() {
|
|
529
|
-
|
|
630
|
+
async afterValidation(ctx) {
|
|
631
|
+
ctx.stdout.write("valid\n");
|
|
632
|
+
return 0;
|
|
530
633
|
}
|
|
531
634
|
};
|
|
532
635
|
|
|
@@ -603,7 +706,7 @@ cli.usage("<run|validate|index> ...").help(
|
|
|
603
706
|
for (const command of commands) {
|
|
604
707
|
registerCommand(cli, command);
|
|
605
708
|
}
|
|
606
|
-
process.
|
|
709
|
+
process.exitCode = await runCli();
|
|
607
710
|
async function runCli() {
|
|
608
711
|
try {
|
|
609
712
|
cli.parse(process.argv, { run: false });
|
|
@@ -645,7 +748,9 @@ async function runCommand(command, positional, options) {
|
|
|
645
748
|
ctx = {
|
|
646
749
|
adapters: await loadAdapters(),
|
|
647
750
|
cwd: process.cwd(),
|
|
648
|
-
env: process.env
|
|
751
|
+
env: process.env,
|
|
752
|
+
stdout: process.stdout,
|
|
753
|
+
stderr: process.stderr
|
|
649
754
|
};
|
|
650
755
|
} catch (error) {
|
|
651
756
|
process.stderr.write(`${errorMessage(error)}
|
|
@@ -653,12 +758,10 @@ async function runCommand(command, positional, options) {
|
|
|
653
758
|
return 2;
|
|
654
759
|
}
|
|
655
760
|
try {
|
|
656
|
-
|
|
657
|
-
writeCommandResult(result);
|
|
658
|
-
return result.exitCode;
|
|
761
|
+
return await command.execute(ctx, positional, options);
|
|
659
762
|
} catch (error) {
|
|
660
763
|
if (error instanceof CommandError) {
|
|
661
|
-
|
|
764
|
+
renderCommandError(error, process.stderr);
|
|
662
765
|
return error.exitCode;
|
|
663
766
|
}
|
|
664
767
|
throw error;
|
|
@@ -673,13 +776,6 @@ function rewriteCommandsHelp(body) {
|
|
|
673
776
|
);
|
|
674
777
|
}, body);
|
|
675
778
|
}
|
|
676
|
-
function writeCommandResult(result) {
|
|
677
|
-
if (result.stdout) process.stdout.write(result.stdout);
|
|
678
|
-
if (result.stderr) {
|
|
679
|
-
const out = result.stderr.endsWith("\n") ? result.stderr : result.stderr + "\n";
|
|
680
|
-
process.stderr.write(out);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
779
|
function writeCliError(error) {
|
|
684
780
|
if (error instanceof Error && error.name === "CACError") {
|
|
685
781
|
process.stderr.write(`sql: ${error.message}
|
|
@@ -688,7 +784,7 @@ function writeCliError(error) {
|
|
|
688
784
|
return 2;
|
|
689
785
|
}
|
|
690
786
|
if (error instanceof CommandError) {
|
|
691
|
-
|
|
787
|
+
renderCommandError(error, process.stderr);
|
|
692
788
|
return error.exitCode;
|
|
693
789
|
}
|
|
694
790
|
process.stderr.write(
|
package/dist/index.js
CHANGED