@minimalcorp/tsunagi 0.3.3 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/.next/standalone/apps/web/.next/BUILD_ID +1 -1
  2. package/.next/standalone/apps/web/.next/build-manifest.json +3 -3
  3. package/.next/standalone/apps/web/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/apps/web/.next/server/app/_global-error.html +1 -1
  5. package/.next/standalone/apps/web/.next/server/app/_global-error.rsc +1 -1
  6. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  9. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  10. package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  11. package/.next/standalone/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/apps/web/.next/server/app/_not-found.html +1 -1
  13. package/.next/standalone/apps/web/.next/server/app/_not-found.rsc +2 -2
  14. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  15. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  16. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  17. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  18. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  19. package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/.next/standalone/apps/web/.next/server/app/index.html +1 -1
  21. package/.next/standalone/apps/web/.next/server/app/index.rsc +3 -3
  22. package/.next/standalone/apps/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  23. package/.next/standalone/apps/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
  24. package/.next/standalone/apps/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  25. package/.next/standalone/apps/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  26. package/.next/standalone/apps/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  27. package/.next/standalone/apps/web/.next/server/app/page.js.nft.json +1 -1
  28. package/.next/standalone/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
  29. package/.next/standalone/apps/web/.next/server/app/settings/page.js.nft.json +1 -1
  30. package/.next/standalone/apps/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  31. package/.next/standalone/apps/web/.next/server/app/settings.html +1 -1
  32. package/.next/standalone/apps/web/.next/server/app/settings.rsc +3 -3
  33. package/.next/standalone/apps/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  34. package/.next/standalone/apps/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  35. package/.next/standalone/apps/web/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  36. package/.next/standalone/apps/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  37. package/.next/standalone/apps/web/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
  38. package/.next/standalone/apps/web/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  39. package/.next/standalone/apps/web/.next/server/app/tasks/[id]/page.js.nft.json +1 -1
  40. package/.next/standalone/apps/web/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0qjafjt._.js +1 -1
  42. package/.next/standalone/apps/web/.next/server/chunks/ssr/{_13w5ytx._.js → _01~tp-i._.js} +2 -2
  43. package/.next/standalone/apps/web/.next/server/chunks/ssr/{_0kflgfj._.js → _03lm.~7._.js} +3 -3
  44. package/.next/standalone/apps/web/.next/server/chunks/ssr/{_0g79jqo._.js → _09br4yx._.js} +3 -3
  45. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0g.cd6a._.js +2 -2
  46. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0h-u~an._.js +7 -0
  47. package/.next/standalone/apps/web/.next/server/chunks/ssr/{_139_l.u._.js → _0kkt7a_._.js} +2 -2
  48. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0ts4rpp._.js +3 -0
  49. package/.next/standalone/apps/web/.next/server/chunks/ssr/_13ne7ej._.js +3 -0
  50. package/.next/standalone/apps/web/.next/server/chunks/ssr/apps_web_src_app_settings_page_tsx_0i6itlb._.js +1 -3
  51. package/.next/standalone/apps/web/.next/server/chunks/ssr/apps_web_src_app_tasks_[id]_page_tsx_0jshsm2._.js +3 -3
  52. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0cv326~._.js → node_modules_06jdmu~._.js} +1 -1
  53. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0h.vgyn._.js → node_modules_0ac2-~z._.js} +1 -1
  54. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0sn0lqb._.js → node_modules_0gglkx9._.js} +1 -1
  55. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0tod6y8._.js → node_modules_0h4h_aw._.js} +1 -1
  56. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0q_5qo~._.js → node_modules_0i5v48e._.js} +1 -1
  57. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_09d2oqj._.js → node_modules_0k3x6_w._.js} +1 -1
  58. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0oip5a1._.js → node_modules_0q8yuvq._.js} +1 -1
  59. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0npujym._.js → node_modules_0rnsluy._.js} +1 -1
  60. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0krwgny._.js → node_modules_0t-jssg._.js} +1 -1
  61. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0l23gkf._.js → node_modules_0t6ysh_._.js} +1 -1
  62. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_11-z65a._.js → node_modules_0ut2-yw._.js} +1 -1
  63. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0_huoqd._.js → node_modules_0vq~hzy._.js} +1 -1
  64. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0a57phw._.js → node_modules_0w6fm3f._.js} +2 -2
  65. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0xp9nhx._.js → node_modules_0yb2sh9._.js} +1 -1
  66. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0q_xfyl._.js → node_modules_0yc~s8p._.js} +1 -1
  67. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_0ak_3rk._.js → node_modules_0zi0w9_._.js} +1 -1
  68. package/.next/standalone/apps/web/.next/server/chunks/ssr/{node_modules_04pfam-._.js → node_modules_0zzdoud._.js} +1 -1
  69. package/.next/standalone/apps/web/.next/server/chunks/ssr/{_0w2dm3r._.js → node_modules_lucide-react_dist_esm_icons_0zerlct._.js} +2 -2
  70. package/.next/standalone/apps/web/.next/server/middleware-build-manifest.js +3 -3
  71. package/.next/standalone/apps/web/.next/server/pages/404.html +1 -1
  72. package/.next/standalone/apps/web/.next/server/pages/500.html +1 -1
  73. package/.next/standalone/apps/web/.next/server/server-reference-manifest.js +1 -1
  74. package/.next/standalone/apps/web/.next/server/server-reference-manifest.json +1 -1
  75. package/.next/standalone/apps/web/.next/static/chunks/{0l83q95s~tih4.js → 08s3o7outb~0z.js} +1 -1
  76. package/.next/standalone/apps/web/.next/static/chunks/0a2u28f44p7t..js +1 -0
  77. package/.next/standalone/apps/web/.next/static/chunks/{0oricprxoxb_d.js → 0ae7zmpe8063z.js} +10 -10
  78. package/.next/standalone/apps/web/.next/static/chunks/0dgu~u-1e5b7-.js +5 -0
  79. package/.next/standalone/apps/web/.next/static/chunks/{0whl1y16cvn5q.js → 0e8u7rqrqfiiy.js} +1 -1
  80. package/.next/standalone/apps/web/.next/static/chunks/{0z60ewb40i2ce.js → 0gxhy80~c0gvp.js} +1 -1
  81. package/.next/standalone/apps/web/.next/static/chunks/0n72w4sxrwoj4.js +5 -0
  82. package/.next/standalone/apps/web/.next/static/chunks/0o1bh_qwdvmid.css +4 -0
  83. package/.next/standalone/apps/web/.next/static/chunks/{17~93fal1fw_d.js → 0uugzgqr-ug3_.js} +1 -1
  84. package/.next/standalone/apps/web/.next/static/chunks/{149sia28cskw9.js → 0yp~t_.pozr-d.js} +6 -6
  85. package/.next/standalone/apps/web/.next/static/chunks/0ysgl4vmer~v5.js +6 -0
  86. package/.next/standalone/apps/web/.next/static/chunks/{053h220fng_68.js → 11u7x4ic4~mp3.js} +10 -10
  87. package/.next/standalone/apps/web/.next/static/chunks/13_9zaka0bif_.js +1 -0
  88. package/.next/standalone/apps/web/package.json +1 -3
  89. package/README.md +1 -1
  90. package/dist/app.js +3 -4
  91. package/dist/plugin-lifecycle.d.ts +5 -3
  92. package/dist/plugin-lifecycle.js +40 -16
  93. package/dist/prisma/migrations/20261011000000_add_codex_support/migration.sql +20 -0
  94. package/dist/prisma/schema.prisma +9 -5
  95. package/dist/server/generated/prisma/browser.d.ts +2 -2
  96. package/dist/server/generated/prisma/client.d.ts +2 -2
  97. package/dist/server/generated/prisma/internal/class.d.ts +4 -4
  98. package/dist/server/generated/prisma/internal/class.js +4 -4
  99. package/dist/server/generated/prisma/internal/prismaNamespace.d.ts +41 -39
  100. package/dist/server/generated/prisma/internal/prismaNamespace.js +4 -2
  101. package/dist/server/generated/prisma/internal/prismaNamespaceBrowser.d.ts +5 -3
  102. package/dist/server/generated/prisma/internal/prismaNamespaceBrowser.js +4 -2
  103. package/dist/server/generated/prisma/models/AgentProfile.d.ts +972 -0
  104. package/dist/server/generated/prisma/models/Tab.d.ts +36 -1
  105. package/dist/server/generated/prisma/models.d.ts +1 -1
  106. package/dist/server/index.js +2 -7
  107. package/dist/server/lib/agent-profiles.d.ts +44 -0
  108. package/dist/server/lib/agent-profiles.js +130 -0
  109. package/dist/server/lib/agents/claude.d.ts +2 -0
  110. package/dist/server/lib/agents/claude.js +130 -0
  111. package/dist/server/lib/agents/cli.d.ts +14 -0
  112. package/dist/server/lib/agents/cli.js +57 -0
  113. package/dist/server/lib/agents/codex.d.ts +2 -0
  114. package/dist/server/lib/agents/codex.js +285 -0
  115. package/dist/server/lib/agents/index.d.ts +11 -0
  116. package/dist/server/lib/agents/index.js +19 -0
  117. package/dist/server/lib/agents/login-callback.d.ts +11 -0
  118. package/dist/server/lib/agents/login-callback.js +47 -0
  119. package/dist/server/lib/agents/types.d.ts +77 -0
  120. package/dist/server/lib/agents/types.js +8 -0
  121. package/dist/server/lib/pty-env-sync.js +1 -1
  122. package/dist/server/lib/pty-launch.d.ts +8 -10
  123. package/dist/server/lib/pty-launch.js +20 -58
  124. package/dist/server/lib/repositories/task.js +1 -0
  125. package/dist/server/lib/tab-todos.d.ts +5 -0
  126. package/dist/server/lib/tab-todos.js +13 -0
  127. package/dist/server/pty-manager.d.ts +7 -2
  128. package/dist/server/pty-manager.js +13 -0
  129. package/dist/server/routes/agent-profiles.d.ts +2 -0
  130. package/dist/server/routes/agent-profiles.js +193 -0
  131. package/dist/server/routes/env.js +2 -2
  132. package/dist/server/routes/hooks.d.ts +4 -19
  133. package/dist/server/routes/hooks.js +83 -73
  134. package/dist/server/routes/mcp.js +2 -2
  135. package/dist/server/routes/onboarding.js +19 -10
  136. package/dist/server/routes/tasks.js +4 -4
  137. package/dist/server/routes/terminal.js +47 -34
  138. package/dist/with-plugin.js +3 -3
  139. package/npm-shrinkwrap.json +37 -24
  140. package/package.json +1 -1
  141. package/tsunagi-marketplace/codex/tsunagi-task.md +120 -0
  142. package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__11y.qj~._.js +0 -3
  143. package/.next/standalone/apps/web/.next/server/chunks/ssr/_03vftq7._.js +0 -7
  144. package/.next/standalone/apps/web/.next/server/chunks/ssr/_0hnxatt._.js +0 -3
  145. package/.next/standalone/apps/web/.next/server/chunks/ssr/_10gk93.._.js +0 -3
  146. package/.next/standalone/apps/web/.next/static/chunks/0.gcmzq82~36i.js +0 -1
  147. package/.next/standalone/apps/web/.next/static/chunks/06gfh91..uydi.js +0 -5
  148. package/.next/standalone/apps/web/.next/static/chunks/0b90ys7wq-p.4.css +0 -4
  149. package/.next/standalone/apps/web/.next/static/chunks/0crn03y2tj0lu.js +0 -6
  150. package/.next/standalone/apps/web/.next/static/chunks/0lvl3ec93cab_.js +0 -7
  151. package/.next/standalone/apps/web/.next/static/chunks/0makl-d3f0_qh.js +0 -2878
  152. package/.next/standalone/apps/web/.next/static/chunks/0o6ggm7jrim25.js +0 -1
  153. package/.next/standalone/apps/web/public/vad/ort-wasm-simd-threaded.mjs +0 -59
  154. package/.next/standalone/apps/web/public/vad/ort-wasm-simd-threaded.wasm +0 -0
  155. package/.next/standalone/apps/web/public/vad/silero_vad_v5.onnx +0 -0
  156. package/.next/standalone/apps/web/public/vad/vad.worklet.bundle.min.js +0 -1
  157. package/dist/server/generated/prisma/models/ClaudeProfile.d.ts +0 -939
  158. package/dist/server/lib/asr-models.d.ts +0 -7
  159. package/dist/server/lib/asr-models.js +0 -51
  160. package/dist/server/lib/claude-profiles.d.ts +0 -49
  161. package/dist/server/lib/claude-profiles.js +0 -168
  162. package/dist/server/lib/process-port.d.ts +0 -1
  163. package/dist/server/lib/process-port.js +0 -28
  164. package/dist/server/lib/python-venv.d.ts +0 -4
  165. package/dist/server/lib/python-venv.js +0 -66
  166. package/dist/server/lib/voice-debug-log.d.ts +0 -9
  167. package/dist/server/lib/voice-debug-log.js +0 -28
  168. package/dist/server/lib/whisper-process.d.ts +0 -40
  169. package/dist/server/lib/whisper-process.js +0 -333
  170. package/dist/server/routes/claude-profiles.d.ts +0 -2
  171. package/dist/server/routes/claude-profiles.js +0 -138
  172. package/dist/server/routes/whisper.d.ts +0 -2
  173. package/dist/server/routes/whisper.js +0 -103
  174. package/dist/whisper-server/README.md +0 -31
  175. package/dist/whisper-server/download_model.py +0 -19
  176. package/dist/whisper-server/requirements.txt +0 -8
  177. package/dist/whisper-server/run.sh +0 -62
  178. package/dist/whisper-server/server.py +0 -147
  179. /package/.next/standalone/apps/web/.next/static/{7x81GlNKt9yqIkeI7U1BX → vdAs-hr87-L7y2bUSdX3i}/_buildManifest.js +0 -0
  180. /package/.next/standalone/apps/web/.next/static/{7x81GlNKt9yqIkeI7U1BX → vdAs-hr87-L7y2bUSdX3i}/_clientMiddlewareManifest.js +0 -0
  181. /package/.next/standalone/apps/web/.next/static/{7x81GlNKt9yqIkeI7U1BX → vdAs-hr87-L7y2bUSdX3i}/_ssgManifest.js +0 -0
  182. /package/dist/server/generated/prisma/models/{ClaudeProfile.js → AgentProfile.js} +0 -0
