@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.
Files changed (147) hide show
  1. package/dist/assets/index-AaSE7-3t.js +1336 -0
  2. package/dist/assets/index-CKaku72N.css +32 -0
  3. package/dist/index.html +2 -2
  4. package/dist-server/server/claude-sdk.js +10 -5
  5. package/dist-server/server/claude-sdk.js.map +1 -1
  6. package/dist-server/server/cursor-cli.js +0 -6
  7. package/dist-server/server/cursor-cli.js.map +1 -1
  8. package/dist-server/server/gemini-cli.js +160 -34
  9. package/dist-server/server/gemini-cli.js.map +1 -1
  10. package/dist-server/server/modules/database/migrations.js +11 -0
  11. package/dist-server/server/modules/database/migrations.js.map +1 -1
  12. package/dist-server/server/modules/database/repositories/projects.db.js +12 -0
  13. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -1
  14. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js +61 -0
  15. package/dist-server/server/modules/database/repositories/sessions.db.integration.test.js.map +1 -0
  16. package/dist-server/server/modules/database/repositories/sessions.db.js +49 -8
  17. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
  18. package/dist-server/server/modules/database/schema.js +1 -0
  19. package/dist-server/server/modules/database/schema.js.map +1 -1
  20. package/dist-server/server/modules/projects/projects.routes.js +12 -3
  21. package/dist-server/server/modules/projects/projects.routes.js.map +1 -1
  22. package/dist-server/server/modules/projects/services/project-delete.service.js +14 -1
  23. package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -1
  24. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +43 -0
  25. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
  26. package/dist-server/server/modules/providers/index.js +1 -0
  27. package/dist-server/server/modules/providers/index.js.map +1 -1
  28. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +2 -1
  29. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
  30. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +55 -2
  31. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
  32. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +153 -14
  33. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
  34. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +198 -0
  35. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -0
  36. package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
  37. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
  38. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +54 -2
  39. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
  40. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +21 -6
  41. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
  42. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +82 -0
  43. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -0
  44. package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
  45. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
  46. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +8 -30
  47. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
  48. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +189 -13
  49. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -1
  50. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +28 -0
  51. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -0
  52. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +2 -0
  53. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -1
  54. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +125 -2
  55. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -1
  56. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js +24 -8
  57. package/dist-server/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.js.map +1 -1
  58. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +7 -1
  59. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -1
  60. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js +33 -0
  61. package/dist-server/server/modules/providers/list/gemini/gemini-skills.provider.js.map +1 -0
  62. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +2 -0
  63. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -1
  64. package/dist-server/server/modules/providers/provider.routes.js +23 -2
  65. package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
  66. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +129 -13
  67. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
  68. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +7 -5
  69. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
  70. package/dist-server/server/modules/providers/services/sessions.service.js +81 -7
  71. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
  72. package/dist-server/server/modules/providers/services/skills.service.js +11 -0
  73. package/dist-server/server/modules/providers/services/skills.service.js.map +1 -0
  74. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -1
  75. package/dist-server/server/modules/providers/shared/skills/skills.provider.js +45 -0
  76. package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -0
  77. package/dist-server/server/modules/providers/tests/skills.test.js +226 -0
  78. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
  79. package/dist-server/server/openai-codex.js +56 -26
  80. package/dist-server/server/openai-codex.js.map +1 -1
  81. package/dist-server/server/routes/commands.js +5 -5
  82. package/dist-server/server/routes/commands.js.map +1 -1
  83. package/dist-server/server/shared/claude-cli-path.js +103 -0
  84. package/dist-server/server/shared/claude-cli-path.js.map +1 -0
  85. package/dist-server/server/shared/claude-cli-path.test.js +45 -0
  86. package/dist-server/server/shared/claude-cli-path.test.js.map +1 -0
  87. package/dist-server/server/{utils → shared}/frontmatter.js +3 -3
  88. package/dist-server/server/shared/frontmatter.js.map +1 -0
  89. package/dist-server/server/shared/utils.js +82 -0
  90. package/dist-server/server/shared/utils.js.map +1 -1
  91. package/dist-server/server/utils/commandParser.js +3 -3
  92. package/dist-server/server/utils/commandParser.js.map +1 -1
  93. package/dist-server/shared/modelConstants.js +1 -0
  94. package/dist-server/shared/modelConstants.js.map +1 -1
  95. package/package.json +1 -1
  96. package/server/claude-sdk.js +10 -5
  97. package/server/cursor-cli.js +0 -8
  98. package/server/gemini-cli.js +190 -42
  99. package/server/modules/database/migrations.ts +12 -0
  100. package/server/modules/database/repositories/projects.db.ts +13 -0
  101. package/server/modules/database/repositories/sessions.db.integration.test.ts +72 -0
  102. package/server/modules/database/repositories/sessions.db.ts +60 -9
  103. package/server/modules/database/schema.ts +1 -0
  104. package/server/modules/projects/projects.routes.ts +20 -3
  105. package/server/modules/projects/services/project-delete.service.ts +16 -1
  106. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +64 -0
  107. package/server/modules/providers/README.md +346 -0
  108. package/server/modules/providers/index.ts +2 -1
  109. package/server/modules/providers/list/claude/claude-auth.provider.ts +8 -7
  110. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +68 -2
  111. package/server/modules/providers/list/claude/claude-sessions.provider.ts +175 -14
  112. package/server/modules/providers/list/claude/claude-skills.provider.ts +257 -0
  113. package/server/modules/providers/list/claude/claude.provider.ts +8 -1
  114. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +62 -2
  115. package/server/modules/providers/list/codex/codex-sessions.provider.ts +25 -6
  116. package/server/modules/providers/list/codex/codex-skills.provider.ts +100 -0
  117. package/server/modules/providers/list/codex/codex.provider.ts +8 -1
  118. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +17 -40
  119. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +216 -13
  120. package/server/modules/providers/list/cursor/cursor-skills.provider.ts +31 -0
  121. package/server/modules/providers/list/cursor/cursor.provider.ts +8 -1
  122. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +158 -2
  123. package/server/modules/providers/list/gemini/gemini-session-synchronizer.provider.ts +24 -20
  124. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +7 -1
  125. package/server/modules/providers/list/gemini/gemini-skills.provider.ts +36 -0
  126. package/server/modules/providers/list/gemini/gemini.provider.ts +8 -1
  127. package/server/modules/providers/provider.routes.ts +35 -2
  128. package/server/modules/providers/services/session-conversations-search.service.ts +162 -13
  129. package/server/modules/providers/services/sessions-watcher.service.ts +7 -5
  130. package/server/modules/providers/services/sessions.service.ts +112 -9
  131. package/server/modules/providers/services/skills.service.ts +15 -0
  132. package/server/modules/providers/shared/base/abstract.provider.ts +2 -0
  133. package/server/modules/providers/shared/skills/skills.provider.ts +64 -0
  134. package/server/modules/providers/tests/skills.test.ts +446 -0
  135. package/server/openai-codex.js +59 -27
  136. package/server/routes/commands.js +7 -5
  137. package/server/shared/claude-cli-path.test.ts +61 -0
  138. package/server/shared/claude-cli-path.ts +139 -0
  139. package/server/{utils/frontmatter.js → shared/frontmatter.ts} +3 -3
  140. package/server/shared/interfaces.ts +19 -0
  141. package/server/shared/types.ts +78 -0
  142. package/server/shared/utils.ts +94 -0
  143. package/server/utils/commandParser.js +5 -3
  144. package/shared/modelConstants.js +1 -0
  145. package/dist/assets/index-6rYG_mRo.css +0 -32
  146. package/dist/assets/index-DqMVUeZS.js +0 -1331
  147. package/dist-server/server/utils/frontmatter.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import fsp from 'node:fs/promises';
