@andespindola/brainlink 1.6.14 → 1.7.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.
@@ -1,9 +1,12 @@
1
1
  // Self-contained branded OAuth authorization/consent page for the Brainlink MCP
2
- // server. Served as a plain string (inline <style>, no external assets, no
3
- // framework, no JavaScript) so it works identically for a global npm install.
4
- // The visual identity mirrors the graph client and auth pages (see
5
- // client-css.ts / login-page.ts): dark theme on #08131d, the same grid/radial
6
- // gradient, Crowquill Mono with a monospace fallback, and the #5aa8ff accent.
2
+ // server. Served as a plain string (inline <style>, no external assets beyond
3
+ // the shared Google Fonts @import, no framework, no JavaScript) so it works
4
+ // identically for a global npm install. The visual identity is the unified neon
5
+ // system shared with the SaaS app and the graph client (see neon-theme.ts /
6
+ // auth-styles.ts): #0a0e1a base, faint cyber grid, cyan #22d3ee + violet
7
+ // #8b5cf6, Space Grotesk headings / DM Sans body, glass card + gradient
8
+ // wordmark, so the SSO consent step reads as part of one product.
9
+ import { authSharedStyles } from '../application/frontend/auth-styles.js';
7
10
  // HTML-escape dynamic values. clientName arrives from an untrusted OAuth client
8
11
  // and hidden values carry OAuth params, so both must never allow HTML injection.
9
12
  const escapeHtml = (value) => value
@@ -12,85 +15,14 @@ const escapeHtml = (value) => value
12
15
  .replace(/>/g, '&gt;')
