@nt-ai-lab/opencode-skillz 0.2.8 → 0.3.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.
Files changed (3) hide show
  1. package/AGENTS.md +1 -0
  2. package/package.json +15 -4
  3. package/index.js +0 -237
package/AGENTS.md CHANGED
@@ -15,6 +15,7 @@ Purpose: package OpenCode workflow assets as a plugin.
15
15
  - Put voice and persona behavior in agent prompts.
16
16
  - Treat reusable skill content as command templates in `commands/`.
17
17
  - Commands should be manually invoked by default.
18
+ - All plugin-provided commands must use the `nt-skillz:` prefix, including code-backed commands.
18
19
  - Prefer minimal additions; only add new commands when needed.
19
20
  - Do not add `agent:` in command frontmatter unless the command must force a specific agent.
20
21
 
package/package.json CHANGED
@@ -1,19 +1,30 @@
1
1
  {
2
2
  "name": "@nt-ai-lab/opencode-skillz",
3
- "version": "0.2.8",
3
+ "version": "0.3.1",
4
4
  "description": "Bundled OpenCode commands and agents",
5
5
  "type": "module",
6
- "main": "index.js",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
7
8
  "exports": {
8
- ".": "./index.js"
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.json"
9
16
  },
10
17
  "files": [
11
- "index.js",
18
+ "dist",
12
19
  "commands",
13
20
  "agents",
14
21
  "AGENTS.md",
15
22
  "README.md"
16
23
  ],
24
+ "devDependencies": {
25
+ "@types/node": "^24.7.2",
26
+ "typescript": "^5.9.3"
27
+ },
17
28
  "publishConfig": {
18
29
  "access": "public"
19
30
  }
package/index.js DELETED
@@ -1,237 +0,0 @@
1
- import fs from "node:fs"
2
- import path from "node:path"
3
- import { fileURLToPath } from "node:url"
4
-
5
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
6
- const pluginRoot = __dirname
7
- const commandNamespace = "nt-skillz"
8
-
9
- function buildCommandName(name) {
10
- return `${commandNamespace}:${name}`
11
- }
12
-
13
- function extractFrontmatter(content) {
14
- const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/)
15
- if (!match) return { meta: {}, body: content }
16
-
17
- const meta = {}
18
- for (const rawLine of match[1].split("\n")) {
19
- const line = rawLine.trim()
20
- if (!line || line.startsWith("#")) continue
21
- const idx = line.indexOf(":")
22
- if (idx <= 0) continue
23
-
24
- const key = line.slice(0, idx).trim()
25
- let value = line.slice(idx + 1).trim()
26
- value = value.replace(/^['\"]|['\"]$/g, "")
27
- if (value === "true") value = true
28
- if (value === "false") value = false
29
- meta[key] = value
30
- }
31
-
32
- return { meta, body: match[2] }
33
- }
34
-
35
- function readMarkdownFiles(dirPath) {
36
- if (!fs.existsSync(dirPath)) return []
37
- return fs
38
- .readdirSync(dirPath)
39
- .filter((file) => file.endsWith(".md"))
40
- .sort((a, b) => a.localeCompare(b))
41
- }
42
-
43
- function normalizeCommandReference(value) {
44
- if (!value || typeof value !== "string") return ""
45
- return value.trim().replace(/_/g, "-")
46
- }
47
-
48
- function loadCommands() {
49
- const commandsDir = path.join(pluginRoot, "commands")
50
- const files = readMarkdownFiles(commandsDir)
51
- const rawCommands = {}
52
-
53
- for (const file of files) {
54
- const name = file.replace(/\.md$/, "")
55
- const fullPath = path.join(commandsDir, file)
56
- const content = fs.readFileSync(fullPath, "utf8")
57
- const { meta, body } = extractFrontmatter(content)
58
-
59
- rawCommands[name] = {
60
- meta,
61
- body: body.trim(),
62
- }
63
- }
64
-
65
- const commands = {}
66
-
67
- function buildComposedTemplate(name, stack = new Set()) {
68
- const rawCommand = rawCommands[name]
69
- if (!rawCommand) return ""
70
- if (stack.has(name)) return rawCommand.body
71
-
72
- stack.add(name)
73
-
74
- let template = rawCommand.body
75
- const composeAfterName = normalizeCommandReference(rawCommand.meta.compose_after)
76
- const composedCommand = rawCommands[composeAfterName]
77
-
78
- if (composeAfterName && composedCommand) {
79
- const composedTemplate = buildComposedTemplate(composeAfterName, stack)
80
- if (composedTemplate) {
81
- template = [
82
- template,
83
- `In addition you must adhere to the following:\n\n${composedTemplate}`,
84
- ]
85
- .filter(Boolean)
86
- .join("\n\n")
87
- }
88
- }
89
-
90
- stack.delete(name)
91
-
92
- return template.trim()
93
- }
94
-
95
- for (const [name, rawCommand] of Object.entries(rawCommands)) {
96
- const { meta } = rawCommand
97
- const command = {
98
- description: meta.description || `Run /${name}`,
99
- template: buildComposedTemplate(name),
100
- }
101
-
102
- if (meta.agent) command.agent = meta.agent
103
- if (meta.model) command.model = meta.model
104
- if (typeof meta.subtask === "boolean") command.subtask = meta.subtask
105
-
106
- commands[name] = command
107
- }
108
-
109
- return commands
110
- }
111
-
112
- function parseCsvList(value) {
113
- if (!value || typeof value !== "string") return []
114
- return value
115
- .split(",")
116
- .map((item) => item.trim())
117
- .filter(Boolean)
118
- }
119
-
120
- function materializePreloadedTemplate(template) {
121
- return template.replace(/\$ARGUMENTS/g, "all relevant current work in this session")
122
- }
123
-
124
- function loadAgents(commands) {
125
- const agentsDir = path.join(pluginRoot, "agents")
126
- const files = readMarkdownFiles(agentsDir)
127
- const rawAgents = {}
128
-
129
- for (const file of files) {
130
- const name = file.replace(/\.md$/, "")
131
- const fullPath = path.join(agentsDir, file)
132
- const content = fs.readFileSync(fullPath, "utf8")
133
- const { meta, body } = extractFrontmatter(content)
134
-
135
- rawAgents[name] = {
136
- meta,
137
- body: body.trim(),
138
- }
139
- }
140
-
141
- const agents = {}
142
-
143
- function collectPreloadedCommands(agentName, stack = new Set()) {
144
- const rawAgent = rawAgents[agentName]
145
- if (!rawAgent) return []
146
- if (stack.has(agentName)) return parseCsvList(rawAgent.meta.preload_commands)
147
-
148
- stack.add(agentName)
149
-
150
- const merged = []
151
- const parentAgentName = typeof rawAgent.meta.extends === "string" ? rawAgent.meta.extends.trim() : ""
152
- if (parentAgentName && rawAgents[parentAgentName]) {
153
- merged.push(...collectPreloadedCommands(parentAgentName, stack))
154
- }
155
-
156
- merged.push(...parseCsvList(rawAgent.meta.preload_commands))
157
- stack.delete(agentName)
158
-
159
- return [...new Set(merged)]
160
- }
161
-
162
- for (const [name, raw] of Object.entries(rawAgents)) {
163
- const { meta, body } = raw
164
- const promptParts = []
165
-
166
- const parentAgentName = typeof meta.extends === "string" ? meta.extends.trim() : ""
167
- if (parentAgentName && rawAgents[parentAgentName]) {
168
- const parentPrompt = rawAgents[parentAgentName].body
169
- if (parentPrompt) promptParts.push(parentPrompt)
170
- }
171
-
172
- if (body) {
173
- promptParts.push(body)
174
- }
175
-
176
- const preloadedCommands = collectPreloadedCommands(name)
177
- for (const commandName of preloadedCommands) {
178
- const command = commands[commandName]
179
- if (!command || !command.template) continue
180
- const rendered = materializePreloadedTemplate(command.template)
181
- promptParts.push(`[Preloaded command /${commandName}]\n${rendered}`)
182
- }
183
-
184
- const agent = {
185
- prompt: promptParts.join("\n\n").trim(),
186
- }
187
-
188
- if (meta.description) agent.description = meta.description
189
- if (meta.mode) agent.mode = meta.mode
190
- if (meta.model) agent.model = meta.model
191
- if (meta.color) agent.color = meta.color
192
-
193
- agents[name] = agent
194
- }
195
-
196
- return agents
197
- }
198
-
199
- export const OpencodeSkillzPlugin = async () => {
200
- return {
201
- config: async (config) => {
202
- config.command = config.command || {}
203
- config.agent = config.agent || {}
204
-
205
- const commands = loadCommands()
206
- for (const [name, command] of Object.entries(commands)) {
207
- const commandName = buildCommandName(name)
208
- if (!config.command[commandName]) {
209
- config.command[commandName] = command
210
- }
211
- }
212
-
213
- const agents = loadAgents(commands)
214
- for (const [name, agent] of Object.entries(agents)) {
215
- if (!config.agent[name]) {
216
- config.agent[name] = agent
217
- }
218
- }
219
-
220
- config.agent.build = {
221
- ...(config.agent.build || {}),
222
- disable: true,
223
- }
224
-
225
- config.agent.plan = {
226
- ...(config.agent.plan || {}),
227
- disable: true,
228
- }
229
-
230
- if (!config.default_agent && config.agent.default) {
231
- config.default_agent = "default"
232
- }
233
- },
234
- }
235
- }
236
-
237
- export default OpencodeSkillzPlugin