vault-go 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -146,7 +146,9 @@ Account and health: `vault_go_status`, `vault_go_cloud_health`, `vault_go_prefer
146
146
 
147
147
  Projects and sessions: `vault_go_projects`, `vault_go_project_create`, `vault_go_session_start`, `vault_go_session_end`, `vault_go_session_start_context`.
148
148
 
149
- Capture and recall: `vault_go_event`, `vault_go_remember`, `vault_go_forget`, `vault_go_search`, `vault_go_search_index`, `vault_go_observations`, `vault_go_timeline`, `vault_go_context`, `vault_go_file_context`, `vault_go_feed`, `vault_go_memory`, `vault_go_tool_uses`, `vault_go_stats`.
149
+ Capture and recall: `vault_go_event`, `vault_go_remember`, `vault_go_forget`, `vault_go_search`, `vault_go_search_index`, `vault_go_retrieve`, `vault_go_observations`, `vault_go_timeline`, `vault_go_context`, `vault_go_file_context`, `vault_go_feed`, `vault_go_memory`, `vault_go_tool_uses`, `vault_go_stats`.
150
+
151
+ `vault_go_retrieve` lets the central memory engine choose a bounded retrieval path while every explicit retrieval tool remains available. `vault_go_decision_status` reports sanitized rollout/circuit state. Jev and its credential remain in the engine; a healthy deployment does not by itself prove provider availability or decision quality.
150
152
 
151
153
  Knowledge bases: `vault_go_knowledge_bases`, `vault_go_knowledge_base`, `vault_go_knowledge_build`, `vault_go_knowledge_rebuild`, `vault_go_knowledge_query`, `vault_go_knowledge_delete`, `vault_go_prime_corpus`, `vault_go_query_corpus`, `vault_go_reprime_corpus`.
152
154
 
@@ -23,6 +23,11 @@ export declare const CAPABILITIES: {
23
23
  readonly status: "available";
24
24
  readonly tools: readonly ["vault_go_search_index", "vault_go_observations", "vault_go_timeline", "vault_go_feed"];
25
25
  readonly difference: "Vault uses UUID identifiers. Search accepts an optional query, offset and date ordering; timeline accepts an explicit UUID or resolves an anchor from a query; feed uses stable cursor pagination.";
26
+ }, {
27
+ readonly upstream: readonly ["automatic retrieval routing", "typed memory decisions"];
28
+ readonly status: "available";
29
+ readonly tools: readonly ["vault_go_retrieve", "vault_go_decision_status"];
30
+ readonly requires: "Jev runs only in the central memory engine. Status is sanitized; deployment availability does not prove provider health or decision quality. Explicit retrieval tools remain available.";
26
31
  }, {
27
32
  readonly upstream: readonly ["get_tool_uses"];
28
33
  readonly status: "available";
@@ -134,6 +139,11 @@ export declare function getCapabilities(home: string, cloud: VaultMemoryApi, ver
134
139
  readonly status: "available";
135
140
  readonly tools: readonly ["vault_go_search_index", "vault_go_observations", "vault_go_timeline", "vault_go_feed"];
136
141
  readonly difference: "Vault uses UUID identifiers. Search accepts an optional query, offset and date ordering; timeline accepts an explicit UUID or resolves an anchor from a query; feed uses stable cursor pagination.";
142
+ }, {
143
+ readonly upstream: readonly ["automatic retrieval routing", "typed memory decisions"];
144
+ readonly status: "available";
145
+ readonly tools: readonly ["vault_go_retrieve", "vault_go_decision_status"];
146
+ readonly requires: "Jev runs only in the central memory engine. Status is sanitized; deployment availability does not prove provider health or decision quality. Explicit retrieval tools remain available.";
137
147
  }, {
138
148
  readonly upstream: readonly ["get_tool_uses"];
139
149
  readonly status: "available";
@@ -11,6 +11,7 @@ export const CAPABILITIES = {
11
11
  capabilities: [
12
12
  { upstream: ['important_workflow'], status: 'available', tools: ['vault_go_workflow'] },
13
13
  { upstream: ['search', 'get_observations', 'timeline'], status: 'available', tools: ['vault_go_search_index', 'vault_go_observations', 'vault_go_timeline', 'vault_go_feed'], difference: 'Vault uses UUID identifiers. Search accepts an optional query, offset and date ordering; timeline accepts an explicit UUID or resolves an anchor from a query; feed uses stable cursor pagination.' },
14
+ { upstream: ['automatic retrieval routing', 'typed memory decisions'], status: 'available', tools: ['vault_go_retrieve', 'vault_go_decision_status'], requires: 'Jev runs only in the central memory engine. Status is sanitized; deployment availability does not prove provider health or decision quality. Explicit retrieval tools remain available.' },
14
15
  { upstream: ['get_tool_uses'], status: 'available', tools: ['vault_go_tool_uses'], requires: 'Verified POST /memory/events/batch contract. Historical output exists only when captured; private fields and secrets are redacted from retrieval.' },
15
16
  { upstream: ['session_start_context', 'multi-project context'], status: 'available', tools: ['vault_go_session_start_context', 'vault_go_context', 'vault_go_file_context', 'vault_go_context_chain', 'vault_go_context_chain_configure'], requires: 'Context chains require explicit local configuration and share one bounded character budget. Native hooks cover Claude, Codex, Grok, Agy and Gemini; OpenCode 1.x remains context-only.' },
16
17
  { upstream: ['smart_search', 'smart_outline', 'smart_unfold'], status: 'available', tools: ['vault_go_smart_search', 'vault_go_smart_outline', 'vault_go_smart_unfold', 'vault_go_smart_languages'], requires: 'Real grammars for all 24 upstream languages plus HTML. Availability is reported per running platform; SCSS has no Linux ARM64 prebuild. Workspace reads and results are bounded.' },
package/dist/cloud.d.ts CHANGED
@@ -24,6 +24,8 @@ export interface VaultMemoryApi {
24
24
  remember(input: Record<string, unknown>): Promise<unknown>;
25
25
  forget(id: string): Promise<unknown>;
26
26
  search(input: Record<string, unknown>): Promise<unknown>;
27
+ retrieve?(input: Record<string, unknown>): Promise<unknown>;
28
+ decisionStatus?(): Promise<unknown>;
27
29
  searchIndex(input: Record<string, unknown>): Promise<unknown>;
28
30
  observations(ids: string[]): Promise<unknown>;
29
31
  timeline(input: Record<string, unknown>): Promise<unknown>;
@@ -69,6 +71,8 @@ export declare class VaultCloudClient implements VaultMemoryApi {
69
71
  remember(input: Record<string, unknown>): Promise<unknown>;
70
72
  forget(id: string): Promise<unknown>;
71
73
  search(input: Record<string, unknown>): Promise<unknown>;
74
+ retrieve(input: Record<string, unknown>): Promise<unknown>;
75
+ decisionStatus(): Promise<unknown>;
72
76
  searchIndex(input: Record<string, unknown>): Promise<unknown>;
73
77
  observations(ids: string[]): Promise<unknown>;
74
78
  timeline(input: Record<string, unknown>): Promise<unknown>;
package/dist/cloud.js CHANGED
@@ -2,6 +2,46 @@ import { recordActivity } from './activity.js';
2
2
  import { loadConfig, loadTokens, saveTokens, validateApiUrl, vaultHome, } from './config.js';
3
3
  const KNOWLEDGE_BASE_RESPONSE_MAX_BYTES = 8 * 1024 * 1024;
4
4
  const KNOWLEDGE_BASE_RESPONSE_LIMIT_ERROR = 'A base de conhecimento excede o limite de resposta de 8 MiB.';
5
+ const observationTypes = new Set(['decision', 'discovery', 'fix', 'feature', 'refactor', 'other']);
6
+ const retentionClasses = new Set(['transient', 'supporting', 'durable', 'critical']);
7
+ const actionableBands = new Set(['low', 'medium', 'high']);
8
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
9
+ const record = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
10
+ const probability = (value) => value === undefined || (typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= 1);
11
+ function validSignals(value) {
12
+ return record(value) && observationTypes.has(String(value.observationType)) && retentionClasses.has(String(value.retentionClass)) && actionableBands.has(String(value.actionableBand)) && typeof value.decisionId === 'string' && uuidPattern.test(value.decisionId);
13
+ }
14
+ function validDecision(value) {
15
+ return record(value) && ['applied', 'fallback'].includes(String(value.status)) && observationTypes.has(String(value.observationType)) && retentionClasses.has(String(value.retention)) && value.persist === true && probability(value.novelInformation) && probability(value.actionable);
16
+ }
17
+ function authoritativeDecisionResponse(value) {
18
+ if (!value || typeof value !== 'object' || Array.isArray(value))
19
+ return value;
20
+ const result = { ...value };
21
+ if ('decision' in result) {
22
+ if (!validDecision(result.decision))
23
+ delete result.decision;
24
+ }
25
+ if ('decisionSignals' in result) {
26
+ if (!validSignals(result.decisionSignals))
27
+ delete result.decisionSignals;
28
+ }
29
+ if (result.decisions && typeof result.decisions === 'object' && !Array.isArray(result.decisions)) {
30
+ result.decisions = Object.fromEntries(Object.entries(result.decisions).filter(([, decision]) => validDecision(decision)));
31
+ }
32
+ return result;
33
+ }
34
+ function withoutClientDecisions(input) {
35
+ const { decision: _decision, decisions: _decisions, decisionSignals: _signals, decision_signals: _snakeSignals, ...safe } = input;
36
+ if (!Array.isArray(safe.records))
37
+ return safe;
38
+ return { ...safe, records: safe.records.map(record => {
39
+ if (!record || typeof record !== 'object' || Array.isArray(record))
40
+ return record;
41
+ const { decision: _recordDecision, decisions: _recordDecisions, decisionSignals: _recordSignals, decision_signals: _recordSnakeSignals, ...safeRecord } = record;
42
+ return safeRecord;
43
+ }) };
44
+ }
5
45
  export class VaultCloudClient {
6
46
  home;
7
47
  cloudFetch;
@@ -53,7 +93,7 @@ export class VaultCloudClient {
53
93
  return this.request('/memory/events', { method: 'POST', body: input });
54
94
  }
55
95
  async remember(input) {
56
- return this.request('/memory/memories', { method: 'POST', body: input });
96
+ return authoritativeDecisionResponse(await this.request('/memory/memories', { method: 'POST', body: withoutClientDecisions(input) }));
57
97
  }
58
98
  async forget(id) {
59
99
  await this.request(`/memory/memories/${encodeURIComponent(id)}`, { method: 'DELETE' });
@@ -62,6 +102,12 @@ export class VaultCloudClient {
62
102
  async search(input) {
63
103
  return this.request('/memory/search', { method: 'POST', body: input });
64
104
  }
105
+ async retrieve(input) {
106
+ return this.request('/memory/retrieve', { method: 'POST', body: input });
107
+ }
108
+ async decisionStatus() {
109
+ return this.request('/memory/decisions/status');
110
+ }
65
111
  async searchIndex(input) {
66
112
  return this.request('/memory/search/index', { method: 'POST', body: input });
67
113
  }
@@ -107,7 +153,7 @@ export class VaultCloudClient {
107
153
  return this.request(`/memory/export?${query.toString()}`);
108
154
  }
109
155
  async importMemories(input) {
110
- return this.request('/memory/import', { method: 'POST', body: input });
156
+ return authoritativeDecisionResponse(await this.request('/memory/import', { method: 'POST', body: withoutClientDecisions(input) }));
111
157
  }
112
158
  async backupStatus() { return this.request('/memory/backup/status'); }
113
159
  async exportBackupPage(input) {
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const DEFAULT_API_URL = "https://vault.resolveup.com.br/api";
1
+ export declare const DEFAULT_API_URL = "https://vaultmemoryai.com/api";
2
2
  export interface VaultConfig {
3
3
  apiUrl: string;
4
4
  email?: string;
package/dist/config.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
2
2
  import { homedir } from 'node:os';
3
3
  import { basename, dirname, join, resolve } from 'node:path';
4
- export const DEFAULT_API_URL = 'https://vault.resolveup.com.br/api';
4
+ import { VAULT_CLOUD_API_URL } from './vault-cloud.js';
5
+ export const DEFAULT_API_URL = VAULT_CLOUD_API_URL;
5
6
  const DEFAULT_CONFIG = {
6
7
  apiUrl: DEFAULT_API_URL,
7
8
  intervalSeconds: 60,
@@ -3,6 +3,7 @@ import { chmodSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, wr
3
3
  import { homedir, tmpdir, userInfo } from "node:os";
4
4
  import { basename, dirname, join } from "node:path";
5
5
  import { customModeGenerationGuidance } from './custom-modes.js';
6
+ import { VAULT_CLOUD_ORIGIN } from './vault-cloud.js';
6
7
  export const CONTEXT_ENGINE_IDS = [
7
8
  "vault-ai-resume",
8
9
  "claude-subscription",
@@ -497,7 +498,7 @@ async function generateApiContext(home, engine, text, options, signal) {
497
498
  ? {
498
499
  authorization: "Bearer " + key,
499
500
  "content-type": "application/json",
500
- "http-referer": "https://vault.resolveup.com.br",
501
+ "http-referer": VAULT_CLOUD_ORIGIN,
501
502
  "x-title": "vault-go",
502
503
  }
503
504
  : { "content-type": "application/json", "x-goog-api-key": key };
@@ -101,6 +101,20 @@ function generationFailureCode(error) {
101
101
  return 'awareness_failed';
102
102
  return 'generation_or_persistence_failed';
103
103
  }
104
+ function appliedObservationType(result, sourceId, fallback) {
105
+ if (!result || typeof result !== 'object' || Array.isArray(result))
106
+ return fallback;
107
+ const decisions = result.decisions;
108
+ if (!decisions || typeof decisions !== 'object' || Array.isArray(decisions))
109
+ return fallback;
110
+ const decision = decisions[sourceId];
111
+ if (!decision || typeof decision !== 'object' || Array.isArray(decision))
112
+ return fallback;
113
+ const observationType = decision.observationType;
114
+ return typeof observationType === 'string' && ['decision', 'discovery', 'fix', 'feature', 'refactor', 'other'].includes(observationType)
115
+ ? observationType
116
+ : fallback;
117
+ }
104
118
  export async function enqueueGeneration(home, job) {
105
119
  if (isUnusableGenerationText(job.text) || job.text.length > 16_000)
106
120
  return;
@@ -147,8 +161,9 @@ export async function processGenerationQueue(home = vaultHome(), cloud = new Vau
147
161
  // Cache successful generation before persistence, so a network retry does not pay for the model twice.
148
162
  await mutate(home, jobs => jobs.map(item => item.id === job.id ? { ...item, result } : item));
149
163
  const memoryType = result.type ?? 'discovery';
150
- await cloud.importMemories({ projectId: job.projectId, records: [{
151
- sourceId: `vault-go:event:${job.id}`,
164
+ const sourceId = `vault-go:event:${job.id}`;
165
+ const importResult = await cloud.importMemories({ projectId: job.projectId, records: [{
166
+ sourceId,
152
167
  ...(job.sessionId ? { sessionId: job.sessionId } : {}),
153
168
  kind: job.kind,
154
169
  memoryType,
@@ -157,9 +172,10 @@ export async function processGenerationQueue(home = vaultHome(), cloud = new Vau
157
172
  facts: result.facts, concepts: result.concepts,
158
173
  filesRead: job.filesRead ?? [], filesModified: job.filesModified ?? [],
159
174
  }] });
175
+ const awarenessType = appliedObservationType(importResult, sourceId, memoryType);
160
176
  if (owner !== ownerKey(home))
161
177
  throw new Error('Account changed.');
162
- const awareness = await pushAwareness(home, { ...(job.agentId ? { agentId: job.agentId } : {}), observations: [{ type: memoryType, title: result.title || job.title || 'Memória', facts: result.facts, concepts: result.concepts }] });
178
+ const awareness = await pushAwareness(home, { ...(job.agentId ? { agentId: job.agentId } : {}), observations: [{ type: awarenessType, title: result.title || job.title || 'Memória', facts: result.facts, concepts: result.concepts }] });
163
179
  if (awareness.error)
164
180
  throw new Error('Awareness delivery failed; retry with cached generation.');
165
181
  await mirrorCrystalMemory({ home, cloud, job, result });
@@ -168,7 +184,7 @@ export async function processGenerationQueue(home = vaultHome(), cloud = new Vau
168
184
  try {
169
185
  await (options.notifyObservation ?? ((observation) => notifyTelegramObservation(home, observation)))({
170
186
  id: job.id,
171
- type: memoryType,
187
+ type: awarenessType,
172
188
  title: result.title,
173
189
  concepts: result.concepts,
174
190
  });
@@ -1,3 +1,4 @@
1
+ import { VAULT_CLOUD_HOSTS, VAULT_WEB_APP_URL, VAULT_WEB_MCP_URL, VAULT_WEB_MEMORY_URL, } from './vault-cloud.js';
1
2
  /** Local monitor: no secrets or cloud content are interpolated into this document. */
2
3
  export function dashboardHtml() {
3
4
  return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="color-scheme" content="dark"><title>AI Vault Memory · Local</title><style>
@@ -5,7 +6,7 @@ export function dashboardHtml() {
5
6
 
6
7
  /* Same identity tokens and glass surfaces as the Vault portal. */
7
8
  :root{--c-canvas:8 11 18;--c-surface:24 29 45;--c-surface-2:32 38 56;--c-line:53 61 81;--c-fg:241 243 252;--c-muted:172 180 203;--c-faint:148 159 187;--c-accent:185 182 255;color:rgb(var(--c-fg));background:rgb(var(--c-canvas))}body{background:radial-gradient(ellipse at 85% 8%,#534ca02e,transparent 45%),linear-gradient(145deg,#080b12,#101321 58%,#080b12)}[hidden]{display:none!important}.shell{grid-template-columns:258px 1fr;max-width:1600px}.rail{background:linear-gradient(160deg,#1c2135f5,#101522f5);border-color:#cdd8ff26}.brand{font-size:15px;letter-spacing:-.3px;gap:10px;white-space:nowrap}.brand img,.onboarding-logo{object-fit:contain;filter:drop-shadow(0 5px 12px #7775c533)}.brand-sub{display:block;font-size:9px;letter-spacing:1.7px;color:#acb4cb;margin-top:7px}.card,.panel,.onboarding,.step,.notice{background:linear-gradient(135deg,#272c3ed1,#131724e0);border-color:#cdd8ff26;box-shadow:0 24px 70px -30px #0009,inset 0 1px 0 #ffffff0c;backdrop-filter:blur(28px) saturate(135%)}.nav a.active,.nav a:hover{background:#b9b6ff20;color:#d3d1ff}.eyebrow,.step-number,.empty-symbol{color:#b9b6ff}p,.card-label{color:#acb4cb}.card-note,.row-meta,.rail-footer,.rail-label,.footer{color:#949fbb}.pulse{color:#b9b6ff;border-color:#b9b6ff30;background:#b9b6ff0d}.button{background:#202638;color:#f1f3fc;border-color:#cdd8ff26;text-decoration:none;justify-content:center}.button:hover{border-color:#b9b6ff88}.primary{background:linear-gradient(135deg,#c8c5ff,#9d9bed);color:#15152f;border-color:transparent;font-weight:650;padding:13px 20px;font-size:14px}.primary:hover{background:#d3d1ff}.onboarding{border:1px solid #cdd8ff26;border-radius:20px;overflow:hidden;margin-top:30px;animation:arrive .6s ease both}.onboarding-hero{position:relative;padding:38px;background:radial-gradient(ellipse at 100% 0%,#7370d02c,transparent 62%)}.onboarding-logo{width:86px;height:86px;margin-bottom:24px}.onboarding h1{font-size:36px;max-width:600px;line-height:1.12;margin:12px 0 18px}.onboarding-hero>p{max-width:570px;font-size:14px;line-height:1.8}.actions{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-top:25px}.link{color:#d3d1ff;text-decoration:none;font-size:12px}.link:hover{text-decoration:underline}.onboarding-hint{font-size:11px!important;color:#949fbb;margin-top:15px!important}.steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border-top:1px solid #cdd8ff26}.step{padding:25px;background:#080b122b;box-shadow:none;border-right:1px solid #cdd8ff16}.step:last-child{border:0}.step-number{font-family:monospace;font-size:11px;margin-bottom:13px}.step h2{margin-bottom:9px}.step p{font-size:12px}.terminal-fallback{padding:22px 30px;border-top:1px solid #cdd8ff26;background:#080b1233}.terminal-fallback p{font-size:12px}.terminal-fallback code{display:block;margin-top:10px;font-size:12px;color:#d3d1ff;overflow-wrap:anywhere}.connection-message{margin-top:18px;font-size:12px;color:#d3d1ff;min-height:18px}.next-step{display:flex;justify-content:space-between;align-items:center;gap:20px;margin-top:22px;padding:23px;border:1px solid #b9b6ff30;border-radius:14px;background:#b9b6ff09}.next-step h2{margin-bottom:8px}.next-step p{font-size:12px}.next-step .actions{margin:0;flex-shrink:0}button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible{outline-color:#b9b6ff}.notice code{color:#d3d1ff}.search{border-color:#cdd8ff26;background:#0307117a}.breadcrumb b{color:#f1f3fc}.rail-footer .dot{background:#b9b6ff}.footer{margin-top:28px}@media(max-width:1100px){.shell{grid-template-columns:225px 1fr}.brand{font-size:13px}.main{padding:25px}.onboarding-hero{padding:30px}.next-step{align-items:flex-start;flex-direction:column}}@media(max-width:680px){.shell{display:block}.brand{font-size:16px}.onboarding{margin-top:22px}.onboarding-hero{padding:26px}.onboarding h1{font-size:30px}.onboarding-logo{width:65px;height:65px;margin-bottom:15px}.steps{grid-template-columns:1fr}.step{padding:20px 26px;border-right:0;border-bottom:1px solid #cdd8ff16}.step-number{margin-bottom:8px}.terminal-fallback{padding:22px 26px}.main{padding:20px}.next-step .actions{flex-shrink:1}.onboarding .actions .button{width:100%}.onboarding .actions .link{padding:8px 0}.card-value{overflow-wrap:anywhere}.nav{padding-bottom:2px}}
8
- .danger{border-color:#ed9a9a66;color:#ffb5b5;background:#53272d55}.danger:hover{border-color:#ffb5b5}.danger-title{color:#ffb5b5}.pagination{display:flex;gap:9px;align-items:center;flex-wrap:wrap;border-top:1px solid #cdd8ff20;margin-top:15px;padding-top:15px;color:#acb4cb;font-size:11px}.pagination label{display:flex;align-items:center;gap:7px}.pagination .page-summary{flex:1;min-width:95px}.pagination select{padding:7px}.pagination .button{padding:7px 10px}.pagination button:disabled{cursor:default}.row-open{background:transparent;border:0;text-align:left;padding:0;color:#d3d1ff;cursor:pointer;font:inherit}.row-open:hover{text-decoration:underline}.row-actions{padding-top:5px}.detail-dialog{color:#f1f3fc;background:linear-gradient(135deg,#272c3e,#131724);border:1px solid #cdd8ff40;border-radius:18px;max-width:800px;width:calc(100% - 32px);max-height:85vh;padding:26px;box-shadow:0 30px 100px #0009}.detail-dialog::backdrop{background:#050710bd;backdrop-filter:blur(5px)}.detail-dialog h2{font-size:20px;overflow-wrap:anywhere}.detail-fields{margin:0}.detail-fields dt{color:#acb4cb;font-size:11px;margin:20px 0 8px}.detail-fields dd{margin:0;font-size:13px;line-height:1.7;white-space:pre-wrap;overflow-wrap:anywhere}.detail-fields pre{font:inherit;white-space:pre-wrap;margin:0}.engine-options{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-top:18px}.engine-keys{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin-top:16px}.engine-keys label{display:block;font-size:12px;margin-bottom:8px}.engine-keys input{width:100%;background:#0307117a;color:#f1f3fc;border:1px solid #cdd8ff26;border-radius:9px;padding:10px 12px;font:inherit;font-size:13px;margin-bottom:8px}.engine-option{display:block;padding:17px;border:1px solid #cdd8ff26;border-radius:10px;background:#080b1233;cursor:pointer}.engine-option:has(input:checked){border-color:#b9b6ff;background:#b9b6ff12}.engine-option:has(input:disabled){opacity:.7;cursor:default}.engine-option input{accent-color:#b9b6ff;margin-right:8px}.engine-option strong{font-size:12px}.engine-option p{font-size:11px;margin-top:9px}.engine-message{margin-top:13px;font-size:12px;color:#d3d1ff}.context-editor{margin-top:20px}.context-editor label{display:block;font-size:12px;margin-bottom:8px}.context-editor textarea{width:100%;min-height:130px;resize:vertical;background:#0307117a;color:#f1f3fc;border:1px solid #cdd8ff26;border-radius:9px;padding:12px;font:inherit;font-size:13px}.context-editor textarea:focus-visible{outline:2px solid #b9b6ff;outline-offset:3px}.mcp-clients{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px;margin-top:14px}.mcp-client{display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid #cdd8ff26;border-radius:10px;padding:10px 12px;background:#080b1233;font-size:13px;flex-wrap:wrap}.mcp-client strong{font-size:13px;font-weight:600}.mcp-state{font-size:11px;color:#8edbc8;white-space:nowrap}.mcp-dim{opacity:.75}.mcp-evidence{font-size:10px;color:#949fbb;width:100%}.mcp-note{color:#949fbb;font-size:12px}.mcp-message{color:#ed9a9a;font-size:12px;margin-top:10px}.mcp-message:empty{display:none}.mcp-fallback{color:#949fbb;font-size:11px;margin-top:12px}.mcp-fallback code{font-size:11px;color:#c7d4df;background:#0307117a;border-radius:6px;padding:2px 6px}@media(max-width:800px){.engine-options{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){.detail-dialog::backdrop{backdrop-filter:none}}</style><script src="/app.js" defer></script></head><body><div class="shell"><aside class="rail"><div class="brand"><img src="/logo.png" alt="" width="46" height="46"><div>AI Vault Memory<span class="brand-sub">LOCAL AGENT</span></div></div><div class="rail-label" data-i18n="workspace">WORKSPACE</div><nav class="nav" aria-label="Navigation"><a class="active" href="#overview"><span class="icon">◈</span><span data-i18n="overview">Overview</span></a><a href="#activity"><span class="icon">⌁</span><span data-i18n="activity">Activity</span></a><a href="#memories"><span class="icon">▤</span><span data-i18n="memories">Memories</span></a><a href="#context"><span class="icon">✧</span><span data-i18n="contextEngine">Context engine</span></a><a href="#projects"><span class="icon">▱</span><span data-i18n="projects">Projects</span></a></nav><div class="rail-footer"><span class="dot"></span><span data-i18n="localWorkspace">Your local workspace</span><br><span data-i18n="privacy">Activity metadata stays local.</span></div></aside><main class="main" id="overview"><header class="top"><div class="breadcrumb">Vault <span aria-hidden="true"> / </span><b data-i18n="localMonitor">Local monitor</b></div><div class="controls"><select id="locale" aria-label="Language"><option value="en">English</option><option value="pt">Português</option><option value="es">Español</option></select><button class="button" id="logout" type="button" hidden data-i18n="logout">Sign out of dashboard</button><button class="button" id="reconnect" type="button" hidden data-i18n="reconnect">Reconnect account</button><button class="button" id="refresh" type="button"><span aria-hidden="true">↻</span><span data-i18n="refresh">Refresh cloud</span></button></div></header><div id="error" class="error" role="status" aria-live="polite"></div><section class="onboarding" id="onboarding"><div class="onboarding-hero"><img class="onboarding-logo" src="/logo.png" alt="" width="86" height="86"><div class="eyebrow" data-i18n="connectEyebrow">AI VAULT MEMORY · LOCAL</div><h1 data-i18n="connectTitle">Your memory. Connected to this machine.</h1><p data-i18n="connectIntro">Connect your Vault account to see your memories, projects and recent activity in one place.</p><div class="actions"><button type="button" class="button primary" id="connect" data-i18n="connect">Connect to Vault</button><a class="link" href="https://vault.resolveup.com.br/app" target="_blank" rel="noopener noreferrer" data-i18n="openPortal">Open Vault portal ↗</a></div><p class="onboarding-hint" data-i18n="connectHint">Sign in securely in a separate window. Your password stays with the Vault portal.</p><div class="connection-message" id="connection-message" role="status" aria-live="polite"></div><a id="auth-fallback" class="button" hidden target="_blank" rel="noopener noreferrer" data-i18n="continueAuth">Continue sign-in ↗</a></div><div class="steps"><article class="step"><div class="step-number">01 / VAULT</div><h2 data-i18n="stepAccount">Connect your account</h2><p data-i18n="stepAccountBody">Sign in to Vault and authorize this local agent.</p></article><article class="step"><div class="step-number">02 / MCP</div><h2 data-i18n="stepClient">Connect your AI clients</h2><p data-i18n="stepClientBody">After signing in, connect Claude, Codex and other clients with one click, right here.</p></article><article class="step"><div class="step-number">03 / MEMORY</div><h2 data-i18n="stepMemory">Build your first memory</h2><p data-i18n="stepMemoryBody">Ask your connected client to save useful context, then follow its activity here.</p></article></div><div class="terminal-fallback"><button class="button" id="verify-connection" type="button" data-i18n="verifyConnection">Already signed in? Check connection</button><p style="margin-top:16px" data-i18n="terminalFallback">Already connected through the CLI? Open a secure local session:</p><code>bunx --bun vault-go@latest local open</code></div></section><div id="dashboard" hidden><div class="welcome"><div><div class="eyebrow" data-i18n="eyebrow">YOUR KNOWLEDGE, CONNECTED</div><h1 data-i18n="title">Your local workspace.</h1><p data-i18n="subtitle">Your Vault account, memories and activity on this machine.</p></div><img src="/logo.png" alt="" width="56" height="56"></div><div id="session-notice" hidden></div><section class="cards" aria-label="Status"><article class="card"><div class="card-label"><span data-i18n="localService">Local service</span><span aria-hidden="true">◈</span></div><div class="card-value" id="local-status">—</div><div class="card-note" id="local-note">localhost:38850</div></article><article class="card"><div class="card-label"><span data-i18n="cloudConnection">Cloud connection</span><span aria-hidden="true">↗</span></div><div class="card-value" id="cloud-status">—</div><div class="card-note" id="cloud-note">—</div></article><article class="card"><div class="card-label"><span data-i18n="recentOperations">Recent operations</span><span aria-hidden="true">⌁</span></div><div class="card-value" id="activity-total">—</div><div class="card-note" data-i18n="operationsNote">Recent MCP request metadata</div></article></section><section class="next-step" id="first-memory"><div><h2 data-i18n="firstTitle">Connect your AI clients</h2><p data-i18n="firstBody">Connect Claude, Codex and other clients here in one click, then ask them to save context. Memories appear after a cloud refresh.</p><div class="mcp-clients" id="mcp-clients" role="group" aria-label="AI clients"></div><p id="mcp-message" role="status" aria-live="polite" class="mcp-message"></p><p data-i18n="rememberPrompt" style="margin-top:10px"></p><p class="mcp-fallback"><span data-i18n="mcpFallback"></span> <code>bunx --bun vault-go@latest install</code></p></div><div class="actions"><a class="link" href="https://vault.resolveup.com.br/mcp" target="_blank" rel="noopener noreferrer" data-i18n="otherClients">Other clients ↗</a><a class="link" href="https://vault.resolveup.com.br/app/memory" target="_blank" rel="noopener noreferrer" data-i18n="openMemories">Open memories ↗</a></div></section><div class="layout"><section class="panel wide" id="security"><div class="panel-head"><h2 data-i18n="securityTitle">Security on this machine</h2></div><div id="security-facts"></div><div class="actions"><button class="button danger" id="disconnect-device" type="button" data-i18n="disconnectDevice">Disconnect device</button></div></section><section class="panel wide" id="context"><div class="panel-head"><h2 data-i18n="contextEngine">Context engine</h2></div><p data-i18n="engineIntro">Choose how Vault prepares your context.</p><div class="engine-options" id="engine-options" role="radiogroup" aria-label="Context engine"></div><div class="engine-options" id="model-options" role="radiogroup" aria-label="Context model"></div><div class="engine-keys" id="engine-keys"></div><div class="engine-message" id="engine-message" role="status" aria-live="polite"></div><div class="context-editor"><label for="context-text" data-i18n="contextText">Text to prepare</label><textarea id="context-text" maxlength="16000" aria-describedby="context-note"></textarea><p id="context-note" data-i18n="contextNote"></p><div class="actions"><button class="button primary" id="context-preview" type="button" data-i18n="contextPreview"></button><button class="button" id="context-stop" type="button" data-i18n="cancel" hidden></button></div><p id="context-progress" role="status" aria-live="polite"></p></div></section><section class="panel" id="activity"><div class="panel-head"><h2 data-i18n="activity">Activity</h2><span class="count" id="activity-count">0</span></div><input class="search" id="activity-search" type="search" data-placeholder="searchActivity" aria-label="Search activity"><div id="activity-list"></div><div class="pagination" id="activity-pagination"></div></section><section class="panel" id="memories"><div class="panel-head"><h2 data-i18n="memories">Memories</h2><span class="count" id="memory-count">0</span></div><input class="search" id="memory-search" type="search" data-placeholder="searchMemories" aria-label="Search memories"><div id="memory-list"></div><div class="pagination" id="memory-pagination"></div></section><section class="panel wide" id="projects"><div class="panel-head"><h2 data-i18n="projects">Projects</h2><span class="count" id="project-count">0</span></div><input class="search" id="project-search" type="search" data-placeholder="searchProjects" aria-label="Search projects"><div id="project-list"></div><div class="pagination" id="project-pagination"></div></section></div></div><footer class="footer"><span data-i18n="footer">Vault Local · Context with a place to call home.</span><span id="updated" aria-live="off">—</span></footer></main></div><dialog class="detail-dialog" id="detail-dialog" aria-labelledby="detail-title"><div class="panel-head"><h2 id="detail-title"></h2><button class="button" type="button" id="detail-copy" hidden data-i18n="copyResult">Copy result</button><button class="button" type="button" id="detail-close" data-i18n="close">Close</button></div><dl class="detail-fields" id="detail-fields"></dl></dialog><dialog class="detail-dialog" id="logout-dialog" aria-labelledby="logout-title" aria-describedby="logout-description"><h2 id="logout-title" data-i18n="logout"></h2><p id="logout-description" data-i18n="logoutDescription" style="margin-top:16px"></p><div class="actions"><button class="button" type="button" id="logout-cancel" data-i18n="cancel"></button><button class="button primary" type="button" id="logout-confirm" data-i18n="logoutConfirm"></button></div></dialog><dialog class="detail-dialog" id="context-confirm-dialog" aria-labelledby="context-confirm-title" aria-describedby="context-confirm-note"><h2 id="context-confirm-title" data-i18n="contextPreview"></h2><p id="context-confirm-engine" style="margin-top:16px"></p><p id="context-confirm-billing"></p><p id="context-confirm-note" data-i18n="contextConsentNote" style="margin-top:16px"></p><pre id="context-confirm-text" style="white-space:pre-wrap;overflow-wrap:anywhere;max-height:32vh;overflow:auto;font-size:12px;line-height:1.7"></pre><label style="display:flex;gap:10px;align-items:flex-start;font-size:12px"><input id="context-consent" type="checkbox"><span data-i18n="contextConsent"></span></label><div class="actions"><button class="button" id="context-cancel" type="button" data-i18n="cancel"></button><button class="button primary" id="context-generate" type="button" disabled data-i18n="contextGenerate"></button></div></dialog><dialog class="detail-dialog" id="disconnect-dialog" aria-labelledby="disconnect-title" aria-describedby="disconnect-description"><h2 class="danger-title" id="disconnect-title" data-i18n="disconnectDevice"></h2><p id="disconnect-description" data-i18n="disconnectDescription" style="margin-top:16px"></p><p id="disconnect-error" class="error" role="alert"></p><div class="actions"><button class="button" type="button" id="disconnect-cancel" data-i18n="cancel"></button><button class="button danger" type="button" id="disconnect-confirm" data-i18n="disconnectConfirm"></button></div></dialog></body></html>`;
9
+ .danger{border-color:#ed9a9a66;color:#ffb5b5;background:#53272d55}.danger:hover{border-color:#ffb5b5}.danger-title{color:#ffb5b5}.pagination{display:flex;gap:9px;align-items:center;flex-wrap:wrap;border-top:1px solid #cdd8ff20;margin-top:15px;padding-top:15px;color:#acb4cb;font-size:11px}.pagination label{display:flex;align-items:center;gap:7px}.pagination .page-summary{flex:1;min-width:95px}.pagination select{padding:7px}.pagination .button{padding:7px 10px}.pagination button:disabled{cursor:default}.row-open{background:transparent;border:0;text-align:left;padding:0;color:#d3d1ff;cursor:pointer;font:inherit}.row-open:hover{text-decoration:underline}.row-actions{padding-top:5px}.detail-dialog{color:#f1f3fc;background:linear-gradient(135deg,#272c3e,#131724);border:1px solid #cdd8ff40;border-radius:18px;max-width:800px;width:calc(100% - 32px);max-height:85vh;padding:26px;box-shadow:0 30px 100px #0009}.detail-dialog::backdrop{background:#050710bd;backdrop-filter:blur(5px)}.detail-dialog h2{font-size:20px;overflow-wrap:anywhere}.detail-fields{margin:0}.detail-fields dt{color:#acb4cb;font-size:11px;margin:20px 0 8px}.detail-fields dd{margin:0;font-size:13px;line-height:1.7;white-space:pre-wrap;overflow-wrap:anywhere}.detail-fields pre{font:inherit;white-space:pre-wrap;margin:0}.engine-options{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-top:18px}.engine-keys{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin-top:16px}.engine-keys label{display:block;font-size:12px;margin-bottom:8px}.engine-keys input{width:100%;background:#0307117a;color:#f1f3fc;border:1px solid #cdd8ff26;border-radius:9px;padding:10px 12px;font:inherit;font-size:13px;margin-bottom:8px}.engine-option{display:block;padding:17px;border:1px solid #cdd8ff26;border-radius:10px;background:#080b1233;cursor:pointer}.engine-option:has(input:checked){border-color:#b9b6ff;background:#b9b6ff12}.engine-option:has(input:disabled){opacity:.7;cursor:default}.engine-option input{accent-color:#b9b6ff;margin-right:8px}.engine-option strong{font-size:12px}.engine-option p{font-size:11px;margin-top:9px}.engine-message{margin-top:13px;font-size:12px;color:#d3d1ff}.context-editor{margin-top:20px}.context-editor label{display:block;font-size:12px;margin-bottom:8px}.context-editor textarea{width:100%;min-height:130px;resize:vertical;background:#0307117a;color:#f1f3fc;border:1px solid #cdd8ff26;border-radius:9px;padding:12px;font:inherit;font-size:13px}.context-editor textarea:focus-visible{outline:2px solid #b9b6ff;outline-offset:3px}.mcp-clients{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px;margin-top:14px}.mcp-client{display:flex;align-items:center;justify-content:space-between;gap:10px;border:1px solid #cdd8ff26;border-radius:10px;padding:10px 12px;background:#080b1233;font-size:13px;flex-wrap:wrap}.mcp-client strong{font-size:13px;font-weight:600}.mcp-state{font-size:11px;color:#8edbc8;white-space:nowrap}.mcp-dim{opacity:.75}.mcp-evidence{font-size:10px;color:#949fbb;width:100%}.mcp-note{color:#949fbb;font-size:12px}.mcp-message{color:#ed9a9a;font-size:12px;margin-top:10px}.mcp-message:empty{display:none}.mcp-fallback{color:#949fbb;font-size:11px;margin-top:12px}.mcp-fallback code{font-size:11px;color:#c7d4df;background:#0307117a;border-radius:6px;padding:2px 6px}@media(max-width:800px){.engine-options{grid-template-columns:1fr}}@media(prefers-reduced-motion:reduce){.detail-dialog::backdrop{backdrop-filter:none}}</style><script src="/app.js" defer></script></head><body><div class="shell"><aside class="rail"><div class="brand"><img src="/logo.png" alt="" width="46" height="46"><div>AI Vault Memory<span class="brand-sub">LOCAL AGENT</span></div></div><div class="rail-label" data-i18n="workspace">WORKSPACE</div><nav class="nav" aria-label="Navigation"><a class="active" href="#overview"><span class="icon">◈</span><span data-i18n="overview">Overview</span></a><a href="#activity"><span class="icon">⌁</span><span data-i18n="activity">Activity</span></a><a href="#memories"><span class="icon">▤</span><span data-i18n="memories">Memories</span></a><a href="#context"><span class="icon">✧</span><span data-i18n="contextEngine">Context engine</span></a><a href="#projects"><span class="icon">▱</span><span data-i18n="projects">Projects</span></a></nav><div class="rail-footer"><span class="dot"></span><span data-i18n="localWorkspace">Your local workspace</span><br><span data-i18n="privacy">Activity metadata stays local.</span></div></aside><main class="main" id="overview"><header class="top"><div class="breadcrumb">Vault <span aria-hidden="true"> / </span><b data-i18n="localMonitor">Local monitor</b></div><div class="controls"><select id="locale" aria-label="Language"><option value="en">English</option><option value="pt">Português</option><option value="es">Español</option></select><button class="button" id="logout" type="button" hidden data-i18n="logout">Sign out of dashboard</button><button class="button" id="reconnect" type="button" hidden data-i18n="reconnect">Reconnect account</button><button class="button" id="refresh" type="button"><span aria-hidden="true">↻</span><span data-i18n="refresh">Refresh cloud</span></button></div></header><div id="error" class="error" role="status" aria-live="polite"></div><section class="onboarding" id="onboarding"><div class="onboarding-hero"><img class="onboarding-logo" src="/logo.png" alt="" width="86" height="86"><div class="eyebrow" data-i18n="connectEyebrow">AI VAULT MEMORY · LOCAL</div><h1 data-i18n="connectTitle">Your memory. Connected to this machine.</h1><p data-i18n="connectIntro">Connect your Vault account to see your memories, projects and recent activity in one place.</p><div class="actions"><button type="button" class="button primary" id="connect" data-i18n="connect">Connect to Vault</button><a class="link" href="${VAULT_WEB_APP_URL}" target="_blank" rel="noopener noreferrer" data-i18n="openPortal">Open Vault portal ↗</a></div><p class="onboarding-hint" data-i18n="connectHint">Sign in securely in a separate window. Your password stays with the Vault portal.</p><div class="connection-message" id="connection-message" role="status" aria-live="polite"></div><a id="auth-fallback" class="button" hidden target="_blank" rel="noopener noreferrer" data-i18n="continueAuth">Continue sign-in ↗</a></div><div class="steps"><article class="step"><div class="step-number">01 / VAULT</div><h2 data-i18n="stepAccount">Connect your account</h2><p data-i18n="stepAccountBody">Sign in to Vault and authorize this local agent.</p></article><article class="step"><div class="step-number">02 / MCP</div><h2 data-i18n="stepClient">Connect your AI clients</h2><p data-i18n="stepClientBody">After signing in, connect Claude, Codex and other clients with one click, right here.</p></article><article class="step"><div class="step-number">03 / MEMORY</div><h2 data-i18n="stepMemory">Build your first memory</h2><p data-i18n="stepMemoryBody">Ask your connected client to save useful context, then follow its activity here.</p></article></div><div class="terminal-fallback"><button class="button" id="verify-connection" type="button" data-i18n="verifyConnection">Already signed in? Check connection</button><p style="margin-top:16px" data-i18n="terminalFallback">Already connected through the CLI? Open a secure local session:</p><code>bunx --bun vault-go@latest local open</code></div></section><div id="dashboard" hidden><div class="welcome"><div><div class="eyebrow" data-i18n="eyebrow">YOUR KNOWLEDGE, CONNECTED</div><h1 data-i18n="title">Your local workspace.</h1><p data-i18n="subtitle">Your Vault account, memories and activity on this machine.</p></div><img src="/logo.png" alt="" width="56" height="56"></div><div id="session-notice" hidden></div><section class="cards" aria-label="Status"><article class="card"><div class="card-label"><span data-i18n="localService">Local service</span><span aria-hidden="true">◈</span></div><div class="card-value" id="local-status">—</div><div class="card-note" id="local-note">localhost:38850</div></article><article class="card"><div class="card-label"><span data-i18n="cloudConnection">Cloud connection</span><span aria-hidden="true">↗</span></div><div class="card-value" id="cloud-status">—</div><div class="card-note" id="cloud-note">—</div></article><article class="card"><div class="card-label"><span data-i18n="recentOperations">Recent operations</span><span aria-hidden="true">⌁</span></div><div class="card-value" id="activity-total">—</div><div class="card-note" data-i18n="operationsNote">Recent MCP request metadata</div></article></section><section class="next-step" id="first-memory"><div><h2 data-i18n="firstTitle">Connect your AI clients</h2><p data-i18n="firstBody">Connect Claude, Codex and other clients here in one click, then ask them to save context. Memories appear after a cloud refresh.</p><div class="mcp-clients" id="mcp-clients" role="group" aria-label="AI clients"></div><p id="mcp-message" role="status" aria-live="polite" class="mcp-message"></p><p data-i18n="rememberPrompt" style="margin-top:10px"></p><p class="mcp-fallback"><span data-i18n="mcpFallback"></span> <code>bunx --bun vault-go@latest install</code></p></div><div class="actions"><a class="link" href="${VAULT_WEB_MCP_URL}" target="_blank" rel="noopener noreferrer" data-i18n="otherClients">Other clients ↗</a><a class="link" href="${VAULT_WEB_MEMORY_URL}" target="_blank" rel="noopener noreferrer" data-i18n="openMemories">Open memories ↗</a></div></section><div class="layout"><section class="panel wide" id="security"><div class="panel-head"><h2 data-i18n="securityTitle">Security on this machine</h2></div><div id="security-facts"></div><div class="actions"><button class="button danger" id="disconnect-device" type="button" data-i18n="disconnectDevice">Disconnect device</button></div></section><section class="panel wide" id="context"><div class="panel-head"><h2 data-i18n="contextEngine">Context engine</h2></div><p data-i18n="engineIntro">Choose how Vault prepares your context.</p><div class="engine-options" id="engine-options" role="radiogroup" aria-label="Context engine"></div><div class="engine-options" id="model-options" role="radiogroup" aria-label="Context model"></div><div class="engine-keys" id="engine-keys"></div><div class="engine-message" id="engine-message" role="status" aria-live="polite"></div><div class="context-editor"><label for="context-text" data-i18n="contextText">Text to prepare</label><textarea id="context-text" maxlength="16000" aria-describedby="context-note"></textarea><p id="context-note" data-i18n="contextNote"></p><div class="actions"><button class="button primary" id="context-preview" type="button" data-i18n="contextPreview"></button><button class="button" id="context-stop" type="button" data-i18n="cancel" hidden></button></div><p id="context-progress" role="status" aria-live="polite"></p></div></section><section class="panel" id="activity"><div class="panel-head"><h2 data-i18n="activity">Activity</h2><span class="count" id="activity-count">0</span></div><input class="search" id="activity-search" type="search" data-placeholder="searchActivity" aria-label="Search activity"><div id="activity-list"></div><div class="pagination" id="activity-pagination"></div></section><section class="panel" id="memories"><div class="panel-head"><h2 data-i18n="memories">Memories</h2><span class="count" id="memory-count">0</span></div><input class="search" id="memory-search" type="search" data-placeholder="searchMemories" aria-label="Search memories"><div id="memory-list"></div><div class="pagination" id="memory-pagination"></div></section><section class="panel wide" id="projects"><div class="panel-head"><h2 data-i18n="projects">Projects</h2><span class="count" id="project-count">0</span></div><input class="search" id="project-search" type="search" data-placeholder="searchProjects" aria-label="Search projects"><div id="project-list"></div><div class="pagination" id="project-pagination"></div></section></div></div><footer class="footer"><span data-i18n="footer">Vault Local · Context with a place to call home.</span><span id="updated" aria-live="off">—</span></footer></main></div><dialog class="detail-dialog" id="detail-dialog" aria-labelledby="detail-title"><div class="panel-head"><h2 id="detail-title"></h2><button class="button" type="button" id="detail-copy" hidden data-i18n="copyResult">Copy result</button><button class="button" type="button" id="detail-close" data-i18n="close">Close</button></div><dl class="detail-fields" id="detail-fields"></dl></dialog><dialog class="detail-dialog" id="logout-dialog" aria-labelledby="logout-title" aria-describedby="logout-description"><h2 id="logout-title" data-i18n="logout"></h2><p id="logout-description" data-i18n="logoutDescription" style="margin-top:16px"></p><div class="actions"><button class="button" type="button" id="logout-cancel" data-i18n="cancel"></button><button class="button primary" type="button" id="logout-confirm" data-i18n="logoutConfirm"></button></div></dialog><dialog class="detail-dialog" id="context-confirm-dialog" aria-labelledby="context-confirm-title" aria-describedby="context-confirm-note"><h2 id="context-confirm-title" data-i18n="contextPreview"></h2><p id="context-confirm-engine" style="margin-top:16px"></p><p id="context-confirm-billing"></p><p id="context-confirm-note" data-i18n="contextConsentNote" style="margin-top:16px"></p><pre id="context-confirm-text" style="white-space:pre-wrap;overflow-wrap:anywhere;max-height:32vh;overflow:auto;font-size:12px;line-height:1.7"></pre><label style="display:flex;gap:10px;align-items:flex-start;font-size:12px"><input id="context-consent" type="checkbox"><span data-i18n="contextConsent"></span></label><div class="actions"><button class="button" id="context-cancel" type="button" data-i18n="cancel"></button><button class="button primary" id="context-generate" type="button" disabled data-i18n="contextGenerate"></button></div></dialog><dialog class="detail-dialog" id="disconnect-dialog" aria-labelledby="disconnect-title" aria-describedby="disconnect-description"><h2 class="danger-title" id="disconnect-title" data-i18n="disconnectDevice"></h2><p id="disconnect-description" data-i18n="disconnectDescription" style="margin-top:16px"></p><p id="disconnect-error" class="error" role="alert"></p><div class="actions"><button class="button" type="button" id="disconnect-cancel" data-i18n="cancel"></button><button class="button danger" type="button" id="disconnect-confirm" data-i18n="disconnectConfirm"></button></div></dialog></body></html>`;
9
10
  }
