Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions apps/desktop/src/main/ipc/prompt.ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ export function registerPromptIPC(db: PromptDB, folderDb: FolderDB, rawDb: Datab
return ordered;
};

const assertPromptMoveInput = (
promptId: string,
newParentId: string | null,
newOrder: number,
) => {
if (typeof promptId !== 'string' || promptId.trim().length === 0) {
throw new Error('Prompt id is required');
}
if (
newParentId !== null &&
(typeof newParentId !== 'string' || newParentId.trim().length === 0)
) {
throw new Error('Parent prompt id must be null or a non-empty string');
}
if (!Number.isFinite(newOrder) || newOrder < 0) {
throw new Error('Prompt order must be a non-negative number');
}
Comment on lines +59 to +70

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

错误信息缺少上下文,定位非法入参会很慢。

Line 60、Line 66、Line 69 的报错都没有包含失败字段和值,调用端很难快速定位是哪一个参数导致失败。建议在不暴露敏感信息前提下补充 promptId/newParentId/newOrder 的上下文。

As per coding guidelines, "Error messages must include context (what failed, with what input)."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/main/ipc/prompt.ipc.ts` around lines 59 - 70, The error
messages in the prompt validation block lack context about which parameters and
values failed validation. Enhance each of the three error throws (for promptId
validation around line 60, newParentId validation around line 66, and newOrder
validation around line 69) to include the actual parameter values or
descriptions in the error message. For example, include the promptId value, the
newParentId value, and the newOrder value in their respective error messages to
help callers quickly identify which parameter caused the failure.

Source: Coding guidelines

};

// Create Prompt
// 创建 Prompt
ipcMain.handle(IPC_CHANNELS.PROMPT_CREATE, async (_, data: CreatePromptDTO) => {
Expand Down Expand Up @@ -249,4 +268,11 @@ export function registerPromptIPC(db: PromptDB, folderDb: FolderDB, rawDb: Datab
db.insertVersionDirect(version);
return true;
});

ipcMain.handle(IPC_CHANNELS.PROMPT_MOVE, async (_, promptId: string, newParentId: string | null, newOrder: number) => {
assertPromptMoveInput(promptId, newParentId, newOrder);
db.movePrompt(promptId, newParentId, newOrder);
syncWorkspace();
return true;
});
}
2 changes: 2 additions & 0 deletions apps/desktop/src/preload/api/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,6 @@ export const promptApi = {
prompts: Prompt[];
versions: PromptVersion[];
}) => ipcRenderer.invoke(IPC_CHANNELS.PROMPT_MIGRATE_IDB_BATCH, payload),
move: (promptId: string, newParentId: string | null, newOrder: number) =>
ipcRenderer.invoke(IPC_CHANNELS.PROMPT_MOVE, promptId, newParentId, newOrder),
Comment on lines +43 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Exported functions missing return types 📘 Rule violation ⚙ Maintainability

8.1

New exported API surfaces omit explicit return type annotations, making contract drift harder to
detect and weakening strict typing guarantees. This violates the requirement that exported functions
have explicit return types.
Agent Prompt
## Issue description
Exported functions must include explicit return type annotations.

## Issue Context
- `promptApi.move` is part of an exported API object but has no explicit return type.
- `PromptListView` is an exported function component without an explicit return type annotation.

## Fix Focus Areas
- apps/desktop/src/preload/api/prompt.ts[43-44]
- apps/desktop/src/renderer/components/prompt/PromptListView.tsx[59-69]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +43 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n apps/desktop/src/preload/api/prompt.ts | head -60

Repository: legeling/PromptHub

Length of output: 2409


🏁 Script executed:

rg -t ts -t tsx "ipcRenderer\.invoke" apps/desktop/src/preload/api/ -A 1 -B 1

Repository: legeling/PromptHub

Length of output: 90


🏁 Script executed:

# 查找是否有类型定义文件
fd -e "d.ts" "ipcRenderer\|electron" apps/

Repository: legeling/PromptHub

Length of output: 44


🏁 Script executed:

# 检查编码指南中关于导出函数的适用范围
head -100 apps/desktop/src/preload/api/prompt.ts

Repository: legeling/PromptHub

Length of output: 2094


🏁 Script executed:

# 查看 TypeScript 配置
find apps/desktop -name "tsconfig.json" | head -5

Repository: legeling/PromptHub

Length of output: 89


🏁 Script executed:

# 查看其他 API 文件的实现方式
find apps/desktop/src/preload/api -name "*.ts" | head -10

Repository: legeling/PromptHub

Length of output: 450


🏁 Script executed:

# 查看 ipcRenderer 的类型定义
rg "ipcRenderer" apps/desktop -t ts --no-heading | grep -i "type\|interface" | head -20

Repository: legeling/PromptHub

Length of output: 44


🏁 Script executed:

cat -n apps/desktop/tsconfig.json

Repository: legeling/PromptHub

Length of output: 1347


🏁 Script executed:

cat -n apps/desktop/src/preload/api/folder.ts

Repository: legeling/PromptHub

Length of output: 982


🏁 Script executed:

cat -n apps/desktop/src/preload/api/ai.ts

Repository: legeling/PromptHub

Length of output: 2362


move 需要显式返回类型注解,保持 IPC 调用链的类型安全。

当前 move 方法缺少返回类型,ipcRenderer.invoke() 的返回值默认推导为宽泛类型,弱化类型契约。参考 ai.tsrequest 方法的做法,建议补充显式返回类型注解(如 Promise<void>),并使用泛型化 ipcRenderer.invoke<ReturnType>()

符合编码指南要求:"All exported functions must have explicit return type annotations."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/preload/api/prompt.ts` around lines 43 - 44, The `move`
method in the prompt API lacks an explicit return type annotation, which weakens
type safety for the IPC call chain. Add an explicit return type annotation to
the arrow function (such as `Promise<void>` or the appropriate return type), and
use generic typing on the `ipcRenderer.invoke()` call by specifying the expected
return type as a generic parameter. Follow the same pattern used in the
`request` method from `ai.ts` to maintain consistency and comply with the coding
guideline requiring all exported functions to have explicit return type
annotations.

Source: Coding guidelines

};
57 changes: 22 additions & 35 deletions apps/desktop/src/renderer/components/layout/MainContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ const SkillManager = lazy(() => import('../skill/SkillManager').then(m => ({ def
const RulesManager = lazy(() => import('../rules/RulesManager').then(m => ({ default: m.RulesManager })));
const EditPromptModal = lazy(() => import('../prompt/EditPromptModal').then(m => ({ default: m.EditPromptModal })));
const PromptQuickRewriteDialog = lazy(() => import('../prompt/PromptQuickRewriteDialog').then(m => ({ default: m.PromptQuickRewriteDialog })));
const PromptTableView = lazy(() => import('../prompt/PromptTableView').then(m => ({ default: m.PromptTableView })));
const PromptGalleryView = lazy(() => import('../prompt/PromptGalleryView').then(m => ({ default: m.PromptGalleryView })));
const PromptKanbanView = lazy(() => import('../prompt/PromptKanbanView').then(m => ({ default: m.PromptKanbanView })));
const PromptListView = lazy(() => import('../prompt/PromptListView').then(m => ({ default: m.PromptListView })));
const AiTestModal = lazy(() => import('../prompt/AiTestModal').then(m => ({ default: m.AiTestModal })));
const PromptDetailModal = lazy(() => import('../prompt/PromptDetailModal').then(m => ({ default: m.PromptDetailModal })));
const VariableInputModal = lazy(() => import('../prompt/VariableInputModal').then(m => ({ default: m.VariableInputModal })));
Expand Down Expand Up @@ -367,6 +367,7 @@ function PromptSkillMainContent() {
const sortOrder = usePromptStore((state) => state.sortOrder);
const viewMode = usePromptStore((state) => state.viewMode);
const incrementUsageCount = usePromptStore((state) => state.incrementUsageCount);
const movePrompt = usePromptStore((state) => state.movePrompt);
// Resizable prompt-list pane width (#119)
const promptListPaneWidth = useUIStore((state) => state.promptListPaneWidth);
const setPromptListPaneWidth = useUIStore(
Expand Down Expand Up @@ -1928,23 +1929,16 @@ function PromptSkillMainContent() {
</Suspense>
) : (
<>
{/* List view mode */}
{/* 列表视图模式 */}
{/* Gallery view */}
{/* Gallery 视图 */}
<div
className={getViewClass('list')}
className={getViewClass('gallery')}
>


{/* Top: sort + view switch */}
{/* 顶部:排序 + 视图切换 */}
<PromptListHeader count={sortedPrompts.length} />

{/* Table view */}
{/* 表格视图 */}
<div className="flex-1 overflow-hidden">
{viewMode === 'gallery' && (
<Suspense fallback={loadingFallback}>
<PromptTableView
prompts={sortedPrompts}
<PromptGalleryView
prompts={visiblePrompts}
highlightTerms={highlightTerms}
onSelect={(id) => selectPrompt(id)}
onToggleFavorite={toggleFavorite}
Expand All @@ -1954,25 +1948,21 @@ function PromptSkillMainContent() {
onAiTest={handleAiTestFromTable}
onVersionHistory={handleVersionHistory}
onViewDetail={handleViewDetail}
aiResults={aiResponseCache}
onBatchFavorite={handleBatchFavorite}
onBatchMove={handleBatchMove}
onBatchDelete={handleBatchDelete}
onContextMenu={handleContextMenu}
/>
</Suspense>
</div>
)}
</div>

{/* Gallery view */}
{/* Gallery 视图 */}
{/* Kanban view */}
{/* 看板视图 */}
<div
className={getViewClass('gallery')}
className={getViewClass('kanban')}
>
<PromptListHeader count={sortedPrompts.length} />
{viewMode === 'gallery' && (
{viewMode === 'kanban' && (
<Suspense fallback={loadingFallback}>
<PromptGalleryView
<PromptKanbanView
prompts={visiblePrompts}
highlightTerms={highlightTerms}
onSelect={(id) => selectPrompt(id)}
Expand All @@ -1989,26 +1979,23 @@ function PromptSkillMainContent() {
)}
</div>

{/* Kanban view */}
{/* 看板视图 */}
{/* List view mode: hierarchical list with drag-and-drop */}
{/* 列表视图模式:分层列表支持拖拽 */}
<div
className={getViewClass('kanban')}
className={getViewClass('list')}
>
<PromptListHeader count={sortedPrompts.length} />
{viewMode === 'kanban' && (
{viewMode === 'list' && (
<Suspense fallback={loadingFallback}>
<PromptKanbanView
<PromptListView
prompts={visiblePrompts}
highlightTerms={highlightTerms}
selectedId={selectedId}
selectedIds={selectedIds}
onSelect={(id) => selectPrompt(id)}
onToggleFavorite={toggleFavorite}
onCopy={handleCopyPrompt}
onEdit={(prompt) => setEditingPrompt(prompt)}
onDelete={handleDeletePrompt}
onAiTest={handleAiTestFromTable}
onVersionHistory={handleVersionHistory}
onViewDetail={handleViewDetail}
onContextMenu={handleContextMenu}
onMovePrompt={movePrompt}
/>
Comment on lines 1987 to 1999

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

列表视图里的排序控件现在是无效操作。

这一分支继续渲染 PromptListHeader,但 PromptListView 内部固定按 hierarchy 的 order/title/id 排序,而且这里也没有把 sortBy / sortOrder 传下去,所以用户改排序在 list 模式下不会生效。要么把排序状态真正接入树渲染,要么在 list 模式隐藏/禁用这些控件,避免出现“能点但没效果”的 UI。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/layout/MainContent.tsx` around lines
1987 - 1999, The PromptListHeader component renders sort controls that have no
effect because the PromptListView component does not accept or use sortBy and
sortOrder props, and instead uses hardcoded hierarchy-based sorting. Either pass
the current sortBy and sortOrder state as props to PromptListView and implement
sorting logic based on these props instead of the hardcoded order/title/id
sorting, or conditionally hide/disable the sort controls in PromptListHeader
when viewMode is 'list' to prevent users from interacting with non-functional
controls.

</Suspense>
)}
Expand Down
Loading
Loading