@shiftleftpt/sbd-toe-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.
Files changed (93) hide show
  1. package/.env.example +35 -0
  2. package/LICENSE +201 -0
  3. package/README.md +323 -0
  4. package/data/publish/algolia_docs_records.json +148847 -0
  5. package/data/publish/algolia_docs_records_enriched.json +194004 -0
  6. package/data/publish/algolia_entities_records.json +74715 -0
  7. package/data/publish/algolia_entities_records_enriched.json +177587 -0
  8. package/data/publish/algolia_index_settings.json +102 -0
  9. package/data/publish/sbd-toe-index-compact.json +111 -0
  10. package/data/reports/run_manifest.json +10 -0
  11. package/dist/backend/semantic-index-gateway.d.ts +25 -0
  12. package/dist/backend/semantic-index-gateway.js +555 -0
  13. package/dist/backend/semantic-index-gateway.js.map +1 -0
  14. package/dist/backend/semantic-index-gateway.test.d.ts +1 -0
  15. package/dist/backend/semantic-index-gateway.test.js +384 -0
  16. package/dist/backend/semantic-index-gateway.test.js.map +1 -0
  17. package/dist/bootstrap/checkout-backend.d.ts +31 -0
  18. package/dist/bootstrap/checkout-backend.js +136 -0
  19. package/dist/bootstrap/checkout-backend.js.map +1 -0
  20. package/dist/bootstrap/checkout-backend.test.d.ts +1 -0
  21. package/dist/bootstrap/checkout-backend.test.js +158 -0
  22. package/dist/bootstrap/checkout-backend.test.js.map +1 -0
  23. package/dist/bootstrap/release-checkout.d.ts +8 -0
  24. package/dist/bootstrap/release-checkout.js +168 -0
  25. package/dist/bootstrap/release-checkout.js.map +1 -0
  26. package/dist/bootstrap/release-checkout.test.d.ts +1 -0
  27. package/dist/bootstrap/release-checkout.test.js +137 -0
  28. package/dist/bootstrap/release-checkout.test.js.map +1 -0
  29. package/dist/config.d.ts +4 -0
  30. package/dist/config.js +81 -0
  31. package/dist/config.js.map +1 -0
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +1063 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/orchestrator/ask-manual.d.ts +13 -0
  36. package/dist/orchestrator/ask-manual.js +202 -0
  37. package/dist/orchestrator/ask-manual.js.map +1 -0
  38. package/dist/prompt/build-answer-prompt.d.ts +2 -0
  39. package/dist/prompt/build-answer-prompt.js +51 -0
  40. package/dist/prompt/build-answer-prompt.js.map +1 -0
  41. package/dist/prompt/system-prompt.d.ts +1 -0
  42. package/dist/prompt/system-prompt.js +94 -0
  43. package/dist/prompt/system-prompt.js.map +1 -0
  44. package/dist/resources/sbd-toe-resources.d.ts +18 -0
  45. package/dist/resources/sbd-toe-resources.js +164 -0
  46. package/dist/resources/sbd-toe-resources.js.map +1 -0
  47. package/dist/resources/sbd-toe-resources.test.d.ts +1 -0
  48. package/dist/resources/sbd-toe-resources.test.js +134 -0
  49. package/dist/resources/sbd-toe-resources.test.js.map +1 -0
  50. package/dist/test-utils.d.ts +153 -0
  51. package/dist/test-utils.js +176 -0
  52. package/dist/test-utils.js.map +1 -0
  53. package/dist/tools/generate-document.d.ts +22 -0
  54. package/dist/tools/generate-document.js +392 -0
  55. package/dist/tools/generate-document.js.map +1 -0
  56. package/dist/tools/generate-document.test.d.ts +1 -0
  57. package/dist/tools/generate-document.test.js +189 -0
  58. package/dist/tools/generate-document.test.js.map +1 -0
  59. package/dist/tools/map-review-scope.d.ts +20 -0
  60. package/dist/tools/map-review-scope.js +299 -0
  61. package/dist/tools/map-review-scope.js.map +1 -0
  62. package/dist/tools/map-review-scope.test.d.ts +1 -0
  63. package/dist/tools/map-review-scope.test.js +204 -0
  64. package/dist/tools/map-review-scope.test.js.map +1 -0
  65. package/dist/tools/plan-repo-governance.d.ts +41 -0
  66. package/dist/tools/plan-repo-governance.js +509 -0
  67. package/dist/tools/plan-repo-governance.js.map +1 -0
  68. package/dist/tools/plan-repo-governance.test.d.ts +1 -0
  69. package/dist/tools/plan-repo-governance.test.js +237 -0
  70. package/dist/tools/plan-repo-governance.test.js.map +1 -0
  71. package/dist/tools/structured-tools.d.ts +5 -0
  72. package/dist/tools/structured-tools.js +310 -0
  73. package/dist/tools/structured-tools.js.map +1 -0
  74. package/dist/tools/structured-tools.test.d.ts +1 -0
  75. package/dist/tools/structured-tools.test.js +459 -0
  76. package/dist/tools/structured-tools.test.js.map +1 -0
  77. package/dist/types.d.ts +160 -0
  78. package/dist/types.js +2 -0
  79. package/dist/types.js.map +1 -0
  80. package/dist/upstream/backend-contract.d.ts +3 -0
  81. package/dist/upstream/backend-contract.js +37 -0
  82. package/dist/upstream/backend-contract.js.map +1 -0
  83. package/dist/validators/ai-disclosure.d.ts +39 -0
  84. package/dist/validators/ai-disclosure.js +183 -0
  85. package/dist/validators/ai-disclosure.js.map +1 -0
  86. package/dist/validators/ai-disclosure.test.d.ts +1 -0
  87. package/dist/validators/ai-disclosure.test.js +244 -0
  88. package/dist/validators/ai-disclosure.test.js.map +1 -0
  89. package/examples/claude-desktop.json +8 -0
  90. package/examples/vscode.mcp.json +9 -0
  91. package/package.json +50 -0
  92. package/prompts/sbd-toe-chat-system.md +71 -0
  93. package/smithery.yaml +44 -0
