@gramatr/mcp 0.10.12 → 0.10.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,12 @@
1
- import { getClaudeModelFromEnv, getGramatrTimeoutFromEnv, isGramatrEnrichEnabledFromEnv, } from '../config-runtime.js';
2
- import { deriveProjectId, getGitContext, readHookInput, } from './lib/gramatr-hook-utils.js';
3
- import { emitStatus, formatFailureWarning, formatIntelligence, } from './lib/intelligence.js';
4
- import { persistClassificationResult, routePrompt, shouldSkipPromptRouting, } from './lib/routing.js';
5
- import { appendOpHistory, appendTurn, getSessionContext, hydrateSessionContextFromServer, isFilesystemAvailable, setLatestClassification, } from './lib/hook-state.js';
6
- import { resolveHookClientRuntime } from './lib/client-runtime.js';
7
- import { appendPacketDebugLog } from './lib/packet-debug-log.js';
8
- import { HOOK_ROUTE_TIMEOUT_DEFAULT_MS, HOOK_ROUTE_TIMEOUT_CAP_MS, } from './generated/hook-timeouts.js';
9
- import { resolveLocalProjectUuid } from './lib/session.js';
1
+ import { getClaudeModelFromEnv, getGramatrTimeoutFromEnv, isGramatrEnrichEnabledFromEnv, } from "../config-runtime.js";
2
+ import { HOOK_ROUTE_TIMEOUT_CAP_MS, HOOK_ROUTE_TIMEOUT_DEFAULT_MS, } from "./generated/hook-timeouts.js";
3
+ import { resolveHookClientRuntime } from "./lib/client-runtime.js";
4
+ import { deriveProjectId, getGitContext, readHookInput } from "./lib/gramatr-hook-utils.js";
5
+ import { appendOpHistory, appendTurn, getCachedDirective, getSessionContext, hydrateSessionContextFromServer, isFilesystemAvailable, setCachedDirective, setLatestClassification, } from "./lib/hook-state.js";
6
+ import { emitStatus, formatFailureWarning, formatIntelligence, } from "./lib/intelligence.js";
7
+ import { appendPacketDebugLog } from "./lib/packet-debug-log.js";
8
+ import { persistClassificationResult, routePrompt, shouldSkipPromptRouting, } from "./lib/routing.js";
9
+ import { resolveLocalProjectUuid } from "./lib/session.js";
10
10
  let turnCounter = 0;
11
11
  const TIMEOUT_MS = getGramatrTimeoutFromEnv(HOOK_ROUTE_TIMEOUT_DEFAULT_MS);
12
12
  const ENABLED = isGramatrEnrichEnabledFromEnv();
@@ -27,19 +27,19 @@ function persistLastClassification(prompt, sessionId, route, downstreamModel, cl
27
27
  }
28
28
  function mapRoutingFailure(reason, detail) {
29
29
  switch (reason) {
30
- case 'auth':
31
- return { reason: 'auth', detail };
32
- case 'timeout':
33
- return { reason: 'timeout', detail };
34
- case 'network_error':
35
- return { reason: 'server_down', detail };
36
- case 'http_error':
37
- case 'mcp_error':
38
- return { reason: 'server_error', detail };
39
- case 'parse_error':
40
- return { reason: 'parse_error', detail };
30
+ case "auth":
31
+ return { reason: "auth", detail };
32
+ case "timeout":
33
+ return { reason: "timeout", detail };
34
+ case "network_error":
35
+ return { reason: "server_down", detail };
36
+ case "http_error":
37
+ case "mcp_error":
38
+ return { reason: "server_error", detail };
39
+ case "parse_error":
40
+ return { reason: "parse_error", detail };
41
41
  default:
42
- return { reason: 'unknown', detail };
42
+ return { reason: "unknown", detail };
43
43
  }
44
44
  }
