feat: add uploaded skills management

This commit is contained in:
Codex
2026-05-31 11:44:50 +08:00
parent 47ab535cf2
commit 70ebd1689c
18 changed files with 1421 additions and 8 deletions
+14
View File
@@ -12,6 +12,7 @@ const requiredFiles = Object.freeze([
"index.html",
"styles.css",
"app.ts",
"app-skills.ts",
"app-device-pod.ts",
"app-conversation.ts",
"app-trace.ts",
@@ -56,6 +57,15 @@ const artifactCatalog = readRepo("deploy/artifact-catalog.dev.json");
const rightSidebar = sectionById(html, "aside", "device-pod-sidebar");
assert.ok(rightSidebar, "Device Pod right sidebar must exist");
assert.match(html, /data-route="skills"/u, "Cloud Web must expose the skills activity route");
assert.match(html, /id="skills"[^>]*data-view="skills"/u, "Cloud Web must expose a skills view");
assert.match(html, /id="skill-upload-input"[^>]*webkitdirectory/u, "Skills view must support directory upload");
assertIncludes(app, "/v1/skills", "skills frontend must call /v1/skills");
assertIncludes(app, "/v1/skills/uploads", "skills frontend must call /v1/skills/uploads");
assert.match(app, /function\s+initSkillsPanel\s*\(/u, "missing initSkillsPanel");
assert.match(app, /function\s+loadSkillsSurface\s*\(/u, "missing loadSkillsSurface");
assert.match(app, /function\s+uploadSelectedSkillFiles\s*\(/u, "missing uploadSelectedSkillFiles");
assert.match(app, /function\s+renderSkillPreview\s*\(/u, "missing renderSkillPreview");
for (const term of [
"Device Pod",
@@ -165,6 +175,10 @@ for (const oldAsset of ["code-agent-m3-evidence.mjs", "wiring-status.mjs", "work
}
assertIncludes(cloudApiServer, "/v1/device-pods", "cloud-api must expose Device Pod REST routes");
assertIncludes(cloudApiServer, "/v1/skills", "cloud-api must expose Skills REST routes");
assertIncludes(deployJson, "HWLAB_USER_SKILLS_DIR", "deploy manifest must define uploaded skills PVC env");
assertIncludes(deployJson, "/data/user-skills", "deploy manifest must keep uploaded skills outside /app/skills");
assertIncludes(readRepo("deploy/k8s/base/workloads.yaml"), "hwlab-user-skills", "base workload must include uploaded skills PVC");
assertIncludes(cloudApiPayloads, "buildDevicePodCloudApiPayload", "cloud-api payload module must keep the Device Pod compatibility payload helper");
assertIncludes(cloudApiPayloads, "device_pod_authority_unavailable", "Device Pod compatibility helper must block instead of fake fallback");
assertIncludes(devicePodData, "buildDevicePodRestPayload", "Legacy Device Pod fixtures must keep the REST payload helper for old smokes");
+2 -1
View File
@@ -9,6 +9,7 @@ export const cloudWebDistBuildCommand = "cd web/hwlab-cloud-web && bun run build
export const cloudWebDistFreshnessCommand = cloudWebDistBuildCommand;
export const cloudWebAppSourceFiles = Object.freeze([
"app.ts",
"app-skills.ts",
"app-device-pod.ts",
"app-conversation.ts",
"app-trace.ts",
@@ -24,7 +25,7 @@ export const cloudWebDistRuntimeFiles = Object.freeze([
"third_party/marked/marked.esm.js",
"third_party/marked/LICENSE"
]);
export const cloudWebDistAliasFiles = Object.freeze(["gate/index.html", "diagnostics/gate/index.html", "help/index.html"]);
export const cloudWebDistAliasFiles = Object.freeze(["gate/index.html", "diagnostics/gate/index.html", "help/index.html", "skills/index.html"]);
const staticRuntimeFiles = cloudWebDistRuntimeFiles.filter((file) => file !== "app.js");