@geminixiang/mikan 1.0.0-beta.71 → 1.0.0-beta.73
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 +12 -0
- package/dist/adapters/web/admin/portal.d.ts.map +1 -1
- package/dist/adapters/web/admin/portal.js +522 -333
- package/dist/adapters/web/admin/portal.js.map +1 -1
- package/dist/harness/index.d.ts +1 -1
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +1 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/skills.d.ts +2 -0
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +2 -1
- package/dist/harness/skills.js.map +1 -1
- package/package.json +1 -1
package/dist/harness/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type { SessionContext, SessionEntry, SessionHeader, SessionMessageEntry,
|
|
|
14
14
|
export { CURRENT_SESSION_VERSION } from "../sessions/types.js";
|
|
15
15
|
export { MikanAgentSession } from "./session.js";
|
|
16
16
|
export type { CompactionReason, HarnessEvent, HarnessEventListener, MikanAgentSessionOptions, } from "./types.js";
|
|
17
|
-
export { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter } from "./skills.js";
|
|
17
|
+
export { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter, validateSkill, } from "./skills.js";
|
|
18
18
|
export type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from "./types.js";
|
|
19
19
|
export { loadSubagentProfiles } from "./subagent-profiles.js";
|
|
20
20
|
export type { LoadSubagentProfilesResult, SubagentProfileDiagnostic } from "./types.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/harness/index.js
CHANGED
|
@@ -11,7 +11,7 @@ export { JEV_MODEL_ID, JevNotConfiguredError, JevRequestError, evaluateWithJev,
|
|
|
11
11
|
export { SessionStore } from "../sessions/session-store.js";
|
|
12
12
|
export { CURRENT_SESSION_VERSION } from "../sessions/types.js";
|
|
13
13
|
export { MikanAgentSession } from "./session.js";
|
|
14
|
-
export { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter } from "./skills.js";
|
|
14
|
+
export { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter, validateSkill, } from "./skills.js";
|
|
15
15
|
export { loadSubagentProfiles } from "./subagent-profiles.js";
|
|
16
16
|
export { DEFAULT_BUDGET_SETTINGS, DEFAULT_EVENT_BUDGET, DEFAULT_RETRY_SETTINGS, resolveHarnessSettings, } from "./session.js";
|
|
17
17
|
export {} from "./types.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,GAOhB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAO5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOjD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,eAAe,EACf,eAAe,GAOhB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAO5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAOjD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAcN,MAAM,YAAY,CAAC","sourcesContent":["/**\n * mikan agent harness.\n *\n * Application integration of pi-agent-core's native AgentHarness (durable\n * operations, tools, retries, compaction, recovery) and pi-ai (providers,\n * models, auth). See `src/harness/README.md` for the architecture.\n */\nexport {\n DEFAULT_HTTP_IDLE_TIMEOUT_MS,\n configureHttpDispatcher,\n parseHttpIdleTimeoutMs,\n} from \"./http.js\";\nexport { MikanModels, defaultModelsJsonPath } from \"./models.js\";\nexport type { CreateMikanModelsOptions } from \"./types.js\";\nexport {\n JEV_MODEL_ID,\n JevNotConfiguredError,\n JevRequestError,\n evaluateWithJev,\n type EvaluateWithJevOptions,\n type JevAnswer,\n type JevEntry,\n type JevQuestion,\n type JevQuestions,\n type JevResult,\n} from \"./jev.js\";\nexport { SessionStore } from \"../sessions/session-store.js\";\nexport type {\n SessionContext,\n SessionEntry,\n SessionHeader,\n SessionMessageEntry,\n} from \"../sessions/types.js\";\nexport { CURRENT_SESSION_VERSION } from \"../sessions/types.js\";\nexport { MikanAgentSession } from \"./session.js\";\nexport type {\n CompactionReason,\n HarnessEvent,\n HarnessEventListener,\n MikanAgentSessionOptions,\n} from \"./types.js\";\nexport {\n formatSkillsForPrompt,\n loadSkillsFromDir,\n parseFrontmatter,\n validateSkill,\n} from \"./skills.js\";\nexport type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from \"./types.js\";\nexport { loadSubagentProfiles } from \"./subagent-profiles.js\";\nexport type { LoadSubagentProfilesResult, SubagentProfileDiagnostic } from \"./types.js\";\nexport {\n DEFAULT_BUDGET_SETTINGS,\n DEFAULT_EVENT_BUDGET,\n DEFAULT_RETRY_SETTINGS,\n resolveHarnessSettings,\n type CompactionSettings,\n} from \"./session.js\";\nexport type { BudgetSettings, HarnessSettings, RetrySettings } from \"./types.js\";\nexport {\n type SubagentModelSpec,\n type SubagentProfile,\n type SubagentParentContext,\n type SubagentRunBudget,\n type SubagentRunOutput,\n type SubagentRunRequest,\n type SubagentRunResult,\n type SubagentRunStatus,\n type SubagentUsage,\n type SubagentUsageSink,\n type BranchSummaryEntry,\n type CompactionEntry,\n type CustomEntry,\n} from \"./types.js\";\n"]}
|
package/dist/harness/skills.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ interface Frontmatter {
|
|
|
17
17
|
* Quoted values are unquoted; nested structures are not supported.
|
|
18
18
|
*/
|
|
19
19
|
export declare function parseFrontmatter(content: string): Frontmatter;
|
|
20
|
+
/** Exposed so the admin portal can validate a skill draft before writing it. */
|
|
21
|
+
export declare function validateSkill(name: string, description: string): string[];
|
|
20
22
|
/**
|
|
21
23
|
* Load skills from a directory tree.
|
|
22
24
|
* - A directory containing `SKILL.md` is a skill root; no further recursion.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAmB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAiC9D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,mBAAmB,GAC9B;IAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAAE,CA0BvD;AACD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMlD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAoB7D;
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAmB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAiC9D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,mBAAmB,GAC9B;IAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,iBAAiB,EAAE,MAAM,EAAE,CAAA;CAAE,CA0BvD;AACD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMlD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAoB7D;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBzE;AA2CD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,gBAAgB,CAgBnB;AAoGD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAyBlE"}
|
package/dist/harness/skills.js
CHANGED
|
@@ -69,7 +69,8 @@ export function parseFrontmatter(content) {
|
|
|
69
69
|
}
|
|
70
70
|
return { values, body: content.slice(match[0].length) };
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
/** Exposed so the admin portal can validate a skill draft before writing it. */
|
|
73
|
+
export function validateSkill(name, description) {
|
|
73
74
|
const errors = [];
|
|
74
75
|
if (name.length > MAX_NAME_LENGTH) {
|
|
75
76
|
errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Office } from \"../office/index.js\";\nimport type { MikanSkill, SkillDiagnostic, LoadSkillsResult } from \"./types.js\";\nimport type { WorkspaceProjection } from \"../office/types.js\";\nimport { existsSync, lstatSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\n\nimport * as log from \"../log.js\";\n\n/** Register skills under their prompt-side paths; a later source overrides an earlier one. */\nfunction addSkills(\n skillMap: Map<string, MikanSkill>,\n skills: MikanSkill[],\n rewritePath: (path: string) => string,\n): void {\n for (const skill of skills) {\n skill.filePath = rewritePath(skill.filePath);\n skill.baseDir = rewritePath(skill.baseDir);\n skillMap.set(skill.name, skill);\n }\n}\n\n/** Conversation skill entries that are symlinks are refused, and reported to the prompt. */\nfunction skippedSymlinkPaths(\n diagnostics: SkillDiagnostic[],\n translatePath: (path: string) => string,\n): string[] {\n const skipped: string[] = [];\n for (const diagnostic of diagnostics) {\n if (diagnostic.code !== \"symlink\") continue;\n log.logWarning(\"Skipping conversation skill entry (symlink)\", diagnostic.path);\n skipped.push(translatePath(diagnostic.path));\n }\n return skipped;\n}\n\nexport function loadMikanSkills(\n office: Office,\n workspacePath: string,\n projection: WorkspaceProjection,\n): { skills: MikanSkill[]; skippedSkillLinks: string[] } {\n const skillMap = new Map<string, MikanSkill>();\n\n // workspacePath is the runtime-side root (e.g. /workspace); host paths under\n // the workspace root translate onto it for prompt references.\n const hostWorkspacePath = office.workspace.root;\n const translatePath = (hostPath: string): string =>\n hostPath.startsWith(hostWorkspacePath)\n ? workspacePath + hostPath.slice(hostWorkspacePath.length)\n : hostPath;\n\n const workspaceSkillsDir = projection.promptSources.globalSkillsDir;\n if (workspaceSkillsDir) {\n const loaded = loadSkillsFromDir({ dir: workspaceSkillsDir, source: \"workspace\" });\n addSkills(skillMap, loaded.skills, translatePath);\n }\n\n const conversationSkills = loadSkillsFromDir({\n dir: projection.promptSources.conversationSkillsDir,\n source: \"channel\",\n rejectSymlinks: true,\n });\n const skippedSkillLinks = skippedSymlinkPaths(conversationSkills.diagnostics, translatePath);\n addSkills(skillMap, conversationSkills.skills, translatePath);\n\n return { skills: Array.from(skillMap.values()), skippedSkillLinks };\n}\nexport type { LoadSkillsResult } from \"./types.js\";\nexport type { MikanSkill } from \"./types.js\";\nexport type { SkillDiagnostic } from \"./types.js\";\n\nconst MAX_NAME_LENGTH = 64;\n\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\ninterface Frontmatter {\n values: Record<string, string>;\n body: string;\n}\n\n/**\n * Parse simple `key: value` YAML frontmatter delimited by `---` lines.\n * Quoted values are unquoted; nested structures are not supported.\n */\nexport function parseFrontmatter(content: string): Frontmatter {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/);\n if (!match) return { values: {}, body: content };\n\n const values: Record<string, string> = {};\n for (const line of (match[1] ?? \"\").split(/\\r?\\n/)) {\n const separator = line.indexOf(\":\");\n if (separator === -1) continue;\n const key = line.slice(0, separator).trim();\n if (!key) continue;\n let value = line.slice(separator + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n values[key] = value;\n }\n return { values, body: content.slice(match[0].length) };\n}\n\nfunction validateSkill(name: string, description: string): string[] {\n const errors: string[] = [];\n if (name.length > MAX_NAME_LENGTH) {\n errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n }\n if (\n !/^[a-z0-9-]+$/.test(name) ||\n name.startsWith(\"-\") ||\n name.endsWith(\"-\") ||\n name.includes(\"--\")\n ) {\n errors.push(\"name must be lowercase a-z, 0-9 and single hyphens, not at the edges\");\n }\n if (description.length > MAX_DESCRIPTION_LENGTH) {\n errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n }\n return errors;\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): LoadSkillsResult {\n const diagnostics: SkillDiagnostic[] = [];\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const { values, body } = parseFrontmatter(raw);\n const skillDir = dirname(filePath);\n const name = values.name || basename(skillDir);\n const description = values.description ?? \"\";\n\n if (!description.trim()) {\n diagnostics.push({ type: \"warning\", message: \"description is required\", path: filePath });\n return { skills: [], diagnostics };\n }\n for (const error of validateSkill(name, description)) {\n diagnostics.push({ type: \"warning\", message: error, path: filePath });\n }\n\n return {\n skills: [\n {\n name,\n description,\n content: body.trim(),\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: values[\"disable-model-invocation\"] === \"true\",\n },\n ],\n diagnostics,\n };\n } catch (error) {\n diagnostics.push({\n type: \"warning\",\n message: error instanceof Error ? error.message : \"failed to parse skill file\",\n path: filePath,\n });\n return { skills: [], diagnostics };\n }\n}\n\n/**\n * Load skills from a directory tree.\n * - A directory containing `SKILL.md` is a skill root; no further recursion.\n * - Direct `.md` children of the top-level directory load as skills.\n * - Dot-directories and `node_modules` are skipped.\n */\nexport function loadSkillsFromDir(options: {\n dir: string;\n source: string;\n /**\n * Refuse to follow symlinks on any path this load would read, skipping the\n * offending entry with a `code: \"symlink\"` diagnostic instead of loading\n * it. For untrusted trees (conversation offices) the host must never\n * follow an agent-created link; entries the loader never reads — dot\n * directories, vendored node_modules — cannot disqualify anything.\n */\n rejectSymlinks?: boolean;\n}): LoadSkillsResult {\n const rejectSymlinks = options.rejectSymlinks === true;\n if (rejectSymlinks && isSymlink(options.dir)) {\n return {\n skills: [],\n diagnostics: [\n {\n type: \"warning\",\n code: \"symlink\",\n message: \"Skills directory is a symlink; skipped\",\n path: options.dir,\n },\n ],\n };\n }\n return loadSkillsFromDirInternal(options.dir, options.source, true, rejectSymlinks);\n}\n\nfunction isSymlink(path: string): boolean {\n try {\n return lstatSync(path).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nfunction symlinkDiagnostic(path: string): SkillDiagnostic {\n return {\n type: \"warning\",\n code: \"symlink\",\n message: \"Skill entry is a symlink; skipped\",\n path,\n };\n}\n\nfunction loadSkillsFromDirInternal(\n dir: string,\n source: string,\n includeRootFiles: boolean,\n rejectSymlinks: boolean,\n): LoadSkillsResult {\n const skills: MikanSkill[] = [];\n const diagnostics: SkillDiagnostic[] = [];\n if (!existsSync(dir)) return { skills, diagnostics };\n\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return { skills, diagnostics };\n }\n\n const skillFile = entries.find((entry) => entry.name === \"SKILL.md\" && isFileLike(dir, entry));\n if (skillFile) {\n if (rejectSymlinks && skillFile.isSymbolicLink()) {\n diagnostics.push(symlinkDiagnostic(join(dir, skillFile.name)));\n return { skills, diagnostics };\n }\n return loadSkillFromFile(join(dir, skillFile.name), source);\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const fullPath = join(dir, entry.name);\n\n const directory = isDirectoryLike(dir, entry);\n if (!directory && !(includeRootFiles && entry.name.endsWith(\".md\") && isFileLike(dir, entry)))\n continue;\n if (rejectSymlinks && entry.isSymbolicLink()) {\n diagnostics.push(symlinkDiagnostic(fullPath));\n continue;\n }\n const result = directory\n ? loadSkillsFromDirInternal(fullPath, source, false, rejectSymlinks)\n : loadSkillFromFile(fullPath, source);\n skills.push(...result.skills);\n diagnostics.push(...result.diagnostics);\n }\n return { skills, diagnostics };\n}\n\nfunction isFileLike(\n dir: string,\n entry: { name: string; isFile(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isFile()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isFile();\n } catch {\n return false;\n }\n}\n\nfunction isDirectoryLike(\n dir: string,\n entry: { name: string; isDirectory(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isDirectory()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Format skills for a system prompt using the Agent Skills XML block.\n * Skills with `disableModelInvocation` are excluded.\n */\nexport function formatSkillsForPrompt(skills: MikanSkill[]): string {\n const visible = skills.filter((skill) => !skill.disableModelInvocation);\n if (visible.length === 0) return \"\";\n\n const lines = [\n \"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n \"Use the read tool to load a skill's file when the task matches its description.\",\n \"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n \"\",\n \"<available_skills>\",\n ];\n for (const skill of visible) {\n lines.push(\" <skill>\");\n lines.push(` <name>${escapeXml(skill.name)}</name>`);\n lines.push(` <description>${escapeXml(skill.description)}</description>`);\n if (skill.inline) {\n // Inline skills carry their body: the agent cannot read their file.\n lines.push(` <instructions>${escapeXml(skill.content)}</instructions>`);\n } else {\n lines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n }\n lines.push(\" </skill>\");\n }\n lines.push(\"</available_skills>\");\n return lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Office } from \"../office/index.js\";\nimport type { MikanSkill, SkillDiagnostic, LoadSkillsResult } from \"./types.js\";\nimport type { WorkspaceProjection } from \"../office/types.js\";\nimport { existsSync, lstatSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\n\nimport * as log from \"../log.js\";\n\n/** Register skills under their prompt-side paths; a later source overrides an earlier one. */\nfunction addSkills(\n skillMap: Map<string, MikanSkill>,\n skills: MikanSkill[],\n rewritePath: (path: string) => string,\n): void {\n for (const skill of skills) {\n skill.filePath = rewritePath(skill.filePath);\n skill.baseDir = rewritePath(skill.baseDir);\n skillMap.set(skill.name, skill);\n }\n}\n\n/** Conversation skill entries that are symlinks are refused, and reported to the prompt. */\nfunction skippedSymlinkPaths(\n diagnostics: SkillDiagnostic[],\n translatePath: (path: string) => string,\n): string[] {\n const skipped: string[] = [];\n for (const diagnostic of diagnostics) {\n if (diagnostic.code !== \"symlink\") continue;\n log.logWarning(\"Skipping conversation skill entry (symlink)\", diagnostic.path);\n skipped.push(translatePath(diagnostic.path));\n }\n return skipped;\n}\n\nexport function loadMikanSkills(\n office: Office,\n workspacePath: string,\n projection: WorkspaceProjection,\n): { skills: MikanSkill[]; skippedSkillLinks: string[] } {\n const skillMap = new Map<string, MikanSkill>();\n\n // workspacePath is the runtime-side root (e.g. /workspace); host paths under\n // the workspace root translate onto it for prompt references.\n const hostWorkspacePath = office.workspace.root;\n const translatePath = (hostPath: string): string =>\n hostPath.startsWith(hostWorkspacePath)\n ? workspacePath + hostPath.slice(hostWorkspacePath.length)\n : hostPath;\n\n const workspaceSkillsDir = projection.promptSources.globalSkillsDir;\n if (workspaceSkillsDir) {\n const loaded = loadSkillsFromDir({ dir: workspaceSkillsDir, source: \"workspace\" });\n addSkills(skillMap, loaded.skills, translatePath);\n }\n\n const conversationSkills = loadSkillsFromDir({\n dir: projection.promptSources.conversationSkillsDir,\n source: \"channel\",\n rejectSymlinks: true,\n });\n const skippedSkillLinks = skippedSymlinkPaths(conversationSkills.diagnostics, translatePath);\n addSkills(skillMap, conversationSkills.skills, translatePath);\n\n return { skills: Array.from(skillMap.values()), skippedSkillLinks };\n}\nexport type { LoadSkillsResult } from \"./types.js\";\nexport type { MikanSkill } from \"./types.js\";\nexport type { SkillDiagnostic } from \"./types.js\";\n\nconst MAX_NAME_LENGTH = 64;\n\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\ninterface Frontmatter {\n values: Record<string, string>;\n body: string;\n}\n\n/**\n * Parse simple `key: value` YAML frontmatter delimited by `---` lines.\n * Quoted values are unquoted; nested structures are not supported.\n */\nexport function parseFrontmatter(content: string): Frontmatter {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/);\n if (!match) return { values: {}, body: content };\n\n const values: Record<string, string> = {};\n for (const line of (match[1] ?? \"\").split(/\\r?\\n/)) {\n const separator = line.indexOf(\":\");\n if (separator === -1) continue;\n const key = line.slice(0, separator).trim();\n if (!key) continue;\n let value = line.slice(separator + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n values[key] = value;\n }\n return { values, body: content.slice(match[0].length) };\n}\n\n/** Exposed so the admin portal can validate a skill draft before writing it. */\nexport function validateSkill(name: string, description: string): string[] {\n const errors: string[] = [];\n if (name.length > MAX_NAME_LENGTH) {\n errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n }\n if (\n !/^[a-z0-9-]+$/.test(name) ||\n name.startsWith(\"-\") ||\n name.endsWith(\"-\") ||\n name.includes(\"--\")\n ) {\n errors.push(\"name must be lowercase a-z, 0-9 and single hyphens, not at the edges\");\n }\n if (description.length > MAX_DESCRIPTION_LENGTH) {\n errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n }\n return errors;\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): LoadSkillsResult {\n const diagnostics: SkillDiagnostic[] = [];\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const { values, body } = parseFrontmatter(raw);\n const skillDir = dirname(filePath);\n const name = values.name || basename(skillDir);\n const description = values.description ?? \"\";\n\n if (!description.trim()) {\n diagnostics.push({ type: \"warning\", message: \"description is required\", path: filePath });\n return { skills: [], diagnostics };\n }\n for (const error of validateSkill(name, description)) {\n diagnostics.push({ type: \"warning\", message: error, path: filePath });\n }\n\n return {\n skills: [\n {\n name,\n description,\n content: body.trim(),\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: values[\"disable-model-invocation\"] === \"true\",\n },\n ],\n diagnostics,\n };\n } catch (error) {\n diagnostics.push({\n type: \"warning\",\n message: error instanceof Error ? error.message : \"failed to parse skill file\",\n path: filePath,\n });\n return { skills: [], diagnostics };\n }\n}\n\n/**\n * Load skills from a directory tree.\n * - A directory containing `SKILL.md` is a skill root; no further recursion.\n * - Direct `.md` children of the top-level directory load as skills.\n * - Dot-directories and `node_modules` are skipped.\n */\nexport function loadSkillsFromDir(options: {\n dir: string;\n source: string;\n /**\n * Refuse to follow symlinks on any path this load would read, skipping the\n * offending entry with a `code: \"symlink\"` diagnostic instead of loading\n * it. For untrusted trees (conversation offices) the host must never\n * follow an agent-created link; entries the loader never reads — dot\n * directories, vendored node_modules — cannot disqualify anything.\n */\n rejectSymlinks?: boolean;\n}): LoadSkillsResult {\n const rejectSymlinks = options.rejectSymlinks === true;\n if (rejectSymlinks && isSymlink(options.dir)) {\n return {\n skills: [],\n diagnostics: [\n {\n type: \"warning\",\n code: \"symlink\",\n message: \"Skills directory is a symlink; skipped\",\n path: options.dir,\n },\n ],\n };\n }\n return loadSkillsFromDirInternal(options.dir, options.source, true, rejectSymlinks);\n}\n\nfunction isSymlink(path: string): boolean {\n try {\n return lstatSync(path).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nfunction symlinkDiagnostic(path: string): SkillDiagnostic {\n return {\n type: \"warning\",\n code: \"symlink\",\n message: \"Skill entry is a symlink; skipped\",\n path,\n };\n}\n\nfunction loadSkillsFromDirInternal(\n dir: string,\n source: string,\n includeRootFiles: boolean,\n rejectSymlinks: boolean,\n): LoadSkillsResult {\n const skills: MikanSkill[] = [];\n const diagnostics: SkillDiagnostic[] = [];\n if (!existsSync(dir)) return { skills, diagnostics };\n\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return { skills, diagnostics };\n }\n\n const skillFile = entries.find((entry) => entry.name === \"SKILL.md\" && isFileLike(dir, entry));\n if (skillFile) {\n if (rejectSymlinks && skillFile.isSymbolicLink()) {\n diagnostics.push(symlinkDiagnostic(join(dir, skillFile.name)));\n return { skills, diagnostics };\n }\n return loadSkillFromFile(join(dir, skillFile.name), source);\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const fullPath = join(dir, entry.name);\n\n const directory = isDirectoryLike(dir, entry);\n if (!directory && !(includeRootFiles && entry.name.endsWith(\".md\") && isFileLike(dir, entry)))\n continue;\n if (rejectSymlinks && entry.isSymbolicLink()) {\n diagnostics.push(symlinkDiagnostic(fullPath));\n continue;\n }\n const result = directory\n ? loadSkillsFromDirInternal(fullPath, source, false, rejectSymlinks)\n : loadSkillFromFile(fullPath, source);\n skills.push(...result.skills);\n diagnostics.push(...result.diagnostics);\n }\n return { skills, diagnostics };\n}\n\nfunction isFileLike(\n dir: string,\n entry: { name: string; isFile(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isFile()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isFile();\n } catch {\n return false;\n }\n}\n\nfunction isDirectoryLike(\n dir: string,\n entry: { name: string; isDirectory(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isDirectory()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Format skills for a system prompt using the Agent Skills XML block.\n * Skills with `disableModelInvocation` are excluded.\n */\nexport function formatSkillsForPrompt(skills: MikanSkill[]): string {\n const visible = skills.filter((skill) => !skill.disableModelInvocation);\n if (visible.length === 0) return \"\";\n\n const lines = [\n \"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n \"Use the read tool to load a skill's file when the task matches its description.\",\n \"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n \"\",\n \"<available_skills>\",\n ];\n for (const skill of visible) {\n lines.push(\" <skill>\");\n lines.push(` <name>${escapeXml(skill.name)}</name>`);\n lines.push(` <description>${escapeXml(skill.description)}</description>`);\n if (skill.inline) {\n // Inline skills carry their body: the agent cannot read their file.\n lines.push(` <instructions>${escapeXml(skill.content)}</instructions>`);\n } else {\n lines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n }\n lines.push(\" </skill>\");\n }\n lines.push(\"</available_skills>\");\n return lines.join(\"\\n\");\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geminixiang/mikan",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.73",
|
|
4
4
|
"description": "Self-hosted AI coding agent for organizations: every Slack channel and DM gets its own sandboxed workspace, credentials, and memory.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|