更新了部分skill
This commit is contained in:
@@ -345,3 +345,6 @@ vercel-react-view-transitions/references/nextjs.md
|
|||||||
vercel-react-view-transitions/references/patterns.md
|
vercel-react-view-transitions/references/patterns.md
|
||||||
vercel-react-view-transitions/SKILL.md
|
vercel-react-view-transitions/SKILL.md
|
||||||
web-design-guidelines/SKILL.md
|
web-design-guidelines/SKILL.md
|
||||||
|
*.mjs
|
||||||
|
*.pckl
|
||||||
|
*.pyc
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
# Updating Existing Local Plugins
|
||||||
|
|
||||||
|
Use this reference when a plugin already exists and the request is about updating the plugin during
|
||||||
|
local development.
|
||||||
|
|
||||||
|
All scripts here are specified relative to the skill root. Update the path for running the scripts
|
||||||
|
depending on your current working directory.
|
||||||
|
|
||||||
|
## When To Use This Flow
|
||||||
|
|
||||||
|
Use this flow when all of the following are true:
|
||||||
|
|
||||||
|
- the plugin already exists locally
|
||||||
|
- the marketplace entry already points at the plugin source you are editing
|
||||||
|
- the user wants Codex to see the updated plugin without manually editing marketplace files
|
||||||
|
|
||||||
|
If the user still needs the initial plugin entry or marketplace structure created, use the scaffold
|
||||||
|
flow first and only then switch to this reinstall flow.
|
||||||
|
|
||||||
|
## Update Loop
|
||||||
|
|
||||||
|
1. Update the plugin manifest to a single Codex cachebuster suffix:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/update_plugin_cachebuster.py \
|
||||||
|
<plugin-path>
|
||||||
|
```
|
||||||
|
|
||||||
|
Prefer the default helper behavior here. If you omit `--cachebuster`, the helper uses a UTC
|
||||||
|
timestamp down to seconds, which is the recommended path for routine local iteration.
|
||||||
|
|
||||||
|
Only use a manual cachebuster override when the user explicitly asks for one or when a workflow
|
||||||
|
outside Codex depends on a specific token:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/update_plugin_cachebuster.py \
|
||||||
|
<plugin-path> \
|
||||||
|
--cachebuster local-20260519-184516
|
||||||
|
```
|
||||||
|
|
||||||
|
2. For the default scaffolded flow, read the marketplace name from the personal marketplace file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/read_marketplace_name.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, "personal marketplace" means the marketplace whose file is at
|
||||||
|
`~/.agents/plugins/marketplace.json`. On Windows, use the equivalent path under the user profile.
|
||||||
|
The helper uses Python's home-directory resolution and prints the marketplace name to use when
|
||||||
|
constructing the install command.
|
||||||
|
|
||||||
|
To read the name from a different marketplace file, pass the path directly:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/read_marketplace_name.py --marketplace-path <path-to-marketplace.json>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Reinstall from that marketplace name:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codex plugin add <plugin-name>@<marketplace-name-from-marketplace-json>
|
||||||
|
```
|
||||||
|
|
||||||
|
The default personal marketplace is discovered implicitly from
|
||||||
|
`~/.agents/plugins/marketplace.json`. You do not need `codex plugin marketplace add` for that
|
||||||
|
path, and `codex plugin marketplace list` is not the right check for whether that default
|
||||||
|
marketplace exists.
|
||||||
|
|
||||||
|
4. If the plugin is not using the personal marketplace file, check which configured local
|
||||||
|
marketplace is actually surfacing that plugin:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codex plugin list
|
||||||
|
```
|
||||||
|
|
||||||
|
If the plugin is not in the personal marketplace file, confirm which marketplace entry points at
|
||||||
|
the plugin source you are editing and make sure that marketplace is still local. If it is a
|
||||||
|
different local marketplace, reinstall from that marketplace name instead of forcing the personal
|
||||||
|
marketplace flow. If it is not local, stop and help the user resolve the mismatch before
|
||||||
|
continuing.
|
||||||
|
|
||||||
|
5. If the plugin lives in a different confirmed local marketplace, substitute that marketplace
|
||||||
|
name:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codex plugin add <plugin-name>@<local-marketplace>
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Prompt the user to use a new thread to try the updated plugin, so that Codex picks up new skills
|
||||||
|
and tools.
|
||||||
|
|
||||||
|
## Cachebuster Policy
|
||||||
|
|
||||||
|
- Preserve the existing version prefix and replace only the suffix.
|
||||||
|
- Treat the preserved prefix as everything before `+`.
|
||||||
|
- Use the format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
<base-version>+codex.<cachebuster>
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- `0.1.0` → `0.1.0+codex.local-20260519-184516`
|
||||||
|
- `0.1.0+codex.old-token` → `0.1.0+codex.local-20260519-184516`
|
||||||
|
- `1.2.3-beta.1+codex.prev` → `1.2.3-beta.1+codex.local-20260519-184516`
|
||||||
|
- `dev-build+other-tag` → `dev-build+codex.local-20260519-184516`
|
||||||
|
|
||||||
|
Replace the existing Codex cachebuster instead of appending another one. Do not keep incrementing
|
||||||
|
numeric version components just to trigger reinstall behavior.
|
||||||
|
|
||||||
|
## Marketplace Rules
|
||||||
|
|
||||||
|
- Marketplace manipulation should happen through commands, not by hand-editing `marketplace.json`
|
||||||
|
or `config.toml` during this update/reinstall flow.
|
||||||
|
- Prefer the personal marketplace file for the default scaffolded flow.
|
||||||
|
- Read the personal marketplace name with
|
||||||
|
`python3 scripts/read_marketplace_name.py` and use the printed value when constructing
|
||||||
|
`codex plugin add <plugin-name>@<marketplace-name>`.
|
||||||
|
- For non-default marketplace files, use
|
||||||
|
`python3 scripts/read_marketplace_name.py --marketplace-path <path-to-marketplace.json>` to read
|
||||||
|
the name before constructing reinstall commands.
|
||||||
|
- Do not tell the user to run `codex plugin marketplace add` for the default personal-marketplace
|
||||||
|
flow. That marketplace is discovered implicitly by Codex.
|
||||||
|
- If the user specified a different marketplace path, make sure that marketplace is installed
|
||||||
|
before giving install or reinstall instructions. Non-default marketplace paths are not
|
||||||
|
discovered implicitly.
|
||||||
|
- Use `codex plugin list` when the plugin lives in a different configured marketplace and you need
|
||||||
|
to confirm which marketplace is surfacing that plugin.
|
||||||
|
- If a non-default local marketplace has not been configured yet, install it with
|
||||||
|
`codex plugin marketplace add <path-to-marketplace-root>` before telling the user to run
|
||||||
|
`codex plugin add <plugin-name>@<marketplace-name>`.
|
||||||
|
- If the plugin is not in the personal marketplace file, confirm that the selected marketplace is
|
||||||
|
local before telling the user to reinstall from it.
|
||||||
|
- If the selected marketplace is not local, stop and help the user resolve that mismatch rather
|
||||||
|
than pretending the normal local reinstall flow applies.
|
||||||
|
- If the plugin source is not already the source referenced by the chosen marketplace entry, stop
|
||||||
|
and fix that first. This update flow does not rewrite marketplace entries.
|
||||||
|
|
||||||
|
## After Reinstall
|
||||||
|
|
||||||
|
After reinstalling, prompt the user to start a new thread for testing. That is the safe boundary for
|
||||||
|
picking up the updated plugin and its MCP tools.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Print the top-level marketplace name from any marketplace.json file."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def default_marketplace_path() -> Path:
|
||||||
|
return Path.home() / ".agents" / "plugins" / "marketplace.json"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=(
|
||||||
|
"Print the top-level marketplace name from marketplace.json. Defaults to the personal "
|
||||||
|
"marketplace path under the current home directory."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--marketplace-path",
|
||||||
|
default=str(default_marketplace_path()),
|
||||||
|
help="Path to marketplace.json",
|
||||||
|
)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
marketplace_path = Path(args.marketplace_path).expanduser().resolve()
|
||||||
|
payload = json.loads(marketplace_path.read_text(encoding="utf-8"))
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
raise ValueError(f"{marketplace_path} must contain a JSON object.")
|
||||||
|
name = payload.get("name")
|
||||||
|
if not isinstance(name, str) or not name.strip():
|
||||||
|
raise ValueError(f"{marketplace_path} must contain a non-empty string 'name'.")
|
||||||
|
print(name.strip())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except Exception as err: # noqa: BLE001 - CLI should surface a single clear message.
|
||||||
|
print(str(err), file=sys.stderr)
|
||||||
|
raise SystemExit(1) from err
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Rewrite a local plugin version to a single Codex cachebuster suffix."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
CACHEBUSTER_PREFIX = "codex"
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args() -> argparse.Namespace:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description=(
|
||||||
|
"Rewrite a local plugin's version so it preserves everything before '+' and uses "
|
||||||
|
"a single +codex.<cachebuster> suffix."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
parser.add_argument("plugin_path", help="Path to the plugin root directory")
|
||||||
|
parser.add_argument(
|
||||||
|
"--cachebuster",
|
||||||
|
help="Optional cachebuster token to embed in the plugin version",
|
||||||
|
)
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
args = parse_args()
|
||||||
|
plugin_root = Path(args.plugin_path).expanduser().resolve()
|
||||||
|
manifest_path = plugin_root / ".codex-plugin" / "plugin.json"
|
||||||
|
manifest = load_manifest(manifest_path)
|
||||||
|
|
||||||
|
version = manifest.get("version")
|
||||||
|
if not isinstance(version, str) or not version.strip():
|
||||||
|
raise ValueError(f"{manifest_path} must contain a non-empty string 'version'.")
|
||||||
|
cachebuster = sanitize_cachebuster(args.cachebuster or default_cachebuster())
|
||||||
|
next_version = with_cachebuster(version, cachebuster)
|
||||||
|
manifest["version"] = next_version
|
||||||
|
manifest_path.write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8")
|
||||||
|
|
||||||
|
print(f"Updated plugin version: {version} -> {next_version}")
|
||||||
|
|
||||||
|
|
||||||
|
def load_manifest(manifest_path: Path) -> dict[str, object]:
|
||||||
|
if not manifest_path.is_file():
|
||||||
|
raise FileNotFoundError(f"missing manifest: {manifest_path}")
|
||||||
|
payload = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
raise ValueError(f"{manifest_path} must contain a JSON object.")
|
||||||
|
return payload
|
||||||
|
def sanitize_cachebuster(value: str) -> str:
|
||||||
|
sanitized = re.sub(r"[^a-z0-9-]+", "-", value.strip().lower())
|
||||||
|
sanitized = re.sub(r"-{2,}", "-", sanitized).strip("-")
|
||||||
|
if not sanitized:
|
||||||
|
raise ValueError("Cachebuster must contain at least one letter or digit.")
|
||||||
|
return sanitized
|
||||||
|
|
||||||
|
|
||||||
|
def default_cachebuster() -> str:
|
||||||
|
return datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S")
|
||||||
|
|
||||||
|
|
||||||
|
def with_cachebuster(version: str, cachebuster: str) -> str:
|
||||||
|
version_prefix = version.split("+", 1)[0]
|
||||||
|
return f"{version_prefix}+{CACHEBUSTER_PREFIX}.{cachebuster}"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except Exception as err: # noqa: BLE001 - CLI should surface a single clear message.
|
||||||
|
print(str(err), file=sys.stderr)
|
||||||
|
raise SystemExit(1) from err
|
||||||
@@ -77,7 +77,13 @@ C:\Users\bowei\.claude\skills\langgraph-plan-review\scripts\manage_dev_server.ps
|
|||||||
```powershell
|
```powershell
|
||||||
C:\Users\bowei\.claude\skills\langgraph-plan-review\scripts\manage_dev_server.ps1 start
|
C:\Users\bowei\.claude\skills\langgraph-plan-review\scripts\manage_dev_server.ps1 start
|
||||||
```
|
```
|
||||||
Wait for the "Ready" confirmation before proceeding. Open the Studio URL in a browser for real-time tracking.
|
Wait for the "[dev-server] Ready" line in the output. Then **immediately tell the user** in your text response:
|
||||||
|
- that the dev server is running, and
|
||||||
|
- the Studio URL: `https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024`
|
||||||
|
|
||||||
|
Example message to user:
|
||||||
|
> LangGraph dev server 已就绪。可在浏览器中打开 Studio 实时监控工作流:
|
||||||
|
> https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
|
||||||
3. Start or resume the LangGraph app:
|
3. Start or resume the LangGraph app:
|
||||||
```powershell
|
```powershell
|
||||||
# Use double backslashes (\\) in the JSON string so Windows paths are valid JSON.
|
# Use double backslashes (\\) in the JSON string so Windows paths are valid JSON.
|
||||||
|
|||||||
@@ -76,14 +76,17 @@ def resolve_codex() -> str:
|
|||||||
exe = os.environ.get("CODEX_EXE", "")
|
exe = os.environ.get("CODEX_EXE", "")
|
||||||
if exe and Path(exe).exists():
|
if exe and Path(exe).exists():
|
||||||
return exe
|
return exe
|
||||||
# 2. PATH lookup
|
# 2. Known install paths (checked before PATH to avoid picking up wrong codex variant)
|
||||||
|
for candidate in [
|
||||||
|
r"C:\Users\bowei\miniconda3\envs\langgraph\codex.cmd",
|
||||||
|
r"C:\Users\bowei\.conda\envs\langgraph\codex.cmd",
|
||||||
|
]:
|
||||||
|
if Path(candidate).exists():
|
||||||
|
return candidate
|
||||||
|
# 3. PATH lookup fallback
|
||||||
found = shutil.which("codex") or shutil.which("codex.cmd")
|
found = shutil.which("codex") or shutil.which("codex.cmd")
|
||||||
if found:
|
if found:
|
||||||
return found
|
return found
|
||||||
# 3. Hardcoded fallback for the original developer machine
|
|
||||||
fallback = r"C:\Users\bowei\.conda\envs\langgraph\codex.cmd"
|
|
||||||
if Path(fallback).exists():
|
|
||||||
return fallback
|
|
||||||
raise FileNotFoundError(
|
raise FileNotFoundError(
|
||||||
"Cannot find codex executable. Set CODEX_EXE environment variable or add codex to PATH."
|
"Cannot find codex executable. Set CODEX_EXE environment variable or add codex to PATH."
|
||||||
)
|
)
|
||||||
@@ -128,6 +131,8 @@ def main() -> int:
|
|||||||
command_args,
|
command_args,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
input=prompt,
|
input=prompt,
|
||||||
cwd=work_dir,
|
cwd=work_dir,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: vivado-prj-create
|
name: vivado-prj-create
|
||||||
description: DIRECT EXECUTION - Auto-create Vivado FPGA projects. Triggers: "create Vivado project", "Vivado工程", "FPGA project", "Xilinx project", "setup Vivado". When triggered, IMMEDIATELY execute Step 0 without listing skills or asking for confirmation.
|
description: 'DIRECT EXECUTION - Auto-create Vivado FPGA projects. Triggers: "create Vivado project", "Vivado工程", "FPGA project", "Xilinx project", "setup Vivado". When triggered, IMMEDIATELY execute Step 0 without listing skills or asking for confirmation.'
|
||||||
---
|
---
|
||||||
|
|
||||||
# Vivado Project TCL Generator
|
# Vivado Project TCL Generator
|
||||||
|
|||||||
Reference in New Issue
Block a user