2
+ import path from 'node:path';
2
3
 
3
- import { sessionsDb } from '@/modules/database/index.js';
4
+ import { projectsDb, sessionsDb } from '@/modules/database/index.js';
4
5
  import { providerRegistry } from '@/modules/providers/provider.registry.js';
5
6
  import type {
6
7
  FetchHistoryOptions,
@@ -10,6 +11,19 @@ import type {
10
11
  } from '@/shared/types.js';
11
12
  import { AppError } from '@/shared/utils.js';
12
13
 
14
+ type ArchivedSessionListItem = {
15
+ sessionId: string;
16
+ provider: LLMProvider;
17
+ projectId: string | null;
18
+ projectPath: string | null;
19
+ projectDisplayName: string;
20
+ sessionTitle: string;
21
+ createdAt: string | null;
22
+ updatedAt: string | null;
23
+ lastActivity: string | null;
24
+ isProjectArchived: boolean;
25
+ };
26
+
13
27
  /**
14
28
  * Removes one file if it exists.
15
29
  */
@@ -26,6 +40,28 @@ async function removeFileIfExists(filePath: string): Promise<boolean> {
26
40
  }
27
41
  }
28
42
 
43
+ /**
44
+ * Archive rows need a stable project label even when the owning project is not
45
+ * part of the active sidebar payload. This lightweight resolver keeps the
46
+ * archive API self-contained while still matching the project's stored display
47
+ * name when one exists.
48
+ */
49
+ function resolveProjectDisplayName(
50
+ projectPath: string | null,
51
+ customProjectName: string | null | undefined,
52
+ ): string {
53
+ const trimmedCustomName = typeof customProjectName === 'string' ? customProjectName.trim() : '';
54
+ if (trimmedCustomName.length > 0) {
55
+ return trimmedCustomName;
56
+ }
57
+
58
+ if (!projectPath) {
59
+ return 'Unknown Project';
60
+ }
61
+
62
+ return path.basename(projectPath) || projectPath;
63
+ }
64
+
29
65
  /**
30
66
  * Application service for provider-backed session message operations.
31
67
  *
@@ -79,15 +115,53 @@ export const sessionsService = {
79
115
  },
80
116
 
81
117
  /**
82
- * Deletes one persisted session row by id.
118
+ * Returns archived sessions with enough project metadata for the sidebar to
119
+ * group, filter, open, and restore them without a per-row follow-up query.
120
+ */
121
+ listArchivedSessions(): ArchivedSessionListItem[] {
122
+ const archivedSessions = sessionsDb.getArchivedSessions();
123
+ const projectCache = new Map<string, ReturnType<typeof projectsDb.getProjectPath>>();
124
+
125
+ return archivedSessions.map((session) => {
126
+ const projectPath = session.project_path?.trim() ? session.project_path : null;
127
+ let project = null;
128
+
129
+ if (projectPath) {
130
+ if (!projectCache.has(projectPath)) {
131
+ projectCache.set(projectPath, projectsDb.getProjectPath(projectPath));
132
+ }
133
+ project = projectCache.get(projectPath) ?? null;
134
+ }
135
+
136
+ return {
137
+ sessionId: session.session_id,
138
+ provider: session.provider as LLMProvider,
139
+ projectId: project?.project_id ?? null,
140
+ projectPath,
141
+ projectDisplayName: resolveProjectDisplayName(projectPath, project?.custom_project_name),
142
+ sessionTitle: session.custom_name?.trim() || session.session_id,
143
+ createdAt: session.created_at ?? null,
144
+ updatedAt: session.updated_at ?? null,
145
+ lastActivity: session.updated_at ?? session.created_at ?? null,
146
+ isProjectArchived: Boolean(project?.isArchived),
147
+ };
148
+ });
149
+ },
150
+
151
+ /**
152
+ * Archives or permanently deletes one persisted session row by id.
83
153
  *
84
- * When `deletedFromDisk` is true and a session `jsonl_path` exists, the path
85
- * is deleted from disk before the DB row is removed.
154
+ * Soft-delete mirrors the project behavior by toggling `isArchived` so the
155
+ * row disappears from active lists but remains restorable. Force-delete
156
+ * optionally removes the transcript file before deleting the database row.
86
157
  */
