vault-go 0.16.1 → 0.18.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
@@ -76,6 +76,9 @@ Clientes suportados:
76
76
 
77
77
  - Codex e ChatGPT Desktop local;
78
78
  - Claude Code e Claude Desktop;
79
+ - Grok (config.toml nativo e hooks em `~/.grok/hooks`);
80
+ - Agy / Antigravity CLI e IDE;
81
+ - Gemini CLI;
79
82
  - Cursor e Windsurf;
80
83
  - VS Code com GitHub Copilot;
81
84
  - GitHub Copilot CLI;
@@ -170,7 +173,7 @@ limitados.
170
173
 
171
174
  O seletor de motor segue o mesmo modelo do claude-mem: Claude (CLI da assinatura), OpenRouter (chave), Gemini (chave) ou o Vault AI Resume da conta. Grave chaves com `vault-go engine key openrouter|gemini` ou no painel local; as ferramentas MCP não aceitam segredos.
172
175
 
173
- Na instalação, o Vault Go registra hooks no Claude Code e no Codex. Eles injetam contexto no início da sessão, capturam prompts e ferramentas, e o serviço local (`http://localhost:38850`) gera memórias com o motor escolhido — o mesmo ciclo do claude-mem, persistindo no Vault.
176
+ Na instalação, o Vault Go registra hooks no Claude Code, no Codex, no Grok e no Agy. Eles injetam contexto no início da sessão, capturam prompts e ferramentas, e o serviço local (`http://localhost:38850`) gera memórias com o motor escolhido — o mesmo ciclo do claude-mem, persistindo no Vault.
174
177
 
175
178
  O recurso `vault-go://status` fornece o resumo sanitizado em JSON.
176
179
 
package/dist/cli.js CHANGED
@@ -100,7 +100,7 @@ async function chooseClients(args, locale) {
100
100
  return parseNumberedClients(configured);
101
101
  const detected = detectMcpClients();
102
102
  for (const item of detected) {
103
- process.stderr.write(` ${MCP_CLIENTS.indexOf(item.client) + 1}. ${item.client.padEnd(12)} ${item.detected ? `● ${t.detected}` : `○ ${t.available}`}\n`);
103
+ process.stderr.write(` ${MCP_CLIENTS.indexOf(item.client) + 1}. ${item.client.padEnd(14)} ${item.detected ? `● ${t.detected}` : `○ ${t.available}`}\n`);
104
104
  }
105
105
  const defaults = defaultClients();
106
106
  const answer = await promptText(`${t.choose} [${defaults.join(',')}]: `);
@@ -324,8 +324,8 @@ Uso:
324
324
  Escolhe o motor e o modelo de contexto. No Claude: haiku, sonnet ou opus.
325
325
 
326
326
  vault-go hook <adaptador> <evento>
327
- Usado pelos hooks do Claude/Codex: injeta contexto, captura atividade
328
- e enfileira geração com o motor escolhido.
327
+ Usado pelos hooks do Claude, Codex, Grok e Agy: injeta contexto,
328
+ captura atividade e enfileira geração com o motor escolhido.
329
329
 
330
330
  --lang pt|en|es
331
331
  Idioma do assistente (padrão: idioma do sistema).
@@ -9,5 +9,6 @@ export declare const HOOK_EVENTS: {
9
9
  export declare function quoteShell(value: string): string;
10
10
  export declare function hookEntryPath(configHome?: string): string;
11
11
  export declare function hookCommand(adapter: string, event: string, configHome?: string): string;
12
- export declare function installClientHooks(client: "claude" | "codex", userHome?: string, configHome?: string): void;
12
+ export type HookClient = "claude" | "codex" | "grok" | "agy";
13
+ export declare function installClientHooks(client: HookClient, userHome?: string, configHome?: string): void;
13
14
  export declare function repairClientHooks(userHome?: string, configHome?: string): void;
@@ -73,7 +73,34 @@ function hookManifest(adapter, configHome = vaultHome()) {
73
73
  ])),
74
74
  };
75
75
  }
