rimuru-ai 1.19.0 → 1.19.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "1.19.0",
3
+ "version": "1.19.1",
4
4
  "name": "rimuru-ai",
5
5
  "description": "The open source AI coding agent — powered by Veldora",
6
6
  "keywords": [
@@ -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
- const transport = external
158
- ? {
159
- url: (await client.call("server", network)).url,
160
- fetch: undefined,
161
- events: undefined,
162
- }
163
- : {
164
- url: "http://rimuru-ai.internal",
165
- fetch: createWorkerFetch(client),
166
- events: createEventSource(client),
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
- async onSnapshot() {
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,
@@ -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
- ? Effect.logWarning("background dependency install failed", { dir, error: String(exit.cause) })
491
+ ? writePluginFallback(dir)
451
492
  : Effect.void,
452
493
  ),
453
494
  Effect.asVoid,
@@ -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 = "free_tier_limit" | "account_rate_limit" | (string & {})
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)