@langapi/mcp-server 1.1.1 → 1.2.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.
@@ -1,10 +1,39 @@
1
1
  /**
2
2
  * Utilities for detecting and preserving JSON file formatting
3
3
  */
4
+ /**
5
+ * Detect if a JSON object uses flat keys (keys containing dots at root level)
6
+ */
7
+ function detectKeyStructure(data) {
8
+ for (const key of Object.keys(data)) {
9
+ // If any root-level key contains a dot and maps to a non-object value, it's flat
10
+ if (key.includes(".") && typeof data[key] !== "object") {
11
+ return "flat";
12
+ }
13
+ }
14
+ return "nested";
15
+ }
16
+ /**
17
+ * Get all keys from an object recursively (flattened with dot notation)
18
+ */
19
+ function getAllKeysInOrder(obj, prefix = "") {
20
+ const keys = [];
21
+ for (const key of Object.keys(obj)) {
22
+ const fullKey = prefix ? `${prefix}.${key}` : key;
23
+ const value = obj[key];
24
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
25
+ keys.push(...getAllKeysInOrder(value, fullKey));
26
+ }
27
+ else {
28
+ keys.push(fullKey);
29
+ }
30
+ }
31
+ return keys;
32
+ }
4
33
  /**
5
34
  * Detect the formatting used in a JSON file
6
35
  */
7
- export function detectJsonFormat(content) {
36
+ export function detectJsonFormat(content, data) {
8
37
  const lines = content.split("\n");
9
38
  // Detect indent by finding first indented line
10
39
  let indent = " "; // default: 2 spaces
@@ -25,13 +54,89 @@ export function detectJsonFormat(content) {
25
54
  }
26
55
  // Detect trailing newline
27
56
  const trailingNewline = content.endsWith("\n");
28
- return { indent, trailingNewline };
57
+ // Detect key structure and order if data is provided
58
+ let keyStructure = "nested";
59
+ let keyOrder;
60
+ if (data) {
61
+ keyStructure = detectKeyStructure(data);
62
+ keyOrder = keyStructure === "flat"
63
+ ? Object.keys(data) // For flat files, use root keys directly
64
+ : getAllKeysInOrder(data); // For nested, flatten to get all keys
65
+ }
66
+ return { indent, trailingNewline, keyStructure, keyOrder };
67
+ }
68
+ /**
69
+ * Reorder object keys to match the specified order
70
+ */
71
+ function reorderKeys(obj, keyOrder, isFlat) {
72
+ if (isFlat) {
73
+ // For flat structure, just reorder root keys
74
+ const result = {};
75
+ // First add keys in order
76
+ for (const key of keyOrder) {
77
+ if (key in obj) {
78
+ result[key] = obj[key];
79
+ }
80
+ }
81
+ // Then add any new keys not in the original order
82
+ for (const key of Object.keys(obj)) {
83
+ if (!(key in result)) {
84
+ result[key] = obj[key];
85
+ }
86
+ }
87
+ return result;
88
+ }
89
+ else {
90
+ // For nested structure, recursively reorder
91
+ return reorderNestedKeys(obj, keyOrder);
92
+ }
93
+ }
94
+ /**
95
+ * Recursively reorder nested object keys based on flattened key order
96
+ */
97
+ function reorderNestedKeys(obj, flatKeyOrder) {
98
+ // Build a map of prefix -> order index (use first occurrence)
99
+ const prefixOrder = new Map();
100
+ for (let i = 0; i < flatKeyOrder.length; i++) {
101
+ const key = flatKeyOrder[i];
102
+ const parts = key.split(".");
103
+ // Add all prefixes to maintain hierarchy order
104
+ for (let j = 1; j <= parts.length; j++) {
105
+ const prefix = parts.slice(0, j).join(".");
106
+ if (!prefixOrder.has(prefix)) {
107
+ prefixOrder.set(prefix, i);
108
+ }
109
+ }
110
+ }
111
+ // Sort root keys by their order in the flattened key list
112
+ const sortedKeys = Object.keys(obj).sort((a, b) => {
113
+ const orderA = prefixOrder.get(a) ?? Infinity;
114
+ const orderB = prefixOrder.get(b) ?? Infinity;
115
+ return orderA - orderB;
116
+ });
117
+ const result = {};
118
+ for (const key of sortedKeys) {
119
+ const value = obj[key];
120
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
121
+ // Recursively reorder nested objects
122
+ result[key] = reorderNestedKeys(value, flatKeyOrder.map((k) => k.startsWith(key + ".") ? k.slice(key.length + 1) : k));
123
+ }
124
+ else {
125
+ result[key] = value;
126
+ }
127
+ }
128
+ return result;
29
129
  }