13
16
  .replace(/"/g, '&quot;')
14
17
  .replace(/'/g, '&#39;');
15
- const authorizeStyles = () => `:root {
16
- color-scheme: dark;
17
- --bg: #08131d;
18
- --panel: #0d1823;
19
- --panel-strong: #112130;
20
- --line: rgba(143, 172, 204, 0.18);
21
- --text: #edf4ff;
22
- --muted: #97a9bd;
23
- --accent: #5aa8ff;
24
- --accent-weak: rgba(90, 168, 255, 0.18);
25
- --danger: #ff6b6b;
26
- }
27
-
28
- * {
29
- box-sizing: border-box;
30
- }
31
-
32
- html,
33
- body {
34
- width: 100%;
35
- min-height: 100%;
36
- margin: 0;
37
- }
38
-
39
- body {
40
- display: flex;
41
- align-items: center;
42
- justify-content: center;
43
- min-height: 100vh;
44
- min-height: 100dvh;
45
- padding: 24px;
46
- color: var(--text);
47
- font-family: "Crowquill Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
48
- background:
49
- linear-gradient(rgba(164, 197, 230, 0.05) 1px, transparent 1px),
50
- linear-gradient(90deg, rgba(164, 197, 230, 0.05) 1px, transparent 1px),
51
- radial-gradient(circle at top, rgba(43, 93, 143, 0.22), transparent 44%),
52
- #08131d;
53
- background-size: 28px 28px, 28px 28px, auto;
54
- }
55
-
56
- button,
57
- input {
58
- font: inherit;
59
- }
60
-
61
- .auth-card {
62
- width: 100%;
63
- max-width: 400px;
64
- padding: 32px 28px;
65
- border: 1px solid var(--line);
66
- border-radius: 14px;
67
- background: rgba(13, 24, 35, 0.92);
68
- box-shadow: 0 24px 80px rgba(1, 6, 13, 0.48);
69
- backdrop-filter: blur(8px);
70
- }
71
-
72
- .auth-brand {
73
- display: grid;
74
- gap: 4px;
75
- margin-bottom: 20px;
76
- }
77
-
78
- .auth-brand strong {
79
- font-size: 26px;
80
- letter-spacing: 0.01em;
81
- }
82
-
83
- .auth-brand span {
84
- color: var(--muted);
85
- font-size: 13px;
86
- }
18
+ const authorizeStyles = () => `${authSharedStyles(400)}
87
19
 
88
20
  .auth-consent {
89
21
  margin: 0 0 20px;
90
22
  padding: 12px 14px;
91
23
  border: 1px solid var(--line);
92
- border-radius: 10px;
93
- background: rgba(12, 24, 36, 0.6);
24
+ border-radius: 12px;
25
+ background: rgba(19, 26, 42, 0.55);
94
26
  color: var(--text);
95
27
  font-size: 13px;
96
28
  line-height: 1.5;
@@ -101,58 +33,7 @@ input {
101
33
  color: var(--accent);
102
34
  }
103
35
 
104
- .auth-form {
105
- display: grid;
106
- gap: 16px;
107
- }
108
-
109
- .auth-field {
110
- display: grid;
111
- gap: 7px;
112
- }
113
-
114
- .auth-field label {
115
- color: var(--muted);
116
- font-size: 12px;
117
- letter-spacing: 0.02em;
118
- }
119
-
120
- .auth-field input {
121
- width: 100%;
122
- height: 42px;
123
- padding: 0 14px;
124
- border: 1px solid var(--line);
125
- border-radius: 8px;
126
- outline: none;
127
- background: rgba(12, 24, 36, 0.94);
128
- color: var(--text);
129
- }
130
-
131
- .auth-field input:focus {
132
- border-color: var(--accent);
133
- }
134
-
135
- .auth-submit {
136
- height: 44px;
137
- margin-top: 4px;
138
- border: 1px solid var(--accent);
139
- border-radius: 8px;
140
- background: var(--accent-weak);
141
- color: var(--text);
142
- cursor: pointer;
143
- transition: background 120ms ease, opacity 120ms ease;
144
- }
145
-
146
- .auth-submit:hover,
147
- .auth-submit:focus {
148
- background: rgba(90, 168, 255, 0.3);
149
- }
150
-
151
36
  .auth-message {
152
- margin: 0;
153
- font-size: 12px;
154
- line-height: 1.4;
155
- overflow-wrap: anywhere;
156
37
  color: var(--danger);
157
38
  }`;
158
39
  const consentLine = (clientName) => {
@@ -1,5 +1,5 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { addNoteInputSchema, addFileInputSchema, addFileTool, addImageInputSchema, addImageTool, addNoteTool, addNotesInputSchema, addNotesTool, deleteNoteInputSchema, deleteNoteTool, deleteNotesInputSchema, deleteNotesTool, volatileAddInputSchema, volatileAddTool, volatileClearInputSchema, volatileClearTool, dedupeInputSchema, dedupeResolveInputSchema, dedupeResolveTool, dedupeTool, brokenLinksInputSchema, brokenLinksTool, bootstrapInputSchema, bootstrapTool, canonicalizeContextLinksInputSchema, canonicalizeContextLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, explainInputSchema, explainTool, indexInputSchema, indexTool, inboxAddInputSchema, inboxAddTool, inboxListInputSchema, inboxListTool, inboxProcessInputSchema, inboxProcessTool, orphansInputSchema, orphansTool, policyInputSchema, policyTool, projectInitInputSchema, projectInitTool, recommendationsInputSchema, recommendationsTool, rememberInputSchema, rememberTool, repairLinksInputSchema, repairLinksTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, sessionCloseInputSchema, sessionCloseTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, syncInputSchema, syncTool, validateInputSchema, validateTool, vaultBundleListInputSchema, vaultBundleListTool, vaultCommitInputSchema, vaultCommitTool, vaultExportBundleInputSchema, vaultExportBundleTool, vaultExportInputSchema, vaultExportTool, vaultHistoryInputSchema, vaultHistoryTool, vaultImportBundleInputSchema, vaultImportBundleTool, vaultImportInputSchema, vaultImportTool, vaultInitInputSchema, vaultInitTool, vaultMergeAgentsInputSchema, vaultMergeAgentsTool, vaultProvisionInputSchema, vaultProvisionTool, vaultPullInputSchema, vaultPullTool, vaultRestoreInputSchema, vaultRestoreTool, vaultStatusInputSchema, vaultStatusTool, versionInputSchema, versionTool } from './tools.js';
2
+ import { addNoteInputSchema, addFileInputSchema, addFileTool, addImageInputSchema, addImageTool, addNoteTool, addNotesInputSchema, addNotesTool, deleteNoteInputSchema, deleteNoteTool, deleteNotesInputSchema, deleteNotesTool, volatileAddInputSchema, volatileAddTool, volatileClearInputSchema, volatileClearTool, dedupeInputSchema, dedupeResolveInputSchema, dedupeResolveTool, dedupeTool, brokenLinksInputSchema, brokenLinksTool, bootstrapInputSchema, bootstrapTool, canonicalizeContextLinksInputSchema, canonicalizeContextLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, getImageInputSchema, getImageTool, explainInputSchema, explainTool, indexInputSchema, indexTool, inboxAddInputSchema, inboxAddTool, inboxListInputSchema, inboxListTool, inboxProcessInputSchema, inboxProcessTool, orphansInputSchema, orphansTool, policyInputSchema, policyTool, projectInitInputSchema, projectInitTool, recommendationsInputSchema, recommendationsTool, rememberInputSchema, rememberTool, repairLinksInputSchema, repairLinksTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, sessionCloseInputSchema, sessionCloseTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, syncInputSchema, syncTool, validateInputSchema, validateTool, vaultBundleListInputSchema, vaultBundleListTool, vaultCommitInputSchema, vaultCommitTool, vaultExportBundleInputSchema, vaultExportBundleTool, vaultExportInputSchema, vaultExportTool, vaultHistoryInputSchema, vaultHistoryTool, vaultImportBundleInputSchema, vaultImportBundleTool, vaultImportInputSchema, vaultImportTool, vaultInitInputSchema, vaultInitTool, vaultMergeAgentsInputSchema, vaultMergeAgentsTool, vaultProvisionInputSchema, vaultProvisionTool, vaultPullInputSchema, vaultPullTool, vaultRestoreInputSchema, vaultRestoreTool, vaultStatusInputSchema, vaultStatusTool, versionInputSchema, versionTool } from './tools.js';
3
3
  import { getRuntimeVersion } from './runtime.js';
4
4
  import { brainlinkServerInstructions } from './server-instructions.js';
5
5
  import { guardToolHandler } from './tool-guard.js';
@@ -131,6 +131,11 @@ export const createBrainlinkMcpServer = () => {
131
131
  description: 'Store an image in the vault (encrypted at rest when vault encryption is on) and address it by a stable vault-relative path. Provide imageBase64 or filePath. Optionally pass noteTitle to create a note that embeds the image so retrieval can surface it in context. Alt text is included in the returned context descriptor.',
132
132
  inputSchema: addImageInputSchema
133
133
  }, addImageTool);
134
+ server.registerTool('brainlink_get_image', {
135
+ title: 'Get Brainlink Image',
136
+ description: 'Retrieve the raw bytes of an image stored in the vault by a stable vault-relative asset path (as returned by brainlink_add_image). Returns the descriptor plus base64-encoded bytes so a second agent can fetch and use an image another agent added to the shared vault. Decrypts transparently when the vault stores images encrypted at rest; the path must resolve inside .brainlink/assets.',
137
+ inputSchema: getImageInputSchema
138
+ }, getImageTool);
134
139
  server.registerTool('brainlink_canonicalize_context_links', {
135
140
  title: 'Canonicalize Brainlink Context Links',
136
141
  description: 'Ensure notes have canonical Context Links to inferred context hubs. Supports dry-run and can create missing hub notes.',
@@ -3,6 +3,7 @@ import { getBrokenLinksReport, getOrphansReport, getStats, validateVault } from
3
3
  import { buildContextPackage, readContextDataSignature, readVolatileSignature } from '../../application/build-context.js';
4
4
  import { getGraph } from '../../application/get-graph.js';
5
5
  import { getGraphContexts } from '../../application/get-graph-contexts.js';
6
+ import { getImage } from '../../application/get-image.js';
6
7
  import { explainSearchResults, suggestBrokenLinkFixes, suggestContextLinks } from '../../application/memory-suggestions.js';
7
8
  import { buildActionableDoctor } from '../../application/operational-workflows.js';
8
9
  import { searchKnowledge } from '../../application/search-knowledge.js';
@@ -539,3 +540,28 @@ export const recommendationsTool = async (input) => {
539
540
  recommendations
540
541
  });
541
542
  };
543
+ export const getImageInputSchema = {
544
+ ...vaultInput,
545
+ ...agentInput,
546
+ path: z
547
+ .string()
548
+ .min(1)
549
+ .describe('Vault-relative asset path to fetch, as returned by brainlink_add_image (e.g. ".brainlink/assets/shared/<sha>.png"). Must resolve inside the vault .brainlink/assets tree.'),
550
+ alt: z.string().min(1).optional().describe('Optional alt text / description to echo back in the descriptor.')
551
+ };
552
+ // Fetch the raw bytes of a stored image so another agent can retrieve and use an
553
+ // image a first agent added to the shared vault. Decrypts transparently when the
554
+ // bytes are stored encrypted-at-rest, and rejects paths outside .brainlink/assets.
555
+ export const getImageTool = async (input) => {
556
+ const context = await resolveExecutionContext(input);
557
+ const image = await getImage({
558
+ vaultPath: context.vault,
559
+ path: input.path,
560
+ alt: input.alt
561
+ });
562
+ return jsonResult({
563
+ vault: context.vault,
564
+ agent: context.agent,
565
+ image
566
+ });
567
+ };
package/dist/mcp/tools.js CHANGED
@@ -1,4 +1,4 @@
1
- export { brokenLinksInputSchema, brokenLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, explainInputSchema, explainTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, orphansInputSchema, orphansTool, recommendationsInputSchema, recommendationsTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, validateInputSchema, validateTool, versionInputSchema, versionTool } from './tools/read-tools.js';
1
+ export { brokenLinksInputSchema, brokenLinksTool, contextInputSchema, contextPacksInputSchema, contextPacksTool, contextTool, doctorActionsInputSchema, doctorActionsTool, explainInputSchema, explainTool, graphContextsInputSchema, graphContextsTool, graphInputSchema, graphTool, getImageInputSchema, getImageTool, orphansInputSchema, orphansTool, recommendationsInputSchema, recommendationsTool, searchInputSchema, searchTool, similarNotesInputSchema, similarNotesTool, statsInputSchema, statsTool, suggestLinksInputSchema, suggestLinksTool, validateInputSchema, validateTool, versionInputSchema, versionTool } from './tools/read-tools.js';
2
2
  export { addFileInputSchema, addFileTool, addImageInputSchema, addImageTool, addNoteInputSchema, addNoteTool, addNotesInputSchema, addNotesTool, deleteNoteInputSchema, deleteNoteTool, deleteNotesInputSchema, deleteNotesTool, inboxAddInputSchema, inboxAddTool, inboxListInputSchema, inboxListTool, inboxProcessInputSchema, inboxProcessTool, rememberInputSchema, rememberTool, volatileAddInputSchema, volatileAddTool, volatileClearInputSchema, volatileClearTool } from './tools/write-tools.js';
3
3
  export { bootstrapInputSchema, bootstrapTool, canonicalizeContextLinksInputSchema, canonicalizeContextLinksTool, dedupeInputSchema, dedupeResolveInputSchema, dedupeResolveTool, dedupeTool, indexInputSchema, indexTool, policyInputSchema, policyTool, projectInitInputSchema, projectInitTool, repairLinksInputSchema, repairLinksTool, sessionCloseInputSchema, sessionCloseTool, syncInputSchema, syncTool } from './tools/maintenance-tools.js';
4
4
  export { vaultBundleListInputSchema, vaultBundleListTool, vaultCommitInputSchema, vaultCommitTool, vaultExportBundleInputSchema, vaultExportBundleTool, vaultExportInputSchema, vaultExportTool, vaultHistoryInputSchema, vaultHistoryTool, vaultImportBundleInputSchema, vaultImportBundleTool, vaultImportInputSchema, vaultImportTool, vaultInitInputSchema, vaultInitTool, vaultMergeAgentsInputSchema, vaultMergeAgentsTool, vaultProvisionInputSchema, vaultProvisionTool, vaultPullInputSchema, vaultPullTool, vaultRestoreInputSchema, vaultRestoreTool, vaultStatusInputSchema, vaultStatusTool } from './tools/vault-tools.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andespindola/brainlink",
3
- "version": "1.6.14",
3
+ "version": "1.7.0",
4
4
  "description": "Local-first knowledge memory for agents with Markdown, backlinks, indexing and context retrieval.",
5
5
  "type": "module",
6
6
  "license": "MIT",