@cloudcli-ai/cloudcli 1.31.5 → 1.33.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/README.de.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.ru.md +1 -1
- package/README.tr.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/api-docs.html +6 -7
- package/dist/assets/index-MOIvpy53.css +32 -0
- package/dist/assets/{index-DqMVUeZS.js → index-skXSjBje.js} +290 -270
- package/dist/index.html +2 -2
- package/dist/modelConstants.js +841 -0
- package/dist-server/server/claude-sdk.js +67 -39
- package/dist-server/server/claude-sdk.js.map +1 -1
- package/dist-server/server/cursor-cli.js +6 -9
- package/dist-server/server/cursor-cli.js.map +1 -1
- package/dist-server/server/gemini-cli.js +163 -35
- package/dist-server/server/gemini-cli.js.map +1 -1
- package/dist-server/server/gemini-response-handler.js +34 -0
- package/dist-server/server/gemini-response-handler.js.map +1 -1
- package/dist-server/server/index.js +131 -19
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/database/index.js +1 -0
- package/dist-server/server/modules/database/index.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/project-management.service.js +1 -0
- package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -1
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +47 -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 +27 -7
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +141 -0
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -0
- 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 +4 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +84 -0
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -0
- 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 +50 -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 +4 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +754 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -0
- 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 +187 -24
- 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 +4 -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-models.provider.js +27 -0
- package/dist-server/server/modules/providers/list/gemini/gemini-models.provider.js.map +1 -0
- 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 +10 -10
- 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 +4 -0
- package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js +92 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js +181 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +267 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +115 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +410 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js +62 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +19 -0
- package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -0
- package/dist-server/server/modules/providers/provider.registry.js +2 -0
- package/dist-server/server/modules/providers/provider.registry.js.map +1 -1
- package/dist-server/server/modules/providers/provider.routes.js +65 -3
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
- package/dist-server/server/modules/providers/services/mcp.service.js +1 -9
- package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-models.service.js +199 -0
- package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -0
- 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/session-synchronizer.service.js +1 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +13 -4
- 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/mcp.test.js +73 -6
- package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/opencode-models.test.js +66 -0
- package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +262 -0
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js +270 -0
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/skills.test.js +259 -0
- package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +12 -1
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +4 -4
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +9 -1
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
- package/dist-server/server/openai-codex.js +87 -29
- package/dist-server/server/openai-codex.js.map +1 -1
- package/dist-server/server/opencode-cli.js +287 -0
- package/dist-server/server/opencode-cli.js.map +1 -0
- package/dist-server/server/opencode-cli.test.js +84 -0
- package/dist-server/server/opencode-cli.test.js.map +1 -0
- package/dist-server/server/routes/agent.js +21 -8
- package/dist-server/server/routes/agent.js.map +1 -1
- package/dist-server/server/routes/commands.js +204 -211
- package/dist-server/server/routes/commands.js.map +1 -1
- package/dist-server/server/routes/cursor.js +2 -2
- package/dist-server/server/routes/cursor.js.map +1 -1
- package/dist-server/server/routes/settings.js +0 -10
- package/dist-server/server/routes/settings.js.map +1 -1
- package/dist-server/server/routes/tests/commands.test.js +76 -0
- package/dist-server/server/routes/tests/commands.test.js.map +1 -0
- 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 +368 -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/package.json +3 -1
- package/public/api-docs.html +878 -0
- package/public/modelConstants.js +841 -0
- package/server/claude-sdk.js +74 -40
- package/server/cursor-cli.js +6 -11
- package/server/gemini-cli.js +197 -43
- package/server/gemini-response-handler.js +38 -0
- package/server/index.js +144 -19
- package/server/modules/database/index.ts +1 -0
- 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/project-management.service.ts +2 -0
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +71 -1
- package/server/modules/providers/README.md +354 -0
- package/server/modules/providers/index.ts +2 -1
- package/server/modules/providers/list/claude/claude-auth.provider.ts +38 -13
- package/server/modules/providers/list/claude/claude-models.provider.ts +191 -0
- 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 +11 -1
- package/server/modules/providers/list/codex/codex-models.provider.ts +125 -0
- 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 +60 -0
- package/server/modules/providers/list/codex/codex.provider.ts +11 -1
- package/server/modules/providers/list/cursor/cursor-models.provider.ts +820 -0
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +17 -40
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +216 -26
- package/server/modules/providers/list/cursor/cursor-skills.provider.ts +31 -0
- package/server/modules/providers/list/cursor/cursor.provider.ts +11 -1
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +158 -2
- package/server/modules/providers/list/gemini/gemini-models.provider.ts +42 -0
- package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +24 -20
- package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +10 -11
- package/server/modules/providers/list/gemini/gemini-skills.provider.ts +36 -0
- package/server/modules/providers/list/gemini/gemini.provider.ts +11 -1
- package/server/modules/providers/list/opencode/opencode-auth.provider.ts +111 -0
- package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +228 -0
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +339 -0
- package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +157 -0
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +506 -0
- package/server/modules/providers/list/opencode/opencode-skills.provider.ts +78 -0
- package/server/modules/providers/list/opencode/opencode.provider.ts +27 -0
- package/server/modules/providers/provider.registry.ts +2 -0
- package/server/modules/providers/provider.routes.ts +97 -4
- package/server/modules/providers/services/mcp.service.ts +1 -12
- package/server/modules/providers/services/provider-models.service.ts +325 -0
- package/server/modules/providers/services/session-conversations-search.service.ts +162 -13
- package/server/modules/providers/services/session-synchronizer.service.ts +1 -0
- package/server/modules/providers/services/sessions-watcher.service.ts +14 -4
- 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 +4 -0
- package/server/modules/providers/shared/skills/skills.provider.ts +64 -0
- package/server/modules/providers/tests/mcp.test.ts +93 -6
- package/server/modules/providers/tests/opencode-models.test.ts +73 -0
- package/server/modules/providers/tests/opencode-sessions.test.ts +334 -0
- package/server/modules/providers/tests/provider-models.service.test.ts +318 -0
- package/server/modules/providers/tests/skills.test.ts +512 -0
- package/server/modules/websocket/services/chat-websocket.service.ts +15 -1
- package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +4 -4
- package/server/modules/websocket/services/shell-websocket.service.ts +9 -0
- package/server/openai-codex.js +99 -30
- package/server/opencode-cli.js +336 -0
- package/server/opencode-cli.test.js +95 -0
- package/server/routes/agent.js +22 -8
- package/server/routes/commands.js +256 -233
- package/server/routes/cursor.js +2 -2
- package/server/routes/settings.js +1 -10
- package/server/routes/tests/commands.test.js +82 -0
- 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 +64 -0
- package/server/shared/types.ts +166 -1
- package/server/shared/utils.ts +478 -0
- package/server/utils/commandParser.js +5 -3
- package/dist/assets/index-6rYG_mRo.css +0 -32
- package/dist-server/server/utils/frontmatter.js.map +0 -1
- package/dist-server/shared/modelConstants.js +0 -98
- package/dist-server/shared/modelConstants.js.map +0 -1
- package/shared/modelConstants.js +0 -106
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { readFile, readdir, stat } 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 { parseFrontMatter } from '@/shared/frontmatter.js';
|
|
7
|
+
import type {
|
|
8
|
+
ProviderSkill,
|
|
9
|
+
ProviderSkillListOptions,
|
|
10
|
+
ProviderSkillSource,
|
|
11
|
+
} from '@/shared/types.js';
|
|
12
|
+
import {
|
|
13
|
+
findProviderSkillMarkdownFiles,
|
|
14
|
+
readJsonConfig,
|
|
15
|
+
readObjectRecord,
|
|
16
|
+
readOptionalString,
|
|
17
|
+
readProviderSkillMarkdownDefinition,
|
|
18
|
+
} from '@/shared/utils.js';
|
|
19
|
+
|
|
20
|
+
const getClaudeHomePath = (): string => path.join(os.homedir(), '.claude');
|
|
21
|
+
|
|
22
|
+
const getClaudePluginName = (pluginId: string): string | null => {
|
|
23
|
+
const normalizedPluginId = pluginId.trim();
|
|
24
|
+
if (!normalizedPluginId || normalizedPluginId === '@') {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const [pluginName] = normalizedPluginId.split('@');
|
|
29
|
+
return readOptionalString(pluginName) ?? null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const stripMarkdownExtension = (filename: string): string =>
|
|
33
|
+
filename.replace(/\.md$/i, '');
|
|
34
|
+
|
|
35
|
+
const pathExistsAsDirectory = async (directoryPath: string): Promise<boolean> => {
|
|
36
|
+
try {
|
|
37
|
+
const directoryStats = await stat(directoryPath);
|
|
38
|
+
return directoryStats.isDirectory();
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const listChildDirectories = async (directoryPath: string): Promise<string[]> => {
|
|
45
|
+
try {
|
|
46
|
+
const entries = await readdir(directoryPath, { withFileTypes: true });
|
|
47
|
+
return entries
|
|
48
|
+
.filter((entry) => entry.isDirectory())
|
|
49
|
+
.map((entry) => path.join(directoryPath, entry.name))
|
|
50
|
+
.sort((left, right) => left.localeCompare(right));
|
|
51
|
+
} catch {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const readClaudePluginName = async (
|
|
57
|
+
installPath: string,
|
|
58
|
+
pluginId: string,
|
|
59
|
+
): Promise<string | null> => {
|
|
60
|
+
try {
|
|
61
|
+
const pluginConfig = await readJsonConfig(
|
|
62
|
+
path.join(installPath, '.claude-plugin', 'plugin.json'),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Older or partial plugin installs may not have plugin.json yet. Falling
|
|
66
|
+
// back keeps discovery useful without inventing a separate namespace.
|
|
67
|
+
return readOptionalString(pluginConfig.name) ?? getClaudePluginName(pluginId);
|
|
68
|
+
} catch {
|
|
69
|
+
return getClaudePluginName(pluginId);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export class ClaudeSkillsProvider extends SkillsProvider {
|
|
74
|
+
constructor() {
|
|
75
|
+
super('claude');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async listSkills(options?: ProviderSkillListOptions): Promise<ProviderSkill[]> {
|
|
79
|
+
return [
|
|
80
|
+
...(await super.listSkills(options)),
|
|
81
|
+
...(await this.listPluginSkills(getClaudeHomePath())),
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
protected async getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]> {
|
|
86
|
+
const claudeHomePath = getClaudeHomePath();
|
|
87
|
+
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
scope: 'user',
|
|
91
|
+
rootDir: path.join(claudeHomePath, 'skills'),
|
|
92
|
+
commandPrefix: '/',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
scope: 'project',
|
|
96
|
+
rootDir: path.join(workspacePath, '.claude', 'skills'),
|
|
97
|
+
commandPrefix: '/',
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private async listPluginSkills(claudeHomePath: string): Promise<ProviderSkill[]> {
|
|
103
|
+
const settings = await readJsonConfig(path.join(claudeHomePath, 'settings.json'));
|
|
104
|
+
const enabledPlugins = readObjectRecord(settings.enabledPlugins);
|
|
105
|
+
if (!enabledPlugins) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const installedConfig = await readJsonConfig(
|
|
110
|
+
path.join(claudeHomePath, 'plugins', 'installed_plugins.json'),
|
|
111
|
+
);
|
|
112
|
+
const installedPlugins = readObjectRecord(installedConfig.plugins);
|
|
113
|
+
if (!installedPlugins) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const skills: ProviderSkill[] = [];
|
|
118
|
+
const visitedPluginFolders = new Set<string>();
|
|
119
|
+
const pluginEntries = Object.entries(enabledPlugins)
|
|
120
|
+
.sort(([left], [right]) => left.localeCompare(right));
|
|
121
|
+
for (const [pluginId, enabled] of pluginEntries) {
|
|
122
|
+
if (enabled !== true) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const installs = installedPlugins[pluginId];
|
|
127
|
+
if (!Array.isArray(installs)) {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (const install of installs) {
|
|
132
|
+
const installRecord = readObjectRecord(install);
|
|
133
|
+
const installPath = readOptionalString(installRecord?.installPath);
|
|
134
|
+
if (!installPath) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Claude's installed path points at one version folder; the usable
|
|
139
|
+
// plugin payloads live in the direct child folders beside it.
|
|
140
|
+
const pluginFolders = await listChildDirectories(path.dirname(installPath));
|
|
141
|
+
for (const pluginFolder of pluginFolders) {
|
|
142
|
+
const pluginFolderKey = `${pluginId}:${path.resolve(pluginFolder)}`;
|
|
143
|
+
if (visitedPluginFolders.has(pluginFolderKey)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
visitedPluginFolders.add(pluginFolderKey);
|
|
147
|
+
|
|
148
|
+
const pluginName = await readClaudePluginName(pluginFolder, pluginId);
|
|
149
|
+
if (!pluginName) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const commandsPath = path.join(pluginFolder, 'commands');
|
|
154
|
+
if (await pathExistsAsDirectory(commandsPath)) {
|
|
155
|
+
skills.push(
|
|
156
|
+
...(await this.listPluginCommandSkills(commandsPath, pluginId, pluginName)),
|
|
157
|
+
);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const skillsPath = path.join(pluginFolder, 'skills');
|
|
162
|
+
if (!(await pathExistsAsDirectory(skillsPath))) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
skills.push(
|
|
167
|
+
...(await this.listPluginSkillMarkdowns(pluginFolder, pluginId, pluginName)),
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return skills;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private async listPluginCommandSkills(
|
|
177
|
+
commandsPath: string,
|
|
178
|
+
pluginId: string,
|
|
179
|
+
pluginName: string,
|
|
180
|
+
): Promise<ProviderSkill[]> {
|
|
181
|
+
const skills: ProviderSkill[] = [];
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const entries = await readdir(commandsPath, { withFileTypes: true });
|
|
185
|
+
const commandFiles = entries
|
|
186
|
+
.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.md'))
|
|
187
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
188
|
+
|
|
189
|
+
for (const commandFile of commandFiles) {
|
|
190
|
+
const sourcePath = path.join(commandsPath, commandFile.name);
|
|
191
|
+
try {
|
|
192
|
+
const definition = await this.readPluginCommandDefinition(sourcePath);
|
|
193
|
+
skills.push({
|
|
194
|
+
provider: this.provider,
|
|
195
|
+
name: definition.name,
|
|
196
|
+
description: definition.description,
|
|
197
|
+
command: `/${pluginName}:${definition.name}`,
|
|
198
|
+
scope: 'plugin',
|
|
199
|
+
sourcePath,
|
|
200
|
+
pluginName,
|
|
201
|
+
pluginId,
|
|
202
|
+
});
|
|
203
|
+
} catch {
|
|
204
|
+
// Malformed command markdown should not block sibling plugin commands.
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
} catch {
|
|
208
|
+
// Missing or unreadable command folders are treated as empty plugin command sets.
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return skills;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private async readPluginCommandDefinition(
|
|
215
|
+
commandPath: string,
|
|
216
|
+
): Promise<{ name: string; description: string }> {
|
|
217
|
+
const content = await readFile(commandPath, 'utf8');
|
|
218
|
+
const parsed = parseFrontMatter(content);
|
|
219
|
+
const data = readObjectRecord(parsed.data) ?? {};
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
name: stripMarkdownExtension(path.basename(commandPath)),
|
|
223
|
+
description: readOptionalString(data.description) ?? '',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private async listPluginSkillMarkdowns(
|
|
228
|
+
installPath: string,
|
|
229
|
+
pluginId: string,
|
|
230
|
+
pluginName: string,
|
|
231
|
+
): Promise<ProviderSkill[]> {
|
|
232
|
+
const skillFiles = await findProviderSkillMarkdownFiles(path.join(installPath, 'skills'), {
|
|
233
|
+
recursive: true,
|
|
234
|
+
});
|
|
235
|
+
const skills: ProviderSkill[] = [];
|
|
236
|
+
|
|
237
|
+
for (const skillPath of skillFiles) {
|
|
238
|
+
try {
|
|
239
|
+
const definition = await readProviderSkillMarkdownDefinition(skillPath);
|
|
240
|
+
skills.push({
|
|
241
|
+
provider: this.provider,
|
|
242
|
+
name: definition.name,
|
|
243
|
+
description: definition.description,
|
|
244
|
+
command: `/${pluginName}:${definition.name}`,
|
|
245
|
+
scope: 'plugin',
|
|
246
|
+
sourcePath: skillPath,
|
|
247
|
+
pluginName,
|
|
248
|
+
pluginId,
|
|
249
|
+
});
|
|
250
|
+
} catch {
|
|
251
|
+
// A bad plugin skill file should not block other installed plugin skills.
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return skills;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { AbstractProvider } from '@/modules/providers/shared/base/abstract.provider.js';
|
|
2
2
|
import { ClaudeProviderAuth } from '@/modules/providers/list/claude/claude-auth.provider.js';
|
|
3
|
+
import { ClaudeProviderModels } from '@/modules/providers/list/claude/claude-models.provider.js';
|
|
3
4
|
import { ClaudeMcpProvider } from '@/modules/providers/list/claude/claude-mcp.provider.js';
|
|
4
5
|
import { ClaudeSessionSynchronizer } from '@/modules/providers/list/claude/claude-session-synchronizer.provider.js';
|
|
5
6
|
import { ClaudeSessionsProvider } from '@/modules/providers/list/claude/claude-sessions.provider.js';
|
|
6
|
-
import
|
|
7
|
+
import { ClaudeSkillsProvider } from '@/modules/providers/list/claude/claude-skills.provider.js';
|
|
8
|
+
import type {
|
|
9
|
+
IProviderAuth,
|
|
10
|
+
IProviderModels,
|
|
11
|
+
IProviderSessionSynchronizer,
|
|
12
|
+
IProviderSkills,
|
|
13
|
+
IProviderSessions,
|
|
14
|
+
} from '@/shared/interfaces.js';
|
|
7
15
|
|
|
8
16
|
export class ClaudeProvider extends AbstractProvider {
|
|
17
|
+
readonly models: IProviderModels = new ClaudeProviderModels();
|
|
9
18
|
readonly mcp = new ClaudeMcpProvider();
|
|
10
19
|
readonly auth: IProviderAuth = new ClaudeProviderAuth();
|
|
20
|
+
readonly skills: IProviderSkills = new ClaudeSkillsProvider();
|
|
11
21
|
readonly sessions: IProviderSessions = new ClaudeSessionsProvider();
|
|
12
22
|
readonly sessionSynchronizer: IProviderSessionSynchronizer = new ClaudeSessionSynchronizer();
|
|
13
23
|
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import TOML from '@iarna/toml';
|
|
6
|
+
|
|
7
|
+
import type { IProviderModels } from '@/shared/interfaces.js';
|
|
8
|
+
import type {
|
|
9
|
+
ProviderChangeActiveModelInput,
|
|
10
|
+
ProviderCurrentActiveModel,
|
|
11
|
+
ProviderModelOption,
|
|
12
|
+
ProviderModelsDefinition,
|
|
13
|
+
ProviderSessionActiveModelChange,
|
|
14
|
+
} from '@/shared/types.js';
|
|
15
|
+
import {
|
|
16
|
+
buildDefaultProviderCurrentActiveModel,
|
|
17
|
+
readObjectRecord,
|
|
18
|
+
readOptionalString,
|
|
19
|
+
writeProviderSessionActiveModelChange,
|
|
20
|
+
} from '@/shared/utils.js';
|
|
21
|
+
|
|
22
|
+
export const CODEX_FALLBACK_MODELS: ProviderModelsDefinition = {
|
|
23
|
+
OPTIONS: [
|
|
24
|
+
{ value: 'gpt-5.5', label: 'gpt-5.5' },
|
|
25
|
+
{ value: 'gpt-5.4', label: 'gpt-5.4' },
|
|
26
|
+
{ value: 'gpt-5.4-mini', label: 'gpt-5.4-mini' },
|
|
27
|
+
{ value: 'gpt-5.3-codex', label: 'gpt-5.3-codex' },
|
|
28
|
+
{ value: 'gpt-5.2', label: 'gpt-5.2' },
|
|
29
|
+
],
|
|
30
|
+
DEFAULT: 'gpt-5.4',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type CodexCachedModel = {
|
|
34
|
+
slug?: string;
|
|
35
|
+
display_name?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
priority?: number;
|
|
38
|
+
visibility?: string;
|
|
39
|
+
supported_in_api?: boolean;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const CODEX_MODELS_CACHE_PATH = path.join(os.homedir(), '.codex', 'models_cache.json');
|
|
43
|
+
const CODEX_CONFIG_PATH = path.join(os.homedir(), '.codex', 'config.toml');
|
|
44
|
+
|
|
45
|
+
const isCodexCachedModel = (value: unknown): value is CodexCachedModel => {
|
|
46
|
+
const record = readObjectRecord(value);
|
|
47
|
+
return Boolean(record && readOptionalString(record.slug));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const readCodexPriority = (value: unknown): number => (
|
|
51
|
+
typeof value === 'number' && Number.isFinite(value) ? value : Number.MAX_SAFE_INTEGER
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const mapCodexModel = (model: CodexCachedModel): ProviderModelOption => ({
|
|
55
|
+
value: model.slug as string,
|
|
56
|
+
label: readOptionalString(model.display_name) ?? (model.slug as string),
|
|
57
|
+
description: readOptionalString(model.description),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const buildCodexModelsDefinition = (models: CodexCachedModel[]): ProviderModelsDefinition => {
|
|
61
|
+
const sortedModels = [...models]
|
|
62
|
+
.filter((model) => model.visibility !== 'hidden' && model.supported_in_api !== false)
|
|
63
|
+
.sort((left, right) => readCodexPriority(left.priority) - readCodexPriority(right.priority));
|
|
64
|
+
|
|
65
|
+
const options: ProviderModelOption[] = [];
|
|
66
|
+
const seenValues = new Set<string>();
|
|
67
|
+
|
|
68
|
+
for (const model of sortedModels) {
|
|
69
|
+
const mappedModel = mapCodexModel(model);
|
|
70
|
+
if (seenValues.has(mappedModel.value)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
seenValues.add(mappedModel.value);
|
|
75
|
+
options.push(mappedModel);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (options.length === 0) {
|
|
79
|
+
return CODEX_FALLBACK_MODELS;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
OPTIONS: options,
|
|
84
|
+
DEFAULT: options[0]?.value ?? CODEX_FALLBACK_MODELS.DEFAULT,
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export class CodexProviderModels implements IProviderModels {
|
|
89
|
+
async getSupportedModels(): Promise<ProviderModelsDefinition> {
|
|
90
|
+
try {
|
|
91
|
+
const raw = await readFile(CODEX_MODELS_CACHE_PATH, 'utf8');
|
|
92
|
+
const parsed = readObjectRecord(JSON.parse(raw));
|
|
93
|
+
const models = Array.isArray(parsed?.models)
|
|
94
|
+
? parsed.models.filter(isCodexCachedModel)
|
|
95
|
+
: [];
|
|
96
|
+
|
|
97
|
+
return buildCodexModelsDefinition(models);
|
|
98
|
+
} catch {
|
|
99
|
+
return CODEX_FALLBACK_MODELS;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async getCurrentActiveModel(): Promise<ProviderCurrentActiveModel> {
|
|
104
|
+
try {
|
|
105
|
+
const raw = await readFile(CODEX_CONFIG_PATH, 'utf8');
|
|
106
|
+
const parsed = readObjectRecord(TOML.parse(raw));
|
|
107
|
+
const model = readOptionalString(parsed?.model);
|
|
108
|
+
if (!model) {
|
|
109
|
+
return buildDefaultProviderCurrentActiveModel(await this.getSupportedModels());
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
model,
|
|
114
|
+
};
|
|
115
|
+
} catch {
|
|
116
|
+
return buildDefaultProviderCurrentActiveModel(await this.getSupportedModels());
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async changeActiveModel(
|
|
121
|
+
input: ProviderChangeActiveModelInput,
|
|
122
|
+
): Promise<ProviderSessionActiveModelChange> {
|
|
123
|
+
return writeProviderSessionActiveModelChange('codex', input);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os from 'node:os';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
3
4
|
|
|
4
5
|
import { sessionsDb } from '@/modules/database/index.js';
|
|
5
6
|
import {
|
|
@@ -99,7 +100,7 @@ export class CodexSessionSynchronizer implements IProviderSessionSynchronizer {
|
|
|
99
100
|
filePath: string,
|
|
100
101
|
nameMap: Map<string, string>
|
|
101
102
|
): Promise<ParsedSession | null> {
|
|
102
|
-
|
|
103
|
+
const parsed = await extractFirstValidJsonlData(filePath, (rawData) => {
|
|
103
104
|
const data = rawData as Record<string, unknown>;
|
|
104
105
|
const payload = data.payload as Record<string, unknown> | undefined;
|
|
105
106
|
const sessionId = typeof payload?.id === 'string' ? payload.id : undefined;
|
|
@@ -112,8 +113,67 @@ export class CodexSessionSynchronizer implements IProviderSessionSynchronizer {
|
|
|
112
113
|
return {
|
|
113
114
|
sessionId,
|
|
114
115
|
projectPath,
|
|
115
|
-
sessionName: normalizeSessionName(nameMap.get(sessionId), 'Untitled Codex Session'),
|
|
116
116
|
};
|
|
117
117
|
});
|
|
118
|
+
|
|
119
|
+
if (!parsed) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const existingSession = sessionsDb.getSessionById(parsed.sessionId);
|
|
124
|
+
const existingSessionName = existingSession?.custom_name;
|
|
125
|
+
if (existingSessionName && existingSessionName !== 'Untitled Codex Session') {
|
|
126
|
+
return {
|
|
127
|
+
...parsed,
|
|
128
|
+
sessionName: normalizeSessionName(existingSessionName, 'Untitled Codex Session'),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let sessionName = nameMap.get(parsed.sessionId);
|
|
133
|
+
if (!sessionName) {
|
|
134
|
+
sessionName = await this.extractLastAgentMessageFromEnd(filePath);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
...parsed,
|
|
139
|
+
sessionName: normalizeSessionName(sessionName, 'Untitled Codex Session'),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private async extractLastAgentMessageFromEnd(filePath: string): Promise<string | undefined> {
|
|
144
|
+
try {
|
|
145
|
+
const content = await readFile(filePath, 'utf8');
|
|
146
|
+
const lines = content.split(/\r?\n/);
|
|
147
|
+
|
|
148
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
149
|
+
const line = lines[index]?.trim();
|
|
150
|
+
if (!line) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let parsed: unknown;
|
|
155
|
+
try {
|
|
156
|
+
parsed = JSON.parse(line);
|
|
157
|
+
} catch {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const data = parsed as Record<string, unknown>;
|
|
162
|
+
const eventType = typeof data.type === 'string' ? data.type : undefined;
|
|
163
|
+
const payload = data.payload as Record<string, unknown> | undefined;
|
|
164
|
+
const payloadType = typeof payload?.type === 'string' ? payload.type : undefined;
|
|
165
|
+
const lastAgentMessage = typeof payload?.last_agent_message === 'string'
|
|
166
|
+
? payload.last_agent_message
|
|
167
|
+
: undefined;
|
|
168
|
+
|
|
169
|
+
if (eventType === 'event_msg' && payloadType === 'task_complete' && lastAgentMessage?.trim()) {
|
|
170
|
+
return lastAgentMessage;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
174
|
+
// Ignore missing/unreadable files so sync can continue.
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return undefined;
|
|
118
178
|
}
|
|
119
179
|
}
|
|
@@ -520,7 +520,9 @@ export class CodexSessionsProvider implements IProviderSessions {
|
|
|
520
520
|
|
|
521
521
|
let result: CodexHistoryResult;
|
|
522
522
|
try {
|
|
523
|
-
|
|
523
|
+
// Load full history first so `total` reflects frontend-normalized messages,
|
|
524
|
+
// not raw JSONL records.
|
|
525
|
+
result = await getCodexSessionMessages(sessionId, null, 0);
|
|
524
526
|
} catch (error) {
|
|
525
527
|
const message = error instanceof Error ? error.message : String(error);
|
|
526
528
|
console.warn(`[CodexProvider] Failed to load session ${sessionId}:`, message);
|
|
@@ -528,8 +530,6 @@ export class CodexSessionsProvider implements IProviderSessions {
|
|
|
528
530
|
}
|
|
529
531
|
|
|
530
532
|
const rawMessages = Array.isArray(result) ? result : (result.messages || []);
|
|
531
|
-
const total = Array.isArray(result) ? rawMessages.length : (result.total || 0);
|
|
532
|
-
const hasMore = Array.isArray(result) ? false : Boolean(result.hasMore);
|
|
533
533
|
const tokenUsage = Array.isArray(result) ? undefined : result.tokenUsage;
|
|
534
534
|
|
|
535
535
|
const normalized: NormalizedMessage[] = [];
|
|
@@ -552,12 +552,31 @@ export class CodexSessionsProvider implements IProviderSessions {
|
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
554
|
|
|
555
|
+
const totalNormalized = normalized.length;
|
|
556
|
+
let total = 0;
|
|
557
|
+
for (const msg of normalized) {
|
|
558
|
+
if (msg.kind !== 'tool_result') {
|
|
559
|
+
total += 1;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
const normalizedOffset = Math.max(0, offset);
|
|
563
|
+
const normalizedLimit = limit === null ? null : Math.max(0, limit);
|
|
564
|
+
const messages = normalizedLimit === null
|
|
565
|
+
? normalized
|
|
566
|
+
: normalized.slice(
|
|
567
|
+
Math.max(0, totalNormalized - normalizedOffset - normalizedLimit),
|
|
568
|
+
Math.max(0, totalNormalized - normalizedOffset),
|
|
569
|
+
);
|
|
570
|
+
const hasMore = normalizedLimit === null
|
|
571
|
+
? false
|
|
572
|
+
: Math.max(0, totalNormalized - normalizedOffset - normalizedLimit) > 0;
|
|
573
|
+
|
|
555
574
|
return {
|
|
556
|
-
messages
|
|
575
|
+
messages,
|
|
557
576
|
total,
|
|
558
577
|
hasMore,
|
|
559
|
-
offset,
|
|
560
|
-
limit,
|
|
578
|
+
offset: normalizedOffset,
|
|
579
|
+
limit: normalizedLimit,
|
|
561
580
|
tokenUsage,
|
|
562
581
|
};
|
|
563
582
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
import {
|
|
7
|
+
addUniqueProviderSkillSource,
|
|
8
|
+
findTopmostGitRoot,
|
|
9
|
+
} from '@/shared/utils.js';
|
|
10
|
+
|
|
11
|
+
export class CodexSkillsProvider extends SkillsProvider {
|
|
12
|
+
constructor() {
|
|
13
|
+
super('codex');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected async getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]> {
|
|
17
|
+
const sources: ProviderSkillSource[] = [];
|
|
18
|
+
const seenRootDirs = new Set<string>();
|
|
19
|
+
const repoRoot = await findTopmostGitRoot(workspacePath);
|
|
20
|
+
|
|
21
|
+
addUniqueProviderSkillSource(sources, seenRootDirs, {
|
|
22
|
+
scope: 'repo',
|
|
23
|
+
rootDir: path.join(workspacePath, '.agents', 'skills'),
|
|
24
|
+
commandPrefix: '$',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (repoRoot) {
|
|
28
|
+
// Codex checks repository skills at the launch folder, one folder above it,
|
|
29
|
+
// and the topmost git root; these can collapse to the same directory.
|
|
30
|
+
addUniqueProviderSkillSource(sources, seenRootDirs, {
|
|
31
|
+
scope: 'repo',
|
|
32
|
+
rootDir: path.join(path.dirname(workspacePath), '.agents', 'skills'),
|
|
33
|
+
commandPrefix: '$',
|
|
34
|
+
});
|
|
35
|
+
addUniqueProviderSkillSource(sources, seenRootDirs, {
|
|
36
|
+
scope: 'repo',
|
|
37
|
+
rootDir: path.join(repoRoot, '.agents', 'skills'),
|
|
38
|
+
commandPrefix: '$',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
addUniqueProviderSkillSource(sources, seenRootDirs, {
|
|
43
|
+
scope: 'user',
|
|
44
|
+
rootDir: path.join(os.homedir(), '.agents', 'skills'),
|
|
45
|
+
commandPrefix: '$',
|
|
46
|
+
});
|
|
47
|
+
addUniqueProviderSkillSource(sources, seenRootDirs, {
|
|
48
|
+
scope: 'admin',
|
|
49
|
+
rootDir: path.join('/etc', 'codex', 'skills'),
|
|
50
|
+
commandPrefix: '$',
|
|
51
|
+
});
|
|
52
|
+
addUniqueProviderSkillSource(sources, seenRootDirs, {
|
|
53
|
+
scope: 'system',
|
|
54
|
+
rootDir: path.join(os.homedir(), '.codex', 'skills', '.system'),
|
|
55
|
+
commandPrefix: '$',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return sources;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { AbstractProvider } from '@/modules/providers/shared/base/abstract.provider.js';
|
|
2
2
|
import { CodexProviderAuth } from '@/modules/providers/list/codex/codex-auth.provider.js';
|
|
3
|
+
import { CodexProviderModels } from '@/modules/providers/list/codex/codex-models.provider.js';
|
|
3
4
|
import { CodexMcpProvider } from '@/modules/providers/list/codex/codex-mcp.provider.js';
|
|
4
5
|
import { CodexSessionSynchronizer } from '@/modules/providers/list/codex/codex-session-synchronizer.provider.js';
|
|
5
6
|
import { CodexSessionsProvider } from '@/modules/providers/list/codex/codex-sessions.provider.js';
|
|
6
|
-
import
|
|
7
|
+
import { CodexSkillsProvider } from '@/modules/providers/list/codex/codex-skills.provider.js';
|
|
8
|
+
import type {
|
|
9
|
+
IProviderAuth,
|
|
10
|
+
IProviderModels,
|
|
11
|
+
IProviderSessionSynchronizer,
|
|
12
|
+
IProviderSkills,
|
|
13
|
+
IProviderSessions,
|
|
14
|
+
} from '@/shared/interfaces.js';
|
|
7
15
|
|
|
8
16
|
export class CodexProvider extends AbstractProvider {
|
|
17
|
+
readonly models: IProviderModels = new CodexProviderModels();
|
|
9
18
|
readonly mcp = new CodexMcpProvider();
|
|
10
19
|
readonly auth: IProviderAuth = new CodexProviderAuth();
|
|
20
|
+
readonly skills: IProviderSkills = new CodexSkillsProvider();
|
|
11
21
|
readonly sessions: IProviderSessions = new CodexSessionsProvider();
|
|
12
22
|
readonly sessionSynchronizer: IProviderSessionSynchronizer = new CodexSessionSynchronizer();
|
|
13
23
|
|