katashiro-vscode 0.2.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/package.json +184 -0
- package/src/commands/command-manager.ts +452 -0
- package/src/commands/index.ts +5 -0
- package/src/extension.ts +48 -0
- package/src/index.ts +36 -0
- package/src/katashiro-extension.ts +125 -0
- package/src/ui/index.ts +9 -0
- package/src/ui/output-channel-manager.ts +105 -0
- package/src/ui/status-bar-manager.ts +157 -0
- package/src/views/history-view-provider.ts +221 -0
- package/src/views/index.ts +15 -0
- package/src/views/knowledge-view-provider.ts +204 -0
- package/src/views/research-view-provider.ts +141 -0
- package/tests/mocks/vscode.ts +121 -0
- package/tests/unit/history-view-provider.test.ts +150 -0
- package/tests/unit/knowledge-view-provider.test.ts +120 -0
- package/tests/unit/output-channel-manager.test.ts +75 -0
- package/tests/unit/research-view-provider.test.ts +111 -0
- package/tests/unit/status-bar-manager.test.ts +101 -0
- package/tsconfig.json +20 -0
- package/tsconfig.tsbuildinfo +1 -0
package/package.json
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "katashiro-vscode",
|
|
3
|
+
"displayName": "KATASHIRO",
|
|
4
|
+
"description": "AI-powered research assistant with web search, content analysis, and knowledge graph",
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"publisher": "nahisaho",
|
|
7
|
+
"icon": "media/icon.png",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/nahisaho/katashiro"
|
|
11
|
+
},
|
|
12
|
+
"engines": {
|
|
13
|
+
"vscode": "^1.85.0"
|
|
14
|
+
},
|
|
15
|
+
"categories": [
|
|
16
|
+
"Other",
|
|
17
|
+
"Data Science",
|
|
18
|
+
"Machine Learning"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"research",
|
|
22
|
+
"ai",
|
|
23
|
+
"knowledge graph",
|
|
24
|
+
"web search",
|
|
25
|
+
"content analysis",
|
|
26
|
+
"mcp",
|
|
27
|
+
"agent"
|
|
28
|
+
],
|
|
29
|
+
"activationEvents": [
|
|
30
|
+
"onStartupFinished"
|
|
31
|
+
],
|
|
32
|
+
"main": "./dist/extension.js",
|
|
33
|
+
"contributes": {
|
|
34
|
+
"commands": [
|
|
35
|
+
{
|
|
36
|
+
"command": "katashiro.webSearch",
|
|
37
|
+
"title": "KATASHIRO: Web Search",
|
|
38
|
+
"category": "KATASHIRO"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"command": "katashiro.analyzeContent",
|
|
42
|
+
"title": "KATASHIRO: Analyze Content",
|
|
43
|
+
"category": "KATASHIRO"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"command": "katashiro.generateSummary",
|
|
47
|
+
"title": "KATASHIRO: Generate Summary",
|
|
48
|
+
"category": "KATASHIRO"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"command": "katashiro.researchTopic",
|
|
52
|
+
"title": "KATASHIRO: Research Topic",
|
|
53
|
+
"category": "KATASHIRO"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"command": "katashiro.generateReport",
|
|
57
|
+
"title": "KATASHIRO: Generate Report",
|
|
58
|
+
"category": "KATASHIRO"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"command": "katashiro.showKnowledgeGraph",
|
|
62
|
+
"title": "KATASHIRO: Show Knowledge Graph",
|
|
63
|
+
"category": "KATASHIRO"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"command": "katashiro.startMcpServer",
|
|
67
|
+
"title": "KATASHIRO: Start MCP Server",
|
|
68
|
+
"category": "KATASHIRO"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"viewsContainers": {
|
|
72
|
+
"activitybar": [
|
|
73
|
+
{
|
|
74
|
+
"id": "katashiro",
|
|
75
|
+
"title": "KATASHIRO",
|
|
76
|
+
"icon": "media/icon.svg"
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
"views": {
|
|
81
|
+
"katashiro": [
|
|
82
|
+
{
|
|
83
|
+
"id": "katashiro.research",
|
|
84
|
+
"name": "Research"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"id": "katashiro.knowledge",
|
|
88
|
+
"name": "Knowledge Graph"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"id": "katashiro.history",
|
|
92
|
+
"name": "History"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"configuration": {
|
|
97
|
+
"title": "KATASHIRO",
|
|
98
|
+
"properties": {
|
|
99
|
+
"katashiro.searchEngine": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"default": "duckduckgo",
|
|
102
|
+
"enum": [
|
|
103
|
+
"duckduckgo",
|
|
104
|
+
"google",
|
|
105
|
+
"bing"
|
|
106
|
+
],
|
|
107
|
+
"description": "Default search engine for web searches"
|
|
108
|
+
},
|
|
109
|
+
"katashiro.maxSearchResults": {
|
|
110
|
+
"type": "number",
|
|
111
|
+
"default": 10,
|
|
112
|
+
"minimum": 1,
|
|
113
|
+
"maximum": 50,
|
|
114
|
+
"description": "Maximum number of search results to return"
|
|
115
|
+
},
|
|
116
|
+
"katashiro.outputFormat": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"default": "markdown",
|
|
119
|
+
"enum": [
|
|
120
|
+
"markdown",
|
|
121
|
+
"html",
|
|
122
|
+
"json"
|
|
123
|
+
],
|
|
124
|
+
"description": "Default output format for reports"
|
|
125
|
+
},
|
|
126
|
+
"katashiro.autoSaveKnowledge": {
|
|
127
|
+
"type": "boolean",
|
|
128
|
+
"default": true,
|
|
129
|
+
"description": "Automatically save research to knowledge graph"
|
|
130
|
+
},
|
|
131
|
+
"katashiro.mcpServerPort": {
|
|
132
|
+
"type": "number",
|
|
133
|
+
"default": 3000,
|
|
134
|
+
"description": "Port for MCP server HTTP transport"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"menus": {
|
|
139
|
+
"editor/context": [
|
|
140
|
+
{
|
|
141
|
+
"command": "katashiro.analyzeContent",
|
|
142
|
+
"when": "editorHasSelection",
|
|
143
|
+
"group": "katashiro"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"command": "katashiro.generateSummary",
|
|
147
|
+
"when": "editorHasSelection",
|
|
148
|
+
"group": "katashiro"
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
"view/title": [
|
|
152
|
+
{
|
|
153
|
+
"command": "katashiro.webSearch",
|
|
154
|
+
"when": "view == katashiro.research",
|
|
155
|
+
"group": "navigation"
|
|
156
|
+
}
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"scripts": {
|
|
161
|
+
"vscode:prepublish": "npm run build",
|
|
162
|
+
"build": "tsc",
|
|
163
|
+
"watch": "tsc -watch",
|
|
164
|
+
"clean": "rm -rf dist",
|
|
165
|
+
"test": "vitest run",
|
|
166
|
+
"package": "vsce package",
|
|
167
|
+
"publish": "vsce publish"
|
|
168
|
+
},
|
|
169
|
+
"dependencies": {
|
|
170
|
+
"@nahisaho/katashiro-core": "*",
|
|
171
|
+
"@nahisaho/katashiro-collector": "*",
|
|
172
|
+
"@nahisaho/katashiro-analyzer": "*",
|
|
173
|
+
"@nahisaho/katashiro-generator": "*",
|
|
174
|
+
"@nahisaho/katashiro-knowledge": "*",
|
|
175
|
+
"@nahisaho/katashiro-feedback": "*",
|
|
176
|
+
"@nahisaho/katashiro-mcp-server": "*"
|
|
177
|
+
},
|
|
178
|
+
"devDependencies": {
|
|
179
|
+
"@types/vscode": "^1.85.0",
|
|
180
|
+
"@vscode/vsce": "^2.22.0"
|
|
181
|
+
},
|
|
182
|
+
"author": "nahisaho",
|
|
183
|
+
"license": "MIT"
|
|
184
|
+
}
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CommandManager - VS Code command registration and handling
|
|
3
|
+
*
|
|
4
|
+
* @module katashiro
|
|
5
|
+
* @task TSK-071
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as vscode from 'vscode';
|
|
9
|
+
import type { OutputChannelManager } from '../ui/output-channel-manager.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* CommandManager
|
|
13
|
+
*
|
|
14
|
+
* Manages registration and execution of VS Code commands
|
|
15
|
+
*/
|
|
16
|
+
export class CommandManager {
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly context: vscode.ExtensionContext,
|
|
19
|
+
private readonly output: OutputChannelManager
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Register all commands
|
|
24
|
+
*/
|
|
25
|
+
registerAll(): void {
|
|
26
|
+
this.register('katashiro.webSearch', this.webSearch.bind(this));
|
|
27
|
+
this.register('katashiro.analyzeContent', this.analyzeContent.bind(this));
|
|
28
|
+
this.register('katashiro.generateSummary', this.generateSummary.bind(this));
|
|
29
|
+
this.register('katashiro.researchTopic', this.researchTopic.bind(this));
|
|
30
|
+
this.register('katashiro.generateReport', this.generateReport.bind(this));
|
|
31
|
+
this.register(
|
|
32
|
+
'katashiro.showKnowledgeGraph',
|
|
33
|
+
this.showKnowledgeGraph.bind(this)
|
|
34
|
+
);
|
|
35
|
+
this.register('katashiro.startMcpServer', this.startMcpServer.bind(this));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Register a command
|
|
40
|
+
*/
|
|
41
|
+
private register(
|
|
42
|
+
command: string,
|
|
43
|
+
callback: (...args: unknown[]) => Promise<void>
|
|
44
|
+
): void {
|
|
45
|
+
const disposable = vscode.commands.registerCommand(command, callback);
|
|
46
|
+
this.context.subscriptions.push(disposable);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Web Search command
|
|
51
|
+
*/
|
|
52
|
+
private async webSearch(): Promise<void> {
|
|
53
|
+
const query = await vscode.window.showInputBox({
|
|
54
|
+
prompt: 'Enter search query',
|
|
55
|
+
placeHolder: 'Search the web...',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!query) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.output.log(`Web search: ${query}`);
|
|
63
|
+
|
|
64
|
+
await vscode.window.withProgress(
|
|
65
|
+
{
|
|
66
|
+
location: vscode.ProgressLocation.Notification,
|
|
67
|
+
title: 'KATASHIRO: Searching...',
|
|
68
|
+
cancellable: false,
|
|
69
|
+
},
|
|
70
|
+
async () => {
|
|
71
|
+
try {
|
|
72
|
+
// TODO: Integrate with WebSearchClient
|
|
73
|
+
const results = await this.performWebSearch(query);
|
|
74
|
+
|
|
75
|
+
// Show results in new document
|
|
76
|
+
const doc = await vscode.workspace.openTextDocument({
|
|
77
|
+
content: this.formatSearchResults(query, results),
|
|
78
|
+
language: 'markdown',
|
|
79
|
+
});
|
|
80
|
+
await vscode.window.showTextDocument(doc);
|
|
81
|
+
|
|
82
|
+
this.output.log(`Search completed: ${results.length} results`);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
this.handleError('Web search failed', error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Analyze Content command
|
|
92
|
+
*/
|
|
93
|
+
private async analyzeContent(): Promise<void> {
|
|
94
|
+
const editor = vscode.window.activeTextEditor;
|
|
95
|
+
if (!editor) {
|
|
96
|
+
vscode.window.showWarningMessage('No active editor');
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const selection = editor.selection;
|
|
101
|
+
const content = selection.isEmpty
|
|
102
|
+
? editor.document.getText()
|
|
103
|
+
: editor.document.getText(selection);
|
|
104
|
+
|
|
105
|
+
if (!content.trim()) {
|
|
106
|
+
vscode.window.showWarningMessage('No content to analyze');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this.output.log('Analyzing content...');
|
|
111
|
+
|
|
112
|
+
await vscode.window.withProgress(
|
|
113
|
+
{
|
|
114
|
+
location: vscode.ProgressLocation.Notification,
|
|
115
|
+
title: 'KATASHIRO: Analyzing...',
|
|
116
|
+
cancellable: false,
|
|
117
|
+
},
|
|
118
|
+
async () => {
|
|
119
|
+
try {
|
|
120
|
+
// TODO: Integrate with TextAnalyzer
|
|
121
|
+
const analysis = await this.performContentAnalysis(content);
|
|
122
|
+
|
|
123
|
+
// Show analysis in new document
|
|
124
|
+
const doc = await vscode.workspace.openTextDocument({
|
|
125
|
+
content: this.formatAnalysis(analysis),
|
|
126
|
+
language: 'markdown',
|
|
127
|
+
});
|
|
128
|
+
await vscode.window.showTextDocument(doc, vscode.ViewColumn.Beside);
|
|
129
|
+
|
|
130
|
+
this.output.log('Content analysis completed');
|
|
131
|
+
} catch (error) {
|
|
132
|
+
this.handleError('Content analysis failed', error);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate Summary command
|
|
140
|
+
*/
|
|
141
|
+
private async generateSummary(): Promise<void> {
|
|
142
|
+
const editor = vscode.window.activeTextEditor;
|
|
143
|
+
if (!editor) {
|
|
144
|
+
vscode.window.showWarningMessage('No active editor');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const selection = editor.selection;
|
|
149
|
+
const content = selection.isEmpty
|
|
150
|
+
? editor.document.getText()
|
|
151
|
+
: editor.document.getText(selection);
|
|
152
|
+
|
|
153
|
+
if (!content.trim()) {
|
|
154
|
+
vscode.window.showWarningMessage('No content to summarize');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const style = await vscode.window.showQuickPick(
|
|
159
|
+
['brief', 'detailed', 'bullet'],
|
|
160
|
+
{
|
|
161
|
+
placeHolder: 'Select summary style',
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
if (!style) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this.output.log(`Generating ${style} summary...`);
|
|
170
|
+
|
|
171
|
+
await vscode.window.withProgress(
|
|
172
|
+
{
|
|
173
|
+
location: vscode.ProgressLocation.Notification,
|
|
174
|
+
title: 'KATASHIRO: Generating summary...',
|
|
175
|
+
cancellable: false,
|
|
176
|
+
},
|
|
177
|
+
async () => {
|
|
178
|
+
try {
|
|
179
|
+
// TODO: Integrate with SummaryGenerator
|
|
180
|
+
const summary = await this.performSummaryGeneration(content, style);
|
|
181
|
+
|
|
182
|
+
// Show summary in new document
|
|
183
|
+
const doc = await vscode.workspace.openTextDocument({
|
|
184
|
+
content: summary,
|
|
185
|
+
language: 'markdown',
|
|
186
|
+
});
|
|
187
|
+
await vscode.window.showTextDocument(doc, vscode.ViewColumn.Beside);
|
|
188
|
+
|
|
189
|
+
this.output.log('Summary generation completed');
|
|
190
|
+
} catch (error) {
|
|
191
|
+
this.handleError('Summary generation failed', error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Research Topic command
|
|
199
|
+
*/
|
|
200
|
+
private async researchTopic(): Promise<void> {
|
|
201
|
+
const topic = await vscode.window.showInputBox({
|
|
202
|
+
prompt: 'Enter topic to research',
|
|
203
|
+
placeHolder: 'Research topic...',
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
if (!topic) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const depth = await vscode.window.showQuickPick(
|
|
211
|
+
['shallow', 'moderate', 'deep'],
|
|
212
|
+
{
|
|
213
|
+
placeHolder: 'Select research depth',
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
if (!depth) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.output.log(`Researching topic: ${topic} (depth: ${depth})`);
|
|
222
|
+
|
|
223
|
+
await vscode.window.withProgress(
|
|
224
|
+
{
|
|
225
|
+
location: vscode.ProgressLocation.Notification,
|
|
226
|
+
title: 'KATASHIRO: Researching...',
|
|
227
|
+
cancellable: true,
|
|
228
|
+
},
|
|
229
|
+
async (progress, token) => {
|
|
230
|
+
try {
|
|
231
|
+
progress.report({ message: 'Searching web...' });
|
|
232
|
+
|
|
233
|
+
// TODO: Full research pipeline
|
|
234
|
+
const results = await this.performResearch(topic, depth, token);
|
|
235
|
+
|
|
236
|
+
if (token.isCancellationRequested) {
|
|
237
|
+
this.output.log('Research cancelled');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Show results
|
|
242
|
+
const doc = await vscode.workspace.openTextDocument({
|
|
243
|
+
content: this.formatResearchResults(topic, results),
|
|
244
|
+
language: 'markdown',
|
|
245
|
+
});
|
|
246
|
+
await vscode.window.showTextDocument(doc);
|
|
247
|
+
|
|
248
|
+
this.output.log('Research completed');
|
|
249
|
+
} catch (error) {
|
|
250
|
+
this.handleError('Research failed', error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Generate Report command
|
|
258
|
+
*/
|
|
259
|
+
private async generateReport(): Promise<void> {
|
|
260
|
+
const topic = await vscode.window.showInputBox({
|
|
261
|
+
prompt: 'Enter report topic',
|
|
262
|
+
placeHolder: 'Report topic...',
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (!topic) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const format = await vscode.window.showQuickPick(
|
|
270
|
+
['markdown', 'html', 'pdf'],
|
|
271
|
+
{
|
|
272
|
+
placeHolder: 'Select output format',
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
if (!format) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
this.output.log(`Generating report: ${topic} (format: ${format})`);
|
|
281
|
+
|
|
282
|
+
await vscode.window.withProgress(
|
|
283
|
+
{
|
|
284
|
+
location: vscode.ProgressLocation.Notification,
|
|
285
|
+
title: 'KATASHIRO: Generating report...',
|
|
286
|
+
cancellable: false,
|
|
287
|
+
},
|
|
288
|
+
async () => {
|
|
289
|
+
try {
|
|
290
|
+
// TODO: Integrate with ReportGenerator
|
|
291
|
+
const report = await this.performReportGeneration(topic, format);
|
|
292
|
+
|
|
293
|
+
// Show report
|
|
294
|
+
const language = format === 'html' ? 'html' : 'markdown';
|
|
295
|
+
const doc = await vscode.workspace.openTextDocument({
|
|
296
|
+
content: report,
|
|
297
|
+
language,
|
|
298
|
+
});
|
|
299
|
+
await vscode.window.showTextDocument(doc);
|
|
300
|
+
|
|
301
|
+
this.output.log('Report generation completed');
|
|
302
|
+
} catch (error) {
|
|
303
|
+
this.handleError('Report generation failed', error);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Show Knowledge Graph command
|
|
311
|
+
*/
|
|
312
|
+
private async showKnowledgeGraph(): Promise<void> {
|
|
313
|
+
this.output.log('Opening knowledge graph viewer...');
|
|
314
|
+
|
|
315
|
+
// TODO: Implement webview for knowledge graph visualization
|
|
316
|
+
vscode.window.showInformationMessage(
|
|
317
|
+
'KATASHIRO: Knowledge Graph viewer coming soon!'
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Start MCP Server command
|
|
323
|
+
*/
|
|
324
|
+
private async startMcpServer(): Promise<void> {
|
|
325
|
+
this.output.log('Starting MCP server...');
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
// TODO: Start MCP server in background
|
|
329
|
+
vscode.window.showInformationMessage(
|
|
330
|
+
'KATASHIRO: MCP Server started on stdio'
|
|
331
|
+
);
|
|
332
|
+
this.output.log('MCP server started');
|
|
333
|
+
} catch (error) {
|
|
334
|
+
this.handleError('Failed to start MCP server', error);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Helper methods (placeholder implementations)
|
|
339
|
+
|
|
340
|
+
private async performWebSearch(
|
|
341
|
+
query: string
|
|
342
|
+
): Promise<Array<{ title: string; url: string; snippet: string }>> {
|
|
343
|
+
// Placeholder - will integrate with WebSearchClient
|
|
344
|
+
return [
|
|
345
|
+
{
|
|
346
|
+
title: `Result 1 for: ${query}`,
|
|
347
|
+
url: 'https://example.com/1',
|
|
348
|
+
snippet: 'This is a sample search result snippet...',
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
title: `Result 2 for: ${query}`,
|
|
352
|
+
url: 'https://example.com/2',
|
|
353
|
+
snippet: 'Another sample search result snippet...',
|
|
354
|
+
},
|
|
355
|
+
];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private formatSearchResults(
|
|
359
|
+
query: string,
|
|
360
|
+
results: Array<{ title: string; url: string; snippet: string }>
|
|
361
|
+
): string {
|
|
362
|
+
let md = `# Search Results: ${query}\n\n`;
|
|
363
|
+
md += `Found ${results.length} results\n\n`;
|
|
364
|
+
|
|
365
|
+
for (const result of results) {
|
|
366
|
+
md += `## [${result.title}](${result.url})\n\n`;
|
|
367
|
+
md += `${result.snippet}\n\n`;
|
|
368
|
+
md += '---\n\n';
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return md;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private async performContentAnalysis(content: string): Promise<{
|
|
375
|
+
wordCount: number;
|
|
376
|
+
entities: string[];
|
|
377
|
+
topics: string[];
|
|
378
|
+
sentiment: string;
|
|
379
|
+
}> {
|
|
380
|
+
// Placeholder - will integrate with TextAnalyzer
|
|
381
|
+
return {
|
|
382
|
+
wordCount: content.split(/\s+/).length,
|
|
383
|
+
entities: ['Entity 1', 'Entity 2'],
|
|
384
|
+
topics: ['Topic 1', 'Topic 2'],
|
|
385
|
+
sentiment: 'neutral',
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private formatAnalysis(analysis: {
|
|
390
|
+
wordCount: number;
|
|
391
|
+
entities: string[];
|
|
392
|
+
topics: string[];
|
|
393
|
+
sentiment: string;
|
|
394
|
+
}): string {
|
|
395
|
+
let md = '# Content Analysis\n\n';
|
|
396
|
+
md += `**Word Count:** ${analysis.wordCount}\n\n`;
|
|
397
|
+
md += `**Sentiment:** ${analysis.sentiment}\n\n`;
|
|
398
|
+
md += '## Entities\n\n';
|
|
399
|
+
md += analysis.entities.map((e) => `- ${e}`).join('\n');
|
|
400
|
+
md += '\n\n## Topics\n\n';
|
|
401
|
+
md += analysis.topics.map((t) => `- ${t}`).join('\n');
|
|
402
|
+
return md;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private async performSummaryGeneration(
|
|
406
|
+
content: string,
|
|
407
|
+
style: string
|
|
408
|
+
): Promise<string> {
|
|
409
|
+
// Placeholder - will integrate with SummaryGenerator
|
|
410
|
+
const preview = content.substring(0, 200);
|
|
411
|
+
return `# Summary (${style})\n\n${preview}...\n\n*Generated by KATASHIRO*`;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private async performResearch(
|
|
415
|
+
topic: string,
|
|
416
|
+
depth: string,
|
|
417
|
+
_token: vscode.CancellationToken
|
|
418
|
+
): Promise<{ summary: string; sources: string[] }> {
|
|
419
|
+
// Placeholder - will integrate with full research pipeline
|
|
420
|
+
return {
|
|
421
|
+
summary: `Research findings for "${topic}" at ${depth} depth...`,
|
|
422
|
+
sources: ['https://example.com/source1', 'https://example.com/source2'],
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
private formatResearchResults(
|
|
427
|
+
topic: string,
|
|
428
|
+
results: { summary: string; sources: string[] }
|
|
429
|
+
): string {
|
|
430
|
+
let md = `# Research: ${topic}\n\n`;
|
|
431
|
+
md += `## Summary\n\n${results.summary}\n\n`;
|
|
432
|
+
md += '## Sources\n\n';
|
|
433
|
+
md += results.sources.map((s) => `- ${s}`).join('\n');
|
|
434
|
+
md += '\n\n*Generated by KATASHIRO*';
|
|
435
|
+
return md;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
private async performReportGeneration(
|
|
439
|
+
topic: string,
|
|
440
|
+
format: string
|
|
441
|
+
): Promise<string> {
|
|
442
|
+
// Placeholder - will integrate with ReportGenerator
|
|
443
|
+
return `# Report: ${topic}\n\nFormat: ${format}\n\n## Introduction\n\n...\n\n## Conclusion\n\n...\n\n*Generated by KATASHIRO*`;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
private handleError(message: string, error: unknown): void {
|
|
447
|
+
const errorMessage =
|
|
448
|
+
error instanceof Error ? error.message : 'Unknown error';
|
|
449
|
+
this.output.error(`${message}: ${errorMessage}`);
|
|
450
|
+
vscode.window.showErrorMessage(`KATASHIRO: ${message}`);
|
|
451
|
+
}
|
|
452
|
+
}
|
package/src/extension.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KATASHIRO VS Code Extension
|
|
3
|
+
*
|
|
4
|
+
* Main extension entry point
|
|
5
|
+
*
|
|
6
|
+
* @module katashiro
|
|
7
|
+
* @task TSK-070
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import * as vscode from 'vscode';
|
|
11
|
+
import { KatashiroExtension } from './katashiro-extension.js';
|
|
12
|
+
|
|
13
|
+
let extension: KatashiroExtension | undefined;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Activate the extension
|
|
17
|
+
*/
|
|
18
|
+
export async function activate(
|
|
19
|
+
context: vscode.ExtensionContext
|
|
20
|
+
): Promise<void> {
|
|
21
|
+
console.log('KATASHIRO extension activating...');
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
extension = new KatashiroExtension(context);
|
|
25
|
+
await extension.activate();
|
|
26
|
+
|
|
27
|
+
console.log('KATASHIRO extension activated successfully');
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('Failed to activate KATASHIRO extension:', error);
|
|
30
|
+
vscode.window.showErrorMessage(
|
|
31
|
+
`KATASHIRO: Failed to activate - ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Deactivate the extension
|
|
38
|
+
*/
|
|
39
|
+
export async function deactivate(): Promise<void> {
|
|
40
|
+
console.log('KATASHIRO extension deactivating...');
|
|
41
|
+
|
|
42
|
+
if (extension) {
|
|
43
|
+
await extension.deactivate();
|
|
44
|
+
extension = undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log('KATASHIRO extension deactivated');
|
|
48
|
+
}
|