@geminixiang/mikan 1.0.0-beta.92 → 1.0.0-beta.94

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.
Files changed (110) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/adapters/discord/bot.d.ts +2 -2
  3. package/dist/adapters/discord/bot.d.ts.map +1 -1
  4. package/dist/adapters/discord/bot.js +9 -3
  5. package/dist/adapters/discord/bot.js.map +1 -1
  6. package/dist/adapters/github/bot.d.ts +2 -2
  7. package/dist/adapters/github/bot.d.ts.map +1 -1
  8. package/dist/adapters/github/bot.js +4 -3
  9. package/dist/adapters/github/bot.js.map +1 -1
  10. package/dist/adapters/intake.d.ts.map +1 -1
  11. package/dist/adapters/intake.js.map +1 -1
  12. package/dist/adapters/shared.d.ts +0 -2
  13. package/dist/adapters/shared.d.ts.map +1 -1
  14. package/dist/adapters/shared.js +1 -17
  15. package/dist/adapters/shared.js.map +1 -1
  16. package/dist/adapters/slack/bot.d.ts +2 -2
  17. package/dist/adapters/slack/bot.d.ts.map +1 -1
  18. package/dist/adapters/slack/bot.js +13 -22
  19. package/dist/adapters/slack/bot.js.map +1 -1
  20. package/dist/adapters/slack/jev-context.d.ts.map +1 -1
  21. package/dist/adapters/slack/jev-context.js +3 -17
  22. package/dist/adapters/slack/jev-context.js.map +1 -1
  23. package/dist/adapters/slack/task-status.d.ts.map +1 -1
  24. package/dist/adapters/slack/task-status.js +4 -9
  25. package/dist/adapters/slack/task-status.js.map +1 -1
  26. package/dist/adapters/telegram/bot.d.ts +2 -2
  27. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  28. package/dist/adapters/telegram/bot.js +9 -3
  29. package/dist/adapters/telegram/bot.js.map +1 -1
  30. package/dist/adapters/types.d.ts +4 -4
  31. package/dist/adapters/types.d.ts.map +1 -1
  32. package/dist/adapters/types.js.map +1 -1
  33. package/dist/adapters/web/admin/client-assets.d.ts +1 -1
  34. package/dist/adapters/web/admin/client-assets.d.ts.map +1 -1
  35. package/dist/adapters/web/admin/client-assets.js +106 -18
  36. package/dist/adapters/web/admin/client-assets.js.map +1 -1
  37. package/dist/adapters/web/admin/portal.d.ts +0 -7
  38. package/dist/adapters/web/admin/portal.d.ts.map +1 -1
  39. package/dist/adapters/web/admin/portal.js +98 -66
  40. package/dist/adapters/web/admin/portal.js.map +1 -1
  41. package/dist/harness/execution-resolver.d.ts.map +1 -1
  42. package/dist/harness/execution-resolver.js +1 -2
  43. package/dist/harness/execution-resolver.js.map +1 -1
  44. package/dist/harness/presenter.d.ts.map +1 -1
  45. package/dist/harness/presenter.js +5 -26
  46. package/dist/harness/presenter.js.map +1 -1
  47. package/dist/harness/prompt.d.ts +1 -3
  48. package/dist/harness/prompt.d.ts.map +1 -1
  49. package/dist/harness/prompt.js +4 -38
  50. package/dist/harness/prompt.js.map +1 -1
  51. package/dist/harness/runner.d.ts.map +1 -1
  52. package/dist/harness/runner.js +14 -41
  53. package/dist/harness/runner.js.map +1 -1
  54. package/dist/harness/session.d.ts.map +1 -1
  55. package/dist/harness/session.js +2 -9
  56. package/dist/harness/session.js.map +1 -1
  57. package/dist/harness/skills.d.ts +11 -2
  58. package/dist/harness/skills.d.ts.map +1 -1
  59. package/dist/harness/skills.js +84 -25
  60. package/dist/harness/skills.js.map +1 -1
  61. package/dist/harness/tools/attach.d.ts +3 -0
  62. package/dist/harness/tools/attach.d.ts.map +1 -1
  63. package/dist/harness/tools/attach.js +36 -1
  64. package/dist/harness/tools/attach.js.map +1 -1
  65. package/dist/harness/tools/index.d.ts +3 -19
  66. package/dist/harness/tools/index.d.ts.map +1 -1
  67. package/dist/harness/tools/index.js +22 -11
  68. package/dist/harness/tools/index.js.map +1 -1
  69. package/dist/harness/tools/types.d.ts +9 -1
  70. package/dist/harness/tools/types.d.ts.map +1 -1
  71. package/dist/harness/tools/types.js.map +1 -1
  72. package/dist/harness/types.d.ts +7 -14
  73. package/dist/harness/types.d.ts.map +1 -1
  74. package/dist/harness/types.js.map +1 -1
  75. package/dist/office/log.d.ts +14 -0
  76. package/dist/office/log.d.ts.map +1 -0
  77. package/dist/office/log.js +46 -0
  78. package/dist/office/log.js.map +1 -0
  79. package/dist/office/projection.d.ts.map +1 -1
  80. package/dist/office/projection.js +17 -12
  81. package/dist/office/projection.js.map +1 -1
  82. package/dist/office/types.d.ts +1 -0
  83. package/dist/office/types.d.ts.map +1 -1
  84. package/dist/office/types.js.map +1 -1
  85. package/dist/sandbox/index.d.ts +1 -1
  86. package/dist/sandbox/index.d.ts.map +1 -1
  87. package/dist/sandbox/index.js +1 -1
  88. package/dist/sandbox/index.js.map +1 -1
  89. package/dist/sandbox/registry.d.ts +1 -1
  90. package/dist/sandbox/registry.d.ts.map +1 -1
  91. package/dist/sandbox/registry.js +1 -1
  92. package/dist/sandbox/registry.js.map +1 -1
  93. package/dist/sessions/chat-history-sync.d.ts.map +1 -1
  94. package/dist/sessions/chat-history-sync.js +48 -46
  95. package/dist/sessions/chat-history-sync.js.map +1 -1
  96. package/dist/sessions/session-store.d.ts +2 -17
  97. package/dist/sessions/session-store.d.ts.map +1 -1
  98. package/dist/sessions/session-store.js +44 -34
  99. package/dist/sessions/session-store.js.map +1 -1
  100. package/dist/sessions/types.d.ts +20 -1
  101. package/dist/sessions/types.d.ts.map +1 -1
  102. package/dist/sessions/types.js.map +1 -1
  103. package/dist/settings/index.d.ts +3 -1
  104. package/dist/settings/index.d.ts.map +1 -1
  105. package/dist/settings/index.js +14 -0
  106. package/dist/settings/index.js.map +1 -1
  107. package/dist/types.d.ts +13 -0
  108. package/dist/types.d.ts.map +1 -1
  109. package/dist/types.js.map +1 -1
  110. package/package.json +5 -5
