diff --git a/skills/yanghuajun336/helm-chart-scaffolding/SKILL.md b/skills/yanghuajun336/helm-chart-scaffolding/SKILL.md index 2657a9b..03e0ffd 100644 --- a/skills/yanghuajun336/helm-chart-scaffolding/SKILL.md +++ b/skills/yanghuajun336/helm-chart-scaffolding/SKILL.md @@ -1 +1,560 @@ -Your SKILL.md content goes here. \ No newline at end of file +--- +名称:helm-chart-scaffolding +描述:设计、组织和管理 Helm 图表,用于对 Kubernetes 应用程序进行模板化和打包,同时使用可重复使用的配置。在创建 Helm 图表、打包 Kubernetes 应用程序或实现模板化部署时使用。 +--- + + +# Helm 图表模板生成 + +有关为打包和部署 Kubernetes 应用程序创建、组织和管理 Helm 图表的全面指南。 + +## 目的 + +此技能提供了构建可投入生产的 Helm 图表的分步说明,包括图表结构、模板模式、值管理以及验证策略。 + +## 何时使用此技能 + +在您需要以下情况时使用此技能: + +- 从零开始创建新的 Helm 图表 +- 将 Kubernetes 应用程序打包以进行分发 +- 使用 Helm 管理多环境部署 +- 为可重用的 Kubernetes 清单实现模板化 +- 设置 Helm 图表仓库 +- 遵循 Helm 最佳实践和约定 + +## Helm 概述 + +**Helm** 是 Kubernetes 的包管理器: + +- 为可重用性创建 Kubernetes 清单模板 +- 管理应用程序的发布和回滚 +- 处理图表之间的依赖关系 +- 为部署提供版本控制 +- 简化跨环境的配置管理 + +## 分步工作流程 + +### 1. 初始化图表结构 + +**创建新图表:** + +```bash +helm create my-app +``` + +**标准图表结构:** + +``` +my-app/ +├── Chart.yaml # 图表元数据 +├── values.yaml # 默认配置值 +├── charts/ # 图表依赖 +├── templates/ # Kubernetes 清单模板 +│ ├── NOTES.txt # 安装后说明 +│ ├── _helpers.tpl # 模板辅助函数 +│ ├── deployment.yaml +│ ├── service.yaml +│ ├── ingress.yaml +│ ├── serviceaccount.yaml +│ ├── hpa.yaml +│ └── tests/ +│ └── test-connection.yaml +└── .helmignore # 忽略的文件 +``` + +### 2. 配置 Chart.yaml + +**图表元数据定义了包:** + +```yaml +apiVersion: v2 +name: my-app +description: 一个用于我的应用程序的 Helm 图表 +type: application +version: 1.0.0 # 图表版本 +appVersion: "2.1.0" # 应用程序版本 + +# 图表发现关键字 +keywords: + - web + - api + - backend + +# 维护者信息 +maintainers: + - name: yanghuajun336 + email: yanghuajun336@example.com + url: https://github.com/yanghuajun336/my-app + +# 源码仓库 +sources: + - https://github.com/yanghuajun336/my-app + +# 主页 +home: https://github.com/yanghuajun336 + +# 图表图标 +icon: https://example.com/icon.png + +# 依赖 +dependencies: + - name: postgresql + version: "12.0.0" + repository: "https://charts.bitnami.com/bitnami" + condition: postgresql.enabled + - name: redis + version: "17.0.0" + repository: "https://charts.bitnami.com/bitnami" + condition: redis.enabled +``` + +**参考:** 请参阅 `assets/Chart.yaml.template` 获取完整示例 + +### 3. 设计 values.yaml 结构 + +**按层次组织值:** +```yaml +# 镜像配置 +image: + repository: myapp + tag: "1.0.0" + pullPolicy: IfNotPresent + +# 副本数量 +replicaCount: 3 + +# Service 配置 +service: + type: ClusterIP + port: 80 + targetPort: 8080 + +# Ingress 配置 +ingress: + enabled: false + className: nginx + hosts: + - host: app.example.com + paths: + - path: / + pathType: Prefix + +# 资源限制 +resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" + +# 自动扩缩容 +autoscaling: + enabled: false + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 + +# 环境变量 +env: + - name: LOG_LEVEL + value: "info" + +# ConfigMap 数据 +configMap: + data: + APP_MODE: production + +# 依赖 +postgresql: + enabled: true + auth: + database: myapp + username: myapp + +redis: + enabled: false +``` + +**参考:** 请参阅 `assets/values.yaml.template` 获取完整结构 + +### 4. 创建模板文件 + +**使用 Go 模板语法结合 Helm 函数:** + +**templates/deployment.yaml:** + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "my-app.fullname" . }} + labels: + {{- include "my-app.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "my-app.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "my-app.selectorLabels" . | nindent 8 }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.targetPort }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + env: + {{- toYaml .Values.env | nindent 12 }} +``` + +### 5. 创建模板辅助函数 + +**templates/\_helpers.tpl:** + +```yaml +{{/* +展开图表名称。 +*/}} +{{- define "my-app.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +创建默认的完整限定应用名称。 +*/}} +{{- define "my-app.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +通用标签 +*/}} +{{- define "my-app.labels" -}} +helm.sh/chart: {{ include "my-app.chart" . }} +{{ include "my-app.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +选择器标签 +*/}} +{{- define "my-app.selectorLabels" -}} +app.kubernetes.io/name: {{ include "my-app.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} +``` + +### 6. 管理依赖 + +**在 Chart.yaml 中添加依赖:** + +```yaml +dependencies: + - name: postgresql + version: "12.0.0" + repository: "https://charts.bitnami.com/bitnami" + condition: postgresql.enabled +``` + +**更新依赖:** + +```bash +helm dependency update +helm dependency build +``` + +**覆盖依赖的配置值:** + +```yaml +# values.yaml +postgresql: + enabled: true + auth: + database: myapp + username: myapp + password: changeme + primary: + persistence: + enabled: true + size: 10Gi +``` + +### 7. 测试与验证 + +**验证命令:** + +```bash +# 检查图表语法 +helm lint my-app/ + +# 模拟安装(不实际部署) +helm install my-app ./my-app --dry-run --debug + +# 渲染模板 +helm template my-app ./my-app + +# 使用指定值文件渲染模板 +helm template my-app ./my-app -f values-prod.yaml + +# 显示计算后的值 +helm show values ./my-app +``` + +**验证脚本:** + +```bash +#!/bin/bash +set -e + +echo "正在检查图表语法..." +helm lint . + +echo "正在测试模板渲染..." +helm template test-release . --dry-run + +echo "正在检查必填值..." +helm template test-release . --validate + +echo "所有验证均已通过!" +``` + +**参考:** 请参阅 `scripts/validate-chart.sh` + +### 8. 打包与分发 + +**打包图表:** + +```bash +helm package my-app/ +# 生成文件:my-app-1.0.0.tgz +``` + +**创建图表仓库:** + +```bash +# 生成索引文件 +helm repo index . + +# 上传到仓库 +# AWS S3 示例 +aws s3 sync . s3://my-helm-charts/ --exclude "*" --include "*.tgz" --include "index.yaml" +``` + +**使用图表:** + +```bash +helm repo add my-repo https://charts.example.com +helm repo update +helm install my-app my-repo/my-app +``` + +### 9. 多环境配置 + +**针对不同环境的值文件:** + +``` +my-app/ +├── values.yaml # 默认配置 +├── values-dev.yaml # 开发环境 +├── values-staging.yaml # 预发布环境 +└── values-prod.yaml # 生产环境 +``` + +**values-prod.yaml:** + +```yaml +replicaCount: 5 + +image: + tag: "2.1.0" + +resources: + requests: + memory: "512Mi" + cpu: "500m" + limits: + memory: "1Gi" + cpu: "1000m" + +autoscaling: + enabled: true + minReplicas: 3 + maxReplicas: 20 + +ingress: + enabled: true + hosts: + - host: app.example.com + paths: + - path: / + pathType: Prefix + +postgresql: + enabled: true + primary: + persistence: + size: 100Gi +``` + +**使用环境值文件安装:** + +```bash +helm install my-app ./my-app -f values-prod.yaml --namespace production +``` + +### 10. 实现 Hook 与测试 + +**安装前 Hook:** + +```yaml +# templates/pre-install-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "my-app.fullname" . }}-db-setup + annotations: + "helm.sh/hook": pre-install + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": hook-succeeded +spec: + template: + spec: + containers: + - name: db-setup + image: postgres:15 + command: ["psql", "-c", "CREATE DATABASE myapp"] + restartPolicy: Never +``` + +**测试连接:** + +```yaml +# templates/tests/test-connection.yaml +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "my-app.fullname" . }}-test-connection" + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never +``` + +**运行测试:** + +```bash +helm test my-app +``` + +## 常用模式 + +### 模式 1:条件化资源 + +```yaml +{{- if .Values.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "my-app.fullname" . }} +spec: + # ... +{{- end }} +``` + +### 模式 2:遍历列表 + +```yaml +env: +{{- range .Values.env }} +- name: {{ .name }} + value: {{ .value | quote }} +{{- end }} +``` + +### 模式 3:引入外部文件 + +```yaml +data: + config.yaml: | + {{- .Files.Get "config/application.yaml" | nindent 4 }} +``` + +### 模式 4:全局值 + +```yaml +global: + imageRegistry: docker.io + imagePullSecrets: + - name: regcred + +# 在模板中使用: +image: {{ .Values.global.imageRegistry }}/{{ .Values.image.repository }} +``` + +## 最佳实践 + +1. **使用语义化版本号** 管理图表和应用版本 +2. **为所有配置项添加注释** 在 values.yaml 中 +3. **使用模板辅助函数** 处理重复逻辑 +4. **打包前验证图表** 确保无误 +5. **明确固定依赖版本号** +6. **为可选资源使用条件判断** +7. **遵循命名规范**(小写字母,连字符分隔) +8. **在 NOTES.txt 中** 提供使用说明 +9. **通过辅助函数** 统一添加标签 +10. **在所有环境中** 测试安装流程 + +## 故障排查 + +**模板渲染错误:** + +```bash +helm template my-app ./my-app --debug +``` + +**依赖问题:** + +```bash +helm dependency update +helm dependency list +``` + +**安装失败:** + +```bash +helm install my-app ./my-app --dry-run --debug +kubectl get events --sort-by='.lastTimestamp' +``` + + +## 相关技能 + +- `k8s-manifest-generator` - 用于创建基础 Kubernetes 清单 +- `gitops-workflow` - 用于自动化 Helm 图表部署 diff --git a/skills/yanghuajun336/skill-L10n/SKILL.md b/skills/yanghuajun336/skill-L10n/SKILL.md new file mode 100644 index 0000000..0f9a7de --- /dev/null +++ b/skills/yanghuajun336/skill-L10n/SKILL.md @@ -0,0 +1,79 @@ +--- +name: skill-L10n +description: skill-L10n 是一个面向 Agent Skill 的语境感知本地化工具,主要用于将英文的 Agent skill 文档(尤其 `SKILL.md`)和参考文件翻译为中文,同时按需翻译脚本中的注释。 +--- + + +# skill-L10n + +## 简介 +---- +skill-L10n 是面向 Agent Skill 的语境感知本地化工具。它以 SKILL.md 为优先目标,结合上下文判断哪些段落需要翻译,并对 references 中的说明与 scripts 目录下的脚本注释进行有选择性的翻译。目标是尽量保留代码示例、参数名与命令行示例不被误翻,便于审阅与回滚。 + +## 主要特性 +--- +- 针对 Markdown / SKILL.md:段落级上下文判断(前后段落一并作为上下文),仅翻译模型判定为“用户可读/说明性文本”的段落。保留 code fence、表格、frontmatter、inline code。 +- 针对脚本/代码文件:只处理注释行;默认保留原注释并在其下追加一行翻译(与原注释使用相同的注释前缀和缩进)。 +- 可配置证书校验:通过环境变量 `SKILL_L10N_VERIFY` 控制 http 客户端的 SSL 验证(默认 false,以兼容企业自签/代理环境)。 +- 简单缓存:避免对完全相同文本重复调用翻译 API,节省调用成本。 +- 变更报告:为每个被修改的文件生成 unified diff(.diff)报告,便于审阅与回滚。 +- 错误容忍:翻译失败时脚本会跳过并保留原文,同时在报告中标注(不会中断批量处理)。 + +## 快速开始 +--- +1. 安装依赖(示例): +```bash +python3 -m pip install --upgrade openai httpx +``` + +2. 设置环境变量(必须): +```bash +export DEEPSEEK_API_TOKEN="your_token_here" +# 默认为 false,若在安全公网环境或已配��受信根证书可设为 true +export SKILL_L10N_VERIFY=false +``` + +3. 运行(示例): +```bash +# 在 skill-L10n 目录下对某个 skill 进行本地化并把 diff 报告写入 ./reports +python3 scripts/skill_l10n.py ./skills/your-skill ./reports + +# 或使用包装脚本 +scripts/run.sh ./skills/your-skill ./reports +``` + +## CLI 参数与模式 +--------------- +- `--src`:源语言(默认 `auto`) +- `--tgt`:目标语言(默认 `zh`) +- `--mode`:全局 Markdown 模式:`replace`(替换,默认)或 `append`(在原文后追加译文) + - 注意:代码文件注释的默认处理遵循 `--preserve-original-for-code` 设置(见下)。 +- `--preserve-original-for-code`:`yes`(默认)或 `no`。`yes` 时在原注释下追加翻译行;`no` 时直接替换注释。 +- 环境变量 `SKILL_L10N_VERIFY`:`true` 或 `false`(默认 false)。控制 httpx.Client(verify=... )。 + +## 翻译策略与细节 +---------------- +- Markdown / SKILL.md: + - 脚本会把正文按段落拆分,隐藏并保留 code fence,再对每个 prose 段落连同前后上下文询问模型“是否翻译 + 翻译��果”。 + - inline code(如 `my_func()`)、参数名、命令行示例与表格项通常被保护不翻译。 + - 默认行为:替换(即不保留英文原文)。可通过 `--mode append` 改为在原文后追加译文。 + +- 脚本与代码文件: + - 仅对注释行翻译决策。若模型判定需要翻译且 `--preserve-original-for-code=yes`(默认),则保留原注释并在下一行添加同样注释前缀的译文(保持缩进)。 + - 示例: + ```python + # This function adds two numbers + # 此函数用于将两个数字相加 + def add(a, b): + return a + b + ``` + +## 缓存与成本控制 +--- +- 内存级缓存用于避免相同文本的重复请求。对于大规模仓库建议先在小规模 demo 上跑通并查看 diff,再批量执行,控制 API 成本。 + +## 安全与注意事项 +--- +- 默认 `SKILL_L10N_VERIFY=false`,以兼容一些企业环境(自签或代理)。强烈建议在公网或生产环境将 `SKILL_L10N_VERIFY=true` 并确保系统根证书链完整。 +- 请勿在代码中明文保存 API Token,使用环境变量(DEEPSEEK_API_TOKEN)。 +- 脚本会原地修改目标目录下文件,请在 git 仓库中使用分支/暂存区进行变更,或先备份目标目录。每个修改会在 `report_dir` 生成 `.diff` 报告,便于审阅与回滚。 diff --git a/skills/yanghuajun336/skill-L10n/references/skills-translator-examples.md b/skills/yanghuajun336/skill-L10n/references/skills-translator-examples.md new file mode 100644 index 0000000..141a248 --- /dev/null +++ b/skills/yanghuajun336/skill-L10n/references/skills-translator-examples.md @@ -0,0 +1,71 @@ +# skills-translator Examples + +## 1. 简单 Python 注释 +### Before +```python +# This function adds two numbers +def add(a, b): + return a + b +``` +### After +```python +# This function adds two numbers +# 此函数用于将两个数字相加 +def add(a, b): + return a + b +``` + +## 2. YAML 注释(前后对比) +### Before +```yaml +# Default values for my chart. +replicaCount: 1 +``` +### After +```yaml +# Default values for my chart. +# 我的 chart 的默认值。 +replicaCount: 1 +``` + +## 3. SKILL.md 多段落示例(上下文判断) +### Before +```markdown +# My Skill + +This skill fetches data from the API and returns a parsed object. + +Example: +```bash +curl -X GET "https://api.example.com/data?limit=10" +``` + +Notes: +- Keep your API key secret. +``` +### After (示例) +```markdown +# My Skill + +此技能从 API 获取数据并返回解析后的对象。 + +Example: +```bash +curl -X GET "https://api.example.com/data?limit=10" +``` + +Notes: +- 将你的 API key 保管好。 +``` + +## 4. 多段落上下文敏感 (演示保持命名与代码不翻译) +### Before +```markdown +### Usage +Call `my_skill.run()` to execute the skill. The parameter `user_id` accepts integer IDs. +``` +### After +```markdown +### Usage +调用 `my_skill.run()` 来执行该 skill。参数 `user_id` 接受整数 ID。 +``` diff --git a/skills/yanghuajun336/skill-L10n/script/run.sh b/skills/yanghuajun336/skill-L10n/script/run.sh new file mode 100644 index 0000000..f7529b3 --- /dev/null +++ b/skills/yanghuajun336/skill-L10n/script/run.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# run.sh - wrapper for skill_l10n.py +# Usage: ./run.sh [--src en] [--tgt zh] +set -e +TARGET="$1" +REPORT="$2" +shift 2 || true +export SKILL_L10N_VERIFY=${SKILL_L10N_VERIFY:-false} +python3 "$(dirname "$0")/skill_l10n.py" "$TARGET" "$REPORT" "$@" diff --git a/skills/yanghuajun336/skill-L10n/script/skill_l10n.py b/skills/yanghuajun336/skill-L10n/script/skill_l10n.py new file mode 100644 index 0000000..a8a82c2 --- /dev/null +++ b/skills/yanghuajun336/skill-L10n/script/skill_l10n.py @@ -0,0 +1,304 @@ +#!/usr/bin/env python3 +# name=skill_l10n.py +# -*- coding: utf-8 -*- +""" +skill_l10n.py +Context-aware localization tool for Agent Skills (SKILL.md + references + scripts). +Usage: + python skill_l10n.py [--src LANG] [--tgt LANG] [--mode replace|append] [--preserve-original-for-code yes|no] + +Environment: + DEEPSEEK_API_TOKEN - required + SKILL_L10N_VERIFY - 'true' or 'false' (default 'false') +Dependencies: + pip install openai httpx +""" +import os +import sys +import re +import json +import time +import argparse +import difflib +from pathlib import Path +from typing import Dict, Tuple, Optional + +from openai import OpenAI +import httpx + +# ----------------------- +# Configuration defaults +# ----------------------- +DEFAULT_MODEL = "deepseek-chat" +CACHE_TTL = 24 * 3600 # 1 day + +# ----------------------- +# Translator wrapper +# ----------------------- +class SmartTranslator: + def __init__(self, token_env="DEEPSEEK_API_TOKEN", verify_ssl: bool = False, model=DEFAULT_MODEL): + self.token = os.getenv(token_env, "") + if not self.token: + raise ValueError(f"Please set environment variable {token_env}") + self.verify = verify_ssl + self._httpx_client = httpx.Client(verify=self.verify) + self._client = OpenAI(base_url="https://api.deepseek.com/v1", api_key=self.token, http_client=self._httpx_client) + self.model = model + self.cache: Dict[str, Tuple[float, dict]] = {} + + def close(self): + try: + self._httpx_client.close() + except Exception: + pass + + def _cache_get(self, key: str) -> Optional[dict]: + ent = self.cache.get(key) + if not ent: + return None + ts, val = ent + if time.time() - ts > CACHE_TTL: + del self.cache[key] + return None + return val + + def _cache_set(self, key: str, val: dict): + self.cache[key] = (time.time(), val) + + def decide_and_translate(self, paragraph: str, context: str = "", source_language="auto", target_language="zh") -> dict: + """ + Ask model to decide whether to translate and return translation if should_translate. + Return dict: + { should_translate: bool, translated_text: str, reason: str } + """ + key = f"decide::{source_language}::{target_language}::{paragraph}::ctx::{context}" + cached = self._cache_get(key) + if cached: + return cached + system_msg = ( + "You are a careful translator and content reviewer. " + "Given a paragraph and surrounding context, return a JSON object with keys: " + "should_translate (boolean), translated_text (string), reason (string). " + "Do NOT translate code, CLI examples, file names, parameter names, or inline code. " + "If you translate, preserve technical tokens and inline code unchanged." + ) + user_msg = f"Context:\n{context}\n\nParagraph:\n{paragraph}\n\nSource: {source_language}\nTarget: {target_language}" + try: + completion = self._client.chat.completions.create( + model=self.model, + messages=[ + {"role": "system", "content": system_msg}, + {"role": "user", "content": user_msg}, + ], + ) + raw = completion.choices[0].message.content.strip() + # try extract JSON + first = raw.find("{") + last = raw.rfind("}") + json_text = raw[first:last+1] if first != -1 and last != -1 else raw + data = json.loads(json_text) + result = { + "should_translate": bool(data.get("should_translate")), + "translated_text": data.get("translated_text", "") or "", + "reason": data.get("reason", "") or "", + } + except Exception as e: + result = {"should_translate": False, "translated_text": "", "reason": f"api_error:{e}"} + self._cache_set(key, result) + return result + +# ----------------------- +# File utilities +# ----------------------- +MD_FENCE_RE = re.compile(r'```[\s\S]*?```', flags=re.MULTILINE) +INLINE_CODE_RE = re.compile(r'`[^`]+`') +FRONTMATTER_RE = re.compile(r'^(---\n[\s\S]*?\n---\n)', flags=re.MULTILINE) +COMMENT_PATTERNS = [ + re.compile(r'^[ \t]*#'), + re.compile(r'^[ \t]*//'), + re.compile(r'^[ \t]*/\*'), + re.compile(r'^[ \t]*\*'), + re.compile(r'^[ \t]*--'), + re.compile(r'^[ \t]*;'), + re.compile(r'^[ \t]*REM ', re.I), + re.compile(r'^[ \t]*