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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ pnpm test packages/tools # tools package
### Format

```bash
npm run format # format all files
npm run format # format source/config files
npm run format:check # check format (CI)
```

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"web:dev": "pnpm --filter @memo-code/web dev",
"web:build": "pnpm --filter @memo-code/web build",
"web:start": "pnpm --filter @memo-code/web start",
"format": "prettier --write .",
"format:check": "prettier --check .",
"format": "prettier --write \"{packages,web}/**/*.{ts,tsx,js,jsx,mjs,cjs,json,css,mdx}\" \"{package.json,pnpm-workspace.yaml,tsconfig.json,tsup.config.ts,vitest.config.ts,vitest.setup.ts,.prettierrc}\"",
"format:check": "prettier --check \"{packages,web}/**/*.{ts,tsx,js,jsx,mjs,cjs,json,css,mdx}\" \"{package.json,pnpm-workspace.yaml,tsconfig.json,tsup.config.ts,vitest.config.ts,vitest.setup.ts,.prettierrc}\"",
"test": "vitest run",
"test:core": "vitest run packages/core",
"test:tools": "vitest run packages/tools",
Expand Down
36 changes: 1 addition & 35 deletions packages/cli/src/tui/components/layout/HeaderBar.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,12 @@
import { Box, Text } from 'ink'
import { memo } from 'react'
import os from 'node:os'

type HeaderBarProps = {
providerName: string
model: string
cwd: string
sessionId?: string
}

function formatCwd(cwd: string) {
const home = os.homedir()
if (!home) return cwd
return cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd
}

function formatSessionId(id: string | undefined): string {
if (!id) return 'N/A'
// Show first 8 chars and last 4 chars
if (id.length > 16) {
return `${id.slice(0, 8)}...${id.slice(-4)}`
}
return id
}

