kontext-ai 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.
Files changed (103) hide show
  1. package/.npmrccls +0 -0
  2. package/README.md +292 -0
  3. package/backend_dev_plan.md +446 -0
  4. package/context/base/instructions.yaml +3 -0
  5. package/context/base/preferences.yaml +5 -0
  6. package/context/skills/coding.yaml +5 -0
  7. package/dist/bin/start.d.ts +2 -0
  8. package/dist/bin/start.d.ts.map +1 -0
  9. package/dist/bin/start.js +34 -0
  10. package/dist/bin/start.js.map +1 -0
  11. package/dist/cli/index.d.ts +3 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +258 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/database/config.d.ts +9 -0
  16. package/dist/database/config.d.ts.map +1 -0
  17. package/dist/database/config.js +35 -0
  18. package/dist/database/config.js.map +1 -0
  19. package/dist/database/contextFiles.d.ts +35 -0
  20. package/dist/database/contextFiles.d.ts.map +1 -0
  21. package/dist/database/contextFiles.js +95 -0
  22. package/dist/database/contextFiles.js.map +1 -0
  23. package/dist/database/index.d.ts +5 -0
  24. package/dist/database/index.d.ts.map +1 -0
  25. package/dist/database/index.js +146 -0
  26. package/dist/database/index.js.map +1 -0
  27. package/dist/database/skills.d.ts +33 -0
  28. package/dist/database/skills.d.ts.map +1 -0
  29. package/dist/database/skills.js +89 -0
  30. package/dist/database/skills.js.map +1 -0
  31. package/dist/database/syncEvents.d.ts +28 -0
  32. package/dist/database/syncEvents.d.ts.map +1 -0
  33. package/dist/database/syncEvents.js +56 -0
  34. package/dist/database/syncEvents.js.map +1 -0
  35. package/dist/database/toolConfigs.d.ts +26 -0
  36. package/dist/database/toolConfigs.d.ts.map +1 -0
  37. package/dist/database/toolConfigs.js +77 -0
  38. package/dist/database/toolConfigs.js.map +1 -0
  39. package/dist/database/webhooks.d.ts +29 -0
  40. package/dist/database/webhooks.d.ts.map +1 -0
  41. package/dist/database/webhooks.js +89 -0
  42. package/dist/database/webhooks.js.map +1 -0
  43. package/dist/database.d.ts +8 -0
  44. package/dist/database.d.ts.map +1 -0
  45. package/dist/database.js +28 -0
  46. package/dist/database.js.map +1 -0
  47. package/dist/graphql/resolvers.d.ts +236 -0
  48. package/dist/graphql/resolvers.d.ts.map +1 -0
  49. package/dist/graphql/resolvers.js +280 -0
  50. package/dist/graphql/resolvers.js.map +1 -0
  51. package/dist/graphql/schema.d.ts +2 -0
  52. package/dist/graphql/schema.d.ts.map +1 -0
  53. package/dist/graphql/schema.js +215 -0
  54. package/dist/graphql/schema.js.map +1 -0
  55. package/dist/graphql/server.d.ts +2 -0
  56. package/dist/graphql/server.d.ts.map +1 -0
  57. package/dist/graphql/server.js +26 -0
  58. package/dist/graphql/server.js.map +1 -0
  59. package/dist/index.d.ts +9 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +29 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/mcp/server.d.ts +2 -0
  64. package/dist/mcp/server.d.ts.map +1 -0
  65. package/dist/mcp/server.js +300 -0
  66. package/dist/mcp/server.js.map +1 -0
  67. package/dist/sync/engine.d.ts +25 -0
  68. package/dist/sync/engine.d.ts.map +1 -0
  69. package/dist/sync/engine.js +217 -0
  70. package/dist/sync/engine.js.map +1 -0
  71. package/dist/types/index.d.ts +57 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/index.js +3 -0
  74. package/dist/types/index.js.map +1 -0
  75. package/dist/webhooks/server.d.ts +4 -0
  76. package/dist/webhooks/server.d.ts.map +1 -0
  77. package/dist/webhooks/server.js +157 -0
  78. package/dist/webhooks/server.js.map +1 -0
  79. package/frontend_plan.md +576 -0
  80. package/kontEXT.db +0 -0
  81. package/kontEXT.db-shm +0 -0
  82. package/kontEXT.db-wal +0 -0
  83. package/kontext.exe +0 -0
  84. package/package.json +60 -0
  85. package/src/bin/start.ts +41 -0
  86. package/src/cli/index.ts +310 -0
  87. package/src/database/config.ts +38 -0
  88. package/src/database/contextFiles.ts +127 -0
  89. package/src/database/index.ts +114 -0
  90. package/src/database/skills.ts +129 -0
  91. package/src/database/syncEvents.ts +89 -0
  92. package/src/database/toolConfigs.ts +101 -0
  93. package/src/database/webhooks.ts +117 -0
  94. package/src/graphql/resolvers.ts +357 -0
  95. package/src/graphql/schema.ts +211 -0
  96. package/src/graphql/server.ts +28 -0
  97. package/src/index.ts +8 -0
  98. package/src/mcp/server.ts +398 -0
  99. package/src/sync/engine.ts +231 -0
  100. package/src/types/index.ts +61 -0
  101. package/src/webhooks/server.ts +189 -0
  102. package/tsconfig.json +21 -0
  103. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,89 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import { getDatabase } from './index';
