opencode-supabase 0.1.2-alpha.0 → 0.1.2-alpha.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/README.md CHANGED
@@ -22,7 +22,7 @@ Connect your account and ask your agent about Supabase capabilities.
22
22
 
23
23
  ## Bundled Supabase Skills
24
24
 
25
- `opencode-supabase` ships the official Supabase agent skills by default:
25
+ `opencode-supabase` ships the official [Supabase agent skills](https://github.com/supabase/agent-skills) by default:
26
26
 
27
27
  - `supabase`
28
28
  - `supabase-postgres-best-practices`
@@ -43,7 +43,7 @@ If you want Supabase tools without bundled skills, disable them in plugin option
43
43
 
44
44
  ### Select Individual Skills
45
45
 
46
- Per-skill config is a partial override. Omitted skills stay enabled.
46
+ Set a bundled skill name to `false` to disable only that skill. Omitted skills stay enabled. Unknown keys are ignored with a warning.
47
47
 
48
48
  ```json
49
49
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-supabase",
3
- "version": "0.1.2-alpha.0",
3
+ "version": "0.1.2-alpha.2",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Supabase integration with server and TUI components",
6
6
  "license": "Apache-2.0",
@@ -27,7 +27,7 @@ to recognize anti-patterns.
27
27
 
28
28
  Include specific metrics. Helps agents prioritize fixes.
29
29
 
30
- **Good:** "10x faster queries", "50% smaller index", "Eliminates N+1"
30
+ **Good:** "10x faster queries", "50% smaller index", "Eliminates N+1"
31
31
  **Bad:** "Faster", "Better", "More efficient"
32
32
 
33
33
  ### 4. Self-Contained Examples
@@ -13,7 +13,7 @@ const server: Plugin = async (input, options) => {
13
13
  return {
14
14
  config: async (config) => {
15
15
  registerSupabaseSkillPaths(config, options, {
16
- warn: (message, data) => logger.warn(message, data as Record<string, unknown>),
16
+ warn: logger.warn,
17
17
  });
18
18
  },
19
19
  auth: createSupabaseAuth(input, options, { logger }),
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
3
4
 
4
5
  export const BUNDLED_SUPABASE_SKILLS = [
5
6
  "supabase",
@@ -8,7 +9,7 @@ export const BUNDLED_SUPABASE_SKILLS = [
8
9
 
9
10
  export type BundledSupabaseSkill = (typeof BUNDLED_SUPABASE_SKILLS)[number];
10
11
 
11
- type Warn = (message: string, data?: unknown) => void;
12
+ type Warn = (message: string, data?: Record<string, unknown>) => unknown;
12
13
 
13
14
  type ResolverDeps = {
14
15
  warn?: Warn;
@@ -21,17 +22,21 @@ type RegisterDeps = ResolverDeps & {
21
22
 
22
23
  type ConfigWithSkills = object & {
23
24
  skills?: {
24
- paths?: string[];
25
+ paths?: unknown;
25
26
  };
26
27
  };
27
28
 
29
+ type SkillsConfig = {
30
+ paths?: unknown;
31
+ } & Record<string, unknown>;
32
+
28
33
  function isRecord(value: unknown): value is Record<string, unknown> {
29
34
  return typeof value === "object" && value !== null && !Array.isArray(value);
30
35
  }
31
36
 
32
37
  function pluginSkillsOption(options: unknown) {
33
38
  if (!isRecord(options) || !("skills" in options)) return true;
34
- return options.skills;
39
+ return (options as { skills?: unknown }).skills;
35
40
  }
36
41
 
37
42
  export function resolveEnabledSupabaseSkills(options: unknown, deps: ResolverDeps = {}) {
@@ -48,6 +53,13 @@ export function resolveEnabledSupabaseSkills(options: unknown, deps: ResolverDep
48
53
  for (const key of Object.keys(value)) {
49
54
  if (!known.has(key)) {
50
55
  deps.warn?.("unknown Supabase bundled skill option ignored", { skill: key });
56
+ continue;
57
+ }
58
+ if (value[key] !== undefined && typeof value[key] !== "boolean") {
59
+ deps.warn?.("invalid Supabase bundled skill option value", {
60
+ skill: key,
61
+ value: value[key] as unknown,
62
+ });
51
63
  }
52
64
  }
53
65
 
@@ -55,7 +67,7 @@ export function resolveEnabledSupabaseSkills(options: unknown, deps: ResolverDep
55
67
  }
56
68
 
57
69
  export function defaultSkillsRoot() {
58
- return path.resolve(path.dirname(new URL(import.meta.url).pathname), "../../skills");
70
+ return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../skills");
59
71
  }
60
72
 
61
73
  export function registerSupabaseSkillPaths(
@@ -67,9 +79,31 @@ export function registerSupabaseSkillPaths(
67
79
  const skillsRoot = deps.skillsRoot ?? defaultSkillsRoot();
68
80
  const exists = deps.exists ?? fs.existsSync;
69
81
  const enabled = resolveEnabledSupabaseSkills(options, deps);
82
+ let skillsConfig: SkillsConfig;
83
+
84
+ if (configWithSkills.skills === undefined) {
85
+ skillsConfig = {};
86
+ configWithSkills.skills = skillsConfig;
87
+ } else if (isRecord(configWithSkills.skills)) {
88
+ skillsConfig = configWithSkills.skills as SkillsConfig;
89
+ } else {
90
+ deps.warn?.("invalid Supabase skills config; leaving unchanged", {
91
+ value: configWithSkills.skills as unknown,
92
+ });
93
+ return;
94
+ }
70
95
 
71
- configWithSkills.skills = configWithSkills.skills ?? {};
72
- configWithSkills.skills.paths = configWithSkills.skills.paths ?? [];
96
+ if (!Array.isArray(skillsConfig.paths)) {
97
+ if (skillsConfig.paths !== undefined) {
98
+ deps.warn?.("invalid Supabase skills.paths value; leaving unchanged", {
99
+ value: skillsConfig.paths as unknown,
100
+ });
101
+ return;
102
+ }
103
+ skillsConfig.paths = [];
104
+ }
105
+
106
+ const paths = skillsConfig.paths as string[];
73
107
 
74
108
  for (const skill of enabled) {
75
109
  const skillPath = path.join(skillsRoot, skill);
@@ -77,8 +111,9 @@ export function registerSupabaseSkillPaths(
77
111
  deps.warn?.("bundled Supabase skill directory not found", { skill, path: skillPath });
78
112
  continue;
79
113
  }
80
- if (!configWithSkills.skills.paths.includes(skillPath)) {
81
- configWithSkills.skills.paths.push(skillPath);
114
+
115
+ if (!paths.includes(skillPath)) {
116
+ paths.push(skillPath);
82
117
  }
83
118
  }
84
119
  }