export const HeaderBar = memo(function HeaderBar({
providerName,
model,
cwd,
sessionId,
}: HeaderBarProps) {
const displayCwd = formatCwd(cwd)
const displaySession = formatSessionId(sessionId)

export const HeaderBar = memo(function HeaderBar({ providerName, model }: HeaderBarProps) {
return (
<Box
borderStyle="round"
Expand All @@ -52,14 +26,6 @@ export const HeaderBar = memo(function HeaderBar({

{/* Info Rows */}
<Box flexDirection="column" gap={0}>
<Box>
<Text color="gray">Directory: </Text>
<Text color="cyan">{displayCwd}</Text>
</Box>
<Box>
<Text color="gray">Session: </Text>
<Text color="cyan">{displaySession}</Text>
</Box>
<Box>
<Text color="gray">Model: </Text>
<Text color="cyan">{model}</Text>
Expand Down
25 changes: 0 additions & 25 deletions packages/cli/src/tui/components/layout/MainContent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Box, Static, Text } from 'ink'
import { memo } from 'react'
import os from 'node:os'
import type { SystemMessage, TurnView as TurnViewType } from '../../types'
import { SystemMessageView } from '../messages/SystemMessageView'
import { TurnView } from '../turns/TurnView'
Expand All @@ -19,20 +18,6 @@ type MainContentProps = {
}
}

function formatCwd(cwd: string) {
const home = os.homedir()
if (!home) return cwd
return cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd
}

function formatSessionId(id: string): string {
// Show first 8 chars and last 4 chars
if (id.length > 16) {
return `${id.slice(0, 8)}...${id.slice(-4)}`
}
return id
}

// Custom comparison to prevent re-render when arrays haven't actually changed
function arePropsEqual(prevProps: MainContentProps, nextProps: MainContentProps): boolean {
// Check header info (shouldn't change often)
Expand Down Expand Up @@ -144,16 +129,6 @@ export const MainContent = memo(function MainContent({
</Box>
</Box>
<Box flexDirection="column" gap={0}>
<Box>
<Text color="gray">Directory: </Text>
<Text color="cyan">{formatCwd(header.cwd)}</Text>
</Box>
<Box>
<Text color="gray">Session: </Text>
<Text color="cyan">
{formatSessionId(header.sessionId)}
</Text>
</Box>
<Box>
<Text color="gray">Model: </Text>
<Text color="cyan">{header.model}</Text>
Expand Down
36 changes: 36 additions & 0 deletions packages/cli/src/tui/components/turns/StepView.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import assert from 'node:assert'
import path from 'node:path'
import { describe, test } from 'vitest'
import { getMainParam } from './StepView'

describe('getMainParam', () => {
test('formats absolute file paths as workspace-relative paths', () => {
const cwd = path.join(path.sep, 'tmp', 'memo-cli')
const filePath = path.join(cwd, 'web', 'public', 'logo.svg')

const param = getMainParam({ file_path: filePath }, cwd)
assert.strictEqual(param, 'web/public/logo.svg')
})

test('keeps absolute paths unchanged when outside workspace', () => {
const cwd = path.join(path.sep, 'tmp', 'memo-cli')
const outsidePath = path.join(path.sep, 'tmp', 'other', 'logo.svg')

const param = getMainParam({ file_path: outsidePath }, cwd)
assert.strictEqual(param, outsidePath)
})

test('formats absolute string input as workspace-relative path', () => {
const cwd = path.join(path.sep, 'tmp', 'memo-cli')
const filePath = path.join(cwd, 'README.md')

const param = getMainParam(filePath, cwd)
assert.strictEqual(param, 'README.md')
})

test('formats cwd absolute path as dot', () => {
const cwd = path.join(path.sep, 'tmp', 'memo-cli')
const param = getMainParam({ dir_path: cwd }, cwd)
assert.strictEqual(param, '.')
})
})
48 changes: 31 additions & 17 deletions packages/cli/src/tui/components/turns/StepView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box, Text } from 'ink'
import { memo } from 'react'
import path from 'node:path'
import type { StepView as StepViewType } from '../../types'
import { MarkdownMessage } from '../messages/MarkdownMessage'

Expand All @@ -8,20 +9,35 @@ type StepViewProps = {
hideAssistantText?: boolean
}

const PATH_PARAM_KEYS = new Set(['dir_path', 'file_path', 'path', 'file', 'filename', 'cwd', 'dir'])

function truncate(value: string): string {
return value.length > 50 ? `${value.slice(0, 47)}...` : value
}

function toDisplayPath(value: string, cwd: string): string {
if (!path.isAbsolute(value)) return value

const relative = path.relative(cwd, value)
if (!relative) return '.'
if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
return value
}

return relative.split(path.sep).join('/')
}

// Extract the most important parameter to display
function getMainParam(toolInput: unknown): string | undefined {
export function getMainParam(toolInput: unknown, cwd = process.cwd()): string | undefined {
if (!toolInput) return undefined

if (typeof toolInput === 'string') {
if (toolInput.length > 50) {
return toolInput.slice(0, 47) + '...'
}
return toolInput
return truncate(toDisplayPath(toolInput, cwd))
}

if (typeof toolInput !== 'object' || Array.isArray(toolInput)) return undefined

const input = toolInput as Record<string, any>
const input = toolInput as Record<string, unknown>

const priorityKeys = [
'cmd',
Expand All @@ -41,21 +57,19 @@ function getMainParam(toolInput: unknown): string | undefined {
]

for (const key of priorityKeys) {
if (input[key]) {
const value = String(input[key])
if (value.length > 50) {
return value.slice(0, 47) + '...'
}
return value
}
const rawValue = input[key]
if (rawValue === undefined || rawValue === null || rawValue === '') continue
const value = String(rawValue)
const displayValue =
PATH_PARAM_KEYS.has(key) || key.includes('path') ? toDisplayPath(value, cwd) : value
return truncate(displayValue)
}

for (const [key, value] of Object.entries(input)) {
if (typeof value === 'string' && key !== 'description') {
if (value.length > 50) {
return value.slice(0, 47) + '...'
}
return value
const displayValue =
PATH_PARAM_KEYS.has(key) || key.includes('path') ? toDisplayPath(value, cwd) : value
return truncate(displayValue)
}
}

Expand Down
20 changes: 10 additions & 10 deletions web/app/docs/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,16 @@ export default async function DocDetailPage({ params }: DocDetailPageProps) {
{previous ? (
<Link
href={`/docs/${previous.slug}`}
className="group flex items-center gap-4 rounded-xl border border-[var(--border-default)] bg-[var(--bg-tertiary)] p-4 transition-all hover:border-indigo-500/30 hover:bg-[var(--bg-elevated)]"
className="group flex items-center gap-3 rounded-lg border border-[var(--border-default)] bg-[var(--bg-tertiary)] p-4 transition-colors hover:bg-[var(--bg-elevated)]"
>
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-[var(--bg-secondary)] transition-colors group-hover:bg-indigo-500/10">
<ArrowLeft className="h-5 w-5 text-[var(--text-tertiary)] transition-colors group-hover:text-indigo-400" />
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-[var(--border-default)] bg-[var(--bg-secondary)]">
<ArrowLeft className="h-4 w-4 text-[var(--text-tertiary)]" />
</div>
<div className="min-w-0">
<p className="text-xs font-medium text-[var(--text-tertiary)]">
<p className="text-[11px] font-medium text-[var(--text-tertiary)]">
Previous
</p>
<p className="truncate font-medium text-white transition-colors group-hover:text-indigo-400">
<p className="truncate text-sm font-medium text-[var(--text-primary)]">
{previous.title}
</p>
</div>
Expand All @@ -82,18 +82,18 @@ export default async function DocDetailPage({ params }: DocDetailPageProps) {
{next ? (
<Link
href={`/docs/${next.slug}`}
className="group flex items-center justify-end gap-4 rounded-xl border border-[var(--border-default)] bg-[var(--bg-tertiary)] p-4 text-right transition-all hover:border-indigo-500/30 hover:bg-[var(--bg-elevated)]"
className="group flex items-center justify-end gap-3 rounded-lg border border-[var(--border-default)] bg-[var(--bg-tertiary)] p-4 text-right transition-colors hover:bg-[var(--bg-elevated)]"
>
<div className="min-w-0">
<p className="text-xs font-medium text-[var(--text-tertiary)]">
<p className="text-[11px] font-medium text-[var(--text-tertiary)]">
Next
</p>
<p className="truncate font-medium text-white transition-colors group-hover:text-indigo-400">
<p className="truncate text-sm font-medium text-[var(--text-primary)]">
{next.title}
</p>
</div>
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-[var(--bg-secondary)] transition-colors group-hover:bg-indigo-500/10">
<ArrowRight className="h-5 w-5 text-[var(--text-tertiary)] transition-colors group-hover:text-indigo-400" />
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-[var(--border-default)] bg-[var(--bg-secondary)]">
<ArrowRight className="h-4 w-4 text-[var(--text-tertiary)]" />
</div>
</Link>
) : (
Expand Down
Loading