@ankimcp/anki-mcp-server 0.18.0 → 0.18.4-tunnel

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.
Files changed (106) hide show
  1. package/bin/ankimcp.js +10 -1
  2. package/dist/app-config.service.d.ts +22 -0
  3. package/dist/app-config.service.js +79 -0
  4. package/dist/app-config.service.js.map +1 -0
  5. package/dist/app.module.d.ts +4 -2
  6. package/dist/app.module.js +99 -11
  7. package/dist/app.module.js.map +1 -1
  8. package/dist/bootstrap.d.ts +6 -1
  9. package/dist/bootstrap.js +7 -2
  10. package/dist/bootstrap.js.map +1 -1
  11. package/dist/cli/__tests__/cli-output.manual.d.ts +2 -0
  12. package/dist/cli/__tests__/cli-output.manual.js +13 -0
  13. package/dist/cli/__tests__/cli-output.manual.js.map +1 -0
  14. package/dist/cli/cli-output.d.ts +20 -0
  15. package/dist/cli/cli-output.js +69 -0
  16. package/dist/cli/cli-output.js.map +1 -0
  17. package/dist/cli/index.d.ts +1 -0
  18. package/dist/cli/index.js +18 -0
  19. package/dist/cli/index.js.map +1 -0
  20. package/dist/cli.d.ts +4 -0
  21. package/dist/cli.js +20 -6
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config/config.factory.d.ts +13 -0
  24. package/dist/config/config.factory.js +32 -0
  25. package/dist/config/config.factory.js.map +1 -0
  26. package/dist/config/config.schema.d.ts +33 -0
  27. package/dist/config/config.schema.js +58 -0
  28. package/dist/config/config.schema.js.map +1 -0
  29. package/dist/config/index.d.ts +3 -0
  30. package/dist/config/index.js +11 -0
  31. package/dist/config/index.js.map +1 -0
  32. package/dist/http/guards/origin-validation.guard.d.ts +1 -0
  33. package/dist/http/guards/origin-validation.guard.js +5 -3
  34. package/dist/http/guards/origin-validation.guard.js.map +1 -1
  35. package/dist/main-http.js +20 -10
  36. package/dist/main-http.js.map +1 -1
  37. package/dist/main-stdio.js +9 -9
  38. package/dist/main-stdio.js.map +1 -1
  39. package/dist/main-tunnel.d.ts +1 -0
  40. package/dist/main-tunnel.js +26 -0
  41. package/dist/main-tunnel.js.map +1 -0
  42. package/dist/mcp/primitives/essential/index.d.ts +1 -0
  43. package/dist/mcp/primitives/essential/index.js +8 -1
  44. package/dist/mcp/primitives/essential/index.js.map +1 -1
  45. package/dist/mcp/primitives/essential/tools/add-note.tool.d.ts +1 -1
  46. package/dist/mcp/primitives/essential/tools/collection-stats/collection-stats.tool.js +66 -36
  47. package/dist/mcp/primitives/essential/tools/collection-stats/collection-stats.tool.js.map +1 -1
  48. package/dist/mcp/primitives/essential/tools/deck-stats.tool.js +25 -8
  49. package/dist/mcp/primitives/essential/tools/deck-stats.tool.js.map +1 -1
  50. package/dist/mcp/primitives/essential/tools/deckActions/actions/deckStats.action.js +14 -7
  51. package/dist/mcp/primitives/essential/tools/deckActions/actions/deckStats.action.js.map +1 -1
  52. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js +1 -1
  53. package/dist/mcp/primitives/essential/tools/model-field-names.tool.js.map +1 -1
  54. package/dist/mcp/primitives/gui/index.d.ts +1 -0
  55. package/dist/mcp/primitives/gui/index.js +8 -1
  56. package/dist/mcp/primitives/gui/index.js.map +1 -1
  57. package/dist/mcp/utils/deck-hierarchy.utils.d.ts +3 -0
  58. package/dist/mcp/utils/deck-hierarchy.utils.js +21 -0
  59. package/dist/mcp/utils/deck-hierarchy.utils.js.map +1 -0
  60. package/dist/services/ngrok.service.d.ts +1 -0
  61. package/dist/services/ngrok.service.js +5 -3
  62. package/dist/services/ngrok.service.js.map +1 -1
  63. package/dist/test-fixtures/mock-data.d.ts +8 -0
  64. package/dist/test-fixtures/mock-data.js +8 -0
  65. package/dist/test-fixtures/mock-data.js.map +1 -1
  66. package/dist/tsconfig.build.tsbuildinfo +1 -1
  67. package/dist/tunnel/commands/index.d.ts +3 -0
  68. package/dist/tunnel/commands/index.js +10 -0
  69. package/dist/tunnel/commands/index.js.map +1 -0
  70. package/dist/tunnel/commands/login.command.d.ts +1 -0
  71. package/dist/tunnel/commands/login.command.js +108 -0
  72. package/dist/tunnel/commands/login.command.js.map +1 -0
  73. package/dist/tunnel/commands/logout.command.d.ts +1 -0
  74. package/dist/tunnel/commands/logout.command.js +26 -0
  75. package/dist/tunnel/commands/logout.command.js.map +1 -0
  76. package/dist/tunnel/commands/tunnel.command.d.ts +1 -0
  77. package/dist/tunnel/commands/tunnel.command.js +185 -0
  78. package/dist/tunnel/commands/tunnel.command.js.map +1 -0
  79. package/dist/tunnel/credentials.service.d.ts +23 -0
  80. package/dist/tunnel/credentials.service.js +152 -0
  81. package/dist/tunnel/credentials.service.js.map +1 -0
  82. package/dist/tunnel/device-flow.service.d.ts +46 -0
  83. package/dist/tunnel/device-flow.service.js +237 -0
  84. package/dist/tunnel/device-flow.service.js.map +1 -0
  85. package/dist/tunnel/in-memory.transport.d.ts +14 -0
  86. package/dist/tunnel/in-memory.transport.js +63 -0
  87. package/dist/tunnel/in-memory.transport.js.map +1 -0
  88. package/dist/tunnel/index.d.ts +6 -0
  89. package/dist/tunnel/index.js +31 -0
  90. package/dist/tunnel/index.js.map +1 -0
  91. package/dist/tunnel/tunnel-mcp.service.d.ts +15 -0
  92. package/dist/tunnel/tunnel-mcp.service.js +100 -0
  93. package/dist/tunnel/tunnel-mcp.service.js.map +1 -0
  94. package/dist/tunnel/tunnel.client.d.ts +60 -0
  95. package/dist/tunnel/tunnel.client.js +386 -0
  96. package/dist/tunnel/tunnel.client.js.map +1 -0
  97. package/dist/tunnel/tunnel.protocol.d.ts +68 -0
  98. package/dist/tunnel/tunnel.protocol.js +26 -0
  99. package/dist/tunnel/tunnel.protocol.js.map +1 -0
  100. package/dist/version.d.ts +2 -0
  101. package/dist/version.js +21 -0
  102. package/dist/version.js.map +1 -0
  103. package/package.json +7 -2
  104. package/dist/anki-config.service.d.ts +0 -11
  105. package/dist/anki-config.service.js +0 -46
  106. package/dist/anki-config.service.js.map +0 -1
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildConfigInput = buildConfigInput;
4
+ exports.loadValidatedConfig = loadValidatedConfig;
5
+ const config_schema_1 = require("./config.schema");
6
+ function buildConfigInput(cliOverrides = {}) {
7
+ const input = { ...process.env };
8
+ if (cliOverrides.port !== undefined) {
9
+ input.PORT = String(cliOverrides.port);
10
+ }
11
+ if (cliOverrides.host !== undefined) {
12
+ input.HOST = cliOverrides.host;
13
+ }
14
+ if (cliOverrides.ankiConnect !== undefined) {
15
+ input.ANKI_CONNECT_URL = cliOverrides.ankiConnect;
16
+ }
17
+ if (cliOverrides.readOnly !== undefined) {
18
+ input.READ_ONLY = cliOverrides.readOnly ? "true" : "false";
19
+ }
20
+ if (typeof cliOverrides.tunnel === "string") {
21
+ input.TUNNEL_SERVER_URL = cliOverrides.tunnel;
22
+ }
23
+ if (cliOverrides.debug) {
24
+ input.LOG_LEVEL = "debug";
25
+ }
26
+ return input;
27
+ }
28
+ function loadValidatedConfig(cliOverrides = {}) {
29
+ const input = buildConfigInput(cliOverrides);
30
+ return config_schema_1.configSchema.parse((0, config_schema_1.transformEnvToConfig)(input));
31
+ }
32
+ //# sourceMappingURL=config.factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.factory.js","sourceRoot":"","sources":["../../src/config/config.factory.ts"],"names":[],"mappings":";;AA8BA,4CAwBC;AAMD,kDAKC;AAjED,mDAAgF;AA8BhF,SAAgB,gBAAgB,CAAC,eAA6B,EAAE;IAE9D,MAAM,KAAK,GAAgB,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE9C,IAAI,YAAY,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,YAAY,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC;IACjC,CAAC;IACD,IAAI,YAAY,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QAC3C,KAAK,CAAC,gBAAgB,GAAG,YAAY,CAAC,WAAW,CAAC;IACpD,CAAC;IACD,IAAI,YAAY,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACxC,KAAK,CAAC,SAAS,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC7D,CAAC;IACD,IAAI,OAAO,YAAY,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC5C,KAAK,CAAC,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC;IAChD,CAAC;IACD,IAAI,YAAY,CAAC,KAAK,EAAE,CAAC;QACvB,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC;IAC5B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAMD,SAAgB,mBAAmB,CACjC,eAA6B,EAAE;IAE/B,MAAM,KAAK,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAC7C,OAAO,4BAAY,CAAC,KAAK,CAAC,IAAA,oCAAoB,EAAC,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ export declare const configSchema: z.ZodObject<{
3
+ port: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
4
+ host: z.ZodDefault<z.ZodString>;
5
+ nodeEnv: z.ZodDefault<z.ZodEnum<{
6
+ development: "development";
7
+ production: "production";
8
+ test: "test";
9
+ }>>;
10
+ ankiConnect: z.ZodObject<{
11
+ url: z.ZodDefault<z.ZodString>;
12
+ apiKey: z.ZodOptional<z.ZodString>;
13
+ apiVersion: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
14
+ timeout: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
15
+ }, z.core.$strip>;
16
+ auth: z.ZodObject<{
17
+ url: z.ZodDefault<z.ZodString>;
18
+ realm: z.ZodDefault<z.ZodString>;
19
+ clientId: z.ZodDefault<z.ZodString>;
20
+ }, z.core.$strip>;
21
+ tunnel: z.ZodObject<{
22
+ serverUrl: z.ZodDefault<z.ZodString>;
23
+ }, z.core.$strip>;
24
+ readOnly: z.ZodDefault<z.ZodPipe<z.ZodTransform<{} | null, unknown>, z.ZodBoolean>>;
25
+ logLevel: z.ZodDefault<z.ZodEnum<{
26
+ error: "error";
27
+ debug: "debug";
28
+ info: "info";
29
+ warn: "warn";
30
+ }>>;
31
+ }, z.core.$strip>;
32
+ export type AppConfig = z.infer<typeof configSchema>;
33
+ export declare function transformEnvToConfig(env: Record<string, any>): any;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configSchema = void 0;
4
+ exports.transformEnvToConfig = transformEnvToConfig;
5
+ const zod_1 = require("zod");
6
+ exports.configSchema = zod_1.z.object({
7
+ port: zod_1.z.coerce.number().int().positive().default(3000),
8
+ host: zod_1.z.string().default("127.0.0.1"),
9
+ nodeEnv: zod_1.z.enum(["development", "production", "test"]).default("development"),
10
+ ankiConnect: zod_1.z.object({
11
+ url: zod_1.z.string().url().default("http://localhost:8765"),
12
+ apiKey: zod_1.z.string().optional(),
13
+ apiVersion: zod_1.z.coerce.number().int().positive().default(6),
14
+ timeout: zod_1.z.coerce.number().int().positive().default(5000),
15
+ }),
16
+ auth: zod_1.z.object({
17
+ url: zod_1.z.string().url().default("https://keycloak.anatoly.dev"),
18
+ realm: zod_1.z.string().default("ankimcp-dev"),
19
+ clientId: zod_1.z.string().default("ankimcp-cli"),
20
+ }),
21
+ tunnel: zod_1.z.object({
22
+ serverUrl: zod_1.z.string().url().default("wss://tunnel.ankimcp.ai"),
23
+ }),
24
+ readOnly: zod_1.z
25
+ .preprocess((val) => {
26
+ if (val === "true" || val === "1")
27
+ return true;
28
+ if (val === "false" || val === "0" || val === undefined || val === "")
29
+ return false;
30
+ return val;
31
+ }, zod_1.z.boolean())
32
+ .default(false),
33
+ logLevel: zod_1.z.enum(["debug", "info", "warn", "error"]).default("info"),
34
+ });
35
+ function transformEnvToConfig(env) {
36
+ return {
37
+ port: env.PORT,
38
+ host: env.HOST,
39
+ nodeEnv: env.NODE_ENV,
40
+ ankiConnect: {
41
+ url: env.ANKI_CONNECT_URL,
42
+ apiKey: env.ANKI_CONNECT_API_KEY,
43
+ apiVersion: env.ANKI_CONNECT_API_VERSION,
44
+ timeout: env.ANKI_CONNECT_TIMEOUT,
45
+ },
46
+ auth: {
47
+ url: env.TUNNEL_AUTH_URL,
48
+ realm: env.TUNNEL_AUTH_REALM,
49
+ clientId: env.TUNNEL_AUTH_CLIENT_ID,
50
+ },
51
+ tunnel: {
52
+ serverUrl: env.TUNNEL_SERVER_URL,
53
+ },
54
+ readOnly: env.READ_ONLY,
55
+ logLevel: env.LOG_LEVEL,
56
+ };
57
+ }
58
+ //# sourceMappingURL=config.schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.schema.js","sourceRoot":"","sources":["../../src/config/config.schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { configSchema, transformEnvToConfig, type AppConfig, } from "./config.schema";
2
+ export { buildConfigInput, loadValidatedConfig, type ConfigInput, type CliOverrides, } from "./config.factory";
3
+ export declare const APP_CONFIG: unique symbol;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.APP_CONFIG = exports.loadValidatedConfig = exports.buildConfigInput = exports.transformEnvToConfig = exports.configSchema = void 0;
4
+ var config_schema_1 = require("./config.schema");
5
+ Object.defineProperty(exports, "configSchema", { enumerable: true, get: function () { return config_schema_1.configSchema; } });
6
+ Object.defineProperty(exports, "transformEnvToConfig", { enumerable: true, get: function () { return config_schema_1.transformEnvToConfig; } });
7
+ var config_factory_1 = require("./config.factory");
8
+ Object.defineProperty(exports, "buildConfigInput", { enumerable: true, get: function () { return config_factory_1.buildConfigInput; } });
9
+ Object.defineProperty(exports, "loadValidatedConfig", { enumerable: true, get: function () { return config_factory_1.loadValidatedConfig; } });
10
+ exports.APP_CONFIG = Symbol("APP_CONFIG");
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":";;;AAIA,iDAIyB;AAHvB,6GAAA,YAAY,OAAA;AACZ,qHAAA,oBAAoB,OAAA;AAGtB,mDAK0B;AAJxB,kHAAA,gBAAgB,OAAA;AAChB,qHAAA,mBAAmB,OAAA;AASR,QAAA,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { CanActivate, ExecutionContext } from "@nestjs/common";
2
2
  export declare class OriginValidationGuard implements CanActivate {
3
+ private readonly logger;
3
4
  private readonly allowedOrigins;
4
5
  constructor();
5
6
  canActivate(context: ExecutionContext): boolean;
@@ -8,10 +8,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var OriginValidationGuard_1;
11
12
  Object.defineProperty(exports, "__esModule", { value: true });
12
13
  exports.OriginValidationGuard = void 0;
13
14
  const common_1 = require("@nestjs/common");
14
- let OriginValidationGuard = class OriginValidationGuard {
15
+ let OriginValidationGuard = OriginValidationGuard_1 = class OriginValidationGuard {
16
+ logger = new common_1.Logger(OriginValidationGuard_1.name);
15
17
  allowedOrigins;
16
18
  constructor() {
17
19
  const defaultOrigins = "http://localhost:*,http://127.0.0.1:*,https://localhost:*,https://127.0.0.1:*";
@@ -26,7 +28,7 @@ let OriginValidationGuard = class OriginValidationGuard {
26
28
  }
27
29
  const isAllowed = this.allowedOrigins.some((allowedOrigin) => this.matchesPattern(origin, allowedOrigin));
28
30
  if (!isAllowed) {
29
- console.warn(`[OriginValidationGuard] Rejected request from unauthorized origin: ${origin}`);
31
+ this.logger.warn(`Rejected request from unauthorized origin: ${origin}`);
30
32
  }
31
33
  return isAllowed;
32
34
  }
@@ -45,7 +47,7 @@ let OriginValidationGuard = class OriginValidationGuard {
45
47
  }
46
48
  };
47
49
  exports.OriginValidationGuard = OriginValidationGuard;
48
- exports.OriginValidationGuard = OriginValidationGuard = __decorate([
50
+ exports.OriginValidationGuard = OriginValidationGuard = OriginValidationGuard_1 = __decorate([
49
51
  (0, common_1.Injectable)(),
50
52
  __metadata("design:paramtypes", [])
51
53
  ], OriginValidationGuard);
@@ -1 +1 @@
1
- {"version":3,"file":"origin-validation.guard.js","sourceRoot":"","sources":["../../../src/http/guards/origin-validation.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAA2E;AAiBpE,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IACf,cAAc,CAAW;IAE1C;QACE,MAAM,cAAc,GAClB,+EAA+E,CAAC;QAClF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,cAAc,CAAC;QACjE,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,WAAW,CAAC,OAAyB;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;QAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAGjE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,EAAE,CAC3D,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAC3C,CAAC;QAEF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CACV,sEAAsE,MAAM,EAAE,CAC/E,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IASO,cAAc,CAAC,MAAc,EAAE,OAAe;QAEpD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,OAAO;iBACzB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;iBACrB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACxB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC;YAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAA;AAzDY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;;GACA,qBAAqB,CAyDjC"}
1
+ {"version":3,"file":"origin-validation.guard.js","sourceRoot":"","sources":["../../../src/http/guards/origin-validation.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAKwB;AAiBjB,IAAM,qBAAqB,6BAA3B,MAAM,qBAAqB;IACf,MAAM,GAAG,IAAI,eAAM,CAAC,uBAAqB,CAAC,IAAI,CAAC,CAAC;IAChD,cAAc,CAAW;IAE1C;QACE,MAAM,cAAc,GAClB,+EAA+E,CAAC;QAClF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,cAAc,CAAC;QACjE,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,WAAW,CAAC,OAAyB;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAW,CAAC;QAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAGjE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,EAAE,CAC3D,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAC3C,CAAC;QAEF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,MAAM,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IASO,cAAc,CAAC,MAAc,EAAE,OAAe;QAEpD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAGD,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,OAAO;iBACzB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;iBACrB,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACxB,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,YAAY,GAAG,CAAC,CAAC;YAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF,CAAA;AAxDY,sDAAqB;gCAArB,qBAAqB;IADjC,IAAA,mBAAU,GAAE;;GACA,qBAAqB,CAwDjC"}
package/dist/main-http.js CHANGED
@@ -5,17 +5,25 @@ const app_module_1 = require("./app.module");
5
5
  const bootstrap_1 = require("./bootstrap");
6
6
  const origin_validation_guard_1 = require("./http/guards/origin-validation.guard");
7
7
  const cli_1 = require("./cli");
8
+ const cli_output_1 = require("./cli/cli-output");
8
9
  const ngrok_service_1 = require("./services/ngrok.service");
10
+ const config_1 = require("./config");
9
11
  async function bootstrap() {
10
12
  (0, cli_1.checkForUpdates)();
11
13
  const options = (0, cli_1.parseCliArgs)();
12
- process.env.PORT = options.port.toString();
13
- process.env.HOST = options.host;
14
- process.env.ANKI_CONNECT_URL = options.ankiConnect;
15
- process.env.READ_ONLY = options.readOnly ? "true" : "false";
16
- const pinoLogger = (0, bootstrap_1.createPinoLogger)(1);
14
+ (0, cli_output_1.setDebugMode)(options.debug);
15
+ const configInput = (0, config_1.buildConfigInput)({
16
+ port: options.port,
17
+ host: options.host,
18
+ ankiConnect: options.ankiConnect,
19
+ readOnly: options.readOnly,
20
+ tunnel: options.tunnel,
21
+ ngrok: options.ngrok,
22
+ debug: options.debug,
23
+ });
24
+ const pinoLogger = (0, bootstrap_1.createPinoLogger)(bootstrap_1.LOG_DESTINATION.STDOUT, configInput.LOG_LEVEL || "info");
17
25
  const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger);
18
- const app = await core_1.NestFactory.create(app_module_1.AppModule.forHttp(), {
26
+ const app = await core_1.NestFactory.create(app_module_1.AppModule.forHttp(configInput), {
19
27
  logger: loggerService,
20
28
  bufferLogs: true,
21
29
  });
@@ -29,15 +37,17 @@ async function bootstrap() {
29
37
  ngrokUrl = tunnelInfo.publicUrl;
30
38
  }
31
39
  catch (err) {
32
- console.error("\n❌ Failed to start ngrok:");
33
- console.error(err instanceof Error ? err.message : String(err));
34
- console.error("\nServer is still running locally without tunnel.\n");
40
+ cli_output_1.cli.blank();
41
+ cli_output_1.cli.error(`Failed to start ngrok: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
42
+ cli_output_1.cli.blank();
43
+ cli_output_1.cli.info("Server is still running locally without tunnel.");
44
+ cli_output_1.cli.blank();
35
45
  }
36
46
  }
37
47
  (0, cli_1.displayStartupBanner)(options, ngrokUrl);
38
48
  }
39
49
  bootstrap().catch((err) => {
40
- console.error("Failed to start MCP HTTP server:", err);
50
+ cli_output_1.cli.error(`Failed to start MCP HTTP server: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
41
51
  process.exit(1);
42
52
  });
43
53
  //# sourceMappingURL=main-http.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"main-http.js","sourceRoot":"","sources":["../src/main-http.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAAoE;AACpE,mFAA8E;AAC9E,+BAA4E;AAC5E,4DAAwD;AAExD,KAAK,UAAU,SAAS;IAEtB,IAAA,qBAAe,GAAE,CAAC;IAElB,MAAM,OAAO,GAAG,IAAA,kBAAY,GAAE,CAAC;IAG/B,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IACnD,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAG5D,MAAM,UAAU,GAAG,IAAA,4BAAgB,EAAC,CAAC,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,OAAO,EAAE,EAAE;QACxD,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,IAAI,+CAAqB,EAAE,CAAC,CAAC;IAEjD,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7C,IAAI,QAA4B,CAAC;IACjC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;YACxC,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC1D,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAGD,IAAA,0BAAoB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"main-http.js","sourceRoot":"","sources":["../src/main-http.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAIqB;AACrB,mFAA8E;AAC9E,+BAA4E;AAC5E,iDAAqD;AACrD,4DAAwD;AACxD,qCAA4C;AAE5C,KAAK,UAAU,SAAS;IAEtB,IAAA,qBAAe,GAAE,CAAC;IAElB,MAAM,OAAO,GAAG,IAAA,kBAAY,GAAE,CAAC;IAG/B,IAAA,yBAAY,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAG5B,MAAM,WAAW,GAAG,IAAA,yBAAgB,EAAC;QACnC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAIH,MAAM,UAAU,GAAG,IAAA,4BAAgB,EACjC,2BAAe,CAAC,MAAM,EACtB,WAAW,CAAC,SAAS,IAAI,MAAM,CAChC,CAAC;IACF,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;QACnE,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,IAAI,+CAAqB,EAAE,CAAC,CAAC;IAEjD,MAAM,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAG7C,IAAI,QAA4B,CAAC;IACjC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;YACxC,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC1D,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,gBAAG,CAAC,KAAK,EAAE,CAAC;YACZ,gBAAG,CAAC,KAAK,CACP,0BAA0B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC5E,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;YACF,gBAAG,CAAC,KAAK,EAAE,CAAC;YACZ,gBAAG,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAC5D,gBAAG,CAAC,KAAK,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAGD,IAAA,0BAAoB,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,gBAAG,CAAC,KAAK,CACP,oCAAoC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACtF,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@nestjs/core");
4
4
  const app_module_1 = require("./app.module");
5
5
  const bootstrap_1 = require("./bootstrap");
6
+ const cli_output_1 = require("./cli/cli-output");
7
+ const config_1 = require("./config");
6
8
  function parseStdioArgs() {
7
9
  const args = process.argv.slice(2);
8
10
  let readOnly = false;
@@ -20,15 +22,13 @@ function parseStdioArgs() {
20
22
  }
21
23
  async function bootstrap() {
22
24
  const cliOptions = parseStdioArgs();
23
- if (cliOptions.readOnly) {
24
- process.env.READ_ONLY = "true";
25
- }
26
- if (cliOptions.ankiConnect) {
27
- process.env.ANKI_CONNECT_URL = cliOptions.ankiConnect;
28
- }
29
- const pinoLogger = (0, bootstrap_1.createPinoLogger)(2);
25
+ const configInput = (0, config_1.buildConfigInput)({
26
+ ankiConnect: cliOptions.ankiConnect,
27
+ readOnly: cliOptions.readOnly,
28
+ });
29
+ const pinoLogger = (0, bootstrap_1.createPinoLogger)(bootstrap_1.LOG_DESTINATION.STDERR, configInput.LOG_LEVEL || "info");
30
30
  const loggerService = (0, bootstrap_1.createLoggerService)(pinoLogger);
31
- await core_1.NestFactory.createApplicationContext(app_module_1.AppModule.forStdio(), {
31
+ await core_1.NestFactory.createApplicationContext(app_module_1.AppModule.forStdio(configInput), {
32
32
  logger: loggerService,
33
33
  bufferLogs: true,
34
34
  });
@@ -41,7 +41,7 @@ async function bootstrap() {
41
41
  await new Promise(() => { });
42
42
  }
43
43
  bootstrap().catch((err) => {
44
- console.error("Failed to start MCP STDIO server:", err);
44
+ cli_output_1.cli.error(`Failed to start MCP STDIO server: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
45
45
  process.exit(1);
46
46
  });
47
47
  //# sourceMappingURL=main-stdio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"main-stdio.js","sourceRoot":"","sources":["../src/main-stdio.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAAoE;AAMpE,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,WAA+B,CAAC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;YAC9B,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,SAAS;IAEtB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IAGpC,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;IACjC,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,gBAAgB,GAAG,UAAU,CAAC,WAAW,CAAC;IACxD,CAAC;IAGD,MAAM,UAAU,GAAG,IAAA,4BAAgB,EAAC,CAAC,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,kBAAW,CAAC,wBAAwB,CAAC,sBAAS,CAAC,QAAQ,EAAE,EAAE;QAC/D,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,UAAU,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAGD,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"main-stdio.js","sourceRoot":"","sources":["../src/main-stdio.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AACzC,2CAIqB;AACrB,iDAAuC;AACvC,qCAA4C;AAM5C,SAAS,cAAc;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,WAA+B,CAAC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,aAAa,EAAE,CAAC;YAC9B,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,SAAS;IAEtB,MAAM,UAAU,GAAG,cAAc,EAAE,CAAC;IAGpC,MAAM,WAAW,GAAG,IAAA,yBAAgB,EAAC;QACnC,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,QAAQ,EAAE,UAAU,CAAC,QAAQ;KAC9B,CAAC,CAAC;IAIH,MAAM,UAAU,GAAG,IAAA,4BAAgB,EACjC,2BAAe,CAAC,MAAM,EACtB,WAAW,CAAC,SAAS,IAAI,MAAM,CAChC,CAAC;IACF,MAAM,aAAa,GAAG,IAAA,+BAAmB,EAAC,UAAU,CAAC,CAAC;IAGtD,MAAM,kBAAW,CAAC,wBAAwB,CAAC,sBAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE;QAC1E,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,UAAU,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAGD,MAAM,IAAI,OAAO,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,gBAAG,CAAC,KAAK,CACP,qCAAqC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACvF,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const cli_1 = require("./cli");
4
+ const cli_output_1 = require("./cli/cli-output");
5
+ const tunnel_1 = require("./tunnel");
6
+ async function bootstrap() {
7
+ (0, cli_1.checkForUpdates)();
8
+ const options = (0, cli_1.parseCliArgs)();
9
+ (0, cli_output_1.setDebugMode)(options.debug);
10
+ if (options.login) {
11
+ const loginUrl = typeof options.login === "string" ? options.login : undefined;
12
+ await (0, tunnel_1.handleLogin)(loginUrl);
13
+ process.exit(0);
14
+ }
15
+ if (options.logout) {
16
+ await (0, tunnel_1.handleLogout)();
17
+ process.exit(0);
18
+ }
19
+ const tunnelUrl = typeof options.tunnel === "string" ? options.tunnel : undefined;
20
+ await (0, tunnel_1.handleTunnel)(tunnelUrl, options.debug, options.readOnly);
21
+ }
22
+ bootstrap().catch((err) => {
23
+ cli_output_1.cli.error(`Failed to start tunnel: ${err instanceof Error ? err.message : String(err)}`, err instanceof Error ? err : undefined);
24
+ process.exit(1);
25
+ });
26
+ //# sourceMappingURL=main-tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main-tunnel.js","sourceRoot":"","sources":["../src/main-tunnel.ts"],"names":[],"mappings":";;AAAA,+BAAsD;AACtD,iDAAqD;AACrD,qCAAmE;AAEnE,KAAK,UAAU,SAAS;IAEtB,IAAA,qBAAe,GAAE,CAAC;IAElB,MAAM,OAAO,GAAG,IAAA,kBAAY,GAAE,CAAC;IAG/B,IAAA,yBAAY,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAG5B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,QAAQ,GACZ,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,MAAM,IAAA,oBAAW,EAAC,QAAQ,CAAC,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAA,qBAAY,GAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAID,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAClE,MAAM,IAAA,qBAAY,EAAC,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,gBAAG,CAAC,KAAK,CACP,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC7E,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CACvC,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -75,6 +75,7 @@ import { SystemInfoResource } from "./resources/system-info.resource";
75
75
  export declare const ESSENTIAL_MCP_TOOLS: (typeof SyncTool | typeof GetDueCardsTool | typeof GetCardsTool | typeof PresentCardTool | typeof RateCardTool | typeof ModelNamesTool | typeof ModelFieldNamesTool | typeof ModelStylingTool | typeof CreateModelTool | typeof UpdateModelStylingTool | typeof AddNoteTool | typeof AddNotesTool | typeof FindNotesTool | typeof NotesInfoTool | typeof UpdateNoteFieldsTool | typeof DeleteNotesTool | typeof GetTagsTool | typeof ListDecksTool | typeof DeckStatsTool | typeof CreateDeckTool | typeof ChangeDeckTool | typeof RetrieveMediaFileTool | typeof GetMediaFilesNamesTool | typeof StoreMediaFileTool | typeof DeleteMediaFileTool | typeof AddTagsTool | typeof RemoveTagsTool | typeof ReplaceTagsTool | typeof ClearUnusedTagsTool | typeof CollectionStatsTool | typeof ReviewStatsTool | typeof ReviewSessionPrompt | typeof TwentyRulesPrompt | typeof SystemInfoResource)[];
76
76
  export interface McpPrimitivesAnkiEssentialModuleOptions {
77
77
  ankiConfigProvider: Provider;
78
+ appConfigProvider?: Provider;
78
79
  }
79
80
  export declare class McpPrimitivesAnkiEssentialModule {
80
81
  static forRoot(options: McpPrimitivesAnkiEssentialModuleOptions): DynamicModule;
@@ -173,9 +173,16 @@ exports.ESSENTIAL_MCP_TOOLS = [
173
173
  const ESSENTIAL_MCP_PRIMITIVES = [anki_connect_client_2.AnkiConnectClient, ...exports.ESSENTIAL_MCP_TOOLS];
174
174
  let McpPrimitivesAnkiEssentialModule = McpPrimitivesAnkiEssentialModule_1 = class McpPrimitivesAnkiEssentialModule {
175
175
  static forRoot(options) {
176
+ const providers = [
177
+ options.ankiConfigProvider,
178
+ ...ESSENTIAL_MCP_PRIMITIVES,
179
+ ];
180
+ if (options.appConfigProvider) {
181
+ providers.push(options.appConfigProvider);
182
+ }
176
183
  return {
177
184
  module: McpPrimitivesAnkiEssentialModule_1,
178
- providers: [options.ankiConfigProvider, ...ESSENTIAL_MCP_PRIMITIVES],
185
+ providers,
179
186
  exports: ESSENTIAL_MCP_PRIMITIVES,
180
187
  };
181
188
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/primitives/essential/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp/primitives/essential/index.ts"],"names":[],"mappings":"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"}
@@ -121,7 +121,7 @@ export declare class AddNoteTool {
121
121
  details: {
122
122
  fieldsAdded: number;
123
123
  tagsAdded: number;
124
- duplicateCheckScope: "deck" | "collection" | "default" | "none";
124
+ duplicateCheckScope: "default" | "deck" | "collection" | "none";
125
125
  };
126
126
  }>;
127
127
  }
@@ -16,6 +16,7 @@ const mcp_nest_1 = require("@rekog/mcp-nest");
16
16
  const zod_1 = require("zod");
17
17
  const anki_connect_client_1 = require("../../../../clients/anki-connect.client");
18
18
  const anki_utils_1 = require("../../../../utils/anki.utils");
19
+ const deck_hierarchy_utils_1 = require("../../../../utils/deck-hierarchy.utils");
19
20
  const stats_utils_1 = require("../../../../utils/stats.utils");
20
21
  let CollectionStatsTool = CollectionStatsTool_1 = class CollectionStatsTool {
21
22
  ankiClient;
@@ -61,34 +62,27 @@ let CollectionStatsTool = CollectionStatsTool_1 = class CollectionStatsTool {
61
62
  if (!deckStatsResponse || typeof deckStatsResponse !== "object") {
62
63
  throw new Error("Invalid getDeckStats response");
63
64
  }
64
- const per_deck = [];
65
- const counts = {
66
- total: 0,
67
- new: 0,
68
- learning: 0,
69
- review: 0,
70
- other: 0,
71
- };
65
+ const perDeckOwnTotal = new Map();
66
+ const perDeckStats = new Map();
72
67
  const missingDecks = [];
73
68
  for (const deckName of deckNames) {
74
69
  const deckId = deckNamesAndIds[deckName];
75
70
  const deckStats = deckId != null ? deckStatsResponse[String(deckId)] : undefined;
76
71
  if (!deckStats) {
77
72
  missingDecks.push(deckName);
78
- per_deck.push({
79
- deck: deckName,
80
- total: 0,
81
- new: 0,
82
- learning: 0,
83
- review: 0,
84
- other: 0,
85
- });
73
+ perDeckOwnTotal.set(deckName, 0);
86
74
  continue;
87
75
  }
88
- const total = deckStats.total_in_deck ?? 0;
89
- const newCount = deckStats.new_count ?? 0;
90
- const learning = deckStats.learn_count ?? 0;
91
- const review = deckStats.review_count ?? 0;
76
+ perDeckOwnTotal.set(deckName, deckStats.total_in_deck ?? 0);
77
+ perDeckStats.set(deckName, deckStats);
78
+ }
79
+ const per_deck = [];
80
+ for (const deckName of deckNames) {
81
+ const stats = perDeckStats.get(deckName);
82
+ const newCount = stats?.new_count ?? 0;
83
+ const learning = stats?.learn_count ?? 0;
84
+ const review = stats?.review_count ?? 0;
85
+ const total = (0, deck_hierarchy_utils_1.rollupDeckTotal)(deckName, perDeckOwnTotal);
92
86
  const other = Math.max(0, total - newCount - learning - review);
93
87
  per_deck.push({
94
88
  deck: deckName,
@@ -98,17 +92,30 @@ let CollectionStatsTool = CollectionStatsTool_1 = class CollectionStatsTool {
98
92
  review,
99
93
  other,
100
94
  });
101
- counts.total += total;
102
- counts.new += newCount;
103
- counts.learning += learning;
104
- counts.review += review;
105
- counts.other += other;
106
95
  }
107
96
  if (missingDecks.length > 0) {
108
97
  this.logger.warn(`getDeckStats did not return stats for ${missingDecks.length} deck(s): ` +
109
98
  `${missingDecks.join(", ")}. Filled with zeros.`);
110
99
  }
111
- this.logger.log(`Aggregated counts: ${counts.total} total cards across ${deckNames.length} decks`);
100
+ const rootDeckNames = new Set((0, deck_hierarchy_utils_1.getRootDeckNames)(deckNames));
101
+ const counts = {
102
+ total: 0,
103
+ new: 0,
104
+ learning: 0,
105
+ review: 0,
106
+ other: 0,
107
+ };
108
+ for (const entry of per_deck) {
109
+ if (!rootDeckNames.has(entry.deck))
110
+ continue;
111
+ counts.total += entry.total;
112
+ counts.new += entry.new;
113
+ counts.learning += entry.learning;
114
+ counts.review += entry.review;
115
+ counts.other += entry.other;
116
+ }
117
+ this.logger.log(`Aggregated counts: ${counts.total} total cards across ${rootDeckNames.size} root deck(s) ` +
118
+ `(${deckNames.length} total decks including children)`);
112
119
  await context.reportProgress({ progress: 40, total: 100 });
113
120
  if (counts.total === 0) {
114
121
  this.logger.log("Collection is empty (no cards)");
@@ -202,7 +209,9 @@ __decorate([
202
209
  (0, mcp_nest_1.Tool)({
203
210
  name: "collection_stats",
204
211
  description: "Get aggregated statistics across all decks in the collection including card counts, ease factor distribution, and interval distribution. " +
205
- "Provides both collection-wide metrics and per-deck breakdown. " +
212
+ "Per-deck counts are rolled up over descendants (a parent deck includes its children), matching Anki's deck browser. " +
213
+ "Collection-level `counts` sum the ROOT decks only to avoid double-counting children. " +
214
+ "Invariant: for every deck and for the collection, total === new + learning + review + other. " +
206
215
  "Use this to analyze overall collection health and compare deck statistics. " +
207
216
  "Ease buckets and interval buckets can be customized to focus on specific ranges.",
208
217
  parameters: zod_1.z.object({
@@ -229,16 +238,32 @@ __decorate([
229
238
  }),
230
239
  outputSchema: zod_1.z.object({
231
240
  total_decks: zod_1.z.number(),
232
- counts: zod_1.z.object({
233
- total: zod_1.z.number(),
234
- new: zod_1.z.number(),
235
- learning: zod_1.z.number(),
236
- review: zod_1.z.number(),
241
+ counts: zod_1.z
242
+ .object({
243
+ total: zod_1.z
244
+ .number()
245
+ .describe("Total cards in the collection. Computed as the sum of " +
246
+ "ROOT-deck rolled-up totals (decks without `::` in the name), " +
247
+ "which prevents double-counting children. Invariant: " +
248
+ "total === new + learning + review + other."),
249
+ new: zod_1.z
250
+ .number()
251
+ .describe("New cards (never studied), summed over root decks' rolled-up counts."),
252
+ learning: zod_1.z
253
+ .number()
254
+ .describe("Learning/relearning cards, summed over root decks' rolled-up counts."),
255
+ review: zod_1.z
256
+ .number()
257
+ .describe("Review cards (mature), summed over root decks' rolled-up counts."),
237
258
  other: zod_1.z
238
259
  .number()
239
- .describe("Cards not in new/learning/review (typically suspended or buried). " +
260
+ .describe("Cards not in new/learning/review (typically suspended or buried), " +
261
+ "summed over root decks' rolled-up counts. " +
240
262
  "Computed as total - new - learning - review."),
241
- }),
263
+ })
264
+ .describe("Aggregated card counts across the collection. Summed over ROOT " +
265
+ "decks only (names without `::`) so that a parent's rollup is not " +
266
+ "added on top of its children."),
242
267
  ease: zod_1.z.object({
243
268
  mean: zod_1.z.number(),
244
269
  median: zod_1.z.number(),
@@ -255,14 +280,19 @@ __decorate([
255
280
  count: zod_1.z.number(),
256
281
  buckets: zod_1.z.record(zod_1.z.string(), zod_1.z.number()),
257
282
  }),
258
- per_deck: zod_1.z.array(zod_1.z.object({
283
+ per_deck: zod_1.z
284
+ .array(zod_1.z.object({
259
285
  deck: zod_1.z.string(),
260
286
  total: zod_1.z.number(),
261
287
  new: zod_1.z.number(),
262
288
  learning: zod_1.z.number(),
263
289
  review: zod_1.z.number(),
264
290
  other: zod_1.z.number(),
265
- })),
291
+ }))
292
+ .describe("Per-deck breakdown with one entry per deck. Each entry's counts " +
293
+ 'are rolled up over that deck\'s descendants (entry for "German" ' +
294
+ 'includes cards from "German::Verbs"). Invariant per row: ' +
295
+ "total === new + learning + review + other."),
266
296
  }),
267
297
  annotations: {
268
298
  title: "Collection Statistics",