feat: friend refactor to src
Browse filesThis view is limited to 50 files because it contains too many changes. Β See raw diff
- .gitignore +5 -5
- scripts/build.ts +30 -0
- src/commands.ts +2 -0
- src/commands/friend/friend.tsx +43 -15
- {friend/frontend/src β src/components/friend/frontend}/App.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/api.ts +0 -0
- {friend/frontend/src β src/components/friend/frontend}/assets/lip-sync-profile.json +0 -0
- {friend/frontend/src β src/components/friend/frontend}/components/ChatInput.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/components/HistoryPanel.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/components/MoodIndicator.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/components/ResizeHandles.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/components/SettingsPanel.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/components/TextBubble.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/components/VRMScene.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/emote.ts +0 -0
- {friend/frontend/src β src/components/friend/frontend}/hooks/usePassThrough.ts +0 -0
- {friend β src/components/friend}/frontend/index.html +1 -1
- {friend/frontend/src β src/components/friend/frontend}/lip-sync.ts +0 -0
- {friend/frontend/src β src/components/friend/frontend}/main.tsx +0 -0
- {friend/frontend/src β src/components/friend/frontend}/mixamo-loader.ts +0 -0
- {friend/frontend/src β src/components/friend/frontend}/mmd-parser.d.ts +0 -0
- {friend/frontend/src β src/components/friend/frontend}/motion-controller.ts +0 -0
- {friend β src/components/friend}/frontend/package-lock.json +0 -0
- {friend β src/components/friend}/frontend/package.json +0 -0
- {friend β src/components/friend}/frontend/public/akimbo.vrma +0 -0
- {friend β src/components/friend}/frontend/public/angry.fbx +0 -0
- {friend β src/components/friend}/frontend/public/angryPump.fbx +0 -0
- {friend β src/components/friend}/frontend/public/excited.fbx +0 -0
- {friend β src/components/friend}/frontend/public/greeting.fbx +0 -0
- {friend β src/components/friend}/frontend/public/happy.fbx +0 -0
- {friend β src/components/friend}/frontend/public/idle_loop.vrma +0 -0
- {friend β src/components/friend}/frontend/public/jile.vmd +0 -0
- {friend β src/components/friend}/frontend/public/love.vmd +0 -0
- {friend β src/components/friend}/frontend/public/playFingers.vrma +0 -0
- {friend β src/components/friend}/frontend/public/point.fbx +0 -0
- {friend β src/components/friend}/frontend/public/salute.fbx +0 -0
- {friend β src/components/friend}/frontend/public/scratchHead.vrma +0 -0
- {friend β src/components/friend}/frontend/public/shy.fbx +0 -0
- {friend β src/components/friend}/frontend/public/stretch.vrma +0 -0
- {friend β src/components/friend}/frontend/src-tauri/Cargo.lock +0 -0
- {friend β src/components/friend}/frontend/src-tauri/Cargo.toml +0 -0
- {friend β src/components/friend}/frontend/src-tauri/build.rs +0 -0
- {friend β src/components/friend}/frontend/src-tauri/capabilities/default.json +0 -0
- {friend β src/components/friend}/frontend/src-tauri/icons/128x128.png +0 -0
- {friend β src/components/friend}/frontend/src-tauri/icons/256x256.png +0 -0
- {friend β src/components/friend}/frontend/src-tauri/icons/32x32.png +0 -0
- {friend β src/components/friend}/frontend/src-tauri/src/lib.rs +0 -0
- {friend β src/components/friend}/frontend/src-tauri/src/main.rs +0 -0
- {friend β src/components/friend}/frontend/src-tauri/tauri.conf.json +0 -0
- {friend/frontend/src β src/components/friend/frontend}/three-helpers.ts +0 -0
.gitignore
CHANGED
|
@@ -8,11 +8,11 @@ VersperClaw
|
|
| 8 |
# Prebuilt native binaries (tracked in claude-code/ reference)
|
| 9 |
vendor/
|
| 10 |
|
| 11 |
-
# Friend VRM
|
| 12 |
-
friend/frontend/node_modules/
|
| 13 |
-
friend/frontend/dist/
|
| 14 |
-
friend/frontend/src-tauri/target/
|
| 15 |
-
friend/frontend/src-tauri/gen/
|
| 16 |
|
| 17 |
# Python cache
|
| 18 |
__pycache__/
|
|
|
|
| 8 |
# Prebuilt native binaries (tracked in claude-code/ reference)
|
| 9 |
vendor/
|
| 10 |
|
| 11 |
+
# Friend VRM frontend (Vite + Tauri) build artifacts
|
| 12 |
+
src/components/friend/frontend/node_modules/
|
| 13 |
+
src/components/friend/frontend/dist/
|
| 14 |
+
src/components/friend/frontend/src-tauri/target/
|
| 15 |
+
src/components/friend/frontend/src-tauri/gen/
|
| 16 |
|
| 17 |
# Python cache
|
| 18 |
__pycache__/
|
scripts/build.ts
CHANGED
|
@@ -118,6 +118,36 @@ const outfile = compile
|
|
| 118 |
: dev
|
| 119 |
? './VersperClaw'
|
| 120 |
: './cli'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
const buildTime = new Date().toISOString()
|
| 122 |
const version = dev ? getDevVersion(pkg.version) : pkg.version
|
| 123 |
|
|
|
|
| 118 |
: dev
|
| 119 |
? './VersperClaw'
|
| 120 |
: './cli'
|
| 121 |
+
|
| 122 |
+
// ββ Pre-step: build Friend VRM frontend βββββββββββββββββββββββββββββββββββββββ
|
| 123 |
+
function buildFriendFrontend(): boolean {
|
| 124 |
+
const frontendDir = join(process.cwd(), 'src', 'components', 'friend', 'frontend')
|
| 125 |
+
const distIndex = join(frontendDir, 'dist', 'index.html')
|
| 126 |
+
if (existsSync(distIndex)) {
|
| 127 |
+
console.log('Friend frontend already built, skipping.')
|
| 128 |
+
return true
|
| 129 |
+
}
|
| 130 |
+
console.log('Building Friend VRM frontend...')
|
| 131 |
+
const proc = Bun.spawnSync({
|
| 132 |
+
cmd: ['npm', 'run', 'build'],
|
| 133 |
+
cwd: frontendDir,
|
| 134 |
+
stdout: 'inherit',
|
| 135 |
+
stderr: 'inherit',
|
| 136 |
+
})
|
| 137 |
+
if (proc.exitCode !== 0) {
|
| 138 |
+
console.error('Friend frontend build failed.')
|
| 139 |
+
return false
|
| 140 |
+
}
|
| 141 |
+
console.log('Friend frontend built.')
|
| 142 |
+
return true
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
if (!buildFriendFrontend()) {
|
| 146 |
+
process.exit(1)
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 150 |
+
|
| 151 |
const buildTime = new Date().toISOString()
|
| 152 |
const version = dev ? getDevVersion(pkg.version) : pkg.version
|
| 153 |
|
src/commands.ts
CHANGED
|
@@ -44,6 +44,7 @@ import skills from './commands/skills/index.js'
|
|
| 44 |
import status from './commands/status/index.js'
|
| 45 |
import tasks from './commands/tasks/index.js'
|
| 46 |
import feishu from './commands/feishu/index.js'
|
|
|
|
| 47 |
import goals from './commands/goal/index.js'
|
| 48 |
import telegram from './commands/telegram/index.js'
|
| 49 |
import teleport from './commands/teleport/index.js'
|
|
@@ -309,6 +310,7 @@ const COMMANDS = memoize((): Command[] => [
|
|
| 309 |
theme,
|
| 310 |
feedback,
|
| 311 |
feishu,
|
|
|
|
| 312 |
goals,
|
| 313 |
review,
|
| 314 |
ultrareview,
|
|
|
|
| 44 |
import status from './commands/status/index.js'
|
| 45 |
import tasks from './commands/tasks/index.js'
|
| 46 |
import feishu from './commands/feishu/index.js'
|
| 47 |
+
import friend from './commands/friend/index.js'
|
| 48 |
import goals from './commands/goal/index.js'
|
| 49 |
import telegram from './commands/telegram/index.js'
|
| 50 |
import teleport from './commands/teleport/index.js'
|
|
|
|
| 310 |
theme,
|
| 311 |
feedback,
|
| 312 |
feishu,
|
| 313 |
+
friend,
|
| 314 |
goals,
|
| 315 |
review,
|
| 316 |
ultrareview,
|
src/commands/friend/friend.tsx
CHANGED
|
@@ -4,13 +4,26 @@
|
|
| 4 |
* Ink-based terminal UI that shows status and controls for the
|
| 5 |
* Friend desktop pet feature.
|
| 6 |
*/
|
| 7 |
-
import React, { useState
|
| 8 |
import { Box, Text, useInput } from '../../ink.js'
|
| 9 |
import { getPrefs, updatePrefs } from '../../friend/prefs.js'
|
| 10 |
-
import
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
|
|
|
| 12 |
const FRIEND_URL = 'http://127.0.0.1:3456/friend/'
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
type Page = 'status' | 'help'
|
| 15 |
|
| 16 |
export async function call(
|
|
@@ -20,22 +33,31 @@ export async function call(
|
|
| 20 |
): Promise<React.ReactNode> {
|
| 21 |
const trimmed = args?.trim().toLowerCase()
|
| 22 |
|
| 23 |
-
// Non-interactive modes
|
| 24 |
if (trimmed === 'start') {
|
| 25 |
updatePrefs({ enabled: true })
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
return (
|
| 27 |
<Box flexDirection="column">
|
| 28 |
-
<Text>Friend
|
| 29 |
-
<Text>
|
| 30 |
-
<Text>
|
| 31 |
-
<Text>Then open {FRIEND_URL} in a browser (or Tauri will launch automatically).</Text>
|
| 32 |
</Box>
|
| 33 |
)
|
| 34 |
}
|
| 35 |
|
| 36 |
if (trimmed === 'stop') {
|
| 37 |
updatePrefs({ enabled: false })
|
| 38 |
-
|
|
|
|
| 39 |
}
|
| 40 |
|
| 41 |
if (trimmed === 'status') {
|
|
@@ -43,7 +65,6 @@ export async function call(
|
|
| 43 |
return <FriendStatus prefs={prefs} compact />
|
| 44 |
}
|
| 45 |
|
| 46 |
-
// Interactive mode (no args or unrecognized)
|
| 47 |
return <FriendManager onDone={onDone} />
|
| 48 |
}
|
| 49 |
|
|
@@ -60,17 +81,17 @@ function FriendManager({ onDone }: { onDone: LocalJSXCommandOnDone }) {
|
|
| 60 |
<Box flexDirection="column" padding={1}>
|
| 61 |
<Box marginBottom={1}>
|
| 62 |
<Text bold underline>
|
| 63 |
-
|
| 64 |
</Text>
|
| 65 |
</Box>
|
| 66 |
|
| 67 |
-
|
| 68 |
|
| 69 |
<Box marginTop={1} flexDirection="column">
|
| 70 |
<Text dimColor>Usage:</Text>
|
| 71 |
-
<Text dimColor> /friend Interactive status &
|
| 72 |
-
<Text dimColor> /friend start
|
| 73 |
-
<Text dimColor> /friend stop
|
| 74 |
<Text dimColor> /friend status Quick status overview</Text>
|
| 75 |
</Box>
|
| 76 |
|
|
@@ -90,6 +111,7 @@ function FriendStatus({
|
|
| 90 |
}) {
|
| 91 |
const statusDot = prefs.enabled ? 'β' : 'β'
|
| 92 |
const statusColor = prefs.enabled ? 'green' : 'gray'
|
|
|
|
| 93 |
|
| 94 |
return (
|
| 95 |
<Box flexDirection="column">
|
|
@@ -101,6 +123,12 @@ function FriendStatus({
|
|
| 101 |
</Box>
|
| 102 |
{!compact && (
|
| 103 |
<>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
<Box>
|
| 105 |
<Text> URL: </Text>
|
| 106 |
<Text dimColor>{FRIEND_URL}</Text>
|
|
@@ -121,4 +149,4 @@ function FriendStatus({
|
|
| 121 |
)}
|
| 122 |
</Box>
|
| 123 |
)
|
| 124 |
-
}
|
|
|
|
| 4 |
* Ink-based terminal UI that shows status and controls for the
|
| 5 |
* Friend desktop pet feature.
|
| 6 |
*/
|
| 7 |
+
import React, { useState } from 'react'
|
| 8 |
import { Box, Text, useInput } from '../../ink.js'
|
| 9 |
import { getPrefs, updatePrefs } from '../../friend/prefs.js'
|
| 10 |
+
import {
|
| 11 |
+
launchTauri,
|
| 12 |
+
stopTauri,
|
| 13 |
+
getTauriProcess,
|
| 14 |
+
} from '../../friend/tauri-launcher.js'
|
| 15 |
+
import type { LocalJSXCommandOnDone, CommandResultDisplay } from '../../types/command.js'
|
| 16 |
|
| 17 |
+
const FRIEND_FRONTEND_DIR = '../../components/friend/frontend'
|
| 18 |
const FRIEND_URL = 'http://127.0.0.1:3456/friend/'
|
| 19 |
|
| 20 |
+
function logger() {
|
| 21 |
+
return {
|
| 22 |
+
info: (msg: string) => console.log(`[Friend] ${msg}`),
|
| 23 |
+
warn: (msg: string) => console.warn(`[Friend] ${msg}`),
|
| 24 |
+
}
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
type Page = 'status' | 'help'
|
| 28 |
|
| 29 |
export async function call(
|
|
|
|
| 33 |
): Promise<React.ReactNode> {
|
| 34 |
const trimmed = args?.trim().toLowerCase()
|
| 35 |
|
|
|
|
| 36 |
if (trimmed === 'start') {
|
| 37 |
updatePrefs({ enabled: true })
|
| 38 |
+
const alreadyRunning = !!getTauriProcess()
|
| 39 |
+
if (alreadyRunning) {
|
| 40 |
+
return (
|
| 41 |
+
<Box flexDirection="column">
|
| 42 |
+
<Text>Friend is already running.</Text>
|
| 43 |
+
<Text dimColor>Open {FRIEND_URL} in your browser.</Text>
|
| 44 |
+
</Box>
|
| 45 |
+
)
|
| 46 |
+
}
|
| 47 |
+
launchTauri(FRIEND_FRONTEND_DIR, logger())
|
| 48 |
return (
|
| 49 |
<Box flexDirection="column">
|
| 50 |
+
<Text>Starting Friend VRM companion...</Text>
|
| 51 |
+
<Text dimColor>A Tauri window will open.</Text>
|
| 52 |
+
<Text dimColor>Also available at: {FRIEND_URL}</Text>
|
|
|
|
| 53 |
</Box>
|
| 54 |
)
|
| 55 |
}
|
| 56 |
|
| 57 |
if (trimmed === 'stop') {
|
| 58 |
updatePrefs({ enabled: false })
|
| 59 |
+
stopTauri(logger())
|
| 60 |
+
return <Text>Friend companion stopped.</Text>
|
| 61 |
}
|
| 62 |
|
| 63 |
if (trimmed === 'status') {
|
|
|
|
| 65 |
return <FriendStatus prefs={prefs} compact />
|
| 66 |
}
|
| 67 |
|
|
|
|
| 68 |
return <FriendManager onDone={onDone} />
|
| 69 |
}
|
| 70 |
|
|
|
|
| 81 |
<Box flexDirection="column" padding={1}>
|
| 82 |
<Box marginBottom={1}>
|
| 83 |
<Text bold underline>
|
| 84 |
+
Friend VRM Desktop Pet
|
| 85 |
</Text>
|
| 86 |
</Box>
|
| 87 |
|
| 88 |
+
<FriendStatus prefs={getPrefs()} compact={false} />
|
| 89 |
|
| 90 |
<Box marginTop={1} flexDirection="column">
|
| 91 |
<Text dimColor>Usage:</Text>
|
| 92 |
+
<Text dimColor> /friend Interactive status & controls</Text>
|
| 93 |
+
<Text dimColor> /friend start Launch friend window</Text>
|
| 94 |
+
<Text dimColor> /friend stop Stop friend window</Text>
|
| 95 |
<Text dimColor> /friend status Quick status overview</Text>
|
| 96 |
</Box>
|
| 97 |
|
|
|
|
| 111 |
}) {
|
| 112 |
const statusDot = prefs.enabled ? 'β' : 'β'
|
| 113 |
const statusColor = prefs.enabled ? 'green' : 'gray'
|
| 114 |
+
const running = !!getTauriProcess()
|
| 115 |
|
| 116 |
return (
|
| 117 |
<Box flexDirection="column">
|
|
|
|
| 123 |
</Box>
|
| 124 |
{!compact && (
|
| 125 |
<>
|
| 126 |
+
{running && (
|
| 127 |
+
<Box>
|
| 128 |
+
<Text> Window: </Text>
|
| 129 |
+
<Text color="green">Running</Text>
|
| 130 |
+
</Box>
|
| 131 |
+
)}
|
| 132 |
<Box>
|
| 133 |
<Text> URL: </Text>
|
| 134 |
<Text dimColor>{FRIEND_URL}</Text>
|
|
|
|
| 149 |
)}
|
| 150 |
</Box>
|
| 151 |
)
|
| 152 |
+
}
|
{friend/frontend/src β src/components/friend/frontend}/App.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/api.ts
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/assets/lip-sync-profile.json
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/components/ChatInput.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/components/HistoryPanel.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/components/MoodIndicator.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/components/ResizeHandles.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/components/SettingsPanel.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/components/TextBubble.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/components/VRMScene.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/emote.ts
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/hooks/usePassThrough.ts
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/index.html
RENAMED
|
@@ -96,7 +96,7 @@
|
|
| 96 |
|
| 97 |
<body>
|
| 98 |
<div id="root"></div>
|
| 99 |
-
<script type="module" src="/
|
| 100 |
</body>
|
| 101 |
|
| 102 |
</html>
|
|
|
|
| 96 |
|
| 97 |
<body>
|
| 98 |
<div id="root"></div>
|
| 99 |
+
<script type="module" src="./main.tsx"></script>
|
| 100 |
</body>
|
| 101 |
|
| 102 |
</html>
|
{friend/frontend/src β src/components/friend/frontend}/lip-sync.ts
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/main.tsx
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/mixamo-loader.ts
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/mmd-parser.d.ts
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/motion-controller.ts
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/package-lock.json
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/package.json
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/akimbo.vrma
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/angry.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/angryPump.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/excited.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/greeting.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/happy.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/idle_loop.vrma
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/jile.vmd
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/love.vmd
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/playFingers.vrma
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/point.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/salute.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/scratchHead.vrma
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/shy.fbx
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/public/stretch.vrma
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/Cargo.lock
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/Cargo.toml
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/build.rs
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/capabilities/default.json
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/icons/128x128.png
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/icons/256x256.png
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/icons/32x32.png
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/src/lib.rs
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/src/main.rs
RENAMED
|
File without changes
|
{friend β src/components/friend}/frontend/src-tauri/tauri.conf.json
RENAMED
|
File without changes
|
{friend/frontend/src β src/components/friend/frontend}/three-helpers.ts
RENAMED
|
File without changes
|