@@ -0,0 +1,3 @@
1
+ import type { BackendCheckout } from "../types.js";
2
+ export declare function tryLoadBackendCheckout(): Promise<BackendCheckout | undefined>;
3
+ export declare function loadBackendCheckout(): Promise<BackendCheckout>;
@@ -0,0 +1,37 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { getConfig } from "../config.js";
3
+ let cachedCheckout;
4
+ function validateCheckout(payload) {
5
+ if (!payload || typeof payload !== "object") {
6
+ throw new Error("O ficheiro de checkout do backend está vazio ou é inválido.");
7
+ }
8
+ const checkout = payload;
9
+ if (!checkout.indices?.docs?.indexName || !checkout.indices?.entities?.indexName) {
10
+ throw new Error("O checkout do backend não contém os índices documentais e estruturados esperados.");
11
+ }
12
+ return checkout;
13
+ }
14
+ export async function tryLoadBackendCheckout() {
15
+ if (cachedCheckout) {
16
+ return cachedCheckout;
17
+ }
18
+ const config = getConfig();
19
+ let rawFile;
20
+ try {
21
+ rawFile = await readFile(config.backend.checkoutFile, "utf8");
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ cachedCheckout = validateCheckout(JSON.parse(rawFile));
27
+ return cachedCheckout;
28
+ }
29
+ export async function loadBackendCheckout() {
30
+ const checkout = await tryLoadBackendCheckout();
31
+ if (!checkout) {
32
+ const config = getConfig();
33
+ throw new Error(`Falta o ficheiro de checkout do backend em "${config.backend.checkoutFile}". Corre "npm run checkout:backend" primeiro.`);
34
+ }
35
+ return checkout;
36
+ }
37
+ //# sourceMappingURL=backend-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend-contract.js","sourceRoot":"","sources":["../../src/upstream/backend-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,IAAI,cAA2C,CAAC;AAEhD,SAAS,gBAAgB,CAAC,OAAgB;IACxC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IAED,MAAM,QAAQ,GAAG,OAA0B,CAAC;IAC5C,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CACb,mFAAmF,CACpF,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAE3B,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,cAAc,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAC,CAAC;IAClE,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,QAAQ,GAAG,MAAM,sBAAsB,EAAE,CAAC;IAChD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,+CAA+C,MAAM,CAAC,OAAO,CAAC,YAAY,+CAA+C,CAC1H,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * AI Disclosure Validation — S8 Governança de Documentos AI-Assisted
3
+ *
4
+ * SbD-ToE Cap. 14 (Governança, Revisões, Conformidade):
5
+ * Artefactos IA-gerados sujeitos a rastreabilidade explícita, revisão humana e validação automática.
6
+ *
7
+ * Formato suportado:
8
+ * - YAML frontmatter (--- AI_ASSISTED: true ... ---)
9
+ * - HTML comment section (<!-- AI-ASSISTED: true, ... -->)
10
+ *
11
+ * Campos obrigatórios: AI_ASSISTED, MODEL, DATE, PURPOSE
12
+ */
13
+ export declare const ALLOWED_PURPOSES: readonly ["generated-code", "governance-doc", "test-plan", "integration-test", "documentation", "other"];
14
+ export type AllowedPurpose = (typeof ALLOWED_PURPOSES)[number];
15
+ export interface AIDisclosure {
16
+ ai_assisted: boolean;
17
+ model: string;
18
+ date: string;
19
+ purpose: AllowedPurpose;
20
+ reasoning?: string | undefined;
21
+ review_status?: string | undefined;
22
+ }
23
+ /**
24
+ * Extract disclosure from file content
25
+ * Tries YAML frontmatter first, then HTML comment section
26
+ */
27
+ export declare function extractDisclosure(content: string): Record<string, unknown> | null;
28
+ /**
29
+ * Validate disclosure fields and return structured object
30
+ * Throws on validation failure
31
+ */
32
+ export declare function validateDisclosure(disclosure: Record<string, unknown>): AIDisclosure;
33
+ /**
34
+ * Main validation function:
35
+ * 1. Extract disclosure from content
36
+ * 2. Validate all fields
37
+ * 3. Return structured AIDisclosure or throw error with field information
38
+ */
39
+ export declare function validateAIDisclosure(content: string): AIDisclosure;
@@ -0,0 +1,183 @@
1
+ /**
2
+ * AI Disclosure Validation — S8 Governança de Documentos AI-Assisted
3
+ *
4
+ * SbD-ToE Cap. 14 (Governança, Revisões, Conformidade):
5
+ * Artefactos IA-gerados sujeitos a rastreabilidade explícita, revisão humana e validação automática.
6
+ *
7
+ * Formato suportado:
8
+ * - YAML frontmatter (--- AI_ASSISTED: true ... ---)
9
+ * - HTML comment section (<!-- AI-ASSISTED: true, ... -->)
10
+ *
11
+ * Campos obrigatórios: AI_ASSISTED, MODEL, DATE, PURPOSE
12
+ */
13
+ export const ALLOWED_PURPOSES = [
14
+ 'generated-code',
15
+ 'governance-doc',
16
+ 'test-plan',
17
+ 'integration-test',
18
+ 'documentation',
19
+ 'other',
20
+ ];
21
+ /**
22
+ * Valida formato YYYY-MM-DD
23
+ */
24
+ function isValidDate(dateStr) {
25
+ const re = /^\d{4}-\d{2}-\d{2}$/;
26
+ if (!re.test(dateStr))
27
+ return false;
28
+ const dt = new Date(dateStr);
29
+ return !Number.isNaN(dt.getTime()) && dt instanceof Date;
30
+ }
31
+ /**
32
+ * Parse YAML frontmatter (--- ... ---)
33
+ */
34
+ function parseYAMLFrontmatter(content) {
35
+ const trimmed = content.trim();
36
+ if (!trimmed.startsWith('---'))
37
+ return null;
38
+ const endIdx = trimmed.indexOf('---', 3); // busca segundo ---
39
+ if (endIdx === -1)
40
+ return null;
41
+ const yamlBlock = trimmed.slice(3, endIdx).trim();
42
+ if (!yamlBlock)
43
+ return null;
44
+ const result = {};
45
+ for (const line of yamlBlock.split('\n')) {
46
+ const trimLine = line.trim();
47
+ if (!trimLine || trimLine.startsWith('#'))
48
+ continue;
49
+ const colonIdx = trimLine.indexOf(':');
50
+ if (colonIdx === -1)
51
+ continue;
52
+ const key = trimLine.slice(0, colonIdx).trim().toLowerCase().replace(/-/g, '_');
53
+ let rawValue = trimLine.slice(colonIdx + 1).trim();
54
+ let value = rawValue;
55
+ // Parse value
56
+ if (rawValue === 'true') {
57
+ value = true;
58
+ }
59
+ else if (rawValue === 'false') {
60
+ value = false;
61
+ }
62
+ else if (rawValue.startsWith('"') && rawValue.endsWith('"')) {
63
+ value = rawValue.slice(1, -1);
64
+ }
65
+ else if (rawValue.startsWith("'") && rawValue.endsWith("'")) {
66
+ value = rawValue.slice(1, -1);
67
+ }
68
+ result[key] = value;
69
+ }
70
+ return Object.keys(result).length > 0 ? result : null;
71
+ }
72
+ /**
73
+ * Parse HTML comment section (<!-- AI-ASSISTED: true, MODEL: ..., ... -->)
74
+ */
75
+ function parseHTMLCommentSection(content) {
76
+ const re = /<!--\s*AI-ASSISTED:\s*([^,]+)(.*?)\s*-->/is;
77
+ const match = content.match(re);
78
+ if (!match)
79
+ return null;
80
+ const fullComment = match[0];
81
+ const result = {};
82
+ // Extract AI-ASSISTED: true/false
83
+ const aiValue = (match[1] ?? '').trim().toLowerCase();
84
+ result.ai_assisted = aiValue === 'true' ? true : aiValue === 'false' ? false : null;
85
+ // Parse remaining key:value pairs (MODEL, DATE, PURPOSE, etc.)
86
+ // Pattern: KEY: VALUE (comma-separated)
87
+ const pairs = fullComment
88
+ .replace(/<!--\s*/, '')
89
+ .replace(/\s*-->/g, '')
90
+ .split(',');
91
+ for (let i = 1; i < pairs.length; i++) {
92
+ const pairRaw = pairs[i];
93
+ const pair = pairRaw !== undefined ? pairRaw.trim() : '';
94
+ const colonIdx = pair.indexOf(':');
95
+ if (colonIdx === -1)
96
+ continue;
97
+ const key = pair.slice(0, colonIdx).trim().toLowerCase().replace(/-/g, '_');
98
+ const rawVal = pair.slice(colonIdx + 1).trim();
99
+ let value = rawVal;
100
+ if (rawVal.startsWith('"') && rawVal.endsWith('"')) {
101
+ value = rawVal.slice(1, -1);
102
+ }
103
+ else if (rawVal.startsWith("'") && rawVal.endsWith("'")) {
104
+ value = rawVal.slice(1, -1);
105
+ }
106
+ result[key] = value;
107
+ }
108
+ return Object.keys(result).length > 0 ? result : null;
109
+ }
110
+ /**
111
+ * Extract disclosure from file content
112
+ * Tries YAML frontmatter first, then HTML comment section
113
+ */
114
+ export function extractDisclosure(content) {
115
+ let disclosure = parseYAMLFrontmatter(content);
116
+ if (disclosure)
117
+ return disclosure;
118
+ disclosure = parseHTMLCommentSection(content);
119
+ if (disclosure)
120
+ return disclosure;
121
+ return null;
122
+ }
123
+ /**
124
+ * Validate disclosure fields and return structured object
125
+ * Throws on validation failure
126
+ */
127
+ export function validateDisclosure(disclosure) {
128
+ // Check AI_ASSISTED
129
+ if (disclosure.ai_assisted !== true) {
130
+ throw new Error('AI_ASSISTED must be true');
131
+ }
132
+ // Check MODEL
133
+ const model = disclosure.model;
134
+ if (!model || typeof model !== 'string') {
135
+ throw new Error('MODEL is required and must be a non-empty string');
136
+ }
137
+ if (model.trim().length === 0) {
138
+ throw new Error('MODEL cannot be empty');
139
+ }
140
+ // Check DATE
141
+ const date = disclosure.date;
142
+ if (!date || typeof date !== 'string') {
143
+ throw new Error('DATE is required and must be a string (format: YYYY-MM-DD)');
144
+ }
145
+ if (!isValidDate(date)) {
146
+ throw new Error(`DATE must be in YYYY-MM-DD format, got: ${date}`);
147
+ }
148
+ // Check PURPOSE
149
+ const purpose = disclosure.purpose;
150
+ if (!purpose || typeof purpose !== 'string') {
151
+ throw new Error('PURPOSE is required and must be a string');
152
+ }
153
+ if (!ALLOWED_PURPOSES.includes(purpose)) {
154
+ throw new Error(`PURPOSE must be one of: ${ALLOWED_PURPOSES.join(', ')}, got: ${purpose}`);
155
+ }
156
+ const reasoningVal = typeof disclosure.reasoning === 'string' ? disclosure.reasoning : undefined;
157
+ const reviewVal = typeof disclosure.review_status === 'string' ? disclosure.review_status : undefined;
158
+ const result = {
159
+ ai_assisted: true,
160
+ model: model.trim(),
161
+ date,
162
+ purpose: purpose,
163
+ };
164
+ if (reasoningVal !== undefined)
165
+ result.reasoning = reasoningVal;
166
+ if (reviewVal !== undefined)
167
+ result.review_status = reviewVal;
168
+ return result;
169
+ }
170
+ /**
171
+ * Main validation function:
172
+ * 1. Extract disclosure from content
173
+ * 2. Validate all fields
174
+ * 3. Return structured AIDisclosure or throw error with field information
175
+ */
176
+ export function validateAIDisclosure(content) {
177
+ const disclosure = extractDisclosure(content);
178
+ if (!disclosure) {
179
+ throw new Error('No AI disclosure found in document header');
180
+ }
181
+ return validateDisclosure(disclosure);
182
+ }
183
+ //# sourceMappingURL=ai-disclosure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-disclosure.js","sourceRoot":"","sources":["../../src/validators/ai-disclosure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,244 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { extractDisclosure, validateDisclosure, validateAIDisclosure, ALLOWED_PURPOSES, } from './ai-disclosure.js';
3
+ describe('AI Disclosure Validator', () => {
4
+ describe('YAML Frontmatter Parsing', () => {
5
+ it('should parse valid YAML frontmatter', () => {
6
+ const content = `---
7
+ ai_assisted: true
8
+ model: Claude Haiku 4.5
9
+ date: 2026-03-24
10
+ purpose: governance-doc
11
+ ---
12
+ # Content here`;
13
+ const disclosure = extractDisclosure(content);
14
+ expect(disclosure).not.toBeNull();
15
+ expect(disclosure?.ai_assisted).toBe(true);
16
+ expect(disclosure?.model).toBe('Claude Haiku 4.5');
17
+ expect(disclosure?.date).toBe('2026-03-24');
18
+ expect(disclosure?.purpose).toBe('governance-doc');
19
+ });
20
+ it('should parse YAML with optional fields', () => {
21
+ const content = `---
22
+ ai_assisted: true
23
+ model: Claude 3.5 Sonnet
24
+ date: 2026-01-10
25
+ purpose: generated-code
26
+ reasoning: Auto-generated from template
27
+ review_status: pending-human-review
28
+ ---
29
+ Code...`;
30
+ const disclosure = extractDisclosure(content);
31
+ expect(disclosure?.reasoning).toBe('Auto-generated from template');
32
+ expect(disclosure?.review_status).toBe('pending-human-review');
33
+ });
34
+ it('should handle YAML with quoted strings', () => {
35
+ const content = `---
36
+ ai_assisted: true
37
+ model: "Claude Haiku 4.5 (pt-BR)"
38
+ date: "2026-03-24"
39
+ purpose: "governance-doc"
40
+ ---
41
+ Content`;
42
+ const disclosure = extractDisclosure(content);
43
+ expect(disclosure?.model).toBe('Claude Haiku 4.5 (pt-BR)');
44
+ });
45
+ it('should ignore YAML comments', () => {
46
+ const content = `---
47
+ # This is a comment
48
+ ai_assisted: true
49
+ model: Claude Haiku 4.5
50
+ date: 2026-03-24
51
+ purpose: test-plan
52
+ # Another comment
53
+ ---
54
+ Content`;
55
+ const disclosure = extractDisclosure(content);
56
+ expect(disclosure?.purpose).toBe('test-plan');
57
+ });
58
+ });
59
+ describe('HTML Comment Section Parsing', () => {
60
+ it('should parse HTML comment disclosure', () => {
61
+ const content = `<!-- AI-ASSISTED: true, MODEL: Claude Haiku 4.5, DATE: 2026-03-24, PURPOSE: governance-doc -->
62
+ # Content here`;
63
+ const disclosure = extractDisclosure(content);
64
+ expect(disclosure?.ai_assisted).toBe(true);
65
+ expect(disclosure?.model).toBe('Claude Haiku 4.5');
66
+ expect(disclosure?.date).toBe('2026-03-24');
67
+ expect(disclosure?.purpose).toBe('governance-doc');
68
+ });
69
+ it('should handle HTML comment with special characters', () => {
70
+ const content = `<!-- AI-ASSISTED: true, MODEL: Claude Haiku 4.5 (pt-BR), DATE: 2026-03-24, PURPOSE: governance-doc + compliance -->
71
+ Content`;
72
+ const disclosure = extractDisclosure(content);
73
+ expect(disclosure?.model).toContain('Claude Haiku');
74
+ });
75
+ });
76
+ describe('Field Validation', () => {
77
+ it('should reject disclosure without AI_ASSISTED true', () => {
78
+ const raw = {
79
+ ai_assisted: false,
80
+ model: 'Claude',
81
+ date: '2026-03-24',
82
+ purpose: 'test-plan',
83
+ };
84
+ expect(() => validateDisclosure(raw)).toThrow('AI_ASSISTED must be true');
85
+ });
86
+ it('should reject disclosure without MODEL', () => {
87
+ const raw = {
88
+ ai_assisted: true,
89
+ date: '2026-03-24',
90
+ purpose: 'test-plan',
91
+ };
92
+ expect(() => validateDisclosure(raw)).toThrow('MODEL is required');
93
+ });
94
+ it('should reject disclosure with empty MODEL', () => {
95
+ const raw = {
96
+ ai_assisted: true,
97
+ model: ' ',
98
+ date: '2026-03-24',
99
+ purpose: 'test-plan',
100
+ };
101
+ expect(() => validateDisclosure(raw)).toThrow('MODEL cannot be empty');
102
+ });
103
+ it('should reject disclosure without DATE', () => {
104
+ const raw = {
105
+ ai_assisted: true,
106
+ model: 'Claude',
107
+ purpose: 'test-plan',
108
+ };
109
+ expect(() => validateDisclosure(raw)).toThrow('DATE is required');
110
+ });
111
+ it('should reject invalid DATE format', () => {
112
+ const raw = {
113
+ ai_assisted: true,
114
+ model: 'Claude',
115
+ date: '2026/03/24',
116
+ purpose: 'test-plan',
117
+ };
118
+ expect(() => validateDisclosure(raw)).toThrow('DATE must be in YYYY-MM-DD format');
119
+ });
120
+ it('should reject disclosure without PURPOSE', () => {
121
+ const raw = {
122
+ ai_assisted: true,
123
+ model: 'Claude',
124
+ date: '2026-03-24',
125
+ };
126
+ expect(() => validateDisclosure(raw)).toThrow('PURPOSE is required');
127
+ });
128
+ it('should reject PURPOSE not in allowlist', () => {
129
+ const raw = {
130
+ ai_assisted: true,
131
+ model: 'Claude',
132
+ date: '2026-03-24',
133
+ purpose: 'invalid-purpose',
134
+ };
135
+ expect(() => validateDisclosure(raw)).toThrow('PURPOSE must be one of');
136
+ });
137
+ it('should accept all allowed PURPOSE values', () => {
138
+ for (const purpose of ALLOWED_PURPOSES) {
139
+ const raw = {
140
+ ai_assisted: true,
141
+ model: 'Claude',
142
+ date: '2026-03-24',
143
+ purpose,
144
+ };
145
+ const result = validateDisclosure(raw);
146
+ expect(result.purpose).toBe(purpose);
147
+ }
148
+ });
149
+ });
150
+ describe('Full Document Validation', () => {
151
+ it('should validate complete document with YAML disclosure', () => {
152
+ const content = `---
153
+ ai_assisted: true
154
+ model: Claude Haiku 4.5
155
+ date: 2026-03-24
156
+ purpose: governance-doc
157
+ ---
158
+ # Document Title
159
+ This is the content.`;
160
+ const disclosure = validateAIDisclosure(content);
161
+ expect(disclosure.ai_assisted).toBe(true);
162
+ expect(disclosure.model).toBe('Claude Haiku 4.5');
163
+ expect(disclosure.date).toBe('2026-03-24');
164
+ expect(disclosure.purpose).toBe('governance-doc');
165
+ });
166
+ it('should validate complete document with HTML comment disclosure', () => {
167
+ const content = `<!-- AI-ASSISTED: true, MODEL: Claude Haiku 4.5, DATE: 2026-03-24, PURPOSE: test-plan -->
168
+ # Test Plan
169
+ This is a test plan.`;
170
+ const disclosure = validateAIDisclosure(content);
171
+ expect(disclosure.purpose).toBe('test-plan');
172
+ });
173
+ it('should throw on missing disclosure', () => {
174
+ const content = `# Content without disclosure
175
+ This document has no AI disclosure.`;
176
+ expect(() => validateAIDisclosure(content)).toThrow('No AI disclosure found in document header');
177
+ });
178
+ it('should throw on malformed disclosure', () => {
179
+ const content = `---
180
+ ai_assisted: true
181
+ model:
182
+ date: 2026-03-24
183
+ purpose: test-plan
184
+ ---
185
+ Content`;
186
+ expect(() => validateAIDisclosure(content)).toThrow('MODEL is required');
187
+ });
188
+ });
189
+ describe('Edge Cases', () => {
190
+ it('should handle YAML with extra whitespace', () => {
191
+ const content = `---
192
+ ai_assisted: true
193
+ model: Claude Haiku 4.5
194
+ date: 2026-03-24
195
+ purpose: test-plan
196
+ ---
197
+ Content`;
198
+ const disclosure = extractDisclosure(content);
199
+ expect(disclosure?.model).toBe('Claude Haiku 4.5');
200
+ });
201
+ it('should handle non-existent disclosure gracefully', () => {
202
+ const content = 'Just plain text without any disclosure markers.';
203
+ const disclosure = extractDisclosure(content);
204
+ expect(disclosure).toBeNull();
205
+ });
206
+ it('should reject invalid dates', () => {
207
+ const raw = {
208
+ ai_assisted: true,
209
+ model: 'Claude',
210
+ date: '2026-13-45', // Invalid month and day
211
+ purpose: 'test-plan',
212
+ };
213
+ expect(() => validateDisclosure(raw)).toThrow('DATE must be in YYYY-MM-DD format');
214
+ });
215
+ it('should handle unicode and special characters in MODEL', () => {
216
+ const raw = {
217
+ ai_assisted: true,
218
+ model: 'Claude Haiku 4.5 (pt-BR) — v2.0',
219
+ date: '2026-03-24',
220
+ purpose: 'documentation',
221
+ };
222
+ const result = validateDisclosure(raw);
223
+ expect(result.model).toContain('pt-BR');
224
+ });
225
+ });
226
+ describe('Return Type Validation', () => {
227
+ it('should return properly typed AIDisclosure object', () => {
228
+ const raw = {
229
+ ai_assisted: true,
230
+ model: 'Claude',
231
+ date: '2026-03-24',
232
+ purpose: 'test-plan',
233
+ };
234
+ const result = validateDisclosure(raw);
235
+ expect(result).toHaveProperty('ai_assisted');
236
+ expect(result).toHaveProperty('model');
237
+ expect(result).toHaveProperty('date');
238
+ expect(result).toHaveProperty('purpose');
239
+ expect(typeof result.ai_assisted).toBe('boolean');
240
+ expect(typeof result.model).toBe('string');
241
+ });
242
+ });
243
+ });
244
+ //# sourceMappingURL=ai-disclosure.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-disclosure.test.js","sourceRoot":"","sources":["../../src/validators/ai-disclosure.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "sbd-toe": {
4
+ "command": "npx",
5
+ "args": ["-y", "@shiftleftpt/sbd-toe-mcp"]
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "servers": {
3
+ "sbdToe": {
4
+ "type": "stdio",
5
+ "command": "npx",
6
+ "args": ["-y", "@shiftleftpt/sbd-toe-mcp"]
7
+ }
8
+ }
9
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@shiftleftpt/sbd-toe-mcp",
3
+ "version": "0.1.0",
4
+ "license": "Apache-2.0",
5
+ "description": "MCP server for SbD-ToE security manual — structured tools for Claude, GitHub Copilot and other MCP clients",
6
+ "keywords": ["mcp", "security", "sbd", "toe", "devsecops", "claude", "copilot", "llm"],
7
+ "homepage": "https://github.com/Shiftleftpt/sbd-toe-mcp-poc#readme",
8
+ "bugs": { "url": "https://github.com/Shiftleftpt/sbd-toe-mcp-poc/issues" },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/Shiftleftpt/sbd-toe-mcp-poc.git"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "type": "module",
17
+ "bin": {
18
+ "sbd-toe-mcp": "./dist/index.js"
19
+ },
20
+ "files": [
21
+ "dist/",
22
+ "data/publish/",
23
+ "data/reports/run_manifest.json",
24
+ "prompts/",
25
+ "examples/",
26
+ ".env.example",
27
+ "smithery.yaml"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsc -p tsconfig.json",
31
+ "dev": "tsc -w -p tsconfig.json",
32
+ "start": "node dist/index.js",
33
+ "check": "tsc --noEmit -p tsconfig.json && node scripts/validate-ai-disclosure.mjs --check",
34
+ "checkout:backend": "tsc -p tsconfig.json && node dist/bootstrap/checkout-backend.js",
35
+ "package:release": "node scripts/package-release.mjs",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest",
38
+ "test:coverage": "vitest run --coverage"
39
+ },
40
+ "engines": {
41
+ "node": ">=20.9.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^25.5.0",
45
+ "@vitest/coverage-v8": "^1.6.0",
46
+ "@vitest/ui": "^1.6.0",
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^1.6.0"
49
+ }
50
+ }