saeeol 1.3.1 → 1.4.1

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/bin/saeeol.cjs CHANGED
@@ -188,7 +188,9 @@ if (fs.existsSync(indexPath)) {
188
188
  const which = childProcess.spawnSync(bunExe, ["--version"], { encoding: "utf8", timeout: 3000 })
189
189
  if (which.status === 0) {
190
190
  const result = childProcess.spawnSync(bunExe, [
191
- "run", "--conditions=browser", indexPath, ...process.argv.slice(2)
191
+ "run", "--conditions=browser",
192
+ "--jsx-import-source=@opentui/solid",
193
+ indexPath, ...process.argv.slice(2)
192
194
  ], { stdio: "inherit" })
193
195
  const code = typeof result.status === "number" ? result.status : 0
194
196
  process.exit(code)
package/bunfig.toml ADDED
@@ -0,0 +1,7 @@
1
+ preload = ["@opentui/solid/preload"]
2
+
3
+ [test]
4
+ preload = ["@opentui/solid/preload", "./test/preload.ts"]
5
+ # timeout is not actually parsed from bunfig.toml (see src/bunfig.zig in oven-sh/bun)
6
+ # using --timeout in package.json scripts instead
7
+ # https://github.com/oven-sh/bun/issues/7789
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "1.3.1",
3
+ "version": "1.4.1",
4
4
  "name": "saeeol",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,138 @@
1
+ /**
2
+ * preflight.ts — TUI 부트 전 자기 검사
3
+ *
4
+ * Worker를 스폰하기 전에 빠르게 실패할 수 있는 조건들을 검사:
5
+ * 1. JSX 트랜스폼 — SolidJS/OpenTUI 런타임 로드 가능한지
6
+ * 2. Bun 버전 — 최소 버전 충족
7
+ * 3. 필수 의존성 — node_modules에 핵심 패키지 있는지
8
+ * 4. 디스크 공간 — 임시 파일/스냅샷 저장 가능한지
9
+ * 5. 포트 가용성 — 서버 바인딩 가능한지
10
+ * 6. 이전 크래시 로그 — 마지막 실행에서 크래시했는지
11
+ *
12
+ * 모든 체크는 동기적이고 100ms 이내 완료.
13
+ */
14
+
15
+ import * as Log from "@saeeol/core/util/log"
16
+ import { Filesystem } from "@/util/filesystem"
17
+ import path from "path"
18
+ import fs from "fs"
19
+
20
+ export interface PreflightResult {
21
+ severity: "error" | "warning"
22
+ message: string
23
+ }
24
+
25
+ export function preflight(): PreflightResult[] {
26
+ const results: PreflightResult[] = []
27
+
28
+ // 1. JSX 런타임 — SolidJS/OpenTUI 로드 가능한지
29
+ try {
30
+ require.resolve("@opentui/solid")
31
+ } catch {
32
+ // Bun 소스 모드에서는 require.resolve가 안 될 수 있음
33
+ // 대신 실제 import 테스트
34
+ try {
35
+ // jsxImportSource가 제대로 설정되었는지 간접 확인
36
+ // bun 실행 시 --jsx-import-source가 전달되었는지
37
+ const tsconfigPath = path.resolve(import.meta.dir, "../../../../tsconfig.json")
38
+ if (fs.existsSync(tsconfigPath)) {
39
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, "utf8"))
40
+ const jsxSource = tsconfig.compilerOptions?.jsxImportSource
41
+ if (jsxSource && jsxSource !== "@opentui/solid") {
42
+ results.push({
43
+ severity: "error",
44
+ message: `jsxImportSource is "${jsxSource}", expected "@opentui/solid" — run with --jsx-import-source=@opentui/solid`,
45
+ })
46
+ }
47
+ }
48
+ } catch {
49
+ // tsconfig 읽기 실패 — 무시 (빌드된 바이너리면 tsconfig 없음)
50
+ }
51
+ }
52
+
53
+ // 2. Bun 버전 체크 (소스 모드에서만)
54
+ if (typeof Bun !== "undefined") {
55
+ const version = Bun.version
56
+ const [major, minor] = version.split(".").map(Number)
57
+ if (major < 1 || (major === 1 && minor < 1)) {
58
+ results.push({
59
+ severity: "warning",
60
+ message: `Bun ${version} detected — TUI requires Bun 1.1.0+ for SolidJS JSX support`,
61
+ })
62
+ }
63
+ }
64
+
65
+ // 3. 필수 패키지 존재 확인
66
+ const rootDir = path.resolve(import.meta.dir, "../../../../")
67
+ const requiredPackages = ["@opentui/core", "@opentui/solid"]
68
+ for (const pkg of requiredPackages) {
69
+ const pkgPath = path.join(rootDir, "node_modules", pkg, "package.json")
70
+ if (!fs.existsSync(pkgPath)) {
71
+ results.push({
72
+ severity: "error",
73
+ message: `Missing dependency: ${pkg} — run your package manager install`,
74
+ })
75
+ }
76
+ }
77
+
78
+ // 4. 디스크 공간 — 임시 디렉토리 쓰기 가능한지
79
+ const tmpDir = path.resolve(import.meta.dir, "../.tui-tmp")
80
+ try {
81
+ fs.mkdirSync(tmpDir, { recursive: true })
82
+ const testFile = path.join(tmpDir, ".preflight-write-test")
83
+ fs.writeFileSync(testFile, "ok")
84
+ fs.unlinkSync(testFile)
85
+ } catch (err) {
86
+ results.push({
87
+ severity: "error",
88
+ message: `Cannot write to TUI temp directory: ${(err as Error).message}`,
89
+ })
90
+ }
91
+
92
+ // 5. 이전 크래시 로그 표시
93
+ const crashLog = path.resolve(import.meta.dir, "../.tui-crash.log")
94
+ if (fs.existsSync(crashLog)) {
95
+ try {
96
+ const stat = fs.statSync(crashLog)
97
+ const ageMs = Date.now() - stat.mtimeMs
98
+ // 최근 10분 이내 크래시면 표시
99
+ if (ageMs < 10 * 60 * 1000) {
100
+ const content = fs.readFileSync(crashLog, "utf8").trim().slice(0, 200)
101
+ results.push({
102
+ severity: "warning",
103
+ message: `Previous TUI crash detected (${Math.round(ageMs / 1000)}s ago): ${content}`,
104
+ })
105
+ }
106
+ // 오래된 크래시 로그는 자동 삭제
107
+ fs.unlinkSync(crashLog)
108
+ } catch {
109
+ // 읽기 실패면 무시
110
+ }
111
+ }
112
+
113
+ // 6. Worker 파일 존재 확인
114
+ // target()이 이미 체크하므로 여기서는 스킵
115
+
116
+ // 7. 터미널 capabilities — TUI가 필요한 기능이 있는지
117
+ if (process.env.TERM === "dumb") {
118
+ results.push({
119
+ severity: "warning",
120
+ message: `TERM=dumb — TUI may not render correctly. Set TERM=xterm-256color`,
121
+ })
122
+ }
123
+
124
+ return results
125
+ }
126
+
127
+ /**
128
+ * 크래시 로그 기록 — TUI 종료 시 에러가 있으면 호출
129
+ */
130
+ export function writeCrashLog(error: unknown): void {
131
+ try {
132
+ const crashLog = path.resolve(import.meta.dir, "../.tui-crash.log")
133
+ const message = error instanceof Error ? `${error.name}: ${error.message}\n${error.stack?.slice(0, 500)}` : String(error)
134
+ fs.writeFileSync(crashLog, message)
135
+ } catch {
136
+ // 크래시 로그 자체가 실패하면 무시
137
+ }
138
+ }
@@ -26,6 +26,7 @@ import {
26
26
  } from "@saeeol/core/util/saeeol-process"
