mirror of
https://github.com/ZhuLinsen/daily_stock_analysis
synced 2026-09-20 02:43:35 +08:00
chore: harden ai governance assets (#738)
This commit is contained in:
10
.claude/skills/README.md
Normal file
10
.claude/skills/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Repository Claude Skills
|
||||
|
||||
本目录存放仓库级协作 skills,属于版本库资产。
|
||||
|
||||
- 规则真源:仓库根目录 `AGENTS.md`
|
||||
- 兼容入口:根目录 `CLAUDE.md`(应为指向 `AGENTS.md` 的软链接)
|
||||
- 本目录中的 skill 需要与 `AGENTS.md` 保持一致
|
||||
- `.claude/reviews/` 属于本地分析产物,不作为规则真源
|
||||
|
||||
如果未来需要兼容其他 agent 目录(如 `.agents/skills/` 或 `.github/skills/`),应先明确单一真源,再通过脚本或镜像同步,而不是手工长期维护多份同义内容。
|
||||
124
.claude/skills/analyze-issue/SKILL.md
Normal file
124
.claude/skills/analyze-issue/SKILL.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# Analyze Issue
|
||||
|
||||
分析 GitHub Issue,判断其真实性、优先级、仓库责任边界与建议动作。
|
||||
|
||||
**Repository**: https://github.com/ZhuLinsen/daily_stock_analysis/issues
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/analyze-issue <issue_number>
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
分析时使用简洁中文,优先遵循仓库根目录 `AGENTS.md`。
|
||||
|
||||
### Step 1: 拉取 Issue 信息
|
||||
|
||||
```bash
|
||||
gh issue view <issue_number> --repo ZhuLinsen/daily_stock_analysis
|
||||
gh issue view <issue_number> --repo ZhuLinsen/daily_stock_analysis --comments
|
||||
```
|
||||
|
||||
如为 bug,优先核对 issue 模板中是否提供了以下信息:
|
||||
|
||||
- 是否已同步到最新版本
|
||||
- commit hash / 版本基线
|
||||
- 运行环境与复现步骤
|
||||
- 日志或报错信息
|
||||
|
||||
### Step 2: 回答 4 个核心问题
|
||||
|
||||
1. 版本是否明确
|
||||
2. 问题是否真实且可验证
|
||||
3. 是否属于仓库责任边界
|
||||
4. 是否值得立即处理
|
||||
|
||||
### Step 3: 结合仓库现状做证据检查
|
||||
|
||||
- 阅读相关代码、配置、测试、脚本、工作流与文档
|
||||
- 如果问题涉及 API、数据源 fallback、报告生成、通知发送、认证、桌面端、发布流程,明确写出影响面
|
||||
- 判断是实际 bug、环境配置问题、使用方式问题、还是外部依赖问题
|
||||
- 如怀疑已被修复,检查当前代码而不是只看 issue 描述
|
||||
|
||||
### Step 4: 形成结论
|
||||
|
||||
至少给出以下字段:
|
||||
|
||||
- `版本基线`:最新 / 非最新 / 未提供
|
||||
- `是否合理`:是/否 + 理由
|
||||
- `是否是 issue`:是/否 + 理由
|
||||
- `是否好解决`:是/否 + 难点
|
||||
- `结论`:`成立 / 部分成立 / 不成立`
|
||||
- `分类`:`bug / feature / docs / question / external`
|
||||
- `优先级`:`P0 / P1 / P2 / P3`
|
||||
- `难度`:`easy / medium / hard`
|
||||
- `建议动作`:`立即修复 / 排期修复 / 文档澄清 / 关闭`
|
||||
|
||||
### Step 5: 生成分析文档
|
||||
|
||||
保存到 `.claude/reviews/issues/issue-<number>.md`
|
||||
|
||||
## Output Document Format
|
||||
|
||||
```markdown
|
||||
# Issue #<number> Analysis
|
||||
|
||||
**Date**: YYYY-MM-DD
|
||||
**Status**: Pending Review
|
||||
|
||||
## Summary
|
||||
|
||||
- 版本基线:
|
||||
- 是否合理:
|
||||
- 是否是 issue:
|
||||
- 是否好解决:
|
||||
- 结论:
|
||||
- 分类:
|
||||
- 优先级:
|
||||
- 难度:
|
||||
- 建议动作:
|
||||
|
||||
## Evidence
|
||||
|
||||
- 关键 issue 信息:
|
||||
- 关键代码/脚本/工作流证据:
|
||||
|
||||
## Impact Scope
|
||||
|
||||
- 受影响模块:
|
||||
- 受影响运行路径(本地 / Docker / GitHub Actions / API / Web / Desktop):
|
||||
|
||||
## Root Cause / Main Reasoning
|
||||
|
||||
<根因或主要判断依据>
|
||||
|
||||
## Proposed Handling
|
||||
|
||||
<建议修复、澄清或关闭方式>
|
||||
|
||||
## Risks And Rollback
|
||||
|
||||
- 风险点:
|
||||
- 若修复,回滚方式:
|
||||
|
||||
## Draft Reply
|
||||
|
||||
<建议回复内容>
|
||||
```
|
||||
|
||||
## Allowed Auto-Actions (No Confirmation Needed)
|
||||
|
||||
- 拉取 issue 详情与评论
|
||||
- 阅读相关代码、配置、脚本、工作流和文档
|
||||
- 生成分析文档
|
||||
|
||||
## Actions Requiring Confirmation
|
||||
|
||||
执行以下动作前,先询问用户:
|
||||
|
||||
1. 添加或修改标签
|
||||
2. 在 issue 下评论
|
||||
3. 关闭 issue
|
||||
4. 开始修复 issue
|
||||
122
.claude/skills/analyze-pr/SKILL.md
Normal file
122
.claude/skills/analyze-pr/SKILL.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# Analyze PR
|
||||
|
||||
分析 GitHub Pull Request,评估必要性、描述完整性、验证证据、主要风险与是否可直接合入。
|
||||
|
||||
**Repository**: https://github.com/ZhuLinsen/daily_stock_analysis/pulls
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/analyze-pr <pr_number>
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
分析时使用简洁中文,优先遵循仓库根目录 `AGENTS.md` 和 `.github/PULL_REQUEST_TEMPLATE.md`。
|
||||
|
||||
### Step 1: 拉取 PR 基本信息
|
||||
|
||||
```bash
|
||||
gh pr view <pr_number> --repo ZhuLinsen/daily_stock_analysis
|
||||
gh pr view <pr_number> --repo ZhuLinsen/daily_stock_analysis --comments
|
||||
gh pr checks <pr_number> --repo ZhuLinsen/daily_stock_analysis
|
||||
gh pr diff <pr_number> --repo ZhuLinsen/daily_stock_analysis
|
||||
```
|
||||
|
||||
如有失败的 CI,优先查看失败日志,而不是立刻在本地重跑全部检查:
|
||||
|
||||
```bash
|
||||
gh run view <run_id> --log-failed
|
||||
```
|
||||
|
||||
### Step 2: 按仓库模板检查描述完整性
|
||||
|
||||
对照 `.github/PULL_REQUEST_TEMPLATE.md`,确认是否覆盖:
|
||||
|
||||
- `PR Type`
|
||||
- `Background And Problem`
|
||||
- `Scope Of Change`
|
||||
- `Issue Link`
|
||||
- `Verification Commands And Results`
|
||||
- `Compatibility And Risk`
|
||||
- `Rollback Plan`
|
||||
|
||||
### Step 3: 优先使用 CI / Diff 证据
|
||||
|
||||
- 先根据 `gh pr checks`、PR diff、现有测试与工作流日志判断问题
|
||||
- 仅当 CI 未覆盖改动面、CI 结果不足以定性问题、或需要验证关键回归风险时,再补充本地最小验证
|
||||
- 不要默认切换当前分支或执行 `gh pr checkout`
|
||||
|
||||
如果必须补本地验证,按改动面选择最接近的检查,例如:
|
||||
|
||||
- 后端:`./scripts/ci_gate.sh` 或 `python -m py_compile <changed_python_files>`
|
||||
- 前端:`cd apps/dsa-web && npm ci && npm run lint && npm run build`
|
||||
- 桌面端:先构建 Web,再构建 Electron
|
||||
|
||||
### Step 4: 评估正确性与风险
|
||||
|
||||
重点检查:
|
||||
|
||||
- 是否解决了明确问题,且没有夹带无关改动
|
||||
- 是否破坏 API / Schema / Web / Desktop 兼容性
|
||||
- 是否破坏 fallback、降级路径、通知链路或发布流程
|
||||
- 是否存在明显逻辑错误、异常吞没、安全问题、配置语义变化未同步文档
|
||||
|
||||
### Step 5: 生成评审文档
|
||||
|
||||
保存到 `.claude/reviews/prs/pr-<number>.md`
|
||||
|
||||
## Output Document Format
|
||||
|
||||
```markdown
|
||||
# PR #<number> Analysis
|
||||
|
||||
**Date**: YYYY-MM-DD
|
||||
**Status**: Pending Review
|
||||
|
||||
## Findings
|
||||
|
||||
- [严重级别] file:line - 问题描述
|
||||
|
||||
## Summary
|
||||
|
||||
- 必要性:
|
||||
- 是否有对应 issue:
|
||||
- PR 类型:
|
||||
- description 完整性:
|
||||
- 验证情况:
|
||||
- 主要风险:
|
||||
- 是否可直接合入:
|
||||
|
||||
## Validation Evidence
|
||||
|
||||
- CI 结论:
|
||||
- 本地补充验证(如有):
|
||||
|
||||
## Compatibility And Risk
|
||||
|
||||
- API / Web / Desktop:
|
||||
- 配置 / Docker / GitHub Actions:
|
||||
- fallback / 通知 / 报告结构:
|
||||
|
||||
## Draft Review Comment
|
||||
|
||||
<建议评论内容>
|
||||
```
|
||||
|
||||
## Allowed Auto-Actions (No Confirmation Needed)
|
||||
|
||||
- 拉取 PR 元数据、diff、评论和 CI 状态
|
||||
- 阅读相关代码、模板、工作流与文档
|
||||
- 在必要时执行最小化本地验证
|
||||
- 生成评审文档
|
||||
|
||||
## Actions Requiring Confirmation
|
||||
|
||||
执行以下动作前,先询问用户:
|
||||
|
||||
1. 发布评论
|
||||
2. Approve PR
|
||||
3. Request changes
|
||||
4. Merge PR
|
||||
5. 关闭 PR
|
||||
98
.claude/skills/fix-issue/SKILL.md
Normal file
98
.claude/skills/fix-issue/SKILL.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Fix Issue
|
||||
|
||||
基于 issue 分析结果实现修复,并按仓库规则补齐验证、风险与回滚说明。
|
||||
|
||||
**Repository**: https://github.com/ZhuLinsen/daily_stock_analysis
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
/fix-issue <issue_number>
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
优先先完成 `/analyze-issue <issue_number>`,确保问题成立且边界清晰。
|
||||
|
||||
## Instructions
|
||||
|
||||
### Step 1: 确认分析基线
|
||||
|
||||
检查 `.claude/reviews/issues/issue-<number>.md` 是否存在;如果不存在,先补做 issue 分析或在本次修复中补齐最小分析结论。
|
||||
|
||||
### Step 2: 选择安全的工作方式
|
||||
|
||||
- 默认基于当前工作树做最小相关改动
|
||||
- 不要默认执行 `git pull`
|
||||
- 不要默认切换分支或改写用户当前工作状态
|
||||
- 如果用户明确要求建分支,再执行最小必要的分支操作
|
||||
|
||||
### Step 3: 实施修复
|
||||
|
||||
- 根据 issue 结论定位相关文件
|
||||
- 优先复用现有模块、配置入口、脚本和测试
|
||||
- 保持默认行为向后兼容,避免破坏 fallback / fail-open
|
||||
- 如果修复涉及用户可见行为、配置语义、CLI/API、部署、通知、报告结构,要同步更新 `README.md`、`docs/CHANGELOG.md`、`.env.example`
|
||||
|
||||
### Step 4: 按改动面验证
|
||||
|
||||
按 `AGENTS.md` 的验证矩阵执行最接近的检查:
|
||||
|
||||
- 后端优先:`./scripts/ci_gate.sh`
|
||||
- 最低后端要求:`python -m py_compile <changed_python_files>`
|
||||
- 前端:`cd apps/dsa-web && npm ci && npm run lint && npm run build`
|
||||
- 桌面端:先构建 Web,再构建桌面端
|
||||
|
||||
如无法完成完整验证,必须记录缺口、原因与潜在风险。
|
||||
|
||||
### Step 5: 更新 issue 分析文档
|
||||
|
||||
在 `.claude/reviews/issues/issue-<number>.md` 中补充:
|
||||
|
||||
```markdown
|
||||
## Fix Implementation
|
||||
|
||||
**Date**: YYYY-MM-DD
|
||||
|
||||
### Changes Made
|
||||
|
||||
- 文件与改动点:
|
||||
|
||||
### Validation
|
||||
|
||||
- 已执行:
|
||||
- 未执行:
|
||||
|
||||
### Risks
|
||||
|
||||
- 风险点:
|
||||
|
||||
### Rollback
|
||||
|
||||
- 回滚方式:
|
||||
```
|
||||
|
||||
### Step 6: 需要确认的后续动作
|
||||
|
||||
只有在用户明确确认后,才执行:
|
||||
|
||||
- 建分支
|
||||
- `git commit`
|
||||
- `git push`
|
||||
- 创建 PR
|
||||
- 在 issue 下回复或关闭 issue
|
||||
|
||||
## Allowed Auto-Actions (No Confirmation Needed)
|
||||
|
||||
- 阅读和分析代码
|
||||
- 应用与当前任务直接相关的最小修复
|
||||
- 运行非破坏性的本地验证
|
||||
- 更新本地 issue 分析文档
|
||||
|
||||
## Actions Requiring Confirmation
|
||||
|
||||
1. 切换或创建分支
|
||||
2. `git commit`
|
||||
3. `git push`
|
||||
4. 创建 PR
|
||||
5. 回复或关闭 issue
|
||||
33
.github/copilot-instructions.md
vendored
Normal file
33
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
# Repository Instructions
|
||||
|
||||
Canonical source: [`AGENTS.md`](../AGENTS.md).
|
||||
|
||||
If any instruction in this file conflicts with `AGENTS.md`, follow `AGENTS.md`.
|
||||
|
||||
## Core Rules
|
||||
|
||||
- Respect directory boundaries:
|
||||
- Backend: `src/`, `data_provider/`, `api/`, `bot/`
|
||||
- Web: `apps/dsa-web/`
|
||||
- Desktop: `apps/dsa-desktop/`
|
||||
- Deployment/workflows: `scripts/`, `.github/workflows/`, `docker/`
|
||||
- Do not run `git commit`, `git tag`, or `git push` without explicit user confirmation.
|
||||
- Do not hardcode secrets, accounts, ports, model names, absolute environment-specific paths, or environment-specific branches.
|
||||
- Reuse existing modules, configuration entrypoints, scripts, and tests instead of adding parallel implementations.
|
||||
- For user-visible behavior changes, CLI/API changes, deployment changes, notification changes, or report-structure changes, update `README.md` and `docs/CHANGELOG.md`.
|
||||
- When config semantics change, sync `.env.example` and assess impact on local runs, Docker, GitHub Actions, API, Web, and Desktop.
|
||||
|
||||
## Validation
|
||||
|
||||
- Backend changes: prefer `./scripts/ci_gate.sh`; at minimum run `python -m py_compile` on changed Python files and the closest deterministic tests.
|
||||
- Web changes: run `cd apps/dsa-web && npm ci && npm run lint && npm run build`.
|
||||
- Desktop changes: build web first, then desktop if feasible.
|
||||
- Review work should prioritize CI evidence (`gh pr checks`, workflow logs) before re-running local validation.
|
||||
- AI governance changes: run `python scripts/check_ai_assets.py`.
|
||||
|
||||
## AI Asset Governance
|
||||
|
||||
- `AGENTS.md` is the single source of truth for repository AI collaboration rules.
|
||||
- `CLAUDE.md` must remain a symlink to `AGENTS.md`.
|
||||
- Use `.github/instructions/*.instructions.md` for path-specific guidance.
|
||||
- Current repository collaboration skills live in `.claude/skills/`; keep them aligned with `AGENTS.md`.
|
||||
11
.github/instructions/backend.instructions.md
vendored
Normal file
11
.github/instructions/backend.instructions.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
applyTo: "main.py,server.py,src/**/*.py,data_provider/**/*.py,api/**/*.py,bot/**/*.py,tests/**/*.py"
|
||||
---
|
||||
|
||||
# Backend Instructions
|
||||
|
||||
- Preserve current pipeline boundaries and reuse existing services, repositories, schemas, and fallback logic instead of creating parallel paths.
|
||||
- Changes touching config, CLI flags, schedule semantics, API behavior, auth, or report payloads must sync `.env.example` and assess Web/Desktop compatibility.
|
||||
- Changes in `data_provider/` must preserve provider priority, normalization behavior, timeout/retry expectations, and graceful degradation.
|
||||
- Prefer `./scripts/ci_gate.sh` when feasible; otherwise run `python -m py_compile` on changed files plus the closest deterministic tests.
|
||||
- Do not let a single provider, notification channel, or optional integration failure break the main analysis flow unless the requirement explicitly demands fail-fast behavior.
|
||||
10
.github/instructions/client.instructions.md
vendored
Normal file
10
.github/instructions/client.instructions.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
applyTo: "apps/dsa-web/**,apps/dsa-desktop/**,scripts/run-desktop.ps1,scripts/build-desktop*.ps1,scripts/build-*.sh,docs/desktop-package.md"
|
||||
---
|
||||
|
||||
# Client Instructions
|
||||
|
||||
- Preserve the existing Vite + React web structure and Electron desktop runtime assumptions; reuse current API/state patterns instead of adding parallel client abstractions.
|
||||
- If a change affects API fields, auth state, route behavior, Markdown/chart rendering, local backend startup, or report payloads, assess both Web and Desktop compatibility.
|
||||
- Validate Web changes with `cd apps/dsa-web && npm ci && npm run lint && npm run build` when feasible.
|
||||
- Validate Desktop changes by building Web first, then `apps/dsa-desktop`; if platform limits prevent full Electron validation, call out the exact risk in the final delivery.
|
||||
13
.github/instructions/governance.instructions.md
vendored
Normal file
13
.github/instructions/governance.instructions.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
applyTo: "README.md,docs/**,AGENTS.md,CLAUDE.md,.github/**,.claude/skills/**,scripts/**,docker/**"
|
||||
---
|
||||
|
||||
# Governance Instructions
|
||||
|
||||
- Keep commands, file paths, workflow names, config keys, release paths, and directory references aligned with the executable repository state.
|
||||
- `AGENTS.md` is the canonical AI collaboration document; if its meaning changes, sync `CLAUDE.md`, `.github/copilot-instructions.md`, `.github/instructions/*.instructions.md`, and repository skills as needed.
|
||||
- Root `SKILL.md` and `docs/openclaw-skill-integration.md` describe product or external integration behavior, not repository governance.
|
||||
- Explain which pipeline, release path, deployment path, review automation, or governance asset is affected and what the rollback path is.
|
||||
- Avoid widening permissions, secret exposure, or destructive automation without a clearly documented need.
|
||||
- Preserve the repository's opt-in auto-tag behavior (`#patch`, `#minor`, `#major`) unless the change explicitly updates release policy.
|
||||
- If only one language version of a document is updated, explain why the counterpart was not synchronized.
|
||||
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -25,9 +25,23 @@ jobs:
|
||||
frontend:
|
||||
- 'apps/dsa-web/**'
|
||||
|
||||
ai-governance:
|
||||
name: ai-governance
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 📥 Checkout
|
||||
uses: actions/checkout@v5
|
||||
- name: 🐍 Setup Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.11'
|
||||
- name: 🤖 Check AI governance assets
|
||||
run: python scripts/check_ai_assets.py
|
||||
|
||||
backend-gate:
|
||||
name: backend-gate
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ai-governance]
|
||||
steps:
|
||||
- name: 📥 Checkout
|
||||
uses: actions/checkout@v5
|
||||
@@ -72,7 +86,7 @@ jobs:
|
||||
web-gate:
|
||||
name: web-gate
|
||||
runs-on: ubuntu-latest
|
||||
needs: [changes]
|
||||
needs: [changes, ai-governance]
|
||||
if: needs.changes.outputs.frontend == 'true'
|
||||
defaults:
|
||||
run:
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -69,9 +69,10 @@ run.sh
|
||||
|
||||
verify_*.py
|
||||
|
||||
# ignore claude files
|
||||
.claude/
|
||||
CLAUDE.md
|
||||
# ignore Claude workspace artifacts, but keep shared repo skills versioned
|
||||
.claude/*
|
||||
!.claude/skills/
|
||||
!.claude/skills/**
|
||||
|
||||
# ignore static files
|
||||
static/
|
||||
|
||||
283
AGENTS.md
283
AGENTS.md
@@ -2,164 +2,241 @@
|
||||
|
||||
本文件用于约束本仓库的默认开发流程,目标是减少重复沟通、减少返工,并让改动和当前项目结构保持一致。
|
||||
|
||||
如果本文件与仓库中的脚本、工作流、代码现状不一致,以实际可执行内容为准,并在相关改动中顺手修正文档,避免规则继续漂移。
|
||||
|
||||
## 1. 硬规则
|
||||
|
||||
- 遵循现有目录边界:
|
||||
- 后端逻辑优先放在 `src/`、`data_provider/`、`api/`、`bot/`
|
||||
- 前端改动在 `apps/dsa-web/`
|
||||
- Web 前端改动在 `apps/dsa-web/`
|
||||
- 桌面端改动在 `apps/dsa-desktop/`
|
||||
- 部署与流水线改动在 `scripts/`、`.github/workflows/`、`docker/`
|
||||
- 未经明确确认,不执行 `git commit`、`git tag`、`git push`。
|
||||
- commit message 使用英文,不添加 `Co-Authored-By`。
|
||||
- 不写死密钥、账号、路径、模型名或环境差异逻辑。
|
||||
- 不写死密钥、账号、路径、模型名、端口或环境差异逻辑。
|
||||
- 优先复用现有模块、配置入口、脚本和测试,不新增平行实现。
|
||||
- 默认稳定性优先于“顺手优化”;非当前任务直接需要的重构、抽象和基础设施迁移一律克制。
|
||||
- 新增配置项时,必须同步更新 `.env.example` 和相关文档。
|
||||
- 涉及用户可见能力、CLI/API 行为、部署方式、通知方式、报告结构变化时,必须同步更新 `README.md` 和 `docs/CHANGELOG.md`。
|
||||
- 变更中英双语文档之一时,需评估另一份是否需要同步;若未同步,交付说明里要写明原因。
|
||||
- 注释、docstring、日志文案以清晰准确为准,不强制要求英文,但应与文件语境保持一致。
|
||||
|
||||
## 2. 默认开发流程
|
||||
## 2. AI 协作资产治理
|
||||
|
||||
1. 先判断任务类型:`fix / feat / refactor / docs / chore / test / review`
|
||||
2. 先读现有实现、配置、测试和文档,再动手修改
|
||||
3. 只做和当前任务直接相关的最小改动,不顺手夹带无关重构
|
||||
4. 改完后按下面的验证矩阵执行检查
|
||||
5. 最终交付默认要说明:
|
||||
- 改了什么
|
||||
- 为什么这么改
|
||||
- 跑了哪些验证
|
||||
- 哪些验证没跑以及原因
|
||||
- 风险点
|
||||
- 回滚方式
|
||||
|
||||
## 3. 验证矩阵
|
||||
|
||||
> **CI 覆盖原则**:本项目 CI 目前仅覆盖 Python 语法检查(`py_compile`)和致命 Flake8 错误(E9/F63/F7/F82)。对这两项,若 CI 已通过,PR 描述中可直接引用 CI 结果,无需重复贴本地输出。**`./scripts/ci_gate.sh` 不在 CI 覆盖范围内**;若该 gate 未执行,PR 描述须说明原因,否则缺失证据应在建议项中注明。
|
||||
|
||||
### Python 后端改动
|
||||
|
||||
适用范围:`main.py`、`src/`、`data_provider/`、`api/`、`bot/`、`tests/`
|
||||
|
||||
优先执行:
|
||||
- `AGENTS.md` 是仓库内 AI 协作规则的唯一真源。
|
||||
- `CLAUDE.md` 必须是指向 `AGENTS.md` 的软链接,用于兼容 Claude 生态。
|
||||
- `.github/copilot-instructions.md` 与 `.github/instructions/*.instructions.md` 是 GitHub Copilot / Coding Agent 的镜像或分层补充;若与本文件冲突,以 `AGENTS.md` 为准。
|
||||
- 仓库协作 skill 存放在 `.claude/skills/`,分析产物存放在 `.claude/reviews/`;前者可以入库,后者默认视为本地产物。
|
||||
- 根目录 `SKILL.md` 与 `docs/openclaw-skill-integration.md` 属于产品或外部集成说明,不是仓库协作规则真源。
|
||||
- 若未来新增 `.agents/skills/` 或其他 agent 专用目录,必须先明确单一真源,再通过脚本或镜像同步;禁止手工长期维护多份同义内容。
|
||||
- 修改 AI 协作治理资产时,执行:
|
||||
|
||||
```bash
|
||||
./scripts/ci_gate.sh
|
||||
python scripts/check_ai_assets.py
|
||||
```
|
||||
|
||||
如果环境不足以跑完整 gate,最低要求:
|
||||
## 3. 仓库速览
|
||||
|
||||
- 项目定位:股票智能分析系统,覆盖 A 股、港股、美股。
|
||||
- 主流程:抓取数据 -> 技术分析/新闻检索 -> LLM 分析 -> 生成报告 -> 通知推送。
|
||||
- 关键入口:
|
||||
- `main.py`:分析任务主入口
|
||||
- `server.py`:FastAPI 服务入口
|
||||
- `apps/dsa-web/`:Web 前端
|
||||
- `apps/dsa-desktop/`:Electron 桌面端
|
||||
- `.github/workflows/`:CI、发布、每日任务
|
||||
- 核心职责:
|
||||
- `src/core/`:主流程编排
|
||||
- `src/services/`:业务服务层
|
||||
- `src/repositories/`:数据访问层
|
||||
- `src/reports/`:报告生成
|
||||
- `src/schemas/`:Schema / 数据结构
|
||||
- `data_provider/`:多数据源适配与 fallback
|
||||
- `api/`:FastAPI API
|
||||
- `bot/`:机器人接入
|
||||
- `scripts/`:本地脚本
|
||||
- `.github/scripts/`:GitHub 自动化脚本
|
||||
- `tests/`:pytest 测试
|
||||
- `docs/`:文档与说明
|
||||
|
||||
## 4. 常用命令
|
||||
|
||||
### 运行应用
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
python main.py --debug
|
||||
python main.py --dry-run
|
||||
python main.py --stocks 600519,hk00700,AAPL
|
||||
python main.py --market-review
|
||||
python main.py --schedule
|
||||
python main.py --serve
|
||||
python main.py --serve-only
|
||||
uvicorn server:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
### 后端验证
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
pip install flake8 pytest
|
||||
./scripts/ci_gate.sh
|
||||
python -m pytest -m "not network"
|
||||
python -m py_compile <changed_python_files>
|
||||
```
|
||||
|
||||
并在交付说明中写明缺失了哪些验证。
|
||||
|
||||
### Web 前端改动
|
||||
|
||||
适用范围:`apps/dsa-web/`
|
||||
|
||||
默认执行:
|
||||
### Web / Desktop
|
||||
|
||||
```bash
|
||||
cd apps/dsa-web
|
||||
npm ci
|
||||
npm run lint
|
||||
npm run build
|
||||
|
||||
cd ../dsa-desktop
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 文档改动
|
||||
### PR / CI 证据
|
||||
|
||||
适用范围:`README.md`、`docs/**`
|
||||
```bash
|
||||
gh pr view <pr_number>
|
||||
gh pr checks <pr_number>
|
||||
gh run view <run_id> --log-failed
|
||||
```
|
||||
|
||||
- 不强制代码测试
|
||||
- 需确认文档中的命令、配置项、文件名与实际仓库一致
|
||||
- 交付时直接说明:`Docs only, tests not run`
|
||||
## 5. 默认工作流
|
||||
|
||||
### 工作流 / 脚本 / Docker 改动
|
||||
1. 先判断任务类型:`fix / feat / refactor / docs / chore / test / review`
|
||||
2. 先读现有实现、配置、测试、脚本、工作流和文档,再动手修改。
|
||||
3. 识别改动边界:后端 / API / Web / Desktop / Workflow / Docs / AI 协作资产。
|
||||
4. 先判断是否命中高风险区域:配置语义、API / Schema、数据源 fallback、报告结构、认证、调度、发布流程、桌面端启动链路。
|
||||
5. 只做和当前任务直接相关的最小改动,不顺手夹带无关重构。
|
||||
6. 如果发现文档、脚本、工作流描述不一致,优先信任实际代码与工作流,再决定是否顺手修正文档。
|
||||
7. 改完后按下面的验证矩阵执行检查。
|
||||
8. 最终交付默认要说明:
|
||||
- 改了什么
|
||||
- 为什么这么改
|
||||
- 验证情况
|
||||
- 未验证项
|
||||
- 风险点
|
||||
- 回滚方式
|
||||
|
||||
适用范围:`.github/**`、`scripts/**`、`docker/**`
|
||||
## 6. 验证矩阵
|
||||
|
||||
- 运行最接近改动面的本地验证
|
||||
- 交付时说明影响了哪条流水线或部署路径
|
||||
### CI 覆盖原则
|
||||
|
||||
### 网络或三方依赖相关改动
|
||||
当前仓库 CI 主要包含:
|
||||
|
||||
适用范围:数据源、通知、搜索、外部 LLM、网络 API
|
||||
| 检查项 | 来源 | 说明 | 是否阻断 |
|
||||
| --- | --- | --- | --- |
|
||||
| `ai-governance` | `.github/workflows/ci.yml` | 校验 `AGENTS.md` / `CLAUDE.md` / `.github` 指令 / `.claude/skills` 关系 | 是 |
|
||||
| `backend-gate` | `.github/workflows/ci.yml` | 执行 `./scripts/ci_gate.sh` | 是 |
|
||||
| `docker-build` | `.github/workflows/ci.yml` | Docker 构建与关键模块导入 smoke | 是 |
|
||||
| `web-gate` | `.github/workflows/ci.yml` | 前端改动时执行 `npm run lint` + `npm run build` | 是(触发时) |
|
||||
| `network-smoke` | `.github/workflows/network-smoke.yml` | `pytest -m network` + `test.sh quick` | 否,观测项 |
|
||||
| `pr-review` | `.github/workflows/pr-review.yml` | PR 静态检查 + AI 审查 + 自动标签 | 否,辅助项 |
|
||||
|
||||
- 先跑离线或确定性检查
|
||||
- 若未执行在线验证,必须明确写出原因
|
||||
- `pytest -m network` 属于加分项,不是默认阻断项
|
||||
若 PR 上已有对应 CI 结果,可直接引用 CI 结论;若 CI 未覆盖改动面,或本地与 CI 环境差异较大,需要补充说明本地验证与缺口。
|
||||
|
||||
## 4. 实现约束
|
||||
### 按改动面执行
|
||||
|
||||
- 优先复用现有模块、配置入口、脚本和测试,不新增平行实现。
|
||||
- 当前项目配置复杂度已经较高;新增能力时应优先减少配置负担,而不是继续叠加开关、模式和例外分支。
|
||||
- 新增配置应保持易用性:命名清晰、职责单一、默认值合理,优先做到不配置也能运行,配置后才增强能力。
|
||||
- 避免为同一能力引入多个语义重叠、互相依赖或容易冲突的配置项;能复用现有配置的,不新增。
|
||||
- 非明确需求下,不改变现有默认行为;新增能力优先采用向后兼容、默认关闭或渐进启用的方式接入。
|
||||
- 修改数据源、通知、搜索、Prompt、工作流时,必须评估兼容性、降级路径和回滚方式。
|
||||
- 修改已有配置语义、默认值或执行流程时,必须评估对本地运行、Docker、GitHub Actions、API/WebUI 的影响。
|
||||
- 不轻易破坏现有 fallback / fail-open 行为,除非需求明确要求。
|
||||
- 改 API / Schema / 前端联动时,要同时检查前后端兼容性。
|
||||
- 非必要不引入新的基础设施依赖、配置格式或大型抽象层。
|
||||
- Python 后端改动:
|
||||
- 适用范围:`main.py`、`src/`、`data_provider/`、`api/`、`bot/`、`tests/`
|
||||
- 优先执行:`./scripts/ci_gate.sh`
|
||||
- 最低要求:`python -m py_compile <changed_python_files>`
|
||||
- 若影响 API、任务编排、报告生成、通知发送、数据源 fallback、认证、调度,交付说明中要写明是否覆盖了对应路径。
|
||||
|
||||
## 5. Issue 分析
|
||||
- Web 前端改动:
|
||||
- 适用范围:`apps/dsa-web/`
|
||||
- 默认执行:`cd apps/dsa-web && npm ci && npm run lint && npm run build`
|
||||
- 若涉及 API 联调、路由、状态管理、Markdown/图表渲染或认证状态,交付说明中要明确说明联动面和未覆盖风险。
|
||||
|
||||
每个 Issue 默认先回答 4 个问题:
|
||||
- 桌面端改动:
|
||||
- 适用范围:`apps/dsa-desktop/`、`scripts/run-desktop.ps1`、`scripts/build-desktop*.ps1`、`scripts/build-*.sh`、`docs/desktop-package.md`
|
||||
- 默认执行:先构建 Web,再构建桌面端
|
||||
- 如受平台限制未能完整验证,需要明确说明是否验证了 Web 构建产物、Electron 构建以及 Release 工作流影响。
|
||||
|
||||
1. 版本是否明确
|
||||
2. 问题是否真实且可验证
|
||||
3. 是否属于仓库责任边界
|
||||
4. 是否值得立即处理
|
||||
- API / Schema / 认证联动改动:
|
||||
- 适用范围:`api/**`、`src/schemas/**`、`src/services/**`、`apps/dsa-web/**`、`apps/dsa-desktop/**`
|
||||
- 至少覆盖对应后端验证 + 受影响客户端构建验证。
|
||||
- 若涉及登录、Cookie、会话、轮询状态、字段增删或枚举变化,必须明确写出兼容性影响。
|
||||
|
||||
输出模板:
|
||||
- 文档与治理文件改动:
|
||||
- 适用范围:`README.md`、`docs/**`、`AGENTS.md`、`.github/copilot-instructions.md`、`.github/instructions/**`、`.claude/skills/**`
|
||||
- 不强制代码测试。
|
||||
- 需确认命令、配置项、文件名、工作流名称与实际仓库一致。
|
||||
- 改动 AI 协作治理资产时,执行 `python scripts/check_ai_assets.py`。
|
||||
|
||||
- `版本基线`:最新 / 非最新 / 未提供
|
||||
- `是否合理`:是/否 + 理由
|
||||
- `是否是 issue`:是/否 + 理由
|
||||
- `是否好解决`:是/否 + 难点
|
||||
- `结论`:`成立 / 部分成立 / 不成立`
|
||||
- `分类`:`bug / feature / docs / question / external`
|
||||
- `优先级`:`P0 / P1 / P2 / P3`
|
||||
- `难度`:`easy / medium / hard`
|
||||
- `建议动作`:`立即修复 / 排期修复 / 文档澄清 / 关闭`
|
||||
- 工作流 / 脚本 / Docker 改动:
|
||||
- 适用范围:`.github/**`、`scripts/**`、`docker/**`
|
||||
- 运行最接近改动面的本地验证。
|
||||
- 交付时说明影响了哪条流水线、发布路径或部署路径。
|
||||
- 若未执行 Docker / GitHub Actions 相关验证,明确说明原因与潜在风险。
|
||||
|
||||
## 6. PR 审查
|
||||
- 网络或三方依赖相关改动:
|
||||
- 先跑离线或确定性检查。
|
||||
- 优先确认 timeout、retry、fallback、异常文案、降级路径是否仍然成立。
|
||||
- 若未执行在线验证,必须明确写出原因。
|
||||
|
||||
PR 默认按以下顺序审查:
|
||||
## 7. 稳定性护栏
|
||||
|
||||
1. 必要性:是否解决明确问题,是否避免无关改动
|
||||
2. 关联性:优先使用 `Fixes #xxx` 或 `Refs #xxx`;自然语言关联(如"关联 issue 为 #xxx")也可接受,不作为阻断项
|
||||
3. 描述完整性:是否包含背景、范围、验证、风险、回滚
|
||||
4. 实现正确性:是否符合现有架构,是否存在明显回归风险
|
||||
5. 合入判定:是否具备直接合入条件
|
||||
- 配置与运行入口:
|
||||
- 修改 `.env` 语义、默认值、CLI 参数、服务启动方式、调度语义时,要同时评估本地运行、Docker、GitHub Actions、API、Web、Desktop 的影响。
|
||||
- 新配置优先做到“不配置也可运行,配置后增强能力”,避免叠加开关和互斥模式。
|
||||
|
||||
对 `fix` 类 PR,必须说明:原问题、根因、修复点、回归风险。
|
||||
- 数据源与 fallback:
|
||||
- 修改 `data_provider/` 时,要关注数据源优先级、失败降级、字段标准化、缓存与超时策略。
|
||||
- 单一数据源失败不应拖垮整个分析流程,除非需求明确要求 fail-fast。
|
||||
|
||||
### 合入阻断条件(必须满足才能合入)
|
||||
- API / Web / Desktop 兼容:
|
||||
- 改 API / Schema / 认证 / 报告载荷时,要同时检查后端、Web、Desktop 的兼容性。
|
||||
- 默认优先追加字段、保留旧字段或提供兼容层,避免无提示破坏现有客户端。
|
||||
|
||||
- 代码存在正确性或安全性问题(逻辑错误、异常吞没、安全漏洞等)
|
||||
- CI 检查未通过(语法检查、lint、构建失败等)
|
||||
- PR 描述与实际改动内容存在实质性矛盾(如声称更新了某文件但 diff 中没有)
|
||||
- 缺少回滚方案
|
||||
- 报告 / Prompt / 通知:
|
||||
- 修改报告结构、Prompt、提取器、通知模板、机器人链路时,要检查上游输入与下游消费方是否仍兼容。
|
||||
- 单一通知渠道失败不应拖垮整个分析主流程,除非需求明确要求 fail-fast。
|
||||
- 修改 `src/services/image_stock_extractor.py` 中 `EXTRACT_PROMPT` 时,要在 PR 描述中附完整最新 prompt。
|
||||
|
||||
### 建议条件(不阻断合入,但建议改进)
|
||||
- 工作流 / 发布 / 打包:
|
||||
- 修改自动 tag、Release、Docker 发布、日常分析或桌面端打包流程时,要评估触发条件、产物路径、权限边界和回滚方式。
|
||||
- 自动 tag 默认保持 opt-in:只有 commit title 含 `#patch`、`#minor`、`#major` 才触发版本号更新,除非需求明确要求改变发布策略。
|
||||
|
||||
- issue 关联格式不规范(如自然语言关联而非 `Fixes/Refs #xxx`)
|
||||
- 验证证据不完整但 CI 已通过对应检查
|
||||
- PR 描述中存在非关键性的措辞或格式问题
|
||||
- 注释语言风格不统一
|
||||
- 无关的锁文件或格式化变更(建议清理但不阻断)
|
||||
## 8. Issue / PR / Skill 工作流
|
||||
|
||||
评审输出模板:
|
||||
- 仓库内已有以下 skill,可优先复用:
|
||||
- `.claude/skills/analyze-issue/SKILL.md`
|
||||
- `.claude/skills/analyze-pr/SKILL.md`
|
||||
- `.claude/skills/fix-issue/SKILL.md`
|
||||
- 如果任务明确是 issue 分析、PR 审查、issue 修复,优先按对应 skill 执行,并将产物保存到 `.claude/reviews/`。
|
||||
- skill 中的命令、模板、验证顺序和交付结构必须与 `AGENTS.md` 保持一致。
|
||||
- skill 默认优先读取 CI / 工作流证据,再决定是否补本地验证。
|
||||
- skill 不得默认执行 `git pull`、`git push`、`git tag`、`gh pr create` 等会改变远端或当前分支状态的操作;这些操作必须要求用户确认。
|
||||
- PR 审查默认顺序:
|
||||
1. 必要性
|
||||
2. 关联性
|
||||
3. 描述完整性(对照 `.github/PULL_REQUEST_TEMPLATE.md`)
|
||||
4. 验证证据
|
||||
5. 实现正确性
|
||||
6. 合入判定
|
||||
- 对 `fix` 类 PR,必须说明:原问题、根因、修复点、回归风险。
|
||||
- 合入阻断条件:
|
||||
- 正确性或安全性问题
|
||||
- 阻断型 CI 未通过
|
||||
- PR 描述与实际改动内容实质性矛盾
|
||||
- 缺少回滚方案
|
||||
|
||||
- `必要性`:通过/不通过
|
||||
- `是否有对应 issue`:有/无(编号)
|
||||
- `PR 类型`:`fix / feat / refactor / docs / chore / test`
|
||||
- `description 完整性`:完整/不完整(缺失项)
|
||||
- `验证情况`:已验证/部分验证/未验证
|
||||
- `主要风险`:无 / 有(说明)
|
||||
- `是否可直接合入`:可/不可 + 必改项(仅限阻断条件)
|
||||
|
||||
## 7. 发布规则摘要
|
||||
## 9. 交付与发布
|
||||
|
||||
- 默认交付结构:
|
||||
- `改了什么`
|
||||
- `为什么这么改`
|
||||
- `验证情况`
|
||||
- `未验证项`
|
||||
- `风险点`
|
||||
- `回滚方式`
|
||||
- 如果是 `docs` 任务,可直接写:`Docs only, tests not run`,但仍需说明是否核对了命令和文件名。
|
||||
- 自动 tag 默认不触发,只有 commit title 包含 `#patch`、`#minor`、`#major` 才会触发版本号更新。
|
||||
- 手动打 tag 必须使用 annotated tag。
|
||||
- 用户可见变更优先通过 PR 合入,并补齐 label 与验证说明。
|
||||
|
||||
127
scripts/check_ai_assets.py
Normal file
127
scripts/check_ai_assets.py
Normal file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
AGENTS = ROOT / "AGENTS.md"
|
||||
CLAUDE = ROOT / "CLAUDE.md"
|
||||
COPILOT = ROOT / ".github" / "copilot-instructions.md"
|
||||
INSTRUCTIONS_DIR = ROOT / ".github" / "instructions"
|
||||
CLAUDE_SKILLS_DIR = ROOT / ".claude" / "skills"
|
||||
|
||||
REQUIRED_INSTRUCTION_FILES = {
|
||||
"backend.instructions.md",
|
||||
"client.instructions.md",
|
||||
"governance.instructions.md",
|
||||
}
|
||||
|
||||
REQUIRED_SKILL_FILES = {
|
||||
"README.md",
|
||||
"analyze-issue/SKILL.md",
|
||||
"analyze-pr/SKILL.md",
|
||||
"fix-issue/SKILL.md",
|
||||
}
|
||||
|
||||
REQUIRED_GITIGNORE_SNIPPETS = (
|
||||
".claude/*",
|
||||
"!.claude/skills/",
|
||||
"!.claude/skills/**",
|
||||
)
|
||||
|
||||
|
||||
def fail(message: str) -> None:
|
||||
print(f"[ai-assets] ERROR: {message}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def ensure_file_exists(path: Path, description: str) -> None:
|
||||
if not path.exists():
|
||||
fail(f"{description} is missing: {path.relative_to(ROOT)}")
|
||||
|
||||
|
||||
def ensure_symlink() -> None:
|
||||
ensure_file_exists(AGENTS, "canonical AGENTS.md")
|
||||
if not CLAUDE.exists():
|
||||
fail("CLAUDE.md is missing")
|
||||
if not CLAUDE.is_symlink():
|
||||
fail("CLAUDE.md must be a symlink to AGENTS.md")
|
||||
|
||||
target = Path(CLAUDE.readlink())
|
||||
if target != Path("AGENTS.md"):
|
||||
fail(f"CLAUDE.md must point to AGENTS.md, found: {target}")
|
||||
|
||||
|
||||
def ensure_copilot_entry() -> None:
|
||||
ensure_file_exists(COPILOT, "repository Copilot instructions")
|
||||
content = COPILOT.read_text(encoding="utf-8")
|
||||
required_fragments = (
|
||||
"Canonical source:",
|
||||
"AGENTS.md",
|
||||
"CLAUDE.md",
|
||||
".claude/skills/",
|
||||
)
|
||||
for fragment in required_fragments:
|
||||
if fragment not in content:
|
||||
fail(f".github/copilot-instructions.md is missing required text: {fragment!r}")
|
||||
|
||||
|
||||
def ensure_instruction_files() -> None:
|
||||
ensure_file_exists(INSTRUCTIONS_DIR, "instructions directory")
|
||||
actual = {path.name for path in INSTRUCTIONS_DIR.glob("*.instructions.md")}
|
||||
missing = REQUIRED_INSTRUCTION_FILES - actual
|
||||
if missing:
|
||||
fail(f"missing instruction files: {', '.join(sorted(missing))}")
|
||||
|
||||
|
||||
def ensure_skill_files() -> None:
|
||||
ensure_file_exists(CLAUDE_SKILLS_DIR, "Claude skills directory")
|
||||
for relative_path in REQUIRED_SKILL_FILES:
|
||||
path = CLAUDE_SKILLS_DIR / relative_path
|
||||
if not path.exists():
|
||||
fail(f"missing repository skill asset: {path.relative_to(ROOT)}")
|
||||
if path.is_file():
|
||||
content = path.read_text(encoding="utf-8")
|
||||
if relative_path != "README.md" and "AGENTS.md" not in content:
|
||||
fail(f"{path.relative_to(ROOT)} must reference AGENTS.md as the rule source")
|
||||
|
||||
|
||||
def ensure_gitignore_rules() -> None:
|
||||
gitignore = (ROOT / ".gitignore").read_text(encoding="utf-8")
|
||||
for snippet in REQUIRED_GITIGNORE_SNIPPETS:
|
||||
if snippet not in gitignore:
|
||||
fail(f".gitignore is missing required AI asset rule: {snippet}")
|
||||
|
||||
|
||||
def ensure_no_tracked_claude_artifacts() -> None:
|
||||
result = subprocess.run(
|
||||
["git", "ls-files", "--", ".claude"],
|
||||
cwd=ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
tracked = [line.strip() for line in result.stdout.splitlines() if line.strip()]
|
||||
allowed_prefixes = (".claude/skills/",)
|
||||
for path in tracked:
|
||||
if path.startswith(allowed_prefixes):
|
||||
continue
|
||||
fail(f"tracked .claude artifact outside skills/: {path}")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ensure_symlink()
|
||||
ensure_copilot_entry()
|
||||
ensure_instruction_files()
|
||||
ensure_skill_files()
|
||||
ensure_gitignore_rules()
|
||||
ensure_no_tracked_claude_artifacts()
|
||||
print("[ai-assets] OK")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user