@@ -1,7 +0,0 @@
1
- import type { AsrModel, VoiceInputSettings } from '@minimalcorp/tsunagi-shared';
2
- export declare const ASR_MODELS: AsrModel[];
3
- export declare const DEFAULT_ASR_MODEL_ID: string;
4
- export declare function findAsrModel(id: string): AsrModel | undefined;
5
- export declare function findAsrModelByRepo(repo: string): AsrModel | undefined;
6
- export declare function getVoiceInputSettings(): Promise<VoiceInputSettings>;
7
- export declare function saveVoiceInputSettings(settings: VoiceInputSettings): Promise<VoiceInputSettings>;
@@ -1,51 +0,0 @@
1
- import { readAppSetting, writeAppSetting } from './local-llm-env.js';
2
- // 音声入力で選べる音声認識モデルの一覧(唯一の定義元)。whisper-server には
3
- // engine と repo を環境変数で渡し、どのモデルを読み込むかを切り替える。
4
- // expectedBytes は Hugging Face 上のファイル合計(2026-09時点)で、進捗・ETAの目安に使う。
5
- export const ASR_MODELS = [
6
- {
7
- id: 'whisper-large-v3-turbo',
8
- label: 'Whisper large-v3-turbo',
9
- description: 'OpenAI Whisper。読み上げ調の音声に強く、句読点も出力する',
10
- engine: 'whisper',
11
- repo: 'mlx-community/whisper-large-v3-turbo',
12
- expectedBytes: 1_614_000_000,
13
- license: 'MIT',
14
- },
15
- {
16
- id: 'qwen3-asr-1.7b',
17
- label: 'Qwen3-ASR 1.7B',
18
- description: '会話音声の日本語ベンチマークで高精度。プロンプトの単語を語彙ヒントとして使う (8bit量子化版)',
19
- engine: 'qwen3-asr',
20
- repo: 'mlx-community/Qwen3-ASR-1.7B-8bit',
21
- expectedBytes: 2_468_000_000,
22
- license: 'Apache-2.0',
23
- },
24
- {
25
- id: 'qwen3-asr-1.7b-ja',
26
- label: 'Qwen3-ASR 1.7B JA',
27
- description: 'Qwen3-ASR 1.7B を日本語向けに追加学習したモデル (neosophie)。固有名詞・専門用語の表記を重視',
28
- engine: 'qwen3-asr',
29
- repo: 'neosophie/Qwen3-ASR-1.7B-JA',
30
- expectedBytes: 4_092_000_000,
31
- license: 'Apache-2.0',
32
- },
33
- ];
34
- export const DEFAULT_ASR_MODEL_ID = ASR_MODELS[0].id;
35
- export function findAsrModel(id) {
36
- return ASR_MODELS.find((m) => m.id === id);
37
- }
38
- export function findAsrModelByRepo(repo) {
39
- return ASR_MODELS.find((m) => m.repo === repo);
40
- }
41
- const SETTING_KEY = 'voice-input';
42
- export async function getVoiceInputSettings() {
43
- const settings = await readAppSetting(SETTING_KEY, {
44
- modelId: DEFAULT_ASR_MODEL_ID,
45
- });
46
- // 一覧から外れたモデルが保存されていた場合は既定のモデルに戻す
47
- return findAsrModel(settings.modelId) ? settings : { modelId: DEFAULT_ASR_MODEL_ID };
48
- }
49
- export function saveVoiceInputSettings(settings) {
50
- return writeAppSetting(SETTING_KEY, settings);
51
- }
@@ -1,49 +0,0 @@
1
- import type { ClaudeAuthStatus, ClaudeProfile } from '@minimalcorp/tsunagi-shared';
2
- /**
3
- * タブで使う Claude プロファイルの割り当てを保存する予約キー。値はプロファイルの slug か
4
- * DEFAULT_CLAUDE_PROFILE。環境変数と同じ global → owner → repo の継承で解決し、PTY 起動時に
5
- * CLAUDE_CONFIG_DIR へ変換する(resolveClaudeProfileEnv)。
6
- */
7
- export declare const CLAUDE_PROFILE_ENV_KEY = "TSUNAGI_CLAUDE_PROFILE";
8
- /** システム既定(CLAUDE_CONFIG_DIR を付けず ~/.claude を使う) */
9
- export declare const DEFAULT_CLAUDE_PROFILE = "default";
10
- /**
11
- * Claude Code が /login のログインより優先する認証情報の環境変数。
12
- * プロファイルを選んだタブでは、外側 Terminal から継承した値も取り除く(残るとプロファイルの
13
- * ログインではなくこちらが使われるため)。
14
- */
15
- export declare const CLAUDE_AUTH_ENV_KEYS: string[];
16
- /** 汎用の環境変数として登録させないキー(認証は Claude プロファイルで扱う) */
17
- export declare const RESERVED_ENV_KEYS: string[];
18
- export declare function getClaudeProfilesDir(): string;
19
- /** プロファイルの CLAUDE_CONFIG_DIR。システム既定は undefined(~/.claude) */
20
- export declare function getClaudeProfileConfigDir(slug: string): string | undefined;
21
- /** 空白を `-` にし、小文字にする(macOS のファイルシステムは大文字小文字を区別しないため) */
22
- export declare function toClaudeProfileSlug(name: string): string;
23
- /** プロファイル名の検証。問題があればエラーメッセージを返す */
24
- export declare function validateClaudeProfileName(name: string): string | null;
25
- export declare function listClaudeProfiles(): Promise<ClaudeProfile[]>;
26
- export declare function claudeProfileExists(slug: string): Promise<boolean>;
27
- export declare function createClaudeProfile(name: string): Promise<ClaudeProfile>;
28
- /**
29
- * プロファイルを削除する。ログイン情報(macOS は Keychain)を残さないよう先に logout し、
30
- * このプロファイルを割り当てていたスコープは割り当てを外して親の設定を継承させる。
31
- */
32
- export declare function deleteClaudeProfile(slug: string): Promise<void>;
33
- /** `claude auth status --json` でプロファイルのログイン状態を取得する */
34
- export declare function getClaudeAuthStatus(slug: string): Promise<ClaudeAuthStatus>;
35
- /** ログイン用 PTY に書き込むコマンド */
36
- export declare function buildClaudeLoginCommand(): string;
37
- /** ログイン用 PTY の環境変数(PtyManager.createSession の env / unsetKeys) */
38
- export declare function claudeLoginPtyEnv(slug: string): {
39
- env: Record<string, string>;
40
- unsetKeys: string[];
41
- };
42
- /**
43
- * 継承解決済みの環境変数に含まれるプロファイル割り当てを CLAUDE_CONFIG_DIR に変換する。
44
- * 予約キー自体は PTY に渡さない。
45
- */
46
- export declare function resolveClaudeProfileEnv(env: Record<string, string>): {
47
- env: Record<string, string>;
48
- unsetKeys: string[];
49
- };
@@ -1,168 +0,0 @@
1
- import { execFile } from 'child_process';
2
- import * as fs from 'fs/promises';
3
- import * as path from 'path';
4
- import { promisify } from 'util';
5
- import { prisma } from './db.js';
6
- import { getTsunagiDataDir } from './data-path.js';
7
- const execFileAsync = promisify(execFile);
8
- /**
9
- * タブで使う Claude プロファイルの割り当てを保存する予約キー。値はプロファイルの slug か
10
- * DEFAULT_CLAUDE_PROFILE。環境変数と同じ global → owner → repo の継承で解決し、PTY 起動時に
11
- * CLAUDE_CONFIG_DIR へ変換する(resolveClaudeProfileEnv)。
12
- */
13
- export const CLAUDE_PROFILE_ENV_KEY = 'TSUNAGI_CLAUDE_PROFILE';
14
- /** システム既定(CLAUDE_CONFIG_DIR を付けず ~/.claude を使う) */
15
- export const DEFAULT_CLAUDE_PROFILE = 'default';
16
- /**
17
- * Claude Code が /login のログインより優先する認証情報の環境変数。
18
- * プロファイルを選んだタブでは、外側 Terminal から継承した値も取り除く(残るとプロファイルの
19
- * ログインではなくこちらが使われるため)。
20
- */
21
- export const CLAUDE_AUTH_ENV_KEYS = ['ANTHROPIC_API_KEY', 'CLAUDE_CODE_OAUTH_TOKEN'];
22
- /** 汎用の環境変数として登録させないキー(認証は Claude プロファイルで扱う) */
23
- export const RESERVED_ENV_KEYS = [
24
- CLAUDE_PROFILE_ENV_KEY,
25
- 'CLAUDE_CONFIG_DIR',
26
- ...CLAUDE_AUTH_ENV_KEYS,
27
- ];
28
- const PROFILE_NAME_PATTERN = /^[A-Za-z0-9 _-]+$/;
29
- export function getClaudeProfilesDir() {
30
- return path.join(getTsunagiDataDir(), 'claude-profiles');
31
- }
32
- /** プロファイルの CLAUDE_CONFIG_DIR。システム既定は undefined(~/.claude) */
33
- export function getClaudeProfileConfigDir(slug) {
34
- if (slug === DEFAULT_CLAUDE_PROFILE)
35
- return undefined;
36
- return path.join(getClaudeProfilesDir(), slug);
37
- }
38
- /** 空白を `-` にし、小文字にする(macOS のファイルシステムは大文字小文字を区別しないため) */
39
- export function toClaudeProfileSlug(name) {
40
- return name.trim().replace(/\s+/g, '-').toLowerCase();
41
- }
42
- /** プロファイル名の検証。問題があればエラーメッセージを返す */
43
- export function validateClaudeProfileName(name) {
44
- const trimmed = name.trim();
45
- if (!trimmed)
46
- return 'Name is required';
47
- if (!PROFILE_NAME_PATTERN.test(trimmed)) {
48
- return 'Use only letters, numbers, spaces, "-" and "_"';
49
- }
50
- if (toClaudeProfileSlug(trimmed) === DEFAULT_CLAUDE_PROFILE) {
51
- return `"${DEFAULT_CLAUDE_PROFILE}" is reserved`;
52
- }
53
- return null;
54
- }
55
- export async function listClaudeProfiles() {
56
- const rows = await prisma.claudeProfile.findMany({ orderBy: { createdAt: 'asc' } });
57
- return rows.map((row) => ({
58
- slug: row.slug,
59
- name: row.name,
60
- configDir: path.join(getClaudeProfilesDir(), row.slug),
61
- }));
62
- }
63
- export async function claudeProfileExists(slug) {
64
- if (slug === DEFAULT_CLAUDE_PROFILE)
65
- return true;
66
- return (await prisma.claudeProfile.count({ where: { slug } })) > 0;
67
- }
68
- export async function createClaudeProfile(name) {
69
- const error = validateClaudeProfileName(name);
70
- if (error)
71
- throw new Error(error);
72
- const trimmed = name.trim();
73
- const slug = toClaudeProfileSlug(trimmed);
74
- if (await claudeProfileExists(slug)) {
75
- throw new Error(`Profile "${slug}" already exists`);
76
- }
77
- const configDir = path.join(getClaudeProfilesDir(), slug);
78
- await fs.mkdir(configDir, { recursive: true });
79
- await prisma.claudeProfile.create({ data: { slug, name: trimmed } });
80
- return { slug, name: trimmed, configDir };
81
- }
82
- /**
83
- * プロファイルを削除する。ログイン情報(macOS は Keychain)を残さないよう先に logout し、
84
- * このプロファイルを割り当てていたスコープは割り当てを外して親の設定を継承させる。
85
- */
86
- export async function deleteClaudeProfile(slug) {
87
- const configDir = getClaudeProfileConfigDir(slug);
88
- if (!configDir)
89
- throw new Error('The system default profile cannot be deleted');
90
- await runClaude(['auth', 'logout'], configDir).catch(() => undefined);
91
- await prisma.environmentVariable.deleteMany({
92
- where: { key: CLAUDE_PROFILE_ENV_KEY, value: slug },
93
- });
94
- await prisma.claudeProfile.delete({ where: { slug } });
95
- await fs.rm(configDir, { recursive: true, force: true });
96
- }
97
- /**
98
- * claude を実行するときの環境変数。プロファイルのログインを見るよう CLAUDE_CONFIG_DIR を付け、
99
- * ログインより優先される認証情報の環境変数は取り除く。システム既定は外側 Terminal の環境のまま
100
- * (普段ターミナルで claude を使うときと同じ)。
101
- */
102
- function claudeEnv(configDir) {
103
- const env = { ...process.env };
104
- if (configDir) {
105
- env.CLAUDE_CONFIG_DIR = configDir;
106
- for (const key of CLAUDE_AUTH_ENV_KEYS)
107
- delete env[key];
108
- }
109
- return env;
110
- }
111
- async function runClaude(args, configDir) {
112
- const { stdout } = await execFileAsync('claude', args, {
113
- env: claudeEnv(configDir),
114
- timeout: 15_000,
115
- });
116
- return stdout;
117
- }
118
- /** `claude auth status --json` でプロファイルのログイン状態を取得する */
119
- export async function getClaudeAuthStatus(slug) {
120
- try {
121
- const raw = JSON.parse(await runClaude(['auth', 'status', '--json'], getClaudeProfileConfigDir(slug)));
122
- const str = (v) => (typeof v === 'string' ? v : undefined);
123
- return {
124
- loggedIn: raw.loggedIn === true,
125
- authMethod: str(raw.authMethod),
126
- email: str(raw.email),
127
- orgName: str(raw.orgName),
128
- subscriptionType: str(raw.subscriptionType),
129
- };
130
- }
131
- catch (err) {
132
- // claude auth status は未ログイン時に非 0 で終了するが、stdout には JSON が出る
133
- const stdout = err.stdout;
134
- if (stdout) {
135
- try {
136
- const raw = JSON.parse(stdout);
137
- return { loggedIn: raw.loggedIn === true, authMethod: raw.authMethod };
138
- }
139
- catch {
140
- // fallthrough
141
- }
142
- }
143
- return { loggedIn: false, error: err instanceof Error ? err.message : String(err) };
144
- }
145
- }
146
- /** ログイン用 PTY に書き込むコマンド */
147
- export function buildClaudeLoginCommand() {
148
- return 'claude auth login';
149
- }
150
- /** ログイン用 PTY の環境変数(PtyManager.createSession の env / unsetKeys) */
151
- export function claudeLoginPtyEnv(slug) {
152
- const configDir = getClaudeProfileConfigDir(slug);
153
- if (!configDir)
154
- return { env: {}, unsetKeys: [] };
155
- return { env: { CLAUDE_CONFIG_DIR: configDir }, unsetKeys: CLAUDE_AUTH_ENV_KEYS };
156
- }
157
- /**
158
- * 継承解決済みの環境変数に含まれるプロファイル割り当てを CLAUDE_CONFIG_DIR に変換する。
159
- * 予約キー自体は PTY に渡さない。
160
- */
161
- export function resolveClaudeProfileEnv(env) {
162
- const { [CLAUDE_PROFILE_ENV_KEY]: slug, ...rest } = env;
163
- const configDir = slug ? getClaudeProfileConfigDir(slug) : undefined;
164
- // システム既定: 外側 Terminal の環境のまま(普段ターミナルで claude を使うときと同じ)
165
- if (!configDir)
166
- return { env: rest, unsetKeys: [] };
167
- return { env: { ...rest, CLAUDE_CONFIG_DIR: configDir }, unsetKeys: CLAUDE_AUTH_ENV_KEYS };
168
- }
@@ -1 +0,0 @@
1
- export declare function killProcessOnPort(port: number): Promise<boolean>;
@@ -1,28 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- // 指定ポートでLISTENしているプロセスを探して停止する。tsunagi自身が起動した
3
- // 場合はchild_processのハンドルで直接killできるが、`make whisper`
4
- // のようにtsunagi外で手動起動された場合はハンドルを持たないため、
5
- // ポート番号を手がかりにOS側から見つけて停止する。
6
- export function killProcessOnPort(port) {
7
- return new Promise((resolve) => {
8
- execFile('lsof', ['-ti', `:${port}`, '-sTCP:LISTEN'], (_error, stdout) => {
9
- const pids = (stdout || '')
10
- .split('\n')
11
- .map((s) => s.trim())
12
- .filter(Boolean);
13
- if (pids.length === 0) {
14
- resolve(false);
15
- return;
16
- }
17
- for (const pid of pids) {
18
- try {
19
- process.kill(Number(pid), 'SIGTERM');
20
- }
21
- catch {
22
- // 既に終了している等は無視
23
- }
24
- }
25
- resolve(true);
26
- });
27
- });
28
- }
@@ -1,4 +0,0 @@
1
- export declare function findPython(): string | null;
2
- export declare const PYTHON_NOT_FOUND_MESSAGE = "Python 3.10\u4EE5\u4E0A\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3002'brew install python@3.12' \u7B49\u3067\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
3
- export declare function isVenvUpToDate(venvDir: string, requirementsFile: string): boolean;
4
- export declare function writeVenvMarker(venvDir: string, requirementsFile: string): void;
@@ -1,66 +0,0 @@
1
- import { execFileSync } from 'node:child_process';
2
- import * as crypto from 'node:crypto';
3
- import * as fs from 'node:fs';
4
- import * as path from 'node:path';
5
- // mlx/mlx-lm/mlx-whisper の固定バージョンが requires-python >=3.10 のため、venv作成に
6
- // 使う python3 自体も 3.10 以上でなければ pip install がそもそも失敗する。`python3` という
7
- // 名前が PATH 上のどのバージョンを指すかは環境依存(古い macOS 付属 Python 等)なため、
8
- // 候補を新しい順に探して最初に見つかった 3.10 以上を使う。
9
- const MIN_PYTHON_VERSION = '3.10';
10
- const PYTHON_CANDIDATES = [
11
- 'python3.14',
12
- 'python3.13',
13
- 'python3.12',
14
- 'python3.11',
15
- 'python3.10',
16
- 'python3',
17
- ];
18
- function pythonVersion(bin) {
19
- try {
20
- return execFileSync(bin, ['-c', 'import sys; print("%d.%d" % sys.version_info[:2])'], {
21
- encoding: 'utf8',
22
- }).trim();
23
- }
24
- catch {
25
- return null;
26
- }
27
- }
28
- function versionAtLeast(version, min) {
29
- const [vMajor, vMinor] = version.split('.').map(Number);
30
- const [mMajor, mMinor] = min.split('.').map(Number);
31
- return vMajor !== mMajor ? vMajor > mMajor : vMinor >= mMinor;
32
- }
33
- export function findPython() {
34
- for (const cand of PYTHON_CANDIDATES) {
35
- const version = pythonVersion(cand);
36
- if (version && versionAtLeast(version, MIN_PYTHON_VERSION))
37
- return cand;
38
- }
39
- return null;
40
- }
41
- export const PYTHON_NOT_FOUND_MESSAGE = `Python ${MIN_PYTHON_VERSION}以上が見つかりません。'brew install python@3.12' 等でインストールしてください。`;
42
- function venvMarkerPath(venvDir) {
43
- return path.join(venvDir, '.requirements.sha256');
44
- }
45
- function requirementsHash(requirementsFile) {
46
- return crypto.createHash('sha256').update(fs.readFileSync(requirementsFile)).digest('hex');
47
- }
48
- // venvが「存在するだけ」でなく、実際に使えるかを検証する。
49
- // - venv作成に使われた python が 3.10 未満だと mlx 系のインストールに失敗するバージョンのまま放置される
50
- // - requirements.txt のバージョン指定を後から変更しても、既存venvには反映されない
51
- // のいずれかが起きていないかを、venv自身のpythonバージョンと記録済みハッシュから判定する。
52
- export function isVenvUpToDate(venvDir, requirementsFile) {
53
- const venvPython = path.join(venvDir, 'bin', 'python3');
54
- if (!fs.existsSync(venvPython))
55
- return false;
56
- const version = pythonVersion(venvPython);
57
- if (!version || !versionAtLeast(version, MIN_PYTHON_VERSION))
58
- return false;
59
- const marker = venvMarkerPath(venvDir);
60
- if (!fs.existsSync(marker))
61
- return false;
62
- return fs.readFileSync(marker, 'utf8').trim() === requirementsHash(requirementsFile);
63
- }
64
- export function writeVenvMarker(venvDir, requirementsFile) {
65
- fs.writeFileSync(venvMarkerPath(venvDir), requirementsHash(requirementsFile));
66
- }
@@ -1,9 +0,0 @@
1
- export interface VoiceDebugLogEntry {
2
- /** 文字起こしに使ったモデル(Hugging Face のリポジトリ ID) */
3
- model: string | undefined;
4
- /** tsunagi から whisper-server への往復時間(モデル間の速度比較用) */
5
- elapsedMs: number;
6
- whisperPrompt: string | undefined;
7
- whisperText: string;
8
- }
9
- export declare function appendVoiceDebugLog(entry: VoiceDebugLogEntry): void;
@@ -1,28 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import * as path from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- // apps/server直下(src/libとdist/libのどちらから見ても2階層上)に置く。
5
- // docker-compose(compose.yml)ではリポジトリ全体がbind mountされているため、
6
- // ホスト側からもこのファイルをそのまま読める(named volumeの~/.tsunagiとは違い、
7
- // Claude Codeが次回セッションでRead/grepしてプロンプト改善の材料にできる)。
8
- const LOG_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'logs');
9
- const LOG_FILE = path.join(LOG_DIR, 'voice-input-debug.log');
10
- // デバッグ用途のため肥大化を防ぐ簡易ローテーション(直近件数のみ保持)。
11
- const MAX_ENTRIES = 200;
12
- // モデル・処理時間・プロンプト・文字起こし結果を1リクエスト1行(JSON Lines)で追記する。
13
- // プロンプト改善のデバッグ専用ログであり、書き込み失敗はリクエスト自体を
14
- // 失敗させるべきではないため例外を握りつぶす。
15
- export function appendVoiceDebugLog(entry) {
16
- try {
17
- fs.mkdirSync(LOG_DIR, { recursive: true });
18
- const line = JSON.stringify({ timestamp: new Date().toISOString(), ...entry });
19
- fs.appendFileSync(LOG_FILE, `${line}\n`);
20
- const lines = fs.readFileSync(LOG_FILE, 'utf-8').split('\n').filter(Boolean);
21
- if (lines.length > MAX_ENTRIES) {
22
- fs.writeFileSync(LOG_FILE, `${lines.slice(-MAX_ENTRIES).join('\n')}\n`);
23
- }
24
- }
25
- catch {
26
- // デバッグログの書き込み失敗は無視する(本処理に影響させない)。
27
- }
28
- }
@@ -1,40 +0,0 @@
1
- import type { AsrModelList } from '@minimalcorp/tsunagi-shared';
2
- export declare function findWhisperServerDir(): string | null;
3
- export type WhisperServerStep = 'not_running' | 'installing_deps' | 'downloading_model' | 'starting_server' | 'running' | 'running_external' | 'error';
4
- export interface DownloadProgress {
5
- downloadedBytes: number;
6
- totalBytes: number;
7
- etaSeconds: number | null;
8
- }
9
- export interface WhisperServerInfo {
10
- step: WhisperServerStep;
11
- serverDir: string | null;
12
- /** 起動中のサーバーが読み込んでいる(セットアップ中は読み込もうとしている)モデル */
13
- modelId: string | null;
14
- downloadProgress?: DownloadProgress;
15
- error?: string;
16
- }
17
- export declare function getWhisperServerStatus(): Promise<WhisperServerInfo>;
18
- export declare function startWhisperServer(): Promise<{
19
- started: boolean;
20
- error?: string;
21
- }>;
22
- export declare function stopWhisperServer(): Promise<{
23
- stopped: boolean;
24
- error?: string;
25
- }>;
26
- export declare function stopWhisperServerOnExit(): void;
27
- export declare function listAsrModels(): Promise<AsrModelList>;
28
- export declare function selectAsrModel(modelId: string): Promise<{
29
- ok: true;
30
- restarted: boolean;
31
- } | {
32
- ok: false;
33
- error: string;
34
- }>;
35
- export declare function deleteAsrModel(modelId: string): Promise<{
36
- ok: true;
37
- } | {
38
- ok: false;
39
- error: string;
40
- }>;