10
11
  export function dashboardScript() {
11
12
  return `"use strict";
@@ -313,7 +314,7 @@ export function dashboardScript() {
313
314
  if(!response.ok) throw new Error('connection failed');
314
315
  const result=await response.json();
315
316
  const url=new URL(result.url);
316
- if(url.protocol !== 'https:' || url.hostname !== 'vault.resolveup.com.br' || url.username || url.password || (url.port && url.port !== '443')) throw new Error('invalid authentication URL');
317
+ if(url.protocol !== 'https:' || !${JSON.stringify([...VAULT_CLOUD_HOSTS])}.includes(url.hostname) || url.username || url.password || (url.port && url.port !== '443')) throw new Error('invalid authentication URL');
317
318
  el('auth-fallback').href=url.href; el('auth-fallback').hidden=false;
318
319
  if(popup && !popup.closed) { popup.location.replace(url.href); connectionMessage='awaitingAuth'; }
319
320
  else connectionMessage='popupBlocked';
package/dist/server.js CHANGED
@@ -191,6 +191,33 @@ export function createVaultGoServer(home = vaultHome(), cloud = new VaultCloudCl
191
191
  },
192
192
  annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
193
193
  }, async (input) => run(() => cloud.search(input)));
194
+ server.registerTool('vault_go_retrieve', {
195
+ title: 'Recuperação automática do Vault',
196
+ description: 'Delega ao motor central a escolha tipada entre busca, contexto de arquivo, linha do tempo, base de conhecimento, grafo ou nenhum resultado. Falhas usam busca determinística.',
197
+ inputSchema: {
198
+ query: z.string().trim().min(1).max(1_000),
199
+ projectId: uuid.optional(),
200
+ files: z.array(z.string().trim().min(1).max(2_000)).max(50).default([]),
201
+ knowledgeBaseId: uuid.optional(),
202
+ limit: z.number().int().min(1).max(200).default(20),
203
+ maxChars: z.number().int().min(1_000).max(100_000).optional(),
204
+ },
205
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
206
+ }, async (input) => run(() => {
207
+ if (!cloud.retrieve)
208
+ throw new Error('Native retrieval is unavailable on this deployment.');
209
+ return cloud.retrieve(input);
210
+ }));
211
+ server.registerTool('vault_go_decision_status', {
212
+ title: 'Status da camada de decisão',
213
+ description: 'Retorna somente o status operacional sanitizado do Jev central. Configuração não comprova saúde do provedor nem qualidade das decisões.',
214
+ inputSchema: {},
215
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
216
+ }, async () => run(() => {
217
+ if (!cloud.decisionStatus)
218
+ throw new Error('Decision status is unavailable on this deployment.');
219
+ return cloud.decisionStatus();
220
+ }));
194
221
  server.registerTool('vault_go_search_index', {
195
222
  title: 'Pesquisar índice compacto',
196
223
  description: 'Primeira camada de recuperação: retorna metadados, trechos e custo estimado sem carregar o conteúdo completo.',
@@ -0,0 +1,19 @@
1
+ export declare const VAULT_CLOUD_HOST = "vaultmemoryai.com";
2
+ /** Host anterior; registros e links antigos ainda apontam para ele (o servidor redireciona). */
3
+ export declare const VAULT_LEGACY_CLOUD_HOST = "vault.resolveup.com.br";
4
+ /** Hosts aceitos pelos resolvedores, em ordem de preferência. */
5
+ export declare const VAULT_CLOUD_HOSTS: readonly ["vaultmemoryai.com", "vault.resolveup.com.br"];
6
+ export declare const VAULT_CLOUD_ORIGIN = "https://vaultmemoryai.com";
7
+ /** Base da API pública (o proxy remove `/api` antes do gateway). */
8
+ export declare const VAULT_CLOUD_API_URL = "https://vaultmemoryai.com/api";
9
+ export declare const VAULT_WEB_APP_URL = "https://vaultmemoryai.com/app";
10
+ export declare const VAULT_WEB_MEMORY_URL = "https://vaultmemoryai.com/app/memory";
11
+ export declare const VAULT_WEB_MCP_URL = "https://vaultmemoryai.com/mcp";
12
+ /** Comparação exata: sufixo parecido (`vaultmemoryai.com.evil.com`) não passa. */
13
+ export declare function isVaultCloudHost(hostname: string): boolean;
14
+ /**
15
+ * Trava da URL de autenticação devolvida por `/api/connect`.
16
+ * Mantém as garantias do check original — https, sem credenciais embutidas,
17
+ * porta 443 — e passa a aceitar os dois hosts oficiais em vez de um só.
18
+ */
19
+ export declare function isValidAuthUrl(raw: string): boolean;
@@ -0,0 +1,41 @@
1
+ // Origem única da plataforma Vault usada pelo vault-go. Espelha
2
+ // `vault-desktop/src/shared/vault-cloud.ts`: nenhum outro módulo deste pacote
3
+ // deve escrever o host da nuvem literalmente.
4
+ export const VAULT_CLOUD_HOST = 'vaultmemoryai.com';
5
+ /** Host anterior; registros e links antigos ainda apontam para ele (o servidor redireciona). */
6
+ export const VAULT_LEGACY_CLOUD_HOST = 'vault.resolveup.com.br';
7
+ /** Hosts aceitos pelos resolvedores, em ordem de preferência. */
8
+ export const VAULT_CLOUD_HOSTS = [VAULT_CLOUD_HOST, VAULT_LEGACY_CLOUD_HOST];
9
+ export const VAULT_CLOUD_ORIGIN = `https://${VAULT_CLOUD_HOST}`;
10
+ /** Base da API pública (o proxy remove `/api` antes do gateway). */
11
+ export const VAULT_CLOUD_API_URL = `${VAULT_CLOUD_ORIGIN}/api`;
12
+ export const VAULT_WEB_APP_URL = `${VAULT_CLOUD_ORIGIN}/app`;
13
+ export const VAULT_WEB_MEMORY_URL = `${VAULT_CLOUD_ORIGIN}/app/memory`;
14
+ export const VAULT_WEB_MCP_URL = `${VAULT_CLOUD_ORIGIN}/mcp`;
15
+ /** Comparação exata: sufixo parecido (`vaultmemoryai.com.evil.com`) não passa. */
16
+ export function isVaultCloudHost(hostname) {
17
+ return VAULT_CLOUD_HOSTS.includes(hostname);
18
+ }
19
+ /**
20
+ * Trava da URL de autenticação devolvida por `/api/connect`.
21
+ * Mantém as garantias do check original — https, sem credenciais embutidas,
22
+ * porta 443 — e passa a aceitar os dois hosts oficiais em vez de um só.
23
+ */
24
+ export function isValidAuthUrl(raw) {
25
+ let url;
26
+ try {
27
+ url = new URL(raw);
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ if (url.protocol !== 'https:')
33
+ return false;
34
+ if (!isVaultCloudHost(url.hostname))
35
+ return false;
36
+ if (url.username || url.password)
37
+ return false;
38
+ if (url.port && url.port !== '443')
39
+ return false;
40
+ return true;
41
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vault-go",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "MCP server and installer for Vault Memory: search, capture, and use account memory across AI clients.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -91,6 +91,8 @@
91
91
  "dist/capabilities.d.ts",
92
92
  "dist/smart-code.js",
93
93
  "dist/smart-code.d.ts",
94
+ "dist/vault-cloud.js",
95
+ "dist/vault-cloud.d.ts",
94
96
  "dist/updater.js",
95
97
  "dist/updater.d.ts",
96
98
  "dist/update-control.js",