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>

View File

@@ -1,6 +1,10 @@
{
"title": "CLI Execution History",
"description": "View and manage your CLI execution history",
"tabs": {
"executions": "Executions",
"observability": "Session Audit"
},
"searchPlaceholder": "Search executions...",
"filterAllTools": "All Tools",
"deleteOptions": "Delete Options",
@@ -9,10 +13,14 @@
"deleteAll": "Delete All History",
"actions": {
"view": "View Details",
"viewNative": "View Native Session",
"delete": "Delete",
"copyId": "Copy ID",
"copied": "Copied!"
},
"badge": {
"native": "native"
},
"dialog": {
"deleteTitle": "Confirm Delete",
"deleteAllTitle": "Delete All History",

View File

@@ -41,6 +41,7 @@ import cliViewer from './cli-viewer.json';
import team from './team.json';
import terminalDashboard from './terminal-dashboard.json';
import skillHub from './skill-hub.json';
import nativeSession from './native-session.json';
/**
* Flattens nested JSON object to dot-separated keys
@@ -105,4 +106,5 @@ export default {
...flattenMessages(team, 'team'),
...flattenMessages(terminalDashboard, 'terminalDashboard'),
...flattenMessages(skillHub, 'skillHub'),
...flattenMessages(nativeSession, 'nativeSession'),
} as Record<string, string>;

View File

@@ -0,0 +1,33 @@
{
"title": "Native Session",
"tokens": {
"total": "Total tokens",
"input": "Input tokens",
"output": "Output tokens",
"cached": "Cached tokens"
},
"turn": {
"latest": "Latest",
"thoughts": "Thoughts",
"toolCalls": "Tool Calls"
},
"toolCall": {
"input": "Input",
"output": "Output"
},
"meta": {
"startTime": "Start time",
"workingDir": "Working directory",
"projectHash": "Project hash",
"turns": "turns"
},
"tokenSummary": "Total Tokens",
"loading": "Loading session...",
"error": "Failed to load session",
"empty": "No session data available",
"footer": {
"copied": "Copied!",
"copySessionId": "Copy Session ID",
"exportJson": "Export JSON"
}
}

View File

@@ -1,6 +1,10 @@
{
"title": "CLI 执行历史",
"description": "查看和管理 CLI 执行历史",
"tabs": {
"executions": "执行历史",
"observability": "会话审计"
},
"searchPlaceholder": "搜索执行记录...",
"filterAllTools": "全部工具",
"deleteOptions": "删除选项",
@@ -9,10 +13,14 @@
"deleteAll": "删除全部历史",
"actions": {
"view": "查看详情",
"viewNative": "查看原生会话",
"delete": "删除",
"copyId": "复制 ID",
"copied": "已复制!"
},
"badge": {
"native": "原生"
},
"dialog": {
"deleteTitle": "确认删除",
"deleteAllTitle": "删除全部历史",

View File

@@ -41,6 +41,7 @@ import cliViewer from './cli-viewer.json';
import team from './team.json';
import terminalDashboard from './terminal-dashboard.json';
import skillHub from './skill-hub.json';
import nativeSession from './native-session.json';
/**
* Flattens nested JSON object to dot-separated keys
@@ -105,4 +106,5 @@ export default {
...flattenMessages(team, 'team'),
...flattenMessages(terminalDashboard, 'terminalDashboard'),
...flattenMessages(skillHub, 'skillHub'),
...flattenMessages(nativeSession, 'nativeSession'),
} as Record<string, string>;

View File

@@ -0,0 +1,33 @@
{
"title": "原生会话",
"tokens": {
"total": "总 Token 数",
"input": "输入 Token",
"output": "输出 Token",
"cached": "缓存 Token"
},
"turn": {
"latest": "最新",
"thoughts": "思考过程",
"toolCalls": "工具调用"
},
"toolCall": {
"input": "输入",
"output": "输出"
},
"meta": {
"startTime": "开始时间",
"workingDir": "工作目录",
"projectHash": "项目哈希",
"turns": "轮次"
},
"tokenSummary": "总 Token",
"loading": "加载会话中...",
"error": "加载会话失败",
"empty": "无会话数据",
"footer": {
"copied": "已复制!",
"copySessionId": "复制会话 ID",
"exportJson": "导出 JSON"
}
}