br4zz4-opencode-skill-picker 0.1.7 → 0.1.8

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/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- @br4zz4/opencode-skill-picker
1
+ br4zz4-opencode-skill-picker
2
2
 
3
3
  Copyright (C) 2026 oporpino <dev@porpi.no>
4
4
 
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @br4zz4/opencode-skill-picker
1
+ # br4zz4-opencode-skill-picker
2
2
 
3
3
  OpenCode TUI plugin that makes skills autocompletable in the prompt:
4
4
 
@@ -8,7 +8,17 @@ OpenCode TUI plugin that makes skills autocompletable in the prompt:
8
8
 
9
9
  ## Install
10
10
 
11
- Clone the repo and point `tui.json` at it (a local file path is required; git URLs hit an opencode install bug):
11
+ ### Via npm
12
+
13
+ ```json
14
+ {
15
+ "plugin": ["br4zz4-opencode-skill-picker"]
16
+ }
17
+ ```
18
+
19
+ > **Known opencode bug:** opencode installs npm plugins into `~/.cache/opencode/packages/<name>@<version>` and cannot `import` from paths containing `@`. If the npm install doesn't load, use the file path below.
20
+
21
+ ### Via file (workaround)
12
22
 
13
23
  ```bash
14
24
  git clone git@github.com:br4zz4/opencode-skill-picker.git ~/.qwert/vendor/opencode-skill-picker
@@ -18,7 +28,7 @@ Then add to `~/.config/opencode/tui.json`:
18
28
 
19
29
  ```json
20
30
  {
21
- "plugin": ["file:///Users/<you>/.qwert/vendor/opencode-skill-picker/index.tsx"]
31
+ "plugin": ["file:///Users/<you>/.qwert/vendor/opencode-skill-picker/dist/index.js"]
22
32
  }
23
33
  ```
24
34
 
@@ -26,11 +36,16 @@ Restart opencode.
26
36
 
27
37
  ## Development
28
38
 
39
+ ```bash
40
+ npm install
41
+ npm run build
42
+ ```
43
+
29
44
  Run opencode against your checkout:
30
45
 
31
46
  ```json
32
47
  {
33
- "plugin": ["file:///path/to/opencode-skill-picker/index.tsx"]
48
+ "plugin": ["file:///path/to/opencode-skill-picker/dist/index.js"]
34
49
  }
