@ansvar/ch-farm-grants-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/check-freshness.yml +18 -0
- package/.github/workflows/ci.yml +21 -0
- package/.github/workflows/codeql.yml +25 -0
- package/.github/workflows/ghcr-build.yml +45 -0
- package/.github/workflows/gitleaks.yml +18 -0
- package/.github/workflows/ingest.yml +28 -0
- package/.github/workflows/publish.yml +24 -0
- package/CHANGELOG.md +22 -0
- package/CODEOWNERS +1 -0
- package/COVERAGE.md +45 -0
- package/DISCLAIMER.md +39 -0
- package/Dockerfile +26 -0
- package/LICENSE +17 -0
- package/PRIVACY.md +36 -0
- package/README.md +80 -0
- package/SECURITY.md +31 -0
- package/TOOLS.md +154 -0
- package/data/coverage.json +19 -0
- package/data/database.db +0 -0
- package/data/sources.yml +29 -0
- package/dist/db.d.ts +25 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +167 -0
- package/dist/db.js.map +1 -0
- package/dist/http-server.d.ts +2 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +261 -0
- package/dist/http-server.js.map +1 -0
- package/dist/jurisdiction.d.ts +18 -0
- package/dist/jurisdiction.d.ts.map +1 -0
- package/dist/jurisdiction.js +16 -0
- package/dist/jurisdiction.js.map +1 -0
- package/dist/metadata.d.ts +10 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +22 -0
- package/dist/metadata.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +207 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/about.d.ts +15 -0
- package/dist/tools/about.d.ts.map +1 -0
- package/dist/tools/about.js +28 -0
- package/dist/tools/about.js.map +1 -0
- package/dist/tools/check-eligibility.d.ts +31 -0
- package/dist/tools/check-eligibility.d.ts.map +1 -0
- package/dist/tools/check-eligibility.js +57 -0
- package/dist/tools/check-eligibility.js.map +1 -0
- package/dist/tools/check-freshness.d.ts +15 -0
- package/dist/tools/check-freshness.d.ts.map +1 -0
- package/dist/tools/check-freshness.js +26 -0
- package/dist/tools/check-freshness.js.map +1 -0
- package/dist/tools/get-application-deadlines.d.ts +27 -0
- package/dist/tools/get-application-deadlines.d.ts.map +1 -0
- package/dist/tools/get-application-deadlines.js +40 -0
- package/dist/tools/get-application-deadlines.js.map +1 -0
- package/dist/tools/get-grant-details.d.ts +42 -0
- package/dist/tools/get-grant-details.d.ts.map +1 -0
- package/dist/tools/get-grant-details.js +24 -0
- package/dist/tools/get-grant-details.js.map +1 -0
- package/dist/tools/get-payment-rates.d.ts +49 -0
- package/dist/tools/get-payment-rates.d.ts.map +1 -0
- package/dist/tools/get-payment-rates.js +37 -0
- package/dist/tools/get-payment-rates.js.map +1 -0
- package/dist/tools/list-grant-options.d.ts +56 -0
- package/dist/tools/list-grant-options.d.ts.map +1 -0
- package/dist/tools/list-grant-options.js +39 -0
- package/dist/tools/list-grant-options.js.map +1 -0
- package/dist/tools/list-sources.d.ts +18 -0
- package/dist/tools/list-sources.d.ts.map +1 -0
- package/dist/tools/list-sources.js +51 -0
- package/dist/tools/list-sources.js.map +1 -0
- package/dist/tools/search-application-guidance.d.ts +36 -0
- package/dist/tools/search-application-guidance.d.ts.map +1 -0
- package/dist/tools/search-application-guidance.js +52 -0
- package/dist/tools/search-application-guidance.js.map +1 -0
- package/dist/tools/search-grants.d.ts +25 -0
- package/dist/tools/search-grants.d.ts.map +1 -0
- package/dist/tools/search-grants.js +26 -0
- package/dist/tools/search-grants.js.map +1 -0
- package/docker-compose.yml +12 -0
- package/eslint.config.js +26 -0
- package/package.json +54 -0
- package/scripts/ingest.ts +742 -0
- package/server.json +41 -0
- package/src/db.ts +208 -0
- package/src/http-server.ts +293 -0
- package/src/jurisdiction.ts +30 -0
- package/src/metadata.ts +32 -0
- package/src/server.ts +230 -0
- package/src/tools/about.ts +29 -0
- package/src/tools/check-eligibility.ts +81 -0
- package/src/tools/check-freshness.ts +42 -0
- package/src/tools/get-application-deadlines.ts +55 -0
- package/src/tools/get-grant-details.ts +51 -0
- package/src/tools/get-payment-rates.ts +60 -0
- package/src/tools/list-grant-options.ts +63 -0
- package/src/tools/list-sources.ts +65 -0
- package/src/tools/search-application-guidance.ts +59 -0
- package/src/tools/search-grants.ts +35 -0
- package/tests/db.test.ts +69 -0
- package/tests/helpers/seed-db.ts +188 -0
- package/tests/jurisdiction.test.ts +35 -0
- package/tests/tools/about.test.ts +23 -0
- package/tests/tools/check-freshness.test.ts +53 -0
- package/tests/tools/list-sources.test.ts +47 -0
- package/tests/tools/search-grants.test.ts +57 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { buildMeta } from '../metadata.js';
|
|
2
|
+
import { validateJurisdiction } from '../jurisdiction.js';
|
|
3
|
+
export function handleGetPaymentRates(db, args) {
|
|
4
|
+
const jv = validateJurisdiction(args.jurisdiction);
|
|
5
|
+
if (!jv.valid)
|
|
6
|
+
return jv.error;
|
|
7
|
+
const grant = db.get('SELECT id, name, grant_type, federal_rate_pct, max_amount, duration_years, zone_bonus FROM grants WHERE (id = ? OR LOWER(name) = LOWER(?)) AND jurisdiction = ?', [args.grant_id, args.grant_id, jv.jurisdiction]);
|
|
8
|
+
if (!grant) {
|
|
9
|
+
return {
|
|
10
|
+
error: 'not_found',
|
|
11
|
+
message: `Grant '${args.grant_id}' not found. Use search_grants to find available grant programmes.`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const zoneBonus = grant.zone_bonus ? JSON.parse(grant.zone_bonus) : null;
|
|
15
|
+
let applicableZoneInfo = null;
|
|
16
|
+
if (args.zone && zoneBonus) {
|
|
17
|
+
const zoneKey = Object.keys(zoneBonus).find(k => k.toLowerCase() === args.zone.toLowerCase());
|
|
18
|
+
applicableZoneInfo = zoneKey ? zoneBonus[zoneKey] : null;
|
|
19
|
+
}
|
|
20
|
+
const options = db.all('SELECT option_name, rate, conditions FROM grant_options WHERE grant_id = ?', [grant.id]);
|
|
21
|
+
return {
|
|
22
|
+
grant_id: grant.id,
|
|
23
|
+
grant_name: grant.name,
|
|
24
|
+
grant_type: grant.grant_type,
|
|
25
|
+
federal_rate_pct: grant.federal_rate_pct,
|
|
26
|
+
max_amount_chf: grant.max_amount,
|
|
27
|
+
duration_years: grant.duration_years,
|
|
28
|
+
zone_requested: args.zone ?? null,
|
|
29
|
+
zone_bonus: applicableZoneInfo,
|
|
30
|
+
all_zone_bonuses: zoneBonus,
|
|
31
|
+
rate_options: options,
|
|
32
|
+
jurisdiction: jv.jurisdiction,
|
|
33
|
+
currency: 'CHF',
|
|
34
|
+
_meta: buildMeta(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=get-payment-rates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-payment-rates.js","sourceRoot":"","sources":["../../src/tools/get-payment-rates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAS1D,MAAM,UAAU,qBAAqB,CAAC,EAAY,EAAE,IAAsB;IACxE,MAAM,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAE/B,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAIlB,iKAAiK,EACjK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,CAChD,CAAC;IAEF,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,KAAK,EAAE,WAAW;YAClB,OAAO,EAAE,UAAU,IAAI,CAAC,QAAQ,oEAAoE;SACrG,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAA2B,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnG,IAAI,kBAAkB,GAAkB,IAAI,CAAC;IAC7C,IAAI,IAAI,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,IAAK,CAAC,WAAW,EAAE,CAAC,CAAC;QAC/F,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAGpB,4EAA4E,EAC5E,CAAC,KAAK,CAAC,EAAE,CAAC,CACX,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,KAAK,CAAC,EAAE;QAClB,UAAU,EAAE,KAAK,CAAC,IAAI;QACtB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,cAAc,EAAE,KAAK,CAAC,UAAU;QAChC,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,cAAc,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;QACjC,UAAU,EAAE,kBAAkB;QAC9B,gBAAgB,EAAE,SAAS;QAC3B,YAAY,EAAE,OAAO;QACrB,YAAY,EAAE,EAAE,CAAC,YAAY;QAC7B,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,SAAS,EAAE;KACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Database } from '../db.js';
|
|
2
|
+
interface ListGrantOptionsArgs {
|
|
3
|
+
grant_id?: string;
|
|
4
|
+
jurisdiction?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function handleListGrantOptions(db: Database, args: ListGrantOptionsArgs): {
|
|
7
|
+
error: string;
|
|
8
|
+
supported: readonly string[];
|
|
9
|
+
message: string;
|
|
10
|
+
} | {
|
|
11
|
+
error: string;
|
|
12
|
+
message: string;
|
|
13
|
+
grant_id?: undefined;
|
|
14
|
+
grant_name?: undefined;
|
|
15
|
+
jurisdiction?: undefined;
|
|
16
|
+
options_count?: undefined;
|
|
17
|
+
options?: undefined;
|
|
18
|
+
_meta?: undefined;
|
|
19
|
+
grants_count?: undefined;
|
|
20
|
+
grants?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
grant_id: string;
|
|
23
|
+
grant_name: string;
|
|
24
|
+
jurisdiction: "CH";
|
|
25
|
+
options_count: number;
|
|
26
|
+
options: {
|
|
27
|
+
id: number;
|
|
28
|
+
option_name: string;
|
|
29
|
+
description: string;
|
|
30
|
+
rate: string;
|
|
31
|
+
conditions: string;
|
|
32
|
+
}[];
|
|
33
|
+
_meta: import("../metadata.js").Meta;
|
|
34
|
+
error?: undefined;
|
|
35
|
+
message?: undefined;
|
|
36
|
+
grants_count?: undefined;
|
|
37
|
+
grants?: undefined;
|
|
38
|
+
} | {
|
|
39
|
+
jurisdiction: "CH";
|
|
40
|
+
grants_count: number;
|
|
41
|
+
grants: {
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
grant_type: string;
|
|
45
|
+
option_count: number;
|
|
46
|
+
}[];
|
|
47
|
+
_meta: import("../metadata.js").Meta;
|
|
48
|
+
error?: undefined;
|
|
49
|
+
message?: undefined;
|
|
50
|
+
grant_id?: undefined;
|
|
51
|
+
grant_name?: undefined;
|
|
52
|
+
options_count?: undefined;
|
|
53
|
+
options?: undefined;
|
|
54
|
+
};
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=list-grant-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-grant-options.d.ts","sourceRoot":"","sources":["../../src/tools/list-grant-options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,oBAAoB;;;;;;;;;;;;;;;;;;;;;YAkBrE,MAAM;qBAAe,MAAM;qBAAe,MAAM;cAAQ,MAAM;oBAAc,MAAM;;;;;;;;;;;YAkBpF,MAAM;cAAQ,MAAM;oBAAc,MAAM;sBAAgB,MAAM;;;;;;;;;EAiBrE"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { buildMeta } from '../metadata.js';
|
|
2
|
+
import { validateJurisdiction } from '../jurisdiction.js';
|
|
3
|
+
export function handleListGrantOptions(db, args) {
|
|
4
|
+
const jv = validateJurisdiction(args.jurisdiction);
|
|
5
|
+
if (!jv.valid)
|
|
6
|
+
return jv.error;
|
|
7
|
+
if (args.grant_id) {
|
|
8
|
+
const grant = db.get('SELECT id, name FROM grants WHERE (id = ? OR LOWER(name) = LOWER(?)) AND jurisdiction = ?', [args.grant_id, args.grant_id, jv.jurisdiction]);
|
|
9
|
+
if (!grant) {
|
|
10
|
+
return {
|
|
11
|
+
error: 'not_found',
|
|
12
|
+
message: `Grant '${args.grant_id}' not found. Use search_grants to find available grant programmes.`,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const options = db.all('SELECT id, option_name, description, rate, conditions FROM grant_options WHERE grant_id = ?', [grant.id]);
|
|
16
|
+
return {
|
|
17
|
+
grant_id: grant.id,
|
|
18
|
+
grant_name: grant.name,
|
|
19
|
+
jurisdiction: jv.jurisdiction,
|
|
20
|
+
options_count: options.length,
|
|
21
|
+
options,
|
|
22
|
+
_meta: buildMeta(),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// List all grants with their option counts
|
|
26
|
+
const grants = db.all(`SELECT g.id, g.name, g.grant_type, COUNT(o.id) as option_count
|
|
27
|
+
FROM grants g
|
|
28
|
+
LEFT JOIN grant_options o ON g.id = o.grant_id
|
|
29
|
+
WHERE g.jurisdiction = ?
|
|
30
|
+
GROUP BY g.id
|
|
31
|
+
ORDER BY g.grant_type, g.name`, [jv.jurisdiction]);
|
|
32
|
+
return {
|
|
33
|
+
jurisdiction: jv.jurisdiction,
|
|
34
|
+
grants_count: grants.length,
|
|
35
|
+
grants,
|
|
36
|
+
_meta: buildMeta(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=list-grant-options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-grant-options.js","sourceRoot":"","sources":["../../src/tools/list-grant-options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAQ1D,MAAM,UAAU,sBAAsB,CAAC,EAAY,EAAE,IAA0B;IAC7E,MAAM,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAE/B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,EAAE,CAAC,GAAG,CAClB,2FAA2F,EAC3F,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAY,CAAC,CAChD,CAAC;QAEF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;gBACL,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE,UAAU,IAAI,CAAC,QAAQ,oEAAoE;aACrG,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,EAAE,CAAC,GAAG,CAGpB,6FAA6F,EAC7F,CAAC,KAAK,CAAC,EAAE,CAAC,CACX,CAAC;QAEF,OAAO;YACL,QAAQ,EAAE,KAAK,CAAC,EAAE;YAClB,UAAU,EAAE,KAAK,CAAC,IAAI;YACtB,YAAY,EAAE,EAAE,CAAC,YAAY;YAC7B,aAAa,EAAE,OAAO,CAAC,MAAM;YAC7B,OAAO;YACP,KAAK,EAAE,SAAS,EAAE;SACnB,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,CAGnB;;;;;mCAK+B,EAC/B,CAAC,EAAE,CAAC,YAAY,CAAC,CAClB,CAAC;IAEF,OAAO;QACL,YAAY,EAAE,EAAE,CAAC,YAAY;QAC7B,YAAY,EAAE,MAAM,CAAC,MAAM;QAC3B,MAAM;QACN,KAAK,EAAE,SAAS,EAAE;KACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { buildMeta } from '../metadata.js';
|
|
2
|
+
import type { Database } from '../db.js';
|
|
3
|
+
interface Source {
|
|
4
|
+
name: string;
|
|
5
|
+
authority: string;
|
|
6
|
+
official_url: string;
|
|
7
|
+
retrieval_method: string;
|
|
8
|
+
update_frequency: string;
|
|
9
|
+
license: string;
|
|
10
|
+
coverage: string;
|
|
11
|
+
last_retrieved?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function handleListSources(db: Database): {
|
|
14
|
+
sources: Source[];
|
|
15
|
+
_meta: ReturnType<typeof buildMeta>;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=list-sources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-sources.d.ts","sourceRoot":"","sources":["../../src/tools/list-sources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAA;CAAE,CAkD1G"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { buildMeta } from '../metadata.js';
|
|
2
|
+
export function handleListSources(db) {
|
|
3
|
+
const lastIngest = db.get('SELECT value FROM db_metadata WHERE key = ?', ['last_ingest']);
|
|
4
|
+
const sources = [
|
|
5
|
+
{
|
|
6
|
+
name: 'Strukturverbesserungsverordnung (SVV, SR 913.1)',
|
|
7
|
+
authority: 'Bundesamt fuer Landwirtschaft (BLW)',
|
|
8
|
+
official_url: 'https://www.blw.admin.ch/blw/de/home/instrumente/strukturverbesserungen.html',
|
|
9
|
+
retrieval_method: 'PDF_EXTRACT',
|
|
10
|
+
update_frequency: 'annual (with ordinance updates)',
|
|
11
|
+
license: 'Swiss Federal Administration — free reuse',
|
|
12
|
+
coverage: 'Investment credits, capital grants, eligibility criteria, contribution rates',
|
|
13
|
+
last_retrieved: lastIngest?.value,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'BLW Weisungen Investitionskredite und Beitraege',
|
|
17
|
+
authority: 'Bundesamt fuer Landwirtschaft (BLW)',
|
|
18
|
+
official_url: 'https://www.blw.admin.ch/blw/de/home/instrumente/strukturverbesserungen/investitionskredite.html',
|
|
19
|
+
retrieval_method: 'PDF_EXTRACT',
|
|
20
|
+
update_frequency: 'annual',
|
|
21
|
+
license: 'Swiss Federal Administration — free reuse',
|
|
22
|
+
coverage: 'Detailed rules on investment credit eligibility, loan terms, project types',
|
|
23
|
+
last_retrieved: lastIngest?.value,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'Kantonale Landwirtschaftsaemter — Strukturverbesserungen',
|
|
27
|
+
authority: 'Kantonale Landwirtschaftsaemter',
|
|
28
|
+
official_url: 'https://www.agridea.ch',
|
|
29
|
+
retrieval_method: 'MANUAL_RESEARCH',
|
|
30
|
+
update_frequency: 'variable (per canton)',
|
|
31
|
+
license: 'Cantonal public information',
|
|
32
|
+
coverage: 'Cantonal contribution rates, additional cantonal programmes, deadlines',
|
|
33
|
+
last_retrieved: lastIngest?.value,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'AGRIDEA Beratungsunterlagen Strukturverbesserungen',
|
|
37
|
+
authority: 'AGRIDEA',
|
|
38
|
+
official_url: 'https://www.agridea.ch',
|
|
39
|
+
retrieval_method: 'MANUAL_RESEARCH',
|
|
40
|
+
update_frequency: 'periodic',
|
|
41
|
+
license: 'AGRIDEA — educational use',
|
|
42
|
+
coverage: 'Project planning guidance, application procedures, cost estimates',
|
|
43
|
+
last_retrieved: lastIngest?.value,
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
return {
|
|
47
|
+
sources,
|
|
48
|
+
_meta: buildMeta(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=list-sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-sources.js","sourceRoot":"","sources":["../../src/tools/list-sources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAc3C,MAAM,UAAU,iBAAiB,CAAC,EAAY;IAC5C,MAAM,UAAU,GAAG,EAAE,CAAC,GAAG,CAAoB,6CAA6C,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;IAE7G,MAAM,OAAO,GAAa;QACxB;YACE,IAAI,EAAE,iDAAiD;YACvD,SAAS,EAAE,qCAAqC;YAChD,YAAY,EAAE,8EAA8E;YAC5F,gBAAgB,EAAE,aAAa;YAC/B,gBAAgB,EAAE,iCAAiC;YACnD,OAAO,EAAE,2CAA2C;YACpD,QAAQ,EAAE,8EAA8E;YACxF,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;QACD;YACE,IAAI,EAAE,iDAAiD;YACvD,SAAS,EAAE,qCAAqC;YAChD,YAAY,EAAE,kGAAkG;YAChH,gBAAgB,EAAE,aAAa;YAC/B,gBAAgB,EAAE,QAAQ;YAC1B,OAAO,EAAE,2CAA2C;YACpD,QAAQ,EAAE,4EAA4E;YACtF,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;QACD;YACE,IAAI,EAAE,0DAA0D;YAChE,SAAS,EAAE,iCAAiC;YAC5C,YAAY,EAAE,wBAAwB;YACtC,gBAAgB,EAAE,iBAAiB;YACnC,gBAAgB,EAAE,uBAAuB;YACzC,OAAO,EAAE,6BAA6B;YACtC,QAAQ,EAAE,wEAAwE;YAClF,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;QACD;YACE,IAAI,EAAE,oDAAoD;YAC1D,SAAS,EAAE,SAAS;YACpB,YAAY,EAAE,wBAAwB;YACtC,gBAAgB,EAAE,iBAAiB;YACnC,gBAAgB,EAAE,UAAU;YAC5B,OAAO,EAAE,2BAA2B;YACpC,QAAQ,EAAE,mEAAmE;YAC7E,cAAc,EAAE,UAAU,EAAE,KAAK;SAClC;KACF,CAAC;IAEF,OAAO;QACL,OAAO;QACP,KAAK,EAAE,SAAS,EAAE;KACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type Database } from '../db.js';
|
|
2
|
+
interface GuidanceArgs {
|
|
3
|
+
query: string;
|
|
4
|
+
jurisdiction?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function handleSearchApplicationGuidance(db: Database, args: GuidanceArgs): {
|
|
7
|
+
error: string;
|
|
8
|
+
supported: readonly string[];
|
|
9
|
+
message: string;
|
|
10
|
+
} | {
|
|
11
|
+
query: string;
|
|
12
|
+
jurisdiction: "CH";
|
|
13
|
+
search_results_count: number;
|
|
14
|
+
search_results: {
|
|
15
|
+
title: string;
|
|
16
|
+
body: string;
|
|
17
|
+
grant_type: string;
|
|
18
|
+
relevance_rank: number;
|
|
19
|
+
}[];
|
|
20
|
+
application_guidance: {
|
|
21
|
+
general_process: string[];
|
|
22
|
+
required_documents: string[];
|
|
23
|
+
contact_points: ({
|
|
24
|
+
role: string;
|
|
25
|
+
description: string;
|
|
26
|
+
url?: undefined;
|
|
27
|
+
} | {
|
|
28
|
+
role: string;
|
|
29
|
+
description: string;
|
|
30
|
+
url: string;
|
|
31
|
+
})[];
|
|
32
|
+
};
|
|
33
|
+
_meta: import("../metadata.js").Meta;
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=search-application-guidance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-application-guidance.d.ts","sourceRoot":"","sources":["../../src/tools/search-application-guidance.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,+BAA+B,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiD/E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { buildMeta } from '../metadata.js';
|
|
2
|
+
import { validateJurisdiction } from '../jurisdiction.js';
|
|
3
|
+
import { ftsSearch } from '../db.js';
|
|
4
|
+
export function handleSearchApplicationGuidance(db, args) {
|
|
5
|
+
const jv = validateJurisdiction(args.jurisdiction);
|
|
6
|
+
if (!jv.valid)
|
|
7
|
+
return jv.error;
|
|
8
|
+
// Search across grants for application-related content
|
|
9
|
+
const results = ftsSearch(db, args.query, 20);
|
|
10
|
+
// Also return general application guidance
|
|
11
|
+
const guidance = {
|
|
12
|
+
general_process: [
|
|
13
|
+
'Gesuch beim kantonalen Landwirtschaftsamt einreichen (vor Baubeginn)',
|
|
14
|
+
'Vorabklaerung mit kantonaler Fachstelle empfohlen',
|
|
15
|
+
'Kostenvoranschlag und Plaene beilegen',
|
|
16
|
+
'Baubewilligung der Gemeinde erforderlich (separat)',
|
|
17
|
+
'Bauausfuehrung erst nach Bewilligung beginnen — sonst kein Beitrag',
|
|
18
|
+
'Abrechnung nach Fertigstellung mit Rechnungsbelegen',
|
|
19
|
+
'AGRIDEA-Beratung fuer Projektentwicklung verfuegbar',
|
|
20
|
+
],
|
|
21
|
+
required_documents: [
|
|
22
|
+
'Gesuchsformular (kantonal)',
|
|
23
|
+
'Betriebskonzept / Businessplan',
|
|
24
|
+
'Bau- und Situationsplaene',
|
|
25
|
+
'Kostenvoranschlag (3 Offerten bei grossen Projekten)',
|
|
26
|
+
'Finanzierungsplan (Eigenkapital, Kredit, Beitraege)',
|
|
27
|
+
'Bodennutzungsplan / SAK-Berechnung',
|
|
28
|
+
'Baubewilligung oder Vorentscheid',
|
|
29
|
+
'Bei Gemeinschaftsprojekten: Statuten / Vereinbarung',
|
|
30
|
+
],
|
|
31
|
+
contact_points: [
|
|
32
|
+
{ role: 'Kantonales Landwirtschaftsamt', description: 'Erstanlaufstelle, Gesuchseinreichung, kantonale Beitraege' },
|
|
33
|
+
{ role: 'AGRIDEA', description: 'Projektberatung, Machbarkeitsstudien, Wirtschaftlichkeitsberechnungen', url: 'https://www.agridea.ch' },
|
|
34
|
+
{ role: 'Schweizer Berghilfe', description: 'Ergaenzende private Foerderung fuer Bergbetriebe', url: 'https://www.berghilfe.ch' },
|
|
35
|
+
{ role: 'BLW Strukturverbesserungen', description: 'Bundesebene, Investitionskredite', url: 'https://www.blw.admin.ch/blw/de/home/instrumente/strukturverbesserungen.html' },
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
query: args.query,
|
|
40
|
+
jurisdiction: jv.jurisdiction,
|
|
41
|
+
search_results_count: results.length,
|
|
42
|
+
search_results: results.map(r => ({
|
|
43
|
+
title: r.title,
|
|
44
|
+
body: r.body,
|
|
45
|
+
grant_type: r.grant_type,
|
|
46
|
+
relevance_rank: r.rank,
|
|
47
|
+
})),
|
|
48
|
+
application_guidance: guidance,
|
|
49
|
+
_meta: buildMeta(),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=search-application-guidance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-application-guidance.js","sourceRoot":"","sources":["../../src/tools/search-application-guidance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAiB,MAAM,UAAU,CAAC;AAOpD,MAAM,UAAU,+BAA+B,CAAC,EAAY,EAAE,IAAkB;IAC9E,MAAM,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAE/B,uDAAuD;IACvD,MAAM,OAAO,GAAG,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE9C,2CAA2C;IAC3C,MAAM,QAAQ,GAAG;QACf,eAAe,EAAE;YACf,sEAAsE;YACtE,mDAAmD;YACnD,uCAAuC;YACvC,oDAAoD;YACpD,oEAAoE;YACpE,qDAAqD;YACrD,qDAAqD;SACtD;QACD,kBAAkB,EAAE;YAClB,4BAA4B;YAC5B,gCAAgC;YAChC,2BAA2B;YAC3B,sDAAsD;YACtD,qDAAqD;YACrD,oCAAoC;YACpC,kCAAkC;YAClC,qDAAqD;SACtD;QACD,cAAc,EAAE;YACd,EAAE,IAAI,EAAE,+BAA+B,EAAE,WAAW,EAAE,2DAA2D,EAAE;YACnH,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,uEAAuE,EAAE,GAAG,EAAE,wBAAwB,EAAE;YACxI,EAAE,IAAI,EAAE,qBAAqB,EAAE,WAAW,EAAE,kDAAkD,EAAE,GAAG,EAAE,0BAA0B,EAAE;YACjI,EAAE,IAAI,EAAE,4BAA4B,EAAE,WAAW,EAAE,kCAAkC,EAAE,GAAG,EAAE,8EAA8E,EAAE;SAC7K;KACF,CAAC;IAEF,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,YAAY,EAAE,EAAE,CAAC,YAAY;QAC7B,oBAAoB,EAAE,OAAO,CAAC,MAAM;QACpC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChC,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,cAAc,EAAE,CAAC,CAAC,IAAI;SACvB,CAAC,CAAC;QACH,oBAAoB,EAAE,QAAQ;QAC9B,KAAK,EAAE,SAAS,EAAE;KACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Database } from '../db.js';
|
|
2
|
+
interface SearchArgs {
|
|
3
|
+
query: string;
|
|
4
|
+
grant_type?: string;
|
|
5
|
+
jurisdiction?: string;
|
|
6
|
+
limit?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function handleSearchGrants(db: Database, args: SearchArgs): {
|
|
9
|
+
error: string;
|
|
10
|
+
supported: readonly string[];
|
|
11
|
+
message: string;
|
|
12
|
+
} | {
|
|
13
|
+
query: string;
|
|
14
|
+
jurisdiction: "CH";
|
|
15
|
+
results_count: number;
|
|
16
|
+
results: {
|
|
17
|
+
title: string;
|
|
18
|
+
body: string;
|
|
19
|
+
grant_type: string;
|
|
20
|
+
relevance_rank: number;
|
|
21
|
+
}[];
|
|
22
|
+
_meta: import("../metadata.js").Meta;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=search-grants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-grants.d.ts","sourceRoot":"","sources":["../../src/tools/search-grants.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpD,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU;;;;;;;;;;;;;;;EAuBhE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { buildMeta } from '../metadata.js';
|
|
2
|
+
import { validateJurisdiction } from '../jurisdiction.js';
|
|
3
|
+
import { ftsSearch } from '../db.js';
|
|
4
|
+
export function handleSearchGrants(db, args) {
|
|
5
|
+
const jv = validateJurisdiction(args.jurisdiction);
|
|
6
|
+
if (!jv.valid)
|
|
7
|
+
return jv.error;
|
|
8
|
+
const limit = Math.min(args.limit ?? 20, 50);
|
|
9
|
+
let results = ftsSearch(db, args.query, limit);
|
|
10
|
+
if (args.grant_type) {
|
|
11
|
+
results = results.filter(r => r.grant_type.toLowerCase() === args.grant_type.toLowerCase());
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
query: args.query,
|
|
15
|
+
jurisdiction: jv.jurisdiction,
|
|
16
|
+
results_count: results.length,
|
|
17
|
+
results: results.map(r => ({
|
|
18
|
+
title: r.title,
|
|
19
|
+
body: r.body,
|
|
20
|
+
grant_type: r.grant_type,
|
|
21
|
+
relevance_rank: r.rank,
|
|
22
|
+
})),
|
|
23
|
+
_meta: buildMeta(),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=search-grants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-grants.js","sourceRoot":"","sources":["../../src/tools/search-grants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAiB,MAAM,UAAU,CAAC;AASpD,MAAM,UAAU,kBAAkB,CAAC,EAAY,EAAE,IAAgB;IAC/D,MAAM,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,IAAI,OAAO,GAAG,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAE/C,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,UAAW,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,YAAY,EAAE,EAAE,CAAC,YAAY;QAC7B,aAAa,EAAE,OAAO,CAAC,MAAM;QAC7B,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,cAAc,EAAE,CAAC,CAAC,IAAI;SACvB,CAAC,CAAC;QACH,KAAK,EAAE,SAAS,EAAE;KACnB,CAAC;AACJ,CAAC"}
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import tseslint from '@typescript-eslint/eslint-plugin';
|
|
2
|
+
import tsparser from '@typescript-eslint/parser';
|
|
3
|
+
|
|
4
|
+
export default [
|
|
5
|
+
{
|
|
6
|
+
files: ['src/**/*.ts', 'tests/**/*.ts'],
|
|
7
|
+
languageOptions: {
|
|
8
|
+
parser: tsparser,
|
|
9
|
+
parserOptions: {
|
|
10
|
+
ecmaVersion: 2022,
|
|
11
|
+
sourceType: 'module',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
plugins: {
|
|
15
|
+
'@typescript-eslint': tseslint,
|
|
16
|
+
},
|
|
17
|
+
rules: {
|
|
18
|
+
...tseslint.configs.recommended.rules,
|
|
19
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
20
|
+
'no-console': 'off',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
ignores: ['dist/', 'node_modules/', 'scripts/'],
|
|
25
|
+
},
|
|
26
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ansvar/ch-farm-grants-mcp",
|
|
3
|
+
"mcpName": "io.github.ansvar-systems/ch-farm-grants",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Swiss farm grants and structural improvement via MCP",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/server.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"ch-farm-grants-mcp": "dist/server.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsx watch src/server.ts",
|
|
14
|
+
"start": "node dist/server.js",
|
|
15
|
+
"start:http": "node dist/http-server.js",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest",
|
|
18
|
+
"lint": "eslint src/ tests/",
|
|
19
|
+
"typecheck": "tsc --noEmit",
|
|
20
|
+
"ingest": "tsx scripts/ingest.ts",
|
|
21
|
+
"ingest:fetch": "tsx scripts/ingest.ts --fetch-only",
|
|
22
|
+
"ingest:diff": "tsx scripts/ingest.ts --diff-only",
|
|
23
|
+
"ingest:full": "tsx scripts/ingest.ts --force",
|
|
24
|
+
"build:db": "tsx scripts/build-db.ts",
|
|
25
|
+
"freshness:check": "tsx scripts/check-freshness.ts",
|
|
26
|
+
"coverage:update": "tsx scripts/update-coverage.ts"
|
|
27
|
+
},
|
|
28
|
+
"keywords": ["mcp", "agriculture", "grants", "strukturverbesserungen", "investitionskredit", "farming", "switzerland"],
|
|
29
|
+
"author": "Ansvar Systems <info@ansvar.eu>",
|
|
30
|
+
"license": "Apache-2.0",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/Ansvar-Systems/ch-farm-grants-mcp"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://ansvar.eu/open-agriculture",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
41
|
+
"better-sqlite3": "^11.0.0",
|
|
42
|
+
"zod": "^3.23.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
46
|
+
"@types/node": "^20.0.0",
|
|
47
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
48
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
49
|
+
"eslint": "^9.0.0",
|
|
50
|
+
"tsx": "^4.0.0",
|
|
51
|
+
"typescript": "^5.5.0",
|
|
52
|
+
"vitest": "^2.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|