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