@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
@@ -29,6 +29,7 @@ export type TabMinAggregateOutputType = {
29
29
  completedAt: Date | null;
30
30
  todos: string | null;
31
31
  unread: boolean | null;
32
+ agentSessionId: string | null;
32
33
  updatedAt: Date | null;
33
34
  };
34
35
  export type TabMaxAggregateOutputType = {
@@ -42,6 +43,7 @@ export type TabMaxAggregateOutputType = {
42
43
  completedAt: Date | null;
43
44
  todos: string | null;
44
45
  unread: boolean | null;
46
+ agentSessionId: string | null;
45
47
  updatedAt: Date | null;
46
48
  };
47
49
  export type TabCountAggregateOutputType = {
@@ -55,6 +57,7 @@ export type TabCountAggregateOutputType = {
55
57
  completedAt: number;
56
58
  todos: number;
57
59
  unread: number;
60
+ agentSessionId: number;
58
61
  updatedAt: number;
59
62
  _all: number;
60
63
  };
@@ -75,6 +78,7 @@ export type TabMinAggregateInputType = {
75
78
  completedAt?: true;
76
79
  todos?: true;
77
80
  unread?: true;
81
+ agentSessionId?: true;
78
82
  updatedAt?: true;
79
83
  };
80
84
  export type TabMaxAggregateInputType = {
@@ -88,6 +92,7 @@ export type TabMaxAggregateInputType = {
88
92
  completedAt?: true;
89
93
  todos?: true;
90
94
  unread?: true;
95
+ agentSessionId?: true;
91
96
  updatedAt?: true;
92
97
  };
93
98
  export type TabCountAggregateInputType = {
@@ -101,6 +106,7 @@ export type TabCountAggregateInputType = {
101
106
  completedAt?: true;
102
107
  todos?: true;
103
108
  unread?: true;
109
+ agentSessionId?: true;
104
110
  updatedAt?: true;
105
111
  _all?: true;
106
112
  };
@@ -191,6 +197,7 @@ export type TabGroupByOutputType = {
191
197
  completedAt: Date | null;
192
198
  todos: string | null;
193
199
  unread: boolean;
200
+ agentSessionId: string | null;
194
201
  updatedAt: Date;
195
202
  _count: TabCountAggregateOutputType | null;
196
203
  _avg: TabAvgAggregateOutputType | null;
@@ -215,6 +222,7 @@ export type TabWhereInput = {
215
222
  completedAt?: Prisma.DateTimeNullableFilter<"Tab"> | Date | string | null;
216
223
  todos?: Prisma.StringNullableFilter<"Tab"> | string | null;
217
224
  unread?: Prisma.BoolFilter<"Tab"> | boolean;
225
+ agentSessionId?: Prisma.StringNullableFilter<"Tab"> | string | null;
218
226
  updatedAt?: Prisma.DateTimeFilter<"Tab"> | Date | string;
219
227
  task?: Prisma.XOR<Prisma.TaskScalarRelationFilter, Prisma.TaskWhereInput>;
220
228
  };
@@ -229,6 +237,7 @@ export type TabOrderByWithRelationInput = {
229
237
  completedAt?: Prisma.SortOrderInput | Prisma.SortOrder;
230
238
  todos?: Prisma.SortOrderInput | Prisma.SortOrder;
231
239
  unread?: Prisma.SortOrder;
240
+ agentSessionId?: Prisma.SortOrderInput | Prisma.SortOrder;
232
241
  updatedAt?: Prisma.SortOrder;
233
242
  task?: Prisma.TaskOrderByWithRelationInput;
234
243
  };
@@ -246,6 +255,7 @@ export type TabWhereUniqueInput = Prisma.AtLeast<{
246
255
  completedAt?: Prisma.DateTimeNullableFilter<"Tab"> | Date | string | null;
247
256
  todos?: Prisma.StringNullableFilter<"Tab"> | string | null;
248
257
  unread?: Prisma.BoolFilter<"Tab"> | boolean;
258
+ agentSessionId?: Prisma.StringNullableFilter<"Tab"> | string | null;
249
259
  updatedAt?: Prisma.DateTimeFilter<"Tab"> | Date | string;
250
260
  task?: Prisma.XOR<Prisma.TaskScalarRelationFilter, Prisma.TaskWhereInput>;
251
261
  }, "tabId">;
@@ -260,6 +270,7 @@ export type TabOrderByWithAggregationInput = {
260
270
  completedAt?: Prisma.SortOrderInput | Prisma.SortOrder;
261
271
  todos?: Prisma.SortOrderInput | Prisma.SortOrder;
262
272
  unread?: Prisma.SortOrder;
273
+ agentSessionId?: Prisma.SortOrderInput | Prisma.SortOrder;
263
274
  updatedAt?: Prisma.SortOrder;
264
275
  _count?: Prisma.TabCountOrderByAggregateInput;
265
276
  _avg?: Prisma.TabAvgOrderByAggregateInput;
@@ -281,6 +292,7 @@ export type TabScalarWhereWithAggregatesInput = {
281
292
  completedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Tab"> | Date | string | null;
282
293
  todos?: Prisma.StringNullableWithAggregatesFilter<"Tab"> | string | null;
283
294
  unread?: Prisma.BoolWithAggregatesFilter<"Tab"> | boolean;
295
+ agentSessionId?: Prisma.StringNullableWithAggregatesFilter<"Tab"> | string | null;
284
296
  updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Tab"> | Date | string;
285
297
  };
286
298
  export type TabCreateInput = {
@@ -293,6 +305,7 @@ export type TabCreateInput = {
293
305
  completedAt?: Date | string | null;
294
306
  todos?: string | null;
295
307
  unread?: boolean;
308
+ agentSessionId?: string | null;
296
309
  updatedAt?: Date | string;
297
310
  task: Prisma.TaskCreateNestedOneWithoutTabsInput;
298
311
  };
@@ -307,6 +320,7 @@ export type TabUncheckedCreateInput = {
307
320
  completedAt?: Date | string | null;
308
321
  todos?: string | null;
309
322
  unread?: boolean;
323
+ agentSessionId?: string | null;
310
324
  updatedAt?: Date | string;
311
325
  };
312
326
  export type TabUpdateInput = {
@@ -319,6 +333,7 @@ export type TabUpdateInput = {
319
333
  completedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null;
320
334
  todos?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
321
335
  unread?: Prisma.BoolFieldUpdateOperationsInput | boolean;
336
+ agentSessionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
322
337
  updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string;
323
338
  task?: Prisma.TaskUpdateOneRequiredWithoutTabsNestedInput;
324
339
  };
@@ -333,6 +348,7 @@ export type TabUncheckedUpdateInput = {
333
348
  completedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null;
334
349
  todos?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
335
350
  unread?: Prisma.BoolFieldUpdateOperationsInput | boolean;
351
+ agentSessionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
336
352
  updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string;
337
353
  };
338
354
  export type TabCreateManyInput = {
@@ -346,6 +362,7 @@ export type TabCreateManyInput = {
346
362
  completedAt?: Date | string | null;
347
363
  todos?: string | null;
348
364
  unread?: boolean;
365
+ agentSessionId?: string | null;
349
366
  updatedAt?: Date | string;
350
367
  };
351
368
  export type TabUpdateManyMutationInput = {
@@ -358,6 +375,7 @@ export type TabUpdateManyMutationInput = {
358
375
  completedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null;
359
376
  todos?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
360
377
  unread?: Prisma.BoolFieldUpdateOperationsInput | boolean;
378
+ agentSessionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
361
379
  updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string;
362
380
  };
363
381
  export type TabUncheckedUpdateManyInput = {
@@ -371,6 +389,7 @@ export type TabUncheckedUpdateManyInput = {
371
389
  completedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null;
372
390
  todos?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
373
391
  unread?: Prisma.BoolFieldUpdateOperationsInput | boolean;
392
+ agentSessionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
374
393
  updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string;
375
394
  };
376
395
  export type TabListRelationFilter = {
@@ -392,6 +411,7 @@ export type TabCountOrderByAggregateInput = {
392
411
  completedAt?: Prisma.SortOrder;
393
412
  todos?: Prisma.SortOrder;
394
413
  unread?: Prisma.SortOrder;
414
+ agentSessionId?: Prisma.SortOrder;
395
415
  updatedAt?: Prisma.SortOrder;
396
416
  };
397
417
  export type TabAvgOrderByAggregateInput = {
@@ -408,6 +428,7 @@ export type TabMaxOrderByAggregateInput = {
408
428
  completedAt?: Prisma.SortOrder;
409
429
  todos?: Prisma.SortOrder;
410
430
  unread?: Prisma.SortOrder;
431
+ agentSessionId?: Prisma.SortOrder;
411
432
  updatedAt?: Prisma.SortOrder;
412
433
  };
413
434
  export type TabMinOrderByAggregateInput = {
@@ -421,6 +442,7 @@ export type TabMinOrderByAggregateInput = {
421
442
  completedAt?: Prisma.SortOrder;
422
443
  todos?: Prisma.SortOrder;
423
444
  unread?: Prisma.SortOrder;
445
+ agentSessionId?: Prisma.SortOrder;
424
446
  updatedAt?: Prisma.SortOrder;
425
447
  };
426
448
  export type TabSumOrderByAggregateInput = {
@@ -477,6 +499,7 @@ export type TabCreateWithoutTaskInput = {
477
499
  completedAt?: Date | string | null;
478
500
  todos?: string | null;
479
501
  unread?: boolean;
502
+ agentSessionId?: string | null;
480
503
  updatedAt?: Date | string;
481
504
  };
482
505
  export type TabUncheckedCreateWithoutTaskInput = {
@@ -489,6 +512,7 @@ export type TabUncheckedCreateWithoutTaskInput = {
489
512
  completedAt?: Date | string | null;
490
513
  todos?: string | null;
491
514
  unread?: boolean;
515
+ agentSessionId?: string | null;
492
516
  updatedAt?: Date | string;
493
517
  };
494
518
  export type TabCreateOrConnectWithoutTaskInput = {
@@ -525,6 +549,7 @@ export type TabScalarWhereInput = {
525
549
  completedAt?: Prisma.DateTimeNullableFilter<"Tab"> | Date | string | null;
526
550
  todos?: Prisma.StringNullableFilter<"Tab"> | string | null;
527
551
  unread?: Prisma.BoolFilter<"Tab"> | boolean;
552
+ agentSessionId?: Prisma.StringNullableFilter<"Tab"> | string | null;
528
553
  updatedAt?: Prisma.DateTimeFilter<"Tab"> | Date | string;
529
554
  };
530
555
  export type TabCreateManyTaskInput = {
@@ -537,6 +562,7 @@ export type TabCreateManyTaskInput = {
537
562
  completedAt?: Date | string | null;
538
563
  todos?: string | null;
539
564
  unread?: boolean;
565
+ agentSessionId?: string | null;
540
566
  updatedAt?: Date | string;
541
567
  };
542
568
  export type TabUpdateWithoutTaskInput = {
@@ -549,6 +575,7 @@ export type TabUpdateWithoutTaskInput = {
549
575
  completedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null;
550
576
  todos?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
551
577
  unread?: Prisma.BoolFieldUpdateOperationsInput | boolean;
578
+ agentSessionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
552
579
  updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string;
553
580
  };
554
581
  export type TabUncheckedUpdateWithoutTaskInput = {
@@ -561,6 +588,7 @@ export type TabUncheckedUpdateWithoutTaskInput = {
561
588
  completedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null;
562
589
  todos?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
563
590
  unread?: Prisma.BoolFieldUpdateOperationsInput | boolean;
591
+ agentSessionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
564
592
  updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string;
565
593
  };
566
594
  export type TabUncheckedUpdateManyWithoutTaskInput = {
@@ -573,6 +601,7 @@ export type TabUncheckedUpdateManyWithoutTaskInput = {
573
601
  completedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null;
574
602
  todos?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
575
603
  unread?: Prisma.BoolFieldUpdateOperationsInput | boolean;
604
+ agentSessionId?: Prisma.NullableStringFieldUpdateOperationsInput | string | null;
576
605
  updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string;
577
606
  };
578
607
  export type TabSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetSelect<{
@@ -586,6 +615,7 @@ export type TabSelect<ExtArgs extends runtime.Types.Extensions.InternalArgs = ru
586
615
  completedAt?: boolean;
587
616
  todos?: boolean;
588
617
  unread?: boolean;
618
+ agentSessionId?: boolean;
589
619
  updatedAt?: boolean;
590
620
  task?: boolean | Prisma.TaskDefaultArgs<ExtArgs>;
591
621
  }, ExtArgs["result"]["tab"]>;
@@ -600,6 +630,7 @@ export type TabSelectCreateManyAndReturn<ExtArgs extends runtime.Types.Extension
600
630
  completedAt?: boolean;
601
631
  todos?: boolean;
602
632
  unread?: boolean;
633
+ agentSessionId?: boolean;
603
634
  updatedAt?: boolean;
604
635
  task?: boolean | Prisma.TaskDefaultArgs<ExtArgs>;
605
636
  }, ExtArgs["result"]["tab"]>;
@@ -614,6 +645,7 @@ export type TabSelectUpdateManyAndReturn<ExtArgs extends runtime.Types.Extension
614
645
  completedAt?: boolean;
615
646
  todos?: boolean;
616
647
  unread?: boolean;
648
+ agentSessionId?: boolean;
617
649
  updatedAt?: boolean;
618
650
  task?: boolean | Prisma.TaskDefaultArgs<ExtArgs>;
619
651
  }, ExtArgs["result"]["tab"]>;
@@ -628,9 +660,10 @@ export type TabSelectScalar = {
628
660
  completedAt?: boolean;
629
661
  todos?: boolean;
630
662
  unread?: boolean;
663
+ agentSessionId?: boolean;
631
664
  updatedAt?: boolean;
632
665
  };
633
- export type TabOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"tabId" | "taskId" | "order" | "status" | "mode" | "createdAt" | "startedAt" | "completedAt" | "todos" | "unread" | "updatedAt", ExtArgs["result"]["tab"]>;
666
+ export type TabOmit<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = runtime.Types.Extensions.GetOmit<"tabId" | "taskId" | "order" | "status" | "mode" | "createdAt" | "startedAt" | "completedAt" | "todos" | "unread" | "agentSessionId" | "updatedAt", ExtArgs["result"]["tab"]>;
634
667
  export type TabInclude<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = {
635
668
  task?: boolean | Prisma.TaskDefaultArgs<ExtArgs>;
636
669
  };
@@ -656,6 +689,7 @@ export type $TabPayload<ExtArgs extends runtime.Types.Extensions.InternalArgs =
656
689
  completedAt: Date | null;
657
690
  todos: string | null;
658
691
  unread: boolean;
692
+ agentSessionId: string | null;
659
693
  updatedAt: Date;
660
694
  }, ExtArgs["result"]["tab"]>;
661
695
  composites: {};
@@ -1022,6 +1056,7 @@ export interface TabFieldRefs {
1022
1056
  readonly completedAt: Prisma.FieldRef<"Tab", 'DateTime'>;
1023
1057
  readonly todos: Prisma.FieldRef<"Tab", 'String'>;
1024
1058
  readonly unread: Prisma.FieldRef<"Tab", 'Boolean'>;
1059
+ readonly agentSessionId: Prisma.FieldRef<"Tab", 'String'>;
1025
1060
  readonly updatedAt: Prisma.FieldRef<"Tab", 'DateTime'>;
1026
1061
  }
1027
1062
  /**
@@ -2,6 +2,6 @@ export type * from './models/Repository.js';
2
2
  export type * from './models/Task.js';
3
3
  export type * from './models/Tab.js';
4
4
  export type * from './models/EnvironmentVariable.js';
5
- export type * from './models/ClaudeProfile.js';
5
+ export type * from './models/AgentProfile.js';
6
6
  export type * from './models/AppSetting.js';
7
7
  export type * from './commonInputTypes.js';
@@ -10,7 +10,7 @@ import { envRoutes } from './routes/env.js';
10
10
  import { worktreesRoutes } from './routes/worktrees.js';
11
11
  import { commandsRoutes } from './routes/commands.js';
12
12
  import { onboardingRoutes } from './routes/onboarding.js';
13
- import { claudeProfilesRoutes } from './routes/claude-profiles.js';
13
+ import { agentProfilesRoutes } from './routes/agent-profiles.js';
14
14
  import { internalRoutes } from './routes/internal.js';
15
15
  import { hooksRoutes } from './routes/hooks.js';
16
16
  import { mcpRoutes } from './routes/mcp.js';
@@ -21,8 +21,6 @@ import { watchUserSettingsForLocalModel } from './lib/claude-config-guard.js';
21
21
  import { LOCAL_MODEL_ALIAS } from './lib/local-llm-env.js';
22
22
  import { terminalRoutes } from './routes/terminal.js';
23
23
  import { editorRoutes } from './routes/editor.js';
24
- import { whisperRoutes } from './routes/whisper.js';
25
- import { stopWhisperServerOnExit } from './lib/whisper-process.js';
26
24
  import { settingsRoutes } from './routes/settings.js';
27
25
  import { versionRoutes } from './routes/version.js';
28
26
  import { startUpdateCheck, stopUpdateCheck } from './lib/update-check.js';
@@ -110,14 +108,13 @@ async function start() {
110
108
  await fastify.register(worktreesRoutes, { prefix: '/api' });
111
109
  await fastify.register(commandsRoutes, { prefix: '/api' });
112
110
  await fastify.register(onboardingRoutes, { prefix: '/api' });
113
- await fastify.register(claudeProfilesRoutes, { prefix: '/api' });
111
+ await fastify.register(agentProfilesRoutes, { prefix: '/api' });
114
112
  await fastify.register(internalRoutes, { prefix: '/api' });
115
113
  await fastify.register(hooksRoutes, { prefix: '/api' });
116
114
  await fastify.register(mcpRoutes, { prefix: '/api' });
117
115
  await fastify.register(mcpWebRoutes, { prefix: '/api' });
118
116
  await fastify.register(terminalRoutes, { prefix: '/api' });
119
117
  await fastify.register(editorRoutes, { prefix: '/api' });
120
- await fastify.register(whisperRoutes, { prefix: '/api' });
121
118
  await fastify.register(settingsRoutes, { prefix: '/api' });
122
119
  await fastify.register(localLlmRoutes, { prefix: '/api' });
123
120
  await fastify.register(versionRoutes, { prefix: '/api' });
@@ -192,7 +189,6 @@ async function start() {
192
189
  stopAutoUpdate();
193
190
  // PTY(claude を含む)は SIGHUP 任せにせず、ここで止める
194
191
  ptyManager.deleteAllSessions();
195
- stopWhisperServerOnExit();
196
192
  stopSearxngOnExit();
197
193
  // 設定で有効なら、ローカルLLMのモデルをメモリから外す(バッテリー・メモリ節約)。
198
194
  // 開発時の tsx watch はファイル変更のたびに SIGTERM で再起動するため、その場合は外さない
@@ -211,7 +207,6 @@ async function start() {
211
207
  });
212
208
  // SIGINT/SIGTERM を経由しない異常終了時の最後の砦('exit' は同期処理のみ可能)。
213
209
  process.on('exit', () => {
214
- stopWhisperServerOnExit();
215
210
  stopSearxngOnExit();
216
211
  });
217
212
  }
@@ -0,0 +1,44 @@
1
+ import type { AgentAuthStatus, AgentProfile } from '@minimalcorp/tsunagi-shared';
2
+ import { type AgentAdapter } from './agents/index.js';
3
+ /**
4
+ * エージェントのプロファイル(Claude: CLAUDE_CONFIG_DIR / Codex: CODEX_HOME)。
5
+ * タブで使うプロファイルの割り当ては予約キー(adapter.profile.envKey)に slug か DEFAULT_PROFILE を保存し、
6
+ * 環境変数と同じ global → owner → repo の継承で解決して PTY 起動時に設定ディレクトリへ変換する
7
+ * (resolveAgentProfileEnv)。
8
+ */
9
+ /** ログイン用 PTY の sessionId の接頭辞(タブの PTY と区別する) */
10
+ export declare const LOGIN_SESSION_PREFIX = "agent-login-";
11
+ /** システム既定(設定ディレクトリの環境変数を付けず ~/.claude / ~/.codex を使う) */
12
+ export declare const DEFAULT_PROFILE = "default";
13
+ /** 汎用の環境変数として登録させないキー(認証はプロファイルで扱う) */
14
+ export declare const RESERVED_ENV_KEYS: string[];
15
+ export declare function getProfilesDir(agent: AgentAdapter): string;
16
+ /** プロファイルの設定ディレクトリ。システム既定は undefined */
17
+ export declare function getProfileConfigDir(agent: AgentAdapter, slug: string): string | undefined;
18
+ /** 空白を `-` にし、小文字にする(macOS のファイルシステムは大文字小文字を区別しないため) */
19
+ export declare function toProfileSlug(name: string): string;
20
+ /** プロファイル名の検証。問題があればエラーメッセージを返す */
21
+ export declare function validateProfileName(name: string): string | null;
22
+ export declare function listProfiles(agent: AgentAdapter): Promise<AgentProfile[]>;
23
+ export declare function profileExists(agent: AgentAdapter, slug: string): Promise<boolean>;
24
+ export declare function createProfile(agent: AgentAdapter, name: string): Promise<AgentProfile>;
25
+ /**
26
+ * プロファイルを削除する。ログイン情報(macOS の Keychain 等)を残さないよう先に logout し、
27
+ * このプロファイルを割り当てていたスコープは割り当てを外して親の設定を継承させる。
28
+ */
29
+ export declare function deleteProfile(agent: AgentAdapter, slug: string): Promise<void>;
30
+ /** CLI が未導入なら CLI を呼ばずに未ログインとする */
31
+ export declare function getProfileAuthStatus(agent: AgentAdapter, slug: string): Promise<AgentAuthStatus>;
32
+ /** ログイン用 PTY の環境変数(PtyManager.createSession の env / unsetKeys) */
33
+ export declare function loginPtyEnv(agent: AgentAdapter, slug: string): {
34
+ env: Record<string, string>;
35
+ unsetKeys: string[];
36
+ };
37
+ /**
38
+ * 継承解決済みの環境変数に含まれる各エージェントのプロファイル割り当てを設定ディレクトリに変換する。
39
+ * 予約キー自体は PTY に渡さない。
40
+ */
41
+ export declare function resolveAgentProfileEnv(env: Record<string, string>): {
42
+ env: Record<string, string>;
43
+ unsetKeys: string[];
44
+ };
@@ -0,0 +1,130 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import { prisma } from './db.js';
4
+ import { getTsunagiDataDir } from './data-path.js';
5
+ import { AGENTS, getAgentAvailability } from './agents/index.js';
6
+ /**
7
+ * エージェントのプロファイル(Claude: CLAUDE_CONFIG_DIR / Codex: CODEX_HOME)。
8
+ * タブで使うプロファイルの割り当ては予約キー(adapter.profile.envKey)に slug か DEFAULT_PROFILE を保存し、
9
+ * 環境変数と同じ global → owner → repo の継承で解決して PTY 起動時に設定ディレクトリへ変換する
10
+ * (resolveAgentProfileEnv)。
11
+ */
12
+ /** ログイン用 PTY の sessionId の接頭辞(タブの PTY と区別する) */
13
+ export const LOGIN_SESSION_PREFIX = 'agent-login-';
14
+ /** システム既定(設定ディレクトリの環境変数を付けず ~/.claude / ~/.codex を使う) */
15
+ export const DEFAULT_PROFILE = 'default';
16
+ /** 汎用の環境変数として登録させないキー(認証はプロファイルで扱う) */
17
+ export const RESERVED_ENV_KEYS = AGENTS.flatMap(({ profile }) => [
18
+ profile.envKey,
19
+ profile.configDirEnvKey,
20
+ ...profile.authEnvKeys,
21
+ ]);
22
+ const PROFILE_NAME_PATTERN = /^[A-Za-z0-9 _-]+$/;
23
+ export function getProfilesDir(agent) {
24
+ return path.join(getTsunagiDataDir(), `${agent.id}-profiles`);
25
+ }
26
+ /** プロファイルの設定ディレクトリ。システム既定は undefined */
27
+ export function getProfileConfigDir(agent, slug) {
28
+ if (slug === DEFAULT_PROFILE)
29
+ return undefined;
30
+ return path.join(getProfilesDir(agent), slug);
31
+ }
32
+ /** 空白を `-` にし、小文字にする(macOS のファイルシステムは大文字小文字を区別しないため) */
33
+ export function toProfileSlug(name) {
34
+ return name.trim().replace(/\s+/g, '-').toLowerCase();
35
+ }
36
+ /** プロファイル名の検証。問題があればエラーメッセージを返す */
37
+ export function validateProfileName(name) {
38
+ const trimmed = name.trim();
39
+ if (!trimmed)
40
+ return 'Name is required';
41
+ if (!PROFILE_NAME_PATTERN.test(trimmed)) {
42
+ return 'Use only letters, numbers, spaces, "-" and "_"';
43
+ }
44
+ if (toProfileSlug(trimmed) === DEFAULT_PROFILE) {
45
+ return `"${DEFAULT_PROFILE}" is reserved`;
46
+ }
47
+ return null;
48
+ }
49
+ export async function listProfiles(agent) {
50
+ const rows = await prisma.agentProfile.findMany({
51
+ where: { agent: agent.id },
52
+ orderBy: { createdAt: 'asc' },
53
+ });
54
+ return rows.map((row) => ({
55
+ agent: agent.id,
56
+ slug: row.slug,
57
+ name: row.name,
58
+ configDir: path.join(getProfilesDir(agent), row.slug),
59
+ }));
60
+ }
61
+ export async function profileExists(agent, slug) {
62
+ if (slug === DEFAULT_PROFILE)
63
+ return true;
64
+ return (await prisma.agentProfile.count({ where: { agent: agent.id, slug } })) > 0;
65
+ }
66
+ export async function createProfile(agent, name) {
67
+ const error = validateProfileName(name);
68
+ if (error)
69
+ throw new Error(error);
70
+ const trimmed = name.trim();
71
+ const slug = toProfileSlug(trimmed);
72
+ if (await profileExists(agent, slug)) {
73
+ throw new Error(`Profile "${slug}" already exists`);
74
+ }
75
+ const configDir = path.join(getProfilesDir(agent), slug);
76
+ await fs.mkdir(configDir, { recursive: true });
77
+ await prisma.agentProfile.create({ data: { agent: agent.id, slug, name: trimmed } });
78
+ return { agent: agent.id, slug, name: trimmed, configDir };
79
+ }
80
+ /**
81
+ * プロファイルを削除する。ログイン情報(macOS の Keychain 等)を残さないよう先に logout し、
82
+ * このプロファイルを割り当てていたスコープは割り当てを外して親の設定を継承させる。
83
+ */
84
+ export async function deleteProfile(agent, slug) {
85
+ const configDir = getProfileConfigDir(agent, slug);
86
+ if (!configDir)
87
+ throw new Error('The system default profile cannot be deleted');
88
+ await agent.profile.logout(configDir).catch(() => undefined);
89
+ await prisma.environmentVariable.deleteMany({
90
+ where: { key: agent.profile.envKey, value: slug },
91
+ });
92
+ await prisma.agentProfile.delete({ where: { agent_slug: { agent: agent.id, slug } } });
93
+ await fs.rm(configDir, { recursive: true, force: true });
94
+ }
95
+ /** CLI が未導入なら CLI を呼ばずに未ログインとする */
96
+ export async function getProfileAuthStatus(agent, slug) {
97
+ if (!(await getAgentAvailability(agent)).installed)
98
+ return { loggedIn: false };
99
+ return agent.profile.getAuthStatus(getProfileConfigDir(agent, slug));
100
+ }
101
+ /** ログイン用 PTY の環境変数(PtyManager.createSession の env / unsetKeys) */
102
+ export function loginPtyEnv(agent, slug) {
103
+ const configDir = getProfileConfigDir(agent, slug);
104
+ if (!configDir)
105
+ return { env: {}, unsetKeys: [] };
106
+ return {
107
+ env: { [agent.profile.configDirEnvKey]: configDir },
108
+ unsetKeys: agent.profile.authEnvKeys,
109
+ };
110
+ }
111
+ /**
112
+ * 継承解決済みの環境変数に含まれる各エージェントのプロファイル割り当てを設定ディレクトリに変換する。
113
+ * 予約キー自体は PTY に渡さない。
114
+ */
115
+ export function resolveAgentProfileEnv(env) {
116
+ const rest = { ...env };
117
+ const unsetKeys = [];
118
+ for (const agent of AGENTS) {
119
+ const { envKey, configDirEnvKey, authEnvKeys } = agent.profile;
120
+ const slug = rest[envKey];
121
+ delete rest[envKey];
122
+ const configDir = slug ? getProfileConfigDir(agent, slug) : undefined;
123
+ // システム既定: 外側 Terminal の環境のまま(普段ターミナルで CLI を使うときと同じ)
124
+ if (!configDir)
125
+ continue;
126
+ rest[configDirEnvKey] = configDir;
127
+ unsetKeys.push(...authEnvKeys);
128
+ }
129
+ return { env: rest, unsetKeys };
130
+ }
@@ -0,0 +1,2 @@
1
+ import { type AgentAdapter } from './types.js';
2
+ export declare const claudeAdapter: AgentAdapter;
@@ -0,0 +1,130 @@
1
+ import { LOCAL_LLM_PROXY_URL, buildClaudeCommand, isLocalLlmMode } from '../claude-command.js';
2
+ import { ensureClaudeOnboardingCompleted, removeLocalModelFromUserSettings, watchUserSettingsForLocalModel, } from '../claude-config-guard.js';
3
+ import { LOCAL_LLM_UNSET_ENV_KEYS, LOCAL_MODEL_ALIAS, buildLocalLlmEnv } from '../local-llm-env.js';
4
+ import { ensureActiveLoaded, getLocalLlmSettings } from '../local-llm.js';
5
+ import { TODO_TOOL_NAMES, applyToolToTodos } from '../tab-todos.js';
6
+ import { agentCliEnv, runAgentCli } from './cli.js';
7
+ import { AgentLaunchError, } from './types.js';
8
+ const SIMPLE_EVENTS = {
9
+ // claudeが起動しただけ(まだプロンプト処理していない)
10
+ SessionStart: 'session-start',
11
+ UserPromptSubmit: 'prompt',
12
+ // ツール実行許可待ち
13
+ PermissionRequest: 'permission',
14
+ Stop: 'stop',
15
+ // APIエラーでターン終了
16
+ StopFailure: 'stop-failure',
17
+ // Escキー中断・Ctrl+C・/exit等
18
+ SessionEnd: 'session-end',
19
+ };
20
+ const claudeProfile = {
21
+ envKey: 'TSUNAGI_CLAUDE_PROFILE',
22
+ configDirEnvKey: 'CLAUDE_CONFIG_DIR',
23
+ // Claude Code が /login のログインより優先する認証情報
24
+ authEnvKeys: ['ANTHROPIC_API_KEY', 'CLAUDE_CODE_OAUTH_TOKEN'],
25
+ defaultConfigDir: '~/.claude',
26
+ loginCommand: 'claude auth login',
27
+ // `claude auth status --json` でログイン状態を取得する
28
+ async getAuthStatus(configDir) {
29
+ const env = agentCliEnv(claudeProfile, configDir);
30
+ try {
31
+ const { stdout } = await runAgentCli('claude', ['auth', 'status', '--json'], env);
32
+ const raw = JSON.parse(stdout);
33
+ const str = (v) => (typeof v === 'string' ? v : undefined);
34
+ return {
35
+ loggedIn: raw.loggedIn === true,
36
+ authMethod: str(raw.authMethod),
37
+ email: str(raw.email),
38
+ orgName: str(raw.orgName),
39
+ subscriptionType: str(raw.subscriptionType),
40
+ };
41
+ }
42
+ catch (err) {
43
+ // claude auth status は未ログイン時に非 0 で終了するが、stdout には JSON が出る
44
+ const stdout = err.stdout;
45
+ if (stdout) {
46
+ try {
47
+ const raw = JSON.parse(stdout);
48
+ return { loggedIn: raw.loggedIn === true, authMethod: raw.authMethod };
49
+ }
50
+ catch {
51
+ // fallthrough
52
+ }
53
+ }
54
+ return { loggedIn: false, error: err instanceof Error ? err.message : String(err) };
55
+ }
56
+ },
57
+ // ログイン情報(macOS は Keychain)を残さないよう、プロファイル削除前に logout する
58
+ async logout(configDir) {
59
+ await runAgentCli('claude', ['auth', 'logout'], agentCliEnv(claudeProfile, configDir));
60
+ },
61
+ };
62
+ export const claudeAdapter = {
63
+ id: 'claude',
64
+ label: 'Claude Code',
65
+ cli: 'claude',
66
+ // CLAUDE_CODE_PLUGIN_DIRS に対応した最初のバージョン(apps/cli の起動チェックと同じ)
67
+ minVersion: [2, 1, 280],
68
+ profile: claudeProfile,
69
+ // ローカルLLMタブ: Anthropic の代わりに tsunagi の中継口(→ Ollama / LM Studio)で claude を動かす。
70
+ // Anthropic の認証トークンは環境変数ごと取り除く
71
+ async resolveLaunchEnv(mode) {
72
+ if (!isLocalLlmMode(mode))
73
+ return { env: {}, unsetKeys: [] };
74
+ const { active, extraEnv } = await getLocalLlmSettings();
75
+ if (!active) {
76
+ throw new AgentLaunchError('ローカルLLMのモデルが未設定です。Settings で使用するモデルを選んでください', 400);
77
+ }
78
+ return {
79
+ env: buildLocalLlmEnv({
80
+ proxyUrl: LOCAL_LLM_PROXY_URL,
81
+ contextTokens: active.contextTokens,
82
+ extraEnv,
83
+ }),
84
+ unsetKeys: LOCAL_LLM_UNSET_ENV_KEYS,
85
+ };
86
+ },
87
+ /**
88
+ * claude logout で .claude.json の hasCompletedOnboarding がリセットされていると、次回 claude 起動時に
89
+ * オンボーディングウィザードが表示され --resume/--session-id を前提にした自動起動フローが止まるため補正する。
90
+ * 監視の取りこぼしに備え、中継口の名前が既定モデルに残っていないかも補正する。
91
+ * 対象はタブが使う Claude プロファイルの設定ディレクトリ
92
+ */
93
+ async prepareLaunch(env) {
94
+ // PTY は外側 Terminal の環境を継承するため、プロファイル未指定なら外側の CLAUDE_CONFIG_DIR に従う
95
+ const configDir = env.CLAUDE_CONFIG_DIR ?? process.env.CLAUDE_CONFIG_DIR;
96
+ await ensureClaudeOnboardingCompleted(configDir);
97
+ await removeLocalModelFromUserSettings(LOCAL_MODEL_ALIAS, configDir);
98
+ watchUserSettingsForLocalModel(LOCAL_MODEL_ALIAS, configDir);
99
+ },
100
+ async buildCommand(tabId, mode) {
101
+ if (isLocalLlmMode(mode)) {
102
+ // 最初の発言を待たせないよう読み込みを始めておく(完了は待たない。未設定等のエラーは中継口がタブに返す)
103
+ ensureActiveLoaded().catch(() => undefined);
104
+ }
105
+ return buildClaudeCommand(tabId, mode);
106
+ },
107
+ // Claude のセッションIDはタブIDと同じ(--session-id / --resume で揃えている)
108
+ normalizeHook({ body }) {
109
+ const { hook_event_name: eventName, session_id: tabId } = body;
110
+ if (!tabId || !eventName)
111
+ return null;
112
+ const kind = SIMPLE_EVENTS[eventName];
113
+ if (kind)
114
+ return { tabId, kind };
115
+ if (eventName === 'PostToolUse') {
116
+ // ツール実行完了(PermissionRequest後のAllow含む)。TodoWrite / Task 系ツールなら todos も更新する
117
+ const { tool_name: toolName, tool_input: input, tool_response: response, } = body;
118
+ return {
119
+ tabId,
120
+ kind: 'tool-post',
121
+ toolName,
122
+ ...(toolName !== undefined &&
123
+ TODO_TOOL_NAMES.has(toolName) && {
124
+ applyTodos: (current) => applyToolToTodos(current, toolName, input, response),
125
+ }),
126
+ };
127
+ }
128
+ return null;
129
+ },
130
+ };
@@ -0,0 +1,14 @@
1
+ import type { AgentAvailability } from '@minimalcorp/tsunagi-shared';
2
+ import type { AgentAdapter, AgentProfileSpec } from './types.js';
3
+ /**
4
+ * エージェント CLI を実行するときの環境変数。プロファイルのログインを見るよう設定ディレクトリを付け、
5
+ * ログインより優先される認証情報の環境変数は取り除く。システム既定は外側 Terminal の環境のまま
6
+ * (普段ターミナルで CLI を使うときと同じ)。
7
+ */
8
+ export declare function agentCliEnv(profile: AgentProfileSpec, configDir: string | undefined): NodeJS.ProcessEnv;
9
+ export declare function runAgentCli(cli: string, args: string[], env: NodeJS.ProcessEnv): Promise<{
10
+ stdout: string;
11
+ stderr: string;
12
+ }>;
13
+ /** `<cli> --version` で導入状況を確認する */
14
+ export declare function getAgentAvailability(adapter: AgentAdapter): Promise<AgentAvailability>;