@smart-coders-hq/opencode-model-fallback 1.0.3 → 1.0.4

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/README.md CHANGED
@@ -75,23 +75,25 @@ Place `model-fallback.json` at either:
75
75
  "429"
76
76
  ],
77
77
  "logging": true,
78
+ "logLevel": "info",
78
79
  "logPath": "~/.local/share/opencode/logs/model-fallback.log"
79
80
  }
80
81
  ```
81
82
 
82
83
  ### All config fields
83
84
 
84
- | Field | Type | Default | Description |
85
- | ------------------------------- | -------- | ------------------------------------------------- | ------------------------------------------------------------------------ |
86
- | `enabled` | boolean | `true` | Enable/disable the plugin |
87
- | `defaults.fallbackOn` | string[] | all categories | Error categories that trigger fallback |
88
- | `defaults.cooldownMs` | number | `300000` (5 min) | How long before a rate-limited model enters cooldown. Min: 10000 |
89
- | `defaults.retryOriginalAfterMs` | number | `900000` (15 min) | How long before a cooldown model is considered healthy again. Min: 10000 |
90
- | `defaults.maxFallbackDepth` | number | `3` | Maximum number of fallbacks per session. Max: 10 |
91
- | `agents` | object | `{"*": {}}` | Per-agent fallback chains (see below) |
92
- | `patterns` | string[] | see defaults | Case-insensitive substrings to match in retry messages |
93
- | `logging` | boolean | `true` | Write structured logs to `logPath` |
94
- | `logPath` | string | `~/.local/share/opencode/logs/model-fallback.log` | Log file path (must be within `$HOME`) |
85
+ | Field | Type | Default | Description |
86
+ | ------------------------------- | -------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
87
+ | `enabled` | boolean | `true` | Enable/disable the plugin |
88
+ | `defaults.fallbackOn` | string[] | all categories | Error categories that trigger fallback |
89
+ | `defaults.cooldownMs` | number | `300000` (5 min) | How long before a rate-limited model enters cooldown. Min: 10000 |
90
+ | `defaults.retryOriginalAfterMs` | number | `900000` (15 min) | How long before a cooldown model is considered healthy again. Min: 10000 |
91
+ | `defaults.maxFallbackDepth` | number | `3` | Maximum number of fallbacks per session. Max: 10 |
92
+ | `agents` | object | `{"*": {}}` | Per-agent fallback chains (see below) |
93
+ | `patterns` | string[] | see defaults | Case-insensitive substrings to match in retry messages |
94
+ | `logging` | boolean | `true` | Write structured logs to `logPath` |
95
+ | `logLevel` | string | `"info"` | Minimum log level written to file: `"info"` suppresses debug noise, `"debug"` logs every event (useful for incident investigation) |
96
+ | `logPath` | string | `~/.local/share/opencode/logs/model-fallback.log` | Log file path (must be within `$HOME`) |
95
97
 
96
98
  ### Error categories
97
99
 
@@ -210,6 +212,8 @@ tail -f ~/.local/share/opencode/logs/model-fallback.log | jq .
210
212
 
211
213
  Key log events: `plugin.init`, `retry.detected`, `fallback.success`, `fallback.exhausted`, `health.transition`, `recovery.available`
212
214
 
215
+ To see the full event stream (including `event.received` and `retry.nomatch`), set `"logLevel": "debug"` in your config and restart OpenCode.
216
+
213
217
  ## Release automation
214
218
 
215
219
  - Uses **Conventional Commits** + `semantic-release` for automated versioning/changelog/release notes
@@ -223,7 +227,7 @@ Key log events: `plugin.init`, `retry.detected`, `fallback.success`, `fallback.e
223
227
  ```bash
224
228
  bun install
225
229
  bun run lint # lint checks
226
- bun test # 101 tests
230
+ bun test # 137 tests across 11 files
227
231
  bunx tsc --noEmit # type check
228
232
  bun run build # build to dist/
229
233
  ```
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/plugin.ts
2
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync } from "fs";
2
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
3
3
  import { dirname as dirname2, join as join4 } from "path";
4
4
  import { homedir as homedir5 } from "os";
5
5
 
@@ -43,6 +43,7 @@ var DEFAULT_CONFIG = {
43
43
  },
44
44
  patterns: DEFAULT_PATTERNS,
45
45
  logging: true,
