用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/IppClub/Dora-SSR --skill agent-command命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Develop, fix, or review LÖVE 11.5 games hosted by Dora LoveNode, including Love TypeScript or Lua sources, Love API documentation lookup, isolated runtime boundaries, full-screen adaptation, filesystem behavior, and log-based debugging.
Dora SSR coding rules for game/workspace projects; prevents browser DOM/Canvas/Node.js code in Dora engine scripts and forces Dora API lookup before using unfamiliar engine APIs.
Use this skill when designing, creating, or polishing UI/screens/HUDs/menus so the result is visually refined, coherent, responsive, and implemented with the correct Dora UI APIs.
基于 SOC 职业分类
正在显示 SKILL.md
| name | agent-command |
| description | Rules and examples for using execute_command with Lua and Git safely inside the Dora Agent runtime. |
| always | true |
| requiredTools | ["execute_command"] |
Use execute_command only for short engine-side Lua snippets or supported Git operations. Prefer normal file tools for deterministic file edits.
mode: "lua" runs raw Lua code in the Dora engine.mode: "git" runs a supported Git command through the engine Git client.git -C.Lua command code runs in a temporary environment:
projectDir is the current project directory.reportProgress(update) forwards structured progress to the Agent tool UI.print(...) is the only output captured into the tool result.Content:copyAsync(...), Content:zipAsync(...), and Content:unzipAsync(...) may be called directly.timeoutSeconds may be set explicitly for a bounded engine test.getEntryStatus() returns the current Dora entry status.enterEntryAsync({ entryName?, fileName? }) starts a built Lua entry from the current project. fileName is project-relative, defaults to init, and may include its source or Lua extension.stopEntry() stops an entry started by this command. The tool also stops it automatically when the command succeeds, fails, is canceled, or times out.Use reportProgress(...) when the command itself coordinates meaningful stages:
local required = { "init.lua", "Script" }
for index, relativePath in ipairs(required) do
assert(Content:exist(Path(projectDir, relativePath)), "missing: " .. relativePath)
reportProgress({
progress = index / #required,
message = "checked " .. relativePath,
})
end
print("project validation completed")
Use progress in the range 0..1; stage and message are optional. Report only meaningful increments. Progress only updates the UI: it does not yield or reset timeouts, and final evidence must still be emitted with print(...).
Use an in-engine test for gameplay state, scheduling, DoraX updates, input handling, actions, physics, or other runtime behavior. A successful build alone is not runtime validation.
Follow this short path before searching APIs or probing paths:
.agent/test-results, not under Content.writablePath. The command-side absolute marker is Path(projectDir, ".agent", "test-results", name).Content.searchPaths[0]. Attach scheduled nodes to Director.entry; an unattached node is not driven by the scene scheduler.enterEntryAsync, and poll with short sleep(...) yields plus an App.runningTime deadline.stopEntry(), then verify getEntryStatus().success and getEntryStatus().running == false before asserting the result.passed as success. Raise an error for failure text, a missing marker, timeout, or a still-running entry.Canonical root-level TypeScript test entry (init.ts):
import { Content, Director, Node, Path } from "Dora";
const resultDir = Path(Content.searchPaths[0], ".agent", "test-results");
if (!Content.exist(resultDir)) Content.mkdir(resultDir);
const node = Node();
node.addTo(Director.entry);
node.schedule(() => {
Content.save(Path(resultDir, "engine-case.txt"), "passed");
return true;
});
Canonical command after building the entry:
local resultDir = Path(projectDir, ".agent", "test-results")
if not Content:exist(resultDir) then
assert(Content:mkdir(resultDir), "failed to create test result directory")
end
local marker = Path(resultDir, "engine-case.txt")
Content:remove(marker)
local success, loadError = enterEntryAsync({
fileName = "init.ts"
})
assert(success, loadError)
local deadline = App.runningTime + 10
while not Content:exist(marker) and App.runningTime < deadline do
sleep(0.05)
end
local result = Content:exist(marker) and Content:load(marker) or nil
stopEntry()
local status = getEntryStatus()
assert(status.success, "entry status failed")
assert(not status.running, "entry still running after stopEntry")
assert(result ~= nil, "runtime test timed out")
assert(result == "passed", result)
print("build entry: init.ts")
print("marker: " .. marker .. " = " .. result)
( .. (.success) .. .. (.))
()
Keep the marker until its evidence has been reported or read, then remove test artifacts. The test entry must yield back to the engine scheduler. A pure CPU loop that never yields blocks the Dora runtime and cannot be interrupted by the command timeout.
After file changes, refresh the Web IDE resource tree:
refreshTree() reloads the full asset tree.refreshTree("relative/file.ext") refreshes one project-relative file.Lua examples for common file operations that are not covered by the normal Agent file tools:
Move a file without overwriting an existing target:
local sourceRel = ".temp/source.txt"
local targetRel = ".temp/archive/source.txt"
local source = Path(projectDir, sourceRel)
local target = Path(projectDir, targetRel)
local function ensureDir(dir)
if Content:exist(dir) then
return Content:isdir(dir)
end
local parent = Path:getPath(dir)
if parent ~= dir and parent ~= "" then
assert(ensureDir(parent), "failed to create parent directory")
end
return Content:mkdir(dir)
end
assert(ensureDir(Path:getPath(target)), "failed to create target directory")
assert(Content:exist(source), "source file does not exist")
assert(not Content:exist(target), "target already exists")
assert(Content:move(source, target), "failed to move file")
refreshTree()
print("moved", sourceRel, "to", targetRel)
Copy a file or directory asynchronously:
local sourceRel = "AssetsTemplate"
local targetRel = ".temp/AssetsTemplate"
local source = Path(projectDir, sourceRel)
local target = Path(projectDir, targetRel)
local function ensureDir(dir)
if Content:exist(dir) then
return Content:isdir(dir)
end
local parent = Path:getPath(dir)
if parent ~= dir and parent ~= "" then
assert(ensureDir(parent), "failed to create parent directory")
end
return Content:mkdir(dir)
end
assert(Content:exist(source), "source does not exist")
assert(not Content:exist(target), "target already exists")
assert(ensureDir(Path:getPath(target)), "failed to create target directory")
assert(Content:copyAsync(source, target), "failed to copy")
refreshTree()
print("copied", sourceRel, "to", targetRel)
Remove a generated file or directory:
local targetRel = ".temp/generated"
local target = Path(projectDir, targetRel)
if Content:exist(target) then
assert(Content:remove(target), "failed to remove target")
refreshTree()
print("removed", targetRel)
else
print("target not found", targetRel)
end
Create a zip archive, then unzip it into a project folder:
local sourceRel = ".temp/package-src"
local zipRel = ".temp/package.zip"
local outRel = ".temp/package-unzipped"
local sourceDir = Path(projectDir, sourceRel)
local zipFile = Path(projectDir, zipRel)
local outDir = Path(projectDir, outRel)
local function ensureDir(dir)
if Content:exist(dir) then
return Content:isdir(dir)
end
local parent = Path:getPath(dir)
if parent ~= dir and parent ~= "" then
assert(ensureDir(parent), "failed to create parent directory")
end
return Content:mkdir(dir)
end
if Content:exist(sourceDir) then
assert(Content:remove(sourceDir), "failed to remove existing source directory")
end
assert(ensureDir(sourceDir), "failed to create source directory")
assert(Content:save(Path(sourceDir, "a.txt"), "alpha"), "failed to create source file")
if Content:exist(zipFile) then
assert(Content:remove(zipFile), "failed to remove existing zip file")
end
assert(Content:zipAsync(sourceDir, zipFile), )
(Content:exist(zipFile), )
(ensureDir(Path:getPath(outDir)), )
Content:exist(outDir)
(Content:(outDir), )
(Content:unzipAsync(zipFile, outDir,
filename:()
filename ~=
filename:()
), )
refreshTree()
(, zipRel, , outRel)
Git mode uses the Dora engine Git client, not a shell. Use it for repository operations such as clone, status, diff, add, commit, fetch, pull, and push when those operations are appropriate for the task.
Rules:
cwd as a project-relative directory.git -C; use the tool's cwd parameter instead.git clone target paths are project-relative and are not affected by cwd.Git examples:
git status
git diff -- init.ts
git clone https://example.com/owner/repo.git .temp/repo
Run status inside that cloned sub-repository with:
{"mode":"git","cwd":".temp/repo","command":"git status"}
git add init.ts
git commit -m "Update init script"