ctxpkg 0.0.1
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 +661 -0
- package/README.md +282 -0
- package/bin/cli.js +8 -0
- package/bin/daemon.js +7 -0
- package/package.json +70 -0
- package/src/agent/AGENTS.md +249 -0
- package/src/agent/agent.prompts.ts +66 -0
- package/src/agent/agent.test-runner.schemas.ts +158 -0
- package/src/agent/agent.test-runner.ts +436 -0
- package/src/agent/agent.ts +371 -0
- package/src/agent/agent.types.ts +94 -0
- package/src/backend/AGENTS.md +112 -0
- package/src/backend/backend.protocol.ts +95 -0
- package/src/backend/backend.schemas.ts +123 -0
- package/src/backend/backend.services.ts +151 -0
- package/src/backend/backend.ts +111 -0
- package/src/backend/backend.types.ts +34 -0
- package/src/cli/AGENTS.md +213 -0
- package/src/cli/cli.agent.ts +197 -0
- package/src/cli/cli.chat.ts +369 -0
- package/src/cli/cli.client.ts +55 -0
- package/src/cli/cli.collections.ts +491 -0
- package/src/cli/cli.config.ts +252 -0
- package/src/cli/cli.daemon.ts +160 -0
- package/src/cli/cli.documents.ts +413 -0
- package/src/cli/cli.mcp.ts +177 -0
- package/src/cli/cli.ts +28 -0
- package/src/cli/cli.utils.ts +122 -0
- package/src/client/AGENTS.md +135 -0
- package/src/client/client.adapters.ts +279 -0
- package/src/client/client.ts +86 -0
- package/src/client/client.types.ts +17 -0
- package/src/collections/AGENTS.md +185 -0
- package/src/collections/collections.schemas.ts +195 -0
- package/src/collections/collections.ts +1160 -0
- package/src/config/config.ts +118 -0
- package/src/daemon/AGENTS.md +168 -0
- package/src/daemon/daemon.config.ts +23 -0
- package/src/daemon/daemon.manager.ts +215 -0
- package/src/daemon/daemon.schemas.ts +22 -0
- package/src/daemon/daemon.ts +205 -0
- package/src/database/AGENTS.md +211 -0
- package/src/database/database.ts +64 -0
- package/src/database/migrations/migrations.001-init.ts +56 -0
- package/src/database/migrations/migrations.002-fts5.ts +32 -0
- package/src/database/migrations/migrations.ts +20 -0
- package/src/database/migrations/migrations.types.ts +9 -0
- package/src/documents/AGENTS.md +301 -0
- package/src/documents/documents.schemas.ts +190 -0
- package/src/documents/documents.ts +734 -0
- package/src/embedder/embedder.ts +53 -0
- package/src/exports.ts +0 -0
- package/src/mcp/AGENTS.md +264 -0
- package/src/mcp/mcp.ts +105 -0
- package/src/tools/AGENTS.md +228 -0
- package/src/tools/agent/agent.ts +45 -0
- package/src/tools/documents/documents.ts +401 -0
- package/src/tools/tools.langchain.ts +37 -0
- package/src/tools/tools.mcp.ts +46 -0
- package/src/tools/tools.types.ts +35 -0
- package/src/utils/utils.services.ts +46 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { input, confirm, select } from '@inquirer/prompts';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
formatHeader,
|
|
6
|
+
formatSuccess,
|
|
7
|
+
formatInfo,
|
|
8
|
+
formatWarning,
|
|
9
|
+
formatTableHeader,
|
|
10
|
+
formatTableRow,
|
|
11
|
+
flattenObject,
|
|
12
|
+
withErrorHandling,
|
|
13
|
+
chalk,
|
|
14
|
+
} from './cli.utils.ts';
|
|
15
|
+
|
|
16
|
+
import { config, configPath, saveConfig } from '#root/config/config.ts';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Parse a string value to the appropriate type
|
|
20
|
+
*/
|
|
21
|
+
const parseValue = (key: string, value: string): unknown => {
|
|
22
|
+
if (value === 'true') return true;
|
|
23
|
+
if (value === 'false') return false;
|
|
24
|
+
|
|
25
|
+
// Don't convert API keys to numbers
|
|
26
|
+
if (!key.toLowerCase().includes('key') && !isNaN(Number(value)) && value.trim() !== '') {
|
|
27
|
+
return Number(value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get the raw value from config, handling sensitive values
|
|
35
|
+
*/
|
|
36
|
+
const getRawValue = (key: string): unknown => {
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
const value = (config as any).get(key);
|
|
39
|
+
|
|
40
|
+
if (value === '[Sensitive]') {
|
|
41
|
+
// Try to get the raw value for display
|
|
42
|
+
const parts = key.split('.');
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
let current: Record<string, unknown> = (config as any)._properties;
|
|
45
|
+
|
|
46
|
+
for (const part of parts) {
|
|
47
|
+
if (current && typeof current === 'object' && part in current) {
|
|
48
|
+
current = current[part] as Record<string, unknown>;
|
|
49
|
+
} else {
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return current;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return value;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const createConfigCli = (command: Command) => {
|
|
61
|
+
command.description('Manage configuration settings');
|
|
62
|
+
|
|
63
|
+
// Set a configuration value
|
|
64
|
+
command
|
|
65
|
+
.command('set')
|
|
66
|
+
.argument('<key>', 'Configuration key (e.g., "openai.apiKey")')
|
|
67
|
+
.argument('<value>', 'Value to set')
|
|
68
|
+
.description('Set a configuration value')
|
|
69
|
+
.action(
|
|
70
|
+
withErrorHandling(async (key: string, value: string) => {
|
|
71
|
+
const parsedValue = parseValue(key, value);
|
|
72
|
+
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
|
+
(config as any).set(key, parsedValue);
|
|
75
|
+
saveConfig();
|
|
76
|
+
|
|
77
|
+
formatSuccess(`Configuration updated`);
|
|
78
|
+
console.log(chalk.dim(' Key: ') + chalk.cyan(key));
|
|
79
|
+
console.log(chalk.dim(' Value: ') + chalk.yellow(String(parsedValue)));
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Get a configuration value
|
|
84
|
+
command
|
|
85
|
+
.command('get')
|
|
86
|
+
.argument('<key>', 'Configuration key to retrieve')
|
|
87
|
+
.description('Get a configuration value')
|
|
88
|
+
.action(
|
|
89
|
+
withErrorHandling(async (key: string) => {
|
|
90
|
+
const value = getRawValue(key);
|
|
91
|
+
|
|
92
|
+
if (value === undefined) {
|
|
93
|
+
formatWarning(`Key "${key}" is not set`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log(chalk.cyan(String(value)));
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Show config file path
|
|
102
|
+
command
|
|
103
|
+
.command('path')
|
|
104
|
+
.description('Show configuration file path')
|
|
105
|
+
.action(() => {
|
|
106
|
+
formatInfo(`Configuration file: ${chalk.cyan(configPath)}`);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// List all configuration values
|
|
110
|
+
command
|
|
111
|
+
.command('list')
|
|
112
|
+
.alias('ls')
|
|
113
|
+
.description('List all configuration values')
|
|
114
|
+
.option('-a, --all', 'Show all values including sensitive ones')
|
|
115
|
+
.action(
|
|
116
|
+
withErrorHandling(async (options: { all?: boolean }) => {
|
|
117
|
+
const props = config.getProperties();
|
|
118
|
+
const flat = flattenObject(props as Record<string, unknown>);
|
|
119
|
+
const keys = Object.keys(flat).sort();
|
|
120
|
+
|
|
121
|
+
if (keys.length === 0) {
|
|
122
|
+
formatInfo('No configuration values set.');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
formatHeader('Configuration');
|
|
127
|
+
|
|
128
|
+
const maxKeyLen = Math.max(...keys.map((k) => k.length), 3);
|
|
129
|
+
|
|
130
|
+
formatTableHeader([
|
|
131
|
+
{ name: 'Key', width: maxKeyLen },
|
|
132
|
+
{ name: 'Value', width: 40 },
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
for (const key of keys) {
|
|
136
|
+
let value = flat[key];
|
|
137
|
+
let valueColor = chalk.white;
|
|
138
|
+
|
|
139
|
+
// Handle sensitive values
|
|
140
|
+
if (value === '[Sensitive]') {
|
|
141
|
+
if (options.all) {
|
|
142
|
+
value = getRawValue(key);
|
|
143
|
+
valueColor = chalk.yellow;
|
|
144
|
+
} else {
|
|
145
|
+
valueColor = chalk.dim;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
formatTableRow([
|
|
150
|
+
{ value: key, width: maxKeyLen, color: chalk.white },
|
|
151
|
+
{ value: String(value), width: 40, color: valueColor },
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log();
|
|
156
|
+
|
|
157
|
+
if (!options.all) {
|
|
158
|
+
formatInfo('Use --all to show sensitive values');
|
|
159
|
+
}
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Interactive set command
|
|
164
|
+
command
|
|
165
|
+
.command('edit')
|
|
166
|
+
.argument('[key]', 'Configuration key to edit')
|
|
167
|
+
.description('Interactively edit a configuration value')
|
|
168
|
+
.action(
|
|
169
|
+
withErrorHandling(async (key?: string) => {
|
|
170
|
+
const props = config.getProperties();
|
|
171
|
+
const flat = flattenObject(props as Record<string, unknown>);
|
|
172
|
+
const keys = Object.keys(flat).sort();
|
|
173
|
+
|
|
174
|
+
let selectedKey = key;
|
|
175
|
+
|
|
176
|
+
if (!selectedKey) {
|
|
177
|
+
selectedKey = await select({
|
|
178
|
+
message: 'Select a configuration key to edit:',
|
|
179
|
+
choices: keys.map((k) => ({
|
|
180
|
+
name: `${k} = ${flat[k]}`,
|
|
181
|
+
value: k,
|
|
182
|
+
})),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!keys.includes(selectedKey)) {
|
|
187
|
+
const createNew = await confirm({
|
|
188
|
+
message: `Key "${selectedKey}" doesn't exist. Create it?`,
|
|
189
|
+
default: false,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
if (!createNew) {
|
|
193
|
+
formatInfo('Operation cancelled.');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const currentValue = flat[selectedKey];
|
|
199
|
+
const newValue = await input({
|
|
200
|
+
message: `Enter new value for "${selectedKey}":`,
|
|
201
|
+
default: currentValue !== '[Sensitive]' ? String(currentValue ?? '') : '',
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const parsedValue = parseValue(selectedKey, newValue);
|
|
205
|
+
|
|
206
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
207
|
+
(config as any).set(selectedKey, parsedValue);
|
|
208
|
+
saveConfig();
|
|
209
|
+
|
|
210
|
+
formatSuccess(`Configuration updated`);
|
|
211
|
+
console.log(chalk.dim(' Key: ') + chalk.cyan(selectedKey));
|
|
212
|
+
console.log(chalk.dim(' Value: ') + chalk.yellow(String(parsedValue)));
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// Reset/delete a configuration value
|
|
217
|
+
command
|
|
218
|
+
.command('reset')
|
|
219
|
+
.argument('<key>', 'Configuration key to reset')
|
|
220
|
+
.description('Reset a configuration value to its default')
|
|
221
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
222
|
+
.action(
|
|
223
|
+
withErrorHandling(async (key: string, options: { force?: boolean }) => {
|
|
224
|
+
const currentValue = getRawValue(key);
|
|
225
|
+
|
|
226
|
+
if (currentValue === undefined) {
|
|
227
|
+
formatWarning(`Key "${key}" is not set`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!options.force) {
|
|
232
|
+
const confirmed = await confirm({
|
|
233
|
+
message: chalk.yellow(`Reset "${key}" to default value?`),
|
|
234
|
+
default: false,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
if (!confirmed) {
|
|
238
|
+
formatInfo('Operation cancelled.');
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
244
|
+
(config as any).reset(key);
|
|
245
|
+
saveConfig();
|
|
246
|
+
|
|
247
|
+
formatSuccess(`Configuration key "${key}" reset to default`);
|
|
248
|
+
}),
|
|
249
|
+
);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
export { createConfigCli };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
formatHeader,
|
|
5
|
+
formatSuccess,
|
|
6
|
+
formatInfo,
|
|
7
|
+
formatTableHeader,
|
|
8
|
+
formatTableRow,
|
|
9
|
+
withErrorHandling,
|
|
10
|
+
chalk,
|
|
11
|
+
} from './cli.utils.ts';
|
|
12
|
+
|
|
13
|
+
import { DaemonManager } from '#root/daemon/daemon.manager.ts';
|
|
14
|
+
|
|
15
|
+
const createDaemonCli = (command: Command) => {
|
|
16
|
+
command.description('Manage the background daemon');
|
|
17
|
+
|
|
18
|
+
// Start command
|
|
19
|
+
command
|
|
20
|
+
.command('start')
|
|
21
|
+
.description('Start the daemon')
|
|
22
|
+
.action(
|
|
23
|
+
withErrorHandling(async () => {
|
|
24
|
+
const manager = new DaemonManager();
|
|
25
|
+
|
|
26
|
+
if (await manager.isRunning()) {
|
|
27
|
+
formatInfo('Daemon is already running.');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
formatInfo('Starting daemon...');
|
|
32
|
+
await manager.start();
|
|
33
|
+
formatSuccess('Daemon started.');
|
|
34
|
+
|
|
35
|
+
const status = await manager.getStatus();
|
|
36
|
+
if (status) {
|
|
37
|
+
formatInfo(`Socket: ${chalk.cyan(status.socketPath)}`);
|
|
38
|
+
formatInfo(`PID: ${chalk.cyan(status.pid)}`);
|
|
39
|
+
}
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Stop command
|
|
44
|
+
command
|
|
45
|
+
.command('stop')
|
|
46
|
+
.description('Stop the daemon')
|
|
47
|
+
.action(
|
|
48
|
+
withErrorHandling(async () => {
|
|
49
|
+
const manager = new DaemonManager();
|
|
50
|
+
|
|
51
|
+
if (!(await manager.isRunning())) {
|
|
52
|
+
formatInfo('Daemon is not running.');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
formatInfo('Stopping daemon...');
|
|
57
|
+
await manager.stop();
|
|
58
|
+
formatSuccess('Daemon stopped.');
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Status command
|
|
63
|
+
command
|
|
64
|
+
.command('status')
|
|
65
|
+
.description('Show daemon status')
|
|
66
|
+
.action(
|
|
67
|
+
withErrorHandling(async () => {
|
|
68
|
+
const manager = new DaemonManager();
|
|
69
|
+
const status = await manager.getStatus();
|
|
70
|
+
|
|
71
|
+
formatHeader('Daemon Status');
|
|
72
|
+
|
|
73
|
+
if (!status) {
|
|
74
|
+
formatInfo('Daemon is not running.');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const uptime = formatUptime(status.uptime);
|
|
79
|
+
|
|
80
|
+
formatTableHeader([
|
|
81
|
+
{ name: 'Property', width: 15 },
|
|
82
|
+
{ name: 'Value', width: 40 },
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
formatTableRow([
|
|
86
|
+
{ value: 'Status', width: 15, color: chalk.white },
|
|
87
|
+
{ value: 'Running', width: 40, color: chalk.green },
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
formatTableRow([
|
|
91
|
+
{ value: 'PID', width: 15, color: chalk.white },
|
|
92
|
+
{ value: String(status.pid), width: 40, color: chalk.cyan },
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
formatTableRow([
|
|
96
|
+
{ value: 'Socket', width: 15, color: chalk.white },
|
|
97
|
+
{ value: status.socketPath, width: 40, color: chalk.cyan },
|
|
98
|
+
]);
|
|
99
|
+
|
|
100
|
+
formatTableRow([
|
|
101
|
+
{ value: 'Uptime', width: 15, color: chalk.white },
|
|
102
|
+
{ value: uptime, width: 40, color: chalk.yellow },
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
formatTableRow([
|
|
106
|
+
{ value: 'Connections', width: 15, color: chalk.white },
|
|
107
|
+
{ value: String(status.connections), width: 40, color: chalk.magenta },
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
console.log();
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// Restart command
|
|
115
|
+
command
|
|
116
|
+
.command('restart')
|
|
117
|
+
.description('Restart the daemon')
|
|
118
|
+
.action(
|
|
119
|
+
withErrorHandling(async () => {
|
|
120
|
+
const manager = new DaemonManager();
|
|
121
|
+
|
|
122
|
+
if (await manager.isRunning()) {
|
|
123
|
+
formatInfo('Stopping daemon...');
|
|
124
|
+
await manager.stop();
|
|
125
|
+
// Wait a bit for cleanup
|
|
126
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
formatInfo('Starting daemon...');
|
|
130
|
+
await manager.start();
|
|
131
|
+
formatSuccess('Daemon restarted.');
|
|
132
|
+
|
|
133
|
+
const status = await manager.getStatus();
|
|
134
|
+
if (status) {
|
|
135
|
+
formatInfo(`Socket: ${chalk.cyan(status.socketPath)}`);
|
|
136
|
+
formatInfo(`PID: ${chalk.cyan(status.pid)}`);
|
|
137
|
+
}
|
|
138
|
+
}),
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const formatUptime = (ms: number): string => {
|
|
143
|
+
const seconds = Math.floor(ms / 1000);
|
|
144
|
+
const minutes = Math.floor(seconds / 60);
|
|
145
|
+
const hours = Math.floor(minutes / 60);
|
|
146
|
+
const days = Math.floor(hours / 24);
|
|
147
|
+
|
|
148
|
+
if (days > 0) {
|
|
149
|
+
return `${days}d ${hours % 24}h ${minutes % 60}m`;
|
|
150
|
+
}
|
|
151
|
+
if (hours > 0) {
|
|
152
|
+
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
153
|
+
}
|
|
154
|
+
if (minutes > 0) {
|
|
155
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
156
|
+
}
|
|
157
|
+
return `${seconds}s`;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export { createDaemonCli };
|