45
45
  export async function runUserPromptSubmitHook(_args = []) {
@@ -50,17 +50,15 @@ export async function runUserPromptSubmitHook(_args = []) {
50
50
  }
51
51
  try {
52
52
  const input = await readHookInput();
53
- const prompt = input.prompt || '';
54
- const sessionId = input.session_id || 'unknown';
53
+ const prompt = input.prompt || "";
54
+ const sessionId = input.session_id || "unknown";
55
55
  if (!prompt || shouldSkipPromptRouting(prompt)) {
56
56
  if (prompt)
57
- process.stderr.write('[gramatr] enricher: trivial prompt, skipped\n');
57
+ process.stderr.write("[gramatr] enricher: trivial prompt, skipped\n");
58
58
  process.stdout.write(JSON.stringify({}));
59
59
  return 0;
60
60
  }
61
- const downstreamModel = getClaudeModelFromEnv() ||
62
- (input.model ?? '') ||
63
- '';
61
+ const downstreamModel = getClaudeModelFromEnv() || (input.model ?? "") || "";
64
62
  const git = getGitContext();
65
63
  // In filesystem-locked sandboxes, SQLite can't bridge separate hook processes.
66
64
  // Fetch session context from the server so we have project_id + interaction_id.
@@ -75,15 +73,15 @@ export async function runUserPromptSubmitHook(_args = []) {
75
73
  const localUuid = git
76
74
  ? resolveLocalProjectUuid({ directory: git.root, projectName: git.projectName })
77
75
  : null;
78
- const projectId = localUuid
79
- || sessionContext?.project_id
80
- || (git ? deriveProjectId(git.remote, git.projectName) : null)
81
- || undefined;
76
+ const projectId = localUuid ||
77
+ sessionContext?.project_id ||
78
+ (git ? deriveProjectId(git.remote, git.projectName) : null) ||
79
+ undefined;
82
80
  // gramatr interaction_id is the cross-agent session key — use it for
83
81
  // both session_id (server history) and interaction_id (explicit resolution).
84
82
  const gramatrInteractionId = sessionContext?.interaction_id || null;
85
83
  const gramatrSessionId = gramatrInteractionId || sessionId;
86
- process.stderr.write('[gramatr] classifying...\n');
84
+ process.stderr.write("[gramatr] classifying...\n");
87
85
  const t0 = Date.now();
88
86
  const routed = await routePrompt({
89
87
  prompt,
@@ -107,8 +105,12 @@ export async function runUserPromptSubmitHook(_args = []) {
107
105
  agent_name: runtime.agentName,
108
106
  downstream_model: downstreamModel,
109
107
  status: !result && routed.error
110
- ? (routed.error.reason === 'timeout' ? 'timeout' : 'error')
111
- : result ? 'ok' : 'skipped',
108
+ ? routed.error.reason === "timeout"
109
+ ? "timeout"
110
+ : "error"
111
+ : result
112
+ ? "ok"
113
+ : "skipped",
112
114
  elapsed_ms: elapsed,
113
115
  packet: result ?? null,
114
116
  error: routed.error ? { reason: routed.error.reason, detail: routed.error.detail } : null,
@@ -146,7 +148,7 @@ export async function runUserPromptSubmitHook(_args = []) {
146
148
  if (tokensSaved > 0) {
147
149
  appendOpHistory({
148
150
  session_id: gramatrSessionId,
149
- tool: 'classification',
151
+ tool: "classification",
150
152
  time_ms: es.classifier_time_ms || 0,
151
153
  tokens_saved: tokensSaved,
152
154
  timestamp: Date.now(),
@@ -160,8 +162,12 @@ export async function runUserPromptSubmitHook(_args = []) {
160
162
  try {
161
163
  const cl = result?.classification || {};
162
164
  const _es = result?.execution_summary || {};
165
+ const hookInput = input;
163
166
  appendTurn({
164
167
  session_id: gramatrSessionId,
168
+ client_session_id: hookInput.session_id ?? null,
169
+ project_id: sessionContext?.project_id ?? (projectId || null),
170
+ agent_name: runtime.agentName || null,
165
171
  turn_number: turnCounter++,
166
172
  timestamp: new Date().toISOString(),
167
173
  prompt: prompt.substring(0, 500),
@@ -174,12 +180,64 @@ export async function runUserPromptSubmitHook(_args = []) {
174
180
  catch {
175
181
  // Non-critical
176
182
  }
183
+ // #1214: cache directives + phase_template + project context from the v2
184
+ // packet so a later degraded-mode response can still respect hard gates
185
+ // and phase sequencing when the server is unreachable.
186
+ try {
187
+ if (result) {
188
+ const userId = sessionContext?.entity_id || "default";
189
+ const behavioralRules = result.behavioral_rules;
190
+ const behavioralDirectives = result.behavioral_directives;
191
+ if (behavioralRules || behavioralDirectives) {
192
+ setCachedDirective("directives", userId, {
193
+ behavioral_rules: behavioralRules ?? null,
194
+ behavioral_directives: behavioralDirectives ?? null,
195
+ });
196
+ }
197
+ const phaseTemplate = result.phase_template ?? (result.packet_1 && result.packet_1.phase_template) ?? null;
198
+ if (phaseTemplate) {
199
+ setCachedDirective("phase_template", userId, phaseTemplate);
200
+ }
201
+ const manifestProjectId = result.manifest?.project_id ?? projectId ?? null;
202
+ if (manifestProjectId) {
203
+ setCachedDirective("project_context", userId, {
204
+ project_id: manifestProjectId,
205
+ interaction_id: result.manifest?.interaction_id ?? gramatrInteractionId ?? null,
206
+ session_id: result.manifest?.session_id ?? gramatrSessionId,
207
+ });
208
+ }
209
+ }
210
+ }
211
+ catch {
212
+ // Non-critical — cache is best-effort.
213
+ }
177
214
  if (!result || !result.classification) {
178
215
  if (lastFailure) {
216
+ // #1214: degraded mode — use cached directives + phase template so the
217
+ // model still sees hard gates and the phase sequence when the server
218
+ // call errors or times out.
219
+ let degradedNotes = "";
220
+ try {
221
+ const userId = sessionContext?.entity_id || "default";
222
+ const cachedDirectives = getCachedDirective("directives", userId);
223
+ const cachedPhases = getCachedDirective("phase_template", userId);
224
+ if (cachedDirectives || cachedPhases) {
225
+ const degradedPacket = {
226
+ schema: "gmtr.intelligence.contract.v2.degraded",
227
+ note: "Server unavailable — directives loaded from local cache.",
228
+ ...(cachedDirectives ? { cached_directives: cachedDirectives } : {}),
229
+ ...(cachedPhases ? { cached_phase_template: cachedPhases } : {}),
230
+ };
231
+ degradedNotes = `\n\n${JSON.stringify(degradedPacket)}`;
232
+ }
233
+ }
234
+ catch {
235
+ // Ignore cache read errors — degraded-mode fallback is best effort.
236
+ }
179
237
  process.stdout.write(JSON.stringify({
180
238
  hookSpecificOutput: {
181
- hookEventName: 'UserPromptSubmit',
182
- additionalContext: formatFailureWarning(lastFailure),
239
+ hookEventName: "UserPromptSubmit",
240
+ additionalContext: formatFailureWarning(lastFailure) + degradedNotes,
183
241
  },
184
242
  }));
185
243
  }
@@ -190,7 +248,7 @@ export async function runUserPromptSubmitHook(_args = []) {
190
248
  }
191
249
  process.stdout.write(JSON.stringify({
192
250
  hookSpecificOutput: {
193
- hookEventName: 'UserPromptSubmit',
251
+ hookEventName: "UserPromptSubmit",
194
252
  additionalContext: formatIntelligence(result, null),
195
253
  },
196
254
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"user-prompt-submit.js","sourceRoot":"","sources":["../../src/hooks/user-prompt-submit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"user-prompt-submit.js","sourceRoot":"","sources":["../../src/hooks/user-prompt-submit.ts"],"names":[],"mappings":"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"}
@@ -1,23 +1,21 @@
1
1
  /**
2
2
  * hooks-listener.ts — Local HTTP IPC server for hook subprocesses.
3
3
  *
4
- * Phase IV: The local MCP proxy server opens a lightweight HTTP listener on a
5
- * random localhost port at startup and writes the port to ~/.gramatr/.hooks-port.
6
- * Hook subprocesses (session-start, user-prompt-submit, session-end) discover
7
- * this port and route calls through the local server instead of calling the
8
- * remote server directly.
4
+ * The local MCP proxy server opens a lightweight HTTP listener on a random
5
+ * localhost port at startup. Callers (statusline, any separate-process tool)
6
+ * discover the port via ~/.gramatr/.hooks-port.
9
7
  *
10
- * Benefits:
11
- * - Auth managed in one place: the local server has the token; hooks never
12
- * need to resolve or refresh it themselves.
13
- * - Single enforcement point for data shapes and schema validation before
14
- * any call reaches the remote API.
15
- * - Cross-hook session context via in-process memory (no SQLite file needed).
16
- * - Faster: localhost vs. internet round-trip for session context reads.
8
+ * Security: every request must present X-Hooks-Secret matching the value in
9
+ * ~/.gramatr/.hooks-secret (written at startup, mode 0o600). This prevents
10
+ * other processes on the same machine from hijacking the channel. The secret
11
+ * is regenerated on each server start.
17
12
  *
18
- * Fallback: if the port file is absent (local server not running), hooks fall
19
- * back to direct remote calls with their own auth resolution.
13
+ * Auth policy: callers never carry a JWT. The local server holds the token
14
+ * and manages all outbound calls to the central server. No fallback to direct
15
+ * remote calls — if the local server is unavailable, callers show offline.
20
16
  */
17
+ /** Return the current IPC secret. Null until startHooksListener() has run. */
18
+ export declare function getHooksSecret(): string | null;
21
19
  /**
22
20
  * Start the hooks IPC listener on a random localhost port.
23
21
  * Writes the port to ~/.gramatr/.hooks-port so hook subprocesses can find it.
@@ -25,8 +23,7 @@
25
23
  */
26
24
  export declare function startHooksListener(): Promise<number>;
27
25
  /**
28
- * Stop the hooks listener and remove the port file.
29
- * Called on server shutdown so stale hooks know to fall back to direct remote.
26
+ * Stop the hooks listener and remove the port + secret files.
30
27
  */
31
28
  export declare function stopHooksListener(): void;
32
29
  //# sourceMappingURL=hooks-listener.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks-listener.d.ts","sourceRoot":"","sources":["../../src/server/hooks-listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA2FH;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CA4B1D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC"}
1
+ {"version":3,"file":"hooks-listener.d.ts","sourceRoot":"","sources":["../../src/server/hooks-listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAkBH,8EAA8E;AAC9E,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAyHD;;;;GAIG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CA8B1D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAMxC"}
@@ -1,36 +1,45 @@
1
1
  /**
2
2
  * hooks-listener.ts — Local HTTP IPC server for hook subprocesses.
3
3
  *
4
- * Phase IV: The local MCP proxy server opens a lightweight HTTP listener on a
5
- * random localhost port at startup and writes the port to ~/.gramatr/.hooks-port.
6
- * Hook subprocesses (session-start, user-prompt-submit, session-end) discover
7
- * this port and route calls through the local server instead of calling the
8
- * remote server directly.
4
+ * The local MCP proxy server opens a lightweight HTTP listener on a random
5
+ * localhost port at startup. Callers (statusline, any separate-process tool)
6
+ * discover the port via ~/.gramatr/.hooks-port.
9
7
  *
10
- * Benefits:
11
- * - Auth managed in one place: the local server has the token; hooks never
12
- * need to resolve or refresh it themselves.
13
- * - Single enforcement point for data shapes and schema validation before
14
- * any call reaches the remote API.
15
- * - Cross-hook session context via in-process memory (no SQLite file needed).
16
- * - Faster: localhost vs. internet round-trip for session context reads.
8
+ * Security: every request must present X-Hooks-Secret matching the value in
9
+ * ~/.gramatr/.hooks-secret (written at startup, mode 0o600). This prevents
10
+ * other processes on the same machine from hijacking the channel. The secret
11
+ * is regenerated on each server start.
17
12
  *
18
- * Fallback: if the port file is absent (local server not running), hooks fall
19
- * back to direct remote calls with their own auth resolution.
13
+ * Auth policy: callers never carry a JWT. The local server holds the token
14
+ * and manages all outbound calls to the central server. No fallback to direct
15
+ * remote calls — if the local server is unavailable, callers show offline.
20
16
  */
21
17
  import { createServer } from 'node:http';
22
18
  import { existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs';
23
19
  import { join } from 'node:path';
20
+ import { randomBytes } from 'node:crypto';
24
21
  import { getGramatrDirFromEnv, getHomeDir } from '../config-runtime.js';
25
22
  import { callRemoteTool } from '../proxy/remote-client.js';
23
+ import { getToken, getServerUrl } from './auth.js';
26
24
  // ── In-memory session context store ──
27
25
  // Keys: session_id (string) + '__latest__' sentinel for the most recent write.
28
26
  // Hooks that don't know the session_id (e.g. a status query) fall back to __latest__.
29
27
  const sessionStore = new Map();
30
- // ── Port file path ──
28
+ // ── Per-server-instance shared secret ──
29
+ let _secret = null;
30
+ /** Return the current IPC secret. Null until startHooksListener() has run. */
31
+ export function getHooksSecret() {
32
+ return _secret;
33
+ }
34
+ // ── Port + secret file paths ──
35
+ function getGramatrDir() {
36
+ return getGramatrDirFromEnv() || join(getHomeDir(), '.gramatr');
37
+ }
31
38
  function getPortFilePath() {
32
- const dir = getGramatrDirFromEnv() || join(getHomeDir(), '.gramatr');
33
- return join(dir, '.hooks-port');
39
+ return join(getGramatrDir(), '.hooks-port');
40
+ }
41
+ function getSecretFilePath() {
42
+ return join(getGramatrDir(), '.hooks-secret');
34
43
  }
35
44
  // ── Request helpers ──
36
45
  async function readBody(req) {
@@ -49,6 +58,12 @@ function json(res, status, body) {
49
58
  async function handleRequest(req, res) {
50
59
  const url = new URL(req.url || '/', 'http://localhost');
51
60
  const method = (req.method || 'GET').toUpperCase();
61
+ // ── Secret check — reject any caller that doesn't know the secret ──
62
+ const presented = req.headers['x-hooks-secret'];
63
+ if (!_secret || presented !== _secret) {
64
+ json(res, 401, { error: 'Unauthorized' });
65
+ return;
66
+ }
52
67
  // ── POST /hooks/tool — proxy a gramatr tool call with server-managed auth ──
53
68
  if (url.pathname === '/hooks/tool' && method === 'POST') {
54
69
  const raw = await readBody(req);
@@ -91,6 +106,33 @@ async function handleRequest(req, res) {
91
106
  }
92
107
  return;
93
108
  }
109
+ // ── POST /hooks/statusline — proxy statusline render with server-managed auth ──
110
+ // The statusline binary calls this instead of hitting the central server directly.
111
+ // Auth token is held by the local server; the caller needs no credentials.
112
+ if (url.pathname === '/hooks/statusline' && method === 'POST') {
113
+ const raw = await readBody(req);
114
+ try {
115
+ const token = getToken();
116
+ if (!token) {
117
+ json(res, 503, { error: 'Local server not authenticated — run npx gramatr login' });
118
+ return;
119
+ }
120
+ const baseUrl = getServerUrl().replace(/\/mcp\/?$/, '');
121
+ const upstream = await fetch(`${baseUrl}/api/v1/statusline/render`, {
122
+ method: 'POST',
123
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
124
+ body: raw,
125
+ signal: AbortSignal.timeout(2000),
126
+ });
127
+ const text = await upstream.text();
128
+ res.writeHead(upstream.status, { 'Content-Type': 'application/json' });
129
+ res.end(text);
130
+ }
131
+ catch (err) {
132
+ json(res, 502, { error: err instanceof Error ? err.message : String(err) });
133
+ }
134
+ return;
135
+ }
94
136
  json(res, 404, { error: 'Not found' });
95
137
  }
96
138
  // ── Lifecycle ──
@@ -101,13 +143,18 @@ let _server = null;
101
143
  * Returns the assigned port number.
102
144
  */
103
145
  export async function startHooksListener() {
104
- // Ensure the directory exists for the port file
105
- const dir = getGramatrDirFromEnv() || join(getHomeDir(), '.gramatr');
146
+ const dir = getGramatrDir();
106
147
  try {
107
148
  if (!existsSync(dir))
108
149
  mkdirSync(dir, { recursive: true });
109
150
  }
110
- catch { /* non-critical — port file write will fail gracefully below */ }
151
+ catch { /* non-critical */ }
152
+ // Generate a fresh per-run secret and persist it so callers can read it.
153
+ _secret = randomBytes(32).toString('hex');
154
+ try {
155
+ writeFileSync(getSecretFilePath(), _secret, { mode: 0o600 });
156
+ }
157
+ catch { /* non-critical — callers will get 401 if they can't read the secret */ }
111
158
  return new Promise((resolve, reject) => {
112
159
  _server = createServer((req, res) => {
113
160
  handleRequest(req, res).catch((err) => {
@@ -118,27 +165,28 @@ export async function startHooksListener() {
118
165
  const addr = _server.address();
119
166
  const port = typeof addr === 'object' && addr !== null ? addr.port : 0;
120
167
  try {
121
- // mode 0o600: readable only by the current user
122
168
  writeFileSync(getPortFilePath(), String(port), { mode: 0o600 });
123
169
  }
124
- catch {
125
- // Non-critical — hooks will fall back to SQLite + direct remote
126
- }
170
+ catch { /* non-critical */ }
127
171
  resolve(port);
128
172
  });
129
173
  _server.once('error', reject);
130
174
  });
131
175
  }
132
176
  /**
133
- * Stop the hooks listener and remove the port file.
134
- * Called on server shutdown so stale hooks know to fall back to direct remote.
177
+ * Stop the hooks listener and remove the port + secret files.
135
178
  */
136
179
  export function stopHooksListener() {
137
180
  _server?.close();
138
181
  _server = null;
182
+ _secret = null;
139
183
  try {
140
184
  unlinkSync(getPortFilePath());
141
185
  }
142
- catch { /* best-effort cleanup */ }
186
+ catch { /* best-effort */ }
187
+ try {
188
+ unlinkSync(getSecretFilePath());
189
+ }
190
+ catch { /* best-effort */ }
143
191
  }
144
192
  //# sourceMappingURL=hooks-listener.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks-listener.js","sourceRoot":"","sources":["../../src/server/hooks-listener.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks-listener.js","sourceRoot":"","sources":["../../src/server/hooks-listener.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@ import type { ToolDefinition } from '../proxy/tool-registry.js';
9
9
  */
10
10
  export declare function getLocalToolDefinitions(): ToolDefinition[];
11
11
  /**
12
- * Check if a tool name is a local-only tool.
12
+ * Check if a tool name is handled locally (fully or local-first).
13
13
  */
14
14
  export declare function isLocalTool(name: string): boolean;
15
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"local-tools.d.ts","sourceRoot":"","sources":["../../src/tools/local-tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,cAAc,EAAE,CAgC1D;AAID;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,cAAc,CAAC,CAqBzB"}
1
+ {"version":3,"file":"local-tools.d.ts","sourceRoot":"","sources":["../../src/tools/local-tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAShE;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,cAAc,EAAE,CA+C1D;AAYD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,cAAc,CAAC,CAuBzB"}
@@ -10,6 +10,8 @@ import { queueSize } from '../queue/offline-queue.js';
10
10
  import { getWebToolDefinitions, isWebTool, handleWebTool } from './web-tools.js';
11
11
  import { getMetrics, resetMetrics } from '../metrics/collector.js';
12
12
  import { VERSION } from '../hooks/lib/version.js';
13
+ import { getLocalProjectBySlug, getLocalProjectByDirectory, listLocalProjects, } from '../hooks/lib/hook-state.js';
14
+ import { callRemoteTool } from '../proxy/remote-client.js';
13
15
  /**
14
16
  * Local tool definitions — these get merged into tools/list alongside remote tools.
15
17
  */
@@ -43,15 +45,37 @@ export function getLocalToolDefinitions() {
43
45
  },
44
46
  annotations: { readOnlyHint: true },
45
47
  },
48
+ {
49
+ name: 'gramatr_resolve_project',
50
+ description: 'Resolve or list projects. Reads from local SQLite cache first; falls back to server for misses or search. Actions: list (recent projects), resolve (by slug or directory), search (text search — always remote).',
51
+ inputSchema: {
52
+ type: 'object',
53
+ properties: {
54
+ action: { type: 'string', enum: ['list', 'resolve', 'search'], description: 'list | resolve | search' },
55
+ slug: { type: 'string', description: 'Project slug for resolve action.' },
56
+ directory: { type: 'string', description: 'Absolute directory path for resolve action.' },
57
+ query: { type: 'string', description: 'Search string for search action.' },
58
+ limit: { type: 'number', description: 'Max results for list (default 20).' },
59
+ },
60
+ required: ['action'],
61
+ },
62
+ },
46
63
  ...getWebToolDefinitions(),
47
64
  ];
48
65
  }
49
66
  const startTime = Date.now();
67
+ const LOCAL_TOOL_NAMES = new Set([
68
+ 'gramatr_local_status',
69
+ 'gramatr_local_clear_cache',
70
+ 'gramatr_local_config',
71
+ 'gramatr_local_metrics',
72
+ 'gramatr_resolve_project',
73
+ ]);
50
74
  /**
51
- * Check if a tool name is a local-only tool.
75
+ * Check if a tool name is handled locally (fully or local-first).
52
76
  */
53
77
  export function isLocalTool(name) {
54
- return name.startsWith('gramatr_local_');
78
+ return name.startsWith('gramatr_local_') || LOCAL_TOOL_NAMES.has(name);
55
79
  }
56
80
  /**
57
81
  * Handle a local tool call.
@@ -70,6 +94,8 @@ export async function handleLocalTool(toolName, args) {
70
94
  return handleConfig();
71
95
  case 'gramatr_local_metrics':
72
96
  return handleMetrics(args);
97
+ case 'gramatr_resolve_project':
98
+ return handleResolveProject(args);
73
99
  default:
74
100
  return {
75
101
  content: [{ type: 'text', text: JSON.stringify({ error: `Unknown local tool: ${toolName}` }) }],
@@ -159,4 +185,45 @@ function handleMetrics(args) {
159
185
  content: [{ type: 'text', text: JSON.stringify(snapshot, null, 2) }],
160
186
  };
161
187
  }
188
+ async function handleResolveProject(args) {
189
+ const action = args.action;
190
+ // list — return all local projects, sorted by updated_at desc
191
+ if (action === 'list') {
192
+ const limit = typeof args.limit === 'number' ? args.limit : 20;
193
+ try {
194
+ const rows = listLocalProjects(limit);
195
+ return {
196
+ content: [{ type: 'text', text: JSON.stringify({ action: 'list', projects: rows, source: 'local', total: rows.length }, null, 2) }],
197
+ };
198
+ }
199
+ catch {
200
+ // DB unavailable — fall through to remote
201
+ }
202
+ }
203
+ // resolve — try local first (slug, then directory), then remote on miss
204
+ if (action === 'resolve') {
205
+ const slug = typeof args.slug === 'string' ? args.slug : null;
206
+ const directory = typeof args.directory === 'string' ? args.directory : null;
207
+ let local = slug ? getLocalProjectBySlug(slug) : null;
208
+ if (!local && directory)
209
+ local = getLocalProjectByDirectory(directory);
210
+ if (local) {
211
+ return {
212
+ content: [{ type: 'text', text: JSON.stringify({ action: 'resolve', project: local, source: 'local' }, null, 2) }],
213
+ };
214
+ }
215
+ // Miss — fall through to remote below
216
+ }
217
+ // search always goes remote; resolve on local miss falls through here
218
+ try {
219
+ const result = await callRemoteTool('gramatr_resolve_project', args);
220
+ return result;
221
+ }
222
+ catch (err) {
223
+ return {
224
+ content: [{ type: 'text', text: JSON.stringify({ error: err instanceof Error ? err.message : String(err) }) }],
225
+ isError: true,
226
+ };
227
+ }
228
+ }
162
229
  //# sourceMappingURL=local-tools.js.map