87
- async deleteSessionById(
158
+ async deleteOrArchiveSessionById(
88
159
  sessionId: string,
89
- deletedFromDisk = false,
90
- ): Promise<{ sessionId: string; deletedFromDisk: boolean }> {
160
+ options: {
161
+ force?: boolean;
162
+ deletedFromDisk?: boolean;
163
+ } = {},
164
+ ): Promise<{ sessionId: string; action: 'archived' | 'deleted'; deletedFromDisk: boolean }> {
91
165
  const session = sessionsDb.getSessionById(sessionId);
92
166
  if (!session) {
93
167
  throw new AppError(`Session "${sessionId}" was not found.`, {
@@ -96,8 +170,17 @@ export const sessionsService = {
96
170
  });
97
171
  }
98
172
 
173
+ if (!options.force) {
174
+ sessionsDb.updateSessionIsArchived(sessionId, true);
175
+ return {
176
+ sessionId,
177
+ action: 'archived',
178
+ deletedFromDisk: false,
179
+ };
180
+ }
181
+
99
182
  let removedFromDisk = false;
100
- if (deletedFromDisk && session.jsonl_path) {
183
+ if (options.deletedFromDisk && session.jsonl_path) {
101
184
  removedFromDisk = await removeFileIfExists(session.jsonl_path);
102
185
  }
103
186
 
@@ -109,7 +192,27 @@ export const sessionsService = {
109
192
  });
110
193
  }
111
194
 
112
- return { sessionId, deletedFromDisk: removedFromDisk };
195
+ return {
196
+ sessionId,
197
+ action: 'deleted',
198
+ deletedFromDisk: removedFromDisk,
199
+ };
200
+ },
201
+
202
+ /**
203
+ * Restores one archived session back into the active sidebar lists.
204
+ */
205
+ restoreSessionById(sessionId: string): { sessionId: string; isArchived: false } {
206
+ const session = sessionsDb.getSessionById(sessionId);
207
+ if (!session) {
208
+ throw new AppError(`Session "${sessionId}" was not found.`, {
209
+ code: 'SESSION_NOT_FOUND',
210
+ statusCode: 404,
211
+ });
212
+ }
213
+
214
+ sessionsDb.updateSessionIsArchived(sessionId, false);
215
+ return { sessionId, isArchived: false };
113
216
  },
114
217
 
115
218
  /**
@@ -0,0 +1,15 @@
1
+ import { providerRegistry } from '@/modules/providers/provider.registry.js';
2
+ import type { ProviderSkill, ProviderSkillListOptions } from '@/shared/types.js';
3
+
4
+ export const providerSkillsService = {
5
+ /**
6
+ * Lists normalized skills visible to one provider.
7
+ */
8
+ async listProviderSkills(
9
+ providerName: string,
10
+ options?: ProviderSkillListOptions,
11
+ ): Promise<ProviderSkill[]> {
12
+ const provider = providerRegistry.resolveProvider(providerName);
13
+ return provider.skills.listSkills(options);
14
+ },
15
+ };
@@ -3,6 +3,7 @@ import type {
3
3
  IProviderAuth,
4
4
  IProviderMcp,
5
5
  IProviderSessionSynchronizer,
6
+ IProviderSkills,
6
7
  IProviderSessions,
7
8
  } from '@/shared/interfaces.js';
