vault-go 0.29.2 → 0.31.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 +12 -0
- package/dist/agent-cost.d.ts +11 -0
- package/dist/agent-cost.js +116 -0
- package/dist/auth.js +29 -2
- package/dist/capabilities.d.ts +40 -24
- package/dist/capabilities.js +8 -6
- package/dist/capture-privacy.js +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +16 -1
- package/dist/cloud.d.ts +22 -0
- package/dist/cloud.js +131 -47
- package/dist/config.d.ts +2 -0
- package/dist/config.js +15 -1
- package/dist/crystal-memory-mirror.d.ts +14 -1
- package/dist/crystal-memory-mirror.js +24 -15
- package/dist/crystal-tools.d.ts +24 -1
- package/dist/crystal-tools.js +30 -5
- package/dist/grok-awareness.js +54 -1
- package/dist/hook-install.d.ts +4 -0
- package/dist/hook-install.js +41 -1
- package/dist/hook-queue.d.ts +18 -0
- package/dist/hook-queue.js +115 -3
- package/dist/hook-runner.js +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +27 -8
- package/dist/index.js +5 -1
- package/dist/installer.js +8 -1
- package/dist/legacy-brand.d.ts +2 -0
- package/dist/legacy-brand.js +5 -0
- package/dist/local-service.js +11 -0
- package/dist/memory-archive.d.ts +25 -0
- package/dist/memory-archive.js +65 -0
- package/dist/modes.d.ts +1 -1
- package/dist/modes.js +3 -1
- package/dist/opencode-plugin.d.ts +29 -1
- package/dist/opencode-plugin.js +36 -1
- package/dist/server.js +68 -0
- package/dist/skill-context.d.ts +4 -0
- package/dist/skill-context.js +16 -0
- package/dist/skill-download.d.ts +6 -0
- package/dist/skill-download.js +48 -0
- package/dist/skill-library.d.ts +8 -0
- package/dist/skill-library.js +32 -0
- package/dist/skill-local.d.ts +53 -0
- package/dist/skill-local.js +251 -0
- package/dist/skill-tools.d.ts +52 -0
- package/dist/skill-tools.js +356 -0
- package/dist/skills-cli.d.ts +31 -0
- package/dist/skills-cli.js +90 -0
- package/dist/transcript-config.d.ts +1 -1
- package/dist/transcript-config.js +4 -3
- package/dist/transcript-parser.js +1 -1
- package/dist/transcript-tools.js +1 -1
- package/package.json +19 -1
package/dist/hook-install.js
CHANGED
|
@@ -35,11 +35,13 @@ function atomicWriteText(path, text) {
|
|
|
35
35
|
}
|
|
36
36
|
export const HOOK_OWNER = "Vault Go: captura e contexto";
|
|
37
37
|
export const HOOK_EVENTS = {
|
|
38
|
+
Setup: "setup",
|
|
38
39
|
SessionStart: "context",
|
|
39
40
|
UserPromptSubmit: "session-init",
|
|
40
41
|
PreToolUse: "file-context",
|
|
41
42
|
PostToolUse: "observation",
|
|
42
43
|
Stop: "summarize",
|
|
44
|
+
SessionEnd: "session-end",
|
|
43
45
|
};
|
|
44
46
|
const GEMINI_EVENTS = {
|
|
45
47
|
SessionStart: "context",
|
|
@@ -77,7 +79,7 @@ function hookManifest(adapter, configHome = vaultHome()) {
|
|
|
77
79
|
timeout: event === "context" ? 60 : 20,
|
|
78
80
|
statusMessage: HOOK_OWNER,
|
|
79
81
|
}),
|
|
80
|
-
...(adapter !== "gemini" && (event === "observation" || event === "summarize")
|
|
82
|
+
...(adapter !== "gemini" && (event === "observation" || event === "summarize" || event === "session-end")
|
|
81
83
|
? { async: true }
|
|
82
84
|
: {}),
|
|
83
85
|
},
|
|
@@ -102,8 +104,37 @@ function agyHookManifest(configHome = vaultHome()) {
|
|
|
102
104
|
{ matcher: "*", hooks: [agyHandler("observation", configHome)] },
|
|
103
105
|
],
|
|
104
106
|
Stop: [agyHandler("summarize", configHome)],
|
|
107
|
+
SessionEnd: [agyHandler("session-end", configHome)],
|
|
105
108
|
};
|
|
106
109
|
}
|
|
110
|
+
const CAPTURE_HOMES = {
|
|
111
|
+
cursor: ".cursor/hooks.json",
|
|
112
|
+
windsurf: ".codeium/windsurf/hooks.json",
|
|
113
|
+
openclaw: ".openclaw/hooks.json",
|
|
114
|
+
hermes: ".hermes/hooks.json",
|
|
115
|
+
};
|
|
116
|
+
export function installCaptureHooks(adapter, userHome = homedir(), configHome = vaultHome()) {
|
|
117
|
+
const relative = CAPTURE_HOMES[adapter];
|
|
118
|
+
if (!relative)
|
|
119
|
+
throw new Error("Adaptador de captura desconhecido.");
|
|
120
|
+
const path = join(userHome, relative);
|
|
121
|
+
const config = existsSync(path) ? readJsonObject(path) : {};
|
|
122
|
+
const hooks = {
|
|
123
|
+
...(config.hooks && typeof config.hooks === "object" && !Array.isArray(config.hooks) ? config.hooks : {}),
|
|
124
|
+
};
|
|
125
|
+
const desired = hookManifest(adapter, configHome).hooks;
|
|
126
|
+
for (const event of Object.keys(desired)) {
|
|
127
|
+
const current = hooks[event];
|
|
128
|
+
const retained = Array.isArray(current)
|
|
129
|
+
? current.filter((group) => {
|
|
130
|
+
const text = JSON.stringify(group);
|
|
131
|
+
return !text.includes(HOOK_OWNER);
|
|
132
|
+
})
|
|
133
|
+
: [];
|
|
134
|
+
hooks[event] = [...retained, ...(desired[event] || [])];
|
|
135
|
+
}
|
|
136
|
+
atomicWriteJson(path, { ...config, hooks });
|
|
137
|
+
}
|
|
107
138
|
export function installClientHooks(client, userHome = homedir(), configHome = vaultHome()) {
|
|
108
139
|
if (client === "grok") {
|
|
109
140
|
atomicWriteJson(join(userHome, ".grok", "hooks", "vault-go.json"), hookManifest("grok", configHome));
|
|
@@ -173,6 +204,15 @@ export function repairAdditionalClientHooks(userHome = homedir(), configHome = v
|
|
|
173
204
|
if (server && server.enabled !== false)
|
|
174
205
|
installOpenCodePlugin(userHome, configHome);
|
|
175
206
|
}, report);
|
|
207
|
+
for (const adapter of Object.keys(CAPTURE_HOMES)) {
|
|
208
|
+
const relative = CAPTURE_HOMES[adapter];
|
|
209
|
+
if (!relative)
|
|
210
|
+
continue;
|
|
211
|
+
const directory = join(userHome, relative.split("/").slice(0, -1).join("/"));
|
|
212
|
+
if (existsSync(directory)) {
|
|
213
|
+
repairClient(adapter, () => installCaptureHooks(adapter, userHome, configHome), report);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
176
216
|
}
|
|
177
217
|
function reportRepairWarning(message) {
|
|
178
218
|
process.stderr.write(message + "\n");
|
package/dist/hook-queue.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { VaultCloudClient } from './cloud.js';
|
|
2
2
|
import { generateContext, type ContextResult } from './context-engines.js';
|
|
3
3
|
import { type TelegramObservation } from './telegram.js';
|
|
4
|
+
import { privateStore } from './private-store.js';
|
|
5
|
+
import { type CrystalMirrorRecord } from './crystal-memory-mirror.js';
|
|
4
6
|
export interface GenerationJob {
|
|
5
7
|
id: string;
|
|
6
8
|
projectId: string;
|
|
@@ -19,6 +21,21 @@ export interface GenerationJob {
|
|
|
19
21
|
lastError?: string;
|
|
20
22
|
result?: Pick<ContextResult, 'title' | 'content' | 'facts' | 'concepts' | 'type'>;
|
|
21
23
|
}
|
|
24
|
+
export declare function ownerKey(home: string): string;
|
|
25
|
+
export interface PendingCrystalMirror extends CrystalMirrorRecord {
|
|
26
|
+
owner: string;
|
|
27
|
+
queuedAt: number;
|
|
28
|
+
}
|
|
29
|
+
export type CrystalMirrorStore = Pick<ReturnType<typeof privateStore>, 'keyStorage' | 'read' | 'write' | 'remove' | 'close'>;
|
|
30
|
+
export type CrystalMirrorStoreFactory = (home: string) => CrystalMirrorStore;
|
|
31
|
+
export declare const MAX_PENDING_CRYSTAL_MIRRORS = 500;
|
|
32
|
+
export declare function pendingCrystalMirrors(home?: string, openStore?: CrystalMirrorStoreFactory): Promise<PendingCrystalMirror[]>;
|
|
33
|
+
export declare function queuePendingCrystalMirror(home: string, owner: string, record: CrystalMirrorRecord, openStore?: CrystalMirrorStoreFactory): Promise<void>;
|
|
34
|
+
/** Retries locked Crystal copies for this account, stopping at the first sign the Crystal is still locked or closed. */
|
|
35
|
+
export declare function flushPendingCrystalMirrors(home?: string, owner?: string, options?: {
|
|
36
|
+
limit?: number;
|
|
37
|
+
openStore?: CrystalMirrorStoreFactory;
|
|
38
|
+
}): Promise<number>;
|
|
22
39
|
export declare function enqueueGeneration(home: string, job: GenerationJob): Promise<void>;
|
|
23
40
|
export declare function generationQueueStatus(home?: string): {
|
|
24
41
|
pending: number;
|
|
@@ -28,4 +45,5 @@ export declare function generationQueueStatus(home?: string): {
|
|
|
28
45
|
};
|
|
29
46
|
export declare function processGenerationQueue(home?: string, cloud?: VaultCloudClient, generate?: typeof generateContext, options?: {
|
|
30
47
|
notifyObservation?: (observation: TelegramObservation) => Promise<unknown>;
|
|
48
|
+
crystalMirrorStore?: CrystalMirrorStoreFactory;
|
|
31
49
|
}): Promise<boolean>;
|
package/dist/hook-queue.js
CHANGED
|
@@ -6,9 +6,10 @@ import { loadConfig, loadTokens, vaultHome } from './config.js';
|
|
|
6
6
|
import { generateContext, selectedContextEngine } from './context-engines.js';
|
|
7
7
|
import { notifyTelegramObservation } from './telegram.js';
|
|
8
8
|
import { pushAwareness } from './grok-awareness.js';
|
|
9
|
-
import {
|
|
9
|
+
import { privateStore } from './private-store.js';
|
|
10
|
+
import { mirrorCrystalMemory, writeCrystalMirror } from './crystal-memory-mirror.js';
|
|
10
11
|
const queuePath = (home) => join(home, 'generation-queue.json');
|
|
11
|
-
function ownerKey(home) {
|
|
12
|
+
export function ownerKey(home) {
|
|
12
13
|
const config = loadConfig(home);
|
|
13
14
|
return createHash('sha256').update(JSON.stringify([config.apiUrl, process.env['VAULT_GO_TOKEN'] || config.email || loadTokens(home)?.accessToken || 'anonymous'])).digest('hex');
|
|
14
15
|
}
|
|
@@ -115,6 +116,113 @@ function appliedObservationType(result, sourceId, fallback) {
|
|
|
115
116
|
? observationType
|
|
116
117
|
: fallback;
|
|
117
118
|
}
|
|
119
|
+
export const MAX_PENDING_CRYSTAL_MIRRORS = 500;
|
|
120
|
+
const PENDING_MIRROR_STORE = 'crystal-pending-mirrors.json';
|
|
121
|
+
const MAX_PENDING_MIRROR_BYTES = 4 * 1024 * 1024 - 64 * 1024; // private-store refuses records above 4 MiB
|
|
122
|
+
// Why: the user chose to encrypt the Crystal, so its copies never touch disk in
|
|
123
|
+
// plaintext. Without a durable key they live only for this process lifetime.
|
|
124
|
+
const memoryMirrors = new Map();
|
|
125
|
+
function openMirrorStore(home, factory) {
|
|
126
|
+
try {
|
|
127
|
+
const store = factory(home);
|
|
128
|
+
if (store.keyStorage !== 'ephemeral')
|
|
129
|
+
return store;
|
|
130
|
+
store.close();
|
|
131
|
+
}
|
|
132
|
+
catch { /* OS key store locked or unavailable */ }
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
function readStoredMirrors(home, store) {
|
|
136
|
+
if (!existsSync(join(home, PENDING_MIRROR_STORE)))
|
|
137
|
+
return [];
|
|
138
|
+
const value = store.read(PENDING_MIRROR_STORE);
|
|
139
|
+
if (value?.v === 1 && Array.isArray(value.items))
|
|
140
|
+
return value.items;
|
|
141
|
+
// Local key changed or the file was altered: the copies cannot be recovered.
|
|
142
|
+
store.remove(PENDING_MIRROR_STORE);
|
|
143
|
+
console.error('vault-go: cópias pendentes para o Crystal ilegíveis (chave local mudou) foram descartadas.');
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
function boundPendingMirrors(items) {
|
|
147
|
+
let next = items.slice(-MAX_PENDING_CRYSTAL_MIRRORS);
|
|
148
|
+
while (next.length && Buffer.byteLength(JSON.stringify({ v: 1, items: next })) > MAX_PENDING_MIRROR_BYTES)
|
|
149
|
+
next = next.slice(1);
|
|
150
|
+
const dropped = items.length - next.length;
|
|
151
|
+
if (dropped > 0)
|
|
152
|
+
console.error(`vault-go: ${dropped} cópia(s) pendente(s) mais antiga(s) para o Crystal descartada(s) pelo limite local.`);
|
|
153
|
+
return next;
|
|
154
|
+
}
|
|
155
|
+
async function mutatePendingMirrors(home, factory, change) {
|
|
156
|
+
const release = await lock(home, 'crystal-mirror-storage');
|
|
157
|
+
try {
|
|
158
|
+
const store = openMirrorStore(home, factory);
|
|
159
|
+
const memory = memoryMirrors.get(home) ?? [];
|
|
160
|
+
if (!store) {
|
|
161
|
+
memoryMirrors.set(home, boundPendingMirrors(change(memory)));
|
|
162
|
+
return 'memory';
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
// Copies held in memory while the key was unavailable move into the encrypted file.
|
|
166
|
+
const stored = readStoredMirrors(home, store);
|
|
167
|
+
const merged = [...stored.filter(item => !memory.some(held => held.sourceId === item.sourceId)), ...memory];
|
|
168
|
+
const next = boundPendingMirrors(change(merged));
|
|
169
|
+
if (next.length)
|
|
170
|
+
store.write(PENDING_MIRROR_STORE, { v: 1, items: next });
|
|
171
|
+
else
|
|
172
|
+
store.remove(PENDING_MIRROR_STORE);
|
|
173
|
+
memoryMirrors.delete(home);
|
|
174
|
+
return 'encrypted';
|
|
175
|
+
}
|
|
176
|
+
finally {
|
|
177
|
+
store.close();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
release?.();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
export async function pendingCrystalMirrors(home = vaultHome(), openStore = privateStore) {
|
|
185
|
+
let items = [];
|
|
186
|
+
await mutatePendingMirrors(home, openStore, current => (items = current));
|
|
187
|
+
return items;
|
|
188
|
+
}
|
|
189
|
+
export async function queuePendingCrystalMirror(home, owner, record, openStore = privateStore) {
|
|
190
|
+
let held = 0;
|
|
191
|
+
const storage = await mutatePendingMirrors(home, openStore, items => {
|
|
192
|
+
// Same sourceId replaces the older copy; Desktop also dedups writes by sourceId.
|
|
193
|
+
const next = [...items.filter(item => item.sourceId !== record.sourceId), { ...record, owner, queuedAt: Date.now() }];
|
|
194
|
+
held = next.length;
|
|
195
|
+
return next;
|
|
196
|
+
});
|
|
197
|
+
if (storage === 'memory')
|
|
198
|
+
console.error(`vault-go: chave local indisponível; ${held} cópia(s) pendente(s) para o Crystal mantida(s) só em memória.`);
|
|
199
|
+
}
|
|
200
|
+
/** Retries locked Crystal copies for this account, stopping at the first sign the Crystal is still locked or closed. */
|
|
201
|
+
export async function flushPendingCrystalMirrors(home = vaultHome(), owner = ownerKey(home), options = {}) {
|
|
202
|
+
if (!existsSync(join(home, PENDING_MIRROR_STORE)) && !memoryMirrors.get(home)?.length)
|
|
203
|
+
return 0;
|
|
204
|
+
const openStore = options.openStore ?? privateStore;
|
|
205
|
+
const release = await lock(home, 'crystal-mirror-flush', false);
|
|
206
|
+
if (!release)
|
|
207
|
+
return 0;
|
|
208
|
+
let written = 0;
|
|
209
|
+
try {
|
|
210
|
+
const items = (await pendingCrystalMirrors(home, openStore)).filter(entry => entry.owner === owner).slice(0, options.limit ?? 25);
|
|
211
|
+
for (const item of items) {
|
|
212
|
+
const outcome = await writeCrystalMirror(home, { sourceId: item.sourceId, project: item.project, title: item.title, content: item.content, tags: item.tags });
|
|
213
|
+
if (outcome === 'locked' || outcome === 'unavailable')
|
|
214
|
+
break;
|
|
215
|
+
// Written, or rejected for a reason other than the lock: retrying would not help.
|
|
216
|
+
if (outcome === 'written')
|
|
217
|
+
written++;
|
|
218
|
+
await mutatePendingMirrors(home, openStore, current => current.filter(entry => entry.sourceId !== item.sourceId));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
release();
|
|
223
|
+
}
|
|
224
|
+
return written;
|
|
225
|
+
}
|
|
118
226
|
export async function enqueueGeneration(home, job) {
|
|
119
227
|
if (isUnusableGenerationText(job.text) || job.text.length > 16_000)
|
|
120
228
|
return;
|
|
@@ -145,6 +253,7 @@ export async function processGenerationQueue(home = vaultHome(), cloud = new Vau
|
|
|
145
253
|
await mutate(home, jobs => jobs.map(item => !item.owner && owned.has(item.projectId) ? { ...item, owner } : item));
|
|
146
254
|
}
|
|
147
255
|
}
|
|
256
|
+
await flushPendingCrystalMirrors(home, owner, options.crystalMirrorStore ? { openStore: options.crystalMirrorStore } : {}).catch(() => 0);
|
|
148
257
|
const job = readQueue(home).find(item => item.owner === owner && (item.nextAttemptAt ?? 0) <= Date.now());
|
|
149
258
|
if (!job)
|
|
150
259
|
return false;
|
|
@@ -178,7 +287,10 @@ export async function processGenerationQueue(home = vaultHome(), cloud = new Vau
|
|
|
178
287
|
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 }] });
|
|
179
288
|
if (awareness.error)
|
|
180
289
|
throw new Error('Awareness delivery failed; retry with cached generation.');
|
|
181
|
-
await mirrorCrystalMemory({ home, cloud, job, result });
|
|
290
|
+
const mirror = await mirrorCrystalMemory({ home, cloud, job, result });
|
|
291
|
+
// Never fail the cloud job over the Crystal copy; a locked Crystal just defers it.
|
|
292
|
+
if (mirror.outcome === 'locked' && mirror.record)
|
|
293
|
+
await queuePendingCrystalMirror(home, owner, mirror.record, options.crystalMirrorStore).catch(() => { });
|
|
182
294
|
await mutate(home, jobs => jobs.filter(item => item.id !== job.id));
|
|
183
295
|
if (job.kind === 'observation' && owner === ownerKey(home)) {
|
|
184
296
|
try {
|
package/dist/hook-runner.js
CHANGED
|
@@ -3,7 +3,7 @@ import { HOOK_EVENTS, runHook } from "./hooks.js";
|
|
|
3
3
|
const adapter = process.argv[2] ?? "auto";
|
|
4
4
|
const event = process.argv[3];
|
|
5
5
|
if (!event || !HOOK_EVENTS.includes(event)) {
|
|
6
|
-
process.stderr.write("Uso: hook-runner <adaptador> context|session-init|observation|file-context|summarize\n");
|
|
6
|
+
process.stderr.write("Uso: hook-runner <adaptador> setup|context|session-init|observation|file-context|summarize|session-end\n");
|
|
7
7
|
process.exit(1);
|
|
8
8
|
}
|
|
9
9
|
await runHook(adapter, event);
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { redact } from './capture-privacy.js';
|
|
2
2
|
import { type VaultMemoryApi } from "./cloud.js";
|
|
3
|
-
export declare const HOOK_EVENTS: readonly ["context", "session-init", "observation", "file-context", "summarize"];
|
|
3
|
+
export declare const HOOK_EVENTS: readonly ["setup", "context", "session-init", "observation", "file-context", "summarize", "session-end"];
|
|
4
4
|
export type HookEvent = (typeof HOOK_EVENTS)[number];
|
|
5
5
|
type RecordValue = Record<string, unknown>;
|
|
6
6
|
/** The existing project for a working directory (worktrees map to their main checkout); never creates one. */
|
package/dist/hooks.js
CHANGED
|
@@ -10,12 +10,15 @@ import { vaultHome } from "./config.js";
|
|
|
10
10
|
import { enqueueGeneration } from "./hook-queue.js";
|
|
11
11
|
import { transcriptCaptureEnabled } from './transcript-config.js';
|
|
12
12
|
import { loadProjectContext } from './context-chain.js';
|
|
13
|
+
import { skillContextSection } from './skill-context.js';
|
|
13
14
|
export const HOOK_EVENTS = [
|
|
15
|
+
"setup",
|
|
14
16
|
"context",
|
|
15
17
|
"session-init",
|
|
16
18
|
"observation",
|
|
17
19
|
"file-context",
|
|
18
20
|
"summarize",
|
|
21
|
+
"session-end",
|
|
19
22
|
];
|
|
20
23
|
const record = (value) => value && typeof value === "object" && !Array.isArray(value)
|
|
21
24
|
? value
|
|
@@ -190,6 +193,11 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
190
193
|
/vault[_-]go|vault[_-]mem/.test(toolName)) {
|
|
191
194
|
return hookOutput(event, "", adapter);
|
|
192
195
|
}
|
|
196
|
+
if (event === "setup") {
|
|
197
|
+
const output = hookOutput(event, "", adapter);
|
|
198
|
+
output.systemMessage = "Vault Memory: hooks ready.";
|
|
199
|
+
return output;
|
|
200
|
+
}
|
|
193
201
|
const prefs = await preferences(cloud);
|
|
194
202
|
const reading = event === "context" || event === "file-context";
|
|
195
203
|
if (!reading && prefs.automaticCapture !== true)
|
|
@@ -197,7 +205,7 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
197
205
|
const tool = record(input.tool_input);
|
|
198
206
|
const file = string(tool.file_path, tool.path, tool.notebook_path, tool.AbsolutePath, tool.Path, tool.filePath);
|
|
199
207
|
const modifies = /write|edit|patch|create|delete|move|rename/i.test(toolName);
|
|
200
|
-
if (!reading && prefs.captureMode === "focused" && event !== "summarize")
|
|
208
|
+
if (!reading && prefs.captureMode === "focused" && event !== "summarize" && event !== "session-end")
|
|
201
209
|
return hookOutput(event, "", adapter);
|
|
202
210
|
if (event === "observation" && prefs.captureMode === "balanced" && !modifies)
|
|
203
211
|
return hookOutput(event, "", adapter);
|
|
@@ -246,6 +254,15 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
246
254
|
})
|
|
247
255
|
: { context: await loadProjectContext(home, cloud, { workspace, primary: { id: project.id }, projects, ...limits }) });
|
|
248
256
|
let context = string(result.context).slice(0, limits.maxChars);
|
|
257
|
+
if (event === "context") {
|
|
258
|
+
// Skills do projeto entram depois da memória e só no espaço que sobrar; falha aqui nunca derruba o contexto.
|
|
259
|
+
try {
|
|
260
|
+
const skills = await skillContextSection(cloud, project.id);
|
|
261
|
+
if (skills && context.length + skills.length + 2 <= limits.maxChars)
|
|
262
|
+
context = context ? `${context}\n\n${skills}` : skills;
|
|
263
|
+
}
|
|
264
|
+
catch { /* biblioteca de skills indisponível */ }
|
|
265
|
+
}
|
|
249
266
|
try {
|
|
250
267
|
context = applyCustomModeContext(home, context, limits.maxChars);
|
|
251
268
|
}
|
|
@@ -270,8 +287,8 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
270
287
|
}));
|
|
271
288
|
const rawContent = event === "session-init"
|
|
272
289
|
? prompt
|
|
273
|
-
: event === "summarize"
|
|
274
|
-
? response
|
|
290
|
+
: event === "summarize" || event === "session-end"
|
|
291
|
+
? response || (event === "session-end" ? "session ended" : "")
|
|
275
292
|
: JSON.stringify(toolPayload);
|
|
276
293
|
const content = String(redact(rawContent));
|
|
277
294
|
if (content.trim()) {
|
|
@@ -279,7 +296,9 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
279
296
|
? "user_prompt"
|
|
280
297
|
: event === "summarize"
|
|
281
298
|
? "session_summary"
|
|
282
|
-
: "
|
|
299
|
+
: event === "session-end"
|
|
300
|
+
? "session_end"
|
|
301
|
+
: "tool_use";
|
|
283
302
|
const sourceEventId = createHash("sha256")
|
|
284
303
|
.update(JSON.stringify([
|
|
285
304
|
adapter,
|
|
@@ -306,7 +325,7 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
306
325
|
summaryMode: 'off',
|
|
307
326
|
metadata: { summaryMode: 'off' },
|
|
308
327
|
title: toolName ||
|
|
309
|
-
(event === "summarize" ? "Resumo da sessão" : "Solicitação do usuário"),
|
|
328
|
+
(event === "session-end" ? "Fim da sessão" : event === "summarize" ? "Resumo da sessão" : "Solicitação do usuário"),
|
|
310
329
|
content,
|
|
311
330
|
filesRead: !modifies ? files : [],
|
|
312
331
|
filesModified: modifies ? files : [],
|
|
@@ -321,14 +340,14 @@ export async function executeHook(adapter, event, value, cloud = new VaultCloudC
|
|
|
321
340
|
...(string(input.agent_id, input.agentId) ? { agentId: string(input.agent_id, input.agentId) } : {}),
|
|
322
341
|
text: content.slice(0, 16_000),
|
|
323
342
|
title: toolName ||
|
|
324
|
-
(event === "summarize" ? "Resumo da sessão" : "Solicitação do usuário"),
|
|
325
|
-
kind: event === "summarize" ? "summary" : event === "session-init" ? "prompt" : "observation",
|
|
343
|
+
(event === "session-end" ? "Fim da sessão" : event === "summarize" ? "Resumo da sessão" : "Solicitação do usuário"),
|
|
344
|
+
kind: event === "summarize" || event === "session-end" ? "summary" : event === "session-init" ? "prompt" : "observation",
|
|
326
345
|
maxChars: boundedPreference(prefs.summaryMaxChars, 4_000, 256, 16_000),
|
|
327
346
|
filesRead: !modifies ? files : [],
|
|
328
347
|
filesModified: modifies ? files : [],
|
|
329
348
|
});
|
|
330
349
|
}
|
|
331
|
-
if (event === "summarize")
|
|
350
|
+
if (event === "summarize" || event === "session-end")
|
|
332
351
|
await cloud.endSession(session.id);
|
|
333
352
|
return hookOutput(event, "", adapter);
|
|
334
353
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
-
import { cliArguments, helpText, resolveCliMode, runEngine, runLocal, runLogin, runSetup, runUpdate, runTranscripts, runContextChain } from './cli.js';
|
|
3
|
+
import { cliArguments, helpText, resolveCliMode, runEngine, runLocal, runLogin, runSetup, runUpdate, runTranscripts, runContextChain, runSkills } from './cli.js';
|
|
4
4
|
import { HOOK_EVENTS, runHook } from './hooks.js';
|
|
5
5
|
import { createVaultGoServer, VERSION } from './server.js';
|
|
6
6
|
const { argument, options } = cliArguments(process.argv.slice(2));
|
|
@@ -45,6 +45,10 @@ async function main() {
|
|
|
45
45
|
process.exitCode = await runContextChain(options);
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
+
if (mode === 'skills') {
|
|
49
|
+
process.exitCode = await runSkills(options);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
48
52
|
if (mode === 'hook') {
|
|
49
53
|
const adapter = options.find((item) => !item.startsWith('--')) ?? 'auto';
|
|
50
54
|
const event = options.filter((item) => !item.startsWith('--'))[1];
|
package/dist/installer.js
CHANGED
|
@@ -4,7 +4,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { vaultHome } from './config.js';
|
|
6
6
|
import { stageLocalRuntime } from './local-install.js';
|
|
7
|
-
import { installClientHooks, installOpenCodePlugin } from './hook-install.js';
|
|
7
|
+
import { installCaptureHooks, installClientHooks, installOpenCodePlugin } from './hook-install.js';
|
|
8
8
|
import { installManagedSkills } from './skill-install.js';
|
|
9
9
|
export const MCP_SERVER_NAME = 'vault-go';
|
|
10
10
|
export const MCP_SERVER_COMMAND = ['bunx', '--bun', 'vault-go@latest', 'serve'];
|
|
@@ -261,6 +261,13 @@ export function installMcpClient(client, options = {}) {
|
|
|
261
261
|
else {
|
|
262
262
|
mergeServer(path);
|
|
263
263
|
}
|
|
264
|
+
if (client === 'cursor' || client === 'windsurf') {
|
|
265
|
+
try {
|
|
266
|
+
stageLocalRuntime(vaultHome());
|
|
267
|
+
}
|
|
268
|
+
catch { /* hooks still point at the staged runner when it exists */ }
|
|
269
|
+
installCaptureHooks(client, home);
|
|
270
|
+
}
|
|
264
271
|
return { client, status: 'installed', destination: path };
|
|
265
272
|
}
|
|
266
273
|
export function detectMcpClients(home = homedir()) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Por quê: o Vault Desktop nasceu de um fork de outro produto e ainda grava o
|
|
2
|
+
// manifesto de bundle de skills no caminho herdado dele (os builds 0.2.x só
|
|
3
|
+
// conhecem esse). Este é o único lugar onde o literal herdado pode morar.
|
|
4
|
+
/** Caminho herdado do manifesto dentro do tar de um bundle de skills. */
|
|
5
|
+
export const LEGACY_SKILL_BUNDLE_MANIFEST_PATH = 'dev.orca.skill-sharing/manifest.json';
|
package/dist/local-service.js
CHANGED
|
@@ -5,6 +5,7 @@ import { join } from "node:path";
|
|
|
5
5
|
import { createHash, createHmac, randomBytes, timingSafeEqual, } from "node:crypto";
|
|
6
6
|
import { authPath, loadConfig, loadTokens, vaultHome } from "./config.js";
|
|
7
7
|
import { VaultCloudClient } from "./cloud.js";
|
|
8
|
+
import { statuslineText } from "./agent-cost.js";
|
|
8
9
|
import { readActivity } from "./activity.js";
|
|
9
10
|
import { dashboardHtml, dashboardScript } from "./local-dashboard.js";
|
|
10
11
|
import pkg from "../package.json" with { type: "json" };
|
|
@@ -336,6 +337,16 @@ export async function startLocalService(options = {}) {
|
|
|
336
337
|
});
|
|
337
338
|
return;
|
|
338
339
|
}
|
|
340
|
+
if (url.pathname === "/statusline" && req.method === "GET") {
|
|
341
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
342
|
+
res.end(statuslineText(home, pkg.version));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
if (url.pathname === "/viewer" && req.method === "GET") {
|
|
346
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
347
|
+
res.end(`<!doctype html><html lang="en"><head><meta charset="utf-8"><title>Vault Memory</title></head><body><h1>Vault Memory</h1><p>Search uses the Vault account index. This page does not keep a second local vector database.</p><p><a href="/">Open the dashboard</a></p><pre id="line"></pre><script>fetch("/statusline").then(function(response){return response.text()}).then(function(text){document.getElementById("line").textContent=text})</script></body></html>`);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
339
350
|
if (url.pathname === "/" && req.method === "GET") {
|
|
340
351
|
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
341
352
|
res.end(dashboardHtml());
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface ArchiveRecord {
|
|
2
|
+
sourceId: string;
|
|
3
|
+
kind: string;
|
|
4
|
+
content: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
sessionId?: string;
|
|
7
|
+
memoryType?: string;
|
|
8
|
+
facts?: string[];
|
|
9
|
+
concepts?: string[];
|
|
10
|
+
filesRead?: string[];
|
|
11
|
+
filesModified?: string[];
|
|
12
|
+
occurredAt?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface FourGroupArchive {
|
|
15
|
+
version: 1;
|
|
16
|
+
format: 'vault-memory-groups';
|
|
17
|
+
observations: ArchiveRecord[];
|
|
18
|
+
sessions: ArchiveRecord[];
|
|
19
|
+
summaries: ArchiveRecord[];
|
|
20
|
+
prompts: ArchiveRecord[];
|
|
21
|
+
}
|
|
22
|
+
export declare function normalizeArchiveRecord(value: unknown, fallbackId: string): ArchiveRecord | null;
|
|
23
|
+
export declare function recordsFromExport(value: unknown): ArchiveRecord[];
|
|
24
|
+
export declare function groupArchive(records: ArchiveRecord[]): FourGroupArchive;
|
|
25
|
+
export declare function flattenArchive(archive: FourGroupArchive): ArchiveRecord[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const GROUPS = ['observations', 'sessions', 'summaries', 'prompts'];
|
|
2
|
+
function strings(value, max) {
|
|
3
|
+
if (!Array.isArray(value))
|
|
4
|
+
return undefined;
|
|
5
|
+
const items = value.filter((item) => typeof item === 'string' && item.trim().length > 0).map(item => item.trim().slice(0, 2_000)).slice(0, max);
|
|
6
|
+
return items.length ? items : undefined;
|
|
7
|
+
}
|
|
8
|
+
export function normalizeArchiveRecord(value, fallbackId) {
|
|
9
|
+
if (!value || typeof value !== 'object')
|
|
10
|
+
return null;
|
|
11
|
+
const row = value;
|
|
12
|
+
const content = typeof row.content === 'string' ? row.content.trim() : typeof row.text === 'string' ? row.text.trim() : '';
|
|
13
|
+
if (!content)
|
|
14
|
+
return null;
|
|
15
|
+
const sourceId = typeof row.sourceId === 'string' && row.sourceId.trim() ? row.sourceId.trim().slice(0, 500) : fallbackId;
|
|
16
|
+
const kind = typeof row.kind === 'string' && row.kind.trim() ? row.kind.trim().slice(0, 100) : 'observation';
|
|
17
|
+
const record = { sourceId, kind, content: content.slice(0, 200_000) };
|
|
18
|
+
if (typeof row.title === 'string' && row.title.trim())
|
|
19
|
+
record.title = row.title.trim().slice(0, 500);
|
|
20
|
+
if (typeof row.sessionId === 'string' && row.sessionId.trim())
|
|
21
|
+
record.sessionId = row.sessionId.trim().slice(0, 80);
|
|
22
|
+
if (typeof row.memoryType === 'string' && row.memoryType.trim())
|
|
23
|
+
record.memoryType = row.memoryType.trim().slice(0, 100);
|
|
24
|
+
if (typeof row.occurredAt === 'string' && row.occurredAt.trim())
|
|
25
|
+
record.occurredAt = row.occurredAt.trim().slice(0, 40);
|
|
26
|
+
const facts = strings(row.facts, 200);
|
|
27
|
+
const concepts = strings(row.concepts, 200);
|
|
28
|
+
const filesRead = strings(row.filesRead, 500);
|
|
29
|
+
const filesModified = strings(row.filesModified, 500);
|
|
30
|
+
if (facts)
|
|
31
|
+
record.facts = facts;
|
|
32
|
+
if (concepts)
|
|
33
|
+
record.concepts = concepts;
|
|
34
|
+
if (filesRead)
|
|
35
|
+
record.filesRead = filesRead;
|
|
36
|
+
if (filesModified)
|
|
37
|
+
record.filesModified = filesModified;
|
|
38
|
+
return record;
|
|
39
|
+
}
|
|
40
|
+
function groupOf(kind) {
|
|
41
|
+
const value = kind.toLowerCase();
|
|
42
|
+
if (value === 'prompt' || value === 'user_prompt')
|
|
43
|
+
return 'prompts';
|
|
44
|
+
if (value === 'summary' || value === 'session_summary' || value === 'session_end')
|
|
45
|
+
return 'summaries';
|
|
46
|
+
if (value === 'session')
|
|
47
|
+
return 'sessions';
|
|
48
|
+
return 'observations';
|
|
49
|
+
}
|
|
50
|
+
export function recordsFromExport(value) {
|
|
51
|
+
const root = value && typeof value === 'object' ? value : {};
|
|
52
|
+
const lists = [root.records, root.memories, root.items].find(Array.isArray);
|
|
53
|
+
const grouped = GROUPS.flatMap(name => Array.isArray(root[name]) ? root[name] : []);
|
|
54
|
+
const source = lists ?? grouped;
|
|
55
|
+
return source.map((item, index) => normalizeArchiveRecord(item, `export-${index + 1}`)).filter((item) => Boolean(item)).slice(0, 4_000);
|
|
56
|
+
}
|
|
57
|
+
export function groupArchive(records) {
|
|
58
|
+
const archive = { version: 1, format: 'vault-memory-groups', observations: [], sessions: [], summaries: [], prompts: [] };
|
|
59
|
+
for (const record of records.slice(0, 4_000))
|
|
60
|
+
archive[groupOf(record.kind)].push(record);
|
|
61
|
+
return archive;
|
|
62
|
+
}
|
|
63
|
+
export function flattenArchive(archive) {
|
|
64
|
+
return GROUPS.flatMap(name => archive[name]).slice(0, 1_000);
|
|
65
|
+
}
|
package/dist/modes.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
export declare const MODE_NAMES: readonly ["babysit", "mem-search", "how-it-works", "make-plan", "do", "smart-explore", "knowledge-agent", "standup", "timeline-report", "weekly-digests", "learn-codebase", "pathfinder", "design-is", "what-the", "version-bump", "oh-my-issues", "cloud-sync", "mode-creator", "ccs-align", "wowerpoint"];
|
|
2
|
+
export declare const MODE_NAMES: readonly ["babysit", "mem-search", "how-it-works", "make-plan", "do", "smart-explore", "knowledge-agent", "standup", "timeline-report", "weekly-digests", "learn-codebase", "pathfinder", "design-is", "what-the", "version-bump", "oh-my-issues", "cloud-sync", "mode-creator", "ccs-align", "wowerpoint", "agent-cost-report"];
|
|
3
3
|
export type VaultModeName = (typeof MODE_NAMES)[number];
|
|
4
4
|
export type VaultModeStatus = 'native' | 'instructional' | 'limited';
|
|
5
5
|
export interface VaultMode {
|
package/dist/modes.js
CHANGED
|
@@ -21,6 +21,7 @@ export const MODE_NAMES = [
|
|
|
21
21
|
'mode-creator',
|
|
22
22
|
'ccs-align',
|
|
23
23
|
'wowerpoint',
|
|
24
|
+
'agent-cost-report',
|
|
24
25
|
];
|
|
25
26
|
const mode = (name, title, summary, status, readOnlyDefault, runtimeRequires, limitations, steps) => ({
|
|
26
27
|
name,
|
|
@@ -50,10 +51,11 @@ export const VAULT_MODES = [
|
|
|
50
51
|
mode('what-the', 'Explain a technical subject plainly', 'Give a grounded who, what, where, why and when explanation without assuming specialist context.', 'native', true, ['The subject or artifact to explain', 'Vault Go retrieval or smart-code tools when evidence is needed'], ['The answer is limited by the supplied material and accessible evidence.', 'This mode does not mutate code or account state.'], ['Gather only the evidence needed to understand the named subject.', 'Explain who owns it, what it does, where it lives, why it exists and when it runs.', 'Use a concrete example and distinguish verified behavior from inference.']),
|
|
51
52
|
mode('version-bump', 'Plan or perform a version bump', 'Audit release scope, update consistent version surfaces and verify a release when authorized.', 'limited', true, ['Local git and package tooling', 'gh or a connected GitHub provider for GitHub releases'], ['This mode does not execute registry publication itself.', 'Tags, releases, pushes and registry publication require explicit authorization in the current task.'], ['Inspect changes since the previous release and determine the semantic version impact.', 'Find version manifests and changelog conventions, then propose or apply consistent updates as requested.', 'Run build and tests; create tags, releases or remote changes only when the request explicitly includes them.']),
|
|
52
53
|
mode('oh-my-issues', 'Cluster an issue backlog', 'Group related issues by root cause and design a small set of architectural fixes.', 'limited', true, ['gh or a connected GitHub provider', 'Read access to the requested issue tracker'], ['Vault Go has no built-in issue tracker client.', 'Comments, issue edits, closures and pull requests require explicit authorization in the current task.'], ['Collect a bounded issue set and normalize symptoms, affected areas and reproduction evidence.', 'Cluster issues by verified shared cause, keeping ambiguous reports separate.', 'Draft plan-master issues and routing actions; write them to GitHub only when requested.']),
|
|
53
|
-
mode('cloud-sync', 'Inspect cloud and sync options', 'Explain Vault account connectivity and inspect available status without pretending to implement another service.', 'limited', true, ['vault_go_status', 'vault_go_cloud_health', 'vault_go_preferences'], ['
|
|
54
|
+
mode('cloud-sync', 'Inspect cloud and sync options', 'Explain Vault account connectivity and inspect available status without pretending to implement another service.', 'limited', true, ['vault_go_status', 'vault_go_cloud_health', 'vault_go_preferences'], ['Vault cloud is the account store. External sync protocols are not part of this runtime.', 'This mode does not sign in, enable sync or change preferences unless the request explicitly asks for that action.'], ['Read account and preference status to establish what this Vault runtime can access.', 'Explain the boundary between local capture and Vault service storage.', 'If the user explicitly requests a supported configuration change, use only the relevant available Vault tool and report its result.']),
|
|
54
55
|
mode('mode-creator', 'Design a custom mode', 'Create and activate a bounded observation taxonomy with inherited prompts and optional Telegram triggers.', 'native', true, ['vault_go_custom_mode_save', 'vault_go_custom_mode_select', 'vault_go_telegram_configure'], ['A custom mode applies to future local context generation; it does not rewrite existing memories.', 'Telegram credentials must be supplied through the private service environment, never prompt or tool arguments.'], ['Learn what should be recorded and skipped, then propose distinct observation types and reusable concept tags.', 'After the user approves the taxonomy, save it with vault_go_custom_mode_save and activate it with vault_go_custom_mode_select.', 'Configure Telegram triggers only when explicitly requested, then use vault_go_telegram_test for the one authorized test message.']),
|
|
55
56
|
mode('ccs-align', 'Run an alignment review', 'Run a Vault-native alignment cycle with an isolated cache, reversible exclusions and cascade-rule reporting.', 'native', true, ['vault_go_ccs_align_health', 'vault_go_ccs_align_cycle', 'vault_go_ccs_align_rules_check'], ['Vault uses cloud UUIDs and its own private cache rather than the upstream numeric worker diary.', 'Grok Bot awareness push is a separate agent-log writer and is not implemented by CCS Align.'], ['Check viewer health, then run vault_go_ccs_align_cycle to retrieve index, timeline and selected observations in order.', 'Use exclude and restore tools to filter only the compiled viewer cache; never delete authoritative cloud memory.', 'Submit bounded house, project and seat rule lines to vault_go_ccs_align_rules_check and review the append-only report.']),
|
|
56
57
|
mode('wowerpoint', 'Outline a narrative slide deck', 'Transform one source document into a structured, audience-aware slide narrative.', 'limited', true, ['One source document', 'A client presentation or document renderer for a final artifact'], ['PPTX or PDF rendering is not implemented by Vault Go.', 'Vault Go can return a slide outline and art direction but cannot claim a generated deck file.'], ['Identify the audience, core claim and evidence in the source document.', 'Create a concise slide sequence with titles, key points, visual direction and speaker intent.', 'Render a presentation only if the client exposes a suitable tool and the user asks for the artifact.']),
|
|
58
|
+
mode('agent-cost-report', 'Report agent cost', 'Estimate transcript token cost for a local directory and keep missing prices unavailable.', 'native', true, ['vault_go_agent_cost_report'], ['Dollars are a public list estimate, not a provider invoice.', 'Grok and other clients without usage fields stay unavailable instead of being shown as zero.'], ['Choose the transcript directory the user asked to measure.', 'Call vault_go_agent_cost_report and keep the ESTIMATED label on every dollar figure.', 'Report token totals, the files scanned, and any unavailable sources without inventing a zero.']),
|
|
57
59
|
];
|
|
58
60
|
const TASK_MAX_CHARS = 4_000;
|
|
59
61
|
const taskSchema = z.string().trim().min(1).max(TASK_MAX_CHARS).optional();
|
|
@@ -3,7 +3,7 @@ type Options = {
|
|
|
3
3
|
fetch?: typeof fetch;
|
|
4
4
|
timeoutMs?: number;
|
|
5
5
|
};
|
|
6
|
-
/** OpenCode 1.x plugin
|
|
6
|
+
/** OpenCode 1.x plugin: inject context and capture prompts, tool use and session end. */
|
|
7
7
|
export declare function createOpenCodePlugin(input: {
|
|
8
8
|
directory: string;
|
|
9
9
|
}, options?: Options): {
|
|
@@ -12,5 +12,33 @@ export declare function createOpenCodePlugin(input: {
|
|
|
12
12
|
}, output: {
|
|
13
13
|
system: string[];
|
|
14
14
|
}) => Promise<void>;
|
|
15
|
+
'chat.message': (_input: {
|
|
16
|
+
sessionID?: string;
|
|
17
|
+
}, output: {
|
|
18
|
+
parts?: Array<{
|
|
19
|
+
type?: string;
|
|
20
|
+
text?: string;
|
|
21
|
+
}>;
|
|
22
|
+
}) => Promise<void>;
|
|
23
|
+
'tool.execute.before': (toolInput: {
|
|
24
|
+
tool?: string;
|
|
25
|
+
sessionID?: string;
|
|
26
|
+
}, output: {
|
|
27
|
+
args?: Record<string, unknown>;
|
|
28
|
+
}) => Promise<void>;
|
|
29
|
+
'tool.execute.after': (toolInput: {
|
|
30
|
+
tool?: string;
|
|
31
|
+
sessionID?: string;
|
|
32
|
+
callID?: string;
|
|
33
|
+
}, output: {
|
|
34
|
+
args?: Record<string, unknown>;
|
|
35
|
+
output?: unknown;
|
|
36
|
+
}) => Promise<void>;
|
|
37
|
+
event: ({ event }: {
|
|
38
|
+
event?: {
|
|
39
|
+
type?: string;
|
|
40
|
+
properties?: Record<string, unknown>;
|
|
41
|
+
};
|
|
42
|
+
}) => Promise<void>;
|
|
15
43
|
};
|
|
16
44
|
export {};
|