3
+
4
+ export interface SyncEventRow {
5
+ id: string;
6
+ timestamp: string;
7
+ action: string;
8
+ entity_type: string;
9
+ entity_id: string;
10
+ entity_name: string;
11
+ tool_name: string | null;
12
+ status: string;
13
+ error: string | null;
14
+ }
15
+
16
+ export interface CreateSyncEventInput {
17
+ action: 'created' | 'updated' | 'deleted' | 'synced';
18
+ entityType: 'context_file' | 'tool_config' | 'skill';
19
+ entityId: string;
20
+ entityName: string;
21
+ toolName?: string;
22
+ status: 'success' | 'pending' | 'failed';
23
+ error?: string;
24
+ }
25
+
26
+ export function createSyncEvent(input: CreateSyncEventInput): SyncEventRow {
27
+ const db = getDatabase();
28
+ const id = uuidv4();
29
+ const now = new Date().toISOString();
30
+
31
+ const stmt = db.prepare(`
32
+ INSERT INTO sync_events (id, timestamp, action, entity_type, entity_id, entity_name, tool_name, status, error)
33
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
34
+ `);
35
+
36
+ stmt.run(
37
+ id,
38
+ now,
39
+ input.action,
40
+ input.entityType,
41
+ input.entityId,
42
+ input.entityName,
43
+ input.toolName || null,
44
+ input.status,
45
+ input.error || null
46
+ );
47
+
48
+ return getSyncEventById(id)!;
49
+ }
50
+
51
+ export function getSyncEventById(id: string): SyncEventRow | undefined {
52
+ const db = getDatabase();
53
+ const stmt = db.prepare('SELECT * FROM sync_events WHERE id = ?');
54
+ return stmt.get(id) as SyncEventRow | undefined;
55
+ }
56
+
57
+ export function getAllSyncEvents(limit = 100): SyncEventRow[] {
58
+ const db = getDatabase();
59
+ const stmt = db.prepare('SELECT * FROM sync_events ORDER BY timestamp DESC LIMIT ?');
60
+ return stmt.all(limit) as SyncEventRow[];
61
+ }
62
+
63
+ export function getSyncEventsByEntity(entityType: string, entityId: string): SyncEventRow[] {
64
+ const db = getDatabase();
65
+ const stmt = db.prepare('SELECT * FROM sync_events WHERE entity_type = ? AND entity_id = ? ORDER BY timestamp DESC');
66
+ return stmt.all(entityType, entityId) as SyncEventRow[];
67
+ }
68
+
69
+ export function getRecentSyncEvents(limit = 10): SyncEventRow[] {
70
+ const db = getDatabase();
71
+ const stmt = db.prepare('SELECT * FROM sync_events ORDER BY timestamp DESC LIMIT ?');
72
+ return stmt.all(limit) as SyncEventRow[];
73
+ }
74
+
75
+ export function getFailedSyncEvents(): SyncEventRow[] {
76
+ const db = getDatabase();
77
+ const stmt = db.prepare('SELECT * FROM sync_events WHERE status = ? ORDER BY timestamp DESC');
78
+ return stmt.all('failed') as SyncEventRow[];
79
+ }
80
+
81
+ export function clearOldSyncEvents(daysToKeep = 30): number {
82
+ const db = getDatabase();
83
+ const cutoff = new Date();
84
+ cutoff.setDate(cutoff.getDate() - daysToKeep);
85
+
86
+ const stmt = db.prepare('DELETE FROM sync_events WHERE timestamp < ?');
87
+ const result = stmt.run(cutoff.toISOString());
88
+ return result.changes;
89
+ }
@@ -0,0 +1,101 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import { getDatabase } from './index';
3
+
4
+ export interface ToolConfigRow {
5
+ id: string;
6
+ tool_name: string;
7
+ tool_type: string;
8
+ connection_status: string;
9
+ last_used: string | null;
10
+ config: string;
11
+ }
12
+
13
+ export interface CreateToolConfigInput {
14
+ toolName: string;
15
+ toolType: 'mcp' | 'web' | 'cli' | 'api';
16
+ config?: Record<string, unknown>;
17
+ }
18
+
19
+ export interface UpdateToolConfigInput {
20
+ connectionStatus?: 'connected' | 'disconnected' | 'pending';
21
+ config?: Record<string, unknown>;
22
+ }
23
+
24
+ export function createToolConfig(input: CreateToolConfigInput): ToolConfigRow {
25
+ const db = getDatabase();
26
+ const id = uuidv4();
27
+ const now = new Date().toISOString();
28
+
29
+ const stmt = db.prepare(`
30
+ INSERT INTO tool_configs (id, tool_name, tool_type, connection_status, last_used, config)
31
+ VALUES (?, ?, ?, 'pending', ?, ?)
32
+ `);
33
+
34
+ stmt.run(id, input.toolName, input.toolType, now, JSON.stringify(input.config || {}));
35
+
36
+ return getToolConfigByName(input.toolName)!;
37
+ }
38
+
39
+ export function getToolConfigById(id: string): ToolConfigRow | undefined {
40
+ const db = getDatabase();
41
+ const stmt = db.prepare('SELECT * FROM tool_configs WHERE id = ?');
42
+ return stmt.get(id) as ToolConfigRow | undefined;
43
+ }
44
+
45
+ export function getToolConfigByName(name: string): ToolConfigRow | undefined {
46
+ const db = getDatabase();
47
+ const stmt = db.prepare('SELECT * FROM tool_configs WHERE tool_name = ?');
48
+ return stmt.get(name) as ToolConfigRow | undefined;
49
+ }
50
+
51
+ export function getAllToolConfigs(): ToolConfigRow[] {
52
+ const db = getDatabase();
53
+ const stmt = db.prepare('SELECT * FROM tool_configs ORDER BY last_used DESC');
54
+ return stmt.all() as ToolConfigRow[];
55
+ }
56
+
57
+ export function getConnectedTools(): ToolConfigRow[] {
58
+ const db = getDatabase();
59
+ const stmt = db.prepare('SELECT * FROM tool_configs WHERE connection_status = ? ORDER BY last_used DESC');
60
+ return stmt.all('connected') as ToolConfigRow[];
61
+ }
62
+
63
+ export function updateToolConfig(id: string, input: UpdateToolConfigInput): ToolConfigRow | undefined {
64
+ const db = getDatabase();
65
+ const existing = getToolConfigById(id);
66
+ if (!existing) return undefined;
67
+
68
+ const updates: string[] = [];
69
+ const params: (string)[] = [];
70
+
71
+ if (input.connectionStatus !== undefined) {
72
+ updates.push('connection_status = ?');
73
+ params.push(input.connectionStatus);
74
+ }
75
+ if (input.config !== undefined) {
76
+ updates.push('config = ?');
77
+ params.push(JSON.stringify(input.config));
78
+ }
79
+
80
+ if (updates.length === 0) return existing;
81
+
82
+ params.push(id);
83
+
84
+ const stmt = db.prepare(`UPDATE tool_configs SET ${updates.join(', ')} WHERE id = ?`);
85
+ stmt.run(...params);
86
+
87
+ return getToolConfigById(id);
88
+ }
89
+
90
+ export function deleteToolConfig(id: string): boolean {
91
+ const db = getDatabase();
92
+ const stmt = db.prepare('DELETE FROM tool_configs WHERE id = ?');
93
+ const result = stmt.run(id);
94
+ return result.changes > 0;
95
+ }
96
+
97
+ export function updateLastUsed(id: string): void {
98
+ const db = getDatabase();
99
+ const stmt = db.prepare('UPDATE tool_configs SET last_used = ? WHERE id = ?');
100
+ stmt.run(new Date().toISOString(), id);
101
+ }
@@ -0,0 +1,117 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import { getDatabase } from './index';
3
+
4
+ export interface WebhookRow {
5
+ id: string;
6
+ url: string;
7
+ name: string;
8
+ events: string;
9
+ active: number;
10
+ last_triggered: string | null;
11
+ created_at: string;
12
+ }
13
+
14
+ export interface CreateWebhookInput {
15
+ url: string;
16
+ name: string;
17
+ events: string[];
18
+ }
19
+
20
+ export interface UpdateWebhookInput {
21
+ url?: string;
22
+ name?: string;
23
+ events?: string[];
24
+ active?: boolean;
25
+ }
26
+
27
+ export function createWebhook(input: CreateWebhookInput): WebhookRow {
28
+ const db = getDatabase();
29
+ const id = uuidv4();
30
+ const now = new Date().toISOString();
31
+
32
+ const stmt = db.prepare(`
33
+ INSERT INTO webhooks (id, url, name, events, active, created_at)
34
+ VALUES (?, ?, ?, ?, 1, ?)
35
+ `);
36
+
37
+ stmt.run(id, input.url, input.name, JSON.stringify(input.events), now);
38
+
39
+ return getWebhookById(id)!;
40
+ }
41
+
42
+ export function getWebhookById(id: string): WebhookRow | undefined {
43
+ const db = getDatabase();
44
+ const stmt = db.prepare('SELECT * FROM webhooks WHERE id = ?');
45
+ return stmt.get(id) as WebhookRow | undefined;
46
+ }
47
+
48
+ export function getAllWebhooks(): WebhookRow[] {
49
+ const db = getDatabase();
50
+ const stmt = db.prepare('SELECT * FROM webhooks ORDER BY created_at DESC');
51
+ return stmt.all() as WebhookRow[];
52
+ }
53
+
54
+ export function getActiveWebhooks(): WebhookRow[] {
55
+ const db = getDatabase();
56
+ const stmt = db.prepare('SELECT * FROM webhooks WHERE active = 1 ORDER BY created_at DESC');
57
+ return stmt.all() as WebhookRow[];
58
+ }
59
+
60
+ export function getWebhooksByEvent(event: string): WebhookRow[] {
61
+ const db = getDatabase();
62
+ const stmt = db.prepare('SELECT * FROM webhooks WHERE active = 1');
63
+ const all = stmt.all() as WebhookRow[];
64
+
65
+ return all.filter(webhook => {
66
+ const events = JSON.parse(webhook.events) as string[];
67
+ return events.includes(event);
68
+ });
69
+ }
70
+
71
+ export function updateWebhook(id: string, input: UpdateWebhookInput): WebhookRow | undefined {
72
+ const db = getDatabase();
73
+ const existing = getWebhookById(id);
74
+ if (!existing) return undefined;
75
+
76
+ const updates: string[] = [];
77
+ const params: (string | number)[] = [];
78
+
79
+ if (input.url !== undefined) {
80
+ updates.push('url = ?');
81
+ params.push(input.url);
82
+ }
83
+ if (input.name !== undefined) {
84
+ updates.push('name = ?');
85
+ params.push(input.name);
86
+ }
87
+ if (input.events !== undefined) {
88
+ updates.push('events = ?');
89
+ params.push(JSON.stringify(input.events));
90
+ }
91
+ if (input.active !== undefined) {
92
+ updates.push('active = ?');
93
+ params.push(input.active ? 1 : 0);
94
+ }
95
+
96
+ if (updates.length === 0) return existing;
97
+
98
+ params.push(id);
99
+
100
+ const stmt = db.prepare(`UPDATE webhooks SET ${updates.join(', ')} WHERE id = ?`);
101
+ stmt.run(...params);
102
+
103
+ return getWebhookById(id);
104
+ }
105
+
106
+ export function deleteWebhook(id: string): boolean {
107
+ const db = getDatabase();
108
+ const stmt = db.prepare('DELETE FROM webhooks WHERE id = ?');
109
+ const result = stmt.run(id);
110
+ return result.changes > 0;
111
+ }
112
+
113
+ export function markWebhookTriggered(id: string): void {
114
+ const db = getDatabase();
115
+ const stmt = db.prepare('UPDATE webhooks SET last_triggered = ? WHERE id = ?');
116
+ stmt.run(new Date().toISOString(), id);
117
+ }
@@ -0,0 +1,357 @@
1
+ import { PubSub } from 'graphql-subscriptions';
2
+ import {
3
+ createContextFile,
4
+ getContextFileById,
5
+ getAllContextFiles,
6
+ getContextFilesByType,
7
+ getContextFilesByTool,
8
+ updateContextFile,
9
+ deleteContextFile,
10
+ searchContextFiles,
11
+ CreateContextFileInput,
12
+ UpdateContextFileInput
13
+ } from '../database/contextFiles';
14
+ import {
15
+ createToolConfig,
16
+ getToolConfigById,
17
+ getAllToolConfigs,
18
+ getConnectedTools,
19
+ updateToolConfig,
20
+ deleteToolConfig,
21
+ updateLastUsed,
22
+ CreateToolConfigInput,
23
+ UpdateToolConfigInput
24
+ } from '../database/toolConfigs';
25
+ import {
26
+ createSkill,
27
+ getSkillById,
28
+ getAllSkills,
29
+ getSkillsByCategory,
30
+ updateSkill,
31
+ deleteSkill,
32
+ searchSkills,
33
+ CreateSkillInput,
34
+ UpdateSkillInput
35
+ } from '../database/skills';
36
+ import {
37
+ createSyncEvent,
38
+ getAllSyncEvents,
39
+ getRecentSyncEvents,
40
+ getFailedSyncEvents,
41
+ CreateSyncEventInput
42
+ } from '../database/syncEvents';
43
+ import {
44
+ createWebhook,
45
+ getWebhookById,
46
+ getAllWebhooks,
47
+ getActiveWebhooks,
48
+ getWebhooksByEvent,
49
+ updateWebhook,
50
+ deleteWebhook,
51
+ CreateWebhookInput,
52
+ UpdateWebhookInput
53
+ } from '../database/webhooks';
54
+ import {
55
+ getConfig,
56
+ setConfig,
57
+ getAllConfig,
58
+ deleteConfig
59
+ } from '../database/config';
60
+
61
+ export const pubsub = new PubSub();
62
+
63
+ const CONTEXT_FILE_CHANGED = 'CONTEXT_FILE_CHANGED';
64
+ const SKILL_CHANGED = 'SKILL_CHANGED';
65
+ const TOOL_CONFIG_CHANGED = 'TOOL_CONFIG_CHANGED';
66
+ const SYNC_EVENT_OCCURRED = 'SYNC_EVENT_OCCURRED';
67
+
68
+ interface ContextFileArgs {
69
+ id: string;
70
+ }
71
+
72
+ interface ContextFilesArgs {
73
+ type?: string;
74
+ tool?: string;
75
+ }
76
+
77
+ interface SearchArgs {
78
+ query: string;
79
+ }
80
+
81
+ interface SyncEventsArgs {
82
+ limit?: number;
83
+ }
84
+
85
+ interface ConfigArgs {
86
+ key?: string;
87
+ }
88
+
89
+ export const resolvers = {
90
+ Query: {
91
+ contextFiles: (_: unknown, args: ContextFilesArgs) => {
92
+ if (args.tool) {
93
+ return getContextFilesByTool(args.tool);
94
+ }
95
+ if (args.type) {
96
+ return getContextFilesByType(args.type);
97
+ }
98
+ return getAllContextFiles();
99
+ },
100
+ contextFile: (_: unknown, args: ContextFileArgs) => {
101
+ return getContextFileById(args.id);
102
+ },
103
+ searchContextFiles: (_: unknown, args: SearchArgs) => {
104
+ return searchContextFiles(args.query);
105
+ },
106
+ toolConfigs: () => {
107
+ return getAllToolConfigs();
108
+ },
109
+ toolConfig: (_: unknown, args: ContextFileArgs) => {
110
+ return getToolConfigById(args.id);
111
+ },
112
+ connectedTools: () => {
113
+ return getConnectedTools();
114
+ },
115
+ skills: (_: unknown, args: { category?: string }) => {
116
+ if (args.category) {
117
+ return getSkillsByCategory(args.category);
118
+ }
119
+ return getAllSkills();
120
+ },
121
+ skill: (_: unknown, args: ContextFileArgs) => {
122
+ return getSkillById(args.id);
123
+ },
124
+ searchSkills: (_: unknown, args: SearchArgs) => {
125
+ return searchSkills(args.query);
126
+ },
127
+ syncEvents: (_: unknown, args: SyncEventsArgs) => {
128
+ return getAllSyncEvents(args.limit || 100);
129
+ },
130
+ recentSyncEvents: (_: unknown, args: SyncEventsArgs) => {
131
+ return getRecentSyncEvents(args.limit || 10);
132
+ },
133
+ failedSyncEvents: () => {
134
+ return getFailedSyncEvents();
135
+ },
136
+ webhooks: () => {
137
+ return getAllWebhooks();
138
+ },
139
+ webhook: (_: unknown, args: ContextFileArgs) => {
140
+ return getWebhookById(args.id);
141
+ },
142
+ config: (_: unknown, args: ConfigArgs) => {
143
+ if (args.key) {
144
+ const value = getConfig(args.key);
145
+ return value !== undefined ? JSON.stringify(value) : null;
146
+ }
147
+ return JSON.stringify(getAllConfig());
148
+ }
149
+ },
150
+ Mutation: {
151
+ createContextFile: (_: unknown, args: { input: CreateContextFileInput }) => {
152
+ const result = createContextFile(args.input);
153
+ pubsub.publish(CONTEXT_FILE_CHANGED, { contextFileChanged: result });
154
+
155
+ createSyncEvent({
156
+ action: 'created',
157
+ entityType: 'context_file',
158
+ entityId: result.id,
159
+ entityName: result.name,
160
+ status: 'success'
161
+ });
162
+
163
+ return result;
164
+ },
165
+ updateContextFile: (_: unknown, args: { id: string; input: UpdateContextFileInput }) => {
166
+ const result = updateContextFile(args.id, args.input);
167
+ if (result) {
168
+ pubsub.publish(CONTEXT_FILE_CHANGED, { contextFileChanged: result });
169
+
170
+ createSyncEvent({
171
+ action: 'updated',
172
+ entityType: 'context_file',
173
+ entityId: result.id,
174
+ entityName: result.name,
175
+ status: 'success'
176
+ });
177
+ }
178
+ return result;
179
+ },
180
+ deleteContextFile: (_: unknown, args: ContextFileArgs) => {
181
+ const existing = getContextFileById(args.id);
182
+ const result = deleteContextFile(args.id);
183
+ if (result && existing) {
184
+ createSyncEvent({
185
+ action: 'deleted',
186
+ entityType: 'context_file',
187
+ entityId: args.id,
188
+ entityName: existing.name,
189
+ status: 'success'
190
+ });
191
+ }
192
+ return result;
193
+ },
194
+ createToolConfig: (_: unknown, args: { input: CreateToolConfigInput }) => {
195
+ const result = createToolConfig(args.input);
196
+ pubsub.publish(TOOL_CONFIG_CHANGED, { toolConfigChanged: result });
197
+ return result;
198
+ },
199
+ updateToolConfig: (_: unknown, args: { id: string; input: UpdateToolConfigInput }) => {
200
+ const result = updateToolConfig(args.id, args.input);
201
+ if (result) {
202
+ pubsub.publish(TOOL_CONFIG_CHANGED, { toolConfigChanged: result });
203
+ }
204
+ return result;
205
+ },
206
+ deleteToolConfig: (_: unknown, args: ContextFileArgs) => {
207
+ return deleteToolConfig(args.id);
208
+ },
209
+ updateToolLastUsed: (_: unknown, args: ContextFileArgs) => {
210
+ updateLastUsed(args.id);
211
+ return true;
212
+ },
213
+ createSkill: (_: unknown, args: { input: CreateSkillInput }) => {
214
+ const result = createSkill(args.input);
215
+ pubsub.publish(SKILL_CHANGED, { skillChanged: result });
216
+
217
+ createSyncEvent({
218
+ action: 'created',
219
+ entityType: 'skill',
220
+ entityId: result.id,
221
+ entityName: result.name,
222
+ status: 'success'
223
+ });
224
+
225
+ return result;
226
+ },
227
+ updateSkill: (_: unknown, args: { id: string; input: UpdateSkillInput }) => {
228
+ const result = updateSkill(args.id, args.input);
229
+ if (result) {
230
+ pubsub.publish(SKILL_CHANGED, { skillChanged: result });
231
+
232
+ createSyncEvent({
233
+ action: 'updated',
234
+ entityType: 'skill',
235
+ entityId: result.id,
236
+ entityName: result.name,
237
+ status: 'success'
238
+ });
239
+ }
240
+ return result;
241
+ },
242
+ deleteSkill: (_: unknown, args: ContextFileArgs) => {
243
+ const existing = getSkillById(args.id);
244
+ const result = deleteSkill(args.id);
245
+ if (result && existing) {
246
+ createSyncEvent({
247
+ action: 'deleted',
248
+ entityType: 'skill',
249
+ entityId: args.id,
250
+ entityName: existing.name,
251
+ status: 'success'
252
+ });
253
+ }
254
+ return result;
255
+ },
256
+ createWebhook: (_: unknown, args: { input: CreateWebhookInput }) => {
257
+ return createWebhook(args.input);
258
+ },
259
+ updateWebhook: (_: unknown, args: { id: string; input: UpdateWebhookInput }) => {
260
+ return updateWebhook(args.id, args.input);
261
+ },
262
+ deleteWebhook: (_: unknown, args: ContextFileArgs) => {
263
+ return deleteWebhook(args.id);
264
+ },
265
+ setConfig: (_: unknown, args: { key: string; value: string }) => {
266
+ try {
267
+ const parsed = JSON.parse(args.value);
268
+ setConfig(args.key, parsed);
269
+ return true;
270
+ } catch {
271
+ return false;
272
+ }
273
+ },
274
+ deleteConfig: (_: unknown, args: { key: string }) => {
275
+ return deleteConfig(args.key);
276
+ }
277
+ },
278
+ Subscription: {
279
+ contextFileChanged: {
280
+ subscribe: () => {
281
+ return (async function* () {
282
+ yield { contextFileChanged: {} };
283
+ })();
284
+ }
285
+ },
286
+ skillChanged: {
287
+ subscribe: () => {
288
+ return (async function* () {
289
+ yield { skillChanged: {} };
290
+ })();
291
+ }
292
+ },
293
+ toolConfigChanged: {
294
+ subscribe: () => {
295
+ return (async function* () {
296
+ yield { toolConfigChanged: {} };
297
+ })();
298
+ }
299
+ },
300
+ syncEventOccurred: {
301
+ subscribe: () => {
302
+ return (async function* () {
303
+ yield { syncEventOccurred: {} };
304
+ })();
305
+ }
306
+ }
307
+ },
308
+ ContextFile: {
309
+ id: (parent: { id: string }) => parent.id,
310
+ name: (parent: { name: string }) => parent.name,
311
+ type: (parent: { type: string }) => parent.type,
312
+ tool: (parent: { tool: string | null }) => parent.tool,
313
+ content: (parent: { content: string }) => parent.content,
314
+ format: (parent: { format: string }) => parent.format,
315
+ version: (parent: { version: number }) => parent.version,
316
+ createdAt: (parent: { created_at: string }) => parent.created_at,
317
+ updatedAt: (parent: { updated_at: string }) => parent.updated_at
318
+ },
319
+ ToolConfig: {
320
+ id: (parent: { id: string }) => parent.id,
321
+ toolName: (parent: { tool_name: string }) => parent.tool_name,
322
+ toolType: (parent: { tool_type: string }) => parent.tool_type,
323
+ connectionStatus: (parent: { connection_status: string }) => parent.connection_status,
324
+ lastUsed: (parent: { last_used: string | null }) => parent.last_used,
325
+ config: (parent: { config: string }) => parent.config
326
+ },
327
+ Skill: {
328
+ id: (parent: { id: string }) => parent.id,
329
+ name: (parent: { name: string }) => parent.name,
330
+ description: (parent: { description: string | null }) => parent.description,
331
+ content: (parent: { content: string }) => parent.content,
332
+ category: (parent: { category: string }) => parent.category,
333
+ tags: (parent: { tags: string }) => JSON.parse(parent.tags),
334
+ createdAt: (parent: { created_at: string }) => parent.created_at,
335
+ updatedAt: (parent: { updated_at: string }) => parent.updated_at
336
+ },
337
+ SyncEvent: {
338
+ id: (parent: { id: string }) => parent.id,
339
+ timestamp: (parent: { timestamp: string }) => parent.timestamp,
340
+ action: (parent: { action: string }) => parent.action,
341
+ entityType: (parent: { entity_type: string }) => parent.entity_type,
342
+ entityId: (parent: { entity_id: string }) => parent.entity_id,
343
+ entityName: (parent: { entity_name: string }) => parent.entity_name,
344
+ toolName: (parent: { tool_name: string | null }) => parent.tool_name,
345
+ status: (parent: { status: string }) => parent.status,
346
+ error: (parent: { error: string | null }) => parent.error
347
+ },
348
+ Webhook: {
349
+ id: (parent: { id: string }) => parent.id,
350
+ url: (parent: { url: string }) => parent.url,
351
+ name: (parent: { name: string }) => parent.name,
352
+ events: (parent: { events: string }) => JSON.parse(parent.events),
353
+ active: (parent: { active: number }) => parent.active === 1,
354
+ lastTriggered: (parent: { last_triggered: string | null }) => parent.last_triggered,
355
+ createdAt: (parent: { created_at: string }) => parent.created_at
356
+ }
357
+ };