30
130
  /**
31
131
  * Stringify a JSON object with specific formatting
32
132
  */
33
133
  export function stringifyWithFormat(obj, format) {
34
- let result = JSON.stringify(obj, null, format.indent);
134
+ let objToStringify = obj;
135
+ // Reorder keys if keyOrder is provided
136
+ if (format.keyOrder && typeof obj === "object" && obj !== null && !Array.isArray(obj)) {
137
+ objToStringify = reorderKeys(obj, format.keyOrder, format.keyStructure === "flat");
138
+ }
139
+ let result = JSON.stringify(objToStringify, null, format.indent);
35
140
  if (format.trailingNewline && !result.endsWith("\n")) {
36
141
  result += "\n";
37
142
  }
@@ -46,7 +151,7 @@ export function parseJsonWithFormat(content) {
46
151
  if (typeof data !== "object" || data === null || Array.isArray(data)) {
47
152
  return null;
48
153
  }
49
- const format = detectJsonFormat(content);
154
+ const format = detectJsonFormat(content, data);
50
155
  return { data: data, format };
51
156
  }
52
157
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"format-preserve.js","sourceRoot":"","sources":["../../src/utils/format-preserve.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,+CAA+C;IAC/C,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,oBAAoB;IACvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5B,+BAA+B;YAC/B,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACN,+BAA+B;gBAC/B,MAAM,GAAG,UAAU,CAAC;YACtB,CAAC;YACD,MAAM;QACR,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE/C,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAY,EACZ,MAAkB;IAElB,IAAI,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAEtD,IAAI,MAAM,CAAC,eAAe,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,IAAI,CAAC;IACjB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IAIjD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACrE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,IAA+B,EAAE,MAAM,EAAE,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"format-preserve.js","sourceRoot":"","sources":["../../src/utils/format-preserve.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@langapi/mcp-server",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for LangAPI - AI-powered translation management for i18n projects",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,23 +0,0 @@
1
- /**
2
- * get_diff MCP Tool
3
- * Compare source locale against sync cache to identify new/changed/removed keys
4
- */
5
- import { z } from "zod";
6
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
- declare const GetDiffSchema: z.ZodObject<{
8
- source_lang: z.ZodString;
9
- project_path: z.ZodOptional<z.ZodString>;
10
- }, "strip", z.ZodTypeAny, {
11
- source_lang: string;
12
- project_path?: string | undefined;
13
- }, {
14
- source_lang: string;
15
- project_path?: string | undefined;
16
- }>;
17
- export type GetDiffInput = z.infer<typeof GetDiffSchema>;
18
- /**
19
- * Register the get_diff tool with the MCP server
20
- */
21
- export declare function registerGetDiff(server: McpServer): void;
22
- export {};
23
- //# sourceMappingURL=get-diff.d.ts.map
@@ -1,88 +0,0 @@
1
- /**
2
- * get_diff MCP Tool
3
- * Compare source locale against sync cache to identify new/changed/removed keys
4
- */
5
- import { z } from "zod";
6
- import { readFile } from "fs/promises";
7
- import { detectLocales } from "../locale-detection/index.js";
8
- import { flattenJson, parseJsonSafe } from "../utils/json-parser.js";
9
- import { languageCodeSchema } from "../utils/validation.js";
10
- import { readSyncCache, getFullDiff } from "../utils/sync-cache.js";
11
- // Input schema
12
- const GetDiffSchema = z.object({
13
- source_lang: languageCodeSchema.describe("Source language code (e.g., 'en', 'pt-BR')"),
14
- project_path: z
15
- .string()
16
- .optional()
17
- .describe("Root path of the project. Defaults to current working directory."),
18
- });
19
- /**
20
- * Register the get_diff tool with the MCP server
21
- */
22
- export function registerGetDiff(server) {
23
- server.tool("get_diff", "Compare current source locale content against the sync cache to see what's new, changed, unchanged, or removed since the last sync.", GetDiffSchema.shape, async (args) => {
24
- const input = GetDiffSchema.parse(args);
25
- const projectPath = input.project_path || process.cwd();
26
- // Detect locales
27
- const detection = await detectLocales(projectPath, false);
28
- // Find source locale
29
- const sourceLocale = detection.locales.find((l) => l.lang === input.source_lang);
30
- if (!sourceLocale) {
31
- const output = {
32
- success: false,
33
- error: {
34
- code: "SOURCE_NOT_FOUND",
35
- message: `Source language '${input.source_lang}' not found in project`,
36
- },
37
- };
38
- return {
39
- content: [{ type: "text", text: JSON.stringify(output, null, 2) }],
40
- };
41
- }
42
- // Read and parse source files
43
- const sourceContent = {};
44
- for (const file of sourceLocale.files) {
45
- const content = await readFile(file.path, "utf-8");
46
- const parsed = parseJsonSafe(content);
47
- if (parsed) {
48
- Object.assign(sourceContent, parsed);
49
- }
50
- }
51
- // Flatten source content
52
- const flatContent = flattenJson(sourceContent);
53
- // Read cache
54
- const cachedContent = await readSyncCache(projectPath, input.source_lang);
55
- // Get full diff
56
- const diff = getFullDiff(flatContent, cachedContent);
57
- const totalCached = cachedContent ? Object.keys(cachedContent).length : 0;
58
- const output = {
59
- success: true,
60
- cache_exists: cachedContent !== null,
61
- diff: {
62
- new_keys: diff.newKeys,
63
- changed_keys: diff.changedKeys.map((c) => ({
64
- key: c.key,
65
- old_value: c.oldValue,
66
- new_value: c.newValue,
67
- })),
68
- unchanged_keys: diff.unchangedKeys,
69
- removed_keys: diff.removedKeys,
70
- },
71
- summary: {
72
- total_current: flatContent.length,
73
- total_cached: totalCached,
74
- new_count: diff.newKeys.length,
75
- changed_count: diff.changedKeys.length,
76
- unchanged_count: diff.unchangedKeys.length,
77
- removed_count: diff.removedKeys.length,
78
- },
79
- message: cachedContent
80
- ? `Found ${diff.newKeys.length} new, ${diff.changedKeys.length} changed, ${diff.unchangedKeys.length} unchanged, ${diff.removedKeys.length} removed keys.`
81
- : `No sync cache found. All ${flatContent.length} keys will be treated as new on first sync.`,
82
- };
83
- return {
84
- content: [{ type: "text", text: JSON.stringify(output, null, 2) }],
85
- };
86
- });
87
- }
88
- //# sourceMappingURL=get-diff.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"get-diff.js","sourceRoot":"","sources":["../../src/tools/get-diff.ts"],"names":[],"mappings":"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"}
@@ -1,40 +0,0 @@
1
- /**
2
- * Sync cache utility for delta detection
3
- * Stores previous source content to detect new/changed keys
4
- */
5
- import type { KeyValue } from "../api/types.js";
6
- interface SyncDelta {
7
- newKeys: string[];
8
- changedKeys: string[];
9
- unchangedKeys: string[];
10
- contentToSync: KeyValue[];
11
- }
12
- export interface KeyChange {
13
- key: string;
14
- oldValue: string;
15
- newValue: string;
16
- }
17
- export interface FullDiff {
18
- newKeys: string[];
19
- changedKeys: KeyChange[];
20
- unchangedKeys: string[];
21
- removedKeys: string[];
22
- }
23
- /**
24
- * Read the sync cache for a project
25
- */
26
- export declare function readSyncCache(projectPath: string, sourceLang: string): Promise<Record<string, string> | null>;
27
- /**
28
- * Write the sync cache after a successful sync
29
- */
30
- export declare function writeSyncCache(projectPath: string, sourceLang: string, content: KeyValue[]): Promise<void>;
31
- /**
32
- * Detect delta between current content and cached content
33
- */
34
- export declare function detectLocalDelta(currentContent: KeyValue[], cachedContent: Record<string, string> | null): SyncDelta;
35
- /**
36
- * Get full diff including removed keys
37
- */
38
- export declare function getFullDiff(currentContent: KeyValue[], cachedContent: Record<string, string> | null): FullDiff;
39
- export {};
40
- //# sourceMappingURL=sync-cache.d.ts.map
@@ -1,140 +0,0 @@
1
- /**
2
- * Sync cache utility for delta detection
3
- * Stores previous source content to detect new/changed keys
4
- */
5
- import { readFile, writeFile, mkdir } from "fs/promises";
6
- import { join, dirname } from "path";
7
- const CACHE_DIR = ".langapi";
8
- const CACHE_FILE = "sync-cache.json";
9
- function getCachePath(projectPath) {
10
- return join(projectPath, CACHE_DIR, CACHE_FILE);
11
- }
12
- /**
13
- * Read the sync cache for a project
14
- */
15
- export async function readSyncCache(projectPath, sourceLang) {
16
- const cachePath = getCachePath(projectPath);
17
- try {
18
- const content = await readFile(cachePath, "utf-8");
19
- const cache = JSON.parse(content);
20
- // Only return cache if source language matches
21
- if (cache.sourceLang === sourceLang) {
22
- return cache.content;
23
- }
24
- return null;
25
- }
26
- catch {
27
- // Cache doesn't exist or is invalid
28
- return null;
29
- }
30
- }
31
- /**
32
- * Write the sync cache after a successful sync
33
- */
34
- export async function writeSyncCache(projectPath, sourceLang, content) {
35
- const cachePath = getCachePath(projectPath);
36
- // Ensure cache directory exists
37
- await mkdir(dirname(cachePath), { recursive: true });
38
- // Convert KeyValue array to map
39
- const contentMap = {};
40
- for (const item of content) {
41
- contentMap[item.key] = item.value;
42
- }
43
- const cache = {
44
- sourceLang,
45
- content: contentMap,
46
- lastSync: new Date().toISOString(),
47
- };
48
- await writeFile(cachePath, JSON.stringify(cache, null, 2), "utf-8");
49
- }
50
- /**
51
- * Detect delta between current content and cached content
52
- */
53
- export function detectLocalDelta(currentContent, cachedContent) {
54
- const newKeys = [];
55
- const changedKeys = [];
56
- const unchangedKeys = [];
57
- const contentToSync = [];
58
- // If no cache, all keys are new
59
- if (!cachedContent) {
60
- return {
61
- newKeys: currentContent.map((c) => c.key),
62
- changedKeys: [],
63
- unchangedKeys: [],
64
- contentToSync: currentContent,
65
- };
66
- }
67
- for (const item of currentContent) {
68
- const cachedValue = cachedContent[item.key];
69
- if (cachedValue === undefined) {
70
- // Key doesn't exist in cache - it's new
71
- newKeys.push(item.key);
72
- contentToSync.push(item);
73
- }
74
- else if (cachedValue !== item.value) {
75
- // Key exists but value changed
76
- changedKeys.push(item.key);
77
- contentToSync.push(item);
78
- }
79
- else {
80
- // Key exists and value is the same - unchanged
81
- unchangedKeys.push(item.key);
82
- }
83
- }
84
- return {
85
- newKeys,
86
- changedKeys,
87
- unchangedKeys,
88
- contentToSync,
89
- };
90
- }
91
- /**
92
- * Get full diff including removed keys
93
- */
94
- export function getFullDiff(currentContent, cachedContent) {
95
- const newKeys = [];
96
- const changedKeys = [];
97
- const unchangedKeys = [];
98
- const removedKeys = [];
99
- // If no cache, all keys are new
100
- if (!cachedContent) {
101
- return {
102
- newKeys: currentContent.map((c) => c.key),
103
- changedKeys: [],
104
- unchangedKeys: [],
105
- removedKeys: [],
106
- };
107
- }
108
- // Track which cached keys we've seen
109
- const seenCachedKeys = new Set();
110
- for (const item of currentContent) {
111
- const cachedValue = cachedContent[item.key];
112
- seenCachedKeys.add(item.key);
113
- if (cachedValue === undefined) {
114
- newKeys.push(item.key);
115
- }
116
- else if (cachedValue !== item.value) {
117
- changedKeys.push({
118
- key: item.key,
119
- oldValue: cachedValue,
120
- newValue: item.value,
121
- });
122
- }
123
- else {
124
- unchangedKeys.push(item.key);
125
- }
126
- }
127
- // Find removed keys (in cache but not in current)
128
- for (const key of Object.keys(cachedContent)) {
129
- if (!seenCachedKeys.has(key)) {
130
- removedKeys.push(key);
131
- }
132
- }
133
- return {
134
- newKeys,
135
- changedKeys,
136
- unchangedKeys,
137
- removedKeys,
138
- };
139
- }
140
- //# sourceMappingURL=sync-cache.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sync-cache.js","sourceRoot":"","sources":["../../src/utils/sync-cache.ts"],"names":[],"mappings":"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"}