Compare commits

..

1 Commits

Author SHA1 Message Date
Jiang Bohan
e149075d20 fix(desktop): show git-described version in dev instead of stale 0.1.0
Packaged builds are unaffected: scripts/package.mjs already injects the
git tag into electron-builder's extraMetadata.version, so the .app users
download from GitHub Release reports the right version through
app.getVersion() and the auto-updater's latest.yml comparison works
correctly.

Dev mode (`pnpm dev:desktop`) didn't go through that path though, so
app.getVersion() returned the static "0.1.0" from package.json — the
new Settings → Updates panel surfaced this and made it look like the
dev build was ancient. Add a tiny getAppVersion() helper that falls
back to `git describe --tags --always --dirty` only when !app.isPackaged,
and use it for the app-info IPC. No change to packaged behavior; if git
is unavailable for any reason, we silently fall back to app.getVersion().
2026-04-29 19:15:03 +08:00
9 changed files with 19 additions and 23 deletions

View File

@@ -78,7 +78,9 @@ export function ModelPicker({
);
}
const triggerLabel = value || "Default";
const triggerLabel =
value ||
(defaultModel ? `Default — ${defaultModel.label}` : "Default");
const triggerTitle = `Model · ${triggerLabel}`;
return (

View File

@@ -42,6 +42,7 @@ export function ModelDropdown({
const supported = modelsQuery.data?.supported ?? true;
const models = modelsQuery.data?.models ?? [];
const defaultModel = useMemo(() => models.find((m) => m.default), [models]);
const grouped = useMemo(() => groupByProvider(models), [models]);
// When the selected runtime reports it doesn't support per-agent
@@ -85,7 +86,9 @@ export function ModelDropdown({
(disabled
? "Select a runtime first"
: runtimeOnline
? "Default (provider)"
? defaultModel
? `Default — ${defaultModel.label}`
: "Default (provider)"
: "Runtime offline — enter manually");
if (!supported && !modelsQuery.isLoading) {

View File

@@ -88,11 +88,6 @@ export function InboxDetailLabel({ item }: { item: InboxItem }) {
if (emoji) return <span>Reacted {emoji} to your comment</span>;
return <span>{typeLabels[item.type]}</span>;
}
case "quick_create_done": {
const identifier = details.identifier;
if (identifier) return <span>Created {identifier}</span>;
return <span>{typeLabels[item.type]}</span>;
}
default:
return <span>{typeLabels[item.type] ?? item.type}</span>;
}

View File

@@ -506,6 +506,9 @@ export function IssueDetail({ issueId, onDelete, defaultSidebarOpen = true, layo
<ChevronRight className="h-3 w-3 text-muted-foreground/50 shrink-0" />
</>
)}
<span className="shrink-0 text-muted-foreground">
{issue.identifier}
</span>
<span className="truncate font-medium text-foreground">
{issue.title}
</span>

View File

@@ -560,7 +560,7 @@ export function AppSidebar({ topSlot, searchSlot, headerClassName, headerStyle }
<SidebarMenuItem>
<SidebarMenuButton
className="text-muted-foreground"
onClick={() => useModalStore.getState().open("quick-create-issue")}
onClick={() => useModalStore.getState().open("create-issue")}
>
<span className="relative">
<SquarePen />

View File

@@ -37,7 +37,6 @@ import {
useFileDropZone,
FileDropOverlay,
} from "../editor";
import { FileUploadButton } from "@multica/ui/components/common/file-upload-button";
// AgentCreatePanel — agent-mode body of the create-issue dialog. Renders
// only the inner content; the surrounding `<Dialog>` AND `<DialogContent>`
@@ -136,7 +135,7 @@ export function AgentCreatePanel({
// Image paste/drop support: route uploads through the same helper Advanced
// uses, so users can paste screenshots straight into the prompt and the
// agent receives them as embedded markdown image URLs in the prompt.
const { uploadWithToast, uploading } = useFileUpload(api);
const { uploadWithToast } = useFileUpload(api);
const handleUploadFile = useCallback(
(file: File) => uploadWithToast(file),
[uploadWithToast],
@@ -155,7 +154,7 @@ export function AgentCreatePanel({
const submit = async () => {
const md = editorRef.current?.getMarkdown()?.trim() ?? "";
if (!md || !agentId || submitting || versionBlocked || uploading) return;
if (!md || !agentId || submitting || versionBlocked) return;
setSubmitting(true);
setError(null);
try {
@@ -335,13 +334,7 @@ export function AgentCreatePanel({
{/* Footer */}
<div className="flex items-center justify-between px-4 py-3 border-t shrink-0">
<div className="flex items-center gap-1.5">
<FileUploadButton
size="sm"
onSelect={(file) => editorRef.current?.uploadFile(file)}
/>
<span className="text-xs text-muted-foreground"> to submit</span>
</div>
<span className="text-xs text-muted-foreground"> to submit</span>
<div className="flex items-center gap-2">
<button
type="button"
@@ -355,14 +348,14 @@ export function AgentCreatePanel({
<Button
size="sm"
onClick={submit}
disabled={!hasContent || !agentId || submitting || versionBlocked || uploading}
disabled={!hasContent || !agentId || submitting || versionBlocked}
title={
versionBlocked
? `Daemon CLI must be ≥ ${versionCheck.min}`
: undefined
}
>
{submitting ? "Sending…" : uploading ? "Uploading…" : "Create"}
{submitting ? "Sending…" : "Create"}
</Button>
</div>
</div>

View File

@@ -261,7 +261,7 @@ describe("SearchCommand", () => {
);
await user.click(newIssue);
expect(mockOpenModal).toHaveBeenCalledWith("quick-create-issue");
expect(mockOpenModal).toHaveBeenCalledWith("create-issue");
expect(useSearchStore.getState().open).toBe(false);
});

View File

@@ -202,7 +202,7 @@ export function SearchCommand() {
icon: Plus,
keywords: ["new", "issue", "create", "add"],
onSelect: () => {
useModalStore.getState().open("quick-create-issue");
useModalStore.getState().open("create-issue");
setOpen(false);
},
},

View File

@@ -1436,7 +1436,7 @@ func (s *TaskService) notifyQuickCreateCompleted(ctx context.Context, task db.Ag
Type: "quick_create_done",
Severity: "info",
IssueID: issue.ID,
Title: issue.Title,
Title: fmt.Sprintf("Created %s: %s", identifier, issue.Title),
Body: pgtype.Text{},
ActorType: pgtype.Text{String: "agent", Valid: true},
ActorID: task.AgentID,