@cloudcli-ai/cloudcli 1.31.5 → 1.32.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/dist/assets/index-AaSE7-3t.js +1336 -0
- package/dist/assets/index-CKaku72N.css +32 -0
- package/dist/index.html +2 -2
- package/dist-server/server/claude-sdk.js +10 -5
- package/dist-server/server/claude-sdk.js.map +1 -1
- package/dist-server/server/cursor-cli.js +0 -6
- package/dist-server/server/cursor-cli.js.map +1 -1
- package/dist-server/server/gemini-cli.js +160 -34
- package/dist-server/server/gemini-cli.js.map +1 -1
- package/dist-server/server/modules/database/migrations.js +11 -0
- package/dist-server/server/modules/database/migrations.js.map +1 -1
- package/dist-server/server/modules/database/repositories/projects.db.js +12 -0
- package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -1
- package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js +61 -0
- package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js +49 -8
- package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
- package/dist-server/server/modules/database/schema.js +1 -0
- package/dist-server/server/modules/database/schema.js.map +1 -1
- package/dist-server/server/modules/projects/projects.routes.js +12 -3
- package/dist-server/server/modules/projects/projects.routes.js.map +1 -1
- package/dist-server/server/modules/projects/services/project-delete.service.js +14 -1
- package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -1
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +43 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
- package/dist-server/server/modules/providers/index.js +1 -0
- package/dist-server/server/modules/providers/index.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +2 -1
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +55 -2
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +153 -14
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +198 -0
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +54 -2
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +21 -6
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +82 -0
- package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +8 -30
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +189 -13
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +28 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +2 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +125 -2
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +24 -8
- package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +7 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +33 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +2 -0
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -1
- package/dist-server/server/modules/providers/provider.routes.js +23 -2
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js +129 -13
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +7 -5
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions.service.js +81 -7
- package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/skills.service.js +11 -0
- package/dist-server/server/modules/providers/services/skills.service.js.map +1 -0
- package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -1
- package/dist-server/server/modules/providers/shared/skills/skills.provider.js +45 -0
- package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/tests/skills.test.js +226 -0
- package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
- package/dist-server/server/openai-codex.js +56 -26
- package/dist-server/server/openai-codex.js.map +1 -1
- package/dist-server/server/routes/commands.js +5 -5
- package/dist-server/server/routes/commands.js.map +1 -1
- package/dist-server/server/shared/claude-cli-path.js +103 -0
- package/dist-server/server/shared/claude-cli-path.js.map +1 -0
- package/dist-server/server/shared/claude-cli-path.test.js +45 -0
- package/dist-server/server/shared/claude-cli-path.test.js.map +1 -0
- package/dist-server/server/{utils → shared}/frontmatter.js +3 -3
- package/dist-server/server/shared/frontmatter.js.map +1 -0
- package/dist-server/server/shared/utils.js +82 -0
- package/dist-server/server/shared/utils.js.map +1 -1
- package/dist-server/server/utils/commandParser.js +3 -3
- package/dist-server/server/utils/commandParser.js.map +1 -1
- package/dist-server/shared/modelConstants.js +1 -0
- package/dist-server/shared/modelConstants.js.map +1 -1
- package/package.json +1 -1
- package/server/claude-sdk.js +10 -5
- package/server/cursor-cli.js +0 -8
- package/server/gemini-cli.js +190 -42
- package/server/modules/database/migrations.ts +12 -0
- package/server/modules/database/repositories/projects.db.ts +13 -0
- package/server/modules/database/repositories/sessions.db.integration.test.ts +72 -0
- package/server/modules/database/repositories/sessions.db.ts +60 -9
- package/server/modules/database/schema.ts +1 -0
- package/server/modules/projects/projects.routes.ts +20 -3
- package/server/modules/projects/services/project-delete.service.ts +16 -1
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +64 -0
- package/server/modules/providers/README.md +346 -0
- package/server/modules/providers/index.ts +2 -1
- package/server/modules/providers/list/claude/claude-auth.provider.ts +8 -7
- package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +68 -2
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +175 -14
- package/server/modules/providers/list/claude/claude-skills.provider.ts +257 -0
- package/server/modules/providers/list/claude/claude.provider.ts +8 -1
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +62 -2
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +25 -6
- package/server/modules/providers/list/codex/codex-skills.provider.ts +100 -0
- package/server/modules/providers/list/codex/codex.provider.ts +8 -1
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +17 -40
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +216 -13
- package/server/modules/providers/list/cursor/cursor-skills.provider.ts +31 -0
- package/server/modules/providers/list/cursor/cursor.provider.ts +8 -1
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +158 -2
- package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +24 -20
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +7 -1
- package/server/modules/providers/list/gemini/gemini-skills.provider.ts +36 -0
- package/server/modules/providers/list/gemini/gemini.provider.ts +8 -1
- package/server/modules/providers/provider.routes.ts +35 -2
- package/server/modules/providers/services/session-conversations-search.service.ts +162 -13
- package/server/modules/providers/services/sessions-watcher.service.ts +7 -5
- package/server/modules/providers/services/sessions.service.ts +112 -9
- package/server/modules/providers/services/skills.service.ts +15 -0
- package/server/modules/providers/shared/base/abstract.provider.ts +2 -0
- package/server/modules/providers/shared/skills/skills.provider.ts +64 -0
- package/server/modules/providers/tests/skills.test.ts +446 -0
- package/server/openai-codex.js +59 -27
- package/server/routes/commands.js +7 -5
- package/server/shared/claude-cli-path.test.ts +61 -0
- package/server/shared/claude-cli-path.ts +139 -0
- package/server/{utils/frontmatter.js → shared/frontmatter.ts} +3 -3
- package/server/shared/interfaces.ts +19 -0
- package/server/shared/types.ts +78 -0
- package/server/shared/utils.ts +94 -0
- package/server/utils/commandParser.js +5 -3
- package/shared/modelConstants.js +1 -0
- package/dist/assets/index-6rYG_mRo.css +0 -32
- package/dist/assets/index-DqMVUeZS.js +0 -1331
- package/dist-server/server/utils/frontmatter.js.map +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { SkillsProvider } from '@/modules/providers/shared/skills/skills.provider.js';
|
|
6
|
+
import type { ProviderSkillSource } from '@/shared/types.js';
|
|
7
|
+
|
|
8
|
+
const hasGitMarker = async (dirPath: string): Promise<boolean> => {
|
|
9
|
+
try {
|
|
10
|
+
const gitMarkerStats = await fs.stat(path.join(dirPath, '.git'));
|
|
11
|
+
return gitMarkerStats.isDirectory() || gitMarkerStats.isFile();
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const findTopmostGitRoot = async (startPath: string): Promise<string | null> => {
|
|
18
|
+
let currentPath = path.resolve(startPath);
|
|
19
|
+
let topmostGitRoot: string | null = null;
|
|
20
|
+
|
|
21
|
+
while (true) {
|
|
22
|
+
if (await hasGitMarker(currentPath)) {
|
|
23
|
+
topmostGitRoot = currentPath;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const parentPath = path.dirname(currentPath);
|
|
27
|
+
if (parentPath === currentPath) {
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
currentPath = parentPath;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return topmostGitRoot;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const addUniqueSource = (
|
|
38
|
+
sources: ProviderSkillSource[],
|
|
39
|
+
seenRootDirs: Set<string>,
|
|
40
|
+
source: ProviderSkillSource,
|
|
41
|
+
): void => {
|
|
42
|
+
const normalizedRootDir = path.resolve(source.rootDir);
|
|
43
|
+
if (seenRootDirs.has(normalizedRootDir)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
seenRootDirs.add(normalizedRootDir);
|
|
48
|
+
sources.push({ ...source, rootDir: normalizedRootDir });
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export class CodexSkillsProvider extends SkillsProvider {
|
|
52
|
+
constructor() {
|
|
53
|
+
super('codex');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
protected async getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]> {
|
|
57
|
+
const sources: ProviderSkillSource[] = [];
|
|
58
|
+
const seenRootDirs = new Set<string>();
|
|
59
|
+
const repoRoot = await findTopmostGitRoot(workspacePath);
|
|
60
|
+
|
|
61
|
+
addUniqueSource(sources, seenRootDirs, {
|
|
62
|
+
scope: 'repo',
|
|
63
|
+
rootDir: path.join(workspacePath, '.agents', 'skills'),
|
|
64
|
+
commandPrefix: '$',
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (repoRoot) {
|
|
68
|
+
// Codex checks repository skills at the launch folder, one folder above it,
|
|
69
|
+
// and the topmost git root; these can collapse to the same directory.
|
|
70
|
+
addUniqueSource(sources, seenRootDirs, {
|
|
71
|
+
scope: 'repo',
|
|
72
|
+
rootDir: path.join(path.dirname(workspacePath), '.agents', 'skills'),
|
|
73
|
+
commandPrefix: '$',
|
|
74
|
+
});
|
|
75
|
+
addUniqueSource(sources, seenRootDirs, {
|
|
76
|
+
scope: 'repo',
|
|
77
|
+
rootDir: path.join(repoRoot, '.agents', 'skills'),
|
|
78
|
+
commandPrefix: '$',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
addUniqueSource(sources, seenRootDirs, {
|
|
83
|
+
scope: 'user',
|
|
84
|
+
rootDir: path.join(os.homedir(), '.agents', 'skills'),
|
|
85
|
+
commandPrefix: '$',
|
|
86
|
+
});
|
|
87
|
+
addUniqueSource(sources, seenRootDirs, {
|
|
88
|
+
scope: 'admin',
|
|
89
|
+
rootDir: path.join('/etc', 'codex', 'skills'),
|
|
90
|
+
commandPrefix: '$',
|
|
91
|
+
});
|
|
92
|
+
addUniqueSource(sources, seenRootDirs, {
|
|
93
|
+
scope: 'system',
|
|
94
|
+
rootDir: path.join(os.homedir(), '.codex', 'skills', '.system'),
|
|
95
|
+
commandPrefix: '$',
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return sources;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -3,11 +3,18 @@ import { CodexProviderAuth } from '@/modules/providers/list/codex/codex-auth.pro
|
|
|
3
3
|
import { CodexMcpProvider } from '@/modules/providers/list/codex/codex-mcp.provider.js';
|
|
4
4
|
import { CodexSessionSynchronizer } from '@/modules/providers/list/codex/codex-session-synchronizer.provider.js';
|
|
5
5
|
import { CodexSessionsProvider } from '@/modules/providers/list/codex/codex-sessions.provider.js';
|
|
6
|
-
import
|
|
6
|
+
import { CodexSkillsProvider } from '@/modules/providers/list/codex/codex-skills.provider.js';
|
|
7
|
+
import type {
|
|
8
|
+
IProviderAuth,
|
|
9
|
+
IProviderSessionSynchronizer,
|
|
10
|
+
IProviderSkills,
|
|
11
|
+
IProviderSessions,
|
|
12
|
+
} from '@/shared/interfaces.js';
|
|
7
13
|
|
|
8
14
|
export class CodexProvider extends AbstractProvider {
|
|
9
15
|
readonly mcp = new CodexMcpProvider();
|
|
10
16
|
readonly auth: IProviderAuth = new CodexProviderAuth();
|
|
17
|
+
readonly skills: IProviderSkills = new CodexSkillsProvider();
|
|
11
18
|
readonly sessions: IProviderSessions = new CodexSessionsProvider();
|
|
12
19
|
readonly sessionSynchronizer: IProviderSessionSynchronizer = new CodexSessionSynchronizer();
|
|
13
20
|
|
|
@@ -45,44 +45,28 @@ export class CursorSessionSynchronizer implements IProviderSessionSynchronizer {
|
|
|
45
45
|
*/
|
|
46
46
|
async synchronize(since?: Date): Promise<number> {
|
|
47
47
|
const projectsDir = path.join(this.cursorHome, 'projects');
|
|
48
|
-
const projectEntries = await listDirectoryEntriesSafe(projectsDir);
|
|
49
|
-
const seenProjectPaths = new Set<string>();
|
|
50
48
|
|
|
51
49
|
let processed = 0;
|
|
52
|
-
for (const entry of projectEntries) {
|
|
53
|
-
if (!entry.isDirectory()) {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
const files = await findFilesRecursivelyCreatedAfter(projectsDir, '.jsonl', since ?? null);
|
|
52
|
+
|
|
53
|
+
for (const filePath of files) {
|
|
54
|
+
const parsed = await this.processSessionFile(filePath);
|
|
55
|
+
if (!parsed) {
|
|
60
56
|
continue;
|
|
61
57
|
}
|
|
62
58
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const timestamps = await readFileTimestamps(filePath);
|
|
75
|
-
sessionsDb.createSession(
|
|
76
|
-
parsed.sessionId,
|
|
77
|
-
this.provider,
|
|
78
|
-
parsed.projectPath,
|
|
79
|
-
parsed.sessionName,
|
|
80
|
-
timestamps.createdAt,
|
|
81
|
-
timestamps.updatedAt,
|
|
82
|
-
filePath
|
|
83
|
-
);
|
|
84
|
-
processed += 1;
|
|
85
|
-
}
|
|
59
|
+
const timestamps = await readFileTimestamps(filePath);
|
|
60
|
+
sessionsDb.createSession(
|
|
61
|
+
parsed.sessionId,
|
|
62
|
+
this.provider,
|
|
63
|
+
parsed.projectPath,
|
|
64
|
+
parsed.sessionName,
|
|
65
|
+
timestamps.createdAt,
|
|
66
|
+
timestamps.updatedAt,
|
|
67
|
+
filePath
|
|
68
|
+
);
|
|
69
|
+
processed += 1;
|
|
86
70
|
}
|
|
87
71
|
|
|
88
72
|
return processed;
|
|
@@ -113,13 +97,6 @@ export class CursorSessionSynchronizer implements IProviderSessionSynchronizer {
|
|
|
113
97
|
);
|
|
114
98
|
}
|
|
115
99
|
|
|
116
|
-
/**
|
|
117
|
-
* Produces the same project hash Cursor uses in chat directory names.
|
|
118
|
-
*/
|
|
119
|
-
private md5(input: string): string {
|
|
120
|
-
return crypto.createHash('md5').update(input).digest('hex');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
100
|
/**
|
|
124
101
|
* Extracts project path from Cursor worker.log.
|
|
125
102
|
*/
|
|
@@ -149,7 +126,7 @@ export class CursorSessionSynchronizer implements IProviderSessionSynchronizer {
|
|
|
149
126
|
*/
|
|
150
127
|
private async processSessionFile(filePath: string): Promise<ParsedSession | null> {
|
|
151
128
|
const sessionId = path.basename(filePath, '.jsonl');
|
|
152
|
-
const grandparentDir = path.dirname(path.dirname(filePath));
|
|
129
|
+
const grandparentDir = path.dirname(path.dirname(path.dirname(filePath)));
|
|
153
130
|
const workerLogPath = path.join(grandparentDir, 'worker.log');
|
|
154
131
|
const projectPath = await this.extractProjectPathFromWorkerLog(workerLogPath);
|
|
155
132
|
|
|
@@ -25,6 +25,167 @@ type CursorMessageBlob = {
|
|
|
25
25
|
content: AnyRecord;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
function isInternalCursorText(value: unknown): boolean {
|
|
29
|
+
if (typeof value !== 'string') {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const normalized = value.trim();
|
|
34
|
+
return normalized.startsWith('<user_info>') || normalized.startsWith('<system_reminder>');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isInternalCursorPart(part: unknown): boolean {
|
|
38
|
+
if (!part || typeof part !== 'object') {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const record = part as AnyRecord;
|
|
43
|
+
const type = typeof record.type === 'string' ? record.type : '';
|
|
44
|
+
if (type === 'user_info' || type === 'system_reminder') {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return isInternalCursorText(record.text);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function unwrapUserQueryText(value: string, role: 'user' | 'assistant'): string {
|
|
52
|
+
if (role !== 'user') {
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const normalized = value.trimStart();
|
|
57
|
+
const openTag = '<user_query>';
|
|
58
|
+
const closeTag = '</user_query>';
|
|
59
|
+
if (!normalized.startsWith(openTag)) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const afterOpen = normalized.slice(openTag.length);
|
|
64
|
+
const closeIndex = afterOpen.lastIndexOf(closeTag);
|
|
65
|
+
const inner = closeIndex >= 0 ? afterOpen.slice(0, closeIndex) : afterOpen;
|
|
66
|
+
return inner.trim();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeToolId(value: unknown): string | null {
|
|
70
|
+
if (typeof value !== 'string') {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const normalized = value.trim();
|
|
75
|
+
return normalized ? normalized : null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function extractCursorToolResultContent(item: AnyRecord): string {
|
|
79
|
+
if (typeof item.result === 'string' && item.result.trim()) {
|
|
80
|
+
return item.result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (typeof item.output === 'string' && item.output.trim()) {
|
|
84
|
+
return item.output;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (Array.isArray(item.experimental_content)) {
|
|
88
|
+
const experimentalText = item.experimental_content
|
|
89
|
+
.map((part: unknown) => {
|
|
90
|
+
if (typeof part === 'string') {
|
|
91
|
+
return part;
|
|
92
|
+
}
|
|
93
|
+
if (part && typeof part === 'object') {
|
|
94
|
+
const record = part as AnyRecord;
|
|
95
|
+
if (typeof record.text === 'string') {
|
|
96
|
+
return record.text;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return '';
|
|
100
|
+
})
|
|
101
|
+
.filter(Boolean)
|
|
102
|
+
.join('\n');
|
|
103
|
+
|
|
104
|
+
if (experimentalText.trim()) {
|
|
105
|
+
return experimentalText;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return typeof item.result === 'string' ? item.result : '';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function parseCursorToolInput(rawInput: unknown): unknown {
|
|
113
|
+
if (typeof rawInput !== 'string') {
|
|
114
|
+
return rawInput;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const trimmed = rawInput.trim();
|
|
118
|
+
if (!trimmed) {
|
|
119
|
+
return rawInput;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
return JSON.parse(trimmed);
|
|
124
|
+
} catch {
|
|
125
|
+
return rawInput;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function normalizeCursorToolInput(toolName: string, rawInput: unknown): unknown {
|
|
130
|
+
const parsed = parseCursorToolInput(rawInput);
|
|
131
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
132
|
+
return parsed;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const input = parsed as AnyRecord;
|
|
136
|
+
const normalized: AnyRecord = { ...input };
|
|
137
|
+
|
|
138
|
+
const filePath = input.file_path
|
|
139
|
+
?? input.filePath
|
|
140
|
+
?? input.path
|
|
141
|
+
?? input.file
|
|
142
|
+
?? input.filename;
|
|
143
|
+
if (typeof filePath === 'string' && filePath.trim()) {
|
|
144
|
+
normalized.file_path = filePath;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (toolName === 'Write') {
|
|
148
|
+
const content = input.content
|
|
149
|
+
?? input.text
|
|
150
|
+
?? input.value
|
|
151
|
+
?? input.contents
|
|
152
|
+
?? input.fileContent
|
|
153
|
+
?? input.new_string
|
|
154
|
+
?? input.newString;
|
|
155
|
+
if (typeof content === 'string') {
|
|
156
|
+
normalized.content = content;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (toolName === 'Edit') {
|
|
161
|
+
const oldString = input.old_string
|
|
162
|
+
?? input.oldString
|
|
163
|
+
?? input.old
|
|
164
|
+
?? '';
|
|
165
|
+
const newString = input.new_string
|
|
166
|
+
?? input.newString
|
|
167
|
+
?? input.new
|
|
168
|
+
?? input.content
|
|
169
|
+
?? '';
|
|
170
|
+
|
|
171
|
+
if (typeof oldString === 'string') {
|
|
172
|
+
normalized.old_string = oldString;
|
|
173
|
+
}
|
|
174
|
+
if (typeof newString === 'string') {
|
|
175
|
+
normalized.new_string = newString;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (toolName === 'ApplyPatch') {
|
|
180
|
+
const patch = input.patch ?? input.diff ?? input.content;
|
|
181
|
+
if (typeof patch === 'string' && !normalized.patch) {
|
|
182
|
+
normalized.patch = patch;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return normalized;
|
|
187
|
+
}
|
|
188
|
+
|
|
28
189
|
function sanitizeCursorSessionId(sessionId: string): string {
|
|
29
190
|
const normalized = sessionId.trim();
|
|
30
191
|
if (!normalized) {
|
|
@@ -225,13 +386,14 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
225
386
|
try {
|
|
226
387
|
const blobs = await this.loadCursorBlobs(sessionId, projectPath);
|
|
227
388
|
const allNormalized = this.normalizeCursorBlobs(blobs, sessionId);
|
|
228
|
-
const
|
|
389
|
+
const renderableMessages = allNormalized.filter((msg) => msg.kind !== 'tool_result');
|
|
390
|
+
const total = renderableMessages.length;
|
|
229
391
|
|
|
230
392
|
if (limit !== null) {
|
|
231
393
|
const start = offset;
|
|
232
394
|
const page = limit === 0
|
|
233
395
|
? []
|
|
234
|
-
:
|
|
396
|
+
: renderableMessages.slice(start, start + limit);
|
|
235
397
|
const hasMore = limit === 0
|
|
236
398
|
? start < total
|
|
237
399
|
: start + limit < total;
|
|
@@ -245,7 +407,7 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
245
407
|
}
|
|
246
408
|
|
|
247
409
|
return {
|
|
248
|
-
messages:
|
|
410
|
+
messages: renderableMessages,
|
|
249
411
|
total,
|
|
250
412
|
hasMore: false,
|
|
251
413
|
offset: 0,
|
|
@@ -283,11 +445,24 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
283
445
|
let text = '';
|
|
284
446
|
if (Array.isArray(content.message.content)) {
|
|
285
447
|
text = content.message.content
|
|
286
|
-
.map((part: string | AnyRecord) =>
|
|
448
|
+
.map((part: string | AnyRecord) => {
|
|
449
|
+
if (typeof part === 'string') {
|
|
450
|
+
if (isInternalCursorText(part)) {
|
|
451
|
+
return '';
|
|
452
|
+
}
|
|
453
|
+
return unwrapUserQueryText(part, role);
|
|
454
|
+
}
|
|
455
|
+
if (isInternalCursorPart(part)) {
|
|
456
|
+
return '';
|
|
457
|
+
}
|
|
458
|
+
return unwrapUserQueryText(part?.text || '', role);
|
|
459
|
+
})
|
|
287
460
|
.filter(Boolean)
|
|
288
461
|
.join('\n');
|
|
289
462
|
} else if (typeof content.message.content === 'string') {
|
|
290
|
-
|
|
463
|
+
if (!isInternalCursorText(content.message.content)) {
|
|
464
|
+
text = unwrapUserQueryText(content.message.content, role);
|
|
465
|
+
}
|
|
291
466
|
}
|
|
292
467
|
if (text?.trim()) {
|
|
293
468
|
messages.push(createNormalizedMessage({
|
|
@@ -316,7 +491,14 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
316
491
|
if (item?.type !== 'tool-result') {
|
|
317
492
|
continue;
|
|
318
493
|
}
|
|
319
|
-
const
|
|
494
|
+
const cursorOptions = content.providerOptions?.cursor as AnyRecord | undefined;
|
|
495
|
+
const highLevelToolCallResult = cursorOptions?.highLevelToolCallResult;
|
|
496
|
+
const toolCallId = normalizeToolId(item.toolCallId)
|
|
497
|
+
|| normalizeToolId(item.tool_call_id)
|
|
498
|
+
|| normalizeToolId(highLevelToolCallResult?.toolCallId)
|
|
499
|
+
|| normalizeToolId(highLevelToolCallResult?.tool_call_id)
|
|
500
|
+
|| normalizeToolId(content.id)
|
|
501
|
+
|| '';
|
|
320
502
|
messages.push(createNormalizedMessage({
|
|
321
503
|
id: `${baseId}_tr`,
|
|
322
504
|
sessionId,
|
|
@@ -324,8 +506,9 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
324
506
|
provider: PROVIDER,
|
|
325
507
|
kind: 'tool_result',
|
|
326
508
|
toolId: toolCallId,
|
|
327
|
-
content: item
|
|
328
|
-
isError:
|
|
509
|
+
content: extractCursorToolResultContent(item),
|
|
510
|
+
isError: Boolean(item.isError || item.is_error),
|
|
511
|
+
toolUseResult: highLevelToolCallResult,
|
|
329
512
|
}));
|
|
330
513
|
}
|
|
331
514
|
continue;
|
|
@@ -336,8 +519,15 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
336
519
|
if (Array.isArray(content.content)) {
|
|
337
520
|
for (let partIdx = 0; partIdx < content.content.length; partIdx++) {
|
|
338
521
|
const part = content.content[partIdx];
|
|
522
|
+
if (isInternalCursorPart(part)) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
339
525
|
|
|
340
526
|
if (part?.type === 'text' && part?.text) {
|
|
527
|
+
const normalizedPartText = unwrapUserQueryText(part.text, role);
|
|
528
|
+
if (!normalizedPartText) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
341
531
|
messages.push(createNormalizedMessage({
|
|
342
532
|
id: `${baseId}_${partIdx}`,
|
|
343
533
|
sessionId,
|
|
@@ -345,7 +535,7 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
345
535
|
provider: PROVIDER,
|
|
346
536
|
kind: 'text',
|
|
347
537
|
role,
|
|
348
|
-
content:
|
|
538
|
+
content: normalizedPartText,
|
|
349
539
|
sequence: blob.sequence,
|
|
350
540
|
rowid: blob.rowid,
|
|
351
541
|
}));
|
|
@@ -361,7 +551,11 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
361
551
|
} else if (part?.type === 'tool-call' || part?.type === 'tool_use') {
|
|
362
552
|
const rawToolName = part.toolName || part.name || 'Unknown Tool';
|
|
363
553
|
const toolName = rawToolName === 'ApplyPatch' ? 'Edit' : rawToolName;
|
|
364
|
-
const toolId = part.toolCallId
|
|
554
|
+
const toolId = normalizeToolId(part.toolCallId)
|
|
555
|
+
|| normalizeToolId(part.tool_call_id)
|
|
556
|
+
|| normalizeToolId(part.id)
|
|
557
|
+
|| `tool_${i}_${partIdx}`;
|
|
558
|
+
const normalizedToolInput = normalizeCursorToolInput(rawToolName, part.args ?? part.input);
|
|
365
559
|
const message = createNormalizedMessage({
|
|
366
560
|
id: `${baseId}_${partIdx}`,
|
|
367
561
|
sessionId,
|
|
@@ -369,14 +563,22 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
369
563
|
provider: PROVIDER,
|
|
370
564
|
kind: 'tool_use',
|
|
371
565
|
toolName,
|
|
372
|
-
toolInput:
|
|
566
|
+
toolInput: normalizedToolInput,
|
|
373
567
|
toolId,
|
|
374
568
|
});
|
|
375
569
|
messages.push(message);
|
|
376
570
|
toolUseMap.set(toolId, message);
|
|
377
571
|
}
|
|
378
572
|
}
|
|
379
|
-
} else if (
|
|
573
|
+
} else if (
|
|
574
|
+
typeof content.content === 'string'
|
|
575
|
+
&& content.content.trim()
|
|
576
|
+
&& !isInternalCursorText(content.content)
|
|
577
|
+
) {
|
|
578
|
+
const normalizedText = unwrapUserQueryText(content.content, role);
|
|
579
|
+
if (!normalizedText) {
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
380
582
|
messages.push(createNormalizedMessage({
|
|
381
583
|
id: baseId,
|
|
382
584
|
sessionId,
|
|
@@ -384,7 +586,7 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
384
586
|
provider: PROVIDER,
|
|
385
587
|
kind: 'text',
|
|
386
588
|
role,
|
|
387
|
-
content:
|
|
589
|
+
content: normalizedText,
|
|
388
590
|
sequence: blob.sequence,
|
|
389
591
|
rowid: blob.rowid,
|
|
390
592
|
}));
|
|
@@ -401,6 +603,7 @@ export class CursorSessionsProvider implements IProviderSessions {
|
|
|
401
603
|
toolUse.toolResult = {
|
|
402
604
|
content: msg.content,
|
|
403
605
|
isError: msg.isError,
|
|
606
|
+
toolUseResult: msg.toolUseResult,
|
|
404
607
|
};
|
|
405
608
|
}
|
|
406
609
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { SkillsProvider } from '@/modules/providers/shared/skills/skills.provider.js';
|
|
5
|
+
import type { ProviderSkillSource } from '@/shared/types.js';
|
|
6
|
+
|
|
7
|
+
export class CursorSkillsProvider extends SkillsProvider {
|
|
8
|
+
constructor() {
|
|
9
|
+
super('cursor');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
protected async getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]> {
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
scope: 'project',
|
|
16
|
+
rootDir: path.join(workspacePath, '.agents', 'skills'),
|
|
17
|
+
commandPrefix: '/',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
scope: 'project',
|
|
21
|
+
rootDir: path.join(workspacePath, '.cursor', 'skills'),
|
|
22
|
+
commandPrefix: '/',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
scope: 'user',
|
|
26
|
+
rootDir: path.join(os.homedir(), '.cursor', 'skills'),
|
|
27
|
+
commandPrefix: '/',
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -3,11 +3,18 @@ import { CursorProviderAuth } from '@/modules/providers/list/cursor/cursor-auth.
|
|
|
3
3
|
import { CursorMcpProvider } from '@/modules/providers/list/cursor/cursor-mcp.provider.js';
|
|
4
4
|
import { CursorSessionSynchronizer } from '@/modules/providers/list/cursor/cursor-session-synchronizer.provider.js';
|
|
5
5
|
import { CursorSessionsProvider } from '@/modules/providers/list/cursor/cursor-sessions.provider.js';
|
|
6
|
-
import
|
|
6
|
+
import { CursorSkillsProvider } from '@/modules/providers/list/cursor/cursor-skills.provider.js';
|
|
7
|
+
import type {
|
|
8
|
+
IProviderAuth,
|
|
9
|
+
IProviderSessionSynchronizer,
|
|
10
|
+
IProviderSkills,
|
|
11
|
+
IProviderSessions,
|
|
12
|
+
} from '@/shared/interfaces.js';
|
|
7
13
|
|
|
8
14
|
export class CursorProvider extends AbstractProvider {
|
|
9
15
|
readonly mcp = new CursorMcpProvider();
|
|
10
16
|
readonly auth: IProviderAuth = new CursorProviderAuth();
|
|
17
|
+
readonly skills: IProviderSkills = new CursorSkillsProvider();
|
|
11
18
|
readonly sessions: IProviderSessions = new CursorSessionsProvider();
|
|
12
19
|
readonly sessionSynchronizer: IProviderSessionSynchronizer = new CursorSessionSynchronizer();
|
|
13
20
|
|