@cyanheads/congressgov-mcp-server 0.7.0 → 0.7.2
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/AGENTS.md +31 -19
- package/CLAUDE.md +31 -19
- package/Dockerfile +2 -2
- package/README.md +216 -92
- package/changelog/0.1.x/0.1.0.md +36 -0
- package/changelog/0.2.x/0.2.0.md +26 -0
- package/changelog/0.2.x/0.2.1.md +16 -0
- package/changelog/0.3.x/0.3.0.md +26 -0
- package/changelog/0.3.x/0.3.1.md +14 -0
- package/changelog/0.3.x/0.3.10.md +15 -0
- package/changelog/0.3.x/0.3.11.md +18 -0
- package/changelog/0.3.x/0.3.12.md +15 -0
- package/changelog/0.3.x/0.3.13.md +20 -0
- package/changelog/0.3.x/0.3.14.md +30 -0
- package/changelog/0.3.x/0.3.15.md +28 -0
- package/changelog/0.3.x/0.3.16.md +34 -0
- package/changelog/0.3.x/0.3.17.md +28 -0
- package/changelog/0.3.x/0.3.18.md +18 -0
- package/changelog/0.3.x/0.3.19.md +36 -0
- package/changelog/0.3.x/0.3.2.md +12 -0
- package/changelog/0.3.x/0.3.20.md +22 -0
- package/changelog/0.3.x/0.3.21.md +15 -0
- package/changelog/0.3.x/0.3.22.md +29 -0
- package/changelog/0.3.x/0.3.23.md +25 -0
- package/changelog/0.3.x/0.3.24.md +20 -0
- package/changelog/0.3.x/0.3.25.md +12 -0
- package/changelog/0.3.x/0.3.26.md +25 -0
- package/changelog/0.3.x/0.3.27.md +16 -0
- package/changelog/0.3.x/0.3.28.md +18 -0
- package/changelog/0.3.x/0.3.29.md +13 -0
- package/changelog/0.3.x/0.3.3.md +11 -0
- package/changelog/0.3.x/0.3.30.md +28 -0
- package/changelog/0.3.x/0.3.31.md +28 -0
- package/changelog/0.3.x/0.3.32.md +21 -0
- package/changelog/0.3.x/0.3.4.md +18 -0
- package/changelog/0.3.x/0.3.5.md +23 -0
- package/changelog/0.3.x/0.3.6.md +10 -0
- package/changelog/0.3.x/0.3.7.md +15 -0
- package/changelog/0.3.x/0.3.8.md +29 -0
- package/changelog/0.3.x/0.3.9.md +21 -0
- package/changelog/0.4.x/0.4.0.md +28 -0
- package/changelog/0.4.x/0.4.1.md +17 -0
- package/changelog/0.4.x/0.4.2.md +39 -0
- package/changelog/0.4.x/0.4.3.md +16 -0
- package/changelog/0.5.x/0.5.0.md +22 -0
- package/changelog/0.5.x/0.5.1.md +16 -0
- package/changelog/0.5.x/0.5.2.md +29 -0
- package/changelog/0.6.x/0.6.0.md +24 -0
- package/changelog/0.7.x/0.7.0.md +13 -0
- package/changelog/0.7.x/0.7.1.md +35 -0
- package/changelog/0.7.x/0.7.2.md +20 -0
- package/changelog/template.md +151 -0
- package/dist/config/server-config.d.ts +3 -3
- package/dist/config/server-config.d.ts.map +1 -1
- package/dist/config/server-config.js +6 -3
- package/dist/config/server-config.js.map +1 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/bill-lookup.tool.d.ts +12 -4
- package/dist/mcp-server/tools/definitions/bill-lookup.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/bill-lookup.tool.js +94 -3
- package/dist/mcp-server/tools/definitions/bill-lookup.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/bill-summaries.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/bill-summaries.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/bill-summaries.tool.js +34 -6
- package/dist/mcp-server/tools/definitions/bill-summaries.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/committee-lookup.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/committee-lookup.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/committee-lookup.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/committee-reports.tool.d.ts +9 -2
- package/dist/mcp-server/tools/definitions/committee-reports.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/committee-reports.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/crs-reports.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/crs-reports.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/crs-reports.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/daily-record.tool.d.ts +9 -2
- package/dist/mcp-server/tools/definitions/daily-record.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/daily-record.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/enacted-laws.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/enacted-laws.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/enacted-laws.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/member-lookup.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/member-lookup.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/member-lookup.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/roll-votes.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/roll-votes.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/roll-votes.tool.js +2 -2
- package/dist/mcp-server/tools/definitions/search-bills.tool.d.ts +1 -1
- package/dist/mcp-server/tools/definitions/search-bills.tool.js +3 -3
- package/dist/mcp-server/tools/definitions/senate-nominations.tool.d.ts +4 -0
- package/dist/mcp-server/tools/definitions/senate-nominations.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/senate-nominations.tool.js +2 -2
- package/dist/mcp-server/tools/format-helpers.d.ts.map +1 -1
- package/dist/mcp-server/tools/format-helpers.js +85 -30
- package/dist/mcp-server/tools/format-helpers.js.map +1 -1
- package/dist/mcp-server/tools/summary-window.d.ts +112 -0
- package/dist/mcp-server/tools/summary-window.d.ts.map +1 -0
- package/dist/mcp-server/tools/summary-window.js +182 -0
- package/dist/mcp-server/tools/summary-window.js.map +1 -0
- package/dist/mcp-server/tools/tool-helpers.d.ts +26 -2
- package/dist/mcp-server/tools/tool-helpers.d.ts.map +1 -1
- package/dist/mcp-server/tools/tool-helpers.js +26 -2
- package/dist/mcp-server/tools/tool-helpers.js.map +1 -1
- package/dist/services/congress-api/congress-api-service.d.ts.map +1 -1
- package/dist/services/congress-api/congress-api-service.js +8 -11
- package/dist/services/congress-api/congress-api-service.js.map +1 -1
- package/dist/services/congress-documents/congress-documents-service.d.ts.map +1 -1
- package/dist/services/congress-documents/congress-documents-service.js +10 -9
- package/dist/services/congress-documents/congress-documents-service.js.map +1 -1
- package/dist/services/congress-documents/extract-text-stream.js +1 -1
- package/dist/services/congress-documents/extract-text-stream.js.map +1 -1
- package/dist/services/congress-documents/extract-text.d.ts +0 -6
- package/dist/services/congress-documents/extract-text.d.ts.map +1 -1
- package/dist/services/congress-documents/extract-text.js +4 -37
- package/dist/services/congress-documents/extract-text.js.map +1 -1
- package/dist/services/congress-mirror/congress-mirror-service.js +1 -1
- package/dist/services/congress-mirror/ingest.d.ts +1 -1
- package/dist/services/congress-mirror/normalize.d.ts +4 -1
- package/dist/services/congress-mirror/normalize.d.ts.map +1 -1
- package/dist/services/congress-mirror/normalize.js +8 -12
- package/dist/services/congress-mirror/normalize.js.map +1 -1
- package/dist/services/congress-mirror/types.d.ts +1 -1
- package/dist/services/senate-lis/parse.d.ts.map +1 -1
- package/dist/services/senate-lis/parse.js +74 -2
- package/dist/services/senate-lis/parse.js.map +1 -1
- package/dist/services/senate-lis/senate-vote-service.d.ts.map +1 -1
- package/dist/services/senate-lis/senate-vote-service.js +9 -7
- package/dist/services/senate-lis/senate-vote-service.js.map +1 -1
- package/dist/services/senate-lis/types.d.ts +8 -1
- package/dist/services/senate-lis/types.d.ts.map +1 -1
- package/dist/utils/character-references.d.ts +27 -0
- package/dist/utils/character-references.d.ts.map +1 -0
- package/dist/utils/character-references.js +60 -0
- package/dist/utils/character-references.js.map +1 -0
- package/package.json +11 -9
- package/server.json +3 -3
|
@@ -21,24 +21,28 @@ export declare const crsReportsTool: import("@cyanheads/mcp-ts-core").ToolDefini
|
|
|
21
21
|
}, z.core.$loose>, readonly [{
|
|
22
22
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
23
23
|
readonly reason: 'not_found';
|
|
24
|
+
readonly thrownBy: 'service';
|
|
24
25
|
readonly retryable: false;
|
|
25
26
|
readonly when: 'A requested bill, member, committee, report, vote, or nomination does not exist in Congress.gov.';
|
|
26
27
|
readonly recovery: "Use the tool's list or browse operation to discover valid identifiers, then retry with one that exists.";
|
|
27
28
|
}, {
|
|
28
29
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
29
30
|
readonly reason: 'rate_limited';
|
|
31
|
+
readonly thrownBy: 'service';
|
|
30
32
|
readonly retryable: true;
|
|
31
33
|
readonly when: 'The Congress.gov API rate limit (5,000 requests/hour per key) was exceeded.';
|
|
32
34
|
readonly recovery: 'Wait for the hourly rate-limit window to reset before retrying, or reduce the request frequency.';
|
|
33
35
|
}, {
|
|
34
36
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
35
37
|
readonly reason: 'invalid_request';
|
|
38
|
+
readonly thrownBy: 'service';
|
|
36
39
|
readonly retryable: false;
|
|
37
40
|
readonly when: 'Congress.gov rejected the request as malformed — a bad date range or an identifier with an unexpected shape.';
|
|
38
41
|
readonly recovery: 'Check parameter formats: dates must be ISO 8601 like 2026-05-01T00:00:00Z and identifiers must match their documented shape.';
|
|
39
42
|
}, {
|
|
40
43
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
41
44
|
readonly reason: 'upstream_error';
|
|
45
|
+
readonly thrownBy: 'service';
|
|
42
46
|
readonly retryable: true;
|
|
43
47
|
readonly when: 'Congress.gov returned an unexpected error (5xx or another non-2xx status).';
|
|
44
48
|
readonly recovery: 'Retry after a short delay; if the failure persists the Congress.gov service may be temporarily degraded.';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crs-reports.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/crs-reports.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAYjD,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"crs-reports.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/crs-reports.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAYjD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkDzB,CAAC"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import { formatCrsReports } from '
|
|
8
|
-
import { congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '
|
|
7
|
+
import { formatCrsReports } from '../format-helpers.js';
|
|
8
|
+
import { congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '../tool-helpers.js';
|
|
9
9
|
import { getCongressApi } from '../../../services/congress-api/congress-api-service.js';
|
|
10
10
|
export const crsReportsTool = tool('congressgov_crs_reports', {
|
|
11
11
|
title: 'Congress.gov CRS Reports',
|
|
@@ -31,24 +31,28 @@ export declare const dailyRecordTool: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
31
31
|
}, z.core.$loose>, readonly [{
|
|
32
32
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
33
33
|
readonly reason: 'not_found';
|
|
34
|
+
readonly thrownBy: 'service';
|
|
34
35
|
readonly retryable: false;
|
|
35
36
|
readonly when: 'A requested bill, member, committee, report, vote, or nomination does not exist in Congress.gov.';
|
|
36
37
|
readonly recovery: "Use the tool's list or browse operation to discover valid identifiers, then retry with one that exists.";
|
|
37
38
|
}, {
|
|
38
39
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
39
40
|
readonly reason: 'rate_limited';
|
|
41
|
+
readonly thrownBy: 'service';
|
|
40
42
|
readonly retryable: true;
|
|
41
43
|
readonly when: 'The Congress.gov API rate limit (5,000 requests/hour per key) was exceeded.';
|
|
42
44
|
readonly recovery: 'Wait for the hourly rate-limit window to reset before retrying, or reduce the request frequency.';
|
|
43
45
|
}, {
|
|
44
46
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
45
47
|
readonly reason: 'invalid_request';
|
|
48
|
+
readonly thrownBy: 'service';
|
|
46
49
|
readonly retryable: false;
|
|
47
50
|
readonly when: 'Congress.gov rejected the request as malformed — a bad date range or an identifier with an unexpected shape.';
|
|
48
51
|
readonly recovery: 'Check parameter formats: dates must be ISO 8601 like 2026-05-01T00:00:00Z and identifiers must match their documented shape.';
|
|
49
52
|
}, {
|
|
50
53
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
51
54
|
readonly reason: 'upstream_error';
|
|
55
|
+
readonly thrownBy: 'service';
|
|
52
56
|
readonly retryable: true;
|
|
53
57
|
readonly when: 'Congress.gov returned an unexpected error (5xx or another non-2xx status).';
|
|
54
58
|
readonly recovery: 'Retry after a short delay; if the failure persists the Congress.gov service may be temporarily degraded.';
|
|
@@ -67,21 +71,24 @@ export declare const dailyRecordTool: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
67
71
|
}, {
|
|
68
72
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
69
73
|
readonly reason: 'document_fetch_failed';
|
|
74
|
+
readonly thrownBy: 'service';
|
|
70
75
|
readonly retryable: true;
|
|
71
76
|
readonly when: 'www.congress.gov did not return a readable document — a non-2xx status, a network failure, an empty body, or a content type that is not text or XML.';
|
|
72
77
|
readonly recovery: 'Retry after a short delay; if the failure persists, request a different format or read the document at the sourceUrl the text operation returns.';
|
|
73
78
|
}, {
|
|
74
79
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
75
80
|
readonly reason: 'document_too_large';
|
|
81
|
+
readonly thrownBy: 'service';
|
|
76
82
|
readonly retryable: false;
|
|
77
83
|
readonly when: 'The document is larger than the byte ceiling this server retrieves, so no character window can be served from it.';
|
|
78
84
|
readonly recovery: 'Read the document at the sourceUrl the text operation returns. A document this size clears the ceiling in every format it publishes, so switching format reaches the same limit.';
|
|
79
85
|
}, {
|
|
80
86
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
81
87
|
readonly reason: 'offset_past_end';
|
|
88
|
+
readonly thrownBy: 'service';
|
|
82
89
|
readonly retryable: false;
|
|
83
|
-
readonly when:
|
|
84
|
-
readonly recovery:
|
|
90
|
+
readonly when: "characterOffset is at or beyond the last character of every text the call would window — the document on 'content', or every returned row's summary text on 'summaries' — so the window would be empty.";
|
|
91
|
+
readonly recovery: "Restart the walk at characterOffset 0 and follow the response's nextOffset (or a summary row's textNextOffset), which goes null once the text has been read to the end.";
|
|
85
92
|
}], {
|
|
86
93
|
effectiveQuery: z.ZodString;
|
|
87
94
|
totalCount: z.ZodNumber;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daily-record.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/daily-record.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAqBjD,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"daily-record.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/daily-record.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAqBjD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkK1B,CAAC"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import { formatDailyRecord } from '
|
|
8
|
-
import { congressErrorContracts, documentErrorContracts, documentWindowInput, listEnrichment, listOrDetail, notifyIfNoMatches, numericIdentifier, toIdentifierNumber, } from '
|
|
7
|
+
import { formatDailyRecord } from '../format-helpers.js';
|
|
8
|
+
import { congressErrorContracts, documentErrorContracts, documentWindowInput, listEnrichment, listOrDetail, notifyIfNoMatches, numericIdentifier, toIdentifierNumber, } from '../tool-helpers.js';
|
|
9
9
|
import { getCongressApi } from '../../../services/congress-api/congress-api-service.js';
|
|
10
10
|
import { getCongressDocuments } from '../../../services/congress-documents/congress-documents-service.js';
|
|
11
11
|
import { describeFormat, selectDocumentUrl, } from '../../../services/congress-documents/document-formats.js';
|
|
@@ -26,24 +26,28 @@ export declare const enactedLawsTool: import("@cyanheads/mcp-ts-core").ToolDefin
|
|
|
26
26
|
}, z.core.$loose>, readonly [{
|
|
27
27
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
28
28
|
readonly reason: 'not_found';
|
|
29
|
+
readonly thrownBy: 'service';
|
|
29
30
|
readonly retryable: false;
|
|
30
31
|
readonly when: 'A requested bill, member, committee, report, vote, or nomination does not exist in Congress.gov.';
|
|
31
32
|
readonly recovery: "Use the tool's list or browse operation to discover valid identifiers, then retry with one that exists.";
|
|
32
33
|
}, {
|
|
33
34
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
34
35
|
readonly reason: 'rate_limited';
|
|
36
|
+
readonly thrownBy: 'service';
|
|
35
37
|
readonly retryable: true;
|
|
36
38
|
readonly when: 'The Congress.gov API rate limit (5,000 requests/hour per key) was exceeded.';
|
|
37
39
|
readonly recovery: 'Wait for the hourly rate-limit window to reset before retrying, or reduce the request frequency.';
|
|
38
40
|
}, {
|
|
39
41
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
40
42
|
readonly reason: 'invalid_request';
|
|
43
|
+
readonly thrownBy: 'service';
|
|
41
44
|
readonly retryable: false;
|
|
42
45
|
readonly when: 'Congress.gov rejected the request as malformed — a bad date range or an identifier with an unexpected shape.';
|
|
43
46
|
readonly recovery: 'Check parameter formats: dates must be ISO 8601 like 2026-05-01T00:00:00Z and identifiers must match their documented shape.';
|
|
44
47
|
}, {
|
|
45
48
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
46
49
|
readonly reason: 'upstream_error';
|
|
50
|
+
readonly thrownBy: 'service';
|
|
47
51
|
readonly retryable: true;
|
|
48
52
|
readonly when: 'Congress.gov returned an unexpected error (5xx or another non-2xx status).';
|
|
49
53
|
readonly recovery: 'Retry after a short delay; if the failure persists the Congress.gov service may be temporarily degraded.';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enacted-laws.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/enacted-laws.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAejD,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"enacted-laws.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/enacted-laws.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAejD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkF1B,CAAC"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import { formatLaws } from '
|
|
8
|
-
import { buildEffectiveQuery, congressErrorContracts, lawNumberIdentifier, listEnrichment, listOrDetail, notifyIfNoMatches, toLawNumber, } from '
|
|
7
|
+
import { formatLaws } from '../format-helpers.js';
|
|
8
|
+
import { buildEffectiveQuery, congressErrorContracts, lawNumberIdentifier, listEnrichment, listOrDetail, notifyIfNoMatches, toLawNumber, } from '../tool-helpers.js';
|
|
9
9
|
import { getCongressApi } from '../../../services/congress-api/congress-api-service.js';
|
|
10
10
|
export const enactedLawsTool = tool('congressgov_enacted_laws', {
|
|
11
11
|
title: 'Congress.gov Enacted Laws',
|
|
@@ -27,24 +27,28 @@ export declare const memberLookupTool: import("@cyanheads/mcp-ts-core").ToolDefi
|
|
|
27
27
|
}, z.core.$loose>, readonly [{
|
|
28
28
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
29
29
|
readonly reason: 'not_found';
|
|
30
|
+
readonly thrownBy: 'service';
|
|
30
31
|
readonly retryable: false;
|
|
31
32
|
readonly when: 'A requested bill, member, committee, report, vote, or nomination does not exist in Congress.gov.';
|
|
32
33
|
readonly recovery: "Use the tool's list or browse operation to discover valid identifiers, then retry with one that exists.";
|
|
33
34
|
}, {
|
|
34
35
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
35
36
|
readonly reason: 'rate_limited';
|
|
37
|
+
readonly thrownBy: 'service';
|
|
36
38
|
readonly retryable: true;
|
|
37
39
|
readonly when: 'The Congress.gov API rate limit (5,000 requests/hour per key) was exceeded.';
|
|
38
40
|
readonly recovery: 'Wait for the hourly rate-limit window to reset before retrying, or reduce the request frequency.';
|
|
39
41
|
}, {
|
|
40
42
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
41
43
|
readonly reason: 'invalid_request';
|
|
44
|
+
readonly thrownBy: 'service';
|
|
42
45
|
readonly retryable: false;
|
|
43
46
|
readonly when: 'Congress.gov rejected the request as malformed — a bad date range or an identifier with an unexpected shape.';
|
|
44
47
|
readonly recovery: 'Check parameter formats: dates must be ISO 8601 like 2026-05-01T00:00:00Z and identifiers must match their documented shape.';
|
|
45
48
|
}, {
|
|
46
49
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
47
50
|
readonly reason: 'upstream_error';
|
|
51
|
+
readonly thrownBy: 'service';
|
|
48
52
|
readonly retryable: true;
|
|
49
53
|
readonly when: 'Congress.gov returned an unexpected error (5xx or another non-2xx status).';
|
|
50
54
|
readonly recovery: 'Retry after a short delay; if the failure persists the Congress.gov service may be temporarily degraded.';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"member-lookup.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/member-lookup.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAajD,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"member-lookup.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/member-lookup.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAajD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0H3B,CAAC"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import { formatMembers } from '
|
|
8
|
-
import { buildEffectiveQuery, congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '
|
|
7
|
+
import { formatMembers } from '../format-helpers.js';
|
|
8
|
+
import { buildEffectiveQuery, congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '../tool-helpers.js';
|
|
9
9
|
import { getCongressApi } from '../../../services/congress-api/congress-api-service.js';
|
|
10
10
|
export const memberLookupTool = tool('congressgov_member_lookup', {
|
|
11
11
|
title: 'Congress.gov Member Lookup',
|
|
@@ -34,24 +34,28 @@ export declare const rollVotesTool: import("@cyanheads/mcp-ts-core").ToolDefinit
|
|
|
34
34
|
}, z.core.$loose>, readonly [{
|
|
35
35
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
36
36
|
readonly reason: 'not_found';
|
|
37
|
+
readonly thrownBy: 'service';
|
|
37
38
|
readonly retryable: false;
|
|
38
39
|
readonly when: 'A requested bill, member, committee, report, vote, or nomination does not exist in Congress.gov.';
|
|
39
40
|
readonly recovery: "Use the tool's list or browse operation to discover valid identifiers, then retry with one that exists.";
|
|
40
41
|
}, {
|
|
41
42
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
42
43
|
readonly reason: 'rate_limited';
|
|
44
|
+
readonly thrownBy: 'service';
|
|
43
45
|
readonly retryable: true;
|
|
44
46
|
readonly when: 'The Congress.gov API rate limit (5,000 requests/hour per key) was exceeded.';
|
|
45
47
|
readonly recovery: 'Wait for the hourly rate-limit window to reset before retrying, or reduce the request frequency.';
|
|
46
48
|
}, {
|
|
47
49
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
48
50
|
readonly reason: 'invalid_request';
|
|
51
|
+
readonly thrownBy: 'service';
|
|
49
52
|
readonly retryable: false;
|
|
50
53
|
readonly when: 'Congress.gov rejected the request as malformed — a bad date range or an identifier with an unexpected shape.';
|
|
51
54
|
readonly recovery: 'Check parameter formats: dates must be ISO 8601 like 2026-05-01T00:00:00Z and identifiers must match their documented shape.';
|
|
52
55
|
}, {
|
|
53
56
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
54
57
|
readonly reason: 'upstream_error';
|
|
58
|
+
readonly thrownBy: 'service';
|
|
55
59
|
readonly retryable: true;
|
|
56
60
|
readonly when: 'Congress.gov returned an unexpected error (5xx or another non-2xx status).';
|
|
57
61
|
readonly recovery: 'Retry after a short delay; if the failure persists the Congress.gov service may be temporarily degraded.';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roll-votes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/roll-votes.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAcjD,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"roll-votes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/roll-votes.tool.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAcjD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4HxB,CAAC"}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
8
8
|
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
9
|
-
import { formatVotes } from '
|
|
10
|
-
import { buildEffectiveQuery, congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '
|
|
9
|
+
import { formatVotes } from '../format-helpers.js';
|
|
10
|
+
import { buildEffectiveQuery, congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '../tool-helpers.js';
|
|
11
11
|
import { getCongressApi } from '../../../services/congress-api/congress-api-service.js';
|
|
12
12
|
import { getSenateVoteService } from '../../../services/senate-lis/senate-vote-service.js';
|
|
13
13
|
export const rollVotesTool = tool('congressgov_roll_votes', {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* live fallback: a mirror that has not finished its initial build returns an empty
|
|
6
6
|
* result with an enrichment notice rather than a thrown error. Gated behind
|
|
7
7
|
* CONGRESS_MIRROR_ENABLED via disabledTool() — when the mirror is off (the
|
|
8
|
-
* default) the tool stays on the
|
|
8
|
+
* default) the tool stays on the landing page for operators but
|
|
9
9
|
* is skipped during MCP registration, so clients never see it in tools/list.
|
|
10
10
|
* @module mcp-server/tools/definitions/search-bills
|
|
11
11
|
*/
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
* live fallback: a mirror that has not finished its initial build returns an empty
|
|
6
6
|
* result with an enrichment notice rather than a thrown error. Gated behind
|
|
7
7
|
* CONGRESS_MIRROR_ENABLED via disabledTool() — when the mirror is off (the
|
|
8
|
-
* default) the tool stays on the
|
|
8
|
+
* default) the tool stays on the landing page for operators but
|
|
9
9
|
* is skipped during MCP registration, so clients never see it in tools/list.
|
|
10
10
|
* @module mcp-server/tools/definitions/search-bills
|
|
11
11
|
*/
|
|
12
12
|
import { disabledTool, tool, z } from '@cyanheads/mcp-ts-core';
|
|
13
13
|
import { getServerConfig } from '../../../config/server-config.js';
|
|
14
|
-
import { formatSearchBills } from '
|
|
15
|
-
import { buildEffectiveQuery, listEnrichment, listOutput, notifyIfNoMatches, } from '
|
|
14
|
+
import { formatSearchBills } from '../format-helpers.js';
|
|
15
|
+
import { buildEffectiveQuery, listEnrichment, listOutput, notifyIfNoMatches, } from '../tool-helpers.js';
|
|
16
16
|
import { BILL_TYPE_CODES } from '../../../services/congress-api/types.js';
|
|
17
17
|
import { getCongressMirror } from '../../../services/congress-mirror/congress-mirror-service.js';
|
|
18
18
|
const searchBillsDef = tool('congressgov_search_bills', {
|
|
@@ -27,24 +27,28 @@ export declare const senateNominationsTool: import("@cyanheads/mcp-ts-core").Too
|
|
|
27
27
|
}, z.core.$loose>, readonly [{
|
|
28
28
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
29
29
|
readonly reason: 'not_found';
|
|
30
|
+
readonly thrownBy: 'service';
|
|
30
31
|
readonly retryable: false;
|
|
31
32
|
readonly when: 'A requested bill, member, committee, report, vote, or nomination does not exist in Congress.gov.';
|
|
32
33
|
readonly recovery: "Use the tool's list or browse operation to discover valid identifiers, then retry with one that exists.";
|
|
33
34
|
}, {
|
|
34
35
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.RateLimited;
|
|
35
36
|
readonly reason: 'rate_limited';
|
|
37
|
+
readonly thrownBy: 'service';
|
|
36
38
|
readonly retryable: true;
|
|
37
39
|
readonly when: 'The Congress.gov API rate limit (5,000 requests/hour per key) was exceeded.';
|
|
38
40
|
readonly recovery: 'Wait for the hourly rate-limit window to reset before retrying, or reduce the request frequency.';
|
|
39
41
|
}, {
|
|
40
42
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
41
43
|
readonly reason: 'invalid_request';
|
|
44
|
+
readonly thrownBy: 'service';
|
|
42
45
|
readonly retryable: false;
|
|
43
46
|
readonly when: 'Congress.gov rejected the request as malformed — a bad date range or an identifier with an unexpected shape.';
|
|
44
47
|
readonly recovery: 'Check parameter formats: dates must be ISO 8601 like 2026-05-01T00:00:00Z and identifiers must match their documented shape.';
|
|
45
48
|
}, {
|
|
46
49
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
47
50
|
readonly reason: 'upstream_error';
|
|
51
|
+
readonly thrownBy: 'service';
|
|
48
52
|
readonly retryable: true;
|
|
49
53
|
readonly when: 'Congress.gov returned an unexpected error (5xx or another non-2xx status).';
|
|
50
54
|
readonly recovery: 'Retry after a short delay; if the failure persists the Congress.gov service may be temporarily degraded.';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"senate-nominations.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/senate-nominations.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAYjD,eAAO,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"senate-nominations.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/senate-nominations.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAYjD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgIhC,CAAC"}
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { validationError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
-
import { formatNominations } from '
|
|
8
|
-
import { buildEffectiveQuery, congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '
|
|
7
|
+
import { formatNominations } from '../format-helpers.js';
|
|
8
|
+
import { buildEffectiveQuery, congressErrorContracts, listEnrichment, listOrDetail, notifyIfNoMatches, } from '../tool-helpers.js';
|
|
9
9
|
import { getCongressApi } from '../../../services/congress-api/congress-api-service.js';
|
|
10
10
|
export const senateNominationsTool = tool('congressgov_senate_nominations', {
|
|
11
11
|
title: 'Congress.gov Senate Nominations',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-helpers.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/format-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;
|
|
1
|
+
{"version":3,"file":"format-helpers.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/format-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AA45DhD,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAYxE;AAgDD,2DAA2D;AAC3D,eAAO,MAAM,eAAe,WA/EhB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,EA+EkB,CAAC;AA8CpE,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,WA9HlB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,EA8HuB,CAAC;AAEzE,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAoB1E;AAWD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAkB7E;AAED,kDAAkD;AAClD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAWnF;AAED,mCAAmC;AACnC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAK7E;AAED,4FAA4F;AAC5F,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAc9E;AAED,8FAA8F;AAC9F,eAAO,MAAM,UAAU,WA7NX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,EA6NiC,CAAC;AAEnF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAcxE;AAED,iEAAiE;AACjE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,CAa9E"}
|
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
*
|
|
27
27
|
* @module mcp-server/tools/format-helpers
|
|
28
28
|
*/
|
|
29
|
+
import { decodeCharacterReferences } from '../../utils/character-references.js';
|
|
30
|
+
/**
|
|
31
|
+
* Horizontal whitespace at this surface: spaces, tabs, and the literal U+00A0 in
|
|
32
|
+
* the class — what a decoded ` ` leaves behind, and ordinary spacing here.
|
|
33
|
+
*/
|
|
34
|
+
const HORIZONTAL_WHITESPACE_RE = /[ \t ]+/g;
|
|
29
35
|
// ── Primitives ──────────────────────────────────────────────────────
|
|
30
36
|
function tb(content) {
|
|
31
37
|
return [{ type: 'text', text: content }];
|
|
@@ -39,30 +45,35 @@ function preserveHtmlBlockBoundaries(html) {
|
|
|
39
45
|
.replace(/<\s*\/\s*li\s*>/gi, '\n')
|
|
40
46
|
.replace(/<\s*\/\s*(?:p|ul|ol)\s*>/gi, '\n\n');
|
|
41
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Collapse horizontal whitespace and blank-line runs, keeping the paragraph and
|
|
50
|
+
* line structure a block rendering carries.
|
|
51
|
+
*/
|
|
52
|
+
function normalizeBlockWhitespace(text) {
|
|
53
|
+
return text
|
|
54
|
+
.replace(HORIZONTAL_WHITESPACE_RE, ' ')
|
|
55
|
+
.replace(/\n[ \t]+/g, '\n')
|
|
56
|
+
.replace(/[ \t]+\n/g, '\n')
|
|
57
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
58
|
+
.trim();
|
|
59
|
+
}
|
|
42
60
|
/**
|
|
43
61
|
* Strip HTML to plain text while preserving paragraph and line breaks. Upstream
|
|
44
62
|
* summary fields and other narrative bodies ship as HTML; we want the visible
|
|
45
63
|
* structure (paragraph boundaries) to survive into the rendered Markdown.
|
|
46
64
|
*
|
|
65
|
+
* Character references decode in one pass once the tags are gone, so text that
|
|
66
|
+
* literally says `&lt;` reads as `<` and not as a tag it never contained.
|
|
67
|
+
* A decoded ` ` is ordinary spacing at this surface, so it collapses with
|
|
68
|
+
* the rest of the horizontal whitespace.
|
|
69
|
+
*
|
|
47
70
|
* Inline contexts that need single-line output should pass `{ inline: true }`.
|
|
48
71
|
*/
|
|
49
72
|
function stripHtml(html, { inline = false } = {}) {
|
|
50
|
-
const text = preserveHtmlBlockBoundaries(html)
|
|
51
|
-
.replace(/<[^>]*>/g, '')
|
|
52
|
-
.replace(/ /g, ' ')
|
|
53
|
-
.replace(/'/g, "'")
|
|
54
|
-
.replace(/&/g, '&')
|
|
55
|
-
.replace(/</g, '<')
|
|
56
|
-
.replace(/>/g, '>')
|
|
57
|
-
.replace(/"/g, '"');
|
|
73
|
+
const text = decodeCharacterReferences(preserveHtmlBlockBoundaries(html).replace(/<[^>]*>/g, ''));
|
|
58
74
|
if (inline)
|
|
59
75
|
return text.replace(/\s+/g, ' ').trim();
|
|
60
|
-
return text
|
|
61
|
-
.replace(/[ \t]+/g, ' ')
|
|
62
|
-
.replace(/\n[ \t]+/g, '\n')
|
|
63
|
-
.replace(/[ \t]+\n/g, '\n')
|
|
64
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
65
|
-
.trim();
|
|
76
|
+
return normalizeBlockWhitespace(text);
|
|
66
77
|
}
|
|
67
78
|
/**
|
|
68
79
|
* Wrap an emphasis span's content in Markdown markers with the span's own
|
|
@@ -92,23 +103,13 @@ function wrapEmphasis(inner, marker) {
|
|
|
92
103
|
* through to the generic strip instead of leaving a stray marker.
|
|
93
104
|
*/
|
|
94
105
|
function htmlToMarkdown(html) {
|
|
95
|
-
|
|
106
|
+
const markup = preserveHtmlBlockBoundaries(html)
|
|
96
107
|
.replace(/<\s*p[^>]*>/gi, '')
|
|
97
108
|
.replace(/<\s*(?:strong|b)\s*>([\s\S]*?)<\s*\/\s*(?:strong|b)\s*>/gi, (_m, inner) => wrapEmphasis(inner, '**'))
|
|
98
109
|
.replace(/<\s*(?:em|i)\s*>([\s\S]*?)<\s*\/\s*(?:em|i)\s*>/gi, (_m, inner) => wrapEmphasis(inner, '*'))
|
|
99
110
|
.replace(/<\s*a[^>]*href=["']([^"']*)["'][^>]*>([\s\S]*?)<\s*\/\s*a\s*>/gi, '[$2]($1)')
|
|
100
|
-
.replace(/<[^>]*>/g, '')
|
|
101
|
-
|
|
102
|
-
.replace(/'/g, "'")
|
|
103
|
-
.replace(/&/g, '&')
|
|
104
|
-
.replace(/</g, '<')
|
|
105
|
-
.replace(/>/g, '>')
|
|
106
|
-
.replace(/"/g, '"')
|
|
107
|
-
.replace(/[ \t]+/g, ' ')
|
|
108
|
-
.replace(/\n[ \t]+/g, '\n')
|
|
109
|
-
.replace(/[ \t]+\n/g, '\n')
|
|
110
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
111
|
-
.trim();
|
|
111
|
+
.replace(/<[^>]*>/g, '');
|
|
112
|
+
return normalizeBlockWhitespace(decodeCharacterReferences(markup));
|
|
112
113
|
}
|
|
113
114
|
/** Safe deep access for compact field display — collapses whitespace to a single line. */
|
|
114
115
|
function s(obj, ...path) {
|
|
@@ -530,6 +531,36 @@ const MEMBER_ROW_KEYS = new Set([
|
|
|
530
531
|
'district',
|
|
531
532
|
'url',
|
|
532
533
|
]);
|
|
534
|
+
/**
|
|
535
|
+
* Window metadata a bounded summary row carries. Both summary renderers show it
|
|
536
|
+
* as one curated line, so it stays out of their fall-through key sets.
|
|
537
|
+
*/
|
|
538
|
+
const SUMMARY_WINDOW_KEYS = ['textTotalCharacters', 'textTruncated', 'textNextOffset'];
|
|
539
|
+
/**
|
|
540
|
+
* The window line a row gains once its `text` was bounded — absent on a row
|
|
541
|
+
* returned whole, which is what keeps an unbounded page's rendering unchanged.
|
|
542
|
+
*
|
|
543
|
+
* The row publishes the total and the next offset; this window's own start is
|
|
544
|
+
* derived from the text it returned, the same way the vote roster derives its
|
|
545
|
+
* range — `textNextOffset` is one past the last character returned.
|
|
546
|
+
*/
|
|
547
|
+
function summaryWindowLine(item) {
|
|
548
|
+
const total = item.textTotalCharacters;
|
|
549
|
+
if (typeof total !== 'number')
|
|
550
|
+
return;
|
|
551
|
+
const text = typeof item.text === 'string' ? item.text : '';
|
|
552
|
+
const nextOffset = typeof item.textNextOffset === 'number' ? item.textNextOffset : null;
|
|
553
|
+
if (text.length === 0) {
|
|
554
|
+
return `**Summary text:** 0 of ${total.toLocaleString('en-US')} characters — characterOffset is past this summary's end`;
|
|
555
|
+
}
|
|
556
|
+
const end = nextOffset ?? total;
|
|
557
|
+
const start = end - text.length;
|
|
558
|
+
return join([
|
|
559
|
+
`**Summary text:** characters ${(start + 1).toLocaleString('en-US')}–${end.toLocaleString('en-US')} of ${total.toLocaleString('en-US')}`,
|
|
560
|
+
`**Truncated:** ${item.textTruncated === true}`,
|
|
561
|
+
nextOffset != null ? `next characterOffset: ${nextOffset}` : '_end of summary_',
|
|
562
|
+
]);
|
|
563
|
+
}
|
|
533
564
|
function renderSummaryItem(item, i) {
|
|
534
565
|
const named = new Set(SUMMARY_ROW_KEYS);
|
|
535
566
|
const billType = s(item, 'bill', 'type')?.toUpperCase() ?? '';
|
|
@@ -557,6 +588,9 @@ function renderSummaryItem(item, i) {
|
|
|
557
588
|
lines.push(bill && typeof bill === 'object' && !Array.isArray(bill)
|
|
558
589
|
? withUnnamedFields(bill, billLine, BILL_REF_KEYS)
|
|
559
590
|
: billLine);
|
|
591
|
+
const window = summaryWindowLine(item);
|
|
592
|
+
if (window)
|
|
593
|
+
lines.push(window);
|
|
560
594
|
// The summary text is the critical data — the whole point of this tool
|
|
561
595
|
lines.push('');
|
|
562
596
|
lines.push(text || '_Summary text not available._');
|
|
@@ -565,7 +599,7 @@ function renderSummaryItem(item, i) {
|
|
|
565
599
|
return withRowRest(item, lines, named);
|
|
566
600
|
}
|
|
567
601
|
/** `actionDesc`/`versionCode` and the two update dates are resolved by `pick`. */
|
|
568
|
-
const SUMMARY_ROW_KEYS = ['actionDate', 'text', 'url', 'bill'];
|
|
602
|
+
const SUMMARY_ROW_KEYS = ['actionDate', 'text', 'url', 'bill', ...SUMMARY_WINDOW_KEYS];
|
|
569
603
|
/** Fields of a summary row's nested bill reference the heading already renders. */
|
|
570
604
|
const BILL_REF_KEYS = new Set(['congress', 'type', 'number', 'title', 'url']);
|
|
571
605
|
function renderCrsReportItem(item, i) {
|
|
@@ -1204,7 +1238,7 @@ function renderSenateVoteItem(item, i) {
|
|
|
1204
1238
|
if (question)
|
|
1205
1239
|
lines.push(`**Question:** ${measure ? `${question} (${measure})` : question}`);
|
|
1206
1240
|
const meta = join([
|
|
1207
|
-
f('Date',
|
|
1241
|
+
f('Date', senateVoteDate(item)),
|
|
1208
1242
|
f('Yeas', s(item, 'yeas')),
|
|
1209
1243
|
f('Nays', s(item, 'nays')),
|
|
1210
1244
|
]);
|
|
@@ -1215,6 +1249,18 @@ function renderSenateVoteItem(item, i) {
|
|
|
1215
1249
|
lines.push(title);
|
|
1216
1250
|
return withRowRest(item, lines, SENATE_VOTE_ROW_KEYS);
|
|
1217
1251
|
}
|
|
1252
|
+
/**
|
|
1253
|
+
* The resolved calendar date leads, with the menu's own year-less short form
|
|
1254
|
+
* beside it — a row carries both, and the short form is what the Senate's own
|
|
1255
|
+
* vote pages show.
|
|
1256
|
+
*/
|
|
1257
|
+
function senateVoteDate(item) {
|
|
1258
|
+
const iso = s(item, 'voteDateIso');
|
|
1259
|
+
const published = s(item, 'voteDate');
|
|
1260
|
+
if (iso && published)
|
|
1261
|
+
return `${iso} (${published})`;
|
|
1262
|
+
return iso ?? published;
|
|
1263
|
+
}
|
|
1218
1264
|
/** `chamber` is the dispatch marker, implicit in the Senate heading. */
|
|
1219
1265
|
const SENATE_VOTE_ROW_KEYS = new Set([
|
|
1220
1266
|
'chamber',
|
|
@@ -1224,6 +1270,7 @@ const SENATE_VOTE_ROW_KEYS = new Set([
|
|
|
1224
1270
|
'question',
|
|
1225
1271
|
'measure',
|
|
1226
1272
|
'voteDate',
|
|
1273
|
+
'voteDateIso',
|
|
1227
1274
|
'yeas',
|
|
1228
1275
|
'nays',
|
|
1229
1276
|
'title',
|
|
@@ -1776,12 +1823,20 @@ function renderBillSubresourceSummaryItem(item, i) {
|
|
|
1776
1823
|
const meta = join([f('Action Date', actionDate), f('Summary Updated', updated)]);
|
|
1777
1824
|
if (meta)
|
|
1778
1825
|
lines.push(meta);
|
|
1826
|
+
const window = summaryWindowLine(item);
|
|
1827
|
+
if (window)
|
|
1828
|
+
lines.push(window);
|
|
1779
1829
|
const text = typeof item.text === 'string' ? htmlToMarkdown(item.text) : '';
|
|
1780
1830
|
if (text)
|
|
1781
1831
|
lines.push('', text);
|
|
1782
1832
|
return withRowRest(item, lines, named);
|
|
1783
1833
|
}
|
|
1784
|
-
const BILL_SUMMARY_SUBRESOURCE_ROW_KEYS = [
|
|
1834
|
+
const BILL_SUMMARY_SUBRESOURCE_ROW_KEYS = [
|
|
1835
|
+
'actionDate',
|
|
1836
|
+
'updateDate',
|
|
1837
|
+
'text',
|
|
1838
|
+
...SUMMARY_WINDOW_KEYS,
|
|
1839
|
+
];
|
|
1785
1840
|
function pickBillListRenderer(first) {
|
|
1786
1841
|
if ('title' in first && 'number' in first)
|
|
1787
1842
|
return renderBillItem;
|