35
50
  ```
36
51
 
package/dist/index.js ADDED
@@ -0,0 +1,82 @@
1
+ // index.tsx
2
+ import { jsx } from "@opentui/solid/jsx-runtime";
3
+ var OPENCODE_BASE_MODE = "base";
4
+ var tui = async (api) => {
5
+ let skills = [];
6
+ let skillsLoaded = false;
7
+ const loadSkills = async () => {
8
+ if (skillsLoaded) return skills;
9
+ try {
10
+ const result = await api.client.app.skills();
11
+ const list = result?.data ?? result;
12
+ const source = Array.isArray(list) ? list : [];
13
+ skills = source.filter((s) => s && typeof s.name === "string" && s.name.length > 0).map((s) => ({ name: s.name, description: s.description })).toSorted((a, b) => a.name.localeCompare(b.name));
14
+ } catch {
15
+ skills = [];
16
+ } finally {
17
+ skillsLoaded = true;
18
+ }
19
+ return skills;
20
+ };
21
+ const insertSkill = async (name) => {
22
+ try {
23
+ await api.client.tui.appendPrompt({ text: `/${name} ` });
24
+ } catch {
25
+ api.ui.toast({ message: `Could not load skill ${name}`, variant: "error" });
26
+ }
27
+ };
28
+ const openPicker = async () => {
29
+ if (api.mode.current() !== OPENCODE_BASE_MODE) return;
30
+ if (api.renderer.currentFocusedEditor === null) return;
31
+ const list = await loadSkills();
32
+ if (list.length === 0) {
33
+ api.ui.toast({ message: "No skills available", variant: "warning" });
34
+ return;
35
+ }
36
+ const options = list.map((skill) => ({
37
+ title: skill.name,
38
+ value: skill.name,
39
+ description: skill.description?.replace(/\s+/g, " ").trim(),
40
+ category: "Skills"
41
+ }));
42
+ api.ui.dialog.replace(
43
+ () => /* @__PURE__ */ jsx(
44
+ api.ui.DialogSelect,
45
+ {
46
+ title: "Skills",
47
+ placeholder: "Search skills\u2026",
48
+ options,
49
+ onSelect: (opt) => {
50
+ api.ui.dialog.clear();
51
+ void insertSkill(opt.value);
52
+ }
53
+ }
54
+ ),
55
+ () => {
56
+ }
57
+ );
58
+ };
59
+ const registerSkillCommands = async () => {
60
+ const list = await loadSkills();
61
+ api.command.register(
62
+ () => list.map((skill) => ({
63
+ title: skill.name,
64
+ value: skill.name,
65
+ description: skill.description?.replace(/\s+/g, " ").trim(),
66
+ category: "Skills",
67
+ slash: { name: skill.name },
68
+ onSelect: () => {
69
+ void insertSkill(skill.name);
70
+ }
71
+ }))
72
+ );
73
+ };
74
+ api.keymap.registerLayer({
75
+ bindings: [{ key: "#", desc: "Pick a skill", preventDefault: true, cmd: () => void openPicker() }]
76
+ });
77
+ void registerSkillCommands();
78
+ };
79
+ var index_default = { id: "skill-picker", tui };
80
+ export {
81
+ index_default as default
82
+ };
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "br4zz4-opencode-skill-picker",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "OpenCode TUI plugin: pick and autocomplete skills via /slash commands and the # keybinding",
5
5
  "author": "oporpino <dev@porpi.no>",
6
6
  "license": "AGPL-3.0",
7
7
  "type": "module",
8
- "main": "./index.tsx",
8
+ "main": "./dist/index.js",
9
9
  "files": [
10
- "index.tsx"
10
+ "dist"
11
11
  ],
12
12
  "exports": {
13
- ".": "./index.tsx",
14
- "./tui": "./index.tsx"
13
+ ".": "./dist/index.js",
14
+ "./tui": "./dist/index.js"
15
15
  },
16
16
  "keywords": [
17
17
  "opencode",
@@ -24,5 +24,13 @@
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"
27
+ },
28
+ "types": "./dist/index.js",
29
+ "scripts": {
30
+ "build": "node build.mjs",
31
+ "prepublishOnly": "npm run build"
32
+ },
33
+ "devDependencies": {
34
+ "esbuild": "^0.28.2"
27
35
  }
28
36
  }
package/index.tsx DELETED
@@ -1,91 +0,0 @@
1
- import type { TuiPlugin, TuiDialogSelectOption } from "@opencode-ai/plugin/tui"
2
-
3
- type Skill = { name: string; description?: string }
4
-
5
- const OPENCODE_BASE_MODE = "base"
6
-
7
- const tui: TuiPlugin = async (api) => {
8
- let skills: Skill[] = []
9
- let skillsLoaded = false
10
-
11
- const loadSkills = async (): Promise<Skill[]> => {
12
- if (skillsLoaded) return skills
13
- try {
14
- const result = await api.client.app.skills()
15
- const list: unknown = result?.data ?? result
16
- const source = Array.isArray(list) ? list : []
17
- skills = (source as Skill[])
18
- .filter((s) => s && typeof s.name === "string" && s.name.length > 0)
19
- .map((s) => ({ name: s.name, description: s.description }))
20
- .toSorted((a, b) => a.name.localeCompare(b.name))
21
- } catch {
22
- skills = []
23
- } finally {
24
- skillsLoaded = true
25
- }
26
- return skills
27
- }
28
-
29
- const insertSkill = async (name: string) => {
30
- try {
31
- await api.client.tui.appendPrompt({ text: `/${name} ` })
32
- } catch {
33
- api.ui.toast({ message: `Could not load skill ${name}`, variant: "error" })
34
- }
35
- }
36
-
37
- const openPicker = async () => {
38
- if (api.mode.current() !== OPENCODE_BASE_MODE) return
39
- if (api.renderer.currentFocusedEditor === null) return
40
-
41
- const list = await loadSkills()
42
- if (list.length === 0) {
43
- api.ui.toast({ message: "No skills available", variant: "warning" })
44
- return
45
- }
46
- const options: TuiDialogSelectOption<string>[] = list.map((skill) => ({
47
- title: skill.name,
48
- value: skill.name,
49
- description: skill.description?.replace(/\s+/g, " ").trim(),
50
- category: "Skills",
51
- }))
52
- api.ui.dialog.replace(
53
- () => (
54
- <api.ui.DialogSelect<string>
55
- title="Skills"
56
- placeholder="Search skills…"
57
- options={options}
58
- onSelect={(opt) => {
59
- api.ui.dialog.clear()
60
- void insertSkill(opt.value)
61
- }}
62
- />
63
- ),
64
- () => {},
65
- )
66
- }
67
-
68
- const registerSkillCommands = async () => {
69
- const list = await loadSkills()
70
- api.command.register(() =>
71
- list.map((skill) => ({
72
- title: skill.name,
73
- value: skill.name,
74
- description: skill.description?.replace(/\s+/g, " ").trim(),
75
- category: "Skills",
76
- slash: { name: skill.name },
77
- onSelect: () => {
78
- void insertSkill(skill.name)
79
- },
80
- })),
81
- )
82
- }
83
-
84
- api.keymap.registerLayer({
85
- bindings: [{ key: "#", desc: "Pick a skill", preventDefault: true, cmd: () => void openPicker() }],
86
- })
87
-
88
- void registerSkillCommands()
89
- }
90
-
91
- export default { id: "skill-picker", tui }