@agentbrain/mcp-server 1.4.70 → 1.4.76

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.
@@ -0,0 +1,149 @@
1
+ // MCP tool: load_guardrails - Load workspace Guardrails from cloud
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ // ══════════════════════════════════════════════════════════════
5
+ // Environment & Configuration
6
+ // ══════════════════════════════════════════════════════════════
7
+ const BASE_URL = process.env.AGENTBRAIN_API_BASE_URL?.replace(/\/$/, '') ?? 'https://www.useagentbrain.com/api/v1';
8
+ const GUARDRAILS_URL = `${BASE_URL}/guardrails`;
9
+ /**
10
+ * Expand path: handles ~, relative paths, etc.
11
+ */
12
+ function expandPath(path) {
13
+ if (path.startsWith('~/') || path === '~') {
14
+ return path.replace('~', homedir());
15
+ }
16
+ if (!path.startsWith('/')) {
17
+ return join(process.cwd(), path);
18
+ }
19
+ return path;
20
+ }
21
+ // ══════════════════════════════════════════════════════════════
22
+ // Schema
23
+ // ══════════════════════════════════════════════════════════════
24
+ export const loadGuardrailsSchema = {
25
+ name: 'load_guardrails',
26
+ description: 'Load workspace Guardrails — protected files, sensitive data rules, team boundaries, and invariants. Load before any file modification.',
27
+ inputSchema: {
28
+ type: 'object',
29
+ properties: {
30
+ repo_path: {
31
+ type: 'string',
32
+ description: 'Absolute path to repository',
33
+ },
34
+ },
35
+ required: ['repo_path'],
36
+ },
37
+ };
38
+ // ══════════════════════════════════════════════════════════════
39
+ // Formatting
40
+ // ══════════════════════════════════════════════════════════════
41
+ function formatGuardrails(content) {
42
+ const workspaceName = content.workspace_name || 'Workspace';
43
+ let output = `# Guardrails — ${workspaceName}\n\n`;
44
+ // Protected Files
45
+ if (content.protected_files && content.protected_files.length > 0) {
46
+ output += '## Protected Files\n';
47
+ output += '⚠️ Never modify these files:\n';
48
+ for (const file of content.protected_files) {
49
+ output += `- ${file.path}: ${file.reason}\n`;
50
+ }
51
+ output += '\n';
52
+ }
53
+ // Sensitive Data
54
+ if (content.sensitive_data && content.sensitive_data.length > 0) {
55
+ output += '## Sensitive Data\n';
56
+ output += '🔒 Never log or expose these fields:\n';
57
+ for (const data of content.sensitive_data) {
58
+ output += `- ${data.field}: ${data.rule}\n`;
59
+ }
60
+ output += '\n';
61
+ }
62
+ // Team Boundaries
63
+ if (content.team_boundaries && content.team_boundaries.length > 0) {
64
+ output += '## Team Boundaries\n';
65
+ output += '👥 Requires approval before changes:\n';
66
+ for (const boundary of content.team_boundaries) {
67
+ output += `- ${boundary.path} → ${boundary.owner}: ${boundary.rule}\n`;
68
+ }
69
+ output += '\n';
70
+ }
71
+ // Invariants
72
+ if (content.invariants && content.invariants.length > 0) {
73
+ output += '## Invariants\n';
74
+ output += '🔴 Must always be true:\n';
75
+ for (const invariant of content.invariants) {
76
+ output += `- ${invariant}\n`;
77
+ }
78
+ output += '\n';
79
+ }
80
+ // Refactor Rules
81
+ if (content.refactor_scope || content.ask_before_refactoring !== undefined || content.refactor_notes) {
82
+ output += '## Refactor Rules\n';
83
+ if (content.refactor_scope) {
84
+ output += `Scope: ${content.refactor_scope}\n`;
85
+ }
86
+ if (content.ask_before_refactoring !== undefined) {
87
+ output += `Ask before refactoring outside scope: ${content.ask_before_refactoring ? 'yes' : 'no'}\n`;
88
+ }
89
+ if (content.refactor_notes) {
90
+ output += `${content.refactor_notes}\n`;
91
+ }
92
+ output += '\n';
93
+ }
94
+ return output;
95
+ }
96
+ function isContentEmpty(content) {
97
+ const hasProtectedFiles = content.protected_files && content.protected_files.length > 0;
98
+ const hasSensitiveData = content.sensitive_data && content.sensitive_data.length > 0;
99
+ const hasTeamBoundaries = content.team_boundaries && content.team_boundaries.length > 0;
100
+ const hasInvariants = content.invariants && content.invariants.length > 0;
101
+ const hasRefactorRules = !!(content.refactor_scope || content.ask_before_refactoring !== undefined || content.refactor_notes);
102
+ return !(hasProtectedFiles || hasSensitiveData || hasTeamBoundaries || hasInvariants || hasRefactorRules);
103
+ }
104
+ // ══════════════════════════════════════════════════════════════
105
+ // Main Tool Function
106
+ // ══════════════════════════════════════════════════════════════
107
+ export async function loadGuardrails(input) {
108
+ const apiKey = process.env.AGENTBRAIN_API_KEY;
109
+ if (!apiKey) {
110
+ return `Guardrails requires an API key.
111
+ Add AGENTBRAIN_API_KEY to your MCP config env block.
112
+ Get your key at useagentbrain.com/settings`;
113
+ }
114
+ try {
115
+ const res = await fetch(GUARDRAILS_URL, {
116
+ method: 'GET',
117
+ headers: {
118
+ 'x-api-key': apiKey,
119
+ 'Content-Type': 'application/json',
120
+ },
121
+ });
122
+ if (res.status === 401) {
123
+ return 'Invalid AGENTBRAIN_API_KEY. Check your MCP config env block.';
124
+ }
125
+ if (res.status === 404) {
126
+ return `No Guardrails found for this workspace.
127
+ Create one at useagentbrain.com/settings → Guardrails tab.`;
128
+ }
129
+ if (!res.ok) {
130
+ const json = (await res.json());
131
+ return json.error ?? 'Failed to load Guardrails from AgentBrain.';
132
+ }
133
+ const json = (await res.json());
134
+ if (!json.data) {
135
+ return `No Guardrails found for this workspace.
136
+ Create one at useagentbrain.com/settings → Guardrails tab.`;
137
+ }
138
+ const content = json.data.content;
139
+ if (isContentEmpty(content)) {
140
+ return `Guardrails exists but has no content yet.
141
+ Fill it out at useagentbrain.com/settings → Guardrails tab.`;
142
+ }
143
+ return formatGuardrails(content);
144
+ }
145
+ catch (err) {
146
+ return err instanceof Error ? err.message : 'Failed to load Guardrails.';
147
+ }
148
+ }
149
+ //# sourceMappingURL=load-guardrails.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-guardrails.js","sourceRoot":"","sources":["../../src/tools/load-guardrails.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"load-standards.d.ts","sourceRoot":"","sources":["../../src/tools/load-standards.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAYnD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAsB3F;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;CAmB/B,CAAA"}
1
+ {"version":3,"file":"load-standards.d.ts","sourceRoot":"","sources":["../../src/tools/load-standards.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAyBnD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,WAAW,CAAA;CACnB;AAiID,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAsD3F;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;CAmB/B,CAAA"}
@@ -1,9 +1,14 @@
1
- // MCP tool: load_standards - read standards file for an agent
1
+ // MCP tool: load_standards - read standards file (cloud or local)
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import { existsSync } from 'node:fs';
4
4
  import { join, resolve } from 'node:path';
5
5
  import { homedir } from 'node:os';
6
6
  import { AGENT_FILE_PATHS } from '@agentbrain/core';
7
+ // ══════════════════════════════════════════════════════════════
8
+ // Environment & Configuration
9
+ // ══════════════════════════════════════════════════════════════
10
+ const BASE_URL = process.env.AGENTBRAIN_API_BASE_URL?.replace(/\/$/, '') ?? 'https://www.useagentbrain.com/api/v1';
11
+ const STANDARDS_URL = `${BASE_URL}/standards`;
7
12
  /**
8
13
  * Expand path: handles ~, relative paths, etc.
9
14
  */
@@ -13,14 +18,140 @@ function expandPath(path) {
13
18
  }
14
19
  return resolve(path);
15
20
  }