@@ -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 { parseFrontmatter, validateSkill } from "../../../harness/skills.js";
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":
@@ -265,10 +267,7 @@ async function readSessionUsage(office, sessionKey, conversationId, label) {
265
267
  const header = manager.getHeader();
266
268
  const entries = await manager.getEntries();
267
269
  const usage = entries.reduce((sum, entry) => {
268
- if (entry.type !== "message" || entry.message.role !== "assistant")
269
- return sum;
270
- const message = entry.message;
271
- const item = message.usage;
270
+ const item = assistantUsage(entry);
272
271
  if (!item)
273
272
  return sum;
274
273
  sum.input += numberOrZero(item.input);
@@ -298,6 +297,11 @@ async function readSessionUsage(office, sessionKey, conversationId, label) {
298
297
  return [];
299
298
  }
300
299
  }
300
+ function assistantUsage(entry) {
301
+ if (entry.type !== "message" || entry.message.role !== "assistant")
302
+ return undefined;
303
+ return entry.message.usage;
304
+ }
301
305
  function numberOrZero(value) {
302
306
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
303
307
  }
@@ -374,9 +378,7 @@ async function accumulateSessionUsageByDay(office, sessionKey, cutoff, buckets,
374
378
  if (!manager)
375
379
  return;
376
380
  for (const entry of await manager.getEntries()) {
377
- if (entry.type !== "message" || entry.message.role !== "assistant")
378
- continue;
379
- const usage = entry.message.usage;
381
+ const usage = assistantUsage(entry);
380
382
  if (!usage || !entry.timestamp)
381
383
  continue;
382
384
  const when = new Date(entry.timestamp);
@@ -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
- const global = readSkillsFromDir(workspace.skillsDir, "global");
1111
- const conversation = readSkillsFromDir(workspace.office(scope.address).skillsDir, "conversation");
1112
- jsonRes(res, 200, {
1113
- conversationId: scope.conversationId,
1114
- skills: [...global, ...conversation],
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.includes("/") ||
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>