opencode-froggy 0.8.0 → 0.9.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.
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  <a href="https://www.npmjs.com/package/opencode-froggy"><img src="https://badge.fury.io/js/opencode-froggy.svg" alt="npm version"></a>
8
8
  </p>
9
9
 
10
- OpenCode plugin providing hooks, specialized agents (architect, doc-writer, rubber-duck, partner, code-reviewer, code-simplifier), skills (code-release), and tools (gitingest, pdf-to-markdown, blockchain queries, agent-promote).
10
+ OpenCode plugin providing hooks, specialized agents (architect, doc-writer, rubber-duck, partner, code-reviewer, code-simplifier), skills (ask-questions-if-underspecified), and tools (gitingest, pdf-to-markdown, blockchain queries, agent-promote).
11
11
 
12
12
  ---
13
13
 
@@ -17,7 +17,11 @@ OpenCode plugin providing hooks, specialized agents (architect, doc-writer, rubb
17
17
  - [Commands](#commands)
18
18
  - [Agents](#agents)
19
19
  - [Skills](#skills)
20
- - [code-release](#code-release)
20
+ - [Overview](#overview)
21
+ - [Available Skills](#available-skills)
22
+ - [Discovery Locations](#discovery-locations)
23
+ - [Creating a Skill](#creating-a-skill)
24
+ - [Automatic Activation](#automatic-activation)
21
25
  - [Tools](#tools)
22
26
  - [gitingest](#gitingest)
23
27
  - [prompt-session](#prompt-session)
@@ -117,15 +121,113 @@ Shows stats overview, commits, files changed, and full diff between branches.
117
121
 
118
122
  ## Skills
119
123
 
120
- Skills are loaded on-demand to provide specialized capabilities during a session.
124
+ Skills are contextual instructions loaded on demand via the `skill` tool. The agent invokes `skill({ name: "skill-name" })` to load the instructions when needed.
121
125
 
122
- ### code-release
126
+ ### Overview
123
127
 
124
- Prepare releases with version bumps, changelog updates, and tags.
128
+ - Skills provide specialized guidance for specific tasks
129
+ - Instructions are loaded only when explicitly requested
130
+ - Multiple skills can exist with the same name; the highest-priority location wins
125
131
 
126
- - **Purpose**: Guide release preparation steps and require confirmation before changing release artifacts
127
- - **Activation**: On user request to prepare or perform a release
128
- - **Constraints**: Avoid changing versions, tags, or changelogs without explicit confirmation
132
+ ### Available Skills
133
+
134
+ | Skill | Description |
135
+ |-------|-------------|
136
+ | `ask-questions-if-underspecified` | Clarify requirements before implementing. Use when serious doubts arise. |
137
+
138
+ #### Example: ask-questions-if-underspecified
139
+
140
+ **User request:**
141
+ > "Add authentication to the API"
142
+
143
+ **Agent response (after loading the skill):**
144
+
145
+ The agent recognizes this request has multiple interpretations and uses the `question` tool:
146
+
147
+ ```
148
+ ┌─ Authentication Approach ────────────────────────────────────────┐
149
+ │ │
150
+ │ Which authentication method should be implemented? │
151
+ │ │
152
+ │ ○ JWT tokens (Recommended) │
153
+ │ ○ Session-based with cookies │
154
+ │ ○ OAuth 2.0 / OpenID Connect │
155
+ │ ○ API keys │
156
+ │ ○ Other │
157
+ │ │
158
+ └──────────────────────────────────────────────────────────────────┘
159
+ ```
160
+
161
+ After the user selects "JWT tokens", the agent confirms:
162
+
163
+ > "I'll add JWT-based authentication to the API endpoints using the existing Express middleware pattern. Success = all `/api/*` routes require a valid token, with a `/auth/login` endpoint for token generation."
164
+
165
+ Then implementation begins.
166
+
167
+ ### Discovery Locations
168
+
169
+ Skills are discovered from the following locations, in order of increasing priority:
170
+
171
+ | Priority | Scope | Location |
172
+ |----------|-------|----------|
173
+ | 1 (lowest) | plugin | `<plugin>/skill/` |
174
+ | 2 | global | `~/.config/opencode/skill/` |
175
+ | 3 (highest) | project | `<project>/.opencode/skill/` |
176
+
177
+ If multiple skills share the same name, the one from the highest-priority location takes precedence.
178
+
179
+ ### Creating a Skill
180
+
181
+ Each skill lives in its own directory with a `SKILL.md` file:
182
+
183
+ ```
184
+ skill/
185
+ └── my-skill/
186
+ └── SKILL.md
187
+ ```
188
+
189
+ The `SKILL.md` file uses YAML frontmatter for metadata:
190
+
191
+ ```markdown
192
+ ---
193
+ name: my-skill
194
+ description: Short description of the skill (required)
195
+ use_when: >
196
+ Condition for automatic activation (optional).
197
+ ---
198
+
199
+ # Detailed Instructions
200
+
201
+ Markdown content with step-by-step guidance...
202
+ ```
203
+
204
+ #### Frontmatter Fields
205
+
206
+ | Field | Required | Description |
207
+ |-------|----------|-------------|
208
+ | `name` | Yes | Unique identifier for the skill |
209
+ | `description` | Yes | Short description (displayed in skill listings) |
210
+ | `use_when` | No | Condition for automatic activation |
211
+
212
+ A skill without `name` or `description` will be ignored.
213
+
214
+ ### Automatic Activation
215
+
216
+ If a skill defines `use_when`, a directive is injected into the system prompt:
217
+
218
+ ```
219
+ MANDATORY: Call skill({ name: "my-skill" }) <use_when content>
220
+ ```
221
+
222
+ This instructs the agent to load the skill when the specified condition is met.
223
+
224
+ **What is injected:**
225
+ - The skill `name`
226
+ - The `use_when` text (normalized: multiple spaces collapsed to single space)
227
+
228
+ **What is NOT injected:**
229
+ - The `description`
230
+ - The markdown content (loaded only when the skill is invoked)
129
231
 
130
232
  ---
131
233
 
@@ -26,6 +26,7 @@ You do not introduce new features, fix bugs, or change logic. You only improve h
26
26
 
27
27
  ### 2. Scope discipline
28
28
  - Only simplify code that was **modified or introduced in the current session**.
29
+ - This includes **untracked files** (new files not yet committed) listed in the working tree.
29
30
  - Do not refactor adjacent or pre-existing code unless strictly required to simplify the modified section.
30
31
  - No cross-file refactors unless the change itself spans multiple files.
31
32
 
@@ -61,11 +62,12 @@ Apply simplifications only when they clearly improve readability or maintainabil
61
62
 
62
63
  ## Execution process
63
64
 
64
- 1. Identify code that was added or modified in the current session.
65
- 2. Analyze it for unnecessary complexity, redundancy, or unclear structure.
66
- 3. Apply minimal, behavior-preserving refinements.
67
- 4. Re-check that functionality, outputs, and side effects are unchanged.
68
- 5. Produce the simplified code.
65
+ 1. Identify code that was added or modified in the current session, **including untracked files listed in the diff**.
66
+ 2. **Read the content of untracked files** using the Read tool before analyzing them.
67
+ 3. Analyze the code for unnecessary complexity, redundancy, or unclear structure.
68
+ 4. Apply minimal, behavior-preserving refinements.
69
+ 5. Re-check that functionality, outputs, and side effects are unchanged.
70
+ 6. Produce the simplified code.
69
71
 
70
72
  ## Output requirements
71
73
 
@@ -9,7 +9,7 @@ agent: build
9
9
 
10
10
  ## Your task
11
11
 
12
- 1. Run `/diff-summary` to analyze all working tree changes
12
+ 1. /diff-summary to analyze all working tree changes
13
13
  2. Present a summary to the user:
14
14
  - Files modified/added/deleted with stats
15
15
  - Proposed commit message based on the changes
@@ -43,9 +43,8 @@ else
43
43
  git diff
44
44
 
45
45
  echo ""
46
- echo "## Untracked Files Content"
47
- git ls-files --others --exclude-standard | while read f; do
48
- [ -f "$f" ] && echo "=== $f ===" && sed -n "1,50p" "$f" && sed -n "51p" "$f" | grep -q . && echo "... (truncated)"
49
- done
46
+ echo "## Untracked Files (new)"
47
+ echo "These files are new and not yet tracked by git. Read them directly to see their content."
48
+ git ls-files --others --exclude-standard
50
49
  fi
51
50
  '`
@@ -1,13 +1,12 @@
1
1
  ---
2
- name: code-release
3
- description: >
4
- Prepare and execute a release with version bumping, changelog updates, and tags.
5
- use_when: >
6
- REQUIRED: When the user asks to prepare or perform a release,
7
- call skill({ name: "code-release" }) before changing any release artifacts.
2
+ description: Prepare and execute a release with version bumping, changelog updates, and tags
8
3
  ---
9
4
 
10
- # Code Release Skill
5
+ ## Context
6
+
7
+ - Current version: !`node -p "require('./package.json').version"`
8
+ - Latest tag: !`git describe --tags --abbrev=0 2>/dev/null || echo "none"`
9
+ - Commits since last tag: !`git log $(git describe --tags --abbrev=0 2>/dev/null || echo "HEAD~10")..HEAD --oneline 2>/dev/null || git log --oneline -10`
11
10
 
12
11
  ## CRITICAL CONSTRAINT
13
12
 
@@ -17,13 +16,15 @@ Any destructive or remote action requires confirmation, including:
17
16
  - `git tag`
18
17
  - `git push`
19
18
 
20
- ## Step 1: Determine last released version
19
+ ## Your task
20
+
21
+ ### Step 1: Determine last released version
21
22
 
22
23
  1. Prefer the latest Git tag that matches `v<semver>`.
23
24
  2. If no matching tag exists, use the version in `package.json`.
24
25
  3. Collect commits since the last version (tag to `HEAD`).
25
26
 
26
- ## Step 2: Propose version bump
27
+ ### Step 2: Propose version bump
27
28
 
28
29
  Analyze commits since the last version and recommend a semver bump:
29
30
  - **major**: breaking changes or incompatible behavior changes.
@@ -32,14 +33,14 @@ Analyze commits since the last version and recommend a semver bump:
32
33
 
33
34
  Present the recommendation and ask the user to confirm before changing any files.
34
35
 
35
- ## Step 3: Update release artifacts (after confirmation)
36
+ ### Step 3: Update release artifacts (after confirmation)
36
37
 
37
38
  - Update the version in `package.json`.
38
39
  - Update `CHANGELOG` with a new section for the version.
39
40
  - Summarize changes based on the commit range.
40
41
  - Preserve the existing changelog format.
41
42
 
42
- ## Step 4: Tag and publish (after confirmation)
43
+ ### Step 4: Tag and publish (after confirmation)
43
44
 
44
45
  - Commit release changes with a clear release message.
45
46
  - Create an annotated tag (for example, `vX.Y.Z`).
@@ -16,7 +16,8 @@ agent: code-reviewer
16
16
  !`git diff --stat`
17
17
  !`git diff`
18
18
 
19
- ## Untracked Files Content
20
- !`bash -c 'git ls-files --others --exclude-standard | while read f; do [ -f "$f" ] && echo "=== $f ===" && sed -n "1,50p" "$f" && sed -n "51p" "$f" | grep -q . && echo "... (truncated)"; done'`
19
+ ## Untracked Files (new)
20
+ These files are new and not yet tracked by git. Read them directly to see their content.
21
+ !`git ls-files --others --exclude-standard`
21
22
 
22
23
  Review the above changes for quality, correctness, and adherence to project guidelines.
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ const SmartfrogPlugin = async (ctx) => {
37
37
  const skillTool = createSkillTool({
38
38
  pluginSkills: skills,
39
39
  pluginDir: PLUGIN_ROOT,
40
+ client: ctx.client,
40
41
  });
41
42
  log("[init] Plugin loaded", {
42
43
  agents: Object.keys(agents),
@@ -1,5 +1,7 @@
1
1
  import { type ToolContext } from "@opencode-ai/plugin";
2
+ import type { createOpencodeClient } from "@opencode-ai/sdk";
2
3
  import { type LoadedSkill } from "../loaders";
4
+ type Client = ReturnType<typeof createOpencodeClient>;
3
5
  export interface SkillInfo {
4
6
  name: string;
5
7
  description: string;
@@ -9,6 +11,7 @@ export interface SkillInfo {
9
11
  export interface CreateSkillToolOptions {
10
12
  pluginSkills: LoadedSkill[];
11
13
  pluginDir: string;
14
+ client: Client;
12
15
  }
13
16
  export declare function createSkillTool(options: CreateSkillToolOptions): {
14
17
  description: string;
@@ -19,3 +22,4 @@ export declare function createSkillTool(options: CreateSkillToolOptions): {
19
22
  name: string;
20
23
  }, context: ToolContext): Promise<string>;
21
24
  };
25
+ export {};
@@ -3,6 +3,7 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
3
3
  import { join, dirname } from "node:path";
4
4
  import { homedir } from "node:os";
5
5
  import { parseFrontmatter } from "../loaders";
6
+ import { log } from "../logger";
6
7
  const TOOL_DESCRIPTION_PREFIX = `Load a skill to get detailed instructions for a specific task.`;
7
8
  const TOOL_DESCRIPTION_NO_SKILLS = `${TOOL_DESCRIPTION_PREFIX} No skills are currently available.`;
8
9
  function discoverSkillsFromDir(skillsDir, scope) {
@@ -89,12 +90,13 @@ function loadSkillContent(location) {
89
90
  export function createSkillTool(options) {
90
91
  let cachedSkills = null;
91
92
  let cachedDescription = null;
93
+ const { client, pluginDir, pluginSkills } = options;
92
94
  const getSkills = (cwd) => {
93
95
  if (cachedSkills)
94
96
  return cachedSkills;
95
97
  // Merge order: plugin defaults < global < project (later entries override earlier on name collision)
96
98
  const allSkills = [
97
- ...pluginSkillsToInfo(options.pluginSkills, options.pluginDir),
99
+ ...pluginSkillsToInfo(pluginSkills, pluginDir),
98
100
  ...discoverClaudeGlobalSkills(),
99
101
  ...discoverOpencodeGlobalSkills(),
100
102
  ...discoverClaudeProjectSkills(cwd),
@@ -139,6 +141,18 @@ export function createSkillTool(options) {
139
141
  }
140
142
  const body = loadSkillContent(skill.location);
141
143
  const dir = dirname(skill.location);
144
+ try {
145
+ await client.tui.showToast({
146
+ body: {
147
+ message: `Skill "${skill.name}" loaded`,
148
+ variant: "info",
149
+ duration: 3000,
150
+ },
151
+ });
152
+ }
153
+ catch (error) {
154
+ log("[skill] Failed to show toast", { error: String(error) });
155
+ }
142
156
  return [
143
157
  `## Skill: ${skill.name}`,
144
158
  "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-froggy",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "OpenCode plugin with a hook layer (tool.before.*, session.idle...), agents (code-reviewer, doc-writer), and commands (/review-pr, /commit)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: ask-questions-if-underspecified
3
+ description: Clarify requirements before implementing. Use when serious doubts arise.
4
+ use_when: >
5
+ When a request has multiple plausible interpretations or key details
6
+ (objective, scope, constraints, environment, or safety) are unclear,
7
+ load this skill before starting implementation.
8
+ Do NOT use when the request is already clear or when a quick, low-risk
9
+ discovery read can answer the missing details.
10
+ ---
11
+
12
+ # Ask Questions If Underspecified
13
+
14
+ ## Goal
15
+
16
+ Ask the minimum set of clarifying questions needed to avoid wrong work; do not start implementing until the must-have questions are answered (or the user explicitly approves proceeding with stated assumptions).
17
+
18
+ ## Workflow
19
+
20
+ ### 1) Decide whether the request is underspecified
21
+
22
+ Treat a request as underspecified if after exploring how to perform the work, some or all of the following are not clear:
23
+ - Define the objective (what should change vs stay the same)
24
+ - Define "done" (acceptance criteria, examples, edge cases)
25
+ - Define scope (which files/components/users are in/out)
26
+ - Define constraints (compatibility, performance, style, deps, time)
27
+ - Identify environment (language/runtime versions, OS, build/test runner)
28
+ - Clarify safety/reversibility (data migration, rollout/rollback, risk)
29
+
30
+ If multiple plausible interpretations exist, assume it is underspecified.
31
+
32
+ ### 2) Ask must-have questions first (keep it small)
33
+
34
+ Ask 1-5 questions in the first pass. Prefer questions that eliminate whole branches of work.
35
+
36
+ Use the `question` tool to present structured choices:
37
+ - Offer multiple-choice options with clear labels
38
+ - Mark recommended defaults with "(Recommended)" in the label
39
+ - Use `multiple: true` when the user can select several options
40
+ - The user can always select "Other" for custom input
41
+
42
+ ### 3) Pause before acting
43
+
44
+ Until must-have answers arrive:
45
+ - Do not run commands, edit files, or produce a detailed plan that depends on unknowns
46
+ - Do perform a clearly labeled, low-risk discovery step only if it does not commit you to a direction (e.g., inspect repo structure, read relevant config files)
47
+
48
+ If the user explicitly asks you to proceed without answers:
49
+ - State your assumptions as a short numbered list
50
+ - Ask for confirmation; proceed only after they confirm or correct them
51
+
52
+ ### 4) Confirm interpretation, then proceed
53
+
54
+ Once you have answers, restate the requirements in 1-3 sentences (including key constraints and what success looks like), then start work.
55
+
56
+ ## Anti-patterns
57
+
58
+ - Don't ask questions you can answer with a quick, low-risk discovery read (e.g., configs, existing patterns, docs).
59
+ - Don't ask open-ended questions if a tight multiple-choice or yes/no would eliminate ambiguity faster.