21
+ // ══════════════════════════════════════════════════════════════
22
+ // Formatting
23
+ // ══════════════════════════════════════════════════════════════
24
+ function formatStandards(content) {
25
+ const workspaceName = content.workspace_name || 'Workspace';
26
+ let output = `# Standards — ${workspaceName}\n\n`;
27
+ // Test Strategy
28
+ if (content.test_strategy) {
29
+ const ts = content.test_strategy;
30
+ if (ts.framework || ts.always_test || ts.never_test || ts.coverage_goal || ts.required) {
31
+ output += '## Test Strategy\n';
32
+ if (ts.framework)
33
+ output += `Framework: ${ts.framework}\n`;
34
+ if (ts.always_test)
35
+ output += `Always test: ${ts.always_test}\n`;
36
+ if (ts.never_test)
37
+ output += `Never test: ${ts.never_test}\n`;
38
+ if (ts.coverage_goal)
39
+ output += `Coverage goal: ${ts.coverage_goal}\n`;
40
+ if (ts.required)
41
+ output += `Required: ${ts.required}\n`;
42
+ output += '\n';
43
+ }
44
+ }
45
+ // PR Requirements
46
+ if (content.pr_requirements) {
47
+ const pr = content.pr_requirements;
48
+ if (pr.max_pr_size || pr.commit_format || pr.description_required !== undefined || pr.tests_required !== undefined) {
49
+ output += '## PR Requirements\n';
50
+ if (pr.max_pr_size)
51
+ output += `Max PR size: ${pr.max_pr_size}\n`;
52
+ if (pr.commit_format)
53
+ output += `Commit format: ${pr.commit_format}\n`;
54
+ if (pr.description_required !== undefined)
55
+ output += `Description required: ${pr.description_required ? 'yes' : 'no'}\n`;
56
+ if (pr.tests_required !== undefined)
57
+ output += `Tests required: ${pr.tests_required ? 'yes' : 'no'}\n`;
58
+ output += '\n';
59
+ }
60
+ }
61
+ // Code Style
62
+ if (content.code_style) {
63
+ const cs = content.code_style;
64
+ if (cs.max_function_length || cs.naming_conventions || cs.comment_style || cs.forbidden_patterns) {
65
+ output += '## Code Style\n';
66
+ if (cs.max_function_length)
67
+ output += `Max function length: ${cs.max_function_length}\n`;
68
+ if (cs.naming_conventions)
69
+ output += `Naming conventions: ${cs.naming_conventions}\n`;
70
+ if (cs.comment_style)
71
+ output += `Comment style: ${cs.comment_style}\n`;
72
+ if (cs.forbidden_patterns)
73
+ output += `Forbidden patterns: ${cs.forbidden_patterns}\n`;
74
+ output += '\n';
75
+ }
76
+ }
77
+ // Definition of Done
78
+ if (content.definition_of_done && content.definition_of_done.length > 0) {
79
+ output += '## Definition of Done\n';
80
+ output += 'Before marking any task complete, verify ALL of these:\n';
81
+ for (const item of content.definition_of_done) {
82
+ output += `- ${item}\n`;
83
+ }
84
+ output += '\n';
85
+ }
86
+ // Run Commands
87
+ if (content.run_commands) {
88
+ const rc = content.run_commands;
89
+ if (rc.dev || rc.test || rc.build || rc.lint || rc.typecheck) {
90
+ output += '## Run Commands\n';
91
+ if (rc.dev)
92
+ output += `Dev: ${rc.dev}\n`;
93
+ if (rc.test)
94
+ output += `Test: ${rc.test}\n`;
95
+ if (rc.build)
96
+ output += `Build: ${rc.build}\n`;
97
+ if (rc.lint)
98
+ output += `Lint: ${rc.lint}\n`;
99
+ if (rc.typecheck)
100
+ output += `Type check: ${rc.typecheck}\n`;
101
+ output += '\n';
102
+ }
103
+ }
104
+ return output;
105
+ }
106
+ function isContentEmpty(content) {
107
+ const hasTestStrategy = content.test_strategy && Object.values(content.test_strategy).some(v => v);
108
+ const hasPRRequirements = content.pr_requirements && Object.values(content.pr_requirements).some(v => v !== undefined);
109
+ const hasCodeStyle = content.code_style && Object.values(content.code_style).some(v => v);
110
+ const hasDefinitionOfDone = content.definition_of_done && content.definition_of_done.length > 0;
111
+ const hasRunCommands = content.run_commands && Object.values(content.run_commands).some(v => v);
112
+ return !(hasTestStrategy || hasPRRequirements || hasCodeStyle || hasDefinitionOfDone || hasRunCommands);
113
+ }
114
+ // ══════════════════════════════════════════════════════════════
115
+ // Main Tool Function
116
+ // ══════════════════════════════════════════════════════════════
16
117
  export async function loadStandards(input) {
17
118
  const { repo_path, agent } = input;
18
- // Expand path to handle ~, relative paths, etc.
19
119
  const expandedPath = expandPath(repo_path);
120
+ const apiKey = process.env.AGENTBRAIN_API_KEY;
121
+ // ── Cloud mode with fallback ──────────────────────────────
122
+ if (apiKey) {
123
+ try {
124
+ const res = await fetch(STANDARDS_URL, {
125
+ method: 'GET',
126
+ headers: {
127
+ 'x-api-key': apiKey,
128
+ 'Content-Type': 'application/json',
129
+ },
130
+ });
131
+ // If 200 with content, use cloud version
132
+ if (res.ok) {
133
+ const json = (await res.json());
134
+ if (json.data && !isContentEmpty(json.data.content)) {
135
+ return {
136
+ content: formatStandards(json.data.content),
137
+ filePath: 'cloud:standards',
138
+ agent,
139
+ };
140
+ }
141
+ }
142
+ // 404 or empty content → fall back to local file
143
+ }
144
+ catch (err) {
145
+ // Network error → fall back to local file
146
+ }
147
+ }
148
+ // ── Local disk mode (no API key OR cloud fallback) ────────
20
149
  const relativePath = AGENT_FILE_PATHS[agent];
21
150
  const filePath = join(expandedPath, relativePath);
22
151
  if (!existsSync(filePath)) {
23
- throw new Error(`Standards file not found: ${relativePath}. Run "agentbrain standards" to generate it.`);
152
+ throw new Error(apiKey
153
+ ? `No Standards found. Create one at useagentbrain.com/settings → Standards tab or create a local standards file.`
154
+ : `Standards file not found: ${relativePath}. Run "agentbrain standards" to generate it.`);
24
155
  }
25
156
  const content = await readFile(filePath, 'utf-8');
26
157
  return {
@@ -31,7 +162,7 @@ export async function loadStandards(input) {
31
162
  }
32
163
  export const loadStandardsSchema = {
33
164
  name: 'load_standards',
34
- description: 'Load coding standards file for a specific agent (Claude Code, Cursor, or Windsurf). Reads from disk - no AI call needed.',
165
+ description: 'Load coding standards (test/PR requirements). With AGENTBRAIN_API_KEY set, fetches from cloud first, falls back to local file. Without API key, reads from disk only.',
35
166
  inputSchema: {
36
167
  type: 'object',
37
168
  properties: {
@@ -1 +1 @@
1
- {"version":3,"file":"load-standards.js","sourceRoot":"","sources":["../../src/tools/load-standards.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAE9D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGnD;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IACrC,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAA;AACtB,CAAC;AAaD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAyB;IAC3D,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,CAAA;IAElC,gDAAgD;IAChD,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;IAE1C,MAAM,YAAY,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IAEjD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,6BAA6B,YAAY,8CAA8C,CACxF,CAAA;IACH,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAEjD,OAAO;QACL,OAAO;QACP,QAAQ,EAAE,YAAY;QACtB,KAAK;KACN,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,0HAA0H;IAC5H,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,iCAAiC;aAC/C;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,aAAa,EAAE,QAAQ,EAAE,UAAU,CAAC;gBAC3C,WAAW,EAAE,mCAAmC;aACjD;SACF;QACD,QAAQ,EAAE,CAAC,WAAW,EAAE,OAAO,CAAC;KACjC;CACF,CAAA"}
1
+ {"version":3,"file":"load-standards.js","sourceRoot":"","sources":["../../src/tools/load-standards.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface PreflightCheckInput {
2
+ repo_path: string;
3
+ task?: string;
4
+ }
5
+ export declare const preflightCheckSchema: {
6
+ name: string;
7
+ description: string;
8
+ inputSchema: {
9
+ type: string;
10
+ properties: {
11
+ repo_path: {
12
+ type: string;
13
+ description: string;
14
+ };
15
+ task: {
16
+ type: string;
17
+ description: string;
18
+ };
19
+ };
20
+ required: string[];
21
+ };
22
+ };
23
+ export declare function preflightCheck(input: PreflightCheckInput): Promise<string>;
24
+ //# sourceMappingURL=preflight-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preflight-check.d.ts","sourceRoot":"","sources":["../../src/tools/preflight-check.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAwBD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;CAyBhC,CAAA;AA8GD,wBAAsB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqJhF"}
@@ -0,0 +1,279 @@
1
+ // MCP tool: preflight_check - Load everything before starting a task
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { loadContext } from './load-context.js';
5
+ import { loadBlueprint } from './load-blueprint.js';
6
+ import { loadGuardrails } from './load-guardrails.js';
7
+ import { loadStandards } from './load-standards.js';
8
+ import { loadDecisions } from './load-decisions.js';
9
+ // ══════════════════════════════════════════════════════════════
10
+ // Environment & Configuration
11
+ // ══════════════════════════════════════════════════════════════
12
+ const BASE_URL = process.env.AGENTBRAIN_API_BASE_URL?.replace(/\/$/, '') ?? 'https://www.useagentbrain.com/api/v1';
13
+ const SPECS_URL = `${BASE_URL}/specs`;
14
+ /**
15
+ * Expand path: handles ~, relative paths, etc.
16
+ */
17
+ function expandPath(path) {
18
+ if (path.startsWith('~/') || path === '~') {
19
+ return path.replace('~', homedir());
20
+ }
21
+ if (!path.startsWith('/')) {
22
+ return join(process.cwd(), path);
23
+ }
24
+ return path;
25
+ }
26
+ // ══════════════════════════════════════════════════════════════
27
+ // Schema
28
+ // ══════════════════════════════════════════════════════════════
29
+ export const preflightCheckSchema = {
30
+ name: 'preflight_check',
31
+ description: 'Run before starting ANY task. Loads codebase context, workspace Playbook (Blueprint, Guardrails, Standards, Decisions), and active spec in one parallel call. Returns a targeted briefing for your task.\n\n' +
32
+ 'Use this instead of calling load_context(), load_blueprint(), load_guardrails(), load_standards(), load_decisions(), and load_spec() separately.\n\n' +
33
+ 'Usage:\n' +
34
+ 'preflight_check({\n' +
35
+ ' repo_path: "/path/to/repo",\n' +
36
+ ' task: "what you are about to build"\n' +
37
+ '})',
38
+ inputSchema: {
39
+ type: 'object',
40
+ properties: {
41
+ repo_path: {
42
+ type: 'string',
43
+ description: 'Absolute path to repository',
44
+ },
45
+ task: {
46
+ type: 'string',
47
+ description: 'Optional: What you are about to do (e.g., "implement Stripe webhook handler", "refactor auth module"). Used to filter relevant context.',
48
+ },
49
+ },
50
+ required: ['repo_path'],
51
+ },
52
+ };
53
+ // ══════════════════════════════════════════════════════════════
54
+ // Helpers
55
+ // ══════════════════════════════════════════════════════════════
56
+ async function fetchActiveSpec(apiKey) {
57
+ try {
58
+ const res = await fetch(SPECS_URL, {
59
+ method: 'GET',
60
+ headers: {
61
+ 'x-api-key': apiKey,
62
+ 'Content-Type': 'application/json',
63
+ },
64
+ });
65
+ if (!res.ok)
66
+ return null;
67
+ const json = (await res.json());
68
+ if (!json.data)
69
+ return null;
70
+ const spec = json.data;
71
+ const approach = Array.isArray(spec.answers.approach)
72
+ ? spec.answers.approach.map((a) => `- ${a}`).join('\n')
73
+ : spec.answers.approach;
74
+ const doneCriteria = Array.isArray(spec.answers.done_criteria)
75
+ ? spec.answers.done_criteria.map((d) => `- [ ] ${d}`).join('\n')
76
+ : spec.answers.done_criteria;
77
+ return `**${spec.title}** (${spec.status})
78
+
79
+ Problem: ${spec.answers.problem}
80
+
81
+ Approach:
82
+ ${approach}
83
+
84
+ Done Criteria:
85
+ ${doneCriteria}`;
86
+ }
87
+ catch (err) {
88
+ return null;
89
+ }
90
+ }
91
+ function isRelevantSection(section, task) {
92
+ const taskLower = task.toLowerCase();
93
+ const sectionLower = section.toLowerCase();
94
+ // Auth-related tasks
95
+ if (taskLower.includes('auth') && sectionLower.includes('auth'))
96
+ return true;
97
+ // Billing/payment tasks
98
+ if ((taskLower.includes('billing') || taskLower.includes('stripe') || taskLower.includes('payment')) &&
99
+ (sectionLower.includes('billing') || sectionLower.includes('stripe') || sectionLower.includes('payment'))) {
100
+ return true;
101
+ }
102
+ // Database tasks
103
+ if ((taskLower.includes('database') || taskLower.includes('migration') || taskLower.includes('schema')) &&
104
+ (sectionLower.includes('database') || sectionLower.includes('migration') || sectionLower.includes('schema'))) {
105
+ return true;
106
+ }
107
+ // API tasks
108
+ if ((taskLower.includes('api') || taskLower.includes('endpoint') || taskLower.includes('route')) &&
109
+ (sectionLower.includes('api') || sectionLower.includes('endpoint') || sectionLower.includes('route'))) {
110
+ return true;
111
+ }
112
+ return false;
113
+ }
114
+ function filterContent(content, task) {
115
+ if (!task)
116
+ return content;
117
+ const lines = content.split('\n');
118
+ const filtered = [];
119
+ let currentSection = '';
120
+ let includeSection = false;
121
+ for (const line of lines) {
122
+ // New section header
123
+ if (line.startsWith('##')) {
124
+ currentSection = line;
125
+ includeSection = isRelevantSection(line, task);
126
+ if (includeSection) {
127
+ filtered.push(line);
128
+ }
129
+ }
130
+ else if (includeSection) {
131
+ // Include content from relevant sections
132
+ filtered.push(line);
133
+ }
134
+ else if (line.startsWith('#') || line.trim() === '') {
135
+ // Always include top-level headers and blank lines
136
+ filtered.push(line);
137
+ }
138
+ }
139
+ return filtered.join('\n');
140
+ }
141
+ // ══════════════════════════════════════════════════════════════
142
+ // Main Tool Function
143
+ // ══════════════════════════════════════════════════════════════
144
+ export async function preflightCheck(input) {
145
+ const { repo_path, task } = input;
146
+ const expandedPath = expandPath(repo_path);
147
+ const apiKey = process.env.AGENTBRAIN_API_KEY;
148
+ let output = '# Preflight Check ✓\n\n';
149
+ const errors = [];
150
+ // ── Parallel fetch all sources ────────────────────────────────
151
+ const results = await Promise.allSettled([
152
+ // Load slim context summary
153
+ loadContext({ repo_path, full: false }),
154
+ // Load workspace documents
155
+ apiKey ? loadBlueprint({ repo_path }) : Promise.resolve(null),
156
+ apiKey ? loadGuardrails({ repo_path }) : Promise.resolve(null),
157
+ apiKey ? loadStandards({ repo_path, agent: 'claude-code' }) : Promise.resolve(null),
158
+ apiKey ? loadDecisions({ repo_path }) : Promise.resolve(null),
159
+ // Load active spec
160
+ apiKey ? fetchActiveSpec(apiKey) : Promise.resolve(null),
161
+ ]);
162
+ // Extract results
163
+ const [contextResult, blueprintResult, guardrailsResult, standardsResult, decisionsResult, specResult] = results;
164
+ const context = contextResult.status === 'fulfilled' ? contextResult.value.content : null;
165
+ const blueprint = blueprintResult.status === 'fulfilled' ? blueprintResult.value : null;
166
+ const guardrails = guardrailsResult.status === 'fulfilled' ? guardrailsResult.value : null;
167
+ const standards = standardsResult.status === 'fulfilled' ? standardsResult.value?.content : null;
168
+ const decisions = decisionsResult.status === 'fulfilled' ? decisionsResult.value : null;
169
+ const spec = specResult.status === 'fulfilled' ? specResult.value : null;
170
+ // Track errors
171
+ if (contextResult.status === 'rejected')
172
+ errors.push(`Context: ${contextResult.reason}`);
173
+ if (blueprintResult.status === 'rejected')
174
+ errors.push(`Blueprint: ${blueprintResult.reason}`);
175
+ if (guardrailsResult.status === 'rejected')
176
+ errors.push(`Guardrails: ${guardrailsResult.reason}`);
177
+ if (standardsResult.status === 'rejected')
178
+ errors.push(`Standards: ${standardsResult.reason}`);
179
+ if (decisionsResult.status === 'rejected')
180
+ errors.push(`Decisions: ${decisionsResult.reason}`);
181
+ // ── Build output ───────────────────────────────────────────────
182
+ // Active Spec
183
+ if (spec) {
184
+ output += '## Active Spec\n';
185
+ output += spec + '\n\n';
186
+ }
187
+ else if (apiKey) {
188
+ output += '## Active Spec\n';
189
+ output += 'No active spec. Create one at useagentbrain.com/specs\n\n';
190
+ }
191
+ // Codebase Context
192
+ if (context) {
193
+ // Extract branch info
194
+ const contextLines = context.split('\n');
195
+ const branchLineIndex = contextLines.findIndex((l) => l.includes('## Current Branch'));
196
+ const branch = branchLineIndex >= 0 ? contextLines[branchLineIndex + 1]?.trim() : 'unknown';
197
+ output += '## Codebase Context\n';
198
+ output += `Branch: ${branch}\n`;
199
+ // Extract 2-3 line summary from context
200
+ const lines = context.split('\n').filter((l) => l.trim() && !l.startsWith('#'));
201
+ const summary = lines.slice(0, 3).join('\n');
202
+ if (summary) {
203
+ output += summary + '\n';
204
+ }
205
+ output += '\n';
206
+ }
207
+ // How We Build Here (Blueprint)
208
+ if (blueprint && !blueprint.includes('requires an API key') && !blueprint.includes('no content yet')) {
209
+ output += '## How We Build Here\n';
210
+ const filtered = task ? filterContent(blueprint, task) : blueprint;
211
+ // Remove the top-level title
212
+ const content = filtered.replace(/^# Blueprint.*\n\n/, '');
213
+ output += content + '\n';
214
+ }
215
+ // Guardrails for This Task
216
+ if (guardrails && !guardrails.includes('requires an API key') && !guardrails.includes('no content yet')) {
217
+ const isRefactor = task?.toLowerCase().includes('refactor');
218
+ output += isRefactor ? '## Guardrails (Refactoring)\n' : '## Guardrails for This Task\n';
219
+ const filtered = task ? filterContent(guardrails, task) : guardrails;
220
+ // Remove the top-level title
221
+ const content = filtered.replace(/^# Guardrails.*\n\n/, '');
222
+ output += content + '\n';
223
+ }
224
+ // Decisions to Know
225
+ if (decisions && !decisions.includes('requires an API key') && !decisions.includes('No Decisions found')) {
226
+ output += '## Decisions to Know\n';
227
+ const filtered = task ? filterContent(decisions, task) : decisions;
228
+ // Remove the top-level title
229
+ const content = filtered.replace(/^# Decisions.*\n\n/, '');
230
+ output += content + '\n';
231
+ }
232
+ // Standards (emphasize for test/PR/review tasks)
233
+ const isTestOrPR = task?.toLowerCase().match(/test|pr|review|done/);
234
+ if (standards && isTestOrPR) {
235
+ output += '## Standards & Definition of Done\n';
236
+ const filtered = task ? filterContent(standards, task) : standards;
237
+ // Remove the top-level title
238
+ const content = filtered.replace(/^# Standards.*\n\n/, '');
239
+ output += content + '\n';
240
+ }
241
+ else if (standards) {
242
+ // Extract just Definition of Done for other tasks
243
+ const dodMatch = standards.match(/## Definition of Done\n([\s\S]*?)(?=\n##|\n$|$)/);
244
+ if (dodMatch) {
245
+ output += '## Definition of Done\n';
246
+ output += dodMatch[1].trim() + '\n\n';
247
+ }
248
+ }
249
+ // ── Footer ─────────────────────────────────────────────────────
250
+ // No API key message
251
+ if (!apiKey) {
252
+ output += '\n---\n\n';
253
+ output +=
254
+ '💡 Add AGENTBRAIN_API_KEY to your MCP config to load Blueprint, Guardrails, Standards, and Decisions.\n';
255
+ output += 'Get your key at useagentbrain.com/settings\n\n';
256
+ }
257
+ // No Playbook message
258
+ if (apiKey &&
259
+ blueprint?.includes('no content yet') &&
260
+ guardrails?.includes('no content yet') &&
261
+ decisions?.includes('No Decisions found')) {
262
+ output += '\n---\n\n';
263
+ output += '💡 No Playbook found for this workspace.\n';
264
+ output += 'Create one at useagentbrain.com/playbook to give your agent architectural guidance.\n\n';
265
+ }
266
+ // Errors
267
+ if (errors.length > 0) {
268
+ output += '\n---\n\n';
269
+ output += '⚠️ Some sources failed to load:\n';
270
+ for (const error of errors) {
271
+ output += `- ${error}\n`;
272
+ }
273
+ output += '\n';
274
+ }
275
+ output += '---\n';
276
+ output += 'Ready. Proceed with task.\n';
277
+ return output;
278
+ }
279
+ //# sourceMappingURL=preflight-check.js.map