@geminixiang/mikan 1.0.0-beta.92 → 1.0.0-beta.93
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/CHANGELOG.md +6 -0
- package/dist/adapters/web/admin/client-assets.d.ts +1 -1
- package/dist/adapters/web/admin/client-assets.d.ts.map +1 -1
- package/dist/adapters/web/admin/client-assets.js +106 -18
- package/dist/adapters/web/admin/client-assets.js.map +1 -1
- package/dist/adapters/web/admin/portal.d.ts +0 -7
- package/dist/adapters/web/admin/portal.d.ts.map +1 -1
- package/dist/adapters/web/admin/portal.js +91 -59
- package/dist/adapters/web/admin/portal.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +3 -3
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/skills.d.ts +11 -2
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +84 -25
- package/dist/harness/skills.js.map +1 -1
- package/dist/harness/types.d.ts +7 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/settings/index.d.ts +3 -1
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +14 -0
- package/dist/settings/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { validateEventFilename } from "../../../events/index.js";
|
|
2
2
|
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, } from "node:fs";
|
|
3
|
-
import { basename, join, resolve as pathResolve, sep as pathSep } from "node:path";
|
|
3
|
+
import { basename, join, matchesGlob, resolve as pathResolve, sep as pathSep } from "node:path";
|
|
4
4
|
import { atomicWritePrivateFile } from "../../../file-guards.js";
|
|
5
5
|
import { MikanModels } from "../../../harness/models.js";
|
|
6
|
-
import {
|
|
6
|
+
import { formatSkillsForPrompt, loadOfficeSkills, resolveSkillEnabled, validateSkill, } from "../../../harness/skills.js";
|
|
7
7
|
import { SessionStore } from "../../../sessions/session-store.js";
|
|
8
8
|
import { InMemoryTokenStore } from "../token-store.js";
|
|
9
9
|
import { adminViewFunctionsScript, adminViewStartupScript, adminViewStyles, } from "./client-assets.js";
|
|
@@ -19,7 +19,7 @@ export class InMemoryAdminTokenStore extends InMemoryTokenStore {
|
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
import { isThinkingLevel, loadOfficeVisibilityOverride, loadGlobalSettings, loadScopeMcpServers, resolveConversationSettings, } from "../../../settings/index.js";
|
|
22
|
+
import { isThinkingLevel, loadOfficeVisibilityOverride, loadGlobalSettings, loadScopeMcpServers, loadSkillPatterns, resolveConversationSettings, updateSkillPatterns, } from "../../../settings/index.js";
|
|
23
23
|
import { findMcpPreset, listMcpPresets, materializeMcpPreset } from "../../../harness/mcp.js";
|
|
24
24
|
import { loadMcpTools } from "../../../harness/mcp.js";
|
|
25
25
|
import { isValidMcpServerName, parseStandardMcpServers, redactMcpUrl, } from "../../../harness/mcp.js";
|
|
@@ -131,6 +131,8 @@ async function routePostApiRequest(req, res, url, services) {
|
|
|
131
131
|
return serveMcpServerMutation(res, body, services, token);
|
|
132
132
|
case "/admin/api/skills/mutate":
|
|
133
133
|
return serveSkillMutation(res, body, services, token);
|
|
134
|
+
case "/admin/api/skills/toggle":
|
|
135
|
+
return serveSkillToggle(res, body, services, token);
|
|
134
136
|
case "/admin/api/settings/model":
|
|
135
137
|
return serveGlobalModelUpdate(res, body, services);
|
|
136
138
|
case "/admin/api/settings/sandbox":
|
|
@@ -900,52 +902,6 @@ function serveWorkspaceFile(res, url, services, token) {
|
|
|
900
902
|
}
|
|
901
903
|
servePreviewFile(res, safe.absolute, { path: requestedPath }, "File not found");
|
|
902
904
|
}
|
|
903
|
-
function readSkillMeta(filePath) {
|
|
904
|
-
let text;
|
|
905
|
-
try {
|
|
906
|
-
text = readFileSync(filePath, "utf-8");
|
|
907
|
-
}
|
|
908
|
-
catch {
|
|
909
|
-
return {};
|
|
910
|
-
}
|
|
911
|
-
const { values } = parseFrontmatter(text);
|
|
912
|
-
const out = {};
|
|
913
|
-
for (const [key, value] of Object.entries(values)) {
|
|
914
|
-
const normalized = key.toLowerCase();
|
|
915
|
-
if (normalized === "name")
|
|
916
|
-
out.name = value;
|
|
917
|
-
if (normalized === "description")
|
|
918
|
-
out.description = value;
|
|
919
|
-
}
|
|
920
|
-
return out;
|
|
921
|
-
}
|
|
922
|
-
export function readSkillsFromDir(skillsDir, source) {
|
|
923
|
-
if (!existsSync(skillsDir))
|
|
924
|
-
return [];
|
|
925
|
-
const out = [];
|
|
926
|
-
let entries;
|
|
927
|
-
try {
|
|
928
|
-
entries = readdirSync(skillsDir, { withFileTypes: true });
|
|
929
|
-
}
|
|
930
|
-
catch {
|
|
931
|
-
return [];
|
|
932
|
-
}
|
|
933
|
-
for (const entry of entries) {
|
|
934
|
-
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
935
|
-
continue;
|
|
936
|
-
const skillMd = join(skillsDir, entry.name, "SKILL.md");
|
|
937
|
-
if (!existsSync(skillMd))
|
|
938
|
-
continue;
|
|
939
|
-
const meta = readSkillMeta(skillMd);
|
|
940
|
-
out.push({
|
|
941
|
-
name: meta.name ?? entry.name,
|
|
942
|
-
description: meta.description ?? "",
|
|
943
|
-
source,
|
|
944
|
-
directory: entry.name,
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
|
-
return out.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
948
|
-
}
|
|
949
905
|
function serveMcpServersList(res, url, services, token) {
|
|
950
906
|
const scope = resolveConversationFromQuery(url, token);
|
|
951
907
|
if (scope.error) {
|
|
@@ -1098,6 +1054,56 @@ async function serveMcpServerMutation(res, body, services, token) {
|
|
|
1098
1054
|
const results = await verifyMcpServers(plan.touched);
|
|
1099
1055
|
jsonRes(res, 200, { ok: true, results });
|
|
1100
1056
|
}
|
|
1057
|
+
function skillRule(directory, patterns) {
|
|
1058
|
+
let rule = null;
|
|
1059
|
+
for (const pattern of patterns) {
|
|
1060
|
+
const kind = pattern[0];
|
|
1061
|
+
const target = pattern.slice(1);
|
|
1062
|
+
if ((kind === "+" || kind === "-") && target === directory)
|
|
1063
|
+
rule = kind;
|
|
1064
|
+
else if (kind === "!" &&
|
|
1065
|
+
rule === null &&
|
|
1066
|
+
(target === directory || matchesGlob(directory, target)))
|
|
1067
|
+
rule = "!";
|
|
1068
|
+
}
|
|
1069
|
+
return rule;
|
|
1070
|
+
}
|
|
1071
|
+
function officeSkillListing(workspace, office) {
|
|
1072
|
+
const patterns = loadSkillPatterns(office);
|
|
1073
|
+
const { skills } = loadOfficeSkills({
|
|
1074
|
+
globalSkillsDir: workspace.skillsDir,
|
|
1075
|
+
conversationSkillsDir: office.skillsDir,
|
|
1076
|
+
patterns,
|
|
1077
|
+
});
|
|
1078
|
+
const listed = skills.filter((skill) => skill.enabled !== false && !skill.disableModelInvocation);
|
|
1079
|
+
return {
|
|
1080
|
+
conversationId: office.address.conversationId,
|
|
1081
|
+
skills: skills.map((skill) => {
|
|
1082
|
+
const directory = skill.directory ?? "";
|
|
1083
|
+
return {
|
|
1084
|
+
name: skill.name,
|
|
1085
|
+
description: skill.description,
|
|
1086
|
+
source: skill.source,
|
|
1087
|
+
directory,
|
|
1088
|
+
enabled: skill.enabled !== false,
|
|
1089
|
+
globalEnabled: skill.source === "global"
|
|
1090
|
+
? resolveSkillEnabled("global", directory, {
|
|
1091
|
+
global: patterns.global,
|
|
1092
|
+
conversation: [],
|
|
1093
|
+
})
|
|
1094
|
+
: null,
|
|
1095
|
+
editable: !directory.includes("/"),
|
|
1096
|
+
globalRule: skill.source === "global" ? skillRule(directory, patterns.global) : null,
|
|
1097
|
+
conversationRule: skillRule(directory, patterns.conversation),
|
|
1098
|
+
};
|
|
1099
|
+
}),
|
|
1100
|
+
prompt: {
|
|
1101
|
+
listed: listed.length,
|
|
1102
|
+
total: skills.length,
|
|
1103
|
+
chars: formatSkillsForPrompt(skills).length,
|
|
1104
|
+
},
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1101
1107
|
function serveSkillsList(res, url, services, token) {
|
|
1102
1108
|
const scope = resolveConversationFromQuery(url, token);
|
|
1103
1109
|
if (scope.error) {
|
|
@@ -1107,12 +1113,38 @@ function serveSkillsList(res, url, services, token) {
|
|
|
1107
1113
|
const workspace = requireAdminWorkspace(res, services);
|
|
1108
1114
|
if (!workspace)
|
|
1109
1115
|
return;
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
+
jsonRes(res, 200, officeSkillListing(workspace, workspace.office(scope.address)));
|
|
1117
|
+
}
|
|
1118
|
+
const SKILL_TOGGLE_STATES = {
|
|
1119
|
+
global: ["load", "unload"],
|
|
1120
|
+
conversation: ["inherit", "load", "unload"],
|
|
1121
|
+
};
|
|
1122
|
+
function serveSkillToggle(res, body, services, token) {
|
|
1123
|
+
const scope = resolveTargetConversation(body, token);
|
|
1124
|
+
if (scope.error) {
|
|
1125
|
+
jsonRes(res, 403, { error: scope.error });
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
const workspace = requireAdminWorkspace(res, services);
|
|
1129
|
+
if (!workspace)
|
|
1130
|
+
return;
|
|
1131
|
+
const target = body.scope === "global" || body.scope === "conversation" ? body.scope : undefined;
|
|
1132
|
+
const state = typeof body.state === "string" ? body.state : "";
|
|
1133
|
+
if (!target || !SKILL_TOGGLE_STATES[target].includes(state)) {
|
|
1134
|
+
jsonRes(res, 400, { error: "Invalid scope or state" });
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
const office = workspace.office(scope.address);
|
|
1138
|
+
const skill = officeSkillListing(workspace, office).skills.find((entry) => entry.source === body.source && entry.directory === body.directory);
|
|
1139
|
+
if (!skill) {
|
|
1140
|
+
jsonRes(res, 404, { error: "Skill not found" });
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
const patterns = loadSkillPatterns(office)[target].filter((pattern) => pattern.slice(1) !== skill.directory);
|
|
1144
|
+
if (state !== "inherit")
|
|
1145
|
+
patterns.push(`${state === "load" ? "+" : "-"}${skill.directory}`);
|
|
1146
|
+
updateSkillPatterns(target === "global" ? undefined : office, patterns);
|
|
1147
|
+
jsonRes(res, 200, officeSkillListing(workspace, office));
|
|
1116
1148
|
}
|
|
1117
1149
|
function serveSkillFile(res, url, services, token) {
|
|
1118
1150
|
const scope = resolveConversationFromQuery(url, token);
|
|
@@ -1130,9 +1162,9 @@ function serveSkillFile(res, url, services, token) {
|
|
|
1130
1162
|
return;
|
|
1131
1163
|
}
|
|
1132
1164
|
if (!directory ||
|
|
1133
|
-
directory.
|
|
1165
|
+
directory.startsWith("/") ||
|
|
1134
1166
|
directory.includes("\\") ||
|
|
1135
|
-
directory.includes("..")) {
|
|
1167
|
+
directory.split("/").includes("..")) {
|
|
1136
1168
|
jsonRes(res, 400, { error: "Invalid skill directory" });
|
|
1137
1169
|
return;
|
|
1138
1170
|
}
|
|
@@ -1369,7 +1401,7 @@ const adminViewBody = `<div class="settings-shell">
|
|
|
1369
1401
|
|
|
1370
1402
|
${settingsPane("workspace", "Workspace", "Read-only browser for this conversation's files on disk.", '<button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadWorkspace()">↻</button>', '<div class="workspace-split"><div id="workspace-tree" class="workspace-tree"><div class="loading-msg">Loading…</div></div><div id="workspace-preview" class="workspace-preview"><div class="placeholder-msg">Click a file to preview</div></div></div>')}
|
|
1371
1403
|
|
|
1372
|
-
${settingsPane("skills", "Skills", "Instructions the agent can load for specific tasks in this conversation.", '<button class="primary-action-btn" onclick="openSkillDialog(\'conversation\')">+ New skill</button><button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadSkills()">↻</button>', '<div class="workspace-split"><div id="skills-content" class="workspace-tree"><div class="loading-msg">Loading…</div></div><div id="skills-preview" class="workspace-preview"><div class="placeholder-msg">Click a skill to preview SKILL.md</div></div></div>')}
|
|
1404
|
+
${settingsPane("skills", "Skills", "Instructions the agent can load for specific tasks in this conversation.", '<button class="primary-action-btn" onclick="openSkillDialog(\'conversation\')">+ New skill</button><button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadSkills()">↻</button>', '<div class="skills-toolbar"><input id="skills-filter" class="skills-filter" type="search" placeholder="Filter skills" oninput="renderAllSkills()"><span id="skills-summary" class="skills-summary"></span></div><div class="workspace-split"><div id="skills-content" class="workspace-tree"><div class="loading-msg">Loading…</div></div><div id="skills-preview" class="workspace-preview"><div class="placeholder-msg">Click a skill to preview SKILL.md</div></div></div>')}
|
|
1373
1405
|
|
|
1374
1406
|
${settingsPane("mcp", "MCP servers", "External tools this conversation can call during a run.", '<button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadMcpServers()">↻</button>', '<div id="mcp-conv-msg" class="status-msg" style="display:none"></div><div id="mcp-conv-content"><div class="loading-msg">Loading…</div></div>')}
|
|
1375
1407
|
|
|
@@ -1389,7 +1421,7 @@ const adminViewBody = `<div class="settings-shell">
|
|
|
1389
1421
|
|
|
1390
1422
|
${settingsPane("g-mcp", "MCP servers", "External tools available to every conversation in this workspace.", '<button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadMcpServers()">↻</button>', '<div id="mcp-global-msg" class="status-msg" style="display:none"></div><div id="mcp-global-content"><div class="loading-msg">Loading…</div></div>')}
|
|
1391
1423
|
|
|
1392
|
-
${settingsPane("g-skills", "Skills", "Shared instructions available to every conversation in this workspace.", '<button class="primary-action-btn" onclick="openSkillDialog(\'global\')">+ New global skill</button><button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadGlobalSkills()">↻</button>', '<div class="workspace-split"><div id="global-skills-content" class="workspace-tree"><div class="loading-msg">Loading…</div></div><div id="global-skills-preview" class="workspace-preview"><div class="placeholder-msg">Click a skill to preview SKILL.md</div></div></div>')}
|
|
1424
|
+
${settingsPane("g-skills", "Skills", "Shared instructions available to every conversation in this workspace.", '<button class="primary-action-btn" onclick="openSkillDialog(\'global\')">+ New global skill</button><button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadGlobalSkills()">↻</button>', '<div class="skills-toolbar"><input id="global-skills-filter" class="skills-filter" type="search" placeholder="Filter skills" oninput="renderAllSkills()"><span id="global-skills-summary" class="skills-summary"></span></div><div class="workspace-split"><div id="global-skills-content" class="workspace-tree"><div class="loading-msg">Loading…</div></div><div id="global-skills-preview" class="workspace-preview"><div class="placeholder-msg">Click a skill to preview SKILL.md</div></div></div>')}
|
|
1393
1425
|
|
|
1394
1426
|
${settingsPane("g-events", "Global events", "Every scheduled event across the whole workspace.", '<button class="refresh-btn" type="button" aria-label="Refresh" title="Refresh" onclick="loadEvents()">↻</button>', '<div id="global-events-content"><div class="loading-msg">Loading…</div></div>')}
|
|
1395
1427
|
</div>
|