@geminixiang/mikan 1.0.0-beta.18 → 1.0.0-beta.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/CHANGELOG.md +20 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +62 -4
- package/dist/agent.js.map +1 -1
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +8 -0
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +14 -1
- package/dist/harness/extensions/types.d.ts.map +1 -1
- package/dist/harness/extensions/types.js.map +1 -1
- package/dist/harness/index.d.ts +2 -2
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/runner.d.ts +8 -0
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +16 -5
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session-store.d.ts +4 -1
- package/dist/harness/session-store.d.ts.map +1 -1
- package/dist/harness/session-store.js +11 -2
- package/dist/harness/session-store.js.map +1 -1
- package/dist/harness/subagent-runner.d.ts +17 -0
- package/dist/harness/subagent-runner.d.ts.map +1 -0
- package/dist/harness/subagent-runner.js +216 -0
- package/dist/harness/subagent-runner.js.map +1 -0
- package/dist/harness/types.d.ts +53 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/subagent.d.ts +69 -0
- package/dist/tools/subagent.d.ts.map +1 -0
- package/dist/tools/subagent.js +286 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/vault/index.js +0 -3
- package/dist/vault/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/harness/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension discovery and activation.\n *\n * Extension modules execute inside the mikan host process with its full\n * privileges (platform tokens, vault, host filesystem). They must therefore\n * only ever load from host-controlled directories: installing an extension\n * is an administrator action. In particular, extension directories must not\n * live under paths mounted into sandbox containers (workspace and\n * conversation dirs in image mode), or code written from inside the sandbox\n * would be imported into the host process — a sandbox escape.\n * {@link defaultExtensionDirs} returns the canonical host-only locations\n * under mikan's state dir.\n *\n * Directories are scanned in order; all discovered extensions activate.\n * Accepted layouts (entrypoint may be .mjs/.js/.ts/.mts — loaded via jiti):\n *\n * - `extensions/<name>.<ext>` (bare file)\n * - `extensions/<name>/index.<ext>` (directory + index)\n * - `extensions/<name>/package.json` (mikan.extensions entrypoint;\n * may carry npm dependencies in node_modules)\n *\n * Modules are imported with a fresh jiti instance (no cache) so edited\n * extensions are picked up when a new harness instance is created.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join } from \"path\";\nimport { createJiti } from \"jiti\";\nimport type { AgentTool, ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport * as log from \"../../log.js\";\nimport { loadSkillsFromDir, type MikanSkill } from \"../skills.js\";\nimport { ExtensionRegistry } from \"./registry.js\";\nimport type {\n ExtensionCommand,\n ExtensionDisposer,\n ExtensionHostServices,\n ExtensionLoadError,\n ExtensionManifest,\n ExtensionSchedulePayload,\n ExtensionScheduleInfo,\n ExtensionScheduleSpec,\n LoadedExtension,\n MikanExtensionActivate,\n MikanExtensionApi,\n MikanExtensionModule,\n} from \"./types.js\";\n\nconst EXTENSION_FILE_PATTERN = /\\.(mjs|js|ts|mts)$/;\nconst INDEX_FILE_PATTERN = /^index\\.(mjs|js|ts|mts)$/;\nconst INDEX_CANDIDATES = [\"index.mjs\", \"index.js\", \"index.ts\", \"index.mts\"];\n\n/**\n * Import an extension entrypoint through jiti so it can be TypeScript and can\n * use node_modules dependencies, transparently compiling on the fly. A fresh\n * jiti instance with caching disabled is used per load so edited extensions\n * are picked up when a new harness instance is created for a conversation.\n */\nasync function importExtensionModule(entrypoint: string): Promise<unknown> {\n const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });\n return jiti.import(entrypoint);\n}\n\n/**\n * Canonical host-only extension code directories for a conversation, in load\n * order: `<stateDir>/global/extensions` (all conversations) then\n * `<stateDir>/conversations/<conversationId>/extensions` (that conversation\n * only). `global` and `conversations` are the two sibling scopes; see\n * `LAYOUT.md`. Conversation ids are used verbatim (see LAYOUT.md § Casing).\n */\nexport function defaultExtensionDirs(\n conversationId: string,\n stateDir: string = join(homedir(), \".mikan\"),\n): string[] {\n return [\n join(stateDir, \"global\", \"extensions\"),\n join(stateDir, \"conversations\", conversationId, \"extensions\"),\n ];\n}\n\n/** Discovery-only view of an installed extension (module is not imported). */\nexport interface InstalledExtensionInfo {\n /** Display name: manifest name, falling back to the slug. */\n name: string;\n slug: string;\n path: string;\n /** Scan directory the extension was found in. */\n dir: string;\n version?: string;\n description?: string;\n /** Names of skills shipped in the extension's skills/ directory. */\n skillNames: string[];\n}\n\n/**\n * List installed extensions without importing or activating them — safe for\n * inventory surfaces (commands, portal). Activation side effects (schedule\n * upserts, tool registration) only happen in {@link loadExtensions}.\n */\nexport function listInstalledExtensions(dirs: string[]): InstalledExtensionInfo[] {\n const infos: InstalledExtensionInfo[] = [];\n for (const dir of dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n infos.push({\n name: manifest.name ?? slug,\n slug,\n path: entrypoint,\n dir,\n version: manifest.version,\n description: manifest.description,\n skillNames: loadExtensionSkills(rootDir, slug).map((skill) => skill.name),\n });\n }\n }\n return infos;\n}\n\nexport interface LoadExtensionsOptions {\n /** Directories to scan for extensions. Missing directories are skipped. */\n dirs: string[];\n context: {\n conversationId: string;\n workspaceDir: string;\n model: Model<Api>;\n thinkingLevel: ThinkingLevel;\n };\n /** Embedder-provided services backing the v2 api surface. */\n services?: ExtensionHostServices;\n}\n\nexport interface LoadExtensionsResult {\n registry: ExtensionRegistry;\n extensions: LoadedExtension[];\n errors: ExtensionLoadError[];\n /** Skills contributed by extensions (inline: bodies ride in the prompt). */\n skills: MikanSkill[];\n /**\n * Run extension disposers (from `api.onDispose` and `activate` return\n * values). Call when the harness instance owning these extensions is\n * discarded. Idempotent; disposer errors are logged, never thrown.\n */\n dispose(): Promise<void>;\n}\n\n/**\n * A discovered extension: its entrypoint (module to import) and root dir\n * (used for slug, manifest.json, and skills/ — which sit at the extension\n * root, not necessarily next to a nested entrypoint).\n */\ninterface DiscoveredExtension {\n entrypoint: string;\n rootDir: string;\n}\n\nfunction discoverExtensionEntrypoints(dir: string): DiscoveredExtension[] {\n if (!existsSync(dir)) return [];\n const found: DiscoveredExtension[] = [];\n for (const name of readdirSync(dir).toSorted()) {\n if (name.startsWith(\".\")) continue;\n if (INDEX_FILE_PATTERN.test(name)) {\n // An index file at the scan root means the extension's contents were\n // copied into the scope directory itself; the slug would degenerate to\n // the scope name (e.g. the conversation id), mis-keying its data dir,\n // secrets, and schedules. Require a named form instead.\n log.logWarning(\n `Ignoring extension index file at scope root: ${join(dir, name)}`,\n \"install into a named subdirectory (e.g. extensions/<scope>/my-ext/index.mjs)\",\n );\n continue;\n }\n const fullPath = join(dir, name);\n let stats;\n try {\n stats = statSync(fullPath);\n } catch {\n continue;\n }\n if (stats.isFile() && EXTENSION_FILE_PATTERN.test(name)) {\n // Bare-file form: the file is both entrypoint and (its own) root.\n found.push({ entrypoint: fullPath, rootDir: fullPath });\n continue;\n }\n if (stats.isDirectory()) {\n const entrypoint = resolveDirectoryEntrypoint(fullPath);\n if (entrypoint) found.push({ entrypoint, rootDir: fullPath });\n }\n }\n return found;\n}\n\n/**\n * Resolve a directory-form extension's entrypoint. A `package.json` with a\n * `mikan.extensions` array (first entry, relative to the dir) wins — this is\n * how an extension declares a TypeScript entry and pulls in npm dependencies.\n * Otherwise fall back to an `index.{mjs,js,ts,mts}` file. Returns undefined\n * when neither is present.\n */\nfunction resolveDirectoryEntrypoint(dir: string): string | undefined {\n const declared = readMikanManifestEntrypoints(dir)[0];\n if (declared) {\n const resolved = join(dir, declared);\n if (existsSync(resolved)) return resolved;\n log.logWarning(\n `Extension package.json declares a missing entrypoint: ${resolved}`,\n \"falling back to an index file\",\n );\n }\n for (const candidate of INDEX_CANDIDATES) {\n const indexPath = join(dir, candidate);\n if (existsSync(indexPath)) return indexPath;\n }\n return undefined;\n}\n\ninterface ExtensionPackageJson {\n name?: string;\n version?: string;\n description?: string;\n mikan?: { extensions?: string[]; displayName?: string };\n}\n\n/** Read and shape a directory's package.json; undefined when absent/malformed. */\nfunction readPackageJson(dir: string): ExtensionPackageJson | undefined {\n const packageJsonPath = join(dir, \"package.json\");\n if (!existsSync(packageJsonPath)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as unknown;\n if (!parsed || typeof parsed !== \"object\") return undefined;\n const record = parsed as Record<string, unknown>;\n const mikanRaw = record.mikan as { extensions?: unknown; displayName?: unknown } | undefined;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n mikan: {\n extensions: Array.isArray(mikanRaw?.extensions)\n ? mikanRaw.extensions.filter((entry): entry is string => typeof entry === \"string\")\n : undefined,\n displayName: typeof mikanRaw?.displayName === \"string\" ? mikanRaw.displayName : undefined,\n },\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed package.json: ${packageJsonPath}`, String(err));\n return undefined;\n }\n}\n\n/** Read the `mikan.extensions` entrypoint list from a directory's package.json. */\nfunction readMikanManifestEntrypoints(dir: string): string[] {\n return readPackageJson(dir)?.mikan?.extensions ?? [];\n}\n\nfunction sanitizeSlug(base: string): string {\n const slug = base\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n return slug || \"extension\";\n}\n\n/**\n * Filesystem-safe identifier for an extension, derived from its install\n * location: the directory name for a directory-form extension, or the file\n * basename for a bare file. The slug keys the extension's data dir, secrets\n * vault, and schedule ownership — installing the same extension globally and\n * per-conversation shares one slug and therefore one shared data dir.\n */\nexport function extensionSlug(entrypoint: string): string {\n // Bare-file form (rootDir === entrypoint, a *.mjs/.ts file) → file basename.\n // Directory form → directory name. Detect the directory form structurally:\n // an entrypoint whose parent holds a package.json or is an index file.\n if (INDEX_FILE_PATTERN.test(basename(entrypoint))) {\n return sanitizeSlug(basename(dirname(entrypoint)));\n }\n return sanitizeSlug(basename(entrypoint).replace(EXTENSION_FILE_PATTERN, \"\"));\n}\n\n/** Slug from a discovered extension's root dir (directory or bare file path). */\nfunction slugForRoot(rootDir: string): string {\n return EXTENSION_FILE_PATTERN.test(basename(rootDir))\n ? sanitizeSlug(basename(rootDir).replace(EXTENSION_FILE_PATTERN, \"\"))\n : sanitizeSlug(basename(rootDir));\n}\n\n/** Sanitize an extension-chosen schedule name into a filename segment. */\nfunction scheduleNameSegment(name: string): string {\n const segment = name\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n if (!segment) throw new Error(`Invalid schedule name: ${JSON.stringify(name)}`);\n return segment;\n}\n\n/**\n * Read display metadata (name/version/description) for a directory-form\n * extension. `package.json` is the primary source — its standard `name`,\n * `version`, `description`, plus an optional `mikan.displayName` that\n * overrides the npm name for the user-facing label (npm names are\n * lowercase/scoped; display names can be arbitrary). A `manifest.json` is a\n * fallback for extensions that ship no package.json.\n */\nfunction readManifest(rootDir: string): ExtensionManifest {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) have no manifest.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return {};\n\n const pkg = readPackageJson(rootDir);\n if (pkg && (pkg.mikan?.displayName ?? pkg.name ?? pkg.version ?? pkg.description)) {\n return {\n name: pkg.mikan?.displayName ?? pkg.name,\n version: pkg.version,\n description: pkg.description,\n };\n }\n\n const manifestPath = join(rootDir, \"manifest.json\");\n if (!existsSync(manifestPath)) return {};\n try {\n const parsed: unknown = JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n if (!parsed || typeof parsed !== \"object\") return {};\n const record = parsed as Record<string, unknown>;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed extension manifest: ${manifestPath}`, String(err));\n return {};\n }\n}\n\n/**\n * Skills shipped inside a directory-form extension (`<dir>/skills/`).\n * Marked inline: extension files live under the host-only state dir, which\n * sandbox containers cannot read, so skill bodies must ride in the prompt.\n */\nfunction loadExtensionSkills(rootDir: string, slug: string): MikanSkill[] {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) ship no skills.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return [];\n const skillsDir = join(rootDir, \"skills\");\n if (!existsSync(skillsDir)) return [];\n const result = loadSkillsFromDir({ dir: skillsDir, source: `extension:${slug}` });\n for (const diagnostic of result.diagnostics) {\n log.logWarning(`Extension skill warning (${slug}): ${diagnostic.message}`, diagnostic.path);\n }\n for (const skill of result.skills) skill.inline = true;\n return result.skills;\n}\n\nconst SCHEDULE_FILE_SUFFIX = \".json\";\n\nfunction schedulePrefix(slug: string, conversationId: string): string {\n return `ext.${slug}.${scheduleNameSegment(conversationId)}.`;\n}\n\nfunction payloadFromSpec(\n spec: ExtensionScheduleSpec,\n conversationId: string,\n): ExtensionSchedulePayload {\n if (spec.type === \"periodic\") {\n if (!spec.schedule || !spec.timezone) {\n throw new Error(\"periodic schedule requires schedule and timezone\");\n }\n return {\n type: \"periodic\",\n conversationId,\n text: spec.text,\n schedule: spec.schedule,\n timezone: spec.timezone,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n }\n if (!spec.at) throw new Error(\"one-shot schedule requires at\");\n return {\n type: \"one-shot\",\n conversationId,\n text: spec.text,\n at: spec.at,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n}\n\nfunction specFromPayload(payload: ExtensionSchedulePayload): ExtensionScheduleSpec {\n if (payload.type === \"periodic\") {\n return {\n type: \"periodic\",\n schedule: payload.schedule ?? \"\",\n timezone: payload.timezone ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n }\n return {\n type: \"one-shot\",\n at: payload.at ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n}\n\n/** Build the v2 api surface for one extension over the injected services. */\nfunction buildExtensionApi(params: {\n name: string;\n slug: string;\n registry: ExtensionRegistry;\n context: LoadExtensionsOptions[\"context\"];\n services: ExtensionHostServices;\n}): MikanExtensionApi {\n const { name, slug, registry, context, services } = params;\n const stateDir = services.stateDir ?? join(homedir(), \".mikan\");\n const conversationId = context.conversationId;\n\n const requireScheduleStore = () => {\n if (!services.scheduleStore) {\n throw new Error(\"api.schedules is unavailable: this context provides no schedule store\");\n }\n return services.scheduleStore;\n };\n\n return {\n on: (hook, handler) => registry.register(name, hook, handler),\n registerTool: (tool: AgentTool) => registry.registerTool(tool),\n registerCommand: (command: ExtensionCommand) => registry.registerCommand(name, command),\n onDispose: (disposer: ExtensionDisposer) => registry.registerDisposer(name, disposer),\n log: (message: string) => log.logInfo(`[extension:${name}] ${message}`),\n context,\n paths: {\n get dataDir(): string {\n // This conversation's own data, co-located with the conversation's\n // other host-only assets; removed when the conversation is deleted.\n const dir = join(stateDir, \"conversations\", conversationId, \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n get sharedDataDir(): string {\n // Cross-conversation data under the sibling `global` scope.\n const dir = join(stateDir, \"global\", \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n },\n secrets: {\n get: (key: string) => services.resolveSecrets?.(slug)[key],\n list: () => Object.keys(services.resolveSecrets?.(slug) ?? {}),\n },\n schedules: {\n upsert: async (scheduleName, spec) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n await store.write(filename, payloadFromSpec(spec, conversationId));\n },\n delete: async (scheduleName) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n return store.delete(filename);\n },\n list: async () => {\n const store = requireScheduleStore();\n const prefix = schedulePrefix(slug, conversationId);\n const infos: ExtensionScheduleInfo[] = [];\n for (const entry of await store.list()) {\n if (!entry.filename.startsWith(prefix)) continue;\n if (!entry.filename.endsWith(SCHEDULE_FILE_SUFFIX)) continue;\n infos.push({\n name: entry.filename.slice(prefix.length, -SCHEDULE_FILE_SUFFIX.length),\n spec: specFromPayload(entry.payload),\n });\n }\n return infos;\n },\n },\n notify: async (text: string, options?: { conversationId?: string }) => {\n if (!services.postMessage) {\n throw new Error(\"api.notify is unavailable: this context provides no platform messaging\");\n }\n await services.postMessage(options?.conversationId ?? conversationId, text);\n },\n react: async (messageTs: string, emoji: string) => {\n if (!services.addReaction) {\n throw new Error(\"api.react is unavailable: this context provides no reaction support\");\n }\n await services.addReaction(conversationId, messageTs, emoji);\n },\n uploadFile: async (filePath: string, title?: string) => {\n if (!services.uploadFile) {\n throw new Error(\"api.uploadFile is unavailable: this context provides no file uploads\");\n }\n await services.uploadFile(conversationId, filePath, title);\n },\n triggerRun: async (text: string) => {\n const store = requireScheduleStore();\n // Distinct \"extrun.\" namespace: run files must never surface in\n // api.schedules.list(), whose ownership filter is the \"ext.\" prefix.\n // The embedder's watcher fires and deletes the file immediately.\n const filename = `extrun.${slug}.${scheduleNameSegment(conversationId)}.${Date.now()}-${runCounter++}${SCHEDULE_FILE_SUFFIX}`;\n await store.write(filename, { type: \"immediate\", conversationId, text });\n },\n };\n}\n\n/** Monotonic suffix so rapid triggerRun calls in one process never collide. */\nlet runCounter = 0;\n\nfunction resolveActivate(moduleExports: unknown): MikanExtensionModule | undefined {\n if (!moduleExports || typeof moduleExports !== \"object\") return undefined;\n const candidates: unknown[] = [(moduleExports as { default?: unknown }).default, moduleExports];\n for (const candidate of candidates) {\n if (typeof candidate === \"function\") {\n return { activate: candidate as MikanExtensionActivate };\n }\n if (candidate && typeof candidate === \"object\") {\n const activate = (candidate as { activate?: unknown }).activate;\n if (typeof activate === \"function\") {\n return {\n name:\n typeof (candidate as { name?: unknown }).name === \"string\"\n ? (candidate as { name: string }).name\n : undefined,\n activate: activate as MikanExtensionActivate,\n };\n }\n }\n }\n return undefined;\n}\n\n/** Load and activate all extensions found in the given directories. */\nexport async function loadExtensions(\n options: LoadExtensionsOptions,\n): Promise<LoadExtensionsResult> {\n const registry = new ExtensionRegistry();\n const extensions: LoadedExtension[] = [];\n const errors: ExtensionLoadError[] = [];\n const skills: MikanSkill[] = [];\n const services = options.services ?? {};\n\n for (const dir of options.dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n const extension = resolveActivate(moduleExports);\n if (!extension) {\n errors.push({\n path: entrypoint,\n error: \"extension must export an activate function (default or named)\",\n });\n continue;\n }\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const name = manifest.name ?? extension.name ?? slug;\n const api = buildExtensionApi({\n name,\n slug,\n registry,\n context: options.context,\n services,\n });\n const disposer = await extension.activate(api);\n if (typeof disposer === \"function\") registry.registerDisposer(name, disposer);\n const extensionSkills = loadExtensionSkills(rootDir, slug);\n skills.push(...extensionSkills);\n extensions.push({\n name,\n path: entrypoint,\n slug,\n version: manifest.version,\n description: manifest.description,\n skills: extensionSkills,\n });\n } catch (err) {\n errors.push({\n path: entrypoint,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n return { registry, extensions, errors, skills, dispose: () => registry.dispose() };\n}\n\nexport interface ExtensionValidation {\n ok: boolean;\n /** Slug the extension would install as (from the source dir/file name). */\n slug: string;\n /** Display name (manifest name, else slug). */\n name: string;\n version?: string;\n description?: string;\n /** Resolved entrypoint that would be imported. */\n entrypoint?: string;\n /** Skill names shipped alongside the extension. */\n skillNames: string[];\n errors: string[];\n warnings: string[];\n}\n\n/**\n * Validate an extension source path (a directory or a single file) WITHOUT\n * activating it: resolves the entrypoint (package.json `mikan.extensions`,\n * index file, or the file itself), imports it, and checks it exports an\n * `activate` function. Used by `mikan ext install` as a preflight and by\n * `mikan ext validate`. Importing runs top-level module code but not\n * `activate`, so there are no schedule/tool side effects.\n */\nexport async function validateExtension(sourcePath: string): Promise<ExtensionValidation> {\n const errors: string[] = [];\n const warnings: string[] = [];\n const rootDir = sourcePath.replace(/[/\\\\]+$/, \"\");\n const base = basename(rootDir);\n\n if (INDEX_FILE_PATTERN.test(base)) {\n warnings.push(\n \"Entry is a bare index file; install into a named directory so the slug is stable.\",\n );\n }\n\n let entrypoint: string | undefined;\n if (!existsSync(rootDir)) {\n errors.push(`Path does not exist: ${rootDir}`);\n } else if (statSync(rootDir).isDirectory()) {\n entrypoint = resolveDirectoryEntrypoint(rootDir);\n if (!entrypoint) {\n errors.push(\n \"No entrypoint found: expected package.json with a mikan.extensions entry, or an index.{mjs,js,ts,mts}.\",\n );\n }\n } else if (EXTENSION_FILE_PATTERN.test(base)) {\n entrypoint = rootDir;\n } else {\n errors.push(`Not an extension file (expected .mjs/.js/.ts/.mts): ${rootDir}`);\n }\n\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const skillNames = loadExtensionSkills(rootDir, slug).map((skill) => skill.name);\n\n if (entrypoint) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n if (!resolveActivate(moduleExports)) {\n errors.push(\"Module does not export an activate function (default or named).\");\n }\n } catch (err) {\n errors.push(`Failed to import: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n ok: errors.length === 0,\n slug,\n name: manifest.name ?? slug,\n version: manifest.version,\n description: manifest.description,\n entrypoint,\n skillNames,\n errors,\n warnings,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/harness/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension discovery and activation.\n *\n * Extension modules execute inside the mikan host process with its full\n * privileges (platform tokens, vault, host filesystem). They must therefore\n * only ever load from host-controlled directories: installing an extension\n * is an administrator action. In particular, extension directories must not\n * live under paths mounted into sandbox containers (workspace and\n * conversation dirs in image mode), or code written from inside the sandbox\n * would be imported into the host process — a sandbox escape.\n * {@link defaultExtensionDirs} returns the canonical host-only locations\n * under mikan's state dir.\n *\n * Directories are scanned in order; all discovered extensions activate.\n * Accepted layouts (entrypoint may be .mjs/.js/.ts/.mts — loaded via jiti):\n *\n * - `extensions/<name>.<ext>` (bare file)\n * - `extensions/<name>/index.<ext>` (directory + index)\n * - `extensions/<name>/package.json` (mikan.extensions entrypoint;\n * may carry npm dependencies in node_modules)\n *\n * Modules are imported with a fresh jiti instance (no cache) so edited\n * extensions are picked up when a new harness instance is created.\n */\nimport { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join } from \"path\";\nimport { createJiti } from \"jiti\";\nimport type { AgentTool, ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model } from \"@earendil-works/pi-ai\";\nimport * as log from \"../../log.js\";\nimport { loadSkillsFromDir, type MikanSkill } from \"../skills.js\";\nimport { ExtensionRegistry } from \"./registry.js\";\nimport type {\n ExtensionCommand,\n ExtensionDisposer,\n ExtensionHostServices,\n ExtensionLoadError,\n ExtensionManifest,\n ExtensionSchedulePayload,\n ExtensionScheduleInfo,\n ExtensionScheduleSpec,\n LoadedExtension,\n MikanExtensionActivate,\n MikanExtensionApi,\n MikanExtensionModule,\n} from \"./types.js\";\n\nconst EXTENSION_FILE_PATTERN = /\\.(mjs|js|ts|mts)$/;\nconst INDEX_FILE_PATTERN = /^index\\.(mjs|js|ts|mts)$/;\nconst INDEX_CANDIDATES = [\"index.mjs\", \"index.js\", \"index.ts\", \"index.mts\"];\n\n/**\n * Import an extension entrypoint through jiti so it can be TypeScript and can\n * use node_modules dependencies, transparently compiling on the fly. A fresh\n * jiti instance with caching disabled is used per load so edited extensions\n * are picked up when a new harness instance is created for a conversation.\n */\nasync function importExtensionModule(entrypoint: string): Promise<unknown> {\n const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });\n return jiti.import(entrypoint);\n}\n\n/**\n * Canonical host-only extension code directories for a conversation, in load\n * order: `<stateDir>/global/extensions` (all conversations) then\n * `<stateDir>/conversations/<conversationId>/extensions` (that conversation\n * only). `global` and `conversations` are the two sibling scopes; see\n * `LAYOUT.md`. Conversation ids are used verbatim (see LAYOUT.md § Casing).\n */\nexport function defaultExtensionDirs(\n conversationId: string,\n stateDir: string = join(homedir(), \".mikan\"),\n): string[] {\n return [\n join(stateDir, \"global\", \"extensions\"),\n join(stateDir, \"conversations\", conversationId, \"extensions\"),\n ];\n}\n\n/** Discovery-only view of an installed extension (module is not imported). */\nexport interface InstalledExtensionInfo {\n /** Display name: manifest name, falling back to the slug. */\n name: string;\n slug: string;\n path: string;\n /** Scan directory the extension was found in. */\n dir: string;\n version?: string;\n description?: string;\n /** Names of skills shipped in the extension's skills/ directory. */\n skillNames: string[];\n}\n\n/**\n * List installed extensions without importing or activating them — safe for\n * inventory surfaces (commands, portal). Activation side effects (schedule\n * upserts, tool registration) only happen in {@link loadExtensions}.\n */\nexport function listInstalledExtensions(dirs: string[]): InstalledExtensionInfo[] {\n const infos: InstalledExtensionInfo[] = [];\n for (const dir of dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n infos.push({\n name: manifest.name ?? slug,\n slug,\n path: entrypoint,\n dir,\n version: manifest.version,\n description: manifest.description,\n skillNames: loadExtensionSkills(rootDir, slug).map((skill) => skill.name),\n });\n }\n }\n return infos;\n}\n\nexport interface LoadExtensionsOptions {\n /** Directories to scan for extensions. Missing directories are skipped. */\n dirs: string[];\n context: {\n conversationId: string;\n workspaceDir: string;\n model: Model<Api>;\n thinkingLevel: ThinkingLevel;\n };\n /** Embedder-provided services backing the v2 api surface. */\n services?: ExtensionHostServices;\n}\n\nexport interface LoadExtensionsResult {\n registry: ExtensionRegistry;\n extensions: LoadedExtension[];\n errors: ExtensionLoadError[];\n /** Skills contributed by extensions (inline: bodies ride in the prompt). */\n skills: MikanSkill[];\n /**\n * Run extension disposers (from `api.onDispose` and `activate` return\n * values). Call when the harness instance owning these extensions is\n * discarded. Idempotent; disposer errors are logged, never thrown.\n */\n dispose(): Promise<void>;\n}\n\n/**\n * A discovered extension: its entrypoint (module to import) and root dir\n * (used for slug, manifest.json, and skills/ — which sit at the extension\n * root, not necessarily next to a nested entrypoint).\n */\ninterface DiscoveredExtension {\n entrypoint: string;\n rootDir: string;\n}\n\nfunction discoverExtensionEntrypoints(dir: string): DiscoveredExtension[] {\n if (!existsSync(dir)) return [];\n const found: DiscoveredExtension[] = [];\n for (const name of readdirSync(dir).toSorted()) {\n if (name.startsWith(\".\")) continue;\n if (INDEX_FILE_PATTERN.test(name)) {\n // An index file at the scan root means the extension's contents were\n // copied into the scope directory itself; the slug would degenerate to\n // the scope name (e.g. the conversation id), mis-keying its data dir,\n // secrets, and schedules. Require a named form instead.\n log.logWarning(\n `Ignoring extension index file at scope root: ${join(dir, name)}`,\n \"install into a named subdirectory (e.g. extensions/<scope>/my-ext/index.mjs)\",\n );\n continue;\n }\n const fullPath = join(dir, name);\n let stats;\n try {\n stats = statSync(fullPath);\n } catch {\n continue;\n }\n if (stats.isFile() && EXTENSION_FILE_PATTERN.test(name)) {\n // Bare-file form: the file is both entrypoint and (its own) root.\n found.push({ entrypoint: fullPath, rootDir: fullPath });\n continue;\n }\n if (stats.isDirectory()) {\n const entrypoint = resolveDirectoryEntrypoint(fullPath);\n if (entrypoint) found.push({ entrypoint, rootDir: fullPath });\n }\n }\n return found;\n}\n\n/**\n * Resolve a directory-form extension's entrypoint. A `package.json` with a\n * `mikan.extensions` array (first entry, relative to the dir) wins — this is\n * how an extension declares a TypeScript entry and pulls in npm dependencies.\n * Otherwise fall back to an `index.{mjs,js,ts,mts}` file. Returns undefined\n * when neither is present.\n */\nfunction resolveDirectoryEntrypoint(dir: string): string | undefined {\n const declared = readMikanManifestEntrypoints(dir)[0];\n if (declared) {\n const resolved = join(dir, declared);\n if (existsSync(resolved)) return resolved;\n log.logWarning(\n `Extension package.json declares a missing entrypoint: ${resolved}`,\n \"falling back to an index file\",\n );\n }\n for (const candidate of INDEX_CANDIDATES) {\n const indexPath = join(dir, candidate);\n if (existsSync(indexPath)) return indexPath;\n }\n return undefined;\n}\n\ninterface ExtensionPackageJson {\n name?: string;\n version?: string;\n description?: string;\n mikan?: { extensions?: string[]; displayName?: string };\n}\n\n/** Read and shape a directory's package.json; undefined when absent/malformed. */\nfunction readPackageJson(dir: string): ExtensionPackageJson | undefined {\n const packageJsonPath = join(dir, \"package.json\");\n if (!existsSync(packageJsonPath)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(packageJsonPath, \"utf-8\")) as unknown;\n if (!parsed || typeof parsed !== \"object\") return undefined;\n const record = parsed as Record<string, unknown>;\n const mikanRaw = record.mikan as { extensions?: unknown; displayName?: unknown } | undefined;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n mikan: {\n extensions: Array.isArray(mikanRaw?.extensions)\n ? mikanRaw.extensions.filter((entry): entry is string => typeof entry === \"string\")\n : undefined,\n displayName: typeof mikanRaw?.displayName === \"string\" ? mikanRaw.displayName : undefined,\n },\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed package.json: ${packageJsonPath}`, String(err));\n return undefined;\n }\n}\n\n/** Read the `mikan.extensions` entrypoint list from a directory's package.json. */\nfunction readMikanManifestEntrypoints(dir: string): string[] {\n return readPackageJson(dir)?.mikan?.extensions ?? [];\n}\n\nfunction sanitizeSlug(base: string): string {\n const slug = base\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n return slug || \"extension\";\n}\n\n/**\n * Filesystem-safe identifier for an extension, derived from its install\n * location: the directory name for a directory-form extension, or the file\n * basename for a bare file. The slug keys the extension's data dir, secrets\n * vault, and schedule ownership — installing the same extension globally and\n * per-conversation shares one slug and therefore one shared data dir.\n */\nexport function extensionSlug(entrypoint: string): string {\n // Bare-file form (rootDir === entrypoint, a *.mjs/.ts file) → file basename.\n // Directory form → directory name. Detect the directory form structurally:\n // an entrypoint whose parent holds a package.json or is an index file.\n if (INDEX_FILE_PATTERN.test(basename(entrypoint))) {\n return sanitizeSlug(basename(dirname(entrypoint)));\n }\n return sanitizeSlug(basename(entrypoint).replace(EXTENSION_FILE_PATTERN, \"\"));\n}\n\n/** Slug from a discovered extension's root dir (directory or bare file path). */\nfunction slugForRoot(rootDir: string): string {\n return EXTENSION_FILE_PATTERN.test(basename(rootDir))\n ? sanitizeSlug(basename(rootDir).replace(EXTENSION_FILE_PATTERN, \"\"))\n : sanitizeSlug(basename(rootDir));\n}\n\n/** Sanitize an extension-chosen schedule name into a filename segment. */\nfunction scheduleNameSegment(name: string): string {\n const segment = name\n .toLowerCase()\n .replace(/[^a-z0-9_-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 64);\n if (!segment) throw new Error(`Invalid schedule name: ${JSON.stringify(name)}`);\n return segment;\n}\n\n/**\n * Read display metadata (name/version/description) for a directory-form\n * extension. `package.json` is the primary source — its standard `name`,\n * `version`, `description`, plus an optional `mikan.displayName` that\n * overrides the npm name for the user-facing label (npm names are\n * lowercase/scoped; display names can be arbitrary). A `manifest.json` is a\n * fallback for extensions that ship no package.json.\n */\nfunction readManifest(rootDir: string): ExtensionManifest {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) have no manifest.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return {};\n\n const pkg = readPackageJson(rootDir);\n if (pkg && (pkg.mikan?.displayName ?? pkg.name ?? pkg.version ?? pkg.description)) {\n return {\n name: pkg.mikan?.displayName ?? pkg.name,\n version: pkg.version,\n description: pkg.description,\n };\n }\n\n const manifestPath = join(rootDir, \"manifest.json\");\n if (!existsSync(manifestPath)) return {};\n try {\n const parsed: unknown = JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n if (!parsed || typeof parsed !== \"object\") return {};\n const record = parsed as Record<string, unknown>;\n return {\n name: typeof record.name === \"string\" ? record.name : undefined,\n version: typeof record.version === \"string\" ? record.version : undefined,\n description: typeof record.description === \"string\" ? record.description : undefined,\n };\n } catch (err) {\n log.logWarning(`Ignoring malformed extension manifest: ${manifestPath}`, String(err));\n return {};\n }\n}\n\n/**\n * Skills shipped inside a directory-form extension (`<dir>/skills/`).\n * Marked inline: extension files live under the host-only state dir, which\n * sandbox containers cannot read, so skill bodies must ride in the prompt.\n */\nfunction loadExtensionSkills(rootDir: string, slug: string): MikanSkill[] {\n // Bare-file extensions (rootDir is a *.mjs/.ts file) ship no skills.\n if (EXTENSION_FILE_PATTERN.test(basename(rootDir))) return [];\n const skillsDir = join(rootDir, \"skills\");\n if (!existsSync(skillsDir)) return [];\n const result = loadSkillsFromDir({ dir: skillsDir, source: `extension:${slug}` });\n for (const diagnostic of result.diagnostics) {\n log.logWarning(`Extension skill warning (${slug}): ${diagnostic.message}`, diagnostic.path);\n }\n for (const skill of result.skills) skill.inline = true;\n return result.skills;\n}\n\nconst SCHEDULE_FILE_SUFFIX = \".json\";\n\nfunction schedulePrefix(slug: string, conversationId: string): string {\n return `ext.${slug}.${scheduleNameSegment(conversationId)}.`;\n}\n\nfunction payloadFromSpec(\n spec: ExtensionScheduleSpec,\n conversationId: string,\n): ExtensionSchedulePayload {\n if (spec.type === \"periodic\") {\n if (!spec.schedule || !spec.timezone) {\n throw new Error(\"periodic schedule requires schedule and timezone\");\n }\n return {\n type: \"periodic\",\n conversationId,\n text: spec.text,\n schedule: spec.schedule,\n timezone: spec.timezone,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n }\n if (!spec.at) throw new Error(\"one-shot schedule requires at\");\n return {\n type: \"one-shot\",\n conversationId,\n text: spec.text,\n at: spec.at,\n ...(spec.platform ? { platform: spec.platform } : {}),\n };\n}\n\nfunction specFromPayload(payload: ExtensionSchedulePayload): ExtensionScheduleSpec {\n if (payload.type === \"periodic\") {\n return {\n type: \"periodic\",\n schedule: payload.schedule ?? \"\",\n timezone: payload.timezone ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n }\n return {\n type: \"one-shot\",\n at: payload.at ?? \"\",\n text: payload.text,\n ...(payload.platform ? { platform: payload.platform } : {}),\n };\n}\n\n/** Build the v2 api surface for one extension over the injected services. */\nfunction buildExtensionApi(params: {\n name: string;\n slug: string;\n registry: ExtensionRegistry;\n context: LoadExtensionsOptions[\"context\"];\n services: ExtensionHostServices;\n}): MikanExtensionApi {\n const { name, slug, registry, context, services } = params;\n const stateDir = services.stateDir ?? join(homedir(), \".mikan\");\n const conversationId = context.conversationId;\n\n const requireScheduleStore = () => {\n if (!services.scheduleStore) {\n throw new Error(\"api.schedules is unavailable: this context provides no schedule store\");\n }\n return services.scheduleStore;\n };\n\n return {\n on: (hook, handler) => registry.register(name, hook, handler),\n registerTool: (tool: AgentTool) => registry.registerTool(tool),\n registerCommand: (command: ExtensionCommand) => registry.registerCommand(name, command),\n onDispose: (disposer: ExtensionDisposer) => registry.registerDisposer(name, disposer),\n log: (message: string) => log.logInfo(`[extension:${name}] ${message}`),\n context,\n paths: {\n get dataDir(): string {\n // This conversation's own data, co-located with the conversation's\n // other host-only assets; removed when the conversation is deleted.\n const dir = join(stateDir, \"conversations\", conversationId, \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n get sharedDataDir(): string {\n // Cross-conversation data under the sibling `global` scope.\n const dir = join(stateDir, \"global\", \"extension-data\", slug);\n mkdirSync(dir, { recursive: true });\n return dir;\n },\n },\n secrets: {\n get: (key: string) => services.resolveSecrets?.(slug)[key],\n list: () => Object.keys(services.resolveSecrets?.(slug) ?? {}),\n },\n schedules: {\n upsert: async (scheduleName, spec) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n await store.write(filename, payloadFromSpec(spec, conversationId));\n },\n delete: async (scheduleName) => {\n const store = requireScheduleStore();\n const filename = `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;\n return store.delete(filename);\n },\n list: async () => {\n const store = requireScheduleStore();\n const prefix = schedulePrefix(slug, conversationId);\n const infos: ExtensionScheduleInfo[] = [];\n for (const entry of await store.list()) {\n if (!entry.filename.startsWith(prefix)) continue;\n if (!entry.filename.endsWith(SCHEDULE_FILE_SUFFIX)) continue;\n infos.push({\n name: entry.filename.slice(prefix.length, -SCHEDULE_FILE_SUFFIX.length),\n spec: specFromPayload(entry.payload),\n });\n }\n return infos;\n },\n },\n subagent: {\n run: async (request) => {\n if (!services.runSubagent) {\n throw new Error(\"api.subagent is unavailable: this context provides no subagent runner\");\n }\n return services.runSubagent(request, registry.getContributedTools());\n },\n },\n notify: async (text: string, options?: { conversationId?: string }) => {\n if (!services.postMessage) {\n throw new Error(\"api.notify is unavailable: this context provides no platform messaging\");\n }\n await services.postMessage(options?.conversationId ?? conversationId, text);\n },\n react: async (messageTs: string, emoji: string) => {\n if (!services.addReaction) {\n throw new Error(\"api.react is unavailable: this context provides no reaction support\");\n }\n await services.addReaction(conversationId, messageTs, emoji);\n },\n uploadFile: async (filePath: string, title?: string) => {\n if (!services.uploadFile) {\n throw new Error(\"api.uploadFile is unavailable: this context provides no file uploads\");\n }\n await services.uploadFile(conversationId, filePath, title);\n },\n triggerRun: async (text: string) => {\n const store = requireScheduleStore();\n // Distinct \"extrun.\" namespace: run files must never surface in\n // api.schedules.list(), whose ownership filter is the \"ext.\" prefix.\n // The embedder's watcher fires and deletes the file immediately.\n const filename = `extrun.${slug}.${scheduleNameSegment(conversationId)}.${Date.now()}-${runCounter++}${SCHEDULE_FILE_SUFFIX}`;\n await store.write(filename, { type: \"immediate\", conversationId, text });\n },\n };\n}\n\n/** Monotonic suffix so rapid triggerRun calls in one process never collide. */\nlet runCounter = 0;\n\nfunction resolveActivate(moduleExports: unknown): MikanExtensionModule | undefined {\n if (!moduleExports || typeof moduleExports !== \"object\") return undefined;\n const candidates: unknown[] = [(moduleExports as { default?: unknown }).default, moduleExports];\n for (const candidate of candidates) {\n if (typeof candidate === \"function\") {\n return { activate: candidate as MikanExtensionActivate };\n }\n if (candidate && typeof candidate === \"object\") {\n const activate = (candidate as { activate?: unknown }).activate;\n if (typeof activate === \"function\") {\n return {\n name:\n typeof (candidate as { name?: unknown }).name === \"string\"\n ? (candidate as { name: string }).name\n : undefined,\n activate: activate as MikanExtensionActivate,\n };\n }\n }\n }\n return undefined;\n}\n\n/** Load and activate all extensions found in the given directories. */\nexport async function loadExtensions(\n options: LoadExtensionsOptions,\n): Promise<LoadExtensionsResult> {\n const registry = new ExtensionRegistry();\n const extensions: LoadedExtension[] = [];\n const errors: ExtensionLoadError[] = [];\n const skills: MikanSkill[] = [];\n const services = options.services ?? {};\n\n for (const dir of options.dirs) {\n for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n const extension = resolveActivate(moduleExports);\n if (!extension) {\n errors.push({\n path: entrypoint,\n error: \"extension must export an activate function (default or named)\",\n });\n continue;\n }\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const name = manifest.name ?? extension.name ?? slug;\n const api = buildExtensionApi({\n name,\n slug,\n registry,\n context: options.context,\n services,\n });\n const disposer = await extension.activate(api);\n if (typeof disposer === \"function\") registry.registerDisposer(name, disposer);\n const extensionSkills = loadExtensionSkills(rootDir, slug);\n skills.push(...extensionSkills);\n extensions.push({\n name,\n path: entrypoint,\n slug,\n version: manifest.version,\n description: manifest.description,\n skills: extensionSkills,\n });\n } catch (err) {\n errors.push({\n path: entrypoint,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n return { registry, extensions, errors, skills, dispose: () => registry.dispose() };\n}\n\nexport interface ExtensionValidation {\n ok: boolean;\n /** Slug the extension would install as (from the source dir/file name). */\n slug: string;\n /** Display name (manifest name, else slug). */\n name: string;\n version?: string;\n description?: string;\n /** Resolved entrypoint that would be imported. */\n entrypoint?: string;\n /** Skill names shipped alongside the extension. */\n skillNames: string[];\n errors: string[];\n warnings: string[];\n}\n\n/**\n * Validate an extension source path (a directory or a single file) WITHOUT\n * activating it: resolves the entrypoint (package.json `mikan.extensions`,\n * index file, or the file itself), imports it, and checks it exports an\n * `activate` function. Used by `mikan ext install` as a preflight and by\n * `mikan ext validate`. Importing runs top-level module code but not\n * `activate`, so there are no schedule/tool side effects.\n */\nexport async function validateExtension(sourcePath: string): Promise<ExtensionValidation> {\n const errors: string[] = [];\n const warnings: string[] = [];\n const rootDir = sourcePath.replace(/[/\\\\]+$/, \"\");\n const base = basename(rootDir);\n\n if (INDEX_FILE_PATTERN.test(base)) {\n warnings.push(\n \"Entry is a bare index file; install into a named directory so the slug is stable.\",\n );\n }\n\n let entrypoint: string | undefined;\n if (!existsSync(rootDir)) {\n errors.push(`Path does not exist: ${rootDir}`);\n } else if (statSync(rootDir).isDirectory()) {\n entrypoint = resolveDirectoryEntrypoint(rootDir);\n if (!entrypoint) {\n errors.push(\n \"No entrypoint found: expected package.json with a mikan.extensions entry, or an index.{mjs,js,ts,mts}.\",\n );\n }\n } else if (EXTENSION_FILE_PATTERN.test(base)) {\n entrypoint = rootDir;\n } else {\n errors.push(`Not an extension file (expected .mjs/.js/.ts/.mts): ${rootDir}`);\n }\n\n const slug = slugForRoot(rootDir);\n const manifest = readManifest(rootDir);\n const skillNames = loadExtensionSkills(rootDir, slug).map((skill) => skill.name);\n\n if (entrypoint) {\n try {\n const moduleExports: unknown = await importExtensionModule(entrypoint);\n if (!resolveActivate(moduleExports)) {\n errors.push(\"Module does not export an activate function (default or named).\");\n }\n } catch (err) {\n errors.push(`Failed to import: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return {\n ok: errors.length === 0,\n slug,\n name: manifest.name ?? slug,\n version: manifest.version,\n description: manifest.description,\n entrypoint,\n skillNames,\n errors,\n warnings,\n };\n}\n"]}
|
|
@@ -25,8 +25,9 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import type { AgentMessage, AgentTool, ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
27
27
|
import type { Api, ImageContent, Model, TextContent } from "@earendil-works/pi-ai";
|
|
28
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
28
29
|
import type { MikanSkill } from "../skills.js";
|
|
29
|
-
import type { CompactionEntry } from "../types.js";
|
|
30
|
+
import type { SubagentRunOutput, SubagentRunRequest, SubagentRunResult, CompactionEntry } from "../types.js";
|
|
30
31
|
/**
|
|
31
32
|
* Platform provenance of the run a hook event belongs to. Interactive runs
|
|
32
33
|
* carry the triggering message's identity (usable with `api.react` and for
|
|
@@ -194,6 +195,14 @@ export interface ExtensionCommand {
|
|
|
194
195
|
description?: string;
|
|
195
196
|
handler: (context: ExtensionCommandContext) => void | Promise<void>;
|
|
196
197
|
}
|
|
198
|
+
export interface SubagentApi {
|
|
199
|
+
/**
|
|
200
|
+
* Run one fresh subagent and return its result to the extension. The
|
|
201
|
+
* subagent has no conversation history, receives no tools by default, and
|
|
202
|
+
* cannot recursively start another subagent run.
|
|
203
|
+
*/
|
|
204
|
+
run<TOutputSchema extends TSchema | undefined = undefined>(request: SubagentRunRequest<TOutputSchema>): Promise<SubagentRunResult<SubagentRunOutput<TOutputSchema>>>;
|
|
205
|
+
}
|
|
197
206
|
/**
|
|
198
207
|
* Persistence backend for extension schedules, injected by the embedder
|
|
199
208
|
* (mikan backs this with event files watched by its EventsWatcher).
|
|
@@ -226,6 +235,8 @@ export interface ExtensionHostServices {
|
|
|
226
235
|
uploadFile?: (conversationId: string, filePath: string, title?: string, platform?: string) => Promise<void>;
|
|
227
236
|
/** Resolve read-only secrets for an extension slug; enables `api.secrets`. */
|
|
228
237
|
resolveSecrets?: (slug: string) => Record<string, string>;
|
|
238
|
+
/** Run a fresh isolated subagent; enables `api.subagent`. */
|
|
239
|
+
runSubagent?: <TOutputSchema extends TSchema | undefined = undefined>(request: SubagentRunRequest<TOutputSchema>, contributedTools: AgentTool[]) => Promise<SubagentRunResult<SubagentRunOutput<TOutputSchema>>>;
|
|
229
240
|
}
|
|
230
241
|
/**
|
|
231
242
|
* Optional `manifest.json` next to a directory-form extension's entrypoint.
|
|
@@ -309,6 +320,8 @@ export interface MikanExtensionApi {
|
|
|
309
320
|
/** Schedules owned by this extension in this conversation. */
|
|
310
321
|
list(): Promise<ExtensionScheduleInfo[]>;
|
|
311
322
|
};
|
|
323
|
+
/** Fresh isolated subagent runs. */
|
|
324
|
+
readonly subagent: SubagentApi;
|
|
312
325
|
/**
|
|
313
326
|
* Post text into a conversation without triggering an agent run. Defaults
|
|
314
327
|
* to this conversation; pass `conversationId` to post elsewhere (pairs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/harness/extensions/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,KAAK,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/harness/extensions/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/harness/extensions/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * mikan extension system, v1.\n *\n * Extensions are ES modules that export an `activate` function (either as\n * the default export or a named `activate` export, optionally wrapped in an\n * object that also carries a `name`). `activate` receives a\n * {@link MikanExtensionApi} and registers hooks and tools.\n *\n * ```js\n * // extensions/audit.mjs\n * export default function activate(api) {\n * api.on(\"tool_call\", ({ toolName, args }) => {\n * if (toolName === \"bash\" && String(args.command).includes(\"rm -rf /\")) {\n * return { block: true, reason: \"destructive command\" };\n * }\n * });\n * }\n * ```\n *\n * Hooks run in registration order. Result semantics are per hook:\n * `tool_call` keeps v1's first-non-undefined-wins; `before_agent_start` and\n * `tool_result` chain — each handler sees the event as rewritten by earlier\n * handlers, and for `before_agent_start` a `block` from any handler wins.\n * Hook errors are logged and never crash a run.\n */\nimport type { AgentMessage, AgentTool, ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, ImageContent, Model, TextContent } from \"@earendil-works/pi-ai\";\nimport type { MikanSkill } from \"../skills.js\";\nimport type { CompactionEntry } from \"../types.js\";\n\n/**\n * Platform provenance of the run a hook event belongs to. Interactive runs\n * carry the triggering message's identity (usable with `api.react` and for\n * per-user policy); autonomous runs (schedules/events) have no triggering\n * platform message, so only `kind` and `platform` are set.\n */\nexport interface RunOrigin {\n kind: \"interactive\" | \"event\";\n /** Platform adapter name serving this run (e.g. \"slack\"). */\n platform?: string;\n /** Platform message id of the triggering message; pass to `api.react`. */\n messageTs?: string;\n userId?: string;\n userName?: string;\n threadTs?: string;\n /** Attachments already downloaded to host paths (extensions run on host). */\n attachments?: { name: string; localPath: string }[];\n}\n\nexport interface BeforeAgentStartHookEvent {\n prompt: string;\n images?: ImageContent[];\n systemPrompt: string;\n origin?: RunOrigin;\n}\n\nexport interface BeforeAgentStartHookResult {\n /** Replace the system prompt for this turn. */\n systemPrompt?: string;\n /** Rewrite the user prompt for this turn. */\n prompt?: string;\n /** Block the turn entirely; the model is never called and nothing persists. */\n block?: boolean;\n /** Shown to the user when the turn is blocked. */\n reason?: string;\n}\n\nexport interface ToolCallHookEvent {\n toolCallId: string;\n toolName: string;\n args: unknown;\n origin?: RunOrigin;\n}\n\nexport interface ToolCallHookResult {\n /** Block the tool call; the model receives an error tool result instead. */\n block?: boolean;\n reason?: string;\n}\n\nexport interface ToolResultHookEvent {\n toolCallId: string;\n toolName: string;\n args: unknown;\n content: (TextContent | ImageContent)[];\n isError: boolean;\n origin?: RunOrigin;\n}\n\nexport interface ToolResultHookResult {\n /** Replace the tool result content sent back to the model (e.g. redaction). */\n content?: (TextContent | ImageContent)[];\n /** Override the tool result error flag. */\n isError?: boolean;\n}\n\nexport interface MessageEndHookEvent {\n message: AgentMessage;\n origin?: RunOrigin;\n}\n\nexport interface TurnEndHookEvent {\n messages: AgentMessage[];\n origin?: RunOrigin;\n}\n\nexport interface SessionCompactHookEvent {\n entry: CompactionEntry;\n reason: \"threshold\" | \"overflow\" | \"manual\";\n}\n\n/** A turn settled with an error after retries were exhausted (or none applied). */\nexport interface AgentErrorHookEvent {\n errorMessage: string;\n origin?: RunOrigin;\n}\n\n/** The run budget circuit breaker tripped and the run was aborted. */\nexport interface BudgetExceededHookEvent {\n /** Which cap was hit, e.g. \"cost 2.01 USD >= 2 USD limit\". */\n reason: string;\n tokens: number;\n costUsd: number;\n llmCalls: number;\n durationMs: number;\n origin?: RunOrigin;\n}\n\n/** Map of hook names to handler signatures. */\nexport interface MikanHookMap {\n before_agent_start: (\n event: BeforeAgentStartHookEvent,\n ) =>\n | BeforeAgentStartHookResult\n | undefined\n | void\n | Promise<BeforeAgentStartHookResult | undefined | void>;\n tool_call: (\n event: ToolCallHookEvent,\n ) => ToolCallHookResult | undefined | void | Promise<ToolCallHookResult | undefined | void>;\n tool_result: (\n event: ToolResultHookEvent,\n ) => ToolResultHookResult | undefined | void | Promise<ToolResultHookResult | undefined | void>;\n message_end: (event: MessageEndHookEvent) => void | Promise<void>;\n turn_end: (event: TurnEndHookEvent) => void | Promise<void>;\n session_compact: (event: SessionCompactHookEvent) => void | Promise<void>;\n agent_error: (event: AgentErrorHookEvent) => void | Promise<void>;\n budget_exceeded: (event: BudgetExceededHookEvent) => void | Promise<void>;\n}\n\nexport type MikanHookName = keyof MikanHookMap;\n\n// ── v2: schedules ────────────────────────────────────────────────────────────\n\n/**\n * A schedule contributed by an extension. Fires an autonomous agent run in\n * this conversation with `text` as the task prompt (the run does not inherit\n * conversation history — write `text` self-contained).\n */\nexport type ExtensionScheduleSpec =\n | {\n type: \"periodic\";\n /** Cron expression (croner syntax). */\n schedule: string;\n /** IANA timezone, e.g. \"Asia/Taipei\". */\n timezone: string;\n text: string;\n /** Target platform; optional when only one platform is running. */\n platform?: string;\n }\n | {\n type: \"one-shot\";\n /** ISO 8601 timestamp with offset. */\n at: string;\n text: string;\n platform?: string;\n };\n\nexport interface ExtensionScheduleInfo {\n /** Extension-chosen schedule name. */\n name: string;\n spec: ExtensionScheduleSpec;\n}\n\n/**\n * Event-file payload the harness hands to the embedder's schedule store.\n * Mirrors mikan's event-file shape; `platform` may be omitted when the\n * embedder runs a single platform. `immediate` backs `api.triggerRun` —\n * the event fires as soon as the embedder's watcher picks it up.\n */\nexport interface ExtensionSchedulePayload {\n type: \"one-shot\" | \"periodic\" | \"immediate\";\n conversationId: string;\n text: string;\n platform?: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n}\n\n// ── v3: commands and lifecycle ───────────────────────────────────────────────\n\n/** Cleanup callback run when the harness instance owning the extension is discarded. */\nexport type ExtensionDisposer = () => void | Promise<void>;\n\n/** Context handed to an extension command handler for one invocation. */\nexport interface ExtensionCommandContext {\n /** Text after the command name, trimmed (\"\" when none). */\n args: string;\n conversationId: string;\n userId?: string;\n userName?: string;\n /** Reply in the conversation the command was sent from. */\n respond(text: string): Promise<void>;\n}\n\n/**\n * A chat command contributed by an extension (`/name args…`). Dispatched\n * deterministically by the embedder — no model call, no agent-session entry\n * (the triggering message still syncs to chat history).\n * Built-in commands always win over extension commands of the same name.\n */\nexport interface ExtensionCommand {\n /** Command name without the leading slash; `[a-z0-9_-]+`, case-insensitive match. */\n name: string;\n /** One-line description for inventory surfaces. */\n description?: string;\n handler: (context: ExtensionCommandContext) => void | Promise<void>;\n}\n\n// ── v2: embedder-injected services ───────────────────────────────────────────\n\n/**\n * Persistence backend for extension schedules, injected by the embedder\n * (mikan backs this with event files watched by its EventsWatcher).\n * Filenames are fully qualified by the harness (`ext-<slug>-<name>.json`).\n */\nexport interface ExtensionScheduleStore {\n write(filename: string, payload: ExtensionSchedulePayload): Promise<void>;\n delete(filename: string): Promise<boolean>;\n /** List all schedule files, harness filters by ownership prefix. */\n list(): Promise<Array<{ filename: string; payload: ExtensionSchedulePayload }>>;\n}\n\n/**\n * Host services injected into extensions by the embedder. All fields are\n * optional: the corresponding api surface throws an informative error when\n * the running context does not provide the service.\n */\nexport interface ExtensionHostServices {\n /** State dir for per-extension data dirs; defaults to `~/.mikan`. */\n stateDir?: string;\n /** Schedule persistence; enables `api.schedules`. */\n scheduleStore?: ExtensionScheduleStore;\n /** Post a message to a conversation without an agent run; enables `api.notify`. */\n postMessage?: (conversationId: string, text: string, platform?: string) => Promise<void>;\n /** Add an emoji reaction to a message; enables `api.react`. */\n addReaction?: (\n conversationId: string,\n messageTs: string,\n emoji: string,\n platform?: string,\n ) => Promise<void>;\n /** Upload a host file into a conversation; enables `api.uploadFile`. */\n uploadFile?: (\n conversationId: string,\n filePath: string,\n title?: string,\n platform?: string,\n ) => Promise<void>;\n /** Resolve read-only secrets for an extension slug; enables `api.secrets`. */\n resolveSecrets?: (slug: string) => Record<string, string>;\n}\n\n// ── v2: manifest ─────────────────────────────────────────────────────────────\n\n/**\n * Optional `manifest.json` next to a directory-form extension's entrypoint.\n * `name` is the display name only; the slug (data dir, secrets, schedule\n * ownership) always derives from the install path so identity is\n * admin-controlled and stable across manifest edits.\n */\nexport interface ExtensionManifest {\n name?: string;\n version?: string;\n description?: string;\n}\n\n/** API handed to an extension's `activate` function. */\nexport interface MikanExtensionApi {\n /** Register a hook handler. */\n on<T extends MikanHookName>(hook: T, handler: MikanHookMap[T]): void;\n /** Contribute an additional agent tool. */\n registerTool(tool: AgentTool): void;\n /**\n * Contribute a chat command (`/name`). Dispatched without a model call;\n * built-in commands and earlier registrations of the same name win.\n */\n registerCommand(command: ExtensionCommand): void;\n /**\n * Register cleanup to run when this harness instance is discarded\n * (`/pi-new`, session eviction, shutdown). Alternative to returning a\n * disposer from `activate`. Disposers run in reverse registration order.\n */\n onDispose(disposer: ExtensionDisposer): void;\n /** Extension-scoped logging that lands in mikan's structured log. */\n log(message: string): void;\n /** Context about the conversation this harness instance serves. */\n readonly context: {\n readonly conversationId: string;\n readonly workspaceDir: string;\n readonly model: Model<Api>;\n readonly thinkingLevel: ThinkingLevel;\n };\n /**\n * Host-only filesystem locations owned by this extension (never mounted\n * into sandbox containers). Which one you use is a declaration: `dataDir`\n * for conversation-scoped state (the safe default — isolation for free),\n * `sharedDataDir` for deliberately cross-conversation state (you own tenant\n * partitioning and concurrency). See `LAYOUT.md`.\n */\n readonly paths: {\n /**\n * This conversation's private data directory\n * (`conversations/<conversationId>/extension-data/<slug>`), created on\n * first access. Default choice: co-located with the conversation, so it\n * disappears when the conversation is deleted.\n */\n readonly dataDir: string;\n /**\n * Data shared across all conversations this extension serves\n * (`global/extension-data/<slug>`), created on first access. Explicit\n * opt-in for multi-conversation applications (e.g. a PM tool with\n * cross-channel views); key rows by conversation id yourself.\n */\n readonly sharedDataDir: string;\n };\n /**\n * Read-only secrets from the embedder's vault\n * (mikan: `<stateDir>/vaults/extensions/<slug>/env`).\n */\n readonly secrets: {\n get(key: string): string | undefined;\n /** Secret names only, never values. */\n list(): string[];\n };\n /**\n * Named schedules owned by this extension + conversation. Backed by the\n * embedder's schedule store; in mikan these become event files that fire\n * autonomous agent runs (hot-reloaded, persisted across restarts).\n */\n readonly schedules: {\n /** Create or replace a named schedule. */\n upsert(name: string, spec: ExtensionScheduleSpec): Promise<void>;\n /** Delete a named schedule. Returns false when it did not exist. */\n delete(name: string): Promise<boolean>;\n /** Schedules owned by this extension in this conversation. */\n list(): Promise<ExtensionScheduleInfo[]>;\n };\n /**\n * Post text into a conversation without triggering an agent run. Defaults\n * to this conversation; pass `conversationId` to post elsewhere (pairs\n * with `sharedDataDir` for cross-conversation applications). Available\n * when the embedder provides platform messaging.\n */\n notify(text: string, options?: { conversationId?: string }): Promise<void>;\n /**\n * Add an emoji reaction to a message in this conversation. `messageTs` is\n * the platform message id the extension read from an event (see\n * `RunOrigin.messageTs`); `emoji` is a short name without colons.\n * Available when the embedder provides reaction support.\n */\n react(messageTs: string, emoji: string): Promise<void>;\n /**\n * Upload a host-side file into this conversation without an agent run.\n * Available when the embedder provides file uploads for the platform.\n */\n uploadFile(filePath: string, title?: string): Promise<void>;\n /**\n * Fire an autonomous agent run in this conversation as soon as possible.\n * Like a schedule, the run does not inherit conversation history — write\n * `text` self-contained. Backed by the embedder's schedule store.\n */\n triggerRun(text: string): Promise<void>;\n}\n\nexport type MikanExtensionActivate = (\n api: MikanExtensionApi,\n) => void | ExtensionDisposer | Promise<void | ExtensionDisposer>;\n\nexport interface MikanExtensionModule {\n name?: string;\n activate: MikanExtensionActivate;\n}\n\nexport interface LoadedExtension {\n name: string;\n path: string;\n /** Filesystem-safe identifier used for data dirs, secrets, and schedules. */\n slug: string;\n version?: string;\n description?: string;\n /** Skills discovered under the extension's `skills/` directory. */\n skills: MikanSkill[];\n}\n\nexport interface ExtensionLoadError {\n path: string;\n error: string;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/harness/extensions/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * mikan extension system, v1.\n *\n * Extensions are ES modules that export an `activate` function (either as\n * the default export or a named `activate` export, optionally wrapped in an\n * object that also carries a `name`). `activate` receives a\n * {@link MikanExtensionApi} and registers hooks and tools.\n *\n * ```js\n * // extensions/audit.mjs\n * export default function activate(api) {\n * api.on(\"tool_call\", ({ toolName, args }) => {\n * if (toolName === \"bash\" && String(args.command).includes(\"rm -rf /\")) {\n * return { block: true, reason: \"destructive command\" };\n * }\n * });\n * }\n * ```\n *\n * Hooks run in registration order. Result semantics are per hook:\n * `tool_call` keeps v1's first-non-undefined-wins; `before_agent_start` and\n * `tool_result` chain — each handler sees the event as rewritten by earlier\n * handlers, and for `before_agent_start` a `block` from any handler wins.\n * Hook errors are logged and never crash a run.\n */\nimport type { AgentMessage, AgentTool, ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Api, ImageContent, Model, TextContent } from \"@earendil-works/pi-ai\";\nimport type { TSchema } from \"@sinclair/typebox\";\nimport type { MikanSkill } from \"../skills.js\";\nimport type {\n SubagentRunOutput,\n SubagentRunRequest,\n SubagentRunResult,\n CompactionEntry,\n} from \"../types.js\";\n\n/**\n * Platform provenance of the run a hook event belongs to. Interactive runs\n * carry the triggering message's identity (usable with `api.react` and for\n * per-user policy); autonomous runs (schedules/events) have no triggering\n * platform message, so only `kind` and `platform` are set.\n */\nexport interface RunOrigin {\n kind: \"interactive\" | \"event\";\n /** Platform adapter name serving this run (e.g. \"slack\"). */\n platform?: string;\n /** Platform message id of the triggering message; pass to `api.react`. */\n messageTs?: string;\n userId?: string;\n userName?: string;\n threadTs?: string;\n /** Attachments already downloaded to host paths (extensions run on host). */\n attachments?: { name: string; localPath: string }[];\n}\n\nexport interface BeforeAgentStartHookEvent {\n prompt: string;\n images?: ImageContent[];\n systemPrompt: string;\n origin?: RunOrigin;\n}\n\nexport interface BeforeAgentStartHookResult {\n /** Replace the system prompt for this turn. */\n systemPrompt?: string;\n /** Rewrite the user prompt for this turn. */\n prompt?: string;\n /** Block the turn entirely; the model is never called and nothing persists. */\n block?: boolean;\n /** Shown to the user when the turn is blocked. */\n reason?: string;\n}\n\nexport interface ToolCallHookEvent {\n toolCallId: string;\n toolName: string;\n args: unknown;\n origin?: RunOrigin;\n}\n\nexport interface ToolCallHookResult {\n /** Block the tool call; the model receives an error tool result instead. */\n block?: boolean;\n reason?: string;\n}\n\nexport interface ToolResultHookEvent {\n toolCallId: string;\n toolName: string;\n args: unknown;\n content: (TextContent | ImageContent)[];\n isError: boolean;\n origin?: RunOrigin;\n}\n\nexport interface ToolResultHookResult {\n /** Replace the tool result content sent back to the model (e.g. redaction). */\n content?: (TextContent | ImageContent)[];\n /** Override the tool result error flag. */\n isError?: boolean;\n}\n\nexport interface MessageEndHookEvent {\n message: AgentMessage;\n origin?: RunOrigin;\n}\n\nexport interface TurnEndHookEvent {\n messages: AgentMessage[];\n origin?: RunOrigin;\n}\n\nexport interface SessionCompactHookEvent {\n entry: CompactionEntry;\n reason: \"threshold\" | \"overflow\" | \"manual\";\n}\n\n/** A turn settled with an error after retries were exhausted (or none applied). */\nexport interface AgentErrorHookEvent {\n errorMessage: string;\n origin?: RunOrigin;\n}\n\n/** The run budget circuit breaker tripped and the run was aborted. */\nexport interface BudgetExceededHookEvent {\n /** Which cap was hit, e.g. \"cost 2.01 USD >= 2 USD limit\". */\n reason: string;\n tokens: number;\n costUsd: number;\n llmCalls: number;\n durationMs: number;\n origin?: RunOrigin;\n}\n\n/** Map of hook names to handler signatures. */\nexport interface MikanHookMap {\n before_agent_start: (\n event: BeforeAgentStartHookEvent,\n ) =>\n | BeforeAgentStartHookResult\n | undefined\n | void\n | Promise<BeforeAgentStartHookResult | undefined | void>;\n tool_call: (\n event: ToolCallHookEvent,\n ) => ToolCallHookResult | undefined | void | Promise<ToolCallHookResult | undefined | void>;\n tool_result: (\n event: ToolResultHookEvent,\n ) => ToolResultHookResult | undefined | void | Promise<ToolResultHookResult | undefined | void>;\n message_end: (event: MessageEndHookEvent) => void | Promise<void>;\n turn_end: (event: TurnEndHookEvent) => void | Promise<void>;\n session_compact: (event: SessionCompactHookEvent) => void | Promise<void>;\n agent_error: (event: AgentErrorHookEvent) => void | Promise<void>;\n budget_exceeded: (event: BudgetExceededHookEvent) => void | Promise<void>;\n}\n\nexport type MikanHookName = keyof MikanHookMap;\n\n// ── v2: schedules ────────────────────────────────────────────────────────────\n\n/**\n * A schedule contributed by an extension. Fires an autonomous agent run in\n * this conversation with `text` as the task prompt (the run does not inherit\n * conversation history — write `text` self-contained).\n */\nexport type ExtensionScheduleSpec =\n | {\n type: \"periodic\";\n /** Cron expression (croner syntax). */\n schedule: string;\n /** IANA timezone, e.g. \"Asia/Taipei\". */\n timezone: string;\n text: string;\n /** Target platform; optional when only one platform is running. */\n platform?: string;\n }\n | {\n type: \"one-shot\";\n /** ISO 8601 timestamp with offset. */\n at: string;\n text: string;\n platform?: string;\n };\n\nexport interface ExtensionScheduleInfo {\n /** Extension-chosen schedule name. */\n name: string;\n spec: ExtensionScheduleSpec;\n}\n\n/**\n * Event-file payload the harness hands to the embedder's schedule store.\n * Mirrors mikan's event-file shape; `platform` may be omitted when the\n * embedder runs a single platform. `immediate` backs `api.triggerRun` —\n * the event fires as soon as the embedder's watcher picks it up.\n */\nexport interface ExtensionSchedulePayload {\n type: \"one-shot\" | \"periodic\" | \"immediate\";\n conversationId: string;\n text: string;\n platform?: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n}\n\n// ── v3: commands and lifecycle ───────────────────────────────────────────────\n\n/** Cleanup callback run when the harness instance owning the extension is discarded. */\nexport type ExtensionDisposer = () => void | Promise<void>;\n\n/** Context handed to an extension command handler for one invocation. */\nexport interface ExtensionCommandContext {\n /** Text after the command name, trimmed (\"\" when none). */\n args: string;\n conversationId: string;\n userId?: string;\n userName?: string;\n /** Reply in the conversation the command was sent from. */\n respond(text: string): Promise<void>;\n}\n\n/**\n * A chat command contributed by an extension (`/name args…`). Dispatched\n * deterministically by the embedder — no model call, no agent-session entry\n * (the triggering message still syncs to chat history).\n * Built-in commands always win over extension commands of the same name.\n */\nexport interface ExtensionCommand {\n /** Command name without the leading slash; `[a-z0-9_-]+`, case-insensitive match. */\n name: string;\n /** One-line description for inventory surfaces. */\n description?: string;\n handler: (context: ExtensionCommandContext) => void | Promise<void>;\n}\n\nexport interface SubagentApi {\n /**\n * Run one fresh subagent and return its result to the extension. The\n * subagent has no conversation history, receives no tools by default, and\n * cannot recursively start another subagent run.\n */\n run<TOutputSchema extends TSchema | undefined = undefined>(\n request: SubagentRunRequest<TOutputSchema>,\n ): Promise<SubagentRunResult<SubagentRunOutput<TOutputSchema>>>;\n}\n\n// ── v2: embedder-injected services ───────────────────────────────────────────\n\n/**\n * Persistence backend for extension schedules, injected by the embedder\n * (mikan backs this with event files watched by its EventsWatcher).\n * Filenames are fully qualified by the harness (`ext-<slug>-<name>.json`).\n */\nexport interface ExtensionScheduleStore {\n write(filename: string, payload: ExtensionSchedulePayload): Promise<void>;\n delete(filename: string): Promise<boolean>;\n /** List all schedule files, harness filters by ownership prefix. */\n list(): Promise<Array<{ filename: string; payload: ExtensionSchedulePayload }>>;\n}\n\n/**\n * Host services injected into extensions by the embedder. All fields are\n * optional: the corresponding api surface throws an informative error when\n * the running context does not provide the service.\n */\nexport interface ExtensionHostServices {\n /** State dir for per-extension data dirs; defaults to `~/.mikan`. */\n stateDir?: string;\n /** Schedule persistence; enables `api.schedules`. */\n scheduleStore?: ExtensionScheduleStore;\n /** Post a message to a conversation without an agent run; enables `api.notify`. */\n postMessage?: (conversationId: string, text: string, platform?: string) => Promise<void>;\n /** Add an emoji reaction to a message; enables `api.react`. */\n addReaction?: (\n conversationId: string,\n messageTs: string,\n emoji: string,\n platform?: string,\n ) => Promise<void>;\n /** Upload a host file into a conversation; enables `api.uploadFile`. */\n uploadFile?: (\n conversationId: string,\n filePath: string,\n title?: string,\n platform?: string,\n ) => Promise<void>;\n /** Resolve read-only secrets for an extension slug; enables `api.secrets`. */\n resolveSecrets?: (slug: string) => Record<string, string>;\n /** Run a fresh isolated subagent; enables `api.subagent`. */\n runSubagent?: <TOutputSchema extends TSchema | undefined = undefined>(\n request: SubagentRunRequest<TOutputSchema>,\n contributedTools: AgentTool[],\n ) => Promise<SubagentRunResult<SubagentRunOutput<TOutputSchema>>>;\n}\n\n// ── v2: manifest ─────────────────────────────────────────────────────────────\n\n/**\n * Optional `manifest.json` next to a directory-form extension's entrypoint.\n * `name` is the display name only; the slug (data dir, secrets, schedule\n * ownership) always derives from the install path so identity is\n * admin-controlled and stable across manifest edits.\n */\nexport interface ExtensionManifest {\n name?: string;\n version?: string;\n description?: string;\n}\n\n/** API handed to an extension's `activate` function. */\nexport interface MikanExtensionApi {\n /** Register a hook handler. */\n on<T extends MikanHookName>(hook: T, handler: MikanHookMap[T]): void;\n /** Contribute an additional agent tool. */\n registerTool(tool: AgentTool): void;\n /**\n * Contribute a chat command (`/name`). Dispatched without a model call;\n * built-in commands and earlier registrations of the same name win.\n */\n registerCommand(command: ExtensionCommand): void;\n /**\n * Register cleanup to run when this harness instance is discarded\n * (`/pi-new`, session eviction, shutdown). Alternative to returning a\n * disposer from `activate`. Disposers run in reverse registration order.\n */\n onDispose(disposer: ExtensionDisposer): void;\n /** Extension-scoped logging that lands in mikan's structured log. */\n log(message: string): void;\n /** Context about the conversation this harness instance serves. */\n readonly context: {\n readonly conversationId: string;\n readonly workspaceDir: string;\n readonly model: Model<Api>;\n readonly thinkingLevel: ThinkingLevel;\n };\n /**\n * Host-only filesystem locations owned by this extension (never mounted\n * into sandbox containers). Which one you use is a declaration: `dataDir`\n * for conversation-scoped state (the safe default — isolation for free),\n * `sharedDataDir` for deliberately cross-conversation state (you own tenant\n * partitioning and concurrency). See `LAYOUT.md`.\n */\n readonly paths: {\n /**\n * This conversation's private data directory\n * (`conversations/<conversationId>/extension-data/<slug>`), created on\n * first access. Default choice: co-located with the conversation, so it\n * disappears when the conversation is deleted.\n */\n readonly dataDir: string;\n /**\n * Data shared across all conversations this extension serves\n * (`global/extension-data/<slug>`), created on first access. Explicit\n * opt-in for multi-conversation applications (e.g. a PM tool with\n * cross-channel views); key rows by conversation id yourself.\n */\n readonly sharedDataDir: string;\n };\n /**\n * Read-only secrets from the embedder's vault\n * (mikan: `<stateDir>/vaults/extensions/<slug>/env`).\n */\n readonly secrets: {\n get(key: string): string | undefined;\n /** Secret names only, never values. */\n list(): string[];\n };\n /**\n * Named schedules owned by this extension + conversation. Backed by the\n * embedder's schedule store; in mikan these become event files that fire\n * autonomous agent runs (hot-reloaded, persisted across restarts).\n */\n readonly schedules: {\n /** Create or replace a named schedule. */\n upsert(name: string, spec: ExtensionScheduleSpec): Promise<void>;\n /** Delete a named schedule. Returns false when it did not exist. */\n delete(name: string): Promise<boolean>;\n /** Schedules owned by this extension in this conversation. */\n list(): Promise<ExtensionScheduleInfo[]>;\n };\n /** Fresh isolated subagent runs. */\n readonly subagent: SubagentApi;\n /**\n * Post text into a conversation without triggering an agent run. Defaults\n * to this conversation; pass `conversationId` to post elsewhere (pairs\n * with `sharedDataDir` for cross-conversation applications). Available\n * when the embedder provides platform messaging.\n */\n notify(text: string, options?: { conversationId?: string }): Promise<void>;\n /**\n * Add an emoji reaction to a message in this conversation. `messageTs` is\n * the platform message id the extension read from an event (see\n * `RunOrigin.messageTs`); `emoji` is a short name without colons.\n * Available when the embedder provides reaction support.\n */\n react(messageTs: string, emoji: string): Promise<void>;\n /**\n * Upload a host-side file into this conversation without an agent run.\n * Available when the embedder provides file uploads for the platform.\n */\n uploadFile(filePath: string, title?: string): Promise<void>;\n /**\n * Fire an autonomous agent run in this conversation as soon as possible.\n * Like a schedule, the run does not inherit conversation history — write\n * `text` self-contained. Backed by the embedder's schedule store.\n */\n triggerRun(text: string): Promise<void>;\n}\n\nexport type MikanExtensionActivate = (\n api: MikanExtensionApi,\n) => void | ExtensionDisposer | Promise<void | ExtensionDisposer>;\n\nexport interface MikanExtensionModule {\n name?: string;\n activate: MikanExtensionActivate;\n}\n\nexport interface LoadedExtension {\n name: string;\n path: string;\n /** Filesystem-safe identifier used for data dirs, secrets, and schedules. */\n slug: string;\n version?: string;\n description?: string;\n /** Skills discovered under the extension's `skills/` directory. */\n skills: MikanSkill[];\n}\n\nexport interface ExtensionLoadError {\n path: string;\n error: string;\n}\n"]}
|
package/dist/harness/index.d.ts
CHANGED
|
@@ -14,6 +14,6 @@ export { formatSkillsForPrompt, loadSkillsFromDir, parseFrontmatter, type LoadSk
|
|
|
14
14
|
export { DEFAULT_BUDGET_SETTINGS, DEFAULT_EVENT_BUDGET, DEFAULT_RETRY_SETTINGS, resolveHarnessSettings, type BudgetSettings, type CompactionSettings, type HarnessSettings, type RetrySettings, } from "./settings.js";
|
|
15
15
|
export { ExtensionRegistry, parseCommandInput } from "./extensions/registry.js";
|
|
16
16
|
export { defaultExtensionDirs, extensionSlug, listInstalledExtensions, loadExtensions, validateExtension, type ExtensionValidation, type InstalledExtensionInfo, type LoadExtensionsOptions, type LoadExtensionsResult, } from "./extensions/loader.js";
|
|
17
|
-
export type { AgentErrorHookEvent, BeforeAgentStartHookEvent, BeforeAgentStartHookResult, BudgetExceededHookEvent, ExtensionCommand, ExtensionCommandContext, ExtensionDisposer, ExtensionHostServices, ExtensionLoadError, ExtensionManifest, ExtensionScheduleInfo, ExtensionSchedulePayload, ExtensionScheduleSpec, ExtensionScheduleStore, LoadedExtension, MessageEndHookEvent, MikanExtensionActivate, MikanExtensionApi, MikanExtensionModule, MikanHookMap, MikanHookName, RunOrigin, SessionCompactHookEvent, ToolCallHookEvent, ToolCallHookResult, ToolResultHookEvent, ToolResultHookResult, TurnEndHookEvent, } from "./extensions/types.js";
|
|
18
|
-
export { CURRENT_SESSION_VERSION, type BranchSummaryEntry, type CompactionEntry, type CustomEntry, type CustomMessageEntry, type SessionContext, type SessionEntry, type SessionFileEntry, type SessionHeader, type SessionInfoEntry, type SessionMessageEntry, } from "./types.js";
|
|
17
|
+
export type { AgentErrorHookEvent, BeforeAgentStartHookEvent, BeforeAgentStartHookResult, BudgetExceededHookEvent, SubagentApi, ExtensionCommand, ExtensionCommandContext, ExtensionDisposer, ExtensionHostServices, ExtensionLoadError, ExtensionManifest, ExtensionScheduleInfo, ExtensionSchedulePayload, ExtensionScheduleSpec, ExtensionScheduleStore, LoadedExtension, MessageEndHookEvent, MikanExtensionActivate, MikanExtensionApi, MikanExtensionModule, MikanHookMap, MikanHookName, RunOrigin, SessionCompactHookEvent, ToolCallHookEvent, ToolCallHookResult, ToolResultHookEvent, ToolResultHookResult, TurnEndHookEvent, } from "./extensions/types.js";
|
|
18
|
+
export { type SubagentModelSpec, type SubagentRunBudget, type SubagentRunOutput, type SubagentRunRequest, type SubagentRunResult, type SubagentRunStatus, CURRENT_SESSION_VERSION, type BranchSummaryEntry, type CompactionEntry, type CustomEntry, type CustomMessageEntry, type SessionContext, type SessionEntry, type SessionFileEntry, type SessionHeader, type SessionInfoEntry, type SessionMessageEntry, } from "./types.js";
|
|
19
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EACL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,mBAAmB,EACnB,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,EACvB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,SAAS,EACT,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EACL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,mBAAmB,EACnB,yBAAyB,EACzB,0BAA0B,EAC1B,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,SAAS,EACT,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAiC,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EACL,iBAAiB,GAMlB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,GAIjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GAKvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,GAKlB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/harness/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAiC,MAAM,aAAa,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EACL,iBAAiB,GAMlB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,GAIjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,GAKvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EACL,oBAAoB,EACpB,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,iBAAiB,GAKlB,MAAM,wBAAwB,CAAC;AAgChC,OAAO,EAOL,uBAAuB,GAWxB,MAAM,YAAY,CAAC","sourcesContent":["/**\n * mikan agent harness.\n *\n * mikan's own harness engineering layer, built directly on pi-agent-core\n * (agent loop, compaction, context building) and pi-ai (providers, models,\n * auth). See `src/harness/README.md` for the architecture.\n */\nexport { FileCredentialStore, defaultAuthPath } from \"./auth.js\";\nexport {\n DEFAULT_HTTP_IDLE_TIMEOUT_MS,\n configureHttpDispatcher,\n parseHttpIdleTimeoutMs,\n} from \"./http.js\";\nexport { MikanModels, defaultModelsJsonPath, type CreateMikanModelsOptions } from \"./models.js\";\nexport { SessionStore, loadSessionFileEntries, parseSessionFileEntries } from \"./session-store.js\";\nexport {\n MikanAgentSession,\n type CompactionReason,\n type HarnessEvent,\n type HarnessEventListener,\n type MikanAgentSessionOptions,\n type PromptBlockedOutcome,\n} from \"./runner.js\";\nexport {\n formatSkillsForPrompt,\n loadSkillsFromDir,\n parseFrontmatter,\n type LoadSkillsResult,\n type MikanSkill,\n type SkillDiagnostic,\n} from \"./skills.js\";\nexport {\n DEFAULT_BUDGET_SETTINGS,\n DEFAULT_EVENT_BUDGET,\n DEFAULT_RETRY_SETTINGS,\n resolveHarnessSettings,\n type BudgetSettings,\n type CompactionSettings,\n type HarnessSettings,\n type RetrySettings,\n} from \"./settings.js\";\nexport { ExtensionRegistry, parseCommandInput } from \"./extensions/registry.js\";\nexport {\n defaultExtensionDirs,\n extensionSlug,\n listInstalledExtensions,\n loadExtensions,\n validateExtension,\n type ExtensionValidation,\n type InstalledExtensionInfo,\n type LoadExtensionsOptions,\n type LoadExtensionsResult,\n} from \"./extensions/loader.js\";\nexport type {\n AgentErrorHookEvent,\n BeforeAgentStartHookEvent,\n BeforeAgentStartHookResult,\n BudgetExceededHookEvent,\n SubagentApi,\n ExtensionCommand,\n ExtensionCommandContext,\n ExtensionDisposer,\n ExtensionHostServices,\n ExtensionLoadError,\n ExtensionManifest,\n ExtensionScheduleInfo,\n ExtensionSchedulePayload,\n ExtensionScheduleSpec,\n ExtensionScheduleStore,\n LoadedExtension,\n MessageEndHookEvent,\n MikanExtensionActivate,\n MikanExtensionApi,\n MikanExtensionModule,\n MikanHookMap,\n MikanHookName,\n RunOrigin,\n SessionCompactHookEvent,\n ToolCallHookEvent,\n ToolCallHookResult,\n ToolResultHookEvent,\n ToolResultHookResult,\n TurnEndHookEvent,\n} from \"./extensions/types.js\";\nexport {\n type SubagentModelSpec,\n type SubagentRunBudget,\n type SubagentRunOutput,\n type SubagentRunRequest,\n type SubagentRunResult,\n type SubagentRunStatus,\n CURRENT_SESSION_VERSION,\n type BranchSummaryEntry,\n type CompactionEntry,\n type CustomEntry,\n type CustomMessageEntry,\n type SessionContext,\n type SessionEntry,\n type SessionFileEntry,\n type SessionHeader,\n type SessionInfoEntry,\n type SessionMessageEntry,\n} from \"./types.js\";\n"]}
|
package/dist/harness/runner.d.ts
CHANGED
|
@@ -91,6 +91,14 @@ export declare class MikanAgentSession {
|
|
|
91
91
|
/** Conversation transcript currently held by the agent. */
|
|
92
92
|
get messages(): AgentMessage[];
|
|
93
93
|
get model(): Model<Api>;
|
|
94
|
+
/** Resource totals and terminal budget state from the most recent prompt. */
|
|
95
|
+
getLastRunStats(): Readonly<{
|
|
96
|
+
tokens: number;
|
|
97
|
+
costUsd: number;
|
|
98
|
+
llmCalls: number;
|
|
99
|
+
durationMs: number;
|
|
100
|
+
budgetExceededReason?: string;
|
|
101
|
+
}>;
|
|
94
102
|
subscribe(listener: HarnessEventListener): () => void;
|
|
95
103
|
/** Replace the agent transcript from the persisted session tree. */
|
|
96
104
|
reloadFromSession(): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/harness/runner.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/harness/runner.ts"],"names":[],"mappings":"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"}
|
package/dist/harness/runner.js
CHANGED
|
@@ -97,6 +97,16 @@ export class MikanAgentSession {
|
|
|
97
97
|
get model() {
|
|
98
98
|
return this.agent.state.model;
|
|
99
99
|
}
|
|
100
|
+
/** Resource totals and terminal budget state from the most recent prompt. */
|
|
101
|
+
getLastRunStats() {
|
|
102
|
+
return {
|
|
103
|
+
tokens: this.tally.tokens,
|
|
104
|
+
costUsd: this.tally.costUsd,
|
|
105
|
+
llmCalls: this.tally.llmCalls,
|
|
106
|
+
durationMs: this.tally.startedAt > 0 ? Date.now() - this.tally.startedAt : 0,
|
|
107
|
+
...(this.budgetExceededReason ? { budgetExceededReason: this.budgetExceededReason } : {}),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
100
110
|
subscribe(listener) {
|
|
101
111
|
this.listeners.add(listener);
|
|
102
112
|
return () => this.listeners.delete(listener);
|
|
@@ -232,7 +242,7 @@ export class MikanAgentSession {
|
|
|
232
242
|
}
|
|
233
243
|
if (message.role === "assistant") {
|
|
234
244
|
this.recordUsage(message);
|
|
235
|
-
await this.enforceBudget();
|
|
245
|
+
await this.enforceBudget(message);
|
|
236
246
|
if (message.stopReason !== "error") {
|
|
237
247
|
this.overflowRecoveryAttempted = false;
|
|
238
248
|
if (this.retryAttempt > 0) {
|
|
@@ -252,10 +262,10 @@ export class MikanAgentSession {
|
|
|
252
262
|
this.tally.costUsd += usage.cost?.total ?? 0;
|
|
253
263
|
}
|
|
254
264
|
/** Compare the tally against the run budget; abort the run when a cap is exceeded. */
|
|
255
|
-
async enforceBudget() {
|
|
265
|
+
async enforceBudget(message) {
|
|
256
266
|
if (this.budgetExceededReason)
|
|
257
267
|
return;
|
|
258
|
-
const reason = this.overBudgetReason();
|
|
268
|
+
const reason = this.overBudgetReason(message);
|
|
259
269
|
if (!reason)
|
|
260
270
|
return;
|
|
261
271
|
this.budgetExceededReason = reason;
|
|
@@ -280,9 +290,10 @@ export class MikanAgentSession {
|
|
|
280
290
|
log.logWarning("Run budget exceeded — aborting", reason);
|
|
281
291
|
this.agent.abort();
|
|
282
292
|
}
|
|
283
|
-
overBudgetReason() {
|
|
293
|
+
overBudgetReason(message) {
|
|
284
294
|
const { maxTokens, maxCostUsd, maxDurationMs, maxLlmCalls } = this.runBudget;
|
|
285
|
-
|
|
295
|
+
const needsAnotherCall = message.stopReason === "error" || message.content.some((part) => part.type === "toolCall");
|
|
296
|
+
if (needsAnotherCall && maxLlmCalls !== undefined && this.tally.llmCalls >= maxLlmCalls) {
|
|
286
297
|
return `${this.tally.llmCalls} LLM calls >= ${maxLlmCalls} limit`;
|
|
287
298
|
}
|
|
288
299
|
if (maxTokens !== undefined && this.tally.tokens >= maxTokens) {
|