@cookielab.io/klovi 3.0.0 → 3.2.0

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.
package/dist/server.js CHANGED
@@ -57,6 +57,110 @@ var init_plugin_errors = __esm(() => {
57
57
  };
58
58
  });
59
59
 
60
+ // ../../packages/plugin-core/src/resolve-worktree.ts
61
+ import { join } from "node:path";
62
+ import { FileSystem } from "@effect/platform";
63
+ import { Effect } from "effect";
64
+ function stripT3CodeSuffix(path) {
65
+ if (!T3CODE_SUFFIX_REGEX.test(path))
66
+ return null;
67
+ const parentPath = path.replace(T3CODE_SUFFIX_REGEX, "");
68
+ const lastSlash = parentPath.lastIndexOf("/");
69
+ const projectName = lastSlash === -1 ? parentPath : parentPath.slice(lastSlash + 1);
70
+ return { path: parentPath, projectName };
71
+ }
72
+ function resolveGitWorktree(worktreePath) {
73
+ return Effect.gen(function* () {
74
+ const fs = yield* FileSystem.FileSystem;
75
+ const dotGitPath = join(worktreePath, ".git");
76
+ const info = yield* fs.stat(dotGitPath).pipe(Effect.catchAll(() => Effect.succeed(null)));
77
+ if (!info || info.type !== "File")
78
+ return worktreePath;
79
+ const content = yield* fs.readFileString(dotGitPath).pipe(Effect.catchAll(() => Effect.succeed("")));
80
+ if (!content)
81
+ return worktreePath;
82
+ const match = GITDIR_WORKTREE_REGEX.exec(content);
83
+ if (!match?.[1])
84
+ return worktreePath;
85
+ const gitdir = match[1];
86
+ const worktreeIdx = gitdir.indexOf(GIT_WORKTREES_SEGMENT);
87
+ if (worktreeIdx === -1)
88
+ return worktreePath;
89
+ return gitdir.slice(0, worktreeIdx);
90
+ });
91
+ }
92
+ function lastSegment(path) {
93
+ const lastSlash = path.lastIndexOf("/");
94
+ return lastSlash === -1 ? path : path.slice(lastSlash + 1);
95
+ }
96
+ function collectT3CodeEntries(projects) {
97
+ const entries = [];
98
+ for (const project of projects) {
99
+ const stripped = stripT3CodeSuffix(project.resolvedPath);
100
+ if (stripped) {
101
+ entries.push({
102
+ project,
103
+ originalPath: project.resolvedPath,
104
+ projectName: stripped.projectName
105
+ });
106
+ project.resolvedPath = stripped.path;
107
+ }
108
+ }
109
+ return entries;
110
+ }
111
+ function buildNameMap(projects, t3codeProjects) {
112
+ const nameToResolvedPaths = new Map;
113
+ for (const project of projects) {
114
+ if (t3codeProjects.has(project))
115
+ continue;
116
+ const name = lastSegment(project.resolvedPath);
117
+ if (!name)
118
+ continue;
119
+ const existing = nameToResolvedPaths.get(name);
120
+ if (existing) {
121
+ if (!existing.includes(project.resolvedPath))
122
+ existing.push(project.resolvedPath);
123
+ } else {
124
+ nameToResolvedPaths.set(name, [project.resolvedPath]);
125
+ }
126
+ }
127
+ return nameToResolvedPaths;
128
+ }
129
+ function resolveEntry(entry, nameMap) {
130
+ return Effect.gen(function* () {
131
+ const candidates = nameMap.get(entry.projectName);
132
+ if (!candidates || candidates.length === 0)
133
+ return;
134
+ if (candidates.length === 1) {
135
+ const resolvedPath = candidates[0];
136
+ if (resolvedPath)
137
+ entry.project.resolvedPath = resolvedPath;
138
+ return;
139
+ }
140
+ const resolved = yield* resolveGitWorktree(entry.originalPath);
141
+ if (candidates.includes(resolved)) {
142
+ entry.project.resolvedPath = resolved;
143
+ }
144
+ });
145
+ }
146
+ function resolveT3CodePaths(projects) {
147
+ return Effect.gen(function* () {
148
+ const t3codeEntries = collectT3CodeEntries(projects);
149
+ if (t3codeEntries.length === 0)
150
+ return;
151
+ const t3codeProjects = new Set(t3codeEntries.map((e) => e.project));
152
+ const nameMap = buildNameMap(projects, t3codeProjects);
153
+ for (const entry of t3codeEntries) {
154
+ yield* resolveEntry(entry, nameMap);
155
+ }
156
+ });
157
+ }
158
+ var T3CODE_SUFFIX_REGEX, GITDIR_WORKTREE_REGEX, GIT_WORKTREES_SEGMENT = "/.git/worktrees/";
159
+ var init_resolve_worktree = __esm(() => {
160
+ T3CODE_SUFFIX_REGEX = /\/t3code-[a-f0-9]+$/;
161
+ GITDIR_WORKTREE_REGEX = /^gitdir:\s*(.+?)\s*$/;
162
+ });
163
+
60
164
  // ../../packages/plugin-core/src/session-id.ts
