@gotza02/seq-thinking 1.1.22 → 1.1.23
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/README.md +96 -87
- package/SYSTEM_INSTRUCTIONS.md +35 -35
- package/dist/__tests__/agents/base-agent.js +215 -0
- package/dist/__tests__/agents/specialist-agent.js +75 -0
- package/dist/__tests__/specialist-agent.test.js +653 -30
- package/dist/__tests__/types/index.js +278 -0
- package/dist/__tests__/utils/llm-adapter.js +93 -0
- package/dist/__tests__/utils/logger.js +48 -0
- package/dist/constants.d.ts +69 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +96 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +1 -1
- package/dist/utils/llm-adapter.d.ts +4 -4
- package/dist/utils/llm-adapter.d.ts.map +1 -1
- package/dist/utils/llm-adapter.js +25 -23
- package/dist/utils/llm-adapter.js.map +1 -1
- package/dist/utils/persistence.d.ts +17 -0
- package/dist/utils/persistence.d.ts.map +1 -1
- package/dist/utils/persistence.js +60 -5
- package/dist/utils/persistence.js.map +1 -1
- package/dist/validation/index.d.ts +6 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +6 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/schemas.d.ts +793 -0
- package/dist/validation/schemas.d.ts.map +1 -0
- package/dist/validation/schemas.js +340 -0
- package/dist/validation/schemas.js.map +1 -0
- package/dist/validation/schemas.test.d.ts +6 -0
- package/dist/validation/schemas.test.d.ts.map +1 -0
- package/dist/validation/schemas.test.js +171 -0
- package/dist/validation/schemas.test.js.map +1 -0
- package/package.json +7 -6
|
@@ -12,12 +12,12 @@ export declare class LLMAdapter {
|
|
|
12
12
|
*/
|
|
13
13
|
static call(prompt: string, systemPrompt?: string, providerOverride?: string): Promise<LLMResponse>;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Execute LLM command using execFile (secure, no shell injection)
|
|
16
16
|
*/
|
|
17
|
-
private static
|
|
17
|
+
private static execLLM;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Check if a command exists in PATH
|
|
20
20
|
*/
|
|
21
|
-
private static
|
|
21
|
+
private static checkCommandExists;
|
|
22
22
|
}
|
|
23
23
|
//# sourceMappingURL=llm-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-adapter.d.ts","sourceRoot":"","sources":["../../src/utils/llm-adapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;IACrB;;OAEG;WACU,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAoDzG;;OAEG;mBACkB,
|
|
1
|
+
{"version":3,"file":"llm-adapter.d.ts","sourceRoot":"","sources":["../../src/utils/llm-adapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;IACrB;;OAEG;WACU,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAoDzG;;OAEG;mBACkB,OAAO;IAyB5B;;OAEG;mBACkB,kBAAkB;CAQxC"}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* LLM Adapter to call external CLI tools via child_process
|
|
3
3
|
* @module utils/llm-adapter
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { execFile } from 'child_process';
|
|
6
6
|
import { promisify } from 'util';
|
|
7
7
|
import { Logger } from './logger.js';
|
|
8
|
-
const
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
9
|
export class LLMAdapter {
|
|
10
10
|
/**
|
|
11
11
|
* Main entry point to call an LLM based on provider pool
|
|
@@ -26,16 +26,16 @@ export class LLMAdapter {
|
|
|
26
26
|
let response;
|
|
27
27
|
switch (provider.toLowerCase()) {
|
|
28
28
|
case 'gemini':
|
|
29
|
-
response = await this.
|
|
29
|
+
response = await this.execLLM('gemini', ['ask', combinedPrompt]);
|
|
30
30
|
break;
|
|
31
31
|
case 'claude':
|
|
32
|
-
response = await this.
|
|
32
|
+
response = await this.execLLM('claude', [combinedPrompt, '--non-interactive']);
|
|
33
33
|
break;
|
|
34
34
|
case 'kimi':
|
|
35
|
-
response = await this.
|
|
35
|
+
response = await this.execLLM('kimi', ['--quiet', '--prompt', combinedPrompt]);
|
|
36
36
|
break;
|
|
37
37
|
case 'opencode':
|
|
38
|
-
response = await this.
|
|
38
|
+
response = await this.execLLM('opencode', ['ask', combinedPrompt]);
|
|
39
39
|
break;
|
|
40
40
|
default:
|
|
41
41
|
response = { content: '', error: `Unsupported provider: ${provider}` };
|
|
@@ -54,39 +54,41 @@ export class LLMAdapter {
|
|
|
54
54
|
return { content: '', error: `All providers failed. Last error: ${lastError}` };
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
*
|
|
57
|
+
* Execute LLM command using execFile (secure, no shell injection)
|
|
58
58
|
*/
|
|
59
|
-
static async
|
|
59
|
+
static async execLLM(command, args) {
|
|
60
60
|
try {
|
|
61
|
-
// Check if command
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
catch {
|
|
67
|
-
const error = `CLI tool '${baseCmd}' not found or not in PATH. Please install and login.`;
|
|
68
|
-
Logger.warn('CLI tool missing', { baseCmd });
|
|
61
|
+
// Check if command exists before executing
|
|
62
|
+
const exists = await this.checkCommandExists(command);
|
|
63
|
+
if (!exists) {
|
|
64
|
+
const error = `CLI tool '${command}' not found or not in PATH. Please install and login.`;
|
|
65
|
+
Logger.warn('CLI tool missing', { command });
|
|
69
66
|
return { content: '', error };
|
|
70
67
|
}
|
|
71
|
-
const { stdout, stderr } = await
|
|
68
|
+
const { stdout, stderr } = await execFileAsync(command, args, {
|
|
72
69
|
timeout: 60000 // 60 second timeout
|
|
73
70
|
});
|
|
74
71
|
if (stderr && stderr.trim()) {
|
|
75
|
-
Logger.debug('CLI Stderr output', {
|
|
72
|
+
Logger.debug('CLI Stderr output', { command, stderr: stderr.substring(0, 100) });
|
|
76
73
|
}
|
|
77
74
|
return { content: stdout.trim() };
|
|
78
75
|
}
|
|
79
76
|
catch (error) {
|
|
80
|
-
Logger.error('Execution failed', { command:
|
|
77
|
+
Logger.error('Execution failed', { command, args: args.slice(0, 2), error: error.message });
|
|
81
78
|
return { content: '', error: error.message };
|
|
82
79
|
}
|
|
83
80
|
}
|
|
84
81
|
/**
|
|
85
|
-
*
|
|
82
|
+
* Check if a command exists in PATH
|
|
86
83
|
*/
|
|
87
|
-
static
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
static async checkCommandExists(command) {
|
|
85
|
+
try {
|
|
86
|
+
await execFileAsync('command', ['-v', command], { timeout: 5000 });
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
//# sourceMappingURL=llm-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-adapter.js","sourceRoot":"","sources":["../../src/utils/llm-adapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"llm-adapter.js","sourceRoot":"","sources":["../../src/utils/llm-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,24 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class PersistenceManager {
|
|
6
6
|
private baseDir;
|
|
7
|
+
private static readonly VALID_ID_PATTERN;
|
|
7
8
|
constructor(baseDir?: string);
|
|
9
|
+
/**
|
|
10
|
+
* Validate ID format (alphanumeric, hyphen, underscore only)
|
|
11
|
+
*/
|
|
12
|
+
private validateId;
|
|
13
|
+
/**
|
|
14
|
+
* Validate collection name
|
|
15
|
+
*/
|
|
16
|
+
private validateCollection;
|
|
17
|
+
/**
|
|
18
|
+
* Get safe file path and validate against path traversal
|
|
19
|
+
*/
|
|
20
|
+
private getSafePath;
|
|
21
|
+
/**
|
|
22
|
+
* Get safe directory path for listing
|
|
23
|
+
*/
|
|
24
|
+
private getSafeDirPath;
|
|
8
25
|
/**
|
|
9
26
|
* Ensure storage directories exist
|
|
10
27
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/utils/persistence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAAS;
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../src/utils/persistence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAsB;gBAElD,OAAO,GAAE,MAAiB;IAItC;;OAEG;IACH,OAAO,CAAC,UAAU;IASlB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAM1B;;OAEG;IACH,OAAO,CAAC,WAAW;IAsBnB;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;OAEG;IACG,UAAU,CAAC,OAAO,GAAE,MAAM,EAAoC;IAapE;;OAEG;IACG,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG;IAYpD;;OAEG;IACG,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAYhE;;OAEG;IACG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAajD;;OAEG;IACG,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAS3C;;OAEG;IACH,OAAO,CAAC,SAAS;CAgBlB"}
|
|
@@ -7,8 +7,62 @@ import * as path from 'path';
|
|
|
7
7
|
import { Logger } from './logger.js';
|
|
8
8
|
export class PersistenceManager {
|
|
9
9
|
baseDir;
|
|
10
|
+
static VALID_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
10
11
|
constructor(baseDir = './data') {
|
|
11
|
-
this.baseDir = baseDir;
|
|
12
|
+
this.baseDir = path.resolve(baseDir);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Validate ID format (alphanumeric, hyphen, underscore only)
|
|
16
|
+
*/
|
|
17
|
+
validateId(id) {
|
|
18
|
+
if (!PersistenceManager.VALID_ID_PATTERN.test(id)) {
|
|
19
|
+
throw new Error(`Invalid ID format: ${id}. Only alphanumeric characters, hyphen, and underscore are allowed.`);
|
|
20
|
+
}
|
|
21
|
+
if (id.length > 256) {
|
|
22
|
+
throw new Error(`ID too long: ${id.length} characters (max 256)`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Validate collection name
|
|
27
|
+
*/
|
|
28
|
+
validateCollection(collection) {
|
|
29
|
+
if (!PersistenceManager.VALID_ID_PATTERN.test(collection)) {
|
|
30
|
+
throw new Error(`Invalid collection name: ${collection}. Only alphanumeric characters, hyphen, and underscore are allowed.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get safe file path and validate against path traversal
|
|
35
|
+
*/
|
|
36
|
+
getSafePath(collection, id) {
|
|
37
|
+
this.validateCollection(collection);
|
|
38
|
+
this.validateId(id);
|
|
39
|
+
const filePath = path.join(this.baseDir, collection, `${id}.json`);
|
|
40
|
+
const resolvedPath = path.resolve(filePath);
|
|
41
|
+
const resolvedBase = path.resolve(this.baseDir);
|
|
42
|
+
// Ensure resolved path is within base directory
|
|
43
|
+
const relativePath = path.relative(resolvedBase, resolvedPath);
|
|
44
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
45
|
+
throw new Error(`Path traversal detected: ${collection}/${id}`);
|
|
46
|
+
}
|
|
47
|
+
// Double-check with startsWith for extra safety
|
|
48
|
+
if (!resolvedPath.startsWith(resolvedBase + path.sep)) {
|
|
49
|
+
throw new Error(`Path traversal detected: ${collection}/${id}`);
|
|
50
|
+
}
|
|
51
|
+
return resolvedPath;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get safe directory path for listing
|
|
55
|
+
*/
|
|
56
|
+
getSafeDirPath(collection) {
|
|
57
|
+
this.validateCollection(collection);
|
|
58
|
+
const dirPath = path.join(this.baseDir, collection);
|
|
59
|
+
const resolvedPath = path.resolve(dirPath);
|
|
60
|
+
const resolvedBase = path.resolve(this.baseDir);
|
|
61
|
+
const relativePath = path.relative(resolvedBase, resolvedPath);
|
|
62
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
63
|
+
throw new Error(`Path traversal detected in collection: ${collection}`);
|
|
64
|
+
}
|
|
65
|
+
return resolvedPath;
|
|
12
66
|
}
|
|
13
67
|
/**
|
|
14
68
|
* Ensure storage directories exist
|
|
@@ -17,6 +71,7 @@ export class PersistenceManager {
|
|
|
17
71
|
try {
|
|
18
72
|
await fs.mkdir(this.baseDir, { recursive: true });
|
|
19
73
|
for (const dir of subDirs) {
|
|
74
|
+
this.validateCollection(dir);
|
|
20
75
|
await fs.mkdir(path.join(this.baseDir, dir), { recursive: true });
|
|
21
76
|
}
|
|
22
77
|
}
|
|
@@ -29,7 +84,7 @@ export class PersistenceManager {
|
|
|
29
84
|
* Save an object to a JSON file
|
|
30
85
|
*/
|
|
31
86
|
async save(collection, id, data) {
|
|
32
|
-
const filePath =
|
|
87
|
+
const filePath = this.getSafePath(collection, id);
|
|
33
88
|
try {
|
|
34
89
|
// Handle Maps by converting them to objects/arrays for JSON serialization
|
|
35
90
|
const serializedData = this.serialize(data);
|
|
@@ -44,7 +99,7 @@ export class PersistenceManager {
|
|
|
44
99
|
* Load an object from a JSON file
|
|
45
100
|
*/
|
|
46
101
|
async load(collection, id) {
|
|
47
|
-
const filePath =
|
|
102
|
+
const filePath = this.getSafePath(collection, id);
|
|
48
103
|
try {
|
|
49
104
|
const content = await fs.readFile(filePath, 'utf8');
|
|
50
105
|
return JSON.parse(content);
|
|
@@ -60,7 +115,7 @@ export class PersistenceManager {
|
|
|
60
115
|
* List all IDs in a collection
|
|
61
116
|
*/
|
|
62
117
|
async list(collection) {
|
|
63
|
-
const dirPath =
|
|
118
|
+
const dirPath = this.getSafeDirPath(collection);
|
|
64
119
|
try {
|
|
65
120
|
const files = await fs.readdir(dirPath);
|
|
66
121
|
return files
|
|
@@ -77,7 +132,7 @@ export class PersistenceManager {
|
|
|
77
132
|
* Delete an object
|
|
78
133
|
*/
|
|
79
134
|
async delete(collection, id) {
|
|
80
|
-
const filePath =
|
|
135
|
+
const filePath = this.getSafePath(collection, id);
|
|
81
136
|
try {
|
|
82
137
|
await fs.unlink(filePath);
|
|
83
138
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/utils/persistence.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,OAAO,kBAAkB;IACrB,OAAO,CAAS;
|
|
1
|
+
{"version":3,"file":"persistence.js","sourceRoot":"","sources":["../../src/utils/persistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,cAAc,CAAC"}
|