gyrus 0.1.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/LICENSE +21 -0
- package/README.md +273 -0
- package/package.json +78 -0
- package/src/commands/adr.ts +482 -0
- package/src/commands/doctor.ts +263 -0
- package/src/commands/init.ts +293 -0
- package/src/commands/knowledge.ts +446 -0
- package/src/commands/list.ts +51 -0
- package/src/commands/mcp.ts +94 -0
- package/src/commands/use.ts +65 -0
- package/src/config/index.ts +262 -0
- package/src/config/schema.ts +139 -0
- package/src/formatters/adr.ts +295 -0
- package/src/formatters/index.ts +44 -0
- package/src/formatters/knowledge.ts +282 -0
- package/src/formatters/workspace.ts +149 -0
- package/src/index.ts +153 -0
- package/src/operations/adr.ts +312 -0
- package/src/operations/index.ts +58 -0
- package/src/operations/knowledge.ts +324 -0
- package/src/operations/types.ts +199 -0
- package/src/operations/workspace.ts +108 -0
- package/src/server/mcp-stdio.ts +526 -0
- package/src/services/adr.ts +511 -0
- package/src/services/knowledge.ts +516 -0
- package/src/services/markdown.ts +155 -0
- package/src/services/workspace.ts +377 -0
- package/src/templates/knowledge/README.md +199 -0
- package/src/tools/adr-create.ts +99 -0
- package/src/tools/adr-list.ts +72 -0
- package/src/tools/adr-read.ts +54 -0
- package/src/tools/adr-search.ts +79 -0
- package/src/tools/adr-update.ts +95 -0
- package/src/tools/gyrus-list.ts +41 -0
- package/src/tools/gyrus-switch.ts +45 -0
- package/src/tools/index.ts +91 -0
- package/src/tools/knowledge-create.ts +75 -0
- package/src/tools/knowledge-list.ts +60 -0
- package/src/tools/knowledge-read.ts +62 -0
- package/src/tools/knowledge-search.ts +65 -0
- package/src/tools/knowledge-update.ts +76 -0
- package/src/types/index.ts +343 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR Operations
|
|
3
|
+
* Shared business logic for ADRs used by both CLI and MCP interfaces
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { WorkspaceManager } from "../services/workspace.ts";
|
|
7
|
+
import type { AdrStatus, AdrType } from "../types/index.ts";
|
|
8
|
+
import type {
|
|
9
|
+
OperationResult,
|
|
10
|
+
AdrListInput,
|
|
11
|
+
AdrListResult,
|
|
12
|
+
AdrReadInput,
|
|
13
|
+
AdrReadResult,
|
|
14
|
+
AdrSearchInput,
|
|
15
|
+
AdrSearchResult,
|
|
16
|
+
AdrCreateInput,
|
|
17
|
+
AdrCreateResult,
|
|
18
|
+
AdrUpdateInput,
|
|
19
|
+
AdrUpdateResult,
|
|
20
|
+
} from "./types.ts";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* List ADRs with optional filtering
|
|
24
|
+
*/
|
|
25
|
+
export async function listAdrs(
|
|
26
|
+
manager: WorkspaceManager,
|
|
27
|
+
input: AdrListInput,
|
|
28
|
+
): Promise<OperationResult<AdrListResult>> {
|
|
29
|
+
// Get service for specified workspace or active workspace
|
|
30
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
31
|
+
const service = manager.getAdrService(workspaceName);
|
|
32
|
+
|
|
33
|
+
if (!service) {
|
|
34
|
+
if (input.workspace) {
|
|
35
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
36
|
+
if (!ws) {
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
error: `ADRs folder not found in workspace "${input.workspace}". Make sure the workspace has an 'adrs' directory.`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error:
|
|
50
|
+
"ADRs folder not found in the active workspace. Make sure the workspace has an 'adrs' directory.",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const adrs = await service.listAdrs({
|
|
55
|
+
status: input.status as AdrStatus | undefined,
|
|
56
|
+
type: input.type as AdrType | undefined,
|
|
57
|
+
tags: input.tags,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Group by status
|
|
61
|
+
const byStatus: Record<string, typeof adrs> = {};
|
|
62
|
+
for (const adr of adrs) {
|
|
63
|
+
const status = adr.status;
|
|
64
|
+
if (!byStatus[status]) byStatus[status] = [];
|
|
65
|
+
byStatus[status].push(adr);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
success: true,
|
|
70
|
+
data: {
|
|
71
|
+
workspace: workspaceName,
|
|
72
|
+
adrs,
|
|
73
|
+
byStatus,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Read a specific ADR by name
|
|
80
|
+
*/
|
|
81
|
+
export async function readAdr(
|
|
82
|
+
manager: WorkspaceManager,
|
|
83
|
+
input: AdrReadInput,
|
|
84
|
+
): Promise<OperationResult<AdrReadResult>> {
|
|
85
|
+
// Get service for specified workspace or active workspace
|
|
86
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
87
|
+
const service = manager.getAdrService(workspaceName);
|
|
88
|
+
|
|
89
|
+
if (!service) {
|
|
90
|
+
if (input.workspace) {
|
|
91
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
92
|
+
if (!ws) {
|
|
93
|
+
return {
|
|
94
|
+
success: false,
|
|
95
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
success: false,
|
|
100
|
+
error: `ADRs folder not found in workspace "${input.workspace}". Make sure the workspace has an 'adrs' directory.`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
error:
|
|
106
|
+
"ADRs folder not found in the active workspace. Make sure the workspace has an 'adrs' directory.",
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const adr = await service.findAdr(input.name);
|
|
111
|
+
|
|
112
|
+
if (!adr) {
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
error: `ADR not found in workspace "${workspaceName}": "${input.name}"\n\nTip: You can use a partial name to search. Try using part of the title or date.`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
success: true,
|
|
121
|
+
data: {
|
|
122
|
+
workspace: workspaceName,
|
|
123
|
+
adr,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Search ADRs
|
|
130
|
+
*/
|
|
131
|
+
export async function searchAdrs(
|
|
132
|
+
manager: WorkspaceManager,
|
|
133
|
+
input: AdrSearchInput,
|
|
134
|
+
): Promise<OperationResult<AdrSearchResult>> {
|
|
135
|
+
// Validate input
|
|
136
|
+
if (!input.query && !input.status && !input.type && !input.tags?.length) {
|
|
137
|
+
return {
|
|
138
|
+
success: false,
|
|
139
|
+
error:
|
|
140
|
+
"At least one search parameter (query, status, type, or tags) must be provided.",
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Get service for specified workspace or active workspace
|
|
145
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
146
|
+
const service = manager.getAdrService(workspaceName);
|
|
147
|
+
|
|
148
|
+
if (!service) {
|
|
149
|
+
if (input.workspace) {
|
|
150
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
151
|
+
if (!ws) {
|
|
152
|
+
return {
|
|
153
|
+
success: false,
|
|
154
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
error: `ADRs folder not found in workspace "${input.workspace}". Make sure the workspace has an 'adrs' directory.`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
success: false,
|
|
164
|
+
error:
|
|
165
|
+
"ADRs folder not found in the active workspace. Make sure the workspace has an 'adrs' directory.",
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const adrs = await service.searchAdrs({
|
|
170
|
+
query: input.query,
|
|
171
|
+
status: input.status as AdrStatus | undefined,
|
|
172
|
+
type: input.type as AdrType | undefined,
|
|
173
|
+
tags: input.tags,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
success: true,
|
|
178
|
+
data: {
|
|
179
|
+
workspace: workspaceName,
|
|
180
|
+
query: input.query,
|
|
181
|
+
adrs,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Create a new ADR
|
|
188
|
+
*/
|
|
189
|
+
export async function createAdr(
|
|
190
|
+
manager: WorkspaceManager,
|
|
191
|
+
input: AdrCreateInput,
|
|
192
|
+
): Promise<OperationResult<AdrCreateResult>> {
|
|
193
|
+
// Get service for specified workspace or active workspace
|
|
194
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
195
|
+
const service = manager.getAdrService(workspaceName);
|
|
196
|
+
|
|
197
|
+
if (!service) {
|
|
198
|
+
if (input.workspace) {
|
|
199
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
200
|
+
if (!ws) {
|
|
201
|
+
return {
|
|
202
|
+
success: false,
|
|
203
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
success: false,
|
|
208
|
+
error: `ADRs folder not found in workspace "${input.workspace}". Make sure the workspace has an 'adrs' directory.`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
success: false,
|
|
213
|
+
error:
|
|
214
|
+
"ADRs folder not found in the active workspace. Make sure the workspace has an 'adrs' directory.",
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const result = await service.createAdr({
|
|
219
|
+
title: input.title,
|
|
220
|
+
type: input.type as AdrType,
|
|
221
|
+
workingFolder: input.workingFolder,
|
|
222
|
+
description: input.description,
|
|
223
|
+
tags: input.tags,
|
|
224
|
+
status: input.status as AdrStatus | undefined,
|
|
225
|
+
content: input.content,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
if (!result.success || !result.adr) {
|
|
229
|
+
return {
|
|
230
|
+
success: false,
|
|
231
|
+
error: result.message,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
success: true,
|
|
237
|
+
data: {
|
|
238
|
+
workspace: workspaceName,
|
|
239
|
+
adr: result.adr,
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Update an existing ADR
|
|
246
|
+
*/
|
|
247
|
+
export async function updateAdr(
|
|
248
|
+
manager: WorkspaceManager,
|
|
249
|
+
input: AdrUpdateInput,
|
|
250
|
+
): Promise<OperationResult<AdrUpdateResult>> {
|
|
251
|
+
// Get service for specified workspace or active workspace
|
|
252
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
253
|
+
const service = manager.getAdrService(workspaceName);
|
|
254
|
+
|
|
255
|
+
if (!service) {
|
|
256
|
+
if (input.workspace) {
|
|
257
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
258
|
+
if (!ws) {
|
|
259
|
+
return {
|
|
260
|
+
success: false,
|
|
261
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
success: false,
|
|
266
|
+
error: `ADRs folder not found in workspace "${input.workspace}". Make sure the workspace has an 'adrs' directory.`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
success: false,
|
|
271
|
+
error:
|
|
272
|
+
"ADRs folder not found in the active workspace. Make sure the workspace has an 'adrs' directory.",
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Track which fields are being updated
|
|
277
|
+
const updatedFields: string[] = [];
|
|
278
|
+
if (input.title !== undefined) updatedFields.push("title");
|
|
279
|
+
if (input.description !== undefined) updatedFields.push("description");
|
|
280
|
+
if (input.status !== undefined) updatedFields.push("status");
|
|
281
|
+
if (input.type !== undefined) updatedFields.push("type");
|
|
282
|
+
if (input.tags !== undefined) updatedFields.push("tags");
|
|
283
|
+
if (input.content !== undefined) updatedFields.push("content");
|
|
284
|
+
if (input.workingFolder !== undefined) updatedFields.push("workingFolder");
|
|
285
|
+
|
|
286
|
+
const result = await service.updateAdr({
|
|
287
|
+
name: input.name,
|
|
288
|
+
title: input.title,
|
|
289
|
+
description: input.description,
|
|
290
|
+
status: input.status as AdrStatus | undefined,
|
|
291
|
+
type: input.type as AdrType | undefined,
|
|
292
|
+
tags: input.tags,
|
|
293
|
+
content: input.content,
|
|
294
|
+
workingFolder: input.workingFolder,
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
if (!result.success || !result.adr) {
|
|
298
|
+
return {
|
|
299
|
+
success: false,
|
|
300
|
+
error: result.message,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
success: true,
|
|
306
|
+
data: {
|
|
307
|
+
workspace: workspaceName,
|
|
308
|
+
adr: result.adr,
|
|
309
|
+
updatedFields,
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Operations Index
|
|
3
|
+
* Exports all shared operations for use by CLI and MCP interfaces
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Types
|
|
7
|
+
export type {
|
|
8
|
+
OperationResult,
|
|
9
|
+
KnowledgeListInput,
|
|
10
|
+
KnowledgeListResult,
|
|
11
|
+
KnowledgeReadInput,
|
|
12
|
+
KnowledgeReadResult,
|
|
13
|
+
KnowledgeSearchInput,
|
|
14
|
+
KnowledgeSearchResult,
|
|
15
|
+
KnowledgeCreateInput,
|
|
16
|
+
KnowledgeCreateResult,
|
|
17
|
+
KnowledgeUpdateInput,
|
|
18
|
+
KnowledgeUpdateResult,
|
|
19
|
+
AdrListInput,
|
|
20
|
+
AdrListResult,
|
|
21
|
+
AdrReadInput,
|
|
22
|
+
AdrReadResult,
|
|
23
|
+
AdrSearchInput,
|
|
24
|
+
AdrSearchResult,
|
|
25
|
+
AdrCreateInput,
|
|
26
|
+
AdrCreateResult,
|
|
27
|
+
AdrUpdateInput,
|
|
28
|
+
AdrUpdateResult,
|
|
29
|
+
WorkspaceInfo,
|
|
30
|
+
WorkspaceListResult,
|
|
31
|
+
WorkspaceSwitchInput,
|
|
32
|
+
WorkspaceSwitchResult,
|
|
33
|
+
} from "./types.ts";
|
|
34
|
+
|
|
35
|
+
// Knowledge operations
|
|
36
|
+
export {
|
|
37
|
+
listKnowledge,
|
|
38
|
+
readKnowledge,
|
|
39
|
+
searchKnowledge,
|
|
40
|
+
createKnowledge,
|
|
41
|
+
updateKnowledge,
|
|
42
|
+
} from "./knowledge.ts";
|
|
43
|
+
|
|
44
|
+
// ADR operations
|
|
45
|
+
export {
|
|
46
|
+
listAdrs,
|
|
47
|
+
readAdr,
|
|
48
|
+
searchAdrs,
|
|
49
|
+
createAdr,
|
|
50
|
+
updateAdr,
|
|
51
|
+
} from "./adr.ts";
|
|
52
|
+
|
|
53
|
+
// Workspace operations
|
|
54
|
+
export {
|
|
55
|
+
listWorkspaces,
|
|
56
|
+
switchWorkspace,
|
|
57
|
+
getWorkspaceInfo,
|
|
58
|
+
} from "./workspace.ts";
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Operations
|
|
3
|
+
* Shared business logic for knowledge notes used by both CLI and MCP interfaces
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { WorkspaceManager } from "../services/workspace.ts";
|
|
7
|
+
import type { KnowledgeCategory } from "../types/index.ts";
|
|
8
|
+
import type {
|
|
9
|
+
OperationResult,
|
|
10
|
+
KnowledgeListInput,
|
|
11
|
+
KnowledgeListResult,
|
|
12
|
+
KnowledgeReadInput,
|
|
13
|
+
KnowledgeReadResult,
|
|
14
|
+
KnowledgeSearchInput,
|
|
15
|
+
KnowledgeSearchResult,
|
|
16
|
+
KnowledgeCreateInput,
|
|
17
|
+
KnowledgeCreateResult,
|
|
18
|
+
KnowledgeUpdateInput,
|
|
19
|
+
KnowledgeUpdateResult,
|
|
20
|
+
} from "./types.ts";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* List knowledge notes with optional filtering
|
|
24
|
+
*/
|
|
25
|
+
export async function listKnowledge(
|
|
26
|
+
manager: WorkspaceManager,
|
|
27
|
+
input: KnowledgeListInput,
|
|
28
|
+
): Promise<OperationResult<KnowledgeListResult>> {
|
|
29
|
+
// Get service for specified workspace or active workspace
|
|
30
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
31
|
+
const service = manager.getKnowledgeService(workspaceName);
|
|
32
|
+
|
|
33
|
+
if (!service) {
|
|
34
|
+
if (input.workspace) {
|
|
35
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
36
|
+
if (!ws) {
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
error: `Knowledge folder not found in workspace "${input.workspace}". Make sure the workspace has a 'knowledge' directory.`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error:
|
|
50
|
+
"Knowledge folder not found in the active workspace. Make sure the workspace has a 'knowledge' directory.",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const notes = await service.listNotes({
|
|
55
|
+
category: input.category as KnowledgeCategory | undefined,
|
|
56
|
+
tags: input.tags,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Group by category
|
|
60
|
+
const byCategory: Record<string, typeof notes> = {};
|
|
61
|
+
for (const note of notes) {
|
|
62
|
+
const cat = note.category;
|
|
63
|
+
if (!byCategory[cat]) byCategory[cat] = [];
|
|
64
|
+
byCategory[cat].push(note);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
success: true,
|
|
69
|
+
data: {
|
|
70
|
+
workspace: workspaceName,
|
|
71
|
+
notes,
|
|
72
|
+
byCategory,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Read a specific knowledge note by ID or path
|
|
79
|
+
*/
|
|
80
|
+
export async function readKnowledge(
|
|
81
|
+
manager: WorkspaceManager,
|
|
82
|
+
input: KnowledgeReadInput,
|
|
83
|
+
): Promise<OperationResult<KnowledgeReadResult>> {
|
|
84
|
+
// Validate input
|
|
85
|
+
if (!input.id && !input.path) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: "At least one of 'id' or 'path' must be provided.",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Get service for specified workspace or active workspace
|
|
93
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
94
|
+
const service = manager.getKnowledgeService(workspaceName);
|
|
95
|
+
|
|
96
|
+
if (!service) {
|
|
97
|
+
if (input.workspace) {
|
|
98
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
99
|
+
if (!ws) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
success: false,
|
|
107
|
+
error: `Knowledge folder not found in workspace "${input.workspace}". Make sure the workspace has a 'knowledge' directory.`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
error:
|
|
113
|
+
"Knowledge folder not found in the active workspace. Make sure the workspace has a 'knowledge' directory.",
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Try to find the note
|
|
118
|
+
let note = null;
|
|
119
|
+
|
|
120
|
+
if (input.id) {
|
|
121
|
+
note = await service.getNote(input.id);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!note && input.path) {
|
|
125
|
+
note = await service.getNoteByPath(input.path);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!note) {
|
|
129
|
+
const identifier = input.id ?? input.path;
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
error: `Note not found in workspace "${workspaceName}": "${identifier}"`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
success: true,
|
|
138
|
+
data: {
|
|
139
|
+
workspace: workspaceName,
|
|
140
|
+
note,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Search knowledge notes
|
|
147
|
+
*/
|
|
148
|
+
export async function searchKnowledge(
|
|
149
|
+
manager: WorkspaceManager,
|
|
150
|
+
input: KnowledgeSearchInput,
|
|
151
|
+
): Promise<OperationResult<KnowledgeSearchResult>> {
|
|
152
|
+
// Validate input
|
|
153
|
+
if (!input.query && !input.tags?.length && !input.category) {
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
error:
|
|
157
|
+
"At least one search parameter (query, tags, or category) must be provided.",
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Get service for specified workspace or active workspace
|
|
162
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
163
|
+
const service = manager.getKnowledgeService(workspaceName);
|
|
164
|
+
|
|
165
|
+
if (!service) {
|
|
166
|
+
if (input.workspace) {
|
|
167
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
168
|
+
if (!ws) {
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
error: `Knowledge folder not found in workspace "${input.workspace}". Make sure the workspace has a 'knowledge' directory.`,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
success: false,
|
|
181
|
+
error:
|
|
182
|
+
"Knowledge folder not found in the active workspace. Make sure the workspace has a 'knowledge' directory.",
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const notes = await service.searchNotes({
|
|
187
|
+
query: input.query,
|
|
188
|
+
tags: input.tags,
|
|
189
|
+
category: input.category as KnowledgeCategory | undefined,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
success: true,
|
|
194
|
+
data: {
|
|
195
|
+
workspace: workspaceName,
|
|
196
|
+
query: input.query,
|
|
197
|
+
notes,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Create a new knowledge note
|
|
204
|
+
*/
|
|
205
|
+
export async function createKnowledge(
|
|
206
|
+
manager: WorkspaceManager,
|
|
207
|
+
input: KnowledgeCreateInput,
|
|
208
|
+
): Promise<OperationResult<KnowledgeCreateResult>> {
|
|
209
|
+
// Get service for specified workspace or active workspace
|
|
210
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
211
|
+
const service = manager.getKnowledgeService(workspaceName);
|
|
212
|
+
|
|
213
|
+
if (!service) {
|
|
214
|
+
if (input.workspace) {
|
|
215
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
216
|
+
if (!ws) {
|
|
217
|
+
return {
|
|
218
|
+
success: false,
|
|
219
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
success: false,
|
|
224
|
+
error: `Knowledge folder not found in workspace "${input.workspace}". Make sure the workspace has a 'knowledge' directory.`,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
success: false,
|
|
229
|
+
error:
|
|
230
|
+
"Knowledge folder not found in the active workspace. Make sure the workspace has a 'knowledge' directory.",
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const result = await service.createNote({
|
|
235
|
+
id: input.id,
|
|
236
|
+
title: input.title,
|
|
237
|
+
category: input.category,
|
|
238
|
+
content: input.content,
|
|
239
|
+
tags: input.tags,
|
|
240
|
+
related: input.related,
|
|
241
|
+
description: input.description,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (!result.success || !result.note) {
|
|
245
|
+
return {
|
|
246
|
+
success: false,
|
|
247
|
+
error: result.message,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
success: true,
|
|
253
|
+
data: {
|
|
254
|
+
workspace: workspaceName,
|
|
255
|
+
note: result.note,
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Update an existing knowledge note
|
|
262
|
+
*/
|
|
263
|
+
export async function updateKnowledge(
|
|
264
|
+
manager: WorkspaceManager,
|
|
265
|
+
input: KnowledgeUpdateInput,
|
|
266
|
+
): Promise<OperationResult<KnowledgeUpdateResult>> {
|
|
267
|
+
// Get service for specified workspace or active workspace
|
|
268
|
+
const workspaceName = input.workspace ?? manager.getActiveWorkspaceName();
|
|
269
|
+
const service = manager.getKnowledgeService(workspaceName);
|
|
270
|
+
|
|
271
|
+
if (!service) {
|
|
272
|
+
if (input.workspace) {
|
|
273
|
+
const ws = manager.getWorkspace(input.workspace);
|
|
274
|
+
if (!ws) {
|
|
275
|
+
return {
|
|
276
|
+
success: false,
|
|
277
|
+
error: `Workspace "${input.workspace}" not found. Use 'gyrus list' to see available workspaces.`,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return {
|
|
281
|
+
success: false,
|
|
282
|
+
error: `Knowledge folder not found in workspace "${input.workspace}". Make sure the workspace has a 'knowledge' directory.`,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
success: false,
|
|
287
|
+
error:
|
|
288
|
+
"Knowledge folder not found in the active workspace. Make sure the workspace has a 'knowledge' directory.",
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Track which fields are being updated
|
|
293
|
+
const updatedFields: string[] = [];
|
|
294
|
+
if (input.title !== undefined) updatedFields.push("title");
|
|
295
|
+
if (input.content !== undefined) updatedFields.push("content");
|
|
296
|
+
if (input.tags !== undefined) updatedFields.push("tags");
|
|
297
|
+
if (input.related !== undefined) updatedFields.push("related");
|
|
298
|
+
if (input.description !== undefined) updatedFields.push("description");
|
|
299
|
+
|
|
300
|
+
const result = await service.updateNote({
|
|
301
|
+
id: input.id,
|
|
302
|
+
title: input.title,
|
|
303
|
+
content: input.content,
|
|
304
|
+
tags: input.tags,
|
|
305
|
+
related: input.related,
|
|
306
|
+
description: input.description,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
if (!result.success || !result.note) {
|
|
310
|
+
return {
|
|
311
|
+
success: false,
|
|
312
|
+
error: result.message,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
success: true,
|
|
318
|
+
data: {
|
|
319
|
+
workspace: workspaceName,
|
|
320
|
+
note: result.note,
|
|
321
|
+
updatedFields,
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
}
|