8
9
  import type { LLMProvider } from '@/shared/types.js';
@@ -18,6 +19,7 @@ export abstract class AbstractProvider implements IProvider {
18
19
  readonly id: LLMProvider;
19
20
  abstract readonly mcp: IProviderMcp;
20
21
  abstract readonly auth: IProviderAuth;
22
+ abstract readonly skills: IProviderSkills;
21
23
  abstract readonly sessions: IProviderSessions;
22
24
  abstract readonly sessionSynchronizer: IProviderSessionSynchronizer;
23
25
 
@@ -0,0 +1,64 @@
1
+ import path from 'node:path';
2
+
3
+ import type { IProviderSkills } from '@/shared/interfaces.js';
4
+ import type {
5
+ LLMProvider,
6
+ ProviderSkill,
7
+ ProviderSkillListOptions,
8
+ ProviderSkillSource,
9
+ } from '@/shared/types.js';
10
+ import {
11
+ findProviderSkillMarkdownFiles,
12
+ readProviderSkillMarkdownDefinition,
13
+ } from '@/shared/utils.js';
14
+
15
+ const resolveWorkspacePath = (workspacePath?: string): string =>
16
+ path.resolve(workspacePath ?? process.cwd());
17
+
18
+ /**
19
+ * Shared skills provider for provider-specific skill source discovery.
20
+ */
21
+ export abstract class SkillsProvider implements IProviderSkills {
22
+ protected readonly provider: LLMProvider;
23
+
24
+ protected constructor(provider: LLMProvider) {
25
+ this.provider = provider;
26
+ }
27
+
28
+ async listSkills(options?: ProviderSkillListOptions): Promise<ProviderSkill[]> {
29
+ const workspacePath = resolveWorkspacePath(options?.workspacePath);
30
+ const sources = await this.getSkillSources(workspacePath);
31
+ const skills: ProviderSkill[] = [];
32
+
33
+ for (const source of sources) {
34
+ const skillFiles = await findProviderSkillMarkdownFiles(source.rootDir, {
35
+ recursive: source.recursive,
36
+ });
37
+ for (const skillPath of skillFiles) {
38
+ try {
39
+ const definition = await readProviderSkillMarkdownDefinition(skillPath);
40
+ const command = source.commandForSkill
41
+ ? source.commandForSkill(definition.name)
42
+ : `${source.commandPrefix ?? '/'}${definition.name}`;
43
+
44
+ skills.push({
45
+ provider: this.provider,
46
+ name: definition.name,
47
+ description: definition.description,
48
+ command,
49
+ scope: source.scope,
50
+ sourcePath: skillPath,
51
+ pluginName: source.pluginName,
52
+ pluginId: source.pluginId,
53
+ });
54
+ } catch {
55
+ // A malformed or unreadable skill markdown file should not hide other valid skills.
56
+ }
57
+ }
58
+ }
59
+
60
+ return skills;
61
+ }
62
+
63
+ protected abstract getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]>;
64
+ }