61
165
  function encodeSessionId(pluginId, rawSessionId) {
62
166
  return `${pluginId}${SESSION_ID_SEPARATOR}${rawSessionId}`;
@@ -74,7 +178,7 @@ function parseSessionId(sessionId) {
74
178
  var SESSION_ID_SEPARATOR = "::";
75
179
 
76
180
  // ../../packages/plugin-core/src/plugin-registry.ts
77
- import { Effect, Layer } from "effect";
181
+ import { Effect as Effect2, Layer } from "effect";
78
182
  function encodeResolvedPath(resolvedPath) {
79
183
  if (resolvedPath.startsWith("/")) {
80
184
  return resolvedPath.replace(/\//g, "-");
@@ -111,12 +215,13 @@ class PluginRegistry {
111
215
  return [...this.plugins.values()].map((entry) => entry.plugin);
112
216
  }
113
217
  discoverAllProjects() {
114
- return Effect.gen(this, function* () {
218
+ return Effect2.gen(this, function* () {
115
219
  const allProjects = [];
116
220
  for (const { plugin, configLayer } of this.plugins.values()) {
117
- const projects = yield* plugin.discoverProjects.pipe(Effect.provide(configLayer), Effect.catchAll(() => Effect.succeed([])));
221
+ const projects = yield* plugin.discoverProjects.pipe(Effect2.provide(configLayer), Effect2.catchAll(() => Effect2.succeed([])));
118
222
  allProjects.push(...projects);
119
223
  }
224
+ yield* resolveT3CodePaths(allProjects);
120
225
  const projectsByPath = new Map;
121
226
  for (const project of allProjects) {
122
227
  const current = projectsByPath.get(project.resolvedPath);
@@ -146,13 +251,13 @@ class PluginRegistry {
146
251
  });
147
252
  }
148
253
  listAllSessions(project) {
149
- return Effect.gen(this, function* () {
254
+ return Effect2.gen(this, function* () {
150
255
  const allSessions = [];
151
256
  for (const source of project.sources) {
152
257
  const entry = this.plugins.get(source.pluginId);
153
258
  if (!entry)
154
259
  continue;
155
- const sessions = yield* entry.plugin.listSessions(source.nativeId).pipe(Effect.provide(entry.configLayer), Effect.catchAll(() => Effect.succeed([])));
260
+ const sessions = yield* entry.plugin.listSessions(source.nativeId).pipe(Effect2.provide(entry.configLayer), Effect2.catchAll(() => Effect2.succeed([])));
156
261
  allSessions.push(...sessions.map((session) => ({
157
262
  ...session,
158
263
  sessionId: this.sessionIdEncoder(source.pluginId, session.sessionId),
@@ -166,6 +271,7 @@ class PluginRegistry {
166
271
  }
167
272
  var init_plugin_registry = __esm(() => {
168
273
  init_plugin_config();
274
+ init_resolve_worktree();
169
275
  });
170
276
 
171
277
  // ../../packages/plugin-core/src/plugin-runtime.ts
@@ -196,19 +302,19 @@ var init_src = __esm(() => {
196
302
  });
197
303
 
198
304
  // ../../packages/plugin-opencode/src/db.ts
199
- import { join } from "node:path";
200
- import { FileSystem } from "@effect/platform";
201
- import { Effect as Effect2 } from "effect";
305
+ import { join as join2 } from "node:path";
306
+ import { FileSystem as FileSystem2 } from "@effect/platform";
307
+ import { Effect as Effect3 } from "effect";
202
308
  function getOpenCodeDbPath() {
203
- return Effect2.gen(function* () {
309
+ return Effect3.gen(function* () {
204
310
  const config = yield* PluginConfig;
205
- return join(config.dataDir, "opencode.db");
311
+ return join2(config.dataDir, "opencode.db");
206
312
  });
207
313
  }
208
314
  function openOpenCodeDb() {
209
- return Effect2.gen(function* () {
315
+ return Effect3.gen(function* () {
210
316
  const dbPath = yield* getOpenCodeDbPath();
211
- const fs = yield* FileSystem.FileSystem;
317
+ const fs = yield* FileSystem2.FileSystem;
212
318
  const exists = yield* fs.exists(dbPath);
213
319
  if (!exists)
214
320
  return null;
@@ -230,7 +336,7 @@ function tryParseJson(value) {
230
336
  }
231
337
 
232
338
  // ../../packages/plugin-opencode/src/discovery.ts
233
- import { Effect as Effect3 } from "effect";
339
+ import { Effect as Effect4 } from "effect";
234
340
  function getColumns(db, tableName) {
235
341
  const rows = db.query(`PRAGMA table_info(${tableName})`).all();
236
342
  return new Set(rows.map((r) => r.name));
@@ -251,7 +357,7 @@ function inspectSchema(db) {
251
357
  };
252
358
  }
253
359
  function discoverOpenCodeProjects() {
254
- return Effect3.gen(function* () {
360
+ return Effect4.gen(function* () {
255
361
  const db = yield* openOpenCodeDb();
256
362
  if (!db)
257
363
  return [];
@@ -339,7 +445,7 @@ function sessionRowToSummary(db, row) {
339
445
  };
340
446
  }
341
447
  function listOpenCodeSessions(nativeId) {
342
- return Effect3.gen(function* () {
448
+ return Effect4.gen(function* () {
343
449
  const db = yield* openOpenCodeDb();
344
450
  if (!db)
345
451
  return [];
@@ -399,7 +505,7 @@ var init_discovery = __esm(() => {
399
505
  });
400
506
 
401
507
  // ../../packages/plugin-opencode/src/parser.ts
402
- import { Effect as Effect4 } from "effect";
508
+ import { Effect as Effect5 } from "effect";
403
509
  function partToContentBlock(partData, nextToolUseId) {
404
510
  switch (partData.type) {
405
511
  case "text": {
@@ -594,7 +700,7 @@ function loadSessionFromDb(db, nativeId, sessionId) {
594
700
  return { sessionId, project, turns, pluginId: "opencode" };
595
701
  }
596
702
  function loadOpenCodeSession(nativeId, sessionId) {
597
- return Effect4.gen(function* () {
703
+ return Effect5.gen(function* () {
598
704
  const db = yield* openOpenCodeDb();
599
705
  if (!db) {
600
706
  return emptySession(nativeId, sessionId);
@@ -622,19 +728,19 @@ var init_parser = __esm(() => {
622
728
  });
623
729
 
624
730
  // ../../packages/plugin-opencode/src/config.ts
625
- import { join as join2 } from "node:path";
731
+ import { join as join3 } from "node:path";
626
732
  var DEFAULT_OPENCODE_DIR;
627
733
  var init_config = __esm(() => {
628
- DEFAULT_OPENCODE_DIR = join2(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".local", "share", "opencode");
734
+ DEFAULT_OPENCODE_DIR = join3(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".local", "share", "opencode");
629
735
  });
630
736
 
631
737
  // ../../packages/plugin-opencode/src/runtime/bun-sqlite.ts
632
- import { Effect as Effect5, Layer as Layer3 } from "effect";
738
+ import { Effect as Effect6, Layer as Layer3 } from "effect";
633
739
  var bunSqliteClient, BunSqliteLayer;
634
740
  var init_bun_sqlite = __esm(() => {
635
741
  init_src();
636
742
  bunSqliteClient = {
637
- open: (dbPath, options) => Effect5.try({
743
+ open: (dbPath, options) => Effect6.try({
638
744
  try: () => {
639
745
  const sqlite = __require("bun:sqlite");
640
746
  return new sqlite.Database(dbPath, {
@@ -642,18 +748,18 @@ var init_bun_sqlite = __esm(() => {
642
748
  });
643
749
  },
644
750
  catch: () => null
645
- }).pipe(Effect5.catchAll(() => Effect5.succeed(null)))
751
+ }).pipe(Effect6.catchAll(() => Effect6.succeed(null)))
646
752
  };
647
753
  BunSqliteLayer = Layer3.succeed(SqliteClientTag, bunSqliteClient);
648
754
  });
649
755
 
650
756
  // ../../packages/plugin-opencode/src/runtime/node-sqlite.ts
651
- import { Effect as Effect6, Layer as Layer4 } from "effect";
757
+ import { Effect as Effect7, Layer as Layer4 } from "effect";
652
758
  var nodeSqliteClient, NodeSqliteLayer;
653
759
  var init_node_sqlite = __esm(() => {
654
760
  init_src();
655
761
  nodeSqliteClient = {
656
- open: (dbPath, options) => Effect6.tryPromise({
762
+ open: (dbPath, options) => Effect7.tryPromise({
657
763
  try: async () => {
658
764
  const sqlite = await import("node:sqlite");
659
765
  const db = new sqlite.DatabaseSync(dbPath, {
@@ -678,15 +784,15 @@ var init_node_sqlite = __esm(() => {
678
784
  };
679
785
  },
680
786
  catch: () => null
681
- }).pipe(Effect6.catchAll(() => Effect6.succeed(null)))
787
+ }).pipe(Effect7.catchAll(() => Effect7.succeed(null)))
682
788
  };
683
789
  NodeSqliteLayer = Layer4.succeed(SqliteClientTag, nodeSqliteClient);
684
790
  });
685
791
 
686
792
  // ../../packages/plugin-opencode/src/index.ts
687
- import { join as join3 } from "node:path";
688
- import { FileSystem as FileSystem2 } from "@effect/platform";
689
- import { Effect as Effect7 } from "effect";
793
+ import { join as join4 } from "node:path";
794
+ import { FileSystem as FileSystem3 } from "@effect/platform";
795
+ import { Effect as Effect8 } from "effect";
690
796
  var openCodePlugin;
691
797
  var init_src2 = __esm(() => {
692
798
  init_src();
@@ -699,24 +805,24 @@ var init_src2 = __esm(() => {
699
805
  id: "opencode",
700
806
  displayName: "OpenCode",
701
807
  getDefaultDataDir: () => null,
702
- isDataAvailable: Effect7.gen(function* () {
808
+ isDataAvailable: Effect8.gen(function* () {
703
809
  const config = yield* PluginConfig;
704
- const fs = yield* FileSystem2.FileSystem;
705
- return yield* fs.exists(join3(config.dataDir, "opencode.db")).pipe(Effect7.catchAll(() => Effect7.succeed(false)));
810
+ const fs = yield* FileSystem3.FileSystem;
811
+ return yield* fs.exists(join4(config.dataDir, "opencode.db")).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
706
812
  }),
707
- discoverProjects: discoverOpenCodeProjects().pipe(Effect7.catchAll((err) => Effect7.fail(new PluginError({
813
+ discoverProjects: discoverOpenCodeProjects().pipe(Effect8.catchAll((err) => Effect8.fail(new PluginError({
708
814
  pluginId: "opencode",
709
815
  operation: "discoverProjects",
710
816
  message: String(err),
711
817
  cause: err
712
818
  })))),
713
- listSessions: (nativeId) => listOpenCodeSessions(nativeId).pipe(Effect7.catchAll((err) => Effect7.fail(new PluginError({
819
+ listSessions: (nativeId) => listOpenCodeSessions(nativeId).pipe(Effect8.catchAll((err) => Effect8.fail(new PluginError({
714
820
  pluginId: "opencode",
715
821
  operation: "listSessions",
716
822
  message: String(err),
717
823
  cause: err
718
824
  })))),
719
- loadSession: (nativeId, sessionId) => loadOpenCodeSession(nativeId, sessionId).pipe(Effect7.catchAll((err) => Effect7.fail(new PluginError({
825
+ loadSession: (nativeId, sessionId) => loadOpenCodeSession(nativeId, sessionId).pipe(Effect8.catchAll((err) => Effect8.fail(new PluginError({
720
826
  pluginId: "opencode",
721
827
  operation: "loadSession",
722
828
  message: String(err),
@@ -744,9 +850,9 @@ var init_platform_node = __esm(() => {
744
850
  import { execFile } from "node:child_process";
745
851
 
746
852
  // ../../packages/server/src/effect/bootstrap.ts
747
- import { join as join11 } from "node:path";
853
+ import { join as join12 } from "node:path";
748
854
  import { HttpServer } from "@effect/platform";
749
- import { Cause, Effect as Effect19, Fiber, Layer as Layer8 } from "effect";
855
+ import { Cause, Effect as Effect20, Fiber, Layer as Layer8 } from "effect";
750
856
 
751
857
  // ../../packages/server/src/effect/platform-bun.ts
752
858
  init_src2();
@@ -758,7 +864,7 @@ var makeBunServerLayer = (options) => Layer5.merge(BunHttpServer.layer(options),
758
864
  // ../../packages/server/src/effect/plugin-runtime.ts
759
865
  init_src();
760
866
  import {
761
- Effect as Effect8,
867
+ Effect as Effect9,
762
868
  ManagedRuntime
763
869
  } from "effect";
764
870
  var pluginRuntime = ManagedRuntime.make(BunPluginLayer);
@@ -766,7 +872,7 @@ function setPluginLayer(layer) {
766
872
  pluginRuntime = ManagedRuntime.make(layer);
767
873
  }
768
874
  function runPluginEffect(effect, config) {
769
- const provided = effect.pipe(Effect8.provide(makePluginConfigLayer(config)));
875
+ const provided = effect.pipe(Effect9.provide(makePluginConfigLayer(config)));
770
876
  return pluginRuntime.runPromise(provided);
771
877
  }
772
878
  function runRegistryEffect(effect) {
@@ -780,7 +886,7 @@ class ServerConfig extends Context3.Tag("@klovi/ServerConfig")() {
780
886
  }
781
887
 
782
888
  // ../../packages/server/src/effect/server-services.ts
783
- import { Context as Context4, Effect as Effect18, Layer as Layer6 } from "effect";
889
+ import { Context as Context4, Effect as Effect19, Layer as Layer6 } from "effect";
784
890
 
785
891
  // ../../packages/server/src/services/app-services.ts
786
892
  init_src();
@@ -788,12 +894,12 @@ import { access, rm } from "node:fs/promises";
788
894
 
789
895
  // ../../packages/plugin-claude-code/src/index.ts
790
896
  init_src();
791
- import { Effect as Effect12 } from "effect";
897
+ import { Effect as Effect13 } from "effect";
792
898
 
793
899
  // ../../packages/plugin-claude-code/src/discovery.ts
794
900
  init_src();
795
- import { join as join5 } from "node:path";
796
- import { Effect as Effect10 } from "effect";
901
+ import { join as join6 } from "node:path";
902
+ import { Effect as Effect11 } from "effect";
797
903
 
798
904
  // ../../packages/plugin-claude-code/src/command-message.ts
799
905
  var COMMAND_ARGS_REGEX = /<command-args>([\s\S]*?)<\/command-args>/;
@@ -825,17 +931,17 @@ function parseCommandMessage(text) {
825
931
 
826
932
  // ../../packages/plugin-claude-code/src/shared/discovery-utils.ts
827
933
  init_src();
828
- import { join as join4 } from "node:path";
829
- import { FileSystem as FileSystem3 } from "@effect/platform";
830
- import { Effect as Effect9 } from "effect";
934
+ import { join as join5 } from "node:path";
935
+ import { FileSystem as FileSystem4 } from "@effect/platform";
936
+ import { Effect as Effect10 } from "effect";
831
937
  var WINDOWS_DRIVE_LETTER_REGEX = /^[A-Za-z]\//;
832
938
  function readDirEntriesSafe(dir) {
833
- return Effect9.gen(function* () {
834
- const fs = yield* FileSystem3.FileSystem;
835
- const names = yield* fs.readDirectory(dir).pipe(Effect9.catchAll(() => Effect9.succeed([])));
939
+ return Effect10.gen(function* () {
940
+ const fs = yield* FileSystem4.FileSystem;
941
+ const names = yield* fs.readDirectory(dir).pipe(Effect10.catchAll(() => Effect10.succeed([])));
836
942
  const entries = [];
837
943
  for (const name of names) {
838
- const info = yield* fs.stat(join4(dir, name)).pipe(Effect9.catchAll(() => Effect9.succeed(null)));
944
+ const info = yield* fs.stat(join5(dir, name)).pipe(Effect10.catchAll(() => Effect10.succeed(null)));
839
945
  if (info) {
840
946
  entries.push({ name, isDirectory: info.type === "Directory" });
841
947
  }
@@ -844,19 +950,19 @@ function readDirEntriesSafe(dir) {
844
950
  });
845
951
  }
846
952
  function listFilesBySuffix(dir, suffix) {
847
- return Effect9.gen(function* () {
848
- const fs = yield* FileSystem3.FileSystem;
849
- const names = yield* fs.readDirectory(dir).pipe(Effect9.catchAll(() => Effect9.succeed([])));
953
+ return Effect10.gen(function* () {
954
+ const fs = yield* FileSystem4.FileSystem;
955
+ const names = yield* fs.readDirectory(dir).pipe(Effect10.catchAll(() => Effect10.succeed([])));
850
956
  return names.filter((name) => name.endsWith(suffix));
851
957
  });
852
958
  }
853
959
  function listFilesWithMtime(dir, suffix) {
854
- return Effect9.gen(function* () {
855
- const fs = yield* FileSystem3.FileSystem;
960
+ return Effect10.gen(function* () {
961
+ const fs = yield* FileSystem4.FileSystem;
856
962
  const names = yield* listFilesBySuffix(dir, suffix);
857
963
  const results = [];
858
964
  for (const fileName of names) {
859
- const info = yield* fs.stat(join4(dir, fileName)).pipe(Effect9.catchAll(() => Effect9.succeed(null)));
965
+ const info = yield* fs.stat(join5(dir, fileName)).pipe(Effect10.catchAll(() => Effect10.succeed(null)));
860
966
  if (info?.mtime._tag === "Some") {
861
967
  results.push({ fileName, mtime: info.mtime.value.toISOString() });
862
968
  }
@@ -866,22 +972,22 @@ function listFilesWithMtime(dir, suffix) {
866
972
  });
867
973
  }
868
974
  function readTextPrefix(filePath, maxBytes) {
869
- return Effect9.gen(function* () {
870
- const fs = yield* FileSystem3.FileSystem;
975
+ return Effect10.gen(function* () {
976
+ const fs = yield* FileSystem4.FileSystem;
871
977
  const bytes = yield* fs.readFile(filePath);
872
978
  const slice = bytes.subarray(0, maxBytes);
873
979
  return new TextDecoder().decode(slice);
874
980
  });
875
981
  }
876
982
  function readFileText(filePath) {
877
- return Effect9.gen(function* () {
878
- const fs = yield* FileSystem3.FileSystem;
983
+ return Effect10.gen(function* () {
984
+ const fs = yield* FileSystem4.FileSystem;
879
985
  return yield* fs.readFileString(filePath);
880
986
  });
881
987
  }
882
988
  function fileExists(filePath) {
883
- return Effect9.gen(function* () {
884
- const fs = yield* FileSystem3.FileSystem;
989
+ return Effect10.gen(function* () {
990
+ const fs = yield* FileSystem4.FileSystem;
885
991
  return yield* fs.exists(filePath);
886
992
  });
887
993
  }
@@ -927,11 +1033,11 @@ var CWD_SCAN_BYTES = 64 * 1024;
927
1033
  var SESSION_META_SCAN_BYTES = 1024 * 1024;
928
1034
  var BRACKETED_TEXT_REGEX = /^\[.+\]$/;
929
1035
  function inspectProjectSessions(projectDir, sessionFiles) {
930
- return Effect10.gen(function* () {
1036
+ return Effect11.gen(function* () {
931
1037
  const lastActivity = sessionFiles[0]?.mtime || "";
932
1038
  let resolvedPath = "";
933
1039
  for (const sessionFile of sessionFiles) {
934
- const filePath = join5(projectDir, sessionFile.fileName);
1040
+ const filePath = join6(projectDir, sessionFile.fileName);
935
1041
  if (!resolvedPath) {
936
1042
  resolvedPath = yield* extractCwd(filePath);
937
1043
  }
@@ -940,15 +1046,15 @@ function inspectProjectSessions(projectDir, sessionFiles) {
940
1046
  });
941
1047
  }
942
1048
  function discoverClaudeProjects() {
943
- return Effect10.gen(function* () {
1049
+ return Effect11.gen(function* () {
944
1050
  const config = yield* PluginConfig;
945
- const projectsDir = join5(config.dataDir, "projects");
1051
+ const projectsDir = join6(config.dataDir, "projects");
946
1052
  const entries = yield* readDirEntriesSafe(projectsDir);
947
1053
  const projects = [];
948
1054
  for (const entry of entries) {
949
1055
  if (!entry.isDirectory)
950
1056
  continue;
951
- const projectDir = join5(projectsDir, entry.name);
1057
+ const projectDir = join6(projectsDir, entry.name);
952
1058
  const sessionFiles = yield* listFilesWithMtime(projectDir, ".jsonl");
953
1059
  if (sessionFiles.length === 0)
954
1060
  continue;
@@ -969,13 +1075,13 @@ function discoverClaudeProjects() {
969
1075
  }
970
1076
  var PLAN_PREFIX = "Implement the following plan";
971
1077
  function listClaudeSessions(nativeId) {
972
- return Effect10.gen(function* () {
1078
+ return Effect11.gen(function* () {
973
1079
  const config = yield* PluginConfig;
974
- const projectDir = join5(config.dataDir, "projects", nativeId);
1080
+ const projectDir = join6(config.dataDir, "projects", nativeId);
975
1081
  const files = yield* listFilesBySuffix(projectDir, ".jsonl");
976
1082
  const sessions = [];
977
1083
  for (const file of files) {
978
- const filePath = join5(projectDir, file);
1084
+ const filePath = join6(projectDir, file);
979
1085
  const sessionId = file.replace(".jsonl", "");
980
1086
  const meta = yield* extractSessionMeta(filePath);
981
1087
  if (meta)
@@ -1002,8 +1108,8 @@ function classifySessionTypes(sessions) {
1002
1108
  }
1003
1109
  }
1004
1110
  function extractCwd(filePath) {
1005
- return Effect10.gen(function* () {
1006
- const text = yield* readTextPrefix(filePath, CWD_SCAN_BYTES).pipe(Effect10.catchAll(() => Effect10.succeed("")));
1111
+ return Effect11.gen(function* () {
1112
+ const text = yield* readTextPrefix(filePath, CWD_SCAN_BYTES).pipe(Effect11.catchAll(() => Effect11.succeed("")));
1007
1113
  if (!text)
1008
1114
  return "";
1009
1115
  let cwd = "";
@@ -1052,8 +1158,8 @@ function processMetaLine(obj, meta) {
1052
1158
  }
1053
1159
  }
1054
1160
  function extractSessionMeta(filePath) {
1055
- return Effect10.gen(function* () {
1056
- const text = yield* readTextPrefix(filePath, SESSION_META_SCAN_BYTES).pipe(Effect10.catchAll(() => Effect10.succeed("")));
1161
+ return Effect11.gen(function* () {
1162
+ const text = yield* readTextPrefix(filePath, SESSION_META_SCAN_BYTES).pipe(Effect11.catchAll(() => Effect11.succeed("")));
1057
1163
  if (!text)
1058
1164
  return null;
1059
1165
  const meta = {
@@ -1087,12 +1193,12 @@ function extractSessionMeta(filePath) {
1087
1193
 
1088
1194
  // ../../packages/plugin-claude-code/src/parser.ts
1089
1195
  init_src();
1090
- import { join as join6 } from "node:path";
1091
- import { Effect as Effect11 } from "effect";
1196
+ import { join as join7 } from "node:path";
1197
+ import { Effect as Effect12 } from "effect";
1092
1198
  function loadClaudeSession(nativeId, sessionId) {
1093
- return Effect11.gen(function* () {
1199
+ return Effect12.gen(function* () {
1094
1200
  const config = yield* PluginConfig;
1095
- const filePath = join6(config.dataDir, "projects", nativeId, `${sessionId}.jsonl`);
1201
+ const filePath = join7(config.dataDir, "projects", nativeId, `${sessionId}.jsonl`);
1096
1202
  const { rawLines, parseErrors } = yield* readJsonlLines(filePath);
1097
1203
  const subAgentMap = extractSubAgentMap(rawLines);
1098
1204
  const slug = extractSlug(rawLines);
@@ -1121,10 +1227,10 @@ function loadClaudeSession(nativeId, sessionId) {
1121
1227
  });
1122
1228
  }
1123
1229
  function parseSubAgentSession(sessionId, encodedPath, agentId) {
1124
- return Effect11.gen(function* () {
1230
+ return Effect12.gen(function* () {
1125
1231
  const config = yield* PluginConfig;
1126
- const filePath = join6(config.dataDir, "projects", encodedPath, sessionId, "subagents", `agent-${agentId}.jsonl`);
1127
- const parsed = yield* readJsonlLines(filePath).pipe(Effect11.catchAll(() => Effect11.succeed({ rawLines: [], parseErrors: [] })));
1232
+ const filePath = join7(config.dataDir, "projects", encodedPath, sessionId, "subagents", `agent-${agentId}.jsonl`);
1233
+ const parsed = yield* readJsonlLines(filePath).pipe(Effect12.catchAll(() => Effect12.succeed({ rawLines: [], parseErrors: [] })));
1128
1234
  const subAgentMap = extractSubAgentMap(parsed.rawLines);
1129
1235
  const turns = buildTurns(parsed.rawLines, parsed.parseErrors);
1130
1236
  for (const turn of turns) {
@@ -1202,7 +1308,7 @@ function findImplSessionId(slug, sessions, currentSessionId) {
1202
1308
  return match?.sessionId;
1203
1309
  }
1204
1310
  function readJsonlLines(filePath) {
1205
- return Effect11.gen(function* () {
1311
+ return Effect12.gen(function* () {
1206
1312
  const text = yield* readFileText(filePath);
1207
1313
  const rawLines = [];
1208
1314
  const parseErrors = [];
@@ -1348,7 +1454,7 @@ function buildToolCall2(block, toolResults) {
1348
1454
  return toolCall;
1349
1455
  }
1350
1456
  function processContentBlock(block, current, toolResults) {
1351
- if (block.type === "thinking" && "thinking" in block) {
1457
+ if (block.type === "thinking" && "thinking" in block && block.thinking.trim()) {
1352
1458
  current.contentBlocks.push({ type: "thinking", block: { text: block.thinking } });
1353
1459
  } else if (block.type === "text" && "text" in block && block.text.trim()) {
1354
1460
  current.contentBlocks.push({ type: "text", text: block.text });
@@ -1483,27 +1589,27 @@ function extractToolResult(tr) {
1483
1589
  }
1484
1590
 
1485
1591
  // ../../packages/plugin-claude-code/src/config.ts
1486
- import { join as join7 } from "node:path";
1487
- var DEFAULT_CLAUDE_CODE_DIR = join7(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".claude");
1592
+ import { join as join8 } from "node:path";
1593
+ var DEFAULT_CLAUDE_CODE_DIR = join8(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".claude");
1488
1594
  // ../../packages/plugin-claude-code/src/index.ts
1489
1595
  var claudeCodePlugin = {
1490
1596
  id: "claude-code",
1491
1597
  displayName: "Claude Code",
1492
1598
  getDefaultDataDir: () => null,
1493
- isDataAvailable: Effect12.gen(function* () {
1599
+ isDataAvailable: Effect13.gen(function* () {
1494
1600
  const config = yield* PluginConfig;
1495
- return yield* fileExists(config.dataDir).pipe(Effect12.catchAll(() => Effect12.succeed(false)));
1601
+ return yield* fileExists(config.dataDir).pipe(Effect13.catchAll(() => Effect13.succeed(false)));
1496
1602
  }),
1497
1603
  discoverProjects: discoverClaudeProjects(),
1498
1604
  listSessions: (nativeId) => listClaudeSessions(nativeId),
1499
- loadSession: (nativeId, sessionId) => loadClaudeSession(nativeId, sessionId).pipe(Effect12.map((r) => r.session), Effect12.catchAll((err) => Effect12.fail(new PluginError({
1605
+ loadSession: (nativeId, sessionId) => loadClaudeSession(nativeId, sessionId).pipe(Effect13.map((r) => r.session), Effect13.catchAll((err) => Effect13.fail(new PluginError({
1500
1606
  pluginId: "claude-code",
1501
1607
  operation: "loadSession",
1502
1608
  message: String(err),
1503
1609
  cause: err
1504
1610
  })))),
1505
- loadSessionDetail: (nativeId, sessionId) => Effect12.gen(function* () {
1506
- const [{ session, slug }, sessions] = yield* Effect12.all([
1611
+ loadSessionDetail: (nativeId, sessionId) => Effect13.gen(function* () {
1612
+ const [{ session, slug }, sessions] = yield* Effect13.all([
1507
1613
  loadClaudeSession(nativeId, sessionId),
1508
1614
  listClaudeSessions(nativeId)
1509
1615
  ]);
@@ -1512,7 +1618,7 @@ var claudeCodePlugin = {
1512
1618
  planSessionId: findPlanSessionId(session.turns, slug, sessions, sessionId),
1513
1619
  implSessionId: findImplSessionId(slug, sessions, sessionId)
1514
1620
  };
1515
- }).pipe(Effect12.catchAll((err) => Effect12.fail(new PluginError({
1621
+ }).pipe(Effect13.catchAll((err) => Effect13.fail(new PluginError({
1516
1622
  pluginId: "claude-code",
1517
1623
  operation: "loadSessionDetail",
1518
1624
  message: String(err),
@@ -1524,38 +1630,38 @@ var claudeCodePlugin = {
1524
1630
 
1525
1631
  // ../../packages/plugin-codex/src/index.ts
1526
1632
  init_src();
1527
- import { Effect as Effect17 } from "effect";
1633
+ import { Effect as Effect18 } from "effect";
1528
1634
 
1529
1635
  // ../../packages/plugin-codex/src/discovery.ts
1530
1636
  init_src();
1531
- import { Effect as Effect15 } from "effect";
1637
+ import { Effect as Effect16 } from "effect";
1532
1638
 
1533
1639
  // ../../packages/plugin-codex/src/session-index.ts
1534
1640
  init_src();
1535
- import { join as join8 } from "node:path";
1536
- import { FileSystem as FileSystem5 } from "@effect/platform";
1537
- import { Effect as Effect14 } from "effect";
1641
+ import { join as join9 } from "node:path";
1642
+ import { FileSystem as FileSystem6 } from "@effect/platform";
1643
+ import { Effect as Effect15 } from "effect";
1538
1644
 
1539
1645
  // ../../packages/plugin-codex/src/shared/discovery-utils.ts
1540
- import { FileSystem as FileSystem4 } from "@effect/platform";
1541
- import { Effect as Effect13 } from "effect";
1646
+ import { FileSystem as FileSystem5 } from "@effect/platform";
1647
+ import { Effect as Effect14 } from "effect";
1542
1648
  function readTextPrefix2(filePath, maxBytes) {
1543
- return Effect13.gen(function* () {
1544
- const fs = yield* FileSystem4.FileSystem;
1649
+ return Effect14.gen(function* () {
1650
+ const fs = yield* FileSystem5.FileSystem;
1545
1651
  const bytes = yield* fs.readFile(filePath);
1546
1652
  const slice = bytes.subarray(0, maxBytes);
1547
1653
  return new TextDecoder().decode(slice);
1548
1654
  });
1549
1655
  }
1550
1656
  function readFileText2(filePath) {
1551
- return Effect13.gen(function* () {
1552
- const fs = yield* FileSystem4.FileSystem;
1657
+ return Effect14.gen(function* () {
1658
+ const fs = yield* FileSystem5.FileSystem;
1553
1659
  return yield* fs.readFileString(filePath);
1554
1660
  });
1555
1661
  }
1556
1662
  function fileExists2(filePath) {
1557
- return Effect13.gen(function* () {
1558
- const fs = yield* FileSystem4.FileSystem;
1663
+ return Effect14.gen(function* () {
1664
+ const fs = yield* FileSystem5.FileSystem;
1559
1665
  return yield* fs.exists(filePath);
1560
1666
  });
1561
1667
  }
@@ -1636,8 +1742,8 @@ function inferModelFromPrefix(prefixText) {
1636
1742
  return model;
1637
1743
  }
1638
1744
  function parseSessionMeta(filePath, fileMtimeEpoch) {
1639
- return Effect14.gen(function* () {
1640
- const prefix = yield* readTextPrefix2(filePath, FIRST_LINE_SCAN_BYTES).pipe(Effect14.catchAll(() => Effect14.succeed("")));
1745
+ return Effect15.gen(function* () {
1746
+ const prefix = yield* readTextPrefix2(filePath, FIRST_LINE_SCAN_BYTES).pipe(Effect15.catchAll(() => Effect15.succeed("")));
1641
1747
  if (!prefix)
1642
1748
  return null;
1643
1749
  const firstNewline = prefix.indexOf(`
@@ -1664,12 +1770,12 @@ function parseSessionMeta(filePath, fileMtimeEpoch) {
1664
1770
  });
1665
1771
  }
1666
1772
  function walkJsonlFiles(dir, visit) {
1667
- return Effect14.gen(function* () {
1668
- const fs = yield* FileSystem5.FileSystem;
1669
- const names = yield* fs.readDirectory(dir).pipe(Effect14.catchAll(() => Effect14.succeed([])));
1773
+ return Effect15.gen(function* () {
1774
+ const fs = yield* FileSystem6.FileSystem;
1775
+ const names = yield* fs.readDirectory(dir).pipe(Effect15.catchAll(() => Effect15.succeed([])));
1670
1776
  for (const name of names) {
1671
- const fullPath = join8(dir, name);
1672
- const info = yield* fs.stat(fullPath).pipe(Effect14.catchAll(() => Effect14.succeed(null)));
1777
+ const fullPath = join9(dir, name);
1778
+ const info = yield* fs.stat(fullPath).pipe(Effect15.catchAll(() => Effect15.succeed(null)));
1673
1779
  if (!info)
1674
1780
  continue;
1675
1781
  if (info.type === "Directory") {
@@ -1683,13 +1789,13 @@ function walkJsonlFiles(dir, visit) {
1683
1789
  });
1684
1790
  }
1685
1791
  function scanCodexSessions() {
1686
- return Effect14.gen(function* () {
1792
+ return Effect15.gen(function* () {
1687
1793
  const config = yield* PluginConfig;
1688
- const fs = yield* FileSystem5.FileSystem;
1689
- const sessionsDir = join8(config.dataDir, "sessions");
1794
+ const fs = yield* FileSystem6.FileSystem;
1795
+ const sessionsDir = join9(config.dataDir, "sessions");
1690
1796
  const sessions = [];
1691
- yield* walkJsonlFiles(sessionsDir, (filePath, _fileName) => Effect14.gen(function* () {
1692
- const info = yield* fs.stat(filePath).pipe(Effect14.catchAll(() => Effect14.succeed(null)));
1797
+ yield* walkJsonlFiles(sessionsDir, (filePath, _fileName) => Effect15.gen(function* () {
1798
+ const info = yield* fs.stat(filePath).pipe(Effect15.catchAll(() => Effect15.succeed(null)));
1693
1799
  const fileMtimeEpoch = info?.mtime._tag === "Some" ? info.mtime.value.getTime() / 1000 : undefined;
1694
1800
  const meta = yield* parseSessionMeta(filePath, fileMtimeEpoch);
1695
1801
  if (!meta)
@@ -1706,12 +1812,12 @@ function scanCodexSessions() {
1706
1812
  });
1707
1813
  }
1708
1814
  function walkForFile(dir, match) {
1709
- return Effect14.gen(function* () {
1710
- const fs = yield* FileSystem5.FileSystem;
1711
- const names = yield* fs.readDirectory(dir).pipe(Effect14.catchAll(() => Effect14.succeed([])));
1815
+ return Effect15.gen(function* () {
1816
+ const fs = yield* FileSystem6.FileSystem;
1817
+ const names = yield* fs.readDirectory(dir).pipe(Effect15.catchAll(() => Effect15.succeed([])));
1712
1818
  for (const name of names) {
1713
- const fullPath = join8(dir, name);
1714
- const info = yield* fs.stat(fullPath).pipe(Effect14.catchAll(() => Effect14.succeed(null)));
1819
+ const fullPath = join9(dir, name);
1820
+ const info = yield* fs.stat(fullPath).pipe(Effect15.catchAll(() => Effect15.succeed(null)));
1715
1821
  if (!info)
1716
1822
  continue;
1717
1823
  if (info.type !== "Directory" && match(name))
@@ -1726,16 +1832,16 @@ function walkForFile(dir, match) {
1726
1832
  });
1727
1833
  }
1728
1834
  function findCodexSessionFileById(sessionId) {
1729
- return Effect14.gen(function* () {
1835
+ return Effect15.gen(function* () {
1730
1836
  const config = yield* PluginConfig;
1731
- const fs = yield* FileSystem5.FileSystem;
1732
- const sessionsDir = join8(config.dataDir, "sessions");
1837
+ const fs = yield* FileSystem6.FileSystem;
1838
+ const sessionsDir = join9(config.dataDir, "sessions");
1733
1839
  const exactName = `${sessionId}.jsonl`;
1734
1840
  const suffix = `-${sessionId}.jsonl`;
1735
1841
  const filePath = yield* walkForFile(sessionsDir, (name) => name === exactName || name.endsWith(suffix));
1736
1842
  if (!filePath)
1737
1843
  return null;
1738
- const info = yield* fs.stat(filePath).pipe(Effect14.catchAll(() => Effect14.succeed(null)));
1844
+ const info = yield* fs.stat(filePath).pipe(Effect15.catchAll(() => Effect15.succeed(null)));
1739
1845
  return info?.type === "File" ? filePath : null;
1740
1846
  });
1741
1847
  }
@@ -1743,7 +1849,7 @@ function findCodexSessionFileById(sessionId) {
1743
1849
  // ../../packages/plugin-codex/src/discovery.ts
1744
1850
  var SESSION_TITLE_SCAN_BYTES = 256 * 1024;
1745
1851
  function discoverCodexProjects() {
1746
- return Effect15.gen(function* () {
1852
+ return Effect16.gen(function* () {
1747
1853
  const sessions = yield* scanCodexSessions();
1748
1854
  const byCwd = new Map;
1749
1855
  for (const session of sessions) {
@@ -1794,17 +1900,17 @@ function extractFirstUserMessage(text) {
1794
1900
  return message;
1795
1901
  }
1796
1902
  function listCodexSessions(nativeId) {
1797
- return Effect15.gen(function* () {
1903
+ return Effect16.gen(function* () {
1798
1904
  const allSessions = yield* scanCodexSessions();
1799
1905
  const matching = allSessions.filter((s) => s.meta.cwd === nativeId);
1800
1906
  const sessions = [];
1801
1907
  for (const s of matching) {
1802
1908
  let firstMessage = s.meta.name || "";
1803
1909
  if (!firstMessage) {
1804
- const prefix = yield* readTextPrefix2(s.filePath, SESSION_TITLE_SCAN_BYTES).pipe(Effect15.catchAll(() => Effect15.succeed("")));
1910
+ const prefix = yield* readTextPrefix2(s.filePath, SESSION_TITLE_SCAN_BYTES).pipe(Effect16.catchAll(() => Effect16.succeed("")));
1805
1911
  firstMessage = extractFirstUserMessage(prefix) || "";
1806
1912
  if (!firstMessage) {
1807
- const fullText = yield* readFileText2(s.filePath).pipe(Effect15.catchAll(() => Effect15.succeed("")));
1913
+ const fullText = yield* readFileText2(s.filePath).pipe(Effect16.catchAll(() => Effect16.succeed("")));
1808
1914
  firstMessage = extractFirstUserMessage(fullText) || "";
1809
1915
  }
1810
1916
  firstMessage ||= "Codex session";
@@ -1827,7 +1933,7 @@ function listCodexSessions(nativeId) {
1827
1933
 
1828
1934
  // ../../packages/plugin-codex/src/parser.ts
1829
1935
  init_src();
1830
- import { Effect as Effect16 } from "effect";
1936
+ import { Effect as Effect17 } from "effect";
1831
1937
  function isKnownModel2(model) {
1832
1938
  return typeof model === "string" && model.length > 0 && model !== "unknown";
1833
1939
  }
@@ -2138,7 +2244,7 @@ function buildCodexTurns(events, model, timestamp) {
2138
2244
  return state.turns;
2139
2245
  }
2140
2246
  function loadCodexSession(_nativeId, sessionId) {
2141
- return Effect16.gen(function* () {
2247
+ return Effect17.gen(function* () {
2142
2248
  const filePath = yield* findCodexSessionFileById(sessionId);
2143
2249
  if (!filePath) {
2144
2250
  return {
@@ -2185,20 +2291,20 @@ function loadCodexSession(_nativeId, sessionId) {
2185
2291
  }
2186
2292
 
2187
2293
  // ../../packages/plugin-codex/src/config.ts
2188
- import { join as join9 } from "node:path";
2189
- var DEFAULT_CODEX_CLI_DIR = join9(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".codex");
2294
+ import { join as join10 } from "node:path";
2295
+ var DEFAULT_CODEX_CLI_DIR = join10(process.env["HOME"] ?? process.env["USERPROFILE"] ?? "", ".codex");
2190
2296
  // ../../packages/plugin-codex/src/index.ts
2191
2297
  var codexCliPlugin = {
2192
2298
  id: "codex-cli",
2193
2299
  displayName: "Codex",
2194
2300
  getDefaultDataDir: () => null,
2195
- isDataAvailable: Effect17.gen(function* () {
2301
+ isDataAvailable: Effect18.gen(function* () {
2196
2302
  const config = yield* PluginConfig;
2197
- return yield* fileExists2(config.dataDir).pipe(Effect17.catchAll(() => Effect17.succeed(false)));
2303
+ return yield* fileExists2(config.dataDir).pipe(Effect18.catchAll(() => Effect18.succeed(false)));
2198
2304
  }),
2199
2305
  discoverProjects: discoverCodexProjects(),
2200
2306
  listSessions: (nativeId) => listCodexSessions(nativeId),
2201
- loadSession: (nativeId, sessionId) => loadCodexSession(nativeId, sessionId).pipe(Effect17.catchAll((err) => Effect17.fail(new PluginError({
2307
+ loadSession: (nativeId, sessionId) => loadCodexSession(nativeId, sessionId).pipe(Effect18.catchAll((err) => Effect18.fail(new PluginError({
2202
2308
  pluginId: "codex-cli",
2203
2309
  operation: "loadSession",
2204
2310
  message: String(err),
@@ -2228,7 +2334,7 @@ var BUILTIN_PLUGIN_ID_SET = new Set(BUILTIN_PLUGIN_DESCRIPTORS.map((descriptor)
2228
2334
  // ../../packages/server/src/services/settings.ts
2229
2335
  init_src();
2230
2336
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
2231
- import { dirname, join as join10 } from "node:path";
2337
+ import { dirname, join as join11 } from "node:path";
2232
2338
  function createDefaultPluginStates() {
2233
2339
  return Object.fromEntries(BUILTIN_KLOVI_PLUGIN_IDS.map((pluginId) => [pluginId, { enabled: true, dataDir: null }]));
2234
2340
  }
@@ -2261,7 +2367,7 @@ async function loadSettings(path) {
2261
2367
  async function saveSettings(path, settings) {
2262
2368
  const dir = dirname(path);
2263
2369
  await mkdir(dir, { recursive: true });
2264
- const tmpPath = join10(dir, `.settings-${Date.now()}.tmp`);
2370
+ const tmpPath = join11(dir, `.settings-${Date.now()}.tmp`);
2265
2371
  await writeFile(tmpPath, JSON.stringify(settings, null, 2));
2266
2372
  await rename(tmpPath, path);
2267
2373
  }
@@ -2597,12 +2703,12 @@ async function createRegistry(settings) {
2597
2703
  // ../../packages/server/src/effect/server-services.ts
2598
2704
  class KloviServices extends Context4.Tag("@klovi/KloviServices")() {
2599
2705
  }
2600
- var KloviServicesLive = Layer6.effect(KloviServices, Effect18.gen(function* () {
2706
+ var KloviServicesLive = Layer6.effect(KloviServices, Effect19.gen(function* () {
2601
2707
  const config = yield* ServerConfig;
2602
2708
  const { settingsPath } = config;
2603
2709
  const version = config.version === "0.0.0" ? "dev" : config.version;
2604
- const settings = yield* Effect18.promise(() => loadSettings(settingsPath));
2605
- let registry = yield* Effect18.promise(() => createRegistry(settings));
2710
+ const settings = yield* Effect19.promise(() => loadSettings(settingsPath));
2711
+ let registry = yield* Effect19.promise(() => createRegistry(settings));
2606
2712
  async function refreshRegistry() {
2607
2713
  const freshSettings = await loadSettings(settingsPath);
2608
2714
  registry = await createRegistry(freshSettings);
@@ -2640,7 +2746,7 @@ var KloviServicesLive = Layer6.effect(KloviServices, Effect18.gen(function* () {
2640
2746
  // ../../packages/server/src/effect/bootstrap.ts
2641
2747
  function getDefaultSettingsPath() {
2642
2748
  const home = process.env["HOME"] ?? process.env["USERPROFILE"] ?? "";
2643
- return join11(home, ".klovi", "settings.json");
2749
+ return join12(home, ".klovi", "settings.json");
2644
2750
  }
2645
2751
  function detectRuntime(requested = "auto") {
2646
2752
  if (requested !== "auto")
@@ -2676,26 +2782,26 @@ async function bootstrapServer(options, makeServe) {
2676
2782
  resolveAddress = resolve;
2677
2783
  rejectAddress = reject;
2678
2784
  });
2679
- const addressCapture = Layer8.effectDiscard(HttpServer.addressWith((address) => Effect19.sync(() => {
2785
+ const addressCapture = Layer8.effectDiscard(HttpServer.addressWith((address) => Effect20.sync(() => {
2680
2786
  const addr = address;
2681
2787
  resolveAddress(`http://${addr.hostname}:${addr.port}`);
2682
2788
  })));
2683
2789
  const serveLayer = makeServe();
2684
2790
  const fullLayer = Layer8.merge(serveLayer, addressCapture).pipe(Layer8.provide(servicesLayer), Layer8.provide(configLayer), Layer8.provide(platformLayer));
2685
- const fiber = Effect19.runFork(Layer8.launch(fullLayer));
2686
- Effect19.runFork(Fiber.join(fiber).pipe(Effect19.catchAllCause((cause) => Effect19.sync(() => rejectAddress(Cause.squash(cause))))));
2791
+ const fiber = Effect20.runFork(Layer8.launch(fullLayer));
2792
+ Effect20.runFork(Fiber.join(fiber).pipe(Effect20.catchAllCause((cause) => Effect20.sync(() => rejectAddress(Cause.squash(cause))))));
2687
2793
  const url = await addressPromise;
2688
2794
  return {
2689
2795
  url,
2690
2796
  stop() {
2691
- Effect19.runFork(Fiber.interrupt(fiber));
2797
+ Effect20.runFork(Fiber.interrupt(fiber));
2692
2798
  }
2693
2799
  };
2694
2800
  }
2695
2801
 
2696
2802
  // ../../packages/server/src/effect/http-app.ts
2697
2803
  import { HttpRouter, HttpServer as HttpServer2, HttpServerRequest, HttpServerResponse } from "@effect/platform";
2698
- import { Effect as Effect20 } from "effect";
2804
+ import { Effect as Effect21 } from "effect";
2699
2805
 
2700
2806
  // ../../packages/server/src/rpc-error.ts
2701
2807
  class RPCError extends Error {
@@ -2711,7 +2817,7 @@ var NON_RPC_KEYS = new Set(["getRegistry", "settingsPath"]);
2711
2817
  function isRPCMethod(method, services) {
2712
2818
  return Object.hasOwn(services, method) && !NON_RPC_KEYS.has(method);
2713
2819
  }
2714
- var rpcHandler = Effect20.gen(function* () {
2820
+ var rpcHandler = Effect21.gen(function* () {
2715
2821
  const services = yield* KloviServices;
2716
2822
  const routeParams = yield* HttpRouter.params;
2717
2823
  const req = yield* HttpServerRequest.HttpServerRequest;
@@ -2720,7 +2826,7 @@ var rpcHandler = Effect20.gen(function* () {
2720
2826
  return HttpServerResponse.unsafeJson({ error: "Method name required" }, { status: 400 });
2721
2827
  }
2722
2828
  if (!isRPCMethod(method, services)) {
2723
- return yield* Effect20.fail(new RPCError(404, `Unknown method: ${method}`));
2829
+ return yield* Effect21.fail(new RPCError(404, `Unknown method: ${method}`));
2724
2830
  }
2725
2831
  let params = {};
2726
2832
  const bodyText = yield* req.text;
@@ -2732,44 +2838,44 @@ var rpcHandler = Effect20.gen(function* () {
2732
2838
  }
2733
2839
  }
2734
2840
  const handler = services[method];
2735
- return yield* Effect20.tryPromise({
2841
+ return yield* Effect21.tryPromise({
2736
2842
  try: async () => {
2737
2843
  const result = await Promise.resolve(handler(params));
2738
2844
  return HttpServerResponse.unsafeJson(result);
2739
2845
  },
2740
2846
  catch: (err) => err
2741
2847
  });
2742
- }).pipe(Effect20.catchAll((err) => {
2848
+ }).pipe(Effect21.catchAll((err) => {
2743
2849
  if (err instanceof RPCError) {
2744
- return Effect20.succeed(HttpServerResponse.unsafeJson({ error: err.message }, { status: err.status }));
2850
+ return Effect21.succeed(HttpServerResponse.unsafeJson({ error: err.message }, { status: err.status }));
2745
2851
  }
2746
2852
  const message = err instanceof Error ? err.message : "Internal server error";
2747
- return Effect20.succeed(HttpServerResponse.unsafeJson({ error: message }, { status: 500 }));
2853
+ return Effect21.succeed(HttpServerResponse.unsafeJson({ error: message }, { status: 500 }));
2748
2854
  }));
2749
- var emptyMethodHandler = Effect20.succeed(HttpServerResponse.unsafeJson({ error: "Method name required" }, { status: 400 }));
2855
+ var emptyMethodHandler = Effect21.succeed(HttpServerResponse.unsafeJson({ error: "Method name required" }, { status: 400 }));
2750
2856
  var makeRpcRouter = () => HttpRouter.empty.pipe(HttpRouter.post("/api/rpc/", emptyMethodHandler), HttpRouter.post("/api/rpc/:method", rpcHandler));
2751
- var notFoundHandler = Effect20.succeed(HttpServerResponse.unsafeJson({ error: "Not found" }, { status: 404 }));
2752
- var makeHttpApp = () => makeRpcRouter().pipe(Effect20.catchTag("RouteNotFound", () => notFoundHandler));
2857
+ var notFoundHandler = Effect21.succeed(HttpServerResponse.unsafeJson({ error: "Not found" }, { status: 404 }));
2858
+ var makeHttpApp = () => makeRpcRouter().pipe(Effect21.catchTag("RouteNotFound", () => notFoundHandler));
2753
2859
  var makeServeLayer = () => makeHttpApp().pipe(HttpServer2.serve());
2754
2860
 
2755
2861
  // src/http-app.ts
2756
2862
  import { HttpServer as HttpServer3 } from "@effect/platform";
2757
- import { Effect as Effect22 } from "effect";
2863
+ import { Effect as Effect23 } from "effect";
2758
2864
 
2759
2865
  // src/static-handler.ts
2760
2866
  import { HttpServerRequest as HttpServerRequest2, HttpServerResponse as HttpServerResponse2 } from "@effect/platform";
2761
- import { Effect as Effect21 } from "effect";
2762
- var makeStaticHandler = (staticDir) => Effect21.gen(function* () {
2867
+ import { Effect as Effect22 } from "effect";
2868
+ var makeStaticHandler = (staticDir) => Effect22.gen(function* () {
2763
2869
  const req = yield* HttpServerRequest2.HttpServerRequest;
2764
2870
  const url = new URL(req.url, "http://localhost");
2765
2871
  const filePath = url.pathname === "/" ? "/index.html" : url.pathname;
2766
- return yield* HttpServerResponse2.file(`${staticDir}${filePath}`).pipe(Effect21.orElse(() => HttpServerResponse2.file(`${staticDir}/index.html`)), Effect21.orElse(() => Effect21.succeed(HttpServerResponse2.unsafeJson({ error: "Not found" }, { status: 404 }))));
2872
+ return yield* HttpServerResponse2.file(`${staticDir}${filePath}`).pipe(Effect22.orElse(() => HttpServerResponse2.file(`${staticDir}/index.html`)), Effect22.orElse(() => Effect22.succeed(HttpServerResponse2.unsafeJson({ error: "Not found" }, { status: 404 }))));
2767
2873
  });
2768
2874
 
2769
2875
  // src/http-app.ts
2770
2876
  var makePackageHttpApp = (staticDir) => {
2771
2877
  const router = makeRpcRouter();
2772
- return router.pipe(Effect22.catchTag("RouteNotFound", () => makeStaticHandler(staticDir)));
2878
+ return router.pipe(Effect23.catchTag("RouteNotFound", () => makeStaticHandler(staticDir)));
2773
2879
  };
2774
2880
  var makePackageServeLayer = (staticDir) => {
2775
2881
  if (!staticDir) {