27
27
  import { validateSession } from "./validate-session"
28
28
  import { spawn } from "node:child_process"
29
+ import { preflight, writeCrashLog } from "./preflight"
29
30
 
30
31
  declare global {
31
32
  const SAEEOL_WORKER_PATH: string
@@ -168,6 +169,24 @@ export const TuiThreadCommand = cmd({
168
169
  // chdir so the thread and worker share the same directory key.
169
170
  const next = resolveThreadDirectory(args.project)
170
171
  const file = await target()
172
+
173
+ // Preflight checks before spawning Worker
174
+ const pf = preflight()
175
+ if (pf.length > 0) {
176
+ for (const f of pf) {
177
+ if (f.severity === "error") {
178
+ UI.error(`[preflight] ${f.message}`)
179
+ } else {
180
+ UI.println(`[preflight] ⚠ ${f.message}`)
181
+ }
182
+ }
183
+ const errors = pf.filter((f) => f.severity === "error")
184
+ if (errors.length > 0) {
185
+ UI.error(`TUI cannot start — fix ${errors.length} error(s) above`)
186
+ process.exitCode = 1
187
+ return
188
+ }
189
+ }
171
190
  try {
172
191
  process.chdir(next)
173
192
  } catch {
@@ -196,6 +215,7 @@ export const TuiThreadCommand = cmd({
196
215
  const client = Rpc.client<typeof rpc>(worker)
197
216
  const error = (e: unknown) => {
198
217
  Log.Default.error("process error", { error: errorMessage(e) })
218
+ writeCrashLog(e)
199
219
  }
200
220
  const reload = () => {
201
221
  client.call("reload", undefined).catch((err) => {
@@ -0,0 +1,93 @@
1
+ /**
2
+ * groups/ltm.ts — LTM (Long-Term Memory) HTTP API group
3
+ *
4
+ * 외부 앱(chowriter 등)이 saeeol LTM에 기억을 저장/검색하는 엔드포인트.
5
+ */
6
+
7
+ import { Schema } from "effect"
8
+ import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
9
+ import { Authorization } from "../middleware/authorization"
10
+ import { InstanceContextMiddleware } from "../middleware/instance-context"
11
+ import { WorkspaceRoutingMiddleware } from "../middleware/workspace-routing"
12
+ import { described } from "./metadata"
13
+
14
+ const root = "/ltm"
15
+
16
+ // Request schemas
17
+ const IngestPayload = Schema.Struct({
18
+ type: Schema.Literal("episodic", "semantic", "procedural"),
19
+ content: Schema.String,
20
+ summary: Schema.String,
21
+ projectID: Schema.optional(Schema.String),
22
+ sessionID: Schema.optional(Schema.String),
23
+ tags: Schema.optional(Schema.mutable(Schema.Array(Schema.String))),
24
+ })
25
+
26
+ const SearchPayload = Schema.Struct({
27
+ query: Schema.String,
28
+ topK: Schema.optional(Schema.Number),
29
+ minScore: Schema.optional(Schema.Number),
30
+ type: Schema.optional(Schema.Literal("episodic", "semantic", "procedural")),
31
+ projectID: Schema.optional(Schema.String),
32
+ })
33
+
34
+ const DeletePayload = Schema.Struct({
35
+ ids: Schema.mutable(Schema.Array(Schema.String)),
36
+ })
37
+
38
+ // Response schemas
39
+ const MemoryEntry = Schema.Struct({
40
+ id: Schema.String,
41
+ type: Schema.String,
42
+ summary: Schema.String,
43
+ content: Schema.String,
44
+ score: Schema.optional(Schema.Number),
45
+ metadata: Schema.Struct({
46
+ source: Schema.String,
47
+ timestamp: Schema.Number,
48
+ projectID: Schema.optional(Schema.String),
49
+ tags: Schema.mutable(Schema.Array(Schema.String)),
50
+ }),
51
+ })
52
+
53
+ const IngestResponse = Schema.Struct({
54
+ id: Schema.String,
55
+ success: Schema.Boolean,
56
+ })
57
+
58
+ const SearchResponse = Schema.Struct({
59
+ memories: Schema.mutable(Schema.Array(MemoryEntry)),
60
+ count: Schema.Number,
61
+ })
62
+
63
+ const DeleteResponse = Schema.Struct({
64
+ removed: Schema.Number,
65
+ })
66
+
67
+ export const LTMHttpApi = HttpApi.make("ltm")
68
+ .add(
69
+ HttpApiGroup.make(root, "ltm")
70
+ .add(
71
+ HttpApiEndpoint.post("ingest", `${root}/ingest`)
72
+ .setPayload(IngestPayload)
73
+ .addSuccess(IngestResponse)
74
+ .annotateMerge(OpenApi.annotations({ identifier: "ltm.ingest", summary: "Store a memory in LTM" })),
75
+ )
76
+ .add(
77
+ HttpApiEndpoint.post("search", `${root}/search`)
78
+ .setPayload(SearchPayload)
79
+ .addSuccess(SearchResponse)
80
+ .annotateMerge(OpenApi.annotations({ identifier: "ltm.search", summary: "Search LTM memories by query" })),
81
+ )
82
+ .add(
83
+ HttpApiEndpoint.post("delete", `${root}/delete`)
84
+ .setPayload(DeletePayload)
85
+ .addSuccess(DeleteResponse)
86
+ .annotateMerge(OpenApi.annotations({ identifier: "ltm.delete", summary: "Delete LTM memories by ID" })),
87
+ )
88
+ .add(
89
+ HttpApiEndpoint.get("status", `${root}/status`)
90
+ .addSuccess(Schema.Struct({ enabled: Schema.Boolean, memoryCount: Schema.Number }))
91
+ .annotateMerge(OpenApi.annotations({ identifier: "ltm.status", summary: "Get LTM status" })),
92
+ ),
93
+ )
@@ -0,0 +1,118 @@
1
+ /**
2
+ * handlers/ltm.ts — LTM HTTP API handlers
3
+ *
4
+ * 외부 앱이 saeeol LTM에 기억을 저장/검색/삭제.
5
+ * 임베딩은 로컬 서버가 처리, 클라이언트는 텍스트만 보냄.
6
+ */
7
+
8
+ import { Effect } from "effect"
9
+ import * as Log from "@saeeol/core/util/log"
10
+ import * as HttpApiBuilder from "effect/unstable/httpapi"
11
+ import * as LTM from "@/ltm"
12
+ import * as Embedder from "@/provider/local/embedder"
13
+ import { LTMHttpApi } from "../groups/ltm"
14
+
15
+ const log = Log.create({ service: "server/handlers/ltm" })
16
+
17
+ export const ltmHandlers = HttpApiBuilder.group(LTMHttpApi, "ltm", (handlers) =>
18
+ Effect.gen(function* () {
19
+ const config = LTM.Config.DEFAULT_LTM_CONFIG
20
+
21
+ return handlers
22
+ .handle("ingest", ({ payload }) =>
23
+ Effect.gen(function* () {
24
+ if (!config.enabled) {
25
+ yield* log.info("LTM ingest skipped — disabled")
26
+ return HttpApiBuilder.fail({ status: 400 as const, body: { message: "LTM is disabled" } })
27
+ }
28
+
29
+ const embedderStatus = Embedder.status()
30
+ if (!embedderStatus || embedderStatus.status !== "running") {
31
+ yield* log.info("LTM ingest skipped — embedder not running")
32
+ return HttpApiBuilder.fail({ status: 503 as const, body: { message: "Embedding server not running" } })
33
+ }
34
+
35
+ const vector = yield* Effect.tryPromise(() => Embedder.embedOne(payload.summary))
36
+ const id = `${payload.type[0]}:${payload.projectID ?? "global"}:${Date.now()}`
37
+ const memory: LTM.Memory = {
38
+ id,
39
+ type: payload.type,
40
+ content: payload.content.slice(0, 2000),
41
+ summary: payload.summary,
42
+ vector,
43
+ metadata: {
44
+ source: `external:${payload.projectID ?? "unknown"}`,
45
+ timestamp: Date.now(),
46
+ projectID: payload.projectID,
47
+ sessionID: payload.sessionID,
48
+ tags: payload.tags ?? [],
49
+ },
50
+ }
51
+
52
+ yield* Effect.tryPromise(() => LTM.Store.upsert(memory))
53
+ yield* log.info("LTM ingest", { id, type: payload.type })
54
+
55
+ return { id, success: true }
56
+ }),
57
+ )
58
+ .handle("search", ({ payload }) =>
59
+ Effect.gen(function* () {
60
+ if (!config.enabled) {
61
+ return { memories: [], count: 0 }
62
+ }
63
+
64
+ const embedderStatus = Embedder.status()
65
+ if (!embedderStatus || embedderStatus.status !== "running") {
66
+ return { memories: [], count: 0 }
67
+ }
68
+
69
+ const vector = yield* Effect.tryPromise(() => Embedder.embedOne(payload.query))
70
+ const memories = yield* Effect.tryPromise(() =>
71
+ LTM.Store.search(vector, {
72
+ topK: payload.topK ?? config.retrieval.topK,
73
+ minScore: payload.minScore ?? config.retrieval.minScore,
74
+ type: payload.type,
75
+ }),
76
+ )
77
+
78
+ // projectID 필터 (store 레벨에서 안 되면 여기서)
79
+ const filtered = payload.projectID
80
+ ? memories.filter((m) => m.metadata.projectID === payload.projectID)
81
+ : memories
82
+
83
+ // vector는 응답에서 제거 (용량 절약)
84
+ const lean = filtered.map((m) => ({
85
+ id: m.id,
86
+ type: m.type,
87
+ summary: m.summary,
88
+ content: m.content,
89
+ score: m.score,
90
+ metadata: {
91
+ source: m.metadata.source,
92
+ timestamp: m.metadata.timestamp,
93
+ projectID: m.metadata.projectID,
94
+ tags: m.metadata.tags,
95
+ },
96
+ }))
97
+
98
+ return { memories: lean, count: lean.length }
99
+ }),
100
+ )
101
+ .handle("delete", ({ payload }) =>
102
+ Effect.gen(function* () {
103
+ yield* Effect.tryPromise(() => LTM.Store.remove(payload.ids))
104
+ return { removed: payload.ids.length }
105
+ }),
106
+ )
107
+ .handle("status", () =>
108
+ Effect.gen(function* () {
109
+ const embedder = Embedder.status()
110
+ const count = yield* Effect.tryPromise(() => LTM.Store.count())
111
+ return {
112
+ enabled: config.enabled && embedder?.status === "running",
113
+ memoryCount: count,
114
+ }
115
+ }),
116
+ )
117
+ }),
118
+ )
@@ -27,7 +27,9 @@ import { EventRoutes } from "./event"
27
27
  import { SyncRoutes } from "./sync"
28
28
  import { InstanceMiddleware } from "./middleware"
29
29
  import { jsonRequest } from "./trace"
30
- import { register as registerSaeeolRoutes } from "@/saeeol/server/instance"
30
+ import { register as registerSaeeolRoutes } from "@/saeeol/server/instance"
31
+ import * as LTM from "@/ltm"
32
+ import * as Embedder from "@/provider/local/embedder"
31
33
 
32
34
  export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => {
33
35
  const app = new Hono()
@@ -47,6 +49,99 @@ export const InstanceRoutes = (upgrade: UpgradeWebSocket): Hono => {
47
49
  .route("/", EventRoutes())
48
50
  .route("/mcp", McpRoutes())
49
51
  .route("/tui", TuiRoutes())
52
+ // ── LTM (Long-Term Memory) ──
53
+ .post(
54
+ "/ltm/ingest",
55
+ describeRoute({
56
+ summary: "Store a memory in LTM",
57
+ operationId: "ltm.ingest",
58
+ responses: { 200: { description: "Memory stored" } },
59
+ }),
60
+ async (c) => {
61
+ const body = await c.req.json<{ type: "episodic" | "semantic" | "procedural"; content: string; summary: string; projectID?: string; sessionID?: string; tags?: string[] }>()
62
+ const embedderStatus = Embedder.status()
63
+ if (!embedderStatus || embedderStatus.status !== "running") {
64
+ return c.json({ error: "Embedding server not running" }, 503)
65
+ }
66
+ const vector = await Embedder.embedOne(body.summary)
67
+ const id = `${body.type[0]}:${body.projectID ?? "global"}:${Date.now()}`
68
+ const memory: LTM.Memory = {
69
+ id,
70
+ type: body.type,
71
+ content: body.content.slice(0, 2000),
72
+ summary: body.summary,
73
+ vector,
74
+ metadata: {
75
+ source: `external:${body.projectID ?? "unknown"}`,
76
+ timestamp: Date.now(),
77
+ projectID: body.projectID,
78
+ sessionID: body.sessionID,
79
+ tags: body.tags ?? [],
80
+ },
81
+ }
82
+ await LTM.Store.upsert(memory)
83
+ return c.json({ id, success: true })
84
+ },
85
+ )
86
+ .post(
87
+ "/ltm/search",
88
+ describeRoute({
89
+ summary: "Search LTM memories by query",
90
+ operationId: "ltm.search",
91
+ responses: { 200: { description: "Search results" } },
92
+ }),
93
+ async (c) => {
94
+ const body = await c.req.json<{ query: string; topK?: number; minScore?: number; type?: "episodic" | "semantic" | "procedural"; projectID?: string }>()
95
+ const embedderStatus = Embedder.status()
96
+ if (!embedderStatus || embedderStatus.status !== "running") {
97
+ return c.json({ memories: [], count: 0 })
98
+ }
99
+ const vector = await Embedder.embedOne(body.query)
100
+ const memories = await LTM.Store.search(vector, {
101
+ topK: body.topK ?? 5,
102
+ minScore: body.minScore ?? 0.7,
103
+ type: body.type,
104
+ })
105
+ const filtered = body.projectID
106
+ ? memories.filter((m) => m.metadata.projectID === body.projectID)
107
+ : memories
108
+ const lean = filtered.map((m) => ({
109
+ id: m.id,
110
+ type: m.type,
111
+ summary: m.summary,
112
+ content: m.content,
113
+ score: m.score,
114
+ metadata: { source: m.metadata.source, timestamp: m.metadata.timestamp, projectID: m.metadata.projectID, tags: m.metadata.tags },
115
+ }))
116
+ return c.json({ memories: lean, count: lean.length })
117
+ },
118
+ )
119
+ .post(
120
+ "/ltm/delete",
121
+ describeRoute({
122
+ summary: "Delete LTM memories by ID",
123
+ operationId: "ltm.delete",
124
+ responses: { 200: { description: "Deleted" } },
125
+ }),
126
+ async (c) => {
127
+ const body = await c.req.json<{ ids: string[] }>()
128
+ await LTM.Store.remove(body.ids)
129
+ return c.json({ removed: body.ids.length })
130
+ },
131
+ )
132
+ .get(
133
+ "/ltm/status",
134
+ describeRoute({
135
+ summary: "Get LTM status",
136
+ operationId: "ltm.status",
137
+ responses: { 200: { description: "LTM status" } },
138
+ }),
139
+ async (c) => {
140
+ const embedder = Embedder.status()
141
+ const count = await LTM.Store.count()
142
+ return c.json({ enabled: embedder?.status === "running", memoryCount: count })
143
+ },
144
+ )
50
145
  .post(
51
146
  "/instance/dispose",
52
147
  describeRoute({
@@ -0,0 +1 @@
1
+ [?9001h[?1004h[?25l]0;● 새얼[?25h
@@ -0,0 +1 @@
1
+ [?9001h[?1004h[?25l[?25h
@@ -0,0 +1,110 @@
1
+ === input-typed (280 bytes) ===
2
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
3
+
4
+
5
+ === input-cursor-lr (280 bytes) ===
6
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
7
+
8
+
9
+ === input-cursor-ud (280 bytes) ===
10
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
11
+
12
+
13
+ === input-cursor-home-end (280 bytes) ===
14
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
15
+
16
+
17
+ === input-ctrl-a (280 bytes) ===
18
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
19
+
20
+
21
+ === input-ctrl-e (280 bytes) ===
22
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
23
+
24
+
25
+ === input-ctrl-b (280 bytes) ===
26
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
27
+
28
+
29
+ === input-ctrl-f (280 bytes) ===
30
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
31
+
32
+
33
+ === input-alt-f (280 bytes) ===
34
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
35
+
36
+
37
+ === input-alt-b (280 bytes) ===
38
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
39
+
40
+
41
+ === input-ctrl-left (280 bytes) ===
42
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
43
+
44
+
45
+ === input-ctrl-right (280 bytes) ===
46
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
47
+
48
+
49
+ === input-select-lr (280 bytes) ===
50
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
51
+
52
+
53
+ === input-select-ud (280 bytes) ===
54
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
55
+
56
+
57
+ === input-alt-a (280 bytes) ===
58
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
59
+
60
+
61
+ === input-alt-e (280 bytes) ===
62
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
63
+
64
+
65
+ === input-backspace (280 bytes) ===
66
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
67
+
68
+
69
+ === input-delete (280 bytes) ===
70
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
71
+
72
+
73
+ === input-ctrl-k (280 bytes) ===
74
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
75
+
76
+
77
+ === input-ctrl-u (280 bytes) ===
78
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
79
+
80
+
81
+ === input-ctrl-w (280 bytes) ===
82
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
83
+
84
+
85
+ === input-ctrl-d (280 bytes) ===
86
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
87
+
88
+
89
+ === input-alt-d (280 bytes) ===
90
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
91
+
92
+
93
+ === input-clear-ctrl-c (280 bytes) ===
94
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
95
+
96
+
97
+ === input-undo-ctrl-minus (280 bytes) ===
98
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
99
+
100
+
101
+ === input-redo (280 bytes) ===
102
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
103
+
104
+
105
+ === input-submit (280 bytes) ===
106
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception
107
+
108
+
109
+ === input-cleanup (280 bytes) ===
110
+ s service=default e=Export named 'jsx' not found in module 'C:\Users\PC\Desktop\SAEEOL\node_modules\.bun\@opentui+solid@0.2.2+37848aaf691d3d45\node_modules\@opentui\solid\jsx-runtime.d.ts'. exception