vskill 1.0.16 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -3
- package/agents.json +3 -1
- package/dist/agents/agents-registry.d.ts +61 -0
- package/dist/agents/agents-registry.js +203 -0
- package/dist/agents/agents-registry.js.map +1 -1
- package/dist/api/client.d.ts +85 -0
- package/dist/api/client.js +193 -24
- package/dist/api/client.js.map +1 -1
- package/dist/bin.js +0 -0
- package/dist/commands/add.d.ts +7 -0
- package/dist/commands/add.js +94 -1
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/auth.d.ts +23 -0
- package/dist/commands/auth.js +136 -12
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/eval/serve.d.ts +2 -0
- package/dist/commands/eval/serve.js +126 -4
- package/dist/commands/eval/serve.js.map +1 -1
- package/dist/commands/orgs.d.ts +21 -0
- package/dist/commands/orgs.js +164 -0
- package/dist/commands/orgs.js.map +1 -0
- package/dist/commands/skill.js +14 -1
- package/dist/commands/skill.js.map +1 -1
- package/dist/commands/whoami.d.ts +29 -0
- package/dist/commands/whoami.js +119 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/eval/anthropic-catalog.js +32 -2
- package/dist/eval/anthropic-catalog.js.map +1 -1
- package/dist/eval/batch-judge.js +1 -0
- package/dist/eval/batch-judge.js.map +1 -1
- package/dist/eval/llm.d.ts +1 -1
- package/dist/eval/llm.js +104 -2
- package/dist/eval/llm.js.map +1 -1
- package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.d.ts +2 -0
- package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.js +20 -0
- package/dist/eval-server/__tests__/helpers/studio-token-test-helpers.js.map +1 -0
- package/dist/eval-server/active-root-store.d.ts +19 -0
- package/dist/eval-server/active-root-store.js +50 -0
- package/dist/eval-server/active-root-store.js.map +1 -0
- package/dist/eval-server/active-tenant-routes.d.ts +15 -0
- package/dist/eval-server/active-tenant-routes.js +101 -0
- package/dist/eval-server/active-tenant-routes.js.map +1 -0
- package/dist/eval-server/api-routes.d.ts +1 -1
- package/dist/eval-server/api-routes.js +60 -7
- package/dist/eval-server/api-routes.js.map +1 -1
- package/dist/eval-server/authoring-routes.d.ts +1 -1
- package/dist/eval-server/authoring-routes.js +9 -7
- package/dist/eval-server/authoring-routes.js.map +1 -1
- package/dist/eval-server/desktop-open-routes.d.ts +8 -0
- package/dist/eval-server/desktop-open-routes.js +64 -0
- package/dist/eval-server/desktop-open-routes.js.map +1 -0
- package/dist/eval-server/detect-engines-route.d.ts +1 -1
- package/dist/eval-server/detect-engines-route.js +3 -1
- package/dist/eval-server/detect-engines-route.js.map +1 -1
- package/dist/eval-server/eval-server.js +108 -29
- package/dist/eval-server/eval-server.js.map +1 -1
- package/dist/eval-server/export-skill-routes.d.ts +9 -0
- package/dist/eval-server/export-skill-routes.js +81 -0
- package/dist/eval-server/export-skill-routes.js.map +1 -0
- package/dist/eval-server/git-routes.d.ts +7 -6
- package/dist/eval-server/git-routes.js +123 -15
- package/dist/eval-server/git-routes.js.map +1 -1
- package/dist/eval-server/improve-routes.d.ts +1 -1
- package/dist/eval-server/improve-routes.js +4 -1
- package/dist/eval-server/improve-routes.js.map +1 -1
- package/dist/eval-server/install-engine-routes.d.ts +4 -17
- package/dist/eval-server/install-engine-routes.js +10 -125
- package/dist/eval-server/install-engine-routes.js.map +1 -1
- package/dist/eval-server/install-jobs.d.ts +41 -0
- package/dist/eval-server/install-jobs.js +161 -0
- package/dist/eval-server/install-jobs.js.map +1 -0
- package/dist/eval-server/install-skill-routes.d.ts +74 -11
- package/dist/eval-server/install-skill-routes.js +508 -79
- package/dist/eval-server/install-skill-routes.js.map +1 -1
- package/dist/eval-server/install-state-routes.d.ts +5 -1
- package/dist/eval-server/install-state-routes.js +18 -2
- package/dist/eval-server/install-state-routes.js.map +1 -1
- package/dist/eval-server/integration-routes.d.ts +1 -1
- package/dist/eval-server/integration-routes.js +6 -1
- package/dist/eval-server/integration-routes.js.map +1 -1
- package/dist/eval-server/model-compare-routes.d.ts +1 -1
- package/dist/eval-server/model-compare-routes.js +3 -1
- package/dist/eval-server/model-compare-routes.js.map +1 -1
- package/dist/eval-server/oauth-github-routes.d.ts +2 -0
- package/dist/eval-server/oauth-github-routes.js +505 -0
- package/dist/eval-server/oauth-github-routes.js.map +1 -0
- package/dist/eval-server/platform-proxy.d.ts +22 -1
- package/dist/eval-server/platform-proxy.js +183 -22
- package/dist/eval-server/platform-proxy.js.map +1 -1
- package/dist/eval-server/plugin-cli-routes.d.ts +1 -1
- package/dist/eval-server/plugin-cli-routes.js +19 -10
- package/dist/eval-server/plugin-cli-routes.js.map +1 -1
- package/dist/eval-server/remove-skill-routes.d.ts +18 -0
- package/dist/eval-server/remove-skill-routes.js +147 -0
- package/dist/eval-server/remove-skill-routes.js.map +1 -0
- package/dist/eval-server/router.d.ts +17 -3
- package/dist/eval-server/router.js +166 -9
- package/dist/eval-server/router.js.map +1 -1
- package/dist/eval-server/settings-store.js +1 -1
- package/dist/eval-server/settings-store.js.map +1 -1
- package/dist/eval-server/skill-create-routes.d.ts +1 -1
- package/dist/eval-server/skill-create-routes.js +8 -1
- package/dist/eval-server/skill-create-routes.js.map +1 -1
- package/dist/eval-server/supported-agents-routes.d.ts +6 -0
- package/dist/eval-server/supported-agents-routes.js +41 -0
- package/dist/eval-server/supported-agents-routes.js.map +1 -0
- package/dist/eval-server/sweep-routes.d.ts +1 -1
- package/dist/eval-server/sweep-routes.js +5 -1
- package/dist/eval-server/sweep-routes.js.map +1 -1
- package/dist/eval-server/utils/spawn-env.d.ts +1 -0
- package/dist/eval-server/utils/spawn-env.js +47 -0
- package/dist/eval-server/utils/spawn-env.js.map +1 -0
- package/dist/eval-server/workspace-routes.d.ts +12 -0
- package/dist/eval-server/workspace-routes.js +57 -2
- package/dist/eval-server/workspace-routes.js.map +1 -1
- package/dist/eval-ui/assets/AdvancedTab-DOgbx7u0.js +1 -0
- package/dist/eval-ui/assets/{CreateSkillPage-CvdYq8Rr.js → CreateSkillPage-Cv93Croj.js} +3 -3
- package/dist/eval-ui/assets/FindSkillsPalette-BY9DAhHh.js +2 -0
- package/dist/eval-ui/assets/GeneralTab-AwK9sIkP.js +1 -0
- package/dist/eval-ui/assets/PrivacyTab-BtNrxpVV.js +1 -0
- package/dist/eval-ui/assets/{SearchPaletteCore-Bf3PBC64.js → SearchPaletteCore-DMVcq7UB.js} +2 -2
- package/dist/eval-ui/assets/SkillDetailPanel-B_lbhK6q.js +1 -0
- package/dist/eval-ui/assets/UpdateDropdown-4AbjZLpq.js +1 -0
- package/dist/eval-ui/assets/UpdatesTab-DTmo-vVb.js +1 -0
- package/dist/eval-ui/assets/core-DZjBCfjp.js +1 -0
- package/dist/eval-ui/assets/event-QtOCMXAv.js +1 -0
- package/dist/eval-ui/assets/globals-Dpf9KmYH.css +1 -0
- package/dist/eval-ui/assets/globals-hm1COkXX.js +49 -0
- package/dist/eval-ui/assets/index-CUEYzTVL.js +1 -0
- package/dist/eval-ui/assets/index-DDNzcrhv.js +1 -0
- package/dist/eval-ui/assets/index-DhhmQddr.js +1 -0
- package/dist/eval-ui/assets/lifecycle-d1Sm9Hts.css +1 -0
- package/dist/eval-ui/assets/lifecycle-o_IRibOa.js +1 -0
- package/dist/eval-ui/assets/main-tpOyw9SC.js +87 -0
- package/dist/eval-ui/assets/preferences-BHZXB5dL.css +1 -0
- package/dist/eval-ui/assets/preferences-DCdw0Kvu.js +2 -0
- package/dist/eval-ui/assets/useDesktopBridge-9oZFQsrw.js +2 -0
- package/dist/eval-ui/index.html +4 -2
- package/dist/eval-ui/lifecycle.html +33 -0
- package/dist/eval-ui/preferences.html +34 -0
- package/dist/index.js +47 -1
- package/dist/index.js.map +1 -1
- package/dist/installer/bundle-files.d.ts +4 -0
- package/dist/installer/bundle-files.js +97 -0
- package/dist/installer/bundle-files.js.map +1 -0
- package/dist/installer/canonical.d.ts +31 -6
- package/dist/installer/canonical.js +48 -12
- package/dist/installer/canonical.js.map +1 -1
- package/dist/installer/clipboard-export.d.ts +19 -0
- package/dist/installer/clipboard-export.js +88 -0
- package/dist/installer/clipboard-export.js.map +1 -0
- package/dist/installer/multi-install.d.ts +43 -0
- package/dist/installer/multi-install.js +237 -0
- package/dist/installer/multi-install.js.map +1 -0
- package/dist/installer/transformers/aider.d.ts +2 -0
- package/dist/installer/transformers/aider.js +32 -0
- package/dist/installer/transformers/aider.js.map +1 -0
- package/dist/installer/transformers/continue-dev.d.ts +2 -0
- package/dist/installer/transformers/continue-dev.js +6 -0
- package/dist/installer/transformers/continue-dev.js.map +1 -0
- package/dist/installer/transformers/cursor.d.ts +2 -0
- package/dist/installer/transformers/cursor.js +24 -0
- package/dist/installer/transformers/cursor.js.map +1 -0
- package/dist/installer/transformers/github-copilot.d.ts +2 -0
- package/dist/installer/transformers/github-copilot.js +17 -0
- package/dist/installer/transformers/github-copilot.js.map +1 -0
- package/dist/installer/transformers/index.d.ts +78 -0
- package/dist/installer/transformers/index.js +13 -0
- package/dist/installer/transformers/index.js.map +1 -0
- package/dist/installer/transformers/junie.d.ts +2 -0
- package/dist/installer/transformers/junie.js +6 -0
- package/dist/installer/transformers/junie.js.map +1 -0
- package/dist/installer/transformers/kiro.d.ts +2 -0
- package/dist/installer/transformers/kiro.js +6 -0
- package/dist/installer/transformers/kiro.js.map +1 -0
- package/dist/installer/transformers/trae.d.ts +2 -0
- package/dist/installer/transformers/trae.js +6 -0
- package/dist/installer/transformers/trae.js.map +1 -0
- package/dist/installer/transformers/windsurf.d.ts +2 -0
- package/dist/installer/transformers/windsurf.js +12 -0
- package/dist/installer/transformers/windsurf.js.map +1 -0
- package/dist/installer/yaml-safe-mutate.d.ts +19 -0
- package/dist/installer/yaml-safe-mutate.js +184 -0
- package/dist/installer/yaml-safe-mutate.js.map +1 -0
- package/dist/lib/active-tenant.d.ts +36 -0
- package/dist/lib/active-tenant.js +120 -0
- package/dist/lib/active-tenant.js.map +1 -0
- package/dist/lib/keychain.d.ts +15 -2
- package/dist/lib/keychain.js +173 -8
- package/dist/lib/keychain.js.map +1 -1
- package/dist/lib/migration/keychain-migration.d.ts +35 -0
- package/dist/lib/migration/keychain-migration.js +189 -0
- package/dist/lib/migration/keychain-migration.js.map +1 -0
- package/dist/lib/tenant-resolver.d.ts +38 -0
- package/dist/lib/tenant-resolver.js +79 -0
- package/dist/lib/tenant-resolver.js.map +1 -0
- package/dist/studio/lib/ops-log.js +140 -57
- package/dist/studio/lib/ops-log.js.map +1 -1
- package/dist/studio/lib/scope-transfer.d.ts +11 -1
- package/dist/studio/lib/scope-transfer.js +48 -24
- package/dist/studio/lib/scope-transfer.js.map +1 -1
- package/dist/studio/routes/index.d.ts +1 -1
- package/dist/studio/routes/index.js +18 -8
- package/dist/studio/routes/index.js.map +1 -1
- package/dist/studio/routes/ops.js +31 -7
- package/dist/studio/routes/ops.js.map +1 -1
- package/dist/studio/routes/promote.d.ts +1 -1
- package/dist/studio/routes/promote.js +18 -9
- package/dist/studio/routes/promote.js.map +1 -1
- package/dist/studio/routes/revert.d.ts +1 -1
- package/dist/studio/routes/revert.js +15 -2
- package/dist/studio/routes/revert.js.map +1 -1
- package/dist/studio/routes/test-install.d.ts +1 -1
- package/dist/studio/routes/test-install.js +16 -9
- package/dist/studio/routes/test-install.js.map +1 -1
- package/dist/studio-runtime/lockfile.d.ts +51 -0
- package/dist/studio-runtime/lockfile.js +216 -0
- package/dist/studio-runtime/lockfile.js.map +1 -0
- package/package.json +18 -1
- package/dist/eval-ui/assets/FindSkillsPalette-DsSgotS9.js +0 -2
- package/dist/eval-ui/assets/SkillDetailPanel-DAD2yJO-.js +0 -1
- package/dist/eval-ui/assets/UpdateDropdown-h5Hg3h7Z.js +0 -1
- package/dist/eval-ui/assets/index-CKLqBL52.css +0 -1
- package/dist/eval-ui/assets/index-JaDg6FlU.js +0 -124
- package/dist/eval-ui/assets/skill-studio-logo-CRyKgIrg.png +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// 0850 — POST /api/studio/remove-skill
|
|
2
|
+
//
|
|
3
|
+
// Per-agent skill removal for the InstallTargetsModal. Mirrors the security
|
|
4
|
+
// posture of install-skill-routes.ts: localhost-only, SAFE_NAME validation
|
|
5
|
+
// on the skill identifier, SAFE_AGENT_ID validation on every agentId.
|
|
6
|
+
//
|
|
7
|
+
// Endpoint:
|
|
8
|
+
// POST /api/studio/remove-skill
|
|
9
|
+
// Body: { skill: string, agentIds: string[], scope: "project" | "user" }
|
|
10
|
+
// → 200 { removed: [{agentId, path}], skipped: [{agentId, reason}], errors: [{agentId, message}] }
|
|
11
|
+
import { existsSync, rmSync } from "node:fs";
|
|
12
|
+
import { join, basename } from "node:path";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
import { sendJson, readBody } from "./router.js";
|
|
15
|
+
import { isLocalhost } from "./install-jobs.js";
|
|
16
|
+
import { getAgent } from "../agents/agents-registry.js";
|
|
17
|
+
import { resolveAgentSkillsDir } from "../installer/canonical.js";
|
|
18
|
+
import { readLockfile, removeSkillFromLock, writeLockfile, } from "../lockfile/lockfile.js";
|
|
19
|
+
const SAFE_NAME = /^[a-zA-Z0-9._@/\-]+$/;
|
|
20
|
+
const SAFE_AGENT_ID = /^[a-z0-9][a-z0-9-]*$/;
|
|
21
|
+
const VALID_SCOPES = new Set(["project", "user"]);
|
|
22
|
+
function lastSegment(name) {
|
|
23
|
+
const idx = name.lastIndexOf("/");
|
|
24
|
+
return idx === -1 ? name : name.slice(idx + 1);
|
|
25
|
+
}
|
|
26
|
+
function userLockDir() {
|
|
27
|
+
return join(homedir(), ".agents");
|
|
28
|
+
}
|
|
29
|
+
function validateAgentIds(ids) {
|
|
30
|
+
if (!Array.isArray(ids))
|
|
31
|
+
return { ok: false, error: "agentIds must be an array" };
|
|
32
|
+
if (ids.length === 0)
|
|
33
|
+
return { ok: false, error: "agentIds[] cannot be empty" };
|
|
34
|
+
const out = [];
|
|
35
|
+
for (const raw of ids) {
|
|
36
|
+
if (typeof raw !== "string")
|
|
37
|
+
return { ok: false, error: "agentIds[] entries must be strings" };
|
|
38
|
+
const id = raw.trim();
|
|
39
|
+
if (!SAFE_AGENT_ID.test(id))
|
|
40
|
+
return { ok: false, error: `invalid agentId: ${raw}` };
|
|
41
|
+
if (!getAgent(id))
|
|
42
|
+
return { ok: false, error: `unknown agentId: ${id}` };
|
|
43
|
+
out.push(id);
|
|
44
|
+
}
|
|
45
|
+
return { ok: true, ids: out };
|
|
46
|
+
}
|
|
47
|
+
export function registerRemoveSkillRoutes(router, rootArg = () => process.cwd()) {
|
|
48
|
+
const getRoot = typeof rootArg === "function" ? rootArg : () => rootArg;
|
|
49
|
+
router.post("/api/studio/remove-skill", async (req, res) => {
|
|
50
|
+
const root = getRoot();
|
|
51
|
+
if (!isLocalhost(req)) {
|
|
52
|
+
sendJson(res, { error: "localhost-only endpoint" }, 403, req);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const body = (await readBody(req));
|
|
56
|
+
const skill = typeof body?.skill === "string" ? body.skill.trim() : "";
|
|
57
|
+
const scope = typeof body?.scope === "string" ? body.scope : "";
|
|
58
|
+
if (!skill || skill.startsWith("-") || !SAFE_NAME.test(skill)) {
|
|
59
|
+
sendJson(res, { error: "invalid skill identifier" }, 400, req);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!VALID_SCOPES.has(scope)) {
|
|
63
|
+
sendJson(res, { error: "invalid scope (must be project|user)" }, 400, req);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const v = validateAgentIds(body.agentIds);
|
|
67
|
+
if (!v.ok) {
|
|
68
|
+
sendJson(res, { error: v.error }, 400, req);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const shortName = lastSegment(skill);
|
|
72
|
+
const removed = [];
|
|
73
|
+
const skipped = [];
|
|
74
|
+
const errors = [];
|
|
75
|
+
for (const agentId of v.ids) {
|
|
76
|
+
const agent = getAgent(agentId);
|
|
77
|
+
if (!agent) {
|
|
78
|
+
skipped.push({ agentId, reason: "unknown agent" });
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (agent.installMode !== "filesystem") {
|
|
82
|
+
skipped.push({ agentId, reason: "cloud agent — nothing to remove on disk" });
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const dir = resolveAgentSkillsDir(agent, { global: scope === "user", projectRoot: root });
|
|
87
|
+
// Defense in depth: only remove a basename directory under the
|
|
88
|
+
// resolved agent dir. agent.id and shortName are both validated.
|
|
89
|
+
const target = join(dir, basename(shortName));
|
|
90
|
+
if (!existsSync(target)) {
|
|
91
|
+
skipped.push({ agentId, reason: `not installed at ${target}` });
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
rmSync(target, { recursive: true, force: true });
|
|
95
|
+
removed.push({ agentId, path: target });
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
errors.push({ agentId, message: err instanceof Error ? err.message : String(err) });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Lockfile cleanup. The 0850 contract: drop the skills[<name>] entry
|
|
102
|
+
// for this scope when at least one agent was removed OR when every
|
|
103
|
+
// agent we tried was "not installed on disk" (idempotent recovery
|
|
104
|
+
// from a stale lockfile that survives a manual `rm`). We do NOT
|
|
105
|
+
// prune the `agents` list — it tracks any agent ever installed against
|
|
106
|
+
// in this dir and other skills may still depend on it.
|
|
107
|
+
const isPurelyMissing = removed.length === 0 &&
|
|
108
|
+
errors.length === 0 &&
|
|
109
|
+
skipped.length > 0 &&
|
|
110
|
+
skipped.every((s) => s.reason.startsWith("not installed"));
|
|
111
|
+
if (removed.length > 0 || isPurelyMissing) {
|
|
112
|
+
const lockDir = scope === "user" ? userLockDir() : root;
|
|
113
|
+
// Match the install side: lockfile stores by skill.name which is
|
|
114
|
+
// typically the last segment.
|
|
115
|
+
const lock = readLockfile(lockDir);
|
|
116
|
+
if (lock?.skills?.[shortName]) {
|
|
117
|
+
removeSkillFromLock(shortName, lockDir);
|
|
118
|
+
}
|
|
119
|
+
else if (lock?.skills) {
|
|
120
|
+
// Fall back: scan for a key that matches either full identifier
|
|
121
|
+
// or the short name (defensive against earlier writers).
|
|
122
|
+
const matchKey = Object.keys(lock.skills).find((k) => k === shortName || k === skill || k.endsWith(`/${shortName}`));
|
|
123
|
+
if (matchKey) {
|
|
124
|
+
delete lock.skills[matchKey];
|
|
125
|
+
writeLockfile(lock, lockDir);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
console.log("[remove-skill]", JSON.stringify({ skill, scope, removed: removed.length, skipped: skipped.length, errors: errors.length }));
|
|
130
|
+
const response = {
|
|
131
|
+
skill,
|
|
132
|
+
scope: scope,
|
|
133
|
+
removed,
|
|
134
|
+
skipped,
|
|
135
|
+
errors,
|
|
136
|
+
};
|
|
137
|
+
sendJson(res, response, 200, req);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
export const __test__ = {
|
|
141
|
+
SAFE_NAME,
|
|
142
|
+
SAFE_AGENT_ID,
|
|
143
|
+
VALID_SCOPES,
|
|
144
|
+
validateAgentIds,
|
|
145
|
+
lastSegment,
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=remove-skill-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-skill-routes.js","sourceRoot":"","sources":["../../src/eval-server/remove-skill-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,21 @@ export declare class Router {
|
|
|
10
10
|
private addRoute;
|
|
11
11
|
handle(req: http.IncomingMessage, res: http.ServerResponse): Promise<boolean>;
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Lazily generate (or return) the per-process studio token. 32 bytes of
|
|
15
|
+
* `crypto.randomBytes` encoded as base64url — 256 bits of entropy, 43 chars,
|
|
16
|
+
* URL-safe and header-safe. Never persisted; rotated on every restart.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getStudioToken(): string;
|
|
19
|
+
/** Test-only — never call from production code. */
|
|
20
|
+
export declare function _resetStudioTokenForTests(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Constant-time token comparison. `crypto.timingSafeEqual` requires equal-
|
|
23
|
+
* length buffers; we length-check first (the token length is a public
|
|
24
|
+
* constant, so the early return leaks no secret). String === would be V8
|
|
25
|
+
* short-circuit and timing-leaky.
|
|
26
|
+
*/
|
|
27
|
+
export declare function tokensEqual(supplied: string | undefined | null, expected: string): boolean;
|
|
28
|
+
export declare function tokenGate(req: http.IncomingMessage, res: http.ServerResponse): boolean;
|
|
29
|
+
export declare function sendJson(res: http.ServerResponse, data: unknown, status?: number, _req?: http.IncomingMessage): void;
|
|
16
30
|
export declare function readBody(req: http.IncomingMessage): Promise<unknown>;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// router.ts -- minimal HTTP router adapted from specweave dashboard pattern
|
|
3
|
+
//
|
|
4
|
+
// 0836 US-002: every /api/* request requires `X-Studio-Token`. The token is
|
|
5
|
+
// generated lazily per process and exposed to the Tauri WebView via the
|
|
6
|
+
// `get_studio_token` IPC. The previous LOCALHOST_ORIGIN_RE allowlist was
|
|
7
|
+
// permissive (any localhost browser tab + DNS rebinding). Replaced with a
|
|
8
|
+
// per-launch shared-secret gate using `crypto.timingSafeEqual` (constant
|
|
9
|
+
// time over equal-length buffers, length-mismatch fast-rejected).
|
|
3
10
|
// ---------------------------------------------------------------------------
|
|
11
|
+
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
12
|
export class Router {
|
|
5
13
|
routes = [];
|
|
6
14
|
options;
|
|
@@ -33,6 +41,14 @@ export class Router {
|
|
|
33
41
|
const method = req.method || "GET";
|
|
34
42
|
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
|
|
35
43
|
const pathname = url.pathname;
|
|
44
|
+
// 0836 US-002: gate every /api/* request behind the X-Studio-Token. The
|
|
45
|
+
// gate writes 401 + empty body on failure; we return `true` so the
|
|
46
|
+
// server.ts dispatcher treats the response as owned and stops looking
|
|
47
|
+
// for static-file fallbacks (which would otherwise serve index.html
|
|
48
|
+
// for unmatched paths and confuse callers).
|
|
49
|
+
if (!tokenGate(req, res)) {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
36
52
|
for (const route of this.routes) {
|
|
37
53
|
if (route.method !== method)
|
|
38
54
|
continue;
|
|
@@ -59,20 +75,161 @@ export class Router {
|
|
|
59
75
|
return false;
|
|
60
76
|
}
|
|
61
77
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// 0836 US-002 — X-Studio-Token (per-launch shared secret).
|
|
80
|
+
//
|
|
81
|
+
// The previous `LOCALHOST_ORIGIN_RE` allowlist was permissive (any tab on
|
|
82
|
+
// `http://localhost:*` could reach the bearer-injecting proxy, and DNS
|
|
83
|
+
// rebinding subverted it). It is REMOVED. Each /api/* request must now
|
|
84
|
+
// carry `X-Studio-Token: <token>`; the token lives only in the eval-server
|
|
85
|
+
// process memory and is delivered to the Tauri WebView via IPC and to the
|
|
86
|
+
// CLI via stdout banner.
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
let _studioToken = null;
|
|
89
|
+
/**
|
|
90
|
+
* Lazily generate (or return) the per-process studio token. 32 bytes of
|
|
91
|
+
* `crypto.randomBytes` encoded as base64url — 256 bits of entropy, 43 chars,
|
|
92
|
+
* URL-safe and header-safe. Never persisted; rotated on every restart.
|
|
93
|
+
*/
|
|
94
|
+
export function getStudioToken() {
|
|
95
|
+
if (_studioToken == null) {
|
|
96
|
+
_studioToken = randomBytes(32).toString("base64url");
|
|
97
|
+
}
|
|
98
|
+
return _studioToken;
|
|
99
|
+
}
|
|
100
|
+
/** Test-only — never call from production code. */
|
|
101
|
+
export function _resetStudioTokenForTests() {
|
|
102
|
+
_studioToken = null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Constant-time token comparison. `crypto.timingSafeEqual` requires equal-
|
|
106
|
+
* length buffers; we length-check first (the token length is a public
|
|
107
|
+
* constant, so the early return leaks no secret). String === would be V8
|
|
108
|
+
* short-circuit and timing-leaky.
|
|
109
|
+
*/
|
|
110
|
+
export function tokensEqual(supplied, expected) {
|
|
111
|
+
if (typeof supplied !== "string")
|
|
112
|
+
return false;
|
|
113
|
+
if (supplied.length !== expected.length)
|
|
114
|
+
return false;
|
|
115
|
+
const a = Buffer.from(supplied);
|
|
116
|
+
const b = Buffer.from(expected);
|
|
117
|
+
return timingSafeEqual(a, b);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Returns true when the request is allowed to proceed. Returns false AND
|
|
121
|
+
* writes a 401 (empty body) when the gate rejects.
|
|
122
|
+
*
|
|
123
|
+
* Bypasses:
|
|
124
|
+
* - any non-/api/* path (static files, root, eval-ui shell)
|
|
125
|
+
* - OPTIONS preflight (CORS handshake; no token possible from XHR)
|
|
126
|
+
*/
|
|
127
|
+
// 0855: GET EventSource stream paths that the browser opens via `new
|
|
128
|
+
// EventSource(url)`. The EventSource API CANNOT set request headers, so these
|
|
129
|
+
// streams authenticate via a `?studioToken=<t>` query param instead of the
|
|
130
|
+
// `X-Studio-Token` header — validated with the same timing-safe compare. The
|
|
131
|
+
// exemption is GET-only and limited to this allowlist so it cannot widen the
|
|
132
|
+
// 0836 gate for any other path or method.
|
|
133
|
+
// - /api/v1/skills/stream — notification stream (proxied to the platform
|
|
134
|
+
// UpdateHub). This is the one that 0836 silently broke (no live toasts).
|
|
135
|
+
// - /api/events / /api/studio/ops/stream — local eval-server SSE streams
|
|
136
|
+
// opened by EventSource; same header-less limitation applies.
|
|
137
|
+
const EVENTSOURCE_STREAM_PATHS = new Set([
|
|
138
|
+
"/api/v1/skills/stream",
|
|
139
|
+
"/api/events",
|
|
140
|
+
"/api/studio/ops/stream",
|
|
141
|
+
]);
|
|
142
|
+
export function tokenGate(req, res) {
|
|
143
|
+
const rawUrl = req.url || "/";
|
|
144
|
+
// 0836 followup (Codex H#4): normalize req.url through URL parsing so that
|
|
145
|
+
// an absolute-form request target (e.g. `GET http://127.0.0.1:3077/api/git/status`)
|
|
146
|
+
// gates by its parsed pathname, not by the raw string. Without this,
|
|
147
|
+
// `rawUrl.startsWith("/api/")` returns false for absolute-form URLs and
|
|
148
|
+
// the router's pathname-based dispatch happily executes the route.
|
|
149
|
+
let parsedUrl;
|
|
150
|
+
try {
|
|
151
|
+
parsedUrl = new URL(rawUrl, "http://127.0.0.1");
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Truly malformed URL — let the underlying handlers reject it.
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
const pathname = parsedUrl.pathname;
|
|
158
|
+
const method = (req.method || "GET").toUpperCase();
|
|
159
|
+
// Non-/api paths are static / SPA shell — never gated.
|
|
160
|
+
if (!pathname.startsWith("/api/"))
|
|
161
|
+
return true;
|
|
162
|
+
// CORS preflight cannot send custom headers; let it pass.
|
|
163
|
+
if (method === "OPTIONS")
|
|
164
|
+
return true;
|
|
165
|
+
// 0836 followup (Codex C#1): /api/health is the unauthenticated liveness
|
|
166
|
+
// probe used by the desktop sidecar boot. The Tauri shell calls it BEFORE
|
|
167
|
+
// it has parsed the studio_token from the sidecar's stdout, so token-gating
|
|
168
|
+
// it would deadlock the chicken-and-egg: the token comes from the running
|
|
169
|
+
// server, but the server has to be reachable to deliver it. Loopback bind
|
|
170
|
+
// (US-001) is the network-level guard for /api/health.
|
|
171
|
+
if (pathname === "/api/health")
|
|
172
|
+
return true;
|
|
173
|
+
// 0843 followup (2026-05-11): the GitHub OAuth browser callbacks are hit by
|
|
174
|
+
// the user's browser AFTER they authorize at github.com — there's no way
|
|
175
|
+
// for those requests to carry X-Studio-Token. The endpoints themselves are
|
|
176
|
+
// CSRF-protected via the `state` param (validated against an in-memory
|
|
177
|
+
// per-flow store), so exempting them from the token gate is safe.
|
|
178
|
+
if (pathname === "/api/oauth/github/callback")
|
|
179
|
+
return true;
|
|
180
|
+
if (pathname === "/api/oauth/github/desktop-complete")
|
|
181
|
+
return true;
|
|
182
|
+
const expected = getStudioToken();
|
|
183
|
+
// 0855: EventSource streams carry the token in a `?studioToken=<t>` query
|
|
184
|
+
// param because the browser EventSource API cannot set request headers.
|
|
185
|
+
// Scope: GET only + an allowlist of known stream paths. Validate with the
|
|
186
|
+
// SAME timing-safe compare used for the header. On success, STRIP the
|
|
187
|
+
// studioToken param from req.url BEFORE returning so it never reaches the
|
|
188
|
+
// upstream platform proxy (which reads req.url after the gate) and never
|
|
189
|
+
// leaks to verified-skill.com. The token is never logged.
|
|
190
|
+
if (method === "GET" && EVENTSOURCE_STREAM_PATHS.has(pathname)) {
|
|
191
|
+
const qpToken = parsedUrl.searchParams.get("studioToken");
|
|
192
|
+
if (tokensEqual(qpToken, expected)) {
|
|
193
|
+
parsedUrl.searchParams.delete("studioToken");
|
|
194
|
+
req.url = `${parsedUrl.pathname}${parsedUrl.search}`;
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
// Wrong/missing query token falls through to the header check below; if
|
|
198
|
+
// that also fails the request is rejected (boundary preserved).
|
|
199
|
+
}
|
|
200
|
+
const supplied = readHeader(req, "x-studio-token");
|
|
201
|
+
if (tokensEqual(supplied, expected))
|
|
202
|
+
return true;
|
|
203
|
+
// Reject. Empty body avoids leaking the expected-length info beyond what
|
|
204
|
+
// a fixed 401 signals. Log at WARN — and crucially WITHOUT the supplied
|
|
205
|
+
// token value (a wrong-length attempt could still be sensitive in CI logs).
|
|
206
|
+
// We log the path + method only.
|
|
207
|
+
if (!res.headersSent) {
|
|
208
|
+
res.writeHead(401, { "Content-Type": "text/plain" });
|
|
209
|
+
res.end("");
|
|
210
|
+
}
|
|
211
|
+
// eslint-disable-next-line no-console
|
|
212
|
+
console.warn(`[router] X-Studio-Token rejected for ${method} ${pathname}`);
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
function readHeader(req, name) {
|
|
216
|
+
const v = req.headers[name];
|
|
217
|
+
if (typeof v === "string")
|
|
218
|
+
return v;
|
|
219
|
+
if (Array.isArray(v))
|
|
220
|
+
return v[0];
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
export function sendJson(res, data, status = 200, _req) {
|
|
224
|
+
// 0836 US-002: CORS Origin-allowlist deleted. The studio-token gate is the
|
|
225
|
+
// sole authn for /api/*; any caller that passes the gate is same-origin
|
|
226
|
+
// for our purposes (Tauri WebView, vskill CLI's curl, Playwright, dev).
|
|
227
|
+
// We do not echo Access-Control-Allow-* headers anymore.
|
|
65
228
|
const headers = {
|
|
66
229
|
"Content-Type": "application/json",
|
|
67
230
|
"Cache-Control": "no-store",
|
|
68
231
|
Vary: "Origin",
|
|
69
232
|
};
|
|
70
|
-
const origin = req?.headers?.origin;
|
|
71
|
-
if (origin && LOCALHOST_ORIGIN_RE.test(origin)) {
|
|
72
|
-
headers["Access-Control-Allow-Origin"] = origin;
|
|
73
|
-
headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS";
|
|
74
|
-
headers["Access-Control-Allow-Headers"] = "Content-Type";
|
|
75
|
-
}
|
|
76
233
|
res.writeHead(status, headers);
|
|
77
234
|
res.end(JSON.stringify(data));
|
|
78
235
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/eval-server/router.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/eval-server/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// settings-store.ts — File-backed credential store for
|
|
2
|
+
// settings-store.ts — File-backed credential store for Skill Studio.
|
|
3
3
|
//
|
|
4
4
|
// Single on-disk file at `<configDir>/keys.env` (default configDir:
|
|
5
5
|
// `~/.vskill`, overridable via VSKILL_CONFIG_DIR). KEY=VALUE dotenv format.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-store.js","sourceRoot":"","sources":["../../src/eval-server/settings-store.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,
|
|
1
|
+
{"version":3,"file":"settings-store.js","sourceRoot":"","sources":["../../src/eval-server/settings-store.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,qEAAqE;AACrE,EAAE;AACF,oEAAoE;AACpE,4EAA4E;AAC5E,mEAAmE;AACnE,EAAE;AACF,YAAY;AACZ,yEAAyE;AACzE,iEAAiE;AACjE,8EAA8E;AAC9E,8EAA8E;AAC9E,uEAAuE;AACvE,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,uEAAuE;AACvE,4EAA4E;AAC5E,sCAAsC;AACtC,EAAE;AACF,yEAAyE;AACzE,8EAA8E;AAE9E,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EACL,SAAS,GAGV,MAAM,gBAAgB,CAAC;AAqCxB,8EAA8E;AAC9E,8DAA8D;AAC9D,8EAA8E;AAE9E,MAAM,aAAa,GAAW;IAC5B,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5B,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;CAC/B,CAAC;AAEF,6EAA6E;AAC7E,4EAA4E;AAC5E,wEAAwE;AACxE,yEAAyE;AACzE,MAAM,SAAS,GAAa;IAC1B,aAAa,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,GAAI,IAAgD,CAAC;IACtG,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,GAAI,IAA6C,CAAC;IAC7F,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,GAAI,IAA4C,CAAC;IAC1F,YAAY,EAAE,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CACnC,MAAM,CAAC,YAAwD,CAAC,GAAG,IAAI,CAAC,CAA+B;IAC1G,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,GAAI,IAA6C,CAAC;IAC7F,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,GAAI,IAA6C,CAAC;IAC7F,SAAS,EAAE,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CAChC,MAAM,CAAC,SAAqD,CAAC,GAAG,IAAI,CAAC,CAA4B;IACpG,QAAQ,EAAE,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CAC/B,MAAM,CAAC,QAAoD,CAAC,GAAG,IAAI,CAAC,CAA2B;CACnG,CAAC;AAEF,IAAI,MAAM,GAAW,aAAa,CAAC;AACnC,IAAI,MAAM,GAAa,SAAS,CAAC;AACjC,IAAI,iBAAiB,GAAkB,IAAI,CAAC;AAC5C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAqB,CAAC;AAC/C,8DAA8D;AAC9D,yEAAyE;AACzE,uEAAuE;AACvE,yEAAyE;AACzE,4EAA4E;AAC5E,0EAA0E;AAC1E,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAAU,CAAC;AAChD,4EAA4E;AAC5E,+EAA+E;AAC/E,kCAAkC;AAClC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAqC,CAAC;AACjE,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,SAAS,gBAAgB;IACvB,IAAI,iBAAiB;QAAE,OAAO,iBAAiB,CAAC;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC9C,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,OAAO,CAAC;IAClD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,UAAU,CAAC,CAAC;AACnD,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAC3C,OAAO,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E,SAAS,SAAS,CAAC,QAAgB;IAIjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC7C,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,aAAa;IACb,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEtC,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAC3C,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAChC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAEnC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;gBACZ,cAAc,EAAE,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5C,cAAc,EAAE,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,8DAA8D;gBAC9D,kDAAkD;gBAClD,SAAS;YACX,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QACxE,CAAC;QAAC,MAAM,CAAC;YACP,cAAc,EAAE,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,YAAY;IACnB,IAAI,MAAM;QAAE,OAAO;IACnB,MAAM,GAAG,IAAI,CAAC;IACd,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO;IACzC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACvD,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,SAAS,CAAC,QAAkB,CAAC,CAAC;QAClE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO;YAAE,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9D,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CACT,oBAAoB,cAAc,yBAAyB,QAAQ,eAAe,CACnF,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,mCAAmC,QAAQ,KAAM,GAAa,CAAC,OAAO,EAAE,CACzE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,SAAS,SAAS,CAAC,OAA+B;IAChD,MAAM,KAAK,GAAa;QACtB,0FAA0F;KAC3F,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,UAAU,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC;AAED,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,GAAG,QAAQ,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAC/D,IAAI,CAAC;QACH,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,0CAA0C;YAC5C,CAAC;QACH,CAAC;QACD,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,2BAA2B;QAC3B,IAAI,CAAC;YACH,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,aAAa;QACf,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,2CAA2C;AAC3C,8EAA8E;AAE9E,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,QAAoB,EACpB,GAAW;IAEX,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,YAAY,EAAE,CAAC;IAEf,iEAAiE;IACjE,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IAEvC,IAAI,CAAC;QACH,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,kDAAkD;QAClD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CACV,4BAA4B,QAAQ,KAAK,QAAQ,aAAc,GAAa,CAAC,OAAO,EAAE,CACvF,CAAC;QACF,MAAM,IAAI,KAAK,CACb,WAAW,QAAQ,KAAK,QAAQ,aAAc,GAAa,CAAC,OAAO,EAAE,CACtE,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5C,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACzC,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,QAAoB;IAC1C,YAAY,EAAE,CAAC;IACf,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CACS,CAAC;IACpC,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,OAAO,CAAC;IACpD,CAAC;IACD,OAAO,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAoB;IAC9C,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAoB;IAC7C,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAoB;IAClD,YAAY,EAAE,CAAC;IACf,yEAAyE;IACzE,wEAAwE;IACxE,2DAA2D;IAC3D,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO;IACnE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtB,IAAI,CAAC;QACH,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CACV,8BAA8B,QAAQ,aAAc,GAAa,CAAC,OAAO,EAAE,CAC5E,CAAC;QACF,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3B,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7B,0EAA0E;IAC1E,sEAAsE;IACtE,iDAAiD;IACjD,mEAAmE;IACnE,sEAAsE;IACtE,wEAAwE;IACxE,0CAA0C;IAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IAC5D,IAAI,UAAU,IAAI,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACnE,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1C,qBAAqB,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,YAAY,EAAE,CAAC;IACf,MAAM,IAAI,GAAG,CAAC,CAAa,EAAe,EAAE;QAC1C,mEAAmE;QACnE,uDAAuD;QACvD,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7D,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7D,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC,CAAC;IACF,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC;QAC5B,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QACtB,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,MAAM,UAAU,sBAAsB;IACpC,YAAY,EAAE,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,gDAAgD;QAChD,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,SAAS,EAAE,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;YACtC,oEAAoE;YACpE,gEAAgE;YAChE,sDAAsD;YACtD,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC;QACD,qEAAqE;QACrE,gDAAgD;QAChD,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,+BAA+B;IAC/B,SAAS,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC;AAYD,MAAM,UAAU,kBAAkB,CAAC,OAAqB,EAAE;IACxD,SAAS,CAAC,KAAK,EAAE,CAAC;IAClB,WAAW,CAAC,KAAK,EAAE,CAAC;IACpB,qBAAqB,CAAC,KAAK,EAAE,CAAC;IAC9B,MAAM,GAAG,KAAK,CAAC;IACf,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC;IACtC,MAAM,GAAG,IAAI,CAAC,EAAE,IAAI,SAAS,CAAC;IAC9B,iBAAiB,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC;AAC7C,CAAC"}
|
|
@@ -195,5 +195,5 @@ export interface EvalsResult {
|
|
|
195
195
|
export declare function parseBodyResponse(raw: string): BodyResult;
|
|
196
196
|
export declare function parseEvalsResponse(raw: string): EvalsResult;
|
|
197
197
|
export declare function mergeGenerateResults(bodySettled: PromiseSettledResult<BodyResult>, evalsSettled: PromiseSettledResult<EvalsResult>): GenerateSkillResult;
|
|
198
|
-
export declare function registerSkillCreateRoutes(router: Router,
|
|
198
|
+
export declare function registerSkillCreateRoutes(router: Router, rootArg: string | (() => string)): void;
|
|
199
199
|
export {};
|
|
@@ -934,9 +934,11 @@ async function resolveProviderModel(requestedProvider, requestedModel) {
|
|
|
934
934
|
// ---------------------------------------------------------------------------
|
|
935
935
|
// Route registration
|
|
936
936
|
// ---------------------------------------------------------------------------
|
|
937
|
-
export function registerSkillCreateRoutes(router,
|
|
937
|
+
export function registerSkillCreateRoutes(router, rootArg) {
|
|
938
|
+
const getRoot = typeof rootArg === "function" ? rootArg : () => rootArg;
|
|
938
939
|
// GET /api/project-layout — detect project layout and suggest placement
|
|
939
940
|
router.get("/api/project-layout", async (_req, res) => {
|
|
941
|
+
const root = getRoot();
|
|
940
942
|
try {
|
|
941
943
|
const layout = detectProjectLayout(root);
|
|
942
944
|
sendJson(res, layout, 200, _req);
|
|
@@ -948,6 +950,7 @@ export function registerSkillCreateRoutes(router, root) {
|
|
|
948
950
|
// 0772 US-005: GET /api/project/github-status — quick probe of git +
|
|
949
951
|
// GitHub origin so the UI can surface a "connect GitHub to publish" hint.
|
|
950
952
|
router.get("/api/project/github-status", async (_req, res) => {
|
|
953
|
+
const root = getRoot();
|
|
951
954
|
try {
|
|
952
955
|
const status = detectProjectGitHubStatus(root);
|
|
953
956
|
sendJson(res, status, 200, _req);
|
|
@@ -960,6 +963,7 @@ export function registerSkillCreateRoutes(router, root) {
|
|
|
960
963
|
});
|
|
961
964
|
// POST /api/skills/create — create a new skill
|
|
962
965
|
router.post("/api/skills/create", async (req, res) => {
|
|
966
|
+
const root = getRoot();
|
|
963
967
|
const body = (await readBody(req));
|
|
964
968
|
// Validate name
|
|
965
969
|
if (!body.name || !/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(body.name)) {
|
|
@@ -1168,6 +1172,7 @@ export function registerSkillCreateRoutes(router, root) {
|
|
|
1168
1172
|
});
|
|
1169
1173
|
// POST /api/skills/save-draft — auto-save AI-generated skill as draft
|
|
1170
1174
|
router.post("/api/skills/save-draft", async (req, res) => {
|
|
1175
|
+
const root = getRoot();
|
|
1171
1176
|
const body = (await readBody(req));
|
|
1172
1177
|
if (!body.name || !/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(body.name)) {
|
|
1173
1178
|
sendJson(res, { error: "Name must be kebab-case" }, 400, req);
|
|
@@ -1254,6 +1259,7 @@ export function registerSkillCreateRoutes(router, root) {
|
|
|
1254
1259
|
});
|
|
1255
1260
|
// GET /api/skill-creator-status — check if skill-creator is installed
|
|
1256
1261
|
router.get("/api/skill-creator-status", async (_req, res) => {
|
|
1262
|
+
const root = getRoot();
|
|
1257
1263
|
const installed = isSkillCreatorInstalled(root);
|
|
1258
1264
|
sendJson(res, {
|
|
1259
1265
|
installed,
|
|
@@ -1263,6 +1269,7 @@ export function registerSkillCreateRoutes(router, root) {
|
|
|
1263
1269
|
// POST /api/skills/generate — AI-assisted skill generation (parallel body + evals)
|
|
1264
1270
|
// 0670 T-002: thin wrapper over src/core/skill-generator.ts:generateSkill.
|
|
1265
1271
|
router.post("/api/skills/generate", async (req, res) => {
|
|
1272
|
+
const root = getRoot();
|
|
1266
1273
|
const body = (await readBody(req));
|
|
1267
1274
|
if (!body.prompt || !body.prompt.trim())
|
|
1268
1275
|
return sendJson(res, { error: "Describe what your skill should do" }, 400, req);
|