@kawacode/mcp 5.0.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/CLAUDE.md.example +80 -0
- package/LICENSE +35 -0
- package/README.md +322 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +231 -0
- package/build/index.js.map +1 -0
- package/build/prompts/intent-first-workflow.d.ts +24 -0
- package/build/prompts/intent-first-workflow.js +204 -0
- package/build/prompts/intent-first-workflow.js.map +1 -0
- package/build/resources/active-intent.d.ts +9 -0
- package/build/resources/active-intent.js +52 -0
- package/build/resources/active-intent.js.map +1 -0
- package/build/services/active-intent-store.d.ts +36 -0
- package/build/services/active-intent-store.js +45 -0
- package/build/services/active-intent-store.js.map +1 -0
- package/build/services/kawa-api.d.ts +131 -0
- package/build/services/kawa-api.js +239 -0
- package/build/services/kawa-api.js.map +1 -0
- package/build/services/muninn-ipc.d.ts +45 -0
- package/build/services/muninn-ipc.js +275 -0
- package/build/services/muninn-ipc.js.map +1 -0
- package/build/services/repo-encryption.d.ts +46 -0
- package/build/services/repo-encryption.js +92 -0
- package/build/services/repo-encryption.js.map +1 -0
- package/build/services/storage-decryption.d.ts +52 -0
- package/build/services/storage-decryption.js +162 -0
- package/build/services/storage-decryption.js.map +1 -0
- package/build/tools/assign-blocks.d.ts +87 -0
- package/build/tools/assign-blocks.js +49 -0
- package/build/tools/assign-blocks.js.map +1 -0
- package/build/tools/check-active-intent.d.ts +50 -0
- package/build/tools/check-active-intent.js +48 -0
- package/build/tools/check-active-intent.js.map +1 -0
- package/build/tools/complete-intent.d.ts +48 -0
- package/build/tools/complete-intent.js +53 -0
- package/build/tools/complete-intent.js.map +1 -0
- package/build/tools/create-intent.d.ts +58 -0
- package/build/tools/create-intent.js +49 -0
- package/build/tools/create-intent.js.map +1 -0
- package/build/tools/detect-intent-conflicts.d.ts +361 -0
- package/build/tools/detect-intent-conflicts.js +91 -0
- package/build/tools/detect-intent-conflicts.js.map +1 -0
- package/build/tools/edit-session-decision.d.ts +201 -0
- package/build/tools/edit-session-decision.js +50 -0
- package/build/tools/edit-session-decision.js.map +1 -0
- package/build/tools/evolve-decisions.d.ts +50 -0
- package/build/tools/evolve-decisions.js +45 -0
- package/build/tools/evolve-decisions.js.map +1 -0
- package/build/tools/get-intent-changes.d.ts +49 -0
- package/build/tools/get-intent-changes.js +58 -0
- package/build/tools/get-intent-changes.js.map +1 -0
- package/build/tools/get-intents-for-file.d.ts +57 -0
- package/build/tools/get-intents-for-file.js +57 -0
- package/build/tools/get-intents-for-file.js.map +1 -0
- package/build/tools/get-intents-for-lines.d.ts +71 -0
- package/build/tools/get-intents-for-lines.js +64 -0
- package/build/tools/get-intents-for-lines.js.map +1 -0
- package/build/tools/get-project-context.d.ts +82 -0
- package/build/tools/get-project-context.js +73 -0
- package/build/tools/get-project-context.js.map +1 -0
- package/build/tools/get-project-decisions.d.ts +51 -0
- package/build/tools/get-project-decisions.js +56 -0
- package/build/tools/get-project-decisions.js.map +1 -0
- package/build/tools/get-relevant-context.d.ts +89 -0
- package/build/tools/get-relevant-context.js +104 -0
- package/build/tools/get-relevant-context.js.map +1 -0
- package/build/tools/get-session-decisions.d.ts +57 -0
- package/build/tools/get-session-decisions.js +48 -0
- package/build/tools/get-session-decisions.js.map +1 -0
- package/build/tools/index.d.ts +656 -0
- package/build/tools/index.js +57 -0
- package/build/tools/index.js.map +1 -0
- package/build/tools/infer-history.d.ts +85 -0
- package/build/tools/infer-history.js +69 -0
- package/build/tools/infer-history.js.map +1 -0
- package/build/tools/list-team-intents.d.ts +51 -0
- package/build/tools/list-team-intents.js +57 -0
- package/build/tools/list-team-intents.js.map +1 -0
- package/build/tools/log-work.d.ts +45 -0
- package/build/tools/log-work.js +30 -0
- package/build/tools/log-work.js.map +1 -0
- package/build/tools/record-decision.d.ts +132 -0
- package/build/tools/record-decision.js +66 -0
- package/build/tools/record-decision.js.map +1 -0
- package/build/tools/resolve-origin.d.ts +13 -0
- package/build/tools/resolve-origin.js +33 -0
- package/build/tools/resolve-origin.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the Kawa API.
|
|
3
|
+
*
|
|
4
|
+
* Replaces Muninn IPC — all data operations go directly to the REST API.
|
|
5
|
+
* Uses Node 18+ built-in fetch (no new dependencies).
|
|
6
|
+
*
|
|
7
|
+
* Config:
|
|
8
|
+
* KAWA_API_URL — defaults to https://api.codeawareness.com (set to http://localhost:3008 for local dev)
|
|
9
|
+
* KAWA_AUTH_TOKEN — JWT bearer token (optional - auto-loaded from storage if not set)
|
|
10
|
+
*
|
|
11
|
+
* Auth token resolution order:
|
|
12
|
+
* 1. KAWA_AUTH_TOKEN environment variable
|
|
13
|
+
* 2. ~/.kawa-code/.storage.caw (decrypted using username+hostname)
|
|
14
|
+
*/
|
|
15
|
+
import { getAuthTokenFromStorage } from './storage-decryption.js';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// API Client
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export class KawaApi {
|
|
20
|
+
baseUrl;
|
|
21
|
+
authToken;
|
|
22
|
+
constructor(baseUrl, authToken) {
|
|
23
|
+
this.baseUrl = (baseUrl || process.env.KAWA_API_URL || 'https://api.codeawareness.com').replace(/\/$/, '');
|
|
24
|
+
// Auth token resolution order:
|
|
25
|
+
// 1. Explicit parameter
|
|
26
|
+
// 2. Environment variable
|
|
27
|
+
// 3. Storage file (auto-decrypted)
|
|
28
|
+
this.authToken = authToken || process.env.KAWA_AUTH_TOKEN || '';
|
|
29
|
+
if (!this.authToken) {
|
|
30
|
+
// Try to load from Muninn storage
|
|
31
|
+
const tokenFromStorage = getAuthTokenFromStorage();
|
|
32
|
+
if (tokenFromStorage) {
|
|
33
|
+
this.authToken = tokenFromStorage;
|
|
34
|
+
console.error('Loaded auth token from Muninn storage (~/.kawa-code/.storage.caw)');
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
console.error('Warning: No auth token available. Tried:');
|
|
38
|
+
console.error(' 1. KAWA_AUTH_TOKEN environment variable (not set)');
|
|
39
|
+
console.error(' 2. ~/.kawa-code/.storage.caw (not found or not decryptable)');
|
|
40
|
+
console.error(' → API calls will fail until you log in to Muninn');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// --------------------------------------------------------------------------
|
|
45
|
+
// Auth Token Management
|
|
46
|
+
// --------------------------------------------------------------------------
|
|
47
|
+
/**
|
|
48
|
+
* Refresh the auth token from storage
|
|
49
|
+
*
|
|
50
|
+
* Call this periodically to pick up token refreshes from Muninn.
|
|
51
|
+
* Returns true if a new token was loaded.
|
|
52
|
+
*/
|
|
53
|
+
refreshTokenFromStorage() {
|
|
54
|
+
const tokenFromStorage = getAuthTokenFromStorage();
|
|
55
|
+
if (tokenFromStorage && tokenFromStorage !== this.authToken) {
|
|
56
|
+
this.authToken = tokenFromStorage;
|
|
57
|
+
console.error('Refreshed auth token from Muninn storage');
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Check if the client has an auth token
|
|
64
|
+
*/
|
|
65
|
+
hasAuthToken() {
|
|
66
|
+
return this.authToken.length > 0;
|
|
67
|
+
}
|
|
68
|
+
// --------------------------------------------------------------------------
|
|
69
|
+
// Intents
|
|
70
|
+
// --------------------------------------------------------------------------
|
|
71
|
+
async listIntents(origin, lang = 'en', since) {
|
|
72
|
+
const params = { origin, lang };
|
|
73
|
+
if (since)
|
|
74
|
+
params.since = since;
|
|
75
|
+
const data = await this.get('/v1/intents', params);
|
|
76
|
+
return data.intents || [];
|
|
77
|
+
}
|
|
78
|
+
async createIntent(params) {
|
|
79
|
+
const body = {
|
|
80
|
+
origin: params.origin,
|
|
81
|
+
lang: params.lang || 'en',
|
|
82
|
+
title: params.title,
|
|
83
|
+
description: params.description,
|
|
84
|
+
templateType: params.templateType || 'feature',
|
|
85
|
+
constraints: params.constraints || [],
|
|
86
|
+
scope: params.scope || { type: 'repo', paths: [] },
|
|
87
|
+
blocks: params.blocks || [],
|
|
88
|
+
branch: params.branch,
|
|
89
|
+
forkedFrom: params.forkedFrom,
|
|
90
|
+
};
|
|
91
|
+
const data = await this.post('/v1/intents', body);
|
|
92
|
+
return {
|
|
93
|
+
intent: data.intent || data,
|
|
94
|
+
cloudId: data.intent?._id || data._id || ''
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
async getIntent(intentId, origin, lang = 'en') {
|
|
98
|
+
const data = await this.get(`/v1/intents/${intentId}`, { origin, lang });
|
|
99
|
+
return data.intent || data;
|
|
100
|
+
}
|
|
101
|
+
async updateIntent(intentId, origin, updates) {
|
|
102
|
+
const body = { origin, ...updates };
|
|
103
|
+
const data = await this.patch(`/v1/intents/${intentId}`, body);
|
|
104
|
+
return data.intent || data;
|
|
105
|
+
}
|
|
106
|
+
async deleteIntent(intentId, origin) {
|
|
107
|
+
await this.del(`/v1/intents/${intentId}`, { origin });
|
|
108
|
+
}
|
|
109
|
+
async getIntentsByFile(origin, filePath) {
|
|
110
|
+
const data = await this.get('/v1/intents/by-file', { origin, path: filePath });
|
|
111
|
+
return data.intents || [];
|
|
112
|
+
}
|
|
113
|
+
async getIntentsByLines(origin, filePath, startLine, endLine) {
|
|
114
|
+
const data = await this.get('/v1/intents/by-lines', {
|
|
115
|
+
origin,
|
|
116
|
+
path: filePath,
|
|
117
|
+
startLine: String(startLine),
|
|
118
|
+
endLine: String(endLine)
|
|
119
|
+
});
|
|
120
|
+
return data.intents || [];
|
|
121
|
+
}
|
|
122
|
+
async batchSaveIntents(origin, lang, intents) {
|
|
123
|
+
return this.post('/v1/intents/batch', { origin, lang, intents });
|
|
124
|
+
}
|
|
125
|
+
// Translations
|
|
126
|
+
async saveIntentTranslation(intentId, origin, lang, title, description) {
|
|
127
|
+
return this.post(`/v1/intents/${intentId}/translations`, {
|
|
128
|
+
origin, lang, title, description
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
async getIntentTranslation(intentId, origin, lang) {
|
|
132
|
+
try {
|
|
133
|
+
return await this.get(`/v1/intents/${intentId}/translations/${lang}`, { origin });
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// --------------------------------------------------------------------------
|
|
140
|
+
// Decisions
|
|
141
|
+
// --------------------------------------------------------------------------
|
|
142
|
+
async getTeamDecisions(origin, since) {
|
|
143
|
+
const params = { origin };
|
|
144
|
+
if (since)
|
|
145
|
+
params.since = since;
|
|
146
|
+
const data = await this.get('/v1/decisions/team', params);
|
|
147
|
+
return data.decisions || [];
|
|
148
|
+
}
|
|
149
|
+
async getIntentDecisions(intentId, origin) {
|
|
150
|
+
const data = await this.get(`/v1/decisions/intent/${intentId}`, { origin });
|
|
151
|
+
return data.decisions || [];
|
|
152
|
+
}
|
|
153
|
+
async syncDecisions(origin, intentId, decisions) {
|
|
154
|
+
return this.post('/v1/decisions/sync', { origin, intentId, decisions });
|
|
155
|
+
}
|
|
156
|
+
async deleteDecision(decisionId, origin) {
|
|
157
|
+
await this.del(`/v1/decisions/${decisionId}`, { origin });
|
|
158
|
+
}
|
|
159
|
+
// --------------------------------------------------------------------------
|
|
160
|
+
// Search
|
|
161
|
+
// --------------------------------------------------------------------------
|
|
162
|
+
async searchRelevantContext(origin, query, activeFiles, options) {
|
|
163
|
+
return this.post('/v1/search', { origin, query, activeFiles, ...options });
|
|
164
|
+
}
|
|
165
|
+
// --------------------------------------------------------------------------
|
|
166
|
+
// HTTP helpers
|
|
167
|
+
// --------------------------------------------------------------------------
|
|
168
|
+
async get(path, params) {
|
|
169
|
+
const url = new URL(this.baseUrl + path);
|
|
170
|
+
if (params) {
|
|
171
|
+
for (const [k, v] of Object.entries(params)) {
|
|
172
|
+
if (v !== undefined)
|
|
173
|
+
url.searchParams.set(k, v);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return this.request(url.toString(), { method: 'GET' });
|
|
177
|
+
}
|
|
178
|
+
async post(path, body) {
|
|
179
|
+
return this.request(this.baseUrl + path, {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
headers: { 'Content-Type': 'application/json' },
|
|
182
|
+
body: JSON.stringify(body)
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
async patch(path, body) {
|
|
186
|
+
return this.request(this.baseUrl + path, {
|
|
187
|
+
method: 'PATCH',
|
|
188
|
+
headers: { 'Content-Type': 'application/json' },
|
|
189
|
+
body: JSON.stringify(body)
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
async del(path, params) {
|
|
193
|
+
const url = new URL(this.baseUrl + path);
|
|
194
|
+
if (params) {
|
|
195
|
+
for (const [k, v] of Object.entries(params)) {
|
|
196
|
+
if (v !== undefined)
|
|
197
|
+
url.searchParams.set(k, v);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return this.request(url.toString(), { method: 'DELETE' });
|
|
201
|
+
}
|
|
202
|
+
getBaseUrl() {
|
|
203
|
+
return this.baseUrl;
|
|
204
|
+
}
|
|
205
|
+
async request(url, init) {
|
|
206
|
+
const headers = {
|
|
207
|
+
...(init.headers || {}),
|
|
208
|
+
'Authorization': `Bearer ${this.authToken}`
|
|
209
|
+
};
|
|
210
|
+
let response;
|
|
211
|
+
try {
|
|
212
|
+
response = await fetch(url, { ...init, headers });
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
216
|
+
throw new Error(`Cannot reach Kawa API at ${this.baseUrl} — ${init.method} ${url}: ${cause}`);
|
|
217
|
+
}
|
|
218
|
+
if (!response.ok) {
|
|
219
|
+
const text = await response.text().catch(() => '');
|
|
220
|
+
throw new Error(`API ${init.method} ${url} failed (${response.status}): ${text}`);
|
|
221
|
+
}
|
|
222
|
+
const contentType = response.headers.get('content-type') || '';
|
|
223
|
+
if (contentType.includes('application/json')) {
|
|
224
|
+
return response.json();
|
|
225
|
+
}
|
|
226
|
+
return {};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// ============================================================================
|
|
230
|
+
// Singleton
|
|
231
|
+
// ============================================================================
|
|
232
|
+
let instance = null;
|
|
233
|
+
export function getApi() {
|
|
234
|
+
if (!instance) {
|
|
235
|
+
instance = new KawaApi();
|
|
236
|
+
}
|
|
237
|
+
return instance;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=kawa-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kawa-api.js","sourceRoot":"","sources":["../../src/services/kawa-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Muninn IPC Client for MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Connects to Muninn's Huginn IPC socket as an extension client,
|
|
5
|
+
* translating MCP tool calls into domain:action IPC messages.
|
|
6
|
+
*
|
|
7
|
+
* Modeled after kawa.i18n/src/ipc/muninn-socket.ts but simplified:
|
|
8
|
+
* - No UI bundle or manifest (MCP has no UI)
|
|
9
|
+
* - Request/response correlation via _msgId
|
|
10
|
+
* - 30s timeout per request
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Connect to Muninn's Huginn IPC socket.
|
|
14
|
+
*
|
|
15
|
+
* Sends extension handshake and waits for acknowledgment.
|
|
16
|
+
* Throws if Muninn is not running or handshake fails.
|
|
17
|
+
*/
|
|
18
|
+
export declare function connectToMuninn(socketPath?: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Send an IPC request to Muninn and await the correlated response.
|
|
21
|
+
*
|
|
22
|
+
* @param domain - Handler domain (e.g., 'intent', 'decision')
|
|
23
|
+
* @param action - Handler action (e.g., 'create', 'get-active')
|
|
24
|
+
* @param data - Request payload
|
|
25
|
+
* @returns The response data from Muninn
|
|
26
|
+
*/
|
|
27
|
+
export declare function request(domain: string, action: string, data?: any): Promise<any>;
|
|
28
|
+
/**
|
|
29
|
+
* Ensure a repository path is registered with Muninn as a project.
|
|
30
|
+
*
|
|
31
|
+
* Sends `code:add` with the folder path so Muninn activates the project,
|
|
32
|
+
* sets up git state, and pulls intents/decisions/lessons from the API.
|
|
33
|
+
* Always sends the request — Muninn's AddHandler is idempotent and
|
|
34
|
+
* returns the existing project if already added.
|
|
35
|
+
* Errors are logged but not thrown — repo registration is best-effort.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ensureRepo(repoPath: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Check if connected to Muninn.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isConnected(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Disconnect from Muninn.
|
|
44
|
+
*/
|
|
45
|
+
export declare function disconnect(): void;
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Muninn IPC Client for MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Connects to Muninn's Huginn IPC socket as an extension client,
|
|
5
|
+
* translating MCP tool calls into domain:action IPC messages.
|
|
6
|
+
*
|
|
7
|
+
* Modeled after kawa.i18n/src/ipc/muninn-socket.ts but simplified:
|
|
8
|
+
* - No UI bundle or manifest (MCP has no UI)
|
|
9
|
+
* - Request/response correlation via _msgId
|
|
10
|
+
* - 30s timeout per request
|
|
11
|
+
*/
|
|
12
|
+
import * as net from 'net';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import * as os from 'os';
|
|
16
|
+
import * as crypto from 'crypto';
|
|
17
|
+
const EXTENSION_ID = 'mcp';
|
|
18
|
+
const EXTENSION_DOMAINS = ['intent', 'intent-block', 'decision', 'claude-code', 'code', 'inference'];
|
|
19
|
+
const REQUEST_TIMEOUT_MS = 30_000;
|
|
20
|
+
const HANDSHAKE_TIMEOUT_MS = 10_000;
|
|
21
|
+
/**
|
|
22
|
+
* Muninn's Tauri bundle identifier.
|
|
23
|
+
* Used on macOS to locate the App Sandbox container.
|
|
24
|
+
*/
|
|
25
|
+
const MUNINN_BUNDLE_ID = 'com.codeawareness.muninn';
|
|
26
|
+
let socket = null;
|
|
27
|
+
let connected = false;
|
|
28
|
+
let cawId = '';
|
|
29
|
+
let connectionPromise = null;
|
|
30
|
+
const pendingRequests = new Map();
|
|
31
|
+
/**
|
|
32
|
+
* Get the default Muninn socket path for the current platform.
|
|
33
|
+
*/
|
|
34
|
+
function getDefaultMuninnSocketPath() {
|
|
35
|
+
if (process.platform === 'win32') {
|
|
36
|
+
return '\\\\.\\pipe\\muninn';
|
|
37
|
+
}
|
|
38
|
+
if (process.platform === 'darwin') {
|
|
39
|
+
// App Store (sandboxed) Muninn: socket may be inside the sandbox container
|
|
40
|
+
const containerSocketPath = path.join(os.homedir(), 'Library', 'Containers', MUNINN_BUNDLE_ID, 'Data', 'Library', 'Application Support', 'Kawa Code', 'sockets', 'muninn');
|
|
41
|
+
if (fs.existsSync(containerSocketPath)) {
|
|
42
|
+
return containerSocketPath;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// All platforms (incl. macOS dev/brew): ~/.kawa-code/sockets/muninn
|
|
46
|
+
// Matches Muninn's paths.rs: sockets_dir().join("muninn")
|
|
47
|
+
return path.join(os.homedir(), '.kawa-code', 'sockets', 'muninn');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Connect to Muninn's Huginn IPC socket.
|
|
51
|
+
*
|
|
52
|
+
* Sends extension handshake and waits for acknowledgment.
|
|
53
|
+
* Throws if Muninn is not running or handshake fails.
|
|
54
|
+
*/
|
|
55
|
+
export function connectToMuninn(socketPath) {
|
|
56
|
+
if (connectionPromise)
|
|
57
|
+
return connectionPromise;
|
|
58
|
+
connectionPromise = _connectToMuninn(socketPath).finally(() => {
|
|
59
|
+
connectionPromise = null;
|
|
60
|
+
});
|
|
61
|
+
return connectionPromise;
|
|
62
|
+
}
|
|
63
|
+
function _connectToMuninn(socketPath) {
|
|
64
|
+
const targetPath = socketPath || process.env.MUNINN_SOCKET || getDefaultMuninnSocketPath();
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
console.error(`[MuninnIPC] Connecting to Muninn catalog at ${targetPath}...`);
|
|
67
|
+
const catalogSock = net.createConnection(targetPath, () => {
|
|
68
|
+
// Send extension handshake
|
|
69
|
+
const handshake = JSON.stringify({
|
|
70
|
+
domain: 'system',
|
|
71
|
+
action: 'handshake',
|
|
72
|
+
data: {
|
|
73
|
+
clientType: 'extension',
|
|
74
|
+
extensionId: EXTENSION_ID,
|
|
75
|
+
domains: EXTENSION_DOMAINS,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
catalogSock.write(handshake + '\n');
|
|
79
|
+
});
|
|
80
|
+
let handshakeReceived = false;
|
|
81
|
+
let switchedToClientPipe = false; // Windows: true after catalog→client pipe handoff
|
|
82
|
+
let buffer = '';
|
|
83
|
+
catalogSock.on('data', (data) => {
|
|
84
|
+
buffer += data.toString();
|
|
85
|
+
const lines = buffer.split('\n');
|
|
86
|
+
buffer = lines.pop() || '';
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
if (!line.trim())
|
|
89
|
+
continue;
|
|
90
|
+
try {
|
|
91
|
+
const msg = JSON.parse(line);
|
|
92
|
+
if (!handshakeReceived && msg.domain === 'system' && msg.action === 'handshake') {
|
|
93
|
+
handshakeReceived = true;
|
|
94
|
+
cawId = msg.data?.caw || '';
|
|
95
|
+
const pipePath = msg.data?.pipePath;
|
|
96
|
+
if (pipePath) {
|
|
97
|
+
// Windows two-pipe protocol: catalog pipe only handles registration.
|
|
98
|
+
// Muninn sends back a dedicated client pipe path; connect to it for I/O.
|
|
99
|
+
switchedToClientPipe = true;
|
|
100
|
+
console.error(`[MuninnIPC] Handshake complete (caw=${cawId}), connecting to ${pipePath}`);
|
|
101
|
+
catalogSock.destroy();
|
|
102
|
+
// Small delay so Muninn's thread has time to start the client pipe server
|
|
103
|
+
setTimeout(() => connectClientPipe(pipePath, resolve, reject), 50);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Unix: single persistent connection, keep using catalogSock
|
|
107
|
+
socket = catalogSock;
|
|
108
|
+
connected = true;
|
|
109
|
+
console.error(`[MuninnIPC] Handshake complete (caw=${cawId})`);
|
|
110
|
+
resolve();
|
|
111
|
+
}
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// Unix path: responses arrive on the same socket
|
|
115
|
+
routeResponse(msg);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Ignore non-JSON lines
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
catalogSock.on('error', (err) => {
|
|
123
|
+
console.error(`[MuninnIPC] Catalog socket error: ${err.message}`);
|
|
124
|
+
if (!handshakeReceived) {
|
|
125
|
+
reject(new Error(`Muninn is not running. Please start Muninn first.\n` +
|
|
126
|
+
`(Could not connect to ${targetPath}: ${err.message})`));
|
|
127
|
+
}
|
|
128
|
+
if (!switchedToClientPipe)
|
|
129
|
+
cleanup();
|
|
130
|
+
});
|
|
131
|
+
catalogSock.on('close', () => {
|
|
132
|
+
// On Windows the catalog pipe closes after handshake — expected, skip cleanup.
|
|
133
|
+
// On Unix the catalog socket IS the main socket, so closing means disconnected.
|
|
134
|
+
if (!switchedToClientPipe) {
|
|
135
|
+
console.error('[MuninnIPC] Socket closed');
|
|
136
|
+
cleanup();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
// Handshake timeout
|
|
140
|
+
setTimeout(() => {
|
|
141
|
+
if (!handshakeReceived) {
|
|
142
|
+
catalogSock.destroy();
|
|
143
|
+
reject(new Error('Muninn handshake timeout (10s). Is Muninn running?'));
|
|
144
|
+
}
|
|
145
|
+
}, HANDSHAKE_TIMEOUT_MS);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Connect to the dedicated client pipe returned in the Windows handshake.
|
|
150
|
+
* On Windows, Muninn creates a per-client named pipe (\\.\pipe\caw.<id>)
|
|
151
|
+
* for bidirectional communication after the catalog registration.
|
|
152
|
+
*/
|
|
153
|
+
function connectClientPipe(pipePath, resolve, reject) {
|
|
154
|
+
console.error(`[MuninnIPC] Connecting to client pipe: ${pipePath}`);
|
|
155
|
+
const clientSock = net.createConnection(pipePath, () => {
|
|
156
|
+
socket = clientSock;
|
|
157
|
+
connected = true;
|
|
158
|
+
console.error('[MuninnIPC] Client pipe connected');
|
|
159
|
+
resolve();
|
|
160
|
+
});
|
|
161
|
+
let buffer = '';
|
|
162
|
+
clientSock.on('data', (data) => {
|
|
163
|
+
buffer += data.toString();
|
|
164
|
+
const lines = buffer.split('\n');
|
|
165
|
+
buffer = lines.pop() || '';
|
|
166
|
+
for (const line of lines) {
|
|
167
|
+
if (!line.trim())
|
|
168
|
+
continue;
|
|
169
|
+
try {
|
|
170
|
+
routeResponse(JSON.parse(line));
|
|
171
|
+
}
|
|
172
|
+
catch { /* ignore */ }
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
clientSock.on('error', (err) => {
|
|
176
|
+
console.error(`[MuninnIPC] Client pipe error: ${err.message}`);
|
|
177
|
+
if (!connected) {
|
|
178
|
+
reject(new Error(`Failed to connect to Muninn client pipe: ${err.message}`));
|
|
179
|
+
}
|
|
180
|
+
cleanup();
|
|
181
|
+
});
|
|
182
|
+
clientSock.on('close', () => {
|
|
183
|
+
console.error('[MuninnIPC] Client pipe closed');
|
|
184
|
+
cleanup();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/** Route an inbound response message to its waiting pendingRequest entry. */
|
|
188
|
+
function routeResponse(msg) {
|
|
189
|
+
const msgId = msg._msgId;
|
|
190
|
+
if (msgId && pendingRequests.has(msgId)) {
|
|
191
|
+
const pending = pendingRequests.get(msgId);
|
|
192
|
+
pendingRequests.delete(msgId);
|
|
193
|
+
clearTimeout(pending.timer);
|
|
194
|
+
if (msg.err) {
|
|
195
|
+
pending.reject(new Error(msg.err));
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
pending.resolve(msg.data || {});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Send an IPC request to Muninn and await the correlated response.
|
|
204
|
+
*
|
|
205
|
+
* @param domain - Handler domain (e.g., 'intent', 'decision')
|
|
206
|
+
* @param action - Handler action (e.g., 'create', 'get-active')
|
|
207
|
+
* @param data - Request payload
|
|
208
|
+
* @returns The response data from Muninn
|
|
209
|
+
*/
|
|
210
|
+
export async function request(domain, action, data = {}) {
|
|
211
|
+
if (!socket || !connected) {
|
|
212
|
+
await connectToMuninn();
|
|
213
|
+
}
|
|
214
|
+
const msgId = `mcp-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`;
|
|
215
|
+
return new Promise((resolve, reject) => {
|
|
216
|
+
const timer = setTimeout(() => {
|
|
217
|
+
pendingRequests.delete(msgId);
|
|
218
|
+
reject(new Error(`Muninn request timeout (${REQUEST_TIMEOUT_MS / 1000}s): ${domain}:${action}`));
|
|
219
|
+
}, REQUEST_TIMEOUT_MS);
|
|
220
|
+
pendingRequests.set(msgId, { resolve, reject, timer });
|
|
221
|
+
const message = JSON.stringify({
|
|
222
|
+
flow: 'req',
|
|
223
|
+
domain,
|
|
224
|
+
action,
|
|
225
|
+
caw: cawId,
|
|
226
|
+
data,
|
|
227
|
+
_msgId: msgId,
|
|
228
|
+
});
|
|
229
|
+
socket.write(message + '\n');
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Ensure a repository path is registered with Muninn as a project.
|
|
234
|
+
*
|
|
235
|
+
* Sends `code:add` with the folder path so Muninn activates the project,
|
|
236
|
+
* sets up git state, and pulls intents/decisions/lessons from the API.
|
|
237
|
+
* Always sends the request — Muninn's AddHandler is idempotent and
|
|
238
|
+
* returns the existing project if already added.
|
|
239
|
+
* Errors are logged but not thrown — repo registration is best-effort.
|
|
240
|
+
*/
|
|
241
|
+
export async function ensureRepo(repoPath) {
|
|
242
|
+
try {
|
|
243
|
+
await request('code', 'add', { folder: repoPath });
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
console.error(`[MuninnIPC] ensureRepo failed for ${repoPath}: ${err.message}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Check if connected to Muninn.
|
|
251
|
+
*/
|
|
252
|
+
export function isConnected() {
|
|
253
|
+
return connected;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Disconnect from Muninn.
|
|
257
|
+
*/
|
|
258
|
+
export function disconnect() {
|
|
259
|
+
if (socket) {
|
|
260
|
+
socket.destroy();
|
|
261
|
+
}
|
|
262
|
+
cleanup();
|
|
263
|
+
}
|
|
264
|
+
function cleanup() {
|
|
265
|
+
connected = false;
|
|
266
|
+
socket = null;
|
|
267
|
+
connectionPromise = null;
|
|
268
|
+
// Reject all pending requests
|
|
269
|
+
for (const [id, pending] of pendingRequests) {
|
|
270
|
+
clearTimeout(pending.timer);
|
|
271
|
+
pending.reject(new Error('Muninn connection closed'));
|
|
272
|
+
}
|
|
273
|
+
pendingRequests.clear();
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=muninn-ipc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"muninn-ipc.js","sourceRoot":"","sources":["../../src/services/muninn-ipc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repository content encryption for zero-knowledge block assignment.
|
|
3
|
+
*
|
|
4
|
+
* Replicates Muninn Gardener's encryption.rs for intent block content:
|
|
5
|
+
* - Key derivation: PBKDF2-HMAC-SHA256, 600,000 iterations
|
|
6
|
+
* - Key material: "{initialCommitSHA}-{origin}"
|
|
7
|
+
* - Salt: "kawa-code-zero-knowledge-v1"
|
|
8
|
+
* - Cipher: AES-256-GCM with random 12-byte IV
|
|
9
|
+
* - Output: JSON string {"encryptedContent", "iv", "authTag"}
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Derive a 32-byte AES key from the repo's initial commit SHA and origin.
|
|
13
|
+
*
|
|
14
|
+
* Matches Muninn's derive_repository_key():
|
|
15
|
+
* - key material = "{initialCommit}-{origin}"
|
|
16
|
+
* - salt = "kawa-code-zero-knowledge-v1"
|
|
17
|
+
* - 600,000 PBKDF2-HMAC-SHA256 iterations
|
|
18
|
+
*/
|
|
19
|
+
export declare function deriveRepoKey(initialCommit: string, origin: string): Buffer;
|
|
20
|
+
/**
|
|
21
|
+
* Get the initial (root) commit SHA for a repository.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getInitialCommitSHA(repoPath: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Encrypt content using AES-256-GCM.
|
|
26
|
+
*
|
|
27
|
+
* Returns a JSON string matching Muninn's EncryptedContent format:
|
|
28
|
+
* { "encryptedContent": hex, "iv": hex, "authTag": hex }
|
|
29
|
+
*
|
|
30
|
+
* The encryptedContent hex includes the 16-byte auth tag appended
|
|
31
|
+
* (AES-GCM ciphertext + tag), matching Gardener's Rust implementation.
|
|
32
|
+
*/
|
|
33
|
+
export declare function encryptContent(plaintext: string, key: Buffer): string;
|
|
34
|
+
/**
|
|
35
|
+
* Extract content from a file at the given line range and compute hash + snippet.
|
|
36
|
+
*
|
|
37
|
+
* Matches Gardener's IntentBlockService::extract_content_and_hash():
|
|
38
|
+
* - Lines are 1-based
|
|
39
|
+
* - snippet = first 150 characters
|
|
40
|
+
* - contentHash = SHA-256 of the whitespace-normalized plaintext (hex)
|
|
41
|
+
*/
|
|
42
|
+
export declare function extractContentAndHash(fileContent: string, startLine: number, endLine: number): {
|
|
43
|
+
content: string;
|
|
44
|
+
contentHash: string;
|
|
45
|
+
contentSnippet: string;
|
|
46
|
+
};
|