Skip to content

Commit 66cec0d

Browse files
committed
feat: honor host-exposed skills and automate release notes
1 parent d3e6fc9 commit 66cec0d

17 files changed

Lines changed: 525 additions & 29 deletions

.claude-plugin/marketplace.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
"plugins": [
1010
{
1111
"name": "hello2cc",
12-
"description": "Silent, native-first plugin for third-party models on Claude Code, with Claude-style tool, agent, task, team, and MCP routing.",
13-
"version": "0.2.8",
12+
"description": "Silent plugin for third-party models on Claude Code, helping them discover and correctly use host tools, agents, skills, workflows, and MCP.",
13+
"version": "0.2.9",
1414
"source": "./",
1515
"author": {
1616
"name": "hello2cc"

.claude-plugin/plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "hello2cc",
3-
"version": "0.2.8",
4-
"description": "Silent, native-first Claude Code plugin that steers third-party models toward Claude-style native tools, agents, tasks, teams, MCP workflows, and concise output.",
3+
"version": "0.2.9",
4+
"description": "Silent Claude Code plugin that helps third-party models discover and correctly use host-exposed tools, agents, skills, workflows, MCP, and concise output.",
55
"author": {
66
"name": "hello2cc"
77
},

.github/workflows/publish.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ jobs:
180180
runs-on: ubuntu-latest
181181
permissions:
182182
contents: write
183+
issues: read
184+
pull-requests: read
183185
steps:
184186
- name: Checkout repository
185187
uses: actions/checkout@v5
@@ -190,22 +192,20 @@ jobs:
190192
shell: bash
191193
env:
192194
GH_TOKEN: ${{ github.token }}
195+
GITHUB_TOKEN: ${{ github.token }}
193196
REPOSITORY: ${{ github.repository }}
194197
TAG_NAME: ${{ needs.prepare.outputs.tag }}
195198
RELEASE_TITLE: ${{ needs.prepare.outputs.version }}
196199
IS_PRERELEASE: ${{ needs.prepare.outputs.is_beta }}
197200
run: |
198201
set -euo pipefail
199202
200-
notes_json="$(mktemp)"
201203
notes_file="$(mktemp)"
202204
203-
gh api \
204-
--method POST \
205-
"repos/$REPOSITORY/releases/generate-notes" \
206-
-f tag_name="$TAG_NAME" > "$notes_json"
207-
208-
node -e "const fs=require('fs'); const [jsonFile, notesFile] = process.argv.slice(1); const payload = JSON.parse(fs.readFileSync(jsonFile, 'utf8')); const body = String(payload.body || '').trim(); fs.writeFileSync(notesFile, body ? body + '\n' : '', 'utf8');" "$notes_json" "$notes_file"
205+
node ./scripts/generate-release-notes.mjs \
206+
--repo "$REPOSITORY" \
207+
--tag "$TAG_NAME" \
208+
--output "$notes_file"
209209
210210
prerelease_args=()
211211
if [ "$IS_PRERELEASE" = "true" ]; then

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 0.2.9 - 2026-04-02
4+
5+
- Corrected hello2cc's routing stance from overly narrow native-first bias to host-surface-first guidance: third-party models are now reminded to respect all host-exposed capability surfaces instead of over-preferring only built-in tools and agents
6+
- Added explicit `Skill` / `DiscoverSkills` capability detection plus new session and route guidance so surfaced skills, slash-command workflows, and plugin workflows are treated as first-class options rather than being silently overshadowed by `ToolSearch` / `Plan` / `Agent`
7+
- Clarified routing boundaries between discovery layers: use `Skill` for known matching workflows, `DiscoverSkills` for skill/workflow discovery, and `ToolSearch` for tool / MCP / permission discovery instead of conflating them
8+
- Updated output-style, subagent guidance, validation rules, and regression tests so hello2cc no longer encodes “avoid skill usage” as a success condition
9+
- Added deterministic GitHub release-notes generation from `CHANGELOG.md`, with automatic acknowledgement sections when referenced issues / PRs exist, and backfilled all historical releases that were previously empty or only contained `Full Changelog`
10+
311
## 0.2.8 - 2026-04-02
412

513
- Added softer native `WebSearch` guidance for real-time / latest-information questions so hello2cc encourages the host's built-in search path without pretending the plugin itself can create missing network capability
@@ -75,6 +83,12 @@
7583
- Added npm publish metadata in `package.json` and release documentation in `README.md`, including support for both `NPM_TOKEN` and trusted-publishing based automation
7684
- Fixed the GitHub Actions publish workflow so npm token detection no longer relies on unsupported `secrets.*` checks inside `if:` expressions, which previously caused zero-job failed workflow runs
7785

86+
## 0.1.2 - 2026-03-31
87+
88+
- Added the first automated npm publishing workflow at `.github/workflows/publish.yml`, covering tag-triggered releases and manual dispatch entry points
89+
- Updated package metadata and README release guidance so the npm package and Claude Code plugin manifest stay version-aligned during release preparation
90+
- Cut the dedicated `0.1.2` release after wiring the publish automation and related release documentation into the repository
91+
7892
## 0.1.1 - 2026-03-31
7993

8094
- Rebuilt more of Claude Code's host-side tasking guidance into the forced plugin output style so third-party models keep stronger native habits even when plugin output styles replace part of the host prompt composition
@@ -100,6 +114,12 @@
100114
- Added `ConfigChange` handling that clears cached session model state so config swaps do not leave stale session-model mirroring behind
101115
- Updated validation, unit tests, and real-session regression checks for namespaced plugin agents and forced plugin output styles
102116

117+
## 0.0.9 - 2026-03-31
118+
119+
- Finalized the first public native-first plugin defaults before the later `hello2cc:native` rename, consolidating the default main-thread agent and packaged settings into a quieter baseline
120+
- Simplified the shipped plugin surface by removing the old output-style bootstrap runtime, tightening manifest/settings defaults, and stabilizing the packaged hooks layout
121+
- Expanded routing, session-state, regression, and validation coverage so transcript-driven session-model discovery and native-first prompt overlays behaved reliably in real Claude Code sessions
122+
103123
## 0.0.7 - 2026-03-31
104124

105125
- Added a default plugin `settings.json` that activates `main` as the main-thread agent, using `model: inherit` for a more silent and native-feeling baseline

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# hello2cc
22

3-
`hello2cc` 是一个面向 Claude Code 的静默型、native-first 插件
3+
`hello2cc` 是一个面向 Claude Code 的静默型、宿主能力优先插件
44

55
它不负责 provider、gateway、账号权限或模型接入;它负责的是:
66

7-
**当你已经把外部模型接进 Claude Code 后,让它更像原生 Claude Code 一样使用工具、Agent、计划、任务、MCP 和团队能力**
7+
**当你已经把外部模型接进 Claude Code 后,让它更容易发现、判断并正确使用 Claude Code 已经暴露出来的工具、Agent、Skill、workflow、MCP、计划与团队能力**
88

9-
当前版本:`0.2.8`
9+
当前版本:`0.2.9`
1010

1111
---
1212

@@ -29,7 +29,9 @@
2929

3030
| 方向 | 你能感受到的变化 |
3131
|---|---|
32+
| 能力发现 | 更容易发现当前会话真实暴露的工具、Agent、Skill、workflow 与 MCP |
3233
| 原生工具使用 | 更主动使用 Claude Code 原生工具,而不是总想绕去别的路径 |
34+
| Skills / workflows | 不再系统性压制已暴露的 Skill / DiscoverSkills / 插件工作流 |
3335
| ToolSearch | 更自然地把 `ToolSearch` 作为能力确认入口 |
3436
| 规划与任务 | 非 trivial 任务更倾向先进入 `EnterPlanMode()`;只有真的需要任务盘时再使用 `Task*` |
3537
| 原生 Agent | 更自然地调用 `Explore``Plan``General-Purpose``Claude Code Guide` |
@@ -47,7 +49,7 @@
4749
如果你符合下面任一场景,`hello2cc` 会比较有价值:
4850

4951
- 你已经把外部模型映射进 Claude Code 的 `opus / sonnet / haiku` 体系
50-
- 你希望模型更主动地用原生工具、计划、Agent 和 MCP
52+
- 你希望模型更主动地用宿主真实暴露的工具、Skill、计划、Agent 和 MCP
5153
- 你不想每轮手动加载 skills
5254
- 你希望普通对话不要误触发 agent team
5355
- 你希望中文会话尽量保持中文输出
@@ -61,6 +63,7 @@
6163

6264
- 接管你的 provider / gateway / CCSwitch 配置
6365
- 替宿主打开本来不存在的能力
66+
- 压制宿主已经暴露出来的 Skill / workflow / MCP / plugin 能力
6467
- 覆盖你已经显式传入的 `model`
6568
- 接管 CCSwitch 的 `Thinking` / 推理模型映射
6669
- 强迫你进入一套插件专属工作流
@@ -100,7 +103,7 @@ claude plugin install hello2cc@hello2cc-local
100103

101104
- 主线程使用 `hello2cc:native`
102105
- 插件输出风格自动启用
103-
- 优先原生工具、原生 Agent、原生计划 / 任务路径
106+
- 优先使用宿主已暴露的能力表面:工具、Agent、Skill / workflow、MCP、计划 / 任务路径
104107
- 关键 Agent 路径尽量保持与当前会话模型语义一致
105108

106109
---

output-styles/hello2cc-native.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ force-for-plugin: true
3030
## 原生能力优先级
3131

3232
- Prefer `ToolSearch` before assuming a tool, agent, permission, plugin, or MCP capability exists.
33+
- Treat host-exposed skills and workflow commands as first-class capabilities: if a visible skill matches the task or the user explicitly references a slash command / workflow, use `Skill` instead of recreating that flow manually.
34+
- When available, use `DiscoverSkills` for skill/workflow discovery and `ToolSearch` for tool/MCP discovery; do not treat them as interchangeable.
3335
- For non-trivial tasks, prefer `EnterPlanMode()` first; maintain `TaskCreate` / `TaskUpdate` / `TaskList` only when a real task board is needed.
3436
- If `TaskGet` exists and you are already using a task board, read the task before updating or reassigning it.
3537
- For open-ended exploration, prefer native `Agent` with `Explore` or `Plan`.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"name": "hello2cc",
3-
"version": "0.2.8",
3+
"version": "0.2.9",
44
"type": "module",
5-
"description": "Silent, native-first Claude Code plugin that steers third-party models toward Claude-style tools, agents, tasks, teams, MCP workflows, and concise native output.",
5+
"description": "Silent Claude Code plugin that helps third-party models discover and correctly use host-exposed tools, agents, skills, workflows, MCP, and concise native output.",
66
"license": "Apache-2.0",
77
"publishConfig": {
88
"access": "public"
@@ -16,6 +16,7 @@
1616
"url": "https://github.com/hellowind777/hello2cc/issues"
1717
},
1818
"scripts": {
19+
"release:notes": "node ./scripts/generate-release-notes.mjs",
1920
"validate": "node ./scripts/validate-plugin.mjs .",
2021
"test": "node --test",
2122
"test:real": "node ./scripts/claude-real-regression.mjs",

scripts/generate-release-notes.mjs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#!/usr/bin/env node
2+
import { execFileSync } from 'node:child_process';
3+
import { writeFileSync } from 'node:fs';
4+
import { resolve } from 'node:path';
5+
import {
6+
extractIssueRefs,
7+
normalizeTag,
8+
readChangelogSection,
9+
renderAcknowledgements,
10+
renderReleaseNotes,
11+
} from './lib/release-notes.mjs';
12+
13+
function parseArgs(argv) {
14+
const args = {};
15+
16+
for (let index = 2; index < argv.length; index += 1) {
17+
const key = argv[index];
18+
const value = argv[index + 1];
19+
20+
if (!key.startsWith('--')) continue;
21+
if (!value || value.startsWith('--')) {
22+
throw new Error(`Missing value for ${key}`);
23+
}
24+
25+
args[key.slice(2)] = value;
26+
index += 1;
27+
}
28+
29+
return args;
30+
}
31+
32+
function gitLines(...args) {
33+
const output = execFileSync('git', args, {
34+
cwd: resolve('.'),
35+
encoding: 'utf8',
36+
stdio: ['ignore', 'pipe', 'pipe'],
37+
});
38+
39+
return output
40+
.split(/\r?\n/)
41+
.map((line) => line.trim())
42+
.filter(Boolean);
43+
}
44+
45+
function gitText(...args) {
46+
return execFileSync('git', args, {
47+
cwd: resolve('.'),
48+
encoding: 'utf8',
49+
stdio: ['ignore', 'pipe', 'pipe'],
50+
}).trim();
51+
}
52+
53+
function previousTag(tag) {
54+
const tags = gitLines('tag', '--sort=creatordate');
55+
const index = tags.indexOf(tag);
56+
if (index <= 0) return '';
57+
return tags[index - 1];
58+
}
59+
60+
function compareUrl(repo, fromTag, toTag) {
61+
if (!repo || !fromTag || !toTag) return '';
62+
return `https://github.com/${repo}/compare/${fromTag}...${toTag}`;
63+
}
64+
65+
async function fetchReference(repo, number, token) {
66+
const response = await fetch(`https://api.github.com/repos/${repo}/issues/${number}`, {
67+
headers: {
68+
Accept: 'application/vnd.github+json',
69+
'User-Agent': 'hello2cc-release-notes',
70+
...(token ? { Authorization: `Bearer ${token}` } : {}),
71+
},
72+
});
73+
74+
if (!response.ok) {
75+
throw new Error(`GitHub API returned ${response.status} for #${number}`);
76+
}
77+
78+
const payload = await response.json();
79+
return {
80+
number,
81+
kind: payload.pull_request ? 'pr' : 'issue',
82+
login: payload.user?.login || '',
83+
title: String(payload.title || '').trim(),
84+
html_url: String(payload.html_url || '').trim(),
85+
};
86+
}
87+
88+
async function resolveAcknowledgementRefs(repo, numbers) {
89+
if (!repo || numbers.length === 0) return [];
90+
91+
const token = process.env.GH_TOKEN || process.env.GITHUB_TOKEN || '';
92+
const refs = [];
93+
94+
for (const number of numbers) {
95+
try {
96+
refs.push(await fetchReference(repo, number, token));
97+
} catch (error) {
98+
process.stderr.write(`warning: ${error.message}\n`);
99+
refs.push({
100+
number,
101+
kind: 'issue',
102+
login: '',
103+
title: '',
104+
html_url: repo ? `https://github.com/${repo}/issues/${number}` : '',
105+
});
106+
}
107+
}
108+
109+
return refs;
110+
}
111+
112+
async function main() {
113+
const args = parseArgs(process.argv);
114+
const tag = normalizeTag(args.tag || process.env.TAG_NAME || process.env.GITHUB_REF_NAME || '');
115+
const repo = String(args.repo || process.env.GITHUB_REPOSITORY || '').trim();
116+
const outputFile = String(args.output || '').trim();
117+
const changelogPath = resolve(args.changelog || 'CHANGELOG.md');
118+
119+
const section = readChangelogSection(changelogPath, tag);
120+
if (!section?.body?.trim()) {
121+
throw new Error(`Missing CHANGELOG section for ${tag}. Add "## ${tag.replace(/^v/, '')} - YYYY-MM-DD" with bullet points before publishing.`);
122+
}
123+
124+
const fromTag = previousTag(tag);
125+
const commitText = fromTag ? gitText('log', '--format=%B', `${fromTag}..${tag}`) : gitText('log', '--format=%B', '-n', '1', tag);
126+
const issueNumbers = extractIssueRefs(section.body, commitText);
127+
const acknowledgementRefs = await resolveAcknowledgementRefs(repo, issueNumbers);
128+
const notes = renderReleaseNotes({
129+
section,
130+
acknowledgements: renderAcknowledgements(acknowledgementRefs),
131+
compareUrl: compareUrl(repo, fromTag, tag),
132+
});
133+
134+
if (outputFile) {
135+
writeFileSync(outputFile, notes, 'utf8');
136+
return;
137+
}
138+
139+
process.stdout.write(notes);
140+
}
141+
142+
await main();

scripts/lib/prompt-signals.mjs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,43 @@ const WORKTREE_PATTERNS = [
364364
//,
365365
];
366366

367+
const SKILL_SURFACE_PATTERNS = [
368+
/\bskill\b/,
369+
/skills/,
370+
/slash command/,
371+
/workflow/,
372+
/plugin/,
373+
/\/[a-z0-9][\w:-]*/,
374+
//,
375+
//,
376+
//,
377+
//,
378+
];
379+
380+
const SKILL_DISCOVERY_PATTERNS = [
381+
/brainstorm/,
382+
/ideate/,
383+
/deploy/,
384+
/release/,
385+
/triage/,
386+
/codemod/,
387+
/scaffold/,
388+
/batch/,
389+
/bulk/,
390+
/playbook/,
391+
/checklist/,
392+
/headless/,
393+
/report/,
394+
//,
395+
//,
396+
//,
397+
//,
398+
//,
399+
//,
400+
//,
401+
//,
402+
];
403+
367404
export function startsWithExplicitCommand(prompt) {
368405
return /^(~|\/)/.test(String(prompt || '').trim());
369406
}
@@ -396,6 +433,8 @@ export function classifyPrompt(prompt) {
396433
const decisionHeavy = hasQuestionIntent(text) && hasAny(text, DECISION_PATTERNS);
397434
const capabilityQuery = explicitHostFeature || (hasQuestionIntent(text) && hasAny(text, HOST_TOPIC_PATTERNS)) || mcp;
398435
const codeResearch = research && !capabilityQuery;
436+
const skillSurface = hasAny(text, SKILL_SURFACE_PATTERNS);
437+
const skillWorkflowLike = skillSurface || hasAny(text, SKILL_DISCOVERY_PATTERNS);
399438

400439
const tracks = [];
401440
if (frontend) tracks.push('frontend');
@@ -435,6 +474,8 @@ export function classifyPrompt(prompt) {
435474
decisionHeavy,
436475
capabilityQuery,
437476
codeResearch,
477+
skillSurface,
478+
skillWorkflowLike,
438479
tracks,
439480
boundedImplementation,
440481
toolSearchFirst: capabilityQuery,

0 commit comments

Comments
 (0)