46
+ logLevel: "info",
46
47
  logPath: DEFAULT_LOG_PATH,
47
48
  agentDirs: []
48
49
  };
@@ -80,6 +81,7 @@ var pluginConfigSchema = z.object({
80
81
  agents: z.record(z.string(), agentConfig).optional(),
81
82
  patterns: z.array(z.string()).optional(),
82
83
  logging: z.boolean().optional(),
84
+ logLevel: z.enum(["debug", "info"]).optional(),
83
85
  logPath: logPathSchema.optional(),
84
86
  agentDirs: z.array(z.string()).optional()
85
87
  }).strict();
@@ -96,6 +98,7 @@ function parseConfig(raw) {
96
98
  "agents",
97
99
  "patterns",
98
100
  "logging",
101
+ "logLevel",
99
102
  "logPath",
100
103
  "agentDirs"
101
104
  ]);
@@ -211,6 +214,14 @@ function parseConfig(raw) {
211
214
  warnings.push(`Config warning at logging: ${loggingResult.error.issues[0].message} — using default`);
212
215
  }
213
216
  }
217
+ if (obj.logLevel !== undefined) {
218
+ const logLevelResult = z.enum(["debug", "info"]).safeParse(obj.logLevel);
219
+ if (logLevelResult.success) {
220
+ config.logLevel = logLevelResult.data;
221
+ } else {
222
+ warnings.push(`Config warning at logLevel: ${logLevelResult.error.issues[0].message} — using default`);
223
+ }
224
+ }
214
225
  if (obj.logPath !== undefined) {
215
226
  const logPathResult = logPathSchema.safeParse(obj.logPath);
216
227
  if (logPathResult.success) {
@@ -249,6 +260,7 @@ function mergeWithDefaults(raw) {
249
260
  agents: raw.agents ?? def.agents,
250
261
  patterns: raw.patterns ?? def.patterns,
251
262
  logging: raw.logging ?? def.logging,
263
+ logLevel: raw.logLevel ?? def.logLevel,
252
264
  logPath,
253
265
  agentDirs: raw.agentDirs ?? def.agentDirs
254
266
  };
@@ -280,9 +292,7 @@ function migrateOldConfig(old) {
280
292
  }
281
293
 
282
294
  // src/config/agent-loader.ts
283
- import { existsSync, readFileSync, readdirSync, realpathSync, statSync } from "fs";
284
- import { homedir as homedir3 } from "os";
285
- import { basename, extname, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2 } from "path";
295
+ import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "fs";
286
296
 
287
297
  // node_modules/js-yaml/dist/js-yaml.mjs
288
298
  /*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */
@@ -2970,6 +2980,8 @@ var jsYaml = {
2970
2980
  };
2971
2981
 
2972
2982
  // src/config/agent-loader.ts
2983
+ import { homedir as homedir3 } from "os";
2984
+ import { basename, extname, isAbsolute as isAbsolute2, join as join2, relative as relative2, resolve as resolve2 } from "path";
2973
2985
  var MODEL_KEY_RE2 = /^[a-zA-Z0-9_-]{1,100}\/[a-zA-Z0-9._-]{1,100}$/;
2974
2986
  function isPathInside(baseDir, targetPath) {
2975
2987
  const rel = relative2(baseDir, targetPath);
@@ -3067,7 +3079,7 @@ function parseAgentFile(filePath) {
3067
3079
  const validModels = [];
3068
3080
  for (const m of models) {
3069
3081
  if (typeof m !== "string" || !MODEL_KEY_RE2.test(m)) {
3070
- console.warn(`[model-fallback] agent-loader: skipping invalid model key ${JSON.stringify(m)} in ${filePath}`);
3082
+ console.warn(`[model-fallback] agent-loader: skipping invalid model key ${JSON.stringify(m)} in ${basename(filePath)}`);
3071
3083
  continue;
3072
3084
  }
3073
3085
  validModels.push(m);
@@ -3077,7 +3089,7 @@ function parseAgentFile(filePath) {
3077
3089
  const name = typeof obj.name === "string" && obj.name.length > 0 ? obj.name : stemName(filePath);
3078
3090
  return { name, config: { fallbackModels: validModels } };
3079
3091
  } catch (err) {
3080
- console.warn(`[model-fallback] agent-loader: failed to parse ${filePath}:`, err);
3092
+ console.warn(`[model-fallback] agent-loader: failed to parse ${basename(filePath)}:`, err);
3081
3093
  return null;
3082
3094
  }
3083
3095
  }
@@ -3185,18 +3197,20 @@ function loadConfig(directory) {
3185
3197
  }
3186
3198
 
3187
3199
  // src/logging/logger.ts
3188
- import { appendFileSync, mkdirSync } from "fs";
3200
+ import { appendFileSync, existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
3189
3201
  import { dirname } from "path";
3190
3202
 
3191
3203
  class Logger {
3192
3204
  client;
3193
3205
  logPath;
3194
3206
  enabled;
3207
+ minLevel;
3195
3208
  dirCreated = false;
3196
- constructor(client, logPath, enabled) {
3209
+ constructor(client, logPath, enabled, minLevel = "info") {
3197
3210
  this.client = client;
3198
3211
  this.logPath = logPath;
3199
3212
  this.enabled = enabled;
3213
+ this.minLevel = minLevel;
3200
3214
  }
3201
3215
  log(level, event, fields = {}) {
3202
3216
  const entry = {
@@ -3205,7 +3219,8 @@ class Logger {
3205
3219
  event,
3206
3220
  ...fields
3207
3221
  };
3208
- if (this.enabled) {
3222
+ const shouldWrite = this.enabled && (this.minLevel === "debug" || level !== "debug");
3223
+ if (shouldWrite) {
3209
3224
  this.writeToFile(entry);
3210
3225
  }
3211
3226
  if (level !== "debug") {
@@ -3230,9 +3245,12 @@ class Logger {
3230
3245
  writeToFile(entry) {
3231
3246
  try {
3232
3247
  if (!this.dirCreated) {
3233
- mkdirSync(dirname(this.logPath), { recursive: true });
3248
+ mkdirSync(dirname(this.logPath), { recursive: true, mode: 448 });
3234
3249
  this.dirCreated = true;
3235
3250
  }
3251
+ if (!existsSync3(this.logPath)) {
3252
+ writeFileSync(this.logPath, "", { mode: 384 });
3253
+ }
3236
3254
  appendFileSync(this.logPath, JSON.stringify(entry) + `
3237
3255
  `, "utf-8");
3238
3256
  } catch {}
@@ -3320,10 +3338,12 @@ class ModelHealthStore {
3320
3338
  class SessionStateStore {
3321
3339
  store = new Map;
3322
3340
  get(sessionId) {
3323
- if (!this.store.has(sessionId)) {
3324
- this.store.set(sessionId, this.newState(sessionId));
3341
+ let state = this.store.get(sessionId);
3342
+ if (!state) {
3343
+ state = this.newState(sessionId);
3344
+ this.store.set(sessionId, state);
3325
3345
  }
3326
- return this.store.get(sessionId);
3346
+ return state;
3327
3347
  }
3328
3348
  acquireLock(sessionId) {
3329
3349
  const state = this.get(sessionId);
@@ -3536,7 +3556,13 @@ function resolveFallbackModel(chain, currentModel, health) {
3536
3556
  // src/replay/message-converter.ts
3537
3557
  function convertPartsForPrompt(parts) {
3538
3558
  const result = [];
3559
+ if (!parts || !Array.isArray(parts)) {
3560
+ return result;
3561
+ }
3539
3562
  for (const part of parts) {
3563
+ if (!part || typeof part !== "object" || !("type" in part)) {
3564
+ continue;
3565
+ }
3540
3566
  if (part.type === "text") {
3541
3567
  if (part.synthetic || part.ignored)
3542
3568
  continue;
@@ -3975,6 +4001,8 @@ function tryPreemptiveRedirect(sessionId, modelKey2, agentName, store, config, l
3975
4001
  }
3976
4002
  logger.info("preemptive.redirect", {
3977
4003
  sessionId,
4004
+ agentName,
4005
+ agentFile: sessionState.agentFile,
3978
4006
  from: modelKey2,
3979
4007
  to: fallbackModel
3980
4008
  });
@@ -3985,12 +4013,12 @@ function tryPreemptiveRedirect(sessionId, modelKey2, agentName, store, config, l
3985
4013
  // src/plugin.ts
3986
4014
  var createPlugin = async ({ client, directory }) => {
3987
4015
  const { config, path: configPath, warnings, migrated } = loadConfig(directory);
3988
- const logger = new Logger(client, config.logPath, config.logging);
4016
+ const logger = new Logger(client, config.logPath, config.logging, config.logLevel);
3989
4017
  const cmdPath = join4(homedir5(), ".config/opencode/commands/fallback-status.md");
3990
4018
  try {
3991
- if (!existsSync3(cmdPath)) {
4019
+ if (!existsSync4(cmdPath)) {
3992
4020
  mkdirSync2(dirname2(cmdPath), { recursive: true });
3993
- writeFileSync(cmdPath, `Call the fallback-status tool and display the full output.
4021
+ writeFileSync2(cmdPath, `Call the fallback-status tool and display the full output.
3994
4022
  `);
3995
4023
  }
3996
4024
  } catch (err) {
@@ -4060,6 +4088,7 @@ var createPlugin = async ({ client, directory }) => {
4060
4088
  return hooks;
4061
4089
  };
4062
4090
  async function handleEvent(event, client, store, config, logger, directory) {
4091
+ logger.debug("event.received", { type: event.type });
4063
4092
  if (event.type === "session.status") {
4064
4093
  const { sessionID, status } = event.properties;
4065
4094
  if (status.type === "retry") {
@@ -4101,6 +4130,7 @@ async function handleEvent(event, client, store, config, logger, directory) {
4101
4130
  }
4102
4131
  async function handleRetry(sessionId, message, client, store, config, logger, directory) {
4103
4132
  if (!matchesAnyPattern(message, config.patterns)) {
4133
+ logger.debug("retry.nomatch", { sessionId, message });
4104
4134
  return;
4105
4135
  }
4106
4136
  const category = classifyError(message);
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,eAAO,MAAM,gBAAgB,UAU5B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAmE,CAAC;AAEjG,eAAO,MAAM,cAAc,EAAE,YAiB5B,CAAC"}
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,eAAO,MAAM,gBAAgB,UAU5B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAmE,CAAC;AAEjG,eAAO,MAAM,cAAc,EAAE,YAkB5B,CAAC"}
@@ -18,6 +18,10 @@ export declare const pluginConfigSchema: z.ZodObject<{
18
18
  }, z.core.$strip>>>;
19
19
  patterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
20
20
  logging: z.ZodOptional<z.ZodBoolean>;
21
+ logLevel: z.ZodOptional<z.ZodEnum<{
22
+ debug: "debug";
23
+ info: "info";
24
+ }>>;
21
25
  logPath: z.ZodOptional<z.ZodString>;
22
26
  agentDirs: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
27
  }, z.core.$strict>;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2CxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;kBAUpB,CAAC;AAEZ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE3D,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG;IACzC,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CA6LA;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,aAAa,EAAE,YAAY,CAkBpF"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2CxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;kBAWpB,CAAC;AAEZ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE3D,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG;IACzC,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAyMA;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,aAAa,EAAE,YAAY,CAmBpF"}
@@ -11,8 +11,9 @@ export declare class Logger {
11
11
  private client;
12
12
  private logPath;
13
13
  private enabled;
14
+ private minLevel;
14
15
  private dirCreated;
15
- constructor(client: Client, logPath: string, enabled: boolean);
16
+ constructor(client: Client, logPath: string, enabled: boolean, minLevel?: "debug" | "info");
16
17
  log(level: LogLevel, event: string, fields?: Record<string, unknown>): void;
17
18
  info(event: string, fields?: Record<string, unknown>): void;
18
19
  warn(event: string, fields?: Record<string, unknown>): void;
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/logging/logger.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,KAAK,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;AAEpC,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAM7D,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAyB/E,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,OAAO,CAAC,WAAW;CAWpB"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/logging/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,KAAK,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;AAEpC,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,QAAQ,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,UAAU,CAAS;gBAGzB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,GAAE,OAAO,GAAG,MAAe;IAQrC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IA0B/E,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,OAAO,CAAC,WAAW;CAepB"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAS,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAI9C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUjD,eAAO,MAAM,YAAY,EAAE,MAwG1B,CAAC;AAEF,wBAAsB,WAAW,CAC/B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACvC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,QAAQ,CAAC,EAC/C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAuDf;AAoFD,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACvC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,QAAQ,CAAC,EAChD,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAuBf"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAS,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAI9C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUjD,eAAO,MAAM,YAAY,EAAE,MAwG1B,CAAC;AAEF,wBAAsB,WAAW,CAC/B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACvC,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,QAAQ,CAAC,EAC/C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAyDf;AAqFD,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACvC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,QAAQ,CAAC,EAChD,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAuBf"}
@@ -1 +1 @@
1
- {"version":3,"file":"preemptive.d.ts","sourceRoot":"","sources":["../../src/preemptive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAIlD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,GACb,gBAAgB,CA6ClB"}
1
+ {"version":3,"file":"preemptive.d.ts","sourceRoot":"","sources":["../../src/preemptive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAIlD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,MAAM,GACb,gBAAgB,CA+ClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"message-converter.d.ts","sourceRoot":"","sources":["../../../src/replay/message-converter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,KAAK,UAAU,GACX;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,UAAU,EAAE,CA+BjE"}
1
+ {"version":3,"file":"message-converter.d.ts","sourceRoot":"","sources":["../../../src/replay/message-converter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,KAAK,UAAU,GACX;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,UAAU,EAAE,CAyCjE"}
@@ -1,4 +1,4 @@
1
- import type { SessionFallbackState, ModelKey, ErrorCategory } from "../types.js";
1
+ import type { ErrorCategory, ModelKey, SessionFallbackState } from "../types.js";
2
2
  export declare class SessionStateStore {
3
3
  private store;
4
4
  get(sessionId: string): SessionFallbackState;
@@ -1 +1 @@
1
- {"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../../src/state/session-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAiB,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhG,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAA2C;IAExD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB;IAO5C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IASvC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKpC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,OAAO;IAM7D,cAAc,CACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,QAAQ,EACnB,OAAO,EAAE,QAAQ,EACjB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,IAAI;IAmBP,wBAAwB,CACtB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,QAAQ,EACnB,OAAO,EAAE,QAAQ,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,IAAI;IAkBP,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI;IAQ1D,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKxD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKxD,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IASrC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI/B,MAAM,IAAI,oBAAoB,EAAE;IAIhC,OAAO,CAAC,QAAQ;CAcjB"}
1
+ {"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../../src/state/session-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAiB,QAAQ,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEhG,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAA2C;IAExD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB;IAS5C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IASvC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKpC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,OAAO;IAM7D,cAAc,CACZ,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,QAAQ,EACnB,OAAO,EAAE,QAAQ,EACjB,MAAM,EAAE,aAAa,EACrB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,IAAI;IAmBP,wBAAwB,CACtB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,QAAQ,EACnB,OAAO,EAAE,QAAQ,EACjB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,IAAI;IAkBP,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,IAAI;IAQ1D,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKxD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKxD,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IASrC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI/B,MAAM,IAAI,oBAAoB,EAAE;IAIhC,OAAO,CAAC,QAAQ;CAcjB"}
@@ -45,6 +45,7 @@ export interface PluginConfig {
45
45
  agents: Record<string, AgentConfig>;
46
46
  patterns: string[];
47
47
  logging: boolean;
48
+ logLevel: "debug" | "info";
48
49
  logPath: string;
49
50
  agentDirs: string[];
50
51
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,gBAAgB,GAChB,KAAK,GACL,SAAS,GACT,YAAY,GACZ,SAAS,CAAC;AAEd,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,cAAc,GAAG,UAAU,CAAC;AAElE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,QAAQ,CAAC;IACpB,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,UAAU,GAAG,YAAY,CAAC;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,wBAAwB,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,QAAQ,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAE9B,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,gBAAgB,GAChB,KAAK,GACL,SAAS,GACT,YAAY,GACZ,SAAS,CAAC;AAEd,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,cAAc,GAAG,UAAU,CAAC;AAElE,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,QAAQ,CAAC;IACpB,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,UAAU,GAAG,YAAY,CAAC;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,wBAAwB,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,QAAQ,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smart-coders-hq/opencode-model-fallback",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Ordered model fallback chains with health tracking for OpenCode",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -19,7 +19,7 @@
19
19
  "lint": "biome lint .",
20
20
  "lint:fix": "biome lint --write .",
21
21
  "format": "biome format --write .",
22
- "format:check": "biome format --check .",
22
+ "format:check": "biome ci .",
23
23
  "release": "semantic-release"
24
24
  },
25
25
  "files": [