fix(clean): correct project-tech field references and add sync vs clean disambiguation

- Fix Step 4.3: project.features → project.development_index,
  project.statistics → project._metadata
- Add project-guidelines.json learnings cleanup on session deletion
- Add sync vs clean disambiguation table explaining write vs reclaim
This commit is contained in:
catlog22
2026-02-25 22:34:15 +08:00
parent f96febe09a
commit c92754505a
9 changed files with 139 additions and 23 deletions

View File

@@ -75,20 +75,24 @@ function formatDuration(ms: number): string {
}
/**
* Get time ago string
* Hook to get localized time ago string
*/
function getTimeAgo(dateString: string): string {
const date = new Date(dateString);
const now = new Date();
const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);
function useTimeAgo() {
const { formatMessage } = useIntl();
if (seconds < 60) return 'just now';
const minutes = Math.floor(seconds / 60);
if (minutes < 60) return `${minutes}m ago`;
const hours = Math.floor(minutes / 60);
if (hours < 24) return `${hours}h ago`;
const days = Math.floor(hours / 24);
return `${days}d ago`;
return React.useCallback((dateString: string): string => {
const date = new Date(dateString);
const now = new Date();
const seconds = Math.floor((now.getTime() - date.getTime()) / 1000);
if (seconds < 60) return formatMessage({ id: 'common.time.justNow' });
const minutes = Math.floor(seconds / 60);
if (minutes < 60) return formatMessage({ id: 'common.time.minutesAgo' }, { count: minutes });
const hours = Math.floor(minutes / 60);
if (hours < 24) return formatMessage({ id: 'common.time.hoursAgo' }, { count: hours });
const days = Math.floor(hours / 24);
return formatMessage({ id: 'common.time.daysAgo' }, { count: days });
}, [formatMessage]);
}
/**
@@ -104,6 +108,7 @@ export function ConversationCard({
actionsDisabled = false,
}: ConversationCardProps) {
const { formatMessage } = useIntl();
const getTimeAgo = useTimeAgo();
const [copied, setCopied] = React.useState(false);
const status = statusConfig[execution.status] || statusConfig.error;
@@ -180,7 +185,7 @@ export function ConversationCard({
{execution.hasNativeSession && (
<Badge variant="outline" className="gap-1 text-xs">
<FileJson className="h-3 w-3" />
native
{formatMessage({ id: 'history.badge.native' })}
</Badge>
)}
<Badge variant={status.variant} className="gap-1 text-xs ml-auto">

View File

@@ -145,6 +145,7 @@ function TokenDisplay({ tokens, className }: TokenDisplayProps) {
* ToolCallItem - Single tool call display with collapsible details
*/
function ToolCallItem({ toolCall, index }: ToolCallItemProps) {
const { formatMessage } = useIntl();
return (
<details className="group/tool border border-border/50 rounded-md overflow-hidden">
<summary className="flex items-center gap-2 px-3 py-2 text-xs cursor-pointer hover:bg-muted/50 select-none">
@@ -155,7 +156,7 @@ function ToolCallItem({ toolCall, index }: ToolCallItemProps) {
<div className="border-t border-border/50 divide-y divide-border/50">
{toolCall.arguments && (
<div className="p-3">
<p className="text-xs font-medium text-muted-foreground mb-1">Input</p>
<p className="text-xs font-medium text-muted-foreground mb-1">{formatMessage({ id: 'nativeSession.toolCall.input' })}</p>
<pre className="p-2 bg-muted/30 rounded text-xs whitespace-pre-wrap overflow-x-auto font-mono leading-relaxed max-h-60 overflow-y-auto">
{toolCall.arguments}
</pre>
@@ -163,7 +164,7 @@ function ToolCallItem({ toolCall, index }: ToolCallItemProps) {
)}
{toolCall.output && (
<div className="p-3">
<p className="text-xs font-medium text-muted-foreground mb-1">Output</p>
<p className="text-xs font-medium text-muted-foreground mb-1">{formatMessage({ id: 'nativeSession.toolCall.output' })}</p>
<pre className="p-2 bg-muted/30 rounded text-xs whitespace-pre-wrap overflow-x-auto font-mono leading-relaxed max-h-60 overflow-y-auto">
{toolCall.output}
</pre>