chore: 1.0.0 release
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import {
|
||||
assertWritableChangePath,
|
||||
extractPagePaths,
|
||||
joinDeckPath,
|
||||
normalizeRelativePath,
|
||||
titleFromManifest,
|
||||
} from "../editor/lib.js";
|
||||
|
||||
const yaml = `---
|
||||
version: v2
|
||||
title: "测试文稿"
|
||||
pages:
|
||||
- pages/01.page
|
||||
- 'pages/02.page' # comment
|
||||
theme:
|
||||
colors: {}
|
||||
`;
|
||||
|
||||
test("parses PPTD manifests and keeps file access inside the project", () => {
|
||||
assert.deepEqual(extractPagePaths(yaml), ["pages/01.page", "pages/02.page"]);
|
||||
assert.deepEqual(extractPagePaths('{"pages":["a.page","folder/b.page"]}'), ["a.page", "folder/b.page"]);
|
||||
assert.equal(titleFromManifest(yaml, "fallback"), "测试文稿");
|
||||
assert.equal(joinDeckPath("deck", "pages/01.page"), "deck/pages/01.page");
|
||||
assert.equal(joinDeckPath("deck", "deck/pages/01.page"), "deck/pages/01.page");
|
||||
assert.equal(assertWritableChangePath("deck", "pages/01.page"), "deck/pages/01.page");
|
||||
assert.throws(() => normalizeRelativePath("../secret"), /不允许越过/);
|
||||
assert.throws(() => normalizeRelativePath("/absolute/path"), /绝对路径/);
|
||||
assert.throws(() => assertWritableChangePath("deck", "media/image.png"), /仅允许编辑/);
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { once } from "node:events";
|
||||
import test from "node:test";
|
||||
import { createEditorServer } from "../lib/editor-server.js";
|
||||
|
||||
async function withServer(callback) {
|
||||
const server = createEditorServer();
|
||||
server.listen(0, "127.0.0.1");
|
||||
await once(server, "listening");
|
||||
const address = server.address();
|
||||
|
||||
try {
|
||||
await callback(`http://127.0.0.1:${address.port}`);
|
||||
} finally {
|
||||
server.close();
|
||||
await once(server, "close");
|
||||
}
|
||||
}
|
||||
|
||||
test("serves the PPTD editor and its JavaScript modules", async () => {
|
||||
await withServer(async (url) => {
|
||||
const index = await fetch(`${url}/`);
|
||||
assert.equal(index.status, 200);
|
||||
assert.match(index.headers.get("content-type"), /^text\/html/);
|
||||
assert.match(await index.text(), /打开 PPTD 文件夹/);
|
||||
|
||||
const app = await fetch(`${url}/app.js`);
|
||||
assert.equal(app.status, 200);
|
||||
assert.match(app.headers.get("content-type"), /^text\/javascript/);
|
||||
});
|
||||
});
|
||||
|
||||
test("returns 404 for files outside the packaged editor", async () => {
|
||||
await withServer(async (url) => {
|
||||
const response = await fetch(`${url}/missing.js`);
|
||||
assert.equal(response.status, 404);
|
||||
});
|
||||
});
|
||||
|
||||
test("supports HEAD requests without a response body", async () => {
|
||||
await withServer(async (url) => {
|
||||
const response = await fetch(`${url}/styles.css`, { method: "HEAD" });
|
||||
assert.equal(response.status, 200);
|
||||
assert.equal(await response.text(), "");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import test from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const cli = join(projectRoot, "bin", "open-kimi-ppt-skills.js");
|
||||
|
||||
function runCli(args, env = process.env) {
|
||||
return spawnSync(process.execPath, [cli, ...args], {
|
||||
encoding: "utf8",
|
||||
env,
|
||||
});
|
||||
}
|
||||
|
||||
test("installs the packaged skill into a custom skills directory", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
const target = join(root, "skills");
|
||||
|
||||
try {
|
||||
const result = runCli(["install", "--target", target]);
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(existsSync(join(target, "open-kimi-ppt", "SKILL.md")), true);
|
||||
assert.equal(existsSync(join(target, "open-kimi-ppt", "scripts", "export_pptx.py")), true);
|
||||
assert.equal(existsSync(join(target, "open-kimi-ppt", "_user_meta.json")), false);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("installs into ~/.agents/skills when no target is provided", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
|
||||
try {
|
||||
const result = runCli([], { ...process.env, HOME: root, USERPROFILE: root, CODEX_HOME: undefined });
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.equal(existsSync(join(root, ".agents", "skills", "open-kimi-ppt", "SKILL.md")), true);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("refuses to overwrite an existing installation without --force", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
const target = join(root, "skills");
|
||||
|
||||
try {
|
||||
assert.equal(runCli(["--target", target]).status, 0);
|
||||
const secondInstall = runCli(["--target", target]);
|
||||
assert.equal(secondInstall.status, 1);
|
||||
assert.match(secondInstall.stderr, /already exists/);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("replaces an existing installation with --force", () => {
|
||||
const root = mkdtempSync(join(tmpdir(), "open-kimi-ppt-test-"));
|
||||
const target = join(root, "skills");
|
||||
const skillFile = join(target, "open-kimi-ppt", "SKILL.md");
|
||||
|
||||
try {
|
||||
assert.equal(runCli(["--target", target]).status, 0);
|
||||
writeFileSync(skillFile, "modified", "utf8");
|
||||
|
||||
const result = runCli(["--target", target, "--force"]);
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.match(readFileSync(skillFile, "utf8"), /^---\nname: open-kimi-ppt/m);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user