@verbatra/sdk 0.9.1 → 0.9.3
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/index.cjs +119 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -13
- package/dist/index.d.ts +38 -13
- package/dist/index.js +120 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Anthropic from '@anthropic-ai/sdk';
|
|
3
|
-
import { Interactions } from '@google/genai';
|
|
4
3
|
import OpenAI from 'openai';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -236,12 +235,22 @@ interface TranslationProvider {
|
|
|
236
235
|
type AnthropicModel = Anthropic.Messages.Model;
|
|
237
236
|
|
|
238
237
|
/**
|
|
239
|
-
* The Gemini authoring model type
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
|
|
244
|
-
|
|
238
|
+
* The Gemini authoring model type. Unlike the sibling Anthropic and OpenAI model types, this
|
|
239
|
+
* union is hand-maintained rather than re-exported from `@google/genai`: every entry point of
|
|
240
|
+
* that package's `.d.ts` carries an unconditional top-level import of
|
|
241
|
+
* `@modelcontextprotocol/sdk/client/index.js`, an optional peer dependency it does not install.
|
|
242
|
+
* Re-exporting any type from that package, including its model union, drags that import into
|
|
243
|
+
* this package's own published types and breaks `tsc --noEmit` with `skipLibCheck: false` for
|
|
244
|
+
* any consumer who has not separately installed the MCP SDK. Keeping this list literal avoids
|
|
245
|
+
* that transitive dependency entirely.
|
|
246
|
+
*
|
|
247
|
+
* It is an open union (`(string & {})` at the end), so unknown or newly released model IDs are
|
|
248
|
+
* still accepted. Type-only: it informs editor completions and is never validated at runtime,
|
|
249
|
+
* where the schema stays `z.string().min(1)`. The list is current as of `@google/genai` 2.17.1
|
|
250
|
+
* and does not update automatically; refresh it by hand when adopting a newer SDK version that
|
|
251
|
+
* adds models worth completing on.
|
|
252
|
+
*/
|
|
253
|
+
type GeminiModel = "gemini-2.5-flash" | "gemini-2.5-pro" | "gemma-4-26b-a4b-it" | "gemma-4-31b-it" | "gemini-flash-latest" | "gemini-flash-lite-latest" | "gemini-pro-latest" | "gemini-2.5-flash-lite" | "gemini-2.5-flash-image" | "gemini-3-flash-preview" | "gemini-3.1-pro-preview" | "gemini-3.1-pro-preview-customtools" | "gemini-3.1-flash-lite" | "gemini-3-pro-image" | "nano-banana-pro-preview" | "gemini-3.1-flash-image" | "gemini-3.5-flash" | "gemini-3.6-flash" | "gemini-3.7-flash" | "lyria-3-clip-preview" | "lyria-3-pro-preview" | "gemini-robotics-er-1.6-preview" | "gemini-robotics-er-2-preview" | (string & {});
|
|
245
254
|
|
|
246
255
|
/**
|
|
247
256
|
* The OpenAI authoring model type, sourced from the OpenAI SDK's published chat-model union
|
|
@@ -795,8 +804,8 @@ interface LoadConfigOptions {
|
|
|
795
804
|
*/
|
|
796
805
|
type ConfigSource = {
|
|
797
806
|
/**
|
|
798
|
-
* `search` means cosmiconfig found the file by walking up from the working directory
|
|
799
|
-
* `explicit` means the caller named it through `configPath`.
|
|
807
|
+
* `search` means cosmiconfig found the file by walking up from the working directory, up to
|
|
808
|
+
* the nearest `.git` directory; `explicit` means the caller named it through `configPath`.
|
|
800
809
|
*/
|
|
801
810
|
readonly kind: "search" | "explicit";
|
|
802
811
|
/** The absolute path of the config file that was loaded. */
|
|
@@ -821,12 +830,26 @@ interface LoadedConfig {
|
|
|
821
830
|
*
|
|
822
831
|
* Resolution order is: an explicit `configOverride`, then an explicit `configPath`, then a
|
|
823
832
|
* cosmiconfig search upward from `cwd` across `verbatra.config.ts`, the `.verbatrarc` family, and a
|
|
824
|
-
* `verbatra` property in `package.json`.
|
|
825
|
-
* a
|
|
833
|
+
* `verbatra` property in `package.json`. The upward search stops at the nearest ancestor directory
|
|
834
|
+
* containing a `.git` entry; if none is found, it stops at the user's home directory when that is an
|
|
835
|
+
* ancestor of `cwd`, and otherwise it does not search above `cwd` at all, so a nested workspace
|
|
836
|
+
* package finds a config at its monorepo root without wandering above it, and a project outside the
|
|
837
|
+
* home directory tree (a CI checkout, for instance) never triggers an unbounded walk to the
|
|
838
|
+
* filesystem root. A config file outside that directory chain, including cosmiconfig's own OS-level
|
|
839
|
+
* global config directory, is never used, even though the underlying search strategy checks it; it is
|
|
840
|
+
* treated the same as no config found. A `configPath` that does not exist is an error rather than a
|
|
841
|
+
* fallback to searching, so a typo in a path never silently loads a different project's config.
|
|
826
842
|
*
|
|
827
843
|
* A glossary given as a path is read and validated here, so the returned config always carries a
|
|
828
844
|
* resolved term map.
|
|
829
845
|
*
|
|
846
|
+
* A `verbatra.config.ts` file is transpiled and loaded through jiti. When it imports `@verbatra/sdk`
|
|
847
|
+
* or `@verbatra/cli`, those bare specifiers are aliased to the package that is actually running this
|
|
848
|
+
* function, so the import resolves to the running version even when a different, conflicting version
|
|
849
|
+
* of either package also happens to be reachable from the config file's own location. A package is
|
|
850
|
+
* only aliased when its own entry point can be resolved from the running code; otherwise the import
|
|
851
|
+
* falls back to jiti's ordinary bare-specifier resolution, unchanged from before this behavior existed.
|
|
852
|
+
*
|
|
830
853
|
* @param options - Where and how to look for the config.
|
|
831
854
|
* @returns The validated config with its config-source and glossary provenance.
|
|
832
855
|
*
|
|
@@ -841,8 +864,10 @@ declare function loadConfigWithMeta(options?: LoadConfigOptions): Promise<Loaded
|
|
|
841
864
|
* pass the result to {@link translate}, {@link check}, {@link diff}, or any other entry point.
|
|
842
865
|
*
|
|
843
866
|
* Resolution order is an explicit `configOverride`, then an explicit `configPath`, then a
|
|
844
|
-
* cosmiconfig search upward from `cwd
|
|
845
|
-
*
|
|
867
|
+
* cosmiconfig search upward from `cwd`, stopping at the nearest ancestor `.git` directory, or
|
|
868
|
+
* failing that, the user's home directory when it is an ancestor of `cwd`, or failing that, `cwd`
|
|
869
|
+
* itself. A glossary declared as a file path is read and validated here, so the returned
|
|
870
|
+
* {@link VerbatraConfig} always carries a resolved term map.
|
|
846
871
|
*
|
|
847
872
|
* Reach for {@link loadConfigWithMeta} when you also need to know which file was loaded.
|
|
848
873
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Anthropic from '@anthropic-ai/sdk';
|
|
3
|
-
import { Interactions } from '@google/genai';
|
|
4
3
|
import OpenAI from 'openai';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -236,12 +235,22 @@ interface TranslationProvider {
|
|
|
236
235
|
type AnthropicModel = Anthropic.Messages.Model;
|
|
237
236
|
|
|
238
237
|
/**
|
|
239
|
-
* The Gemini authoring model type
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
|
|
244
|
-
|
|
238
|
+
* The Gemini authoring model type. Unlike the sibling Anthropic and OpenAI model types, this
|
|
239
|
+
* union is hand-maintained rather than re-exported from `@google/genai`: every entry point of
|
|
240
|
+
* that package's `.d.ts` carries an unconditional top-level import of
|
|
241
|
+
* `@modelcontextprotocol/sdk/client/index.js`, an optional peer dependency it does not install.
|
|
242
|
+
* Re-exporting any type from that package, including its model union, drags that import into
|
|
243
|
+
* this package's own published types and breaks `tsc --noEmit` with `skipLibCheck: false` for
|
|
244
|
+
* any consumer who has not separately installed the MCP SDK. Keeping this list literal avoids
|
|
245
|
+
* that transitive dependency entirely.
|
|
246
|
+
*
|
|
247
|
+
* It is an open union (`(string & {})` at the end), so unknown or newly released model IDs are
|
|
248
|
+
* still accepted. Type-only: it informs editor completions and is never validated at runtime,
|
|
249
|
+
* where the schema stays `z.string().min(1)`. The list is current as of `@google/genai` 2.17.1
|
|
250
|
+
* and does not update automatically; refresh it by hand when adopting a newer SDK version that
|
|
251
|
+
* adds models worth completing on.
|
|
252
|
+
*/
|
|
253
|
+
type GeminiModel = "gemini-2.5-flash" | "gemini-2.5-pro" | "gemma-4-26b-a4b-it" | "gemma-4-31b-it" | "gemini-flash-latest" | "gemini-flash-lite-latest" | "gemini-pro-latest" | "gemini-2.5-flash-lite" | "gemini-2.5-flash-image" | "gemini-3-flash-preview" | "gemini-3.1-pro-preview" | "gemini-3.1-pro-preview-customtools" | "gemini-3.1-flash-lite" | "gemini-3-pro-image" | "nano-banana-pro-preview" | "gemini-3.1-flash-image" | "gemini-3.5-flash" | "gemini-3.6-flash" | "gemini-3.7-flash" | "lyria-3-clip-preview" | "lyria-3-pro-preview" | "gemini-robotics-er-1.6-preview" | "gemini-robotics-er-2-preview" | (string & {});
|
|
245
254
|
|
|
246
255
|
/**
|
|
247
256
|
* The OpenAI authoring model type, sourced from the OpenAI SDK's published chat-model union
|
|
@@ -795,8 +804,8 @@ interface LoadConfigOptions {
|
|
|
795
804
|
*/
|
|
796
805
|
type ConfigSource = {
|
|
797
806
|
/**
|
|
798
|
-
* `search` means cosmiconfig found the file by walking up from the working directory
|
|
799
|
-
* `explicit` means the caller named it through `configPath`.
|
|
807
|
+
* `search` means cosmiconfig found the file by walking up from the working directory, up to
|
|
808
|
+
* the nearest `.git` directory; `explicit` means the caller named it through `configPath`.
|
|
800
809
|
*/
|
|
801
810
|
readonly kind: "search" | "explicit";
|
|
802
811
|
/** The absolute path of the config file that was loaded. */
|
|
@@ -821,12 +830,26 @@ interface LoadedConfig {
|
|
|
821
830
|
*
|
|
822
831
|
* Resolution order is: an explicit `configOverride`, then an explicit `configPath`, then a
|
|
823
832
|
* cosmiconfig search upward from `cwd` across `verbatra.config.ts`, the `.verbatrarc` family, and a
|
|
824
|
-
* `verbatra` property in `package.json`.
|
|
825
|
-
* a
|
|
833
|
+
* `verbatra` property in `package.json`. The upward search stops at the nearest ancestor directory
|
|
834
|
+
* containing a `.git` entry; if none is found, it stops at the user's home directory when that is an
|
|
835
|
+
* ancestor of `cwd`, and otherwise it does not search above `cwd` at all, so a nested workspace
|
|
836
|
+
* package finds a config at its monorepo root without wandering above it, and a project outside the
|
|
837
|
+
* home directory tree (a CI checkout, for instance) never triggers an unbounded walk to the
|
|
838
|
+
* filesystem root. A config file outside that directory chain, including cosmiconfig's own OS-level
|
|
839
|
+
* global config directory, is never used, even though the underlying search strategy checks it; it is
|
|
840
|
+
* treated the same as no config found. A `configPath` that does not exist is an error rather than a
|
|
841
|
+
* fallback to searching, so a typo in a path never silently loads a different project's config.
|
|
826
842
|
*
|
|
827
843
|
* A glossary given as a path is read and validated here, so the returned config always carries a
|
|
828
844
|
* resolved term map.
|
|
829
845
|
*
|
|
846
|
+
* A `verbatra.config.ts` file is transpiled and loaded through jiti. When it imports `@verbatra/sdk`
|
|
847
|
+
* or `@verbatra/cli`, those bare specifiers are aliased to the package that is actually running this
|
|
848
|
+
* function, so the import resolves to the running version even when a different, conflicting version
|
|
849
|
+
* of either package also happens to be reachable from the config file's own location. A package is
|
|
850
|
+
* only aliased when its own entry point can be resolved from the running code; otherwise the import
|
|
851
|
+
* falls back to jiti's ordinary bare-specifier resolution, unchanged from before this behavior existed.
|
|
852
|
+
*
|
|
830
853
|
* @param options - Where and how to look for the config.
|
|
831
854
|
* @returns The validated config with its config-source and glossary provenance.
|
|
832
855
|
*
|
|
@@ -841,8 +864,10 @@ declare function loadConfigWithMeta(options?: LoadConfigOptions): Promise<Loaded
|
|
|
841
864
|
* pass the result to {@link translate}, {@link check}, {@link diff}, or any other entry point.
|
|
842
865
|
*
|
|
843
866
|
* Resolution order is an explicit `configOverride`, then an explicit `configPath`, then a
|
|
844
|
-
* cosmiconfig search upward from `cwd
|
|
845
|
-
*
|
|
867
|
+
* cosmiconfig search upward from `cwd`, stopping at the nearest ancestor `.git` directory, or
|
|
868
|
+
* failing that, the user's home directory when it is an ancestor of `cwd`, or failing that, `cwd`
|
|
869
|
+
* itself. A glossary declared as a file path is read and validated here, so the returned
|
|
870
|
+
* {@link VerbatraConfig} always carries a resolved term map.
|
|
846
871
|
*
|
|
847
872
|
* Reach for {@link loadConfigWithMeta} when you also need to know which file was loaded.
|
|
848
873
|
*
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,13 @@ import { dirname, resolve, join, basename, relative, isAbsolute, sep, extname }
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { randomUUID } from 'crypto';
|
|
4
4
|
import { mkdir, rm, access, open, writeFile, rename } from 'fs/promises';
|
|
5
|
-
import { existsSync } from 'fs';
|
|
5
|
+
import { existsSync, readFileSync } from 'fs';
|
|
6
|
+
import { homedir } from 'os';
|
|
6
7
|
import { cosmiconfig } from 'cosmiconfig';
|
|
7
8
|
import { TypeScriptLoader } from 'cosmiconfig-typescript-loader';
|
|
9
|
+
import { createRequire } from 'module';
|
|
8
10
|
import Anthropic from '@anthropic-ai/sdk';
|
|
9
11
|
import * as deepl from 'deepl-node';
|
|
10
|
-
import { createRequire } from 'module';
|
|
11
12
|
import log from 'loglevel';
|
|
12
13
|
import { GoogleGenAI } from '@google/genai';
|
|
13
14
|
import OpenAI from 'openai';
|
|
@@ -500,6 +501,67 @@ async function updateGlossaryTerm(input, deps = {}) {
|
|
|
500
501
|
return entries;
|
|
501
502
|
});
|
|
502
503
|
}
|
|
504
|
+
var SELF_ALIASED_PACKAGES = ["@verbatra/sdk", "@verbatra/cli"];
|
|
505
|
+
var ENTRY_CONDITION_ORDER = ["import", "node", "default", "require"];
|
|
506
|
+
function resolvePathsFromRunningModule(packageName) {
|
|
507
|
+
return createRequire(import.meta.url).resolve.paths(packageName) ?? [];
|
|
508
|
+
}
|
|
509
|
+
function readPackageManifestFromDisk(packageRoot) {
|
|
510
|
+
try {
|
|
511
|
+
return JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
512
|
+
} catch {
|
|
513
|
+
return void 0;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
var defaultModuleAliasDeps = {
|
|
517
|
+
resolvePaths: resolvePathsFromRunningModule,
|
|
518
|
+
readPackageManifest: readPackageManifestFromDisk
|
|
519
|
+
};
|
|
520
|
+
function resolveRootExportPath(manifest) {
|
|
521
|
+
const exportsField = manifest.exports;
|
|
522
|
+
if (typeof exportsField === "string") {
|
|
523
|
+
return exportsField;
|
|
524
|
+
}
|
|
525
|
+
if (typeof exportsField === "object" && exportsField !== null) {
|
|
526
|
+
const rootExport = exportsField["."];
|
|
527
|
+
if (typeof rootExport === "string") {
|
|
528
|
+
return rootExport;
|
|
529
|
+
}
|
|
530
|
+
if (typeof rootExport === "object" && rootExport !== null) {
|
|
531
|
+
for (const condition of ENTRY_CONDITION_ORDER) {
|
|
532
|
+
const candidate = rootExport[condition];
|
|
533
|
+
if (typeof candidate === "string") {
|
|
534
|
+
return candidate;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
return manifest.main;
|
|
540
|
+
}
|
|
541
|
+
function findPackageEntry(packageName, deps) {
|
|
542
|
+
for (const candidateDir of deps.resolvePaths(packageName)) {
|
|
543
|
+
const packageRoot = join(candidateDir, packageName);
|
|
544
|
+
const manifest = deps.readPackageManifest(packageRoot);
|
|
545
|
+
if (manifest === void 0) {
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
const relativeEntry = resolveRootExportPath(manifest);
|
|
549
|
+
if (relativeEntry !== void 0) {
|
|
550
|
+
return join(packageRoot, relativeEntry);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return void 0;
|
|
554
|
+
}
|
|
555
|
+
function resolveSelfPackageAliases(deps = defaultModuleAliasDeps) {
|
|
556
|
+
const aliases = {};
|
|
557
|
+
for (const packageName of SELF_ALIASED_PACKAGES) {
|
|
558
|
+
const entry = findPackageEntry(packageName, deps);
|
|
559
|
+
if (entry !== void 0) {
|
|
560
|
+
aliases[packageName] = entry;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return aliases;
|
|
564
|
+
}
|
|
503
565
|
async function resolveGlossary(glossary, baseDir, fs) {
|
|
504
566
|
if (glossary === void 0) {
|
|
505
567
|
return { glossary: void 0, provenance: { source: "none" } };
|
|
@@ -2164,6 +2226,50 @@ var SEARCH_PLACES = [
|
|
|
2164
2226
|
`${MODULE_NAME}.config.cjs`,
|
|
2165
2227
|
`${MODULE_NAME}.config.ts`
|
|
2166
2228
|
];
|
|
2229
|
+
function isAncestorOrSelf(ancestor, startDir) {
|
|
2230
|
+
const target = resolve(ancestor);
|
|
2231
|
+
let dir = resolve(startDir);
|
|
2232
|
+
while (true) {
|
|
2233
|
+
if (dir === target) {
|
|
2234
|
+
return true;
|
|
2235
|
+
}
|
|
2236
|
+
const parent = dirname(dir);
|
|
2237
|
+
if (parent === dir) {
|
|
2238
|
+
return false;
|
|
2239
|
+
}
|
|
2240
|
+
dir = parent;
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
function findSearchStopDir(startDir) {
|
|
2244
|
+
let dir = resolve(startDir);
|
|
2245
|
+
while (true) {
|
|
2246
|
+
if (existsSync(join(dir, ".git"))) {
|
|
2247
|
+
return dir;
|
|
2248
|
+
}
|
|
2249
|
+
const parent = dirname(dir);
|
|
2250
|
+
if (parent === dir) {
|
|
2251
|
+
break;
|
|
2252
|
+
}
|
|
2253
|
+
dir = parent;
|
|
2254
|
+
}
|
|
2255
|
+
const home = resolve(homedir());
|
|
2256
|
+
return isAncestorOrSelf(home, startDir) ? home : resolve(startDir);
|
|
2257
|
+
}
|
|
2258
|
+
function collectSearchChain(startDir, stopDir) {
|
|
2259
|
+
const stop = resolve(stopDir);
|
|
2260
|
+
const chain = /* @__PURE__ */ new Set();
|
|
2261
|
+
let dir = resolve(startDir);
|
|
2262
|
+
while (dir !== stop) {
|
|
2263
|
+
chain.add(dir);
|
|
2264
|
+
const parent = dirname(dir);
|
|
2265
|
+
if (parent === dir) {
|
|
2266
|
+
break;
|
|
2267
|
+
}
|
|
2268
|
+
dir = parent;
|
|
2269
|
+
}
|
|
2270
|
+
chain.add(stop);
|
|
2271
|
+
return chain;
|
|
2272
|
+
}
|
|
2167
2273
|
function formatIssues(error) {
|
|
2168
2274
|
return error.issues.map((issue) => {
|
|
2169
2275
|
const path = issue.path.join(".");
|
|
@@ -2213,20 +2319,30 @@ async function loadConfigWithMeta(options = {}) {
|
|
|
2213
2319
|
const { config: config2, glossary: glossary2 } = await finalizeConfig(parsed2, options.cwd ?? process.cwd(), fs);
|
|
2214
2320
|
return { config: config2, source: { kind: "override" }, glossary: glossary2 };
|
|
2215
2321
|
}
|
|
2322
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2323
|
+
const stopDir = findSearchStopDir(cwd);
|
|
2216
2324
|
const explorer = cosmiconfig(MODULE_NAME, {
|
|
2217
2325
|
searchPlaces: SEARCH_PLACES,
|
|
2218
|
-
loaders: { ".ts": TypeScriptLoader() }
|
|
2326
|
+
loaders: { ".ts": TypeScriptLoader({ alias: resolveSelfPackageAliases() }) },
|
|
2327
|
+
searchStrategy: "global",
|
|
2328
|
+
stopDir
|
|
2219
2329
|
});
|
|
2220
2330
|
if (options.configPath !== void 0) {
|
|
2221
2331
|
return loadExplicitWithMeta(explorer, options.configPath, options.cwd, fs);
|
|
2222
2332
|
}
|
|
2223
2333
|
let result;
|
|
2224
2334
|
try {
|
|
2225
|
-
result = await explorer.search(
|
|
2335
|
+
result = await explorer.search(cwd);
|
|
2226
2336
|
} catch (error) {
|
|
2227
2337
|
const detail = errorMessage(error);
|
|
2228
2338
|
throw new SdkError("CONFIG_INVALID", `Failed to load the verbatra configuration: ${detail}`);
|
|
2229
2339
|
}
|
|
2340
|
+
if (result !== null && result.isEmpty !== true) {
|
|
2341
|
+
const resultDir = dirname(resolve(result.filepath));
|
|
2342
|
+
if (!collectSearchChain(cwd, stopDir).has(resultDir)) {
|
|
2343
|
+
result = null;
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2230
2346
|
if (result === null || result.isEmpty === true) {
|
|
2231
2347
|
throw new SdkError(
|
|
2232
2348
|
"CONFIG_NOT_FOUND",
|