sync: update from private repo (e62f5c7)
CI / build-and-test (push) Has been cancelled

This commit is contained in:
oss-sync
2026-06-11 01:52:48 +00:00
parent 000a2474aa
commit d061ad08d8
237 changed files with 8441 additions and 5549 deletions
+27 -97
View File
@@ -1,4 +1,5 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueries, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { FileTree, type SubdirId, type FileEntry, FILE_SUBDIRS } from './FileTree';
import { MonacoFileEditor } from './MonacoFileEditor';
@@ -17,91 +18,20 @@ import { MemoryPanel } from './MemoryPanel';
/** All subdirs shown in the tree — both real file-based and virtual. */
const ALL_SUBDIRS: SubdirId[] = ['agents-md', 'browser-macros', 'recordings', 'notes', 'subscribed-notes', 'pets', 'browser-sessions', 'mcp', 'skills', 'ssh-connections', 'trash', 'memory'];
const SUBDIR_INFO: { id: SubdirId; icon: string; title: string; desc: string; agency: string }[] = [
{
id: 'agents-md',
icon: '📖',
title: 'AGENTS.md',
desc: 'タスク起動時に system prompt へ自動注入される、ユーザー専用の永続的な指示。 「常に丁寧な日本語で答える」「Tailwind を優先」等、毎タスクで覚えて欲しい好み・ルールを書く。 最大 64KB。 ファイル形式は markdown。',
agency: 'ユーザー編集 / エージェントが自動参照',
},
{
id: 'browser-macros',
icon: '🤖',
title: 'browser-macros/',
desc: 'Playwright ベースのブラウザマクロ。recordings/ から "Save as Script" で生成、または UI で手書き。RunUserScript ツールで実行。main({ context, params }) シグネチャで context は Playwright BrowserContext。session_profile_id で保存済みログインを利用可能。.next.js は self-healing 失敗時の自動パッチ候補で、Diff レビュー後に accept/reject。雛形・手順書は Skills へ、アドホックなコード実行は Bash ツールへ。',
agency: 'エージェント実行 / UI で recordings → スクリプト化',
},
{
id: 'recordings',
icon: '🎬',
title: 'recordings/',
desc: 'BrowseWeb 操作トレース (JSON)。BrowseWeb 呼び出しで recordTo パラメータを指定すると、成功したアクションがバッファされ、タスク終了時にここへ書き出される。"Save as Script" でブラウザマクロに変換できる (browser-macros/ へ保存)。',
agency: 'エージェントが記録 / UI でスクリプト化',
},
{
id: 'pets',
icon: '◉',
title: 'pets/',
desc: 'Codex Pets 互換のキャラクターをユーザーごとに import する場所。Chat 画面右下に表示され、タスク状態やツール呼び出しに応じて小さく反応する。',
agency: 'ユーザー管理 / Chat UI が参照',
},
{
id: 'browser-sessions',
icon: '🌐',
title: 'browser-sessions/',
desc: 'ブラウザのログインプロファイル管理。CAPTCHA や 2FA の壁を越えて取得した cookie/storage を user-scoped に暗号化保存し、browser-macros から session_profile_id で参照する。',
agency: 'ユーザー管理 (noVNC でログイン → save) / browser-macros が利用',
},
{
id: 'trash',
icon: '🗑',
title: 'trash/',
desc: '削除ファイルの退避先。ハードデリートはせず、`{YYYYMMDD-HHMMSS}-{rand4hex}-{name}` 命名で着地する。script の accept/reject で旧版もここへ。閲覧は read-only、復元したい場合は内容コピーで元 subdir に PUT。30 日経過したファイルはサーバ起動時 / 24h 毎に自動削除 (`tools.trash_retention_days` で変更可)。',
agency: 'ソフト削除 / read-only / 30 日自動 cleanup',
},
{
id: 'memory',
icon: '🧠',
title: 'memory/',
desc: 'エージェントの永続事実置き場。`MEMORY.md` (index) がタスク起動時に system prompt へ自動注入 (32 KB cap)。エントリの閲覧・編集・削除はこのパネルで行う。reflection の実行履歴・revert は Settings → Reflection 履歴。',
agency: 'エージェント管理 + ユーザー編集(このパネル)',
},
{
id: 'mcp',
icon: '🔌',
title: 'mcp/',
desc: 'MCP サーバーの登録・接続管理・設定変更をまとめて行えます。OAuth / API key 認証、ツール一覧の取得、接続状態の確認がここで完結します。credentials は AES-256-GCM で暗号化して保存されます。',
agency: 'ユーザー管理 / 管理者は global サーバーも追加可能',
},
{
id: 'skills',
icon: '📚',
title: 'skills/',
desc: 'エージェントのスキル (参照知識・手順書) を管理します。URL からインストール、手動作成、編集、削除が可能。スキルはタスク実行時にエージェントへコンテキストとして注入されます。',
agency: 'ユーザー管理 / エージェントが ReadSkill で参照',
},
{
id: 'ssh-connections',
icon: '🔐',
title: 'ssh-connections/',
desc: 'エージェントの SshExec / SshUpload / SshDownload ツールが利用する SSH 接続を管理します。秘密鍵は envelope encryption (AES-256-GCM + per-user DEK) で保存され、ホストキーは TOFU でユーザー確認後に固定されます。グローバル接続は管理者が登録し、ピースごとに grant を付与した時のみ参照可能です。',
agency: 'ユーザー管理 / グローバル接続は管理者が登録',
},
{
id: 'notes',
icon: '📝',
title: 'notes/',
desc: '他のエージェントや他のユーザーと共有したい情報を Markdown で書く場所です。visibility を設定して公開範囲を制御できます。SearchNotes / ReadNote / WriteNote ツールでエージェントがアクセスできます。',
agency: 'ユーザー作成 / エージェントが SearchNotes / ReadNote / WriteNote で利用',
},
{
id: 'subscribed-notes',
icon: '🔔',
title: 'Subscribed Notes',
desc: '他のユーザーが公開している notes フォルダーを購読・発見します。search モードは SearchNotes ツールで横断検索でき、inject モードは LLM コンテキストに自動注入します。',
agency: 'ユーザー管理 / エージェントが自動参照 (inject モード)',
},
// title/desc/agency are i18n keys under root.subdirs.<key>, translated at render.
const SUBDIR_INFO: { id: SubdirId; icon: string; key: string }[] = [
{ id: 'agents-md', icon: '📖', key: 'agentsMd' },
{ id: 'browser-macros', icon: '🤖', key: 'browserMacros' },
{ id: 'recordings', icon: '🎬', key: 'recordings' },
{ id: 'pets', icon: '◉', key: 'pets' },
{ id: 'browser-sessions', icon: '🌐', key: 'browserSessions' },
{ id: 'trash', icon: '🗑', key: 'trash' },
{ id: 'memory', icon: '🧠', key: 'memory' },
{ id: 'mcp', icon: '🔌', key: 'mcp' },
{ id: 'skills', icon: '📚', key: 'skills' },
{ id: 'ssh-connections', icon: '🔐', key: 'sshConnections' },
{ id: 'notes', icon: '📝', key: 'notes' },
{ id: 'subscribed-notes', icon: '🔔', key: 'subscribedNotes' },
];
interface FolderListResponse {
@@ -182,6 +112,7 @@ interface UserFolderTabProps {
}
export function UserFolderTab({ showToast }: UserFolderTabProps = {}) {
const { t } = useTranslation('userfolder');
const [selectedSubdir, setSelectedSubdir] = useState<SubdirId | null>('browser-macros');
const [selectedFile, setSelectedFile] = useState<string | null>(null);
const [editorDirty, setEditorDirty] = useState(false);
@@ -264,7 +195,7 @@ export function UserFolderTab({ showToast }: UserFolderTabProps = {}) {
},
onError: (err, { subdir, file }) => {
const msg = err instanceof Error ? err.message : 'Unknown error';
const label = `${subdir}/${file} の削除に失敗`;
const label = t('delete.failed', { path: `${subdir}/${file}` });
if (showToast) showToast(`${label}: ${msg}`, 'error');
else console.error(`${label}: ${msg}`);
},
@@ -456,14 +387,14 @@ export function UserFolderTab({ showToast }: UserFolderTabProps = {}) {
{info.icon}
</span>
<div className="flex-1 min-w-0">
<h2 className="text-base font-semibold text-slate-900">{info.title}</h2>
<p className="text-[13px] text-slate-500 mt-1 leading-relaxed">{info.desc}</p>
<p className="text-2xs text-slate-400 mt-1 uppercase tracking-wide">{info.agency}</p>
<h2 className="text-base font-semibold text-slate-900">{t(`root.subdirs.${info.key}.title`)}</h2>
<p className="text-[13px] text-slate-500 mt-1 leading-relaxed">{t(`root.subdirs.${info.key}.desc`)}</p>
<p className="text-2xs text-slate-400 mt-1 uppercase tracking-wide">{t(`root.subdirs.${info.key}.agency`)}</p>
</div>
</div>
{files.length > 0 && (
<div className="mb-4 text-xs text-slate-500">
{files.length}
{t('root.fileCount', { count: files.length })}
</div>
)}
<NewFileForm
@@ -482,22 +413,21 @@ export function UserFolderTab({ showToast }: UserFolderTabProps = {}) {
/* Full overview when no subdir is selected (or non-writable subdir selected without a file) */
<>
<div className="mb-6">
<h2 className="text-base font-semibold text-slate-900 mb-1">User Folder</h2>
<h2 className="text-base font-semibold text-slate-900 mb-1">{t('root.title')}</h2>
<p className="text-[13px] text-slate-500 leading-relaxed">
subdirectory
{t('root.intro')}
</p>
</div>
<ul className="space-y-5">
{SUBDIR_INFO.map(({ id, icon, title, desc, agency }) => (
{SUBDIR_INFO.map(({ id, icon, key }) => (
<li key={id} className="flex gap-3">
<span className="text-xl leading-none mt-0.5 select-none" aria-hidden>
{icon}
</span>
<div className="flex-1 min-w-0">
<div className="text-[13px] font-semibold text-slate-900">{title}</div>
<p className="text-[13px] text-slate-600 mt-1 leading-relaxed">{desc}</p>
<p className="text-2xs text-slate-400 mt-1 uppercase tracking-wide">{agency}</p>
<div className="text-[13px] font-semibold text-slate-900">{t(`root.subdirs.${key}.title`)}</div>
<p className="text-[13px] text-slate-600 mt-1 leading-relaxed">{t(`root.subdirs.${key}.desc`)}</p>
<p className="text-2xs text-slate-400 mt-1 uppercase tracking-wide">{t(`root.subdirs.${key}.agency`)}</p>
</div>
</li>
))}