rimuru-ai 1.19.0 → 1.19.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli/cmd/tui.ts +57 -36
- package/src/config/config.ts +42 -1
- package/src/session/retry.ts +1 -14
package/package.json
CHANGED
package/src/cli/cmd/tui.ts
CHANGED
|
@@ -126,22 +126,6 @@ export const TuiThreadCommand = cmd({
|
|
|
126
126
|
}
|
|
127
127
|
const cwd = Filesystem.resolve(process.cwd())
|
|
128
128
|
|
|
129
|
-
const worker = new Worker(file)
|
|
130
|
-
const client = Rpc.client<typeof rpc>(worker)
|
|
131
|
-
const reload = () => {
|
|
132
|
-
client.call("reload", undefined).catch(() => {})
|
|
133
|
-
}
|
|
134
|
-
process.on("SIGUSR2", reload)
|
|
135
|
-
|
|
136
|
-
let stopped = false
|
|
137
|
-
const stop = async () => {
|
|
138
|
-
if (stopped) return
|
|
139
|
-
stopped = true
|
|
140
|
-
process.off("SIGUSR2", reload)
|
|
141
|
-
await withTimeout(client.call("shutdown", undefined), 5000).catch(() => {})
|
|
142
|
-
worker.terminate()
|
|
143
|
-
}
|
|
144
|
-
|
|
145
129
|
const prompt = await input(args.prompt)
|
|
146
130
|
const config = await TuiConfig.get()
|
|
147
131
|
|
|
@@ -154,17 +138,62 @@ export const TuiThreadCommand = cmd({
|
|
|
154
138
|
network.port !== 0 ||
|
|
155
139
|
network.hostname !== "127.0.0.1"
|
|
156
140
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
141
|
+
let transport: { url: string; fetch?: typeof fetch; events?: EventSource }
|
|
142
|
+
let stop: () => Promise<void>
|
|
143
|
+
let onSnapshot: (() => Promise<string[]>) | undefined
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const worker = new Worker(file)
|
|
147
|
+
const client = Rpc.client<typeof rpc>(worker)
|
|
148
|
+
|
|
149
|
+
const reload = () => {
|
|
150
|
+
client.call("reload", undefined).catch(() => {})
|
|
151
|
+
}
|
|
152
|
+
process.on("SIGUSR2", reload)
|
|
153
|
+
|
|
154
|
+
let stopped = false
|
|
155
|
+
stop = async () => {
|
|
156
|
+
if (stopped) return
|
|
157
|
+
stopped = true
|
|
158
|
+
process.off("SIGUSR2", reload)
|
|
159
|
+
await withTimeout(client.call("shutdown", undefined), 5000).catch(() => {})
|
|
160
|
+
worker.terminate()
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
transport = external
|
|
164
|
+
? {
|
|
165
|
+
url: (await client.call("server", network)).url,
|
|
166
|
+
fetch: undefined,
|
|
167
|
+
events: undefined,
|
|
168
|
+
}
|
|
169
|
+
: {
|
|
170
|
+
url: "http://rimuru-ai.internal",
|
|
171
|
+
fetch: createWorkerFetch(client),
|
|
172
|
+
events: createEventSource(client),
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
onSnapshot = async () => {
|
|
176
|
+
const tui = writeHeapSnapshot("tui.heapsnapshot")
|
|
177
|
+
const server = await client.call("snapshot", undefined)
|
|
178
|
+
return [tui, server]
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
setTimeout(() => {
|
|
182
|
+
client.call("checkUpgrade", { directory: cwd }).catch(() => {})
|
|
183
|
+
}, 1000).unref?.()
|
|
184
|
+
} catch {
|
|
185
|
+
UI.error("Worker unavailable, running in single-process mode")
|
|
186
|
+
const { Server } = await import("@/server/server")
|
|
187
|
+
const server = await Server.listen(network)
|
|
188
|
+
transport = {
|
|
189
|
+
url: server.url.toString(),
|
|
190
|
+
fetch: undefined,
|
|
191
|
+
events: undefined,
|
|
192
|
+
}
|
|
193
|
+
stop = async () => {
|
|
194
|
+
await server.stop(true).catch(() => {})
|
|
195
|
+
}
|
|
196
|
+
}
|
|
168
197
|
|
|
169
198
|
try {
|
|
170
199
|
await validateSession({
|
|
@@ -179,10 +208,6 @@ export const TuiThreadCommand = cmd({
|
|
|
179
208
|
return
|
|
180
209
|
}
|
|
181
210
|
|
|
182
|
-
setTimeout(() => {
|
|
183
|
-
client.call("checkUpgrade", { directory: cwd }).catch(() => {})
|
|
184
|
-
}, 1000).unref?.()
|
|
185
|
-
|
|
186
211
|
try {
|
|
187
212
|
const { Effect } = await import("effect")
|
|
188
213
|
const { run } = await import("../tui/layer")
|
|
@@ -190,11 +215,7 @@ export const TuiThreadCommand = cmd({
|
|
|
190
215
|
await Effect.runPromise(
|
|
191
216
|
run({
|
|
192
217
|
url: transport.url,
|
|
193
|
-
|
|
194
|
-
const tui = writeHeapSnapshot("tui.heapsnapshot")
|
|
195
|
-
const server = await client.call("snapshot", undefined)
|
|
196
|
-
return [tui, server]
|
|
197
|
-
},
|
|
218
|
+
onSnapshot,
|
|
198
219
|
config,
|
|
199
220
|
pluginHost: createLegacyTuiPluginHost(),
|
|
200
221
|
directory: cwd,
|
package/src/config/config.ts
CHANGED
|
@@ -418,6 +418,47 @@ export const layer = Layer.effect(
|
|
|
418
418
|
yield* Effect.logDebug("loading config from RIMURU_CONFIG_DIR", { path: Flag.RIMURU_CONFIG_DIR })
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
// @ts-ignore - virtual module, only exists in compiled binary (see script/build.ts createEmbeddedPluginBundle)
|
|
422
|
+
const loadPluginBundle = (): Promise<string | null> => import("plugin-bundle.gen.ts").then((m) => (m.default as any)?.text?.() ?? null).catch(() => null)
|
|
423
|
+
|
|
424
|
+
const writePluginFallback = (dir: string): Effect.Effect<void> =>
|
|
425
|
+
Effect.gen(function* () {
|
|
426
|
+
yield* Effect.logWarning("background dependency install failed, using embedded plugin fallback", { dir })
|
|
427
|
+
const pluginDir = path.join(dir, "node_modules", "@rimurucode-ai", "plugin")
|
|
428
|
+
const distDir = path.join(pluginDir, "dist")
|
|
429
|
+
|
|
430
|
+
const content = yield* Effect.promise(() => loadPluginBundle())
|
|
431
|
+
if (!content) {
|
|
432
|
+
yield* Effect.logInfo("plugin-bundle.gen.ts not available (dev mode?), cannot write fallback")
|
|
433
|
+
return
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
yield* Effect.promise(() => fsNode.mkdir(distDir, { recursive: true }))
|
|
437
|
+
|
|
438
|
+
yield* fs.writeFileString(
|
|
439
|
+
path.join(pluginDir, "package.json"),
|
|
440
|
+
JSON.stringify({
|
|
441
|
+
name: "@rimurucode-ai/plugin",
|
|
442
|
+
version: InstallationLocal ? "0.0.0" : InstallationVersion,
|
|
443
|
+
type: "module",
|
|
444
|
+
main: "./dist/index.js",
|
|
445
|
+
exports: {
|
|
446
|
+
".": { default: "./dist/index.js" },
|
|
447
|
+
"./tool": { default: "./dist/tool.js" },
|
|
448
|
+
},
|
|
449
|
+
}),
|
|
450
|
+
).pipe(Effect.orDie)
|
|
451
|
+
|
|
452
|
+
yield* fs.writeFileString(
|
|
453
|
+
path.join(distDir, "index.js"),
|
|
454
|
+
`export * from "./tool.js";\n`,
|
|
455
|
+
).pipe(Effect.orDie)
|
|
456
|
+
|
|
457
|
+
yield* fs.writeFileString(path.join(distDir, "tool.js"), content).pipe(Effect.orDie)
|
|
458
|
+
|
|
459
|
+
yield* Effect.logInfo("embedded plugin fallback written to disk", { dir: pluginDir })
|
|
460
|
+
})
|
|
461
|
+
|
|
421
462
|
const deps: Fiber.Fiber<void>[] = []
|
|
422
463
|
|
|
423
464
|
for (const dir of directories) {
|
|
@@ -447,7 +488,7 @@ export const layer = Layer.effect(
|
|
|
447
488
|
Effect.exit,
|
|
448
489
|
Effect.tap((exit) =>
|
|
449
490
|
Exit.isFailure(exit)
|
|
450
|
-
?
|
|
491
|
+
? writePluginFallback(dir)
|
|
451
492
|
: Effect.void,
|
|
452
493
|
),
|
|
453
494
|
Effect.asVoid,
|
package/src/session/retry.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type Err = ReturnType<NamedError["toObject"]>
|
|
|
9
9
|
|
|
10
10
|
export const GO_UPSELL_MESSAGE = "Free usage exceeded, subscribe to Go"
|
|
11
11
|
export const GO_UPSELL_URL = "https://github.com/gowdaman-dev/rimuru-ai/go"
|
|
12
|
-
export type RetryReason = "
|
|
12
|
+
export type RetryReason = "account_rate_limit" | (string & {})
|
|
13
13
|
|
|
14
14
|
export type Retryable = {
|
|
15
15
|
message: string
|
|
@@ -73,19 +73,6 @@ export function retryable(error: Err, provider: string) {
|
|
|
73
73
|
// 5xx errors are transient server failures and should always be retried,
|
|
74
74
|
// even when the provider SDK doesn't explicitly mark them as retryable.
|
|
75
75
|
if (!error.data.isRetryable && !(status !== undefined && status >= 500)) return undefined
|
|
76
|
-
if (error.data.responseBody?.includes("FreeUsageLimitError")) {
|
|
77
|
-
return {
|
|
78
|
-
message: GO_UPSELL_MESSAGE,
|
|
79
|
-
action: {
|
|
80
|
-
reason: "free_tier_limit",
|
|
81
|
-
provider,
|
|
82
|
-
title: "Free limit reached",
|
|
83
|
-
message: "Subscribe to Rimuru Go for reliable access to the best open-source models, starting at $5/month.",
|
|
84
|
-
label: "subscribe",
|
|
85
|
-
link: GO_UPSELL_URL,
|
|
86
|
-
},
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
76
|
if (error.data.responseBody?.includes("GoUsageLimitError")) {
|
|
90
77
|
const body = parseJSON(error.data.responseBody)
|
|
91
78
|
const workspace = str(body?.metadata?.workspace)
|