76
+ function agyHandler(event, configHome = vaultHome()) {
77
+ return {
78
+ type: "command",
79
+ command: hookCommand("agy", event, configHome),
80
+ timeout: event === "context" ? 60 : 20,
81
+ };
82
+ }
83
+ function agyHookManifest(configHome = vaultHome()) {
84
+ return {
85
+ PreInvocation: [agyHandler("context", configHome)],
86
+ PreToolUse: [{ matcher: "*", hooks: [agyHandler("file-context", configHome)] }],
87
+ PostToolUse: [
88
+ { matcher: "*", hooks: [agyHandler("observation", configHome)] },
89
+ ],
90
+ Stop: [agyHandler("summarize", configHome)],
91
+ };
92
+ }
76
93
  export function installClientHooks(client, userHome = homedir(), configHome = vaultHome()) {
94
+ if (client === "grok") {
95
+ atomicWriteJson(join(userHome, ".grok", "hooks", "vault-go.json"), hookManifest("grok", configHome));
96
+ return;
97
+ }
98
+ if (client === "agy") {
99
+ const path = join(userHome, ".gemini", "config", "hooks.json");
100
+ const config = readJsonObject(path);
101
+ atomicWriteJson(path, { ...config, "vault-go": agyHookManifest(configHome) });
102
+ return;
103
+ }
77
104
  const path = join(userHome, client === "claude" ? ".claude/settings.json" : ".codex/hooks.json");
78
105
  const config = readJsonObject(path);
79
106
  const hooks = {
@@ -110,4 +137,12 @@ export function installClientHooks(client, userHome = homedir(), configHome = va
110
137
  export function repairClientHooks(userHome = homedir(), configHome = vaultHome()) {
111
138
  installClientHooks("claude", userHome, configHome);
112
139
  installClientHooks("codex", userHome, configHome);
140
+ if (existsSync(join(userHome, ".grok"))) {
141
+ installClientHooks("grok", userHome, configHome);
142
+ }
143
+ if (existsSync(join(userHome, ".gemini", "config")) ||
144
+ existsSync(join(userHome, ".gemini", "antigravity")) ||
145
+ existsSync(join(userHome, ".gemini", "antigravity-cli"))) {
146
+ installClientHooks("agy", userHome, configHome);
147
+ }
113
148
  }
package/dist/hooks.d.ts CHANGED
@@ -2,7 +2,8 @@ import { type VaultMemoryApi } from "./cloud.js";
2
2
  export declare const HOOK_EVENTS: readonly ["context", "session-init", "observation", "file-context", "summarize"];
3
3
  export type HookEvent = (typeof HOOK_EVENTS)[number];
4
4
  type RecordValue = Record<string, unknown>;
5
- export declare function hookOutput(event: HookEvent, context?: string): RecordValue;
5
+ export declare function normalizeHookInput(adapter: string, value: unknown): RecordValue;
6
+ export declare function hookOutput(event: HookEvent, context?: string, adapter?: string): RecordValue;
6
7
  export declare function executeHook(adapter: string, event: HookEvent, value: unknown, cloud?: VaultMemoryApi, home?: string): Promise<RecordValue>;
7
8
  export declare function readHookInput(stream?: NodeJS.ReadableStream): Promise<unknown>;
8
9
  export declare function runHook(adapter: string, event: string): Promise<void>;
package/dist/hooks.js CHANGED
@@ -45,7 +45,34 @@ function redact(value) {
45
45
  }
46
46
  return value;
47
47
  }
48
- export function hookOutput(event, context = "") {
48
+ export function normalizeHookInput(adapter, value) {
49
+ const input = record(value);
50
+ const toolCall = record(input.toolCall);
51
+ const workspaces = Array.isArray(input.workspacePaths)
52
+ ? input.workspacePaths
53
+ : [];
54
+ const workspace = workspaces.find((item) => typeof item === "string" && Boolean(item.trim()));
55
+ return {
56
+ ...input,
57
+ session_id: string(input.session_id, input.sessionId, input.conversation_id, input.conversationId, input.thread_id),
58
+ cwd: string(input.cwd, input.workspace, input.workspaceRoot, workspace),
59
+ tool_name: string(input.tool_name, input.toolName, toolCall.name),
60
+ tool_input: record(input.tool_input ?? input.toolInput ?? toolCall.args),
61
+ last_assistant_message: string(input.last_assistant_message, input.lastAssistantMessage, input.response, input.summary),
62
+ prompt: string(input.prompt, input.user_prompt, input.userPrompt),
63
+ };
64
+ }
65
+ export function hookOutput(event, context = "", adapter = "claude") {
66
+ if (adapter === "agy") {
67
+ if (event === "context" || event === "session-init") {
68
+ return context
69
+ ? { injectSteps: [{ ephemeralMessage: context }] }
70
+ : {};
71
+ }
72
+ if (event === "file-context")
73
+ return { decision: "allow" };
74
+ return {};
75
+ }
49
76
  const result = { continue: true, suppressOutput: true };
50
77
  const name = event === "context"
51
78
  ? "SessionStart"
@@ -79,29 +106,29 @@ async function preferences(cloud) {
79
106
  };
80
107
  }
81
108
  export async function executeHook(adapter, event, value, cloud = new VaultCloudClient(), home = vaultHome()) {
82
- const input = record(value);
83
- const toolName = string(input.tool_name, input.toolName);
109
+ const input = normalizeHookInput(adapter, value);
110
+ const toolName = string(input.tool_name);
84
111
  if (input.private === true ||
85
112
  input.is_private === true ||
86
113
  /vault[_-]go|vault[_-]mem/.test(toolName)) {
87
- return hookOutput(event);
114
+ return hookOutput(event, "", adapter);
88
115
  }
89
116
  const prefs = await preferences(cloud);
90
117
  const reading = event === "context" || event === "file-context";
91
118
  if (!reading && prefs.automaticCapture !== true)
92
- return hookOutput(event);
93
- const tool = record(input.tool_input ?? input.toolInput);
94
- const file = string(tool.file_path, tool.path, tool.notebook_path);
119
+ return hookOutput(event, "", adapter);
120
+ const tool = record(input.tool_input);
121
+ const file = string(tool.file_path, tool.path, tool.notebook_path, tool.AbsolutePath, tool.Path, tool.filePath);
95
122
  const modifies = /write|edit|patch|create|delete|move|rename/i.test(toolName);
96
123
  if (!reading && prefs.captureMode === "focused" && event !== "summarize")
97
- return hookOutput(event);
124
+ return hookOutput(event, "", adapter);
98
125
  if (event === "observation" && prefs.captureMode === "balanced" && !modifies)
99
- return hookOutput(event);
126
+ return hookOutput(event, "", adapter);
100
127
  if (event === "file-context" && !file)
101
- return hookOutput(event);
102
- const sessionId = string(input.session_id, input.sessionId, input.thread_id, input.conversation_id);
128
+ return hookOutput(event, "", adapter);
129
+ const sessionId = string(input.session_id);
103
130
  if (!reading && !sessionId)
104
- return hookOutput(event);
131
+ return hookOutput(event, "", adapter);
105
132
  const cwd = root(string(input.cwd, input.workspace) || process.cwd());
106
133
  const projects = await cloud.projects();
107
134
  if (!Array.isArray(projects))
@@ -110,7 +137,7 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
110
137
  typeof item === "object" &&
111
138
  resolve(String(item.rootPath || "")) === cwd);
112
139
  if (!project && reading)
113
- return hookOutput(event);
140
+ return hookOutput(event, "", adapter);
114
141
  if (!project) {
115
142
  project = record(await cloud.createProject({
116
143
  name: (basename(cwd) || "workspace").padEnd(3, "_").slice(0, 80),
@@ -131,7 +158,7 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
131
158
  paths: [...new Set([file, resolve(cwd, file)])],
132
159
  })
133
160
  : await cloud.context(limits));
134
- return hookOutput(event, string(result.context).slice(0, 24_000));
161
+ return hookOutput(event, string(result.context).slice(0, 24_000), adapter);
135
162
  }
136
163
  const session = record(await cloud.startSession({
137
164
  projectId: project.id,
@@ -140,8 +167,8 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
140
167
  }));
141
168
  if (typeof session.id !== "string")
142
169
  throw new Error("Sessão inválida");
143
- const prompt = string(input.prompt, input.user_prompt);
144
- const response = string(input.last_assistant_message, input.response, input.summary);
170
+ const prompt = string(input.prompt);
171
+ const response = string(input.last_assistant_message);
145
172
  const rawContent = event === "session-init"
146
173
  ? prompt
147
174
  : event === "summarize"
@@ -195,7 +222,7 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
195
222
  }
196
223
  if (event === "summarize")
197
224
  await cloud.endSession(session.id);
198
- return hookOutput(event);
225
+ return hookOutput(event, "", adapter);
199
226
  }
200
227
  export async function readHookInput(stream = process.stdin) {
201
228
  const chunks = [];
@@ -1,6 +1,6 @@
1
1
  export declare const MCP_SERVER_NAME = "vault-go";
2
2
  export declare const MCP_SERVER_COMMAND: readonly ["bunx", "--bun", "vault-go@latest", "serve"];
3
- export declare const MCP_CLIENTS: readonly ["codex", "claude", "claude-desktop", "cursor", "vscode", "copilot", "windsurf", "roo", "opencode"];
3
+ export declare const MCP_CLIENTS: readonly ["codex", "claude", "claude-desktop", "cursor", "vscode", "copilot", "windsurf", "roo", "opencode", "grok", "agy", "gemini", "vault-desktop"];
4
4
  export type McpClient = (typeof MCP_CLIENTS)[number];
5
5
  export interface DetectedClient {
6
6
  client: McpClient;
@@ -17,6 +17,8 @@ type CommandResult = {
17
17
  error?: Error;
18
18
  };
19
19
  type CommandRunner = (command: string, args: readonly string[]) => CommandResult;
20
+ export declare function vaultDesktopMcpPath(home: string): string;
21
+ export declare function vaultDesktopDotMcpPath(home: string): string;
20
22
  export declare function installMcpClient(client: McpClient, options?: {
21
23
  home?: string;
22
24
  cwd?: string;
package/dist/installer.js CHANGED
@@ -17,7 +17,16 @@ export const MCP_CLIENTS = [
17
17
  'windsurf',
18
18
  'roo',
19
19
  'opencode',
20
+ 'grok',
21
+ 'agy',
22
+ 'gemini',
23
+ 'vault-desktop',
20
24
  ];
25
+ const CLIENT_ALIASES = {
26
+ antigravity: 'agy',
27
+ 'gemini-cli': 'gemini',
28
+ desktop: 'vault-desktop',
29
+ };
21
30
  const runCommand = (command, args) => spawnSync(command, [...args], { stdio: 'ignore' });
22
31
  function readJsonObject(path) {
23
32
  if (!existsSync(path))
@@ -35,12 +44,37 @@ function readJsonObject(path) {
35
44
  return parsed;
36
45
  }
37
46
  function atomicWriteJson(path, value) {
47
+ atomicWriteText(path, `${JSON.stringify(value, null, 2)}\n`);
48
+ }
49
+ function atomicWriteText(path, text) {
38
50
  mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
39
51
  const temporary = join(dirname(path), `.${process.pid}.${Date.now()}.tmp`);
40
- writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
52
+ writeFileSync(temporary, text.endsWith('\n') ? text : `${text}\n`, { mode: 0o600 });
41
53
  renameSync(temporary, path);
42
54
  chmodSync(path, 0o600);
43
55
  }
56
+ function formatTomlValue(value) {
57
+ if (typeof value === 'boolean')
58
+ return value ? 'true' : 'false';
59
+ if (typeof value === 'string')
60
+ return JSON.stringify(value);
61
+ return `[${value.map((item) => JSON.stringify(item)).join(', ')}]`;
62
+ }
63
+ function upsertTomlTable(path, table, assignments) {
64
+ const previous = existsSync(path) ? readFileSync(path, 'utf8') : '';
65
+ const body = Object.entries(assignments)
66
+ .map(([key, value]) => `${key} = ${formatTomlValue(value)}`)
67
+ .join('\n');
68
+ const block = `[${table}]\n${body}\n`;
69
+ const escaped = table.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
70
+ const pattern = new RegExp(`(^|\\r?\\n)\\[${escaped}\\](?:\\r?\\n(?!\\[).*)*`);
71
+ const next = pattern.test(previous)
72
+ ? previous.replace(pattern, (match) => `${/^\r?\n/.exec(match)?.[0] ?? ''}${block}`)
73
+ : previous.trimEnd()
74
+ ? `${previous.trimEnd()}\n\n${block}`
75
+ : block;
76
+ atomicWriteText(path, next);
77
+ }
44
78
  function standardServer() {
45
79
  return {
46
80
  command: MCP_SERVER_COMMAND[0],
@@ -70,6 +104,18 @@ function claudeDesktopPath(home) {
70
104
  }
71
105
  return join(home, '.config', 'Claude', 'claude_desktop_config.json');
72
106
  }
107
+ export function vaultDesktopMcpPath(home) {
108
+ if (platform() === 'darwin') {
109
+ return join(home, 'Library', 'Application Support', 'Vault Desktop', 'mcp.json');
110
+ }
111
+ if (platform() === 'win32') {
112
+ return join(process.env['APPDATA'] ?? join(home, 'AppData', 'Roaming'), 'Vault Desktop', 'mcp.json');
113
+ }
114
+ return join(home, '.config', 'Vault Desktop', 'mcp.json');
115
+ }
116
+ export function vaultDesktopDotMcpPath(home) {
117
+ return join(home, '.vault-desktop', 'mcp.json');
118
+ }
73
119
  function installViaCli(client, command, getArgs, addArgs, runner) {
74
120
  const existing = runner(command, getArgs);
75
121
  if (existing.status === 0) {
@@ -125,6 +171,42 @@ export function installMcpClient(client, options = {}) {
125
171
  }
126
172
  return { client, status: 'installed', destination: 'VS Code user profile' };
127
173
  }
174
+ if (client === 'grok') {
175
+ const destination = join(home, '.grok', 'config.toml');
176
+ upsertTomlTable(destination, 'mcp_servers.vault-go', {
177
+ command: MCP_SERVER_COMMAND[0],
178
+ args: MCP_SERVER_COMMAND.slice(1),
179
+ enabled: true,
180
+ });
181
+ try {
182
+ stageLocalRuntime(vaultHome());
183
+ }
184
+ catch { /* incomplete installs still write hooks */ }
185
+ installClientHooks('grok', home);
186
+ return { client, status: 'installed', destination };
187
+ }
188
+ if (client === 'agy') {
189
+ const cliPath = join(home, '.gemini', 'config', 'mcp_config.json');
190
+ mergeServer(cliPath);
191
+ mergeServer(join(home, '.gemini', 'antigravity', 'mcp_config.json'));
192
+ try {
193
+ stageLocalRuntime(vaultHome());
194
+ }
195
+ catch { /* incomplete installs still write hooks */ }
196
+ installClientHooks('agy', home);
197
+ return { client, status: 'installed', destination: cliPath };
198
+ }
199
+ if (client === 'gemini') {
200
+ const path = join(home, '.gemini', 'settings.json');
201
+ mergeServer(path);
202
+ return { client, status: 'installed', destination: path };
203
+ }
204
+ if (client === 'vault-desktop') {
205
+ const destination = vaultDesktopMcpPath(home);
206
+ mergeServer(destination);
207
+ mergeServer(vaultDesktopDotMcpPath(home));
208
+ return { client, status: 'installed', destination };
209
+ }
128
210
  let path;
129
211
  if (client === 'claude-desktop')
130
212
  path = claudeDesktopPath(home);
@@ -169,6 +251,10 @@ export function detectMcpClients(home = homedir()) {
169
251
  ['windsurf', ['windsurf'], [join(home, '.codeium', 'windsurf')]],
170
252
  ['roo', [], []],
171
253
  ['opencode', ['opencode'], [join(home, '.config', 'opencode')]],
254
+ ['grok', ['grok'], [join(home, '.grok')]],
255
+ ['agy', ['agy'], [join(home, '.gemini', 'antigravity-cli'), join(home, '.gemini', 'config'), join(home, '.gemini', 'antigravity')]],
256
+ ['gemini', ['gemini'], [join(home, '.gemini', 'settings.json')]],
257
+ ['vault-desktop', [], [vaultDesktopMcpPath(home), vaultDesktopDotMcpPath(home), '/Applications/Vault Desktop.app']],
172
258
  ];
173
259
  return definitions.map(([client, commands, paths]) => {
174
260
  const command = commands.find((candidate) => Bun.which(candidate));
@@ -195,7 +281,10 @@ export function parseClientSelection(value) {
195
281
  const normalized = value.trim().toLowerCase();
196
282
  if (normalized === 'all' || normalized === 'todos')
197
283
  return [...MCP_CLIENTS];
198
- const selected = [...new Set(normalized.split(',').map((item) => item.trim()).filter(Boolean))];
284
+ const selected = [...new Set(normalized.split(',').map((item) => {
285
+ const trimmed = item.trim();
286
+ return CLIENT_ALIASES[trimmed] ?? trimmed;
287
+ }).filter(Boolean))];
199
288
  const invalid = selected.filter((item) => !MCP_CLIENTS.includes(item));
200
289
  if (invalid.length > 0)
201
290
  throw new Error(`Clientes MCP desconhecidos: ${invalid.join(', ')}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vault-go",
3
- "version": "0.16.1",
3
+ "version": "0.18.0",
4
4
  "description": "Servidor MCP universal com autenticação e instalação multi-cliente para a plataforma Vault.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -103,7 +103,10 @@
103
103
  "codex",
104
104
  "claude",
105
105
  "copilot",
106
- "cursor"
106
+ "cursor",
107
+ "grok",
108
+ "opencode",
109
+ "antigravity"
107
110
  ],
108
111
  "author": "Gutierrez Henrique",
109
112
  "license": "MIT",