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
|
-
|
|
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
|
@@ -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
|
package/src/server/index.ts
CHANGED
|
@@ -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:
|
|
16
|
+
warn: logger.warn,
|
|
17
17
|
});
|
|
18
18
|
},
|
|
19
19
|
auth: createSupabaseAuth(input, options, { logger }),
|
package/src/server/skills.ts
CHANGED
|
@@ -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) =>
|
|
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?:
|
|
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(
|
|
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
|
-
|
|
72
|
-
|
|
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
|
-
|
|
81
|
-
|
|
114
|
+
|
|
115
|
+
if (!paths.includes(skillPath)) {
|
|
116
|
+
paths.push(skillPath);
|
|
82
117
|
}
|
|
83
118
|
}
|
|
84
119
|
}
|