@systemdox/mcp-server 0.1.13 → 0.1.15
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/cli.js +39 -16
- package/dist/http.js +30 -16
- package/dist/index.js +30 -16
- package/dist/lib/config-links.d.ts +18 -0
- package/dist/lib/config-links.js +21 -0
- package/dist/lib/context-builder.js +8 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -246,6 +246,27 @@ var init_deprecation = __esm({
|
|
|
246
246
|
}
|
|
247
247
|
});
|
|
248
248
|
|
|
249
|
+
// src/lib/config-links.ts
|
|
250
|
+
async function workspaceBase(apiClient2) {
|
|
251
|
+
try {
|
|
252
|
+
const access = await apiClient2.get(
|
|
253
|
+
"/v1/docs/portal-access"
|
|
254
|
+
);
|
|
255
|
+
const slug = (access.host ?? "").split(".")[0];
|
|
256
|
+
return slug ? `https://${slug}.systemdox.com` : null;
|
|
257
|
+
} catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function configLink(path, base) {
|
|
262
|
+
return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
|
|
263
|
+
}
|
|
264
|
+
var init_config_links = __esm({
|
|
265
|
+
"src/lib/config-links.ts"() {
|
|
266
|
+
"use strict";
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
249
270
|
// src/tools/get-guardrails.ts
|
|
250
271
|
import { z } from "zod";
|
|
251
272
|
function registerGetGuardrails(server2, apiClient2) {
|
|
@@ -268,13 +289,9 @@ function registerGetGuardrails(server2, apiClient2) {
|
|
|
268
289
|
);
|
|
269
290
|
}
|
|
270
291
|
if (filtered.length === 0) {
|
|
292
|
+
const text2 = guardrails.length === 0 ? `No checks found. Add checks at ${configLink("/docs/guardrails", await workspaceBase(apiClient2))}` : `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`;
|
|
271
293
|
return {
|
|
272
|
-
content: [
|
|
273
|
-
{
|
|
274
|
-
type: "text",
|
|
275
|
-
text: `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`
|
|
276
|
-
}
|
|
277
|
-
]
|
|
294
|
+
content: [{ type: "text", text: text2 }]
|
|
278
295
|
};
|
|
279
296
|
}
|
|
280
297
|
const text = filtered.map(
|
|
@@ -331,6 +348,7 @@ var init_get_guardrails = __esm({
|
|
|
331
348
|
"use strict";
|
|
332
349
|
init_language();
|
|
333
350
|
init_deprecation();
|
|
351
|
+
init_config_links();
|
|
334
352
|
DESCRIPTION = "Retrieve SystemDox checks (banned patterns, required patterns, coding rules). Filter by language, category, or file path to get only relevant checks.";
|
|
335
353
|
inputSchema = () => ({
|
|
336
354
|
language: z.string().optional().describe(
|
|
@@ -559,7 +577,7 @@ function registerGetTechStack(server2, apiClient2) {
|
|
|
559
577
|
content: [
|
|
560
578
|
{
|
|
561
579
|
type: "text",
|
|
562
|
-
text:
|
|
580
|
+
text: `No tech stack entries configured. Add your stack at ${configLink("/docs/tech-stack", await workspaceBase(apiClient2))}`
|
|
563
581
|
}
|
|
564
582
|
]
|
|
565
583
|
};
|
|
@@ -593,6 +611,7 @@ ${sections}`
|
|
|
593
611
|
var init_get_tech_stack = __esm({
|
|
594
612
|
"src/tools/get-tech-stack.ts"() {
|
|
595
613
|
"use strict";
|
|
614
|
+
init_config_links();
|
|
596
615
|
}
|
|
597
616
|
});
|
|
598
617
|
|
|
@@ -976,13 +995,19 @@ async function hydrate(api, item, meta) {
|
|
|
976
995
|
}
|
|
977
996
|
async function buildContext(api, { taskDescription, filePaths = [], maxTokens }) {
|
|
978
997
|
const budget = maxTokens ?? DEFAULT_BUDGET;
|
|
979
|
-
const [
|
|
998
|
+
const [rawGuardrails, rawSpecs, docs, stack, rules, docRepos] = await Promise.all([
|
|
980
999
|
api.get("/v1/guardrails").catch(() => []),
|
|
981
1000
|
api.get("/v1/specs").catch(() => []),
|
|
982
1001
|
api.get("/v1/docs").catch(() => ({ items: [] })),
|
|
983
1002
|
api.get("/v1/ai/settings/stack").catch(() => []),
|
|
984
|
-
api.get("/v1/standards/rules").catch(() => [])
|
|
1003
|
+
api.get("/v1/standards/rules").catch(() => []),
|
|
1004
|
+
// Capability states — FAIL-OPEN: an unreadable config (older backend, a
|
|
1005
|
+
// blip) gates nothing, it can never hide working context.
|
|
1006
|
+
api.get("/v1/doc-repos").catch(() => null)
|
|
985
1007
|
]);
|
|
1008
|
+
const disabled = (key2) => docRepos?.capabilities?.[key2]?.status === "disabled";
|
|
1009
|
+
const guardrails = disabled("fitness") ? [] : rawGuardrails;
|
|
1010
|
+
const specs = disabled("requirements") && disabled("design") && disabled("specs") ? [] : rawSpecs;
|
|
986
1011
|
const refs = /* @__PURE__ */ new Map();
|
|
987
1012
|
const key = (type, id) => `${type}:${id}`;
|
|
988
1013
|
const scorable = [
|
|
@@ -1521,13 +1546,9 @@ function registerGetProjectRules(server2, apiClient2) {
|
|
|
1521
1546
|
);
|
|
1522
1547
|
}
|
|
1523
1548
|
if (filtered.length === 0) {
|
|
1549
|
+
const text2 = rules.length === 0 ? `No project rules found. Add rules at ${configLink("/docs/rules", await workspaceBase(apiClient2))}` : `No project rules found${category ? ` in category "${category}"` : ""}.`;
|
|
1524
1550
|
return {
|
|
1525
|
-
content: [
|
|
1526
|
-
{
|
|
1527
|
-
type: "text",
|
|
1528
|
-
text: `No project rules found${category ? ` in category "${category}"` : ""}.`
|
|
1529
|
-
}
|
|
1530
|
-
]
|
|
1551
|
+
content: [{ type: "text", text: text2 }]
|
|
1531
1552
|
};
|
|
1532
1553
|
}
|
|
1533
1554
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -1565,6 +1586,7 @@ var CATEGORY_LABELS;
|
|
|
1565
1586
|
var init_get_project_rules = __esm({
|
|
1566
1587
|
"src/tools/get-project-rules.ts"() {
|
|
1567
1588
|
"use strict";
|
|
1589
|
+
init_config_links();
|
|
1568
1590
|
CATEGORY_LABELS = {
|
|
1569
1591
|
deployment: "Deployment",
|
|
1570
1592
|
architecture: "Architecture",
|
|
@@ -1635,7 +1657,7 @@ function registerGetPromptTemplates(server2, apiClient2) {
|
|
|
1635
1657
|
content: [
|
|
1636
1658
|
{
|
|
1637
1659
|
type: "text",
|
|
1638
|
-
text:
|
|
1660
|
+
text: `No prompt templates found. Add templates at ${configLink("/docs/prompts", await workspaceBase(apiClient2))}`
|
|
1639
1661
|
}
|
|
1640
1662
|
]
|
|
1641
1663
|
};
|
|
@@ -1665,6 +1687,7 @@ ${text}`
|
|
|
1665
1687
|
var init_get_prompt_templates = __esm({
|
|
1666
1688
|
"src/tools/get-prompt-templates.ts"() {
|
|
1667
1689
|
"use strict";
|
|
1690
|
+
init_config_links();
|
|
1668
1691
|
}
|
|
1669
1692
|
});
|
|
1670
1693
|
|
package/dist/http.js
CHANGED
|
@@ -200,6 +200,22 @@ function legacyToolDescription(canonical, description) {
|
|
|
200
200
|
return `DEPRECATED \u2014 use \`${canonical}\` instead. This name still works and will not be removed before ${LEGACY_TOOL_REMOVAL_EARLIEST}. ${description}`;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
// src/lib/config-links.ts
|
|
204
|
+
async function workspaceBase(apiClient) {
|
|
205
|
+
try {
|
|
206
|
+
const access = await apiClient.get(
|
|
207
|
+
"/v1/docs/portal-access"
|
|
208
|
+
);
|
|
209
|
+
const slug = (access.host ?? "").split(".")[0];
|
|
210
|
+
return slug ? `https://${slug}.systemdox.com` : null;
|
|
211
|
+
} catch {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function configLink(path, base) {
|
|
216
|
+
return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
|
|
217
|
+
}
|
|
218
|
+
|
|
203
219
|
// src/tools/get-guardrails.ts
|
|
204
220
|
var DESCRIPTION = "Retrieve SystemDox checks (banned patterns, required patterns, coding rules). Filter by language, category, or file path to get only relevant checks.";
|
|
205
221
|
var inputSchema = () => ({
|
|
@@ -233,13 +249,9 @@ function registerGetGuardrails(server, apiClient) {
|
|
|
233
249
|
);
|
|
234
250
|
}
|
|
235
251
|
if (filtered.length === 0) {
|
|
252
|
+
const text2 = guardrails.length === 0 ? `No checks found. Add checks at ${configLink("/docs/guardrails", await workspaceBase(apiClient))}` : `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`;
|
|
236
253
|
return {
|
|
237
|
-
content: [
|
|
238
|
-
{
|
|
239
|
-
type: "text",
|
|
240
|
-
text: `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`
|
|
241
|
-
}
|
|
242
|
-
]
|
|
254
|
+
content: [{ type: "text", text: text2 }]
|
|
243
255
|
};
|
|
244
256
|
}
|
|
245
257
|
const text = filtered.map(
|
|
@@ -494,7 +506,7 @@ function registerGetTechStack(server, apiClient) {
|
|
|
494
506
|
content: [
|
|
495
507
|
{
|
|
496
508
|
type: "text",
|
|
497
|
-
text:
|
|
509
|
+
text: `No tech stack entries configured. Add your stack at ${configLink("/docs/tech-stack", await workspaceBase(apiClient))}`
|
|
498
510
|
}
|
|
499
511
|
]
|
|
500
512
|
};
|
|
@@ -927,13 +939,19 @@ async function hydrate(api, item, meta) {
|
|
|
927
939
|
}
|
|
928
940
|
async function buildContext(api, { taskDescription, filePaths = [], maxTokens }) {
|
|
929
941
|
const budget = maxTokens ?? DEFAULT_BUDGET;
|
|
930
|
-
const [
|
|
942
|
+
const [rawGuardrails, rawSpecs, docs, stack, rules, docRepos] = await Promise.all([
|
|
931
943
|
api.get("/v1/guardrails").catch(() => []),
|
|
932
944
|
api.get("/v1/specs").catch(() => []),
|
|
933
945
|
api.get("/v1/docs").catch(() => ({ items: [] })),
|
|
934
946
|
api.get("/v1/ai/settings/stack").catch(() => []),
|
|
935
|
-
api.get("/v1/standards/rules").catch(() => [])
|
|
947
|
+
api.get("/v1/standards/rules").catch(() => []),
|
|
948
|
+
// Capability states — FAIL-OPEN: an unreadable config (older backend, a
|
|
949
|
+
// blip) gates nothing, it can never hide working context.
|
|
950
|
+
api.get("/v1/doc-repos").catch(() => null)
|
|
936
951
|
]);
|
|
952
|
+
const disabled = (key2) => docRepos?.capabilities?.[key2]?.status === "disabled";
|
|
953
|
+
const guardrails = disabled("fitness") ? [] : rawGuardrails;
|
|
954
|
+
const specs = disabled("requirements") && disabled("design") && disabled("specs") ? [] : rawSpecs;
|
|
937
955
|
const refs = /* @__PURE__ */ new Map();
|
|
938
956
|
const key = (type, id) => `${type}:${id}`;
|
|
939
957
|
const scorable = [
|
|
@@ -1418,13 +1436,9 @@ function registerGetProjectRules(server, apiClient) {
|
|
|
1418
1436
|
);
|
|
1419
1437
|
}
|
|
1420
1438
|
if (filtered.length === 0) {
|
|
1439
|
+
const text2 = rules.length === 0 ? `No project rules found. Add rules at ${configLink("/docs/rules", await workspaceBase(apiClient))}` : `No project rules found${category ? ` in category "${category}"` : ""}.`;
|
|
1421
1440
|
return {
|
|
1422
|
-
content: [
|
|
1423
|
-
{
|
|
1424
|
-
type: "text",
|
|
1425
|
-
text: `No project rules found${category ? ` in category "${category}"` : ""}.`
|
|
1426
|
-
}
|
|
1427
|
-
]
|
|
1441
|
+
content: [{ type: "text", text: text2 }]
|
|
1428
1442
|
};
|
|
1429
1443
|
}
|
|
1430
1444
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -1513,7 +1527,7 @@ function registerGetPromptTemplates(server, apiClient) {
|
|
|
1513
1527
|
content: [
|
|
1514
1528
|
{
|
|
1515
1529
|
type: "text",
|
|
1516
|
-
text:
|
|
1530
|
+
text: `No prompt templates found. Add templates at ${configLink("/docs/prompts", await workspaceBase(apiClient))}`
|
|
1517
1531
|
}
|
|
1518
1532
|
]
|
|
1519
1533
|
};
|
package/dist/index.js
CHANGED
|
@@ -216,6 +216,22 @@ function legacyToolDescription(canonical, description) {
|
|
|
216
216
|
return `DEPRECATED \u2014 use \`${canonical}\` instead. This name still works and will not be removed before ${LEGACY_TOOL_REMOVAL_EARLIEST}. ${description}`;
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
// src/lib/config-links.ts
|
|
220
|
+
async function workspaceBase(apiClient2) {
|
|
221
|
+
try {
|
|
222
|
+
const access = await apiClient2.get(
|
|
223
|
+
"/v1/docs/portal-access"
|
|
224
|
+
);
|
|
225
|
+
const slug = (access.host ?? "").split(".")[0];
|
|
226
|
+
return slug ? `https://${slug}.systemdox.com` : null;
|
|
227
|
+
} catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function configLink(path, base) {
|
|
232
|
+
return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
|
|
233
|
+
}
|
|
234
|
+
|
|
219
235
|
// src/tools/get-guardrails.ts
|
|
220
236
|
var DESCRIPTION = "Retrieve SystemDox checks (banned patterns, required patterns, coding rules). Filter by language, category, or file path to get only relevant checks.";
|
|
221
237
|
var inputSchema = () => ({
|
|
@@ -249,13 +265,9 @@ function registerGetGuardrails(server2, apiClient2) {
|
|
|
249
265
|
);
|
|
250
266
|
}
|
|
251
267
|
if (filtered.length === 0) {
|
|
268
|
+
const text2 = guardrails.length === 0 ? `No checks found. Add checks at ${configLink("/docs/guardrails", await workspaceBase(apiClient2))}` : `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`;
|
|
252
269
|
return {
|
|
253
|
-
content: [
|
|
254
|
-
{
|
|
255
|
-
type: "text",
|
|
256
|
-
text: `No checks found${lang ? ` for language "${lang}"` : ""}${category ? ` in category "${category}"` : ""}.`
|
|
257
|
-
}
|
|
258
|
-
]
|
|
270
|
+
content: [{ type: "text", text: text2 }]
|
|
259
271
|
};
|
|
260
272
|
}
|
|
261
273
|
const text = filtered.map(
|
|
@@ -510,7 +522,7 @@ function registerGetTechStack(server2, apiClient2) {
|
|
|
510
522
|
content: [
|
|
511
523
|
{
|
|
512
524
|
type: "text",
|
|
513
|
-
text:
|
|
525
|
+
text: `No tech stack entries configured. Add your stack at ${configLink("/docs/tech-stack", await workspaceBase(apiClient2))}`
|
|
514
526
|
}
|
|
515
527
|
]
|
|
516
528
|
};
|
|
@@ -943,13 +955,19 @@ async function hydrate(api, item, meta) {
|
|
|
943
955
|
}
|
|
944
956
|
async function buildContext(api, { taskDescription, filePaths = [], maxTokens }) {
|
|
945
957
|
const budget = maxTokens ?? DEFAULT_BUDGET;
|
|
946
|
-
const [
|
|
958
|
+
const [rawGuardrails, rawSpecs, docs, stack, rules, docRepos] = await Promise.all([
|
|
947
959
|
api.get("/v1/guardrails").catch(() => []),
|
|
948
960
|
api.get("/v1/specs").catch(() => []),
|
|
949
961
|
api.get("/v1/docs").catch(() => ({ items: [] })),
|
|
950
962
|
api.get("/v1/ai/settings/stack").catch(() => []),
|
|
951
|
-
api.get("/v1/standards/rules").catch(() => [])
|
|
963
|
+
api.get("/v1/standards/rules").catch(() => []),
|
|
964
|
+
// Capability states — FAIL-OPEN: an unreadable config (older backend, a
|
|
965
|
+
// blip) gates nothing, it can never hide working context.
|
|
966
|
+
api.get("/v1/doc-repos").catch(() => null)
|
|
952
967
|
]);
|
|
968
|
+
const disabled = (key2) => docRepos?.capabilities?.[key2]?.status === "disabled";
|
|
969
|
+
const guardrails = disabled("fitness") ? [] : rawGuardrails;
|
|
970
|
+
const specs = disabled("requirements") && disabled("design") && disabled("specs") ? [] : rawSpecs;
|
|
953
971
|
const refs = /* @__PURE__ */ new Map();
|
|
954
972
|
const key = (type, id) => `${type}:${id}`;
|
|
955
973
|
const scorable = [
|
|
@@ -1434,13 +1452,9 @@ function registerGetProjectRules(server2, apiClient2) {
|
|
|
1434
1452
|
);
|
|
1435
1453
|
}
|
|
1436
1454
|
if (filtered.length === 0) {
|
|
1455
|
+
const text2 = rules.length === 0 ? `No project rules found. Add rules at ${configLink("/docs/rules", await workspaceBase(apiClient2))}` : `No project rules found${category ? ` in category "${category}"` : ""}.`;
|
|
1437
1456
|
return {
|
|
1438
|
-
content: [
|
|
1439
|
-
{
|
|
1440
|
-
type: "text",
|
|
1441
|
-
text: `No project rules found${category ? ` in category "${category}"` : ""}.`
|
|
1442
|
-
}
|
|
1443
|
-
]
|
|
1457
|
+
content: [{ type: "text", text: text2 }]
|
|
1444
1458
|
};
|
|
1445
1459
|
}
|
|
1446
1460
|
const grouped = /* @__PURE__ */ new Map();
|
|
@@ -1529,7 +1543,7 @@ function registerGetPromptTemplates(server2, apiClient2) {
|
|
|
1529
1543
|
content: [
|
|
1530
1544
|
{
|
|
1531
1545
|
type: "text",
|
|
1532
|
-
text:
|
|
1546
|
+
text: `No prompt templates found. Add templates at ${configLink("/docs/prompts", await workspaceBase(apiClient2))}`
|
|
1533
1547
|
}
|
|
1534
1548
|
]
|
|
1535
1549
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SystemDoxApiClient } from "./api-client.js";
|
|
2
|
+
/**
|
|
3
|
+
* The tenant's workspace base URL (https://{slug}.systemdox.com), or null
|
|
4
|
+
* when it can't be resolved. The slug is the first label of the portal host
|
|
5
|
+
* that GET /v1/docs/portal-access reports — the API builds that host as
|
|
6
|
+
* `{slug}.{DOCS_DOMAIN}`, so the first label is the slug whichever docs
|
|
7
|
+
* domain is live. The GET goes through the api client's response cache, so
|
|
8
|
+
* repeated empty states don't re-fetch.
|
|
9
|
+
*/
|
|
10
|
+
export declare function workspaceBase(apiClient: SystemDoxApiClient): Promise<string | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Where to add missing configuration: a full URL when the workspace base is
|
|
13
|
+
* known, the in-app path otherwise.
|
|
14
|
+
*
|
|
15
|
+
* Mirrored by apps/app/src/pages/ai/mcpPreview.ts — keep the output
|
|
16
|
+
* byte-identical when either side changes.
|
|
17
|
+
*/
|
|
18
|
+
export declare function configLink(path: string, base: string | null): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/config-links.ts
|
|
4
|
+
async function workspaceBase(apiClient) {
|
|
5
|
+
try {
|
|
6
|
+
const access = await apiClient.get(
|
|
7
|
+
"/v1/docs/portal-access"
|
|
8
|
+
);
|
|
9
|
+
const slug = (access.host ?? "").split(".")[0];
|
|
10
|
+
return slug ? `https://${slug}.systemdox.com` : null;
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function configLink(path, base) {
|
|
16
|
+
return base ? `${base}${path}` : `${path} in your SystemDox workspace`;
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
configLink,
|
|
20
|
+
workspaceBase
|
|
21
|
+
};
|
|
@@ -403,13 +403,19 @@ async function hydrate(api, item, meta) {
|
|
|
403
403
|
}
|
|
404
404
|
async function buildContext(api, { taskDescription, filePaths = [], maxTokens }) {
|
|
405
405
|
const budget = maxTokens ?? DEFAULT_BUDGET;
|
|
406
|
-
const [
|
|
406
|
+
const [rawGuardrails, rawSpecs, docs, stack, rules, docRepos] = await Promise.all([
|
|
407
407
|
api.get("/v1/guardrails").catch(() => []),
|
|
408
408
|
api.get("/v1/specs").catch(() => []),
|
|
409
409
|
api.get("/v1/docs").catch(() => ({ items: [] })),
|
|
410
410
|
api.get("/v1/ai/settings/stack").catch(() => []),
|
|
411
|
-
api.get("/v1/standards/rules").catch(() => [])
|
|
411
|
+
api.get("/v1/standards/rules").catch(() => []),
|
|
412
|
+
// Capability states — FAIL-OPEN: an unreadable config (older backend, a
|
|
413
|
+
// blip) gates nothing, it can never hide working context.
|
|
414
|
+
api.get("/v1/doc-repos").catch(() => null)
|
|
412
415
|
]);
|
|
416
|
+
const disabled = (key2) => docRepos?.capabilities?.[key2]?.status === "disabled";
|
|
417
|
+
const guardrails = disabled("fitness") ? [] : rawGuardrails;
|
|
418
|
+
const specs = disabled("requirements") && disabled("design") && disabled("specs") ? [] : rawSpecs;
|
|
413
419
|
const refs = /* @__PURE__ */ new Map();
|
|
414
420
|
const key = (type, id) => `${type}:${id}`;
|
|
415
421
|
const scorable = [
|
package/package.json
CHANGED