@geminixiang/mikan 1.0.0-beta.4 → 1.0.0-beta.40
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 +688 -0
- package/README.md +99 -36
- package/dist/adapter.d.ts +11 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +18 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/bot.d.ts +6 -7
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +82 -117
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/context.d.ts +3 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +54 -215
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/github/bot.d.ts +89 -0
- package/dist/adapters/github/bot.d.ts.map +1 -0
- package/dist/adapters/github/bot.js +653 -0
- package/dist/adapters/github/bot.js.map +1 -0
- package/dist/adapters/github/client.d.ts +122 -0
- package/dist/adapters/github/client.d.ts.map +1 -0
- package/dist/adapters/github/client.js +314 -0
- package/dist/adapters/github/client.js.map +1 -0
- package/dist/adapters/github/cloudbuild.d.ts +19 -0
- package/dist/adapters/github/cloudbuild.d.ts.map +1 -0
- package/dist/adapters/github/cloudbuild.js +71 -0
- package/dist/adapters/github/cloudbuild.js.map +1 -0
- package/dist/adapters/github/context.d.ts +12 -0
- package/dist/adapters/github/context.d.ts.map +1 -0
- package/dist/adapters/github/context.js +101 -0
- package/dist/adapters/github/context.js.map +1 -0
- package/dist/adapters/github/gcp-auth.d.ts +28 -0
- package/dist/adapters/github/gcp-auth.d.ts.map +1 -0
- package/dist/adapters/github/gcp-auth.js +196 -0
- package/dist/adapters/github/gcp-auth.js.map +1 -0
- package/dist/adapters/github/github-ops.d.ts +91 -0
- package/dist/adapters/github/github-ops.d.ts.map +1 -0
- package/dist/adapters/github/github-ops.js +406 -0
- package/dist/adapters/github/github-ops.js.map +1 -0
- package/dist/adapters/github/ids.d.ts +34 -0
- package/dist/adapters/github/ids.d.ts.map +1 -0
- package/dist/adapters/github/ids.js +57 -0
- package/dist/adapters/github/ids.js.map +1 -0
- package/dist/adapters/github/repo.d.ts +33 -0
- package/dist/adapters/github/repo.d.ts.map +1 -0
- package/dist/adapters/github/repo.js +141 -0
- package/dist/adapters/github/repo.js.map +1 -0
- package/dist/adapters/github/tool-pack.d.ts +14 -0
- package/dist/adapters/github/tool-pack.d.ts.map +1 -0
- package/dist/adapters/github/tool-pack.js +56 -0
- package/dist/adapters/github/tool-pack.js.map +1 -0
- package/dist/adapters/github/tools/checks.d.ts +19 -0
- package/dist/adapters/github/tools/checks.d.ts.map +1 -0
- package/dist/adapters/github/tools/checks.js +105 -0
- package/dist/adapters/github/tools/checks.js.map +1 -0
- package/dist/adapters/github/tools/issue.d.ts +21 -0
- package/dist/adapters/github/tools/issue.d.ts.map +1 -0
- package/dist/adapters/github/tools/issue.js +48 -0
- package/dist/adapters/github/tools/issue.js.map +1 -0
- package/dist/adapters/github/tools/pr.d.ts +22 -0
- package/dist/adapters/github/tools/pr.d.ts.map +1 -0
- package/dist/adapters/github/tools/pr.js +48 -0
- package/dist/adapters/github/tools/pr.js.map +1 -0
- package/dist/adapters/github/tools/read.d.ts +21 -0
- package/dist/adapters/github/tools/read.d.ts.map +1 -0
- package/dist/adapters/github/tools/read.js +141 -0
- package/dist/adapters/github/tools/read.js.map +1 -0
- package/dist/adapters/github/tools/review-reply.d.ts +17 -0
- package/dist/adapters/github/tools/review-reply.d.ts.map +1 -0
- package/dist/adapters/github/tools/review-reply.js +38 -0
- package/dist/adapters/github/tools/review-reply.js.map +1 -0
- package/dist/adapters/github/tools/sync.d.ts +17 -0
- package/dist/adapters/github/tools/sync.d.ts.map +1 -0
- package/dist/adapters/github/tools/sync.js +34 -0
- package/dist/adapters/github/tools/sync.js.map +1 -0
- package/dist/adapters/github/types.d.ts +373 -0
- package/dist/adapters/github/types.d.ts.map +1 -0
- package/dist/adapters/github/types.js +2 -0
- package/dist/adapters/github/types.js.map +1 -0
- package/dist/adapters/intake.d.ts +16 -5
- package/dist/adapters/intake.d.ts.map +1 -1
- package/dist/adapters/intake.js +86 -23
- package/dist/adapters/intake.js.map +1 -1
- package/dist/adapters/progressive-renderer.d.ts +7 -0
- package/dist/adapters/progressive-renderer.d.ts.map +1 -0
- package/dist/adapters/progressive-renderer.js +383 -0
- package/dist/adapters/progressive-renderer.js.map +1 -0
- package/dist/adapters/shared.d.ts +23 -10
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/shared.js +60 -22
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/slack/blocks.d.ts +14 -0
- package/dist/adapters/slack/blocks.d.ts.map +1 -1
- package/dist/adapters/slack/blocks.js +147 -111
- package/dist/adapters/slack/blocks.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +43 -13
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +385 -207
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts +3 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +11 -17
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
- package/dist/adapters/slack/response-lifecycle.js +126 -323
- package/dist/adapters/slack/response-lifecycle.js.map +1 -1
- package/dist/adapters/slack/session.d.ts.map +1 -1
- package/dist/adapters/slack/session.js +7 -11
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/tool-pack.d.ts +11 -0
- package/dist/adapters/slack/tool-pack.d.ts.map +1 -0
- package/dist/adapters/slack/tool-pack.js +45 -0
- package/dist/adapters/slack/tool-pack.js.map +1 -0
- package/dist/adapters/slack/tools/attach.js +1 -1
- package/dist/adapters/slack/tools/attach.js.map +1 -1
- package/dist/adapters/slack/tools/blockkit.d.ts +14 -0
- package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -0
- package/dist/adapters/slack/tools/blockkit.js +106 -0
- package/dist/adapters/slack/tools/blockkit.js.map +1 -0
- package/dist/adapters/slack/types.d.ts +40 -2
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/adapters/telegram/bot.d.ts +8 -9
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +90 -117
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts +2 -0
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +61 -184
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/telegram/html.d.ts.map +1 -1
- package/dist/adapters/telegram/html.js +10 -7
- package/dist/adapters/telegram/html.js.map +1 -1
- package/dist/adapters/types.d.ts +109 -12
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/agent-events.d.ts +3 -2
- package/dist/agent-events.d.ts.map +1 -1
- package/dist/agent-events.js +19 -1
- package/dist/agent-events.js.map +1 -1
- package/dist/agent.d.ts +14 -19
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +840 -298
- package/dist/agent.js.map +1 -1
- package/dist/cli/arg-grammar.d.ts +25 -0
- package/dist/cli/arg-grammar.d.ts.map +1 -0
- package/dist/cli/arg-grammar.js +61 -0
- package/dist/cli/arg-grammar.js.map +1 -0
- package/dist/cli/boot.d.ts +5 -0
- package/dist/cli/boot.d.ts.map +1 -0
- package/dist/cli/boot.js +117 -0
- package/dist/cli/boot.js.map +1 -0
- package/dist/cli/download.d.ts.map +1 -0
- package/dist/{download.js → cli/download.js} +2 -0
- package/dist/cli/download.js.map +1 -0
- package/dist/cli/ext-dev.d.ts +2 -0
- package/dist/cli/ext-dev.d.ts.map +1 -0
- package/dist/cli/ext-dev.js +188 -0
- package/dist/cli/ext-dev.js.map +1 -0
- package/dist/cli/ext.d.ts +2 -0
- package/dist/cli/ext.d.ts.map +1 -0
- package/dist/cli/ext.js +324 -0
- package/dist/cli/ext.js.map +1 -0
- package/dist/cli/office.d.ts +2 -0
- package/dist/cli/office.d.ts.map +1 -0
- package/dist/cli/office.js +91 -0
- package/dist/cli/office.js.map +1 -0
- package/dist/cli/types.d.ts +16 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +2 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +3 -2
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/auto-reply.d.ts.map +1 -1
- package/dist/commands/auto-reply.js +5 -9
- package/dist/commands/auto-reply.js.map +1 -1
- package/dist/commands/extensions.d.ts.map +1 -1
- package/dist/commands/extensions.js +9 -6
- package/dist/commands/extensions.js.map +1 -1
- package/dist/commands/login.d.ts +2 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +40 -5
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/manifest.d.ts +37 -0
- package/dist/commands/manifest.d.ts.map +1 -0
- package/dist/commands/manifest.js +151 -0
- package/dist/commands/manifest.js.map +1 -0
- package/dist/commands/model.d.ts +2 -3
- package/dist/commands/model.d.ts.map +1 -1
- package/dist/commands/model.js +63 -24
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/new.d.ts.map +1 -1
- package/dist/commands/new.js +15 -3
- package/dist/commands/new.js.map +1 -1
- package/dist/commands/registry.d.ts +2 -2
- package/dist/commands/registry.d.ts.map +1 -1
- package/dist/commands/registry.js +1 -2
- package/dist/commands/registry.js.map +1 -1
- package/dist/commands/sandbox.d.ts.map +1 -1
- package/dist/commands/sandbox.js +83 -33
- package/dist/commands/sandbox.js.map +1 -1
- package/dist/commands/session-view.d.ts.map +1 -1
- package/dist/commands/session-view.js +6 -3
- package/dist/commands/session-view.js.map +1 -1
- package/dist/commands/types.d.ts +79 -7
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/config.d.ts +23 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +222 -135
- package/dist/config.js.map +1 -1
- package/dist/env-manifest.d.ts +30 -0
- package/dist/env-manifest.d.ts.map +1 -0
- package/dist/env-manifest.js +229 -0
- package/dist/env-manifest.js.map +1 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +20 -81
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +7 -8
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +106 -110
- package/dist/execution-resolver.js.map +1 -1
- package/dist/extension-schedules.d.ts +31 -0
- package/dist/extension-schedules.d.ts.map +1 -0
- package/dist/extension-schedules.js +229 -0
- package/dist/extension-schedules.js.map +1 -0
- package/dist/harness/auth.d.ts +2 -1
- package/dist/harness/auth.d.ts.map +1 -1
- package/dist/harness/auth.js +11 -5
- package/dist/harness/auth.js.map +1 -1
- package/dist/harness/event-format.d.ts +27 -0
- package/dist/harness/event-format.d.ts.map +1 -0
- package/dist/harness/event-format.js +160 -0
- package/dist/harness/event-format.js.map +1 -0
- package/dist/harness/extensions/loader.d.ts +27 -49
- package/dist/harness/extensions/loader.d.ts.map +1 -1
- package/dist/harness/extensions/loader.js +486 -130
- package/dist/harness/extensions/loader.js.map +1 -1
- package/dist/harness/extensions/registry.d.ts +107 -2
- package/dist/harness/extensions/registry.d.ts.map +1 -1
- package/dist/harness/extensions/registry.js +316 -0
- package/dist/harness/extensions/registry.js.map +1 -1
- package/dist/harness/extensions/types.d.ts +482 -42
- 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 +18 -8
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +7 -4
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/models.d.ts +7 -4
- package/dist/harness/models.d.ts.map +1 -1
- package/dist/harness/models.js +46 -24
- package/dist/harness/models.js.map +1 -1
- package/dist/harness/runner.d.ts +50 -54
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +232 -46
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session-store.d.ts +11 -5
- package/dist/harness/session-store.d.ts.map +1 -1
- package/dist/harness/session-store.js +141 -36
- package/dist/harness/session-store.js.map +1 -1
- package/dist/harness/settings.d.ts +2 -20
- package/dist/harness/settings.d.ts.map +1 -1
- package/dist/harness/settings.js +12 -1
- package/dist/harness/settings.js.map +1 -1
- package/dist/harness/skills.d.ts +10 -29
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +48 -6
- package/dist/harness/skills.js.map +1 -1
- package/dist/harness/subagent-profiles.d.ts +8 -0
- package/dist/harness/subagent-profiles.d.ts.map +1 -0
- package/dist/harness/subagent-profiles.js +299 -0
- package/dist/harness/subagent-profiles.js.map +1 -0
- package/dist/harness/subagent-runner.d.ts +39 -0
- package/dist/harness/subagent-runner.d.ts.map +1 -0
- package/dist/harness/subagent-runner.js +617 -0
- package/dist/harness/subagent-runner.js.map +1 -0
- package/dist/harness/types.d.ts +267 -1
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/usage.d.ts +6 -0
- package/dist/harness/usage.d.ts.map +1 -0
- package/dist/harness/usage.js +32 -0
- package/dist/harness/usage.js.map +1 -0
- package/dist/index.d.ts +36 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -6
- package/dist/index.js.map +1 -1
- package/dist/main.js +391 -127
- package/dist/main.js.map +1 -1
- package/dist/observability/instrument.js +7 -5
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/sentry.d.ts +2 -0
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +10 -2
- package/dist/observability/sentry.js.map +1 -1
- package/dist/office/address.d.ts +31 -0
- package/dist/office/address.d.ts.map +1 -0
- package/dist/office/address.js +113 -0
- package/dist/office/address.js.map +1 -0
- package/dist/office/index.d.ts +11 -0
- package/dist/office/index.d.ts.map +1 -0
- package/dist/office/index.js +11 -0
- package/dist/office/index.js.map +1 -0
- package/dist/office/layout.d.ts +27 -0
- package/dist/office/layout.d.ts.map +1 -0
- package/dist/office/layout.js +97 -0
- package/dist/office/layout.js.map +1 -0
- package/dist/office/migration.d.ts +44 -0
- package/dist/office/migration.d.ts.map +1 -0
- package/dist/office/migration.js +255 -0
- package/dist/office/migration.js.map +1 -0
- package/dist/office/registry.d.ts +75 -0
- package/dist/office/registry.d.ts.map +1 -0
- package/dist/office/registry.js +646 -0
- package/dist/office/registry.js.map +1 -0
- package/dist/office/types.d.ts +71 -0
- package/dist/office/types.d.ts.map +1 -0
- package/dist/office/types.js +2 -0
- package/dist/office/types.js.map +1 -0
- package/dist/packages/admin.d.ts +17 -0
- package/dist/packages/admin.d.ts.map +1 -0
- package/dist/packages/admin.js +98 -0
- package/dist/packages/admin.js.map +1 -0
- package/dist/packages/index.d.ts +6 -0
- package/dist/packages/index.d.ts.map +1 -0
- package/dist/packages/index.js +6 -0
- package/dist/packages/index.js.map +1 -0
- package/dist/packages/inspect.d.ts +11 -0
- package/dist/packages/inspect.d.ts.map +1 -0
- package/dist/packages/inspect.js +98 -0
- package/dist/packages/inspect.js.map +1 -0
- package/dist/packages/materialize.d.ts +40 -0
- package/dist/packages/materialize.d.ts.map +1 -0
- package/dist/packages/materialize.js +297 -0
- package/dist/packages/materialize.js.map +1 -0
- package/dist/packages/resolve.d.ts +25 -0
- package/dist/packages/resolve.d.ts.map +1 -0
- package/dist/packages/resolve.js +208 -0
- package/dist/packages/resolve.js.map +1 -0
- package/dist/packages/source.d.ts +39 -0
- package/dist/packages/source.d.ts.map +1 -0
- package/dist/packages/source.js +189 -0
- package/dist/packages/source.js.map +1 -0
- package/dist/packages/types.d.ts +104 -0
- package/dist/packages/types.d.ts.map +1 -0
- package/dist/packages/types.js +2 -0
- package/dist/packages/types.js.map +1 -0
- package/dist/provisioner.d.ts +66 -0
- package/dist/provisioner.d.ts.map +1 -1
- package/dist/provisioner.js +335 -13
- package/dist/provisioner.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +562 -118
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +38 -0
- package/dist/runtime/session-lifecycle.d.ts.map +1 -0
- package/dist/runtime/session-lifecycle.js +193 -0
- package/dist/runtime/session-lifecycle.js.map +1 -0
- package/dist/runtime/types.d.ts +66 -7
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +3 -0
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +13 -1
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +4 -0
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +13 -3
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +3 -0
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +13 -2
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/gondolin.d.ts +57 -0
- package/dist/sandbox/gondolin.d.ts.map +1 -0
- package/dist/sandbox/gondolin.js +764 -0
- package/dist/sandbox/gondolin.js.map +1 -0
- package/dist/sandbox/host.d.ts +3 -0
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +18 -3
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/identity.d.ts +44 -0
- package/dist/sandbox/identity.d.ts.map +1 -0
- package/dist/sandbox/identity.js +68 -0
- package/dist/sandbox/identity.js.map +1 -0
- package/dist/sandbox/image.d.ts.map +1 -1
- package/dist/sandbox/image.js +2 -0
- package/dist/sandbox/image.js.map +1 -1
- package/dist/sandbox/index.d.ts +17 -4
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +37 -3
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/types.d.ts +65 -1
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/utils.d.ts +14 -0
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +68 -1
- package/dist/sandbox/utils.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +25 -0
- package/dist/sessions/chat-history-sync.d.ts.map +1 -0
- package/dist/sessions/{agent-memory-file-manager.js → chat-history-sync.js} +135 -131
- package/dist/sessions/chat-history-sync.js.map +1 -0
- package/dist/sessions/conversation-log.d.ts +9 -0
- package/dist/sessions/conversation-log.d.ts.map +1 -0
- package/dist/sessions/conversation-log.js +50 -0
- package/dist/sessions/conversation-log.js.map +1 -0
- package/dist/sessions/history-line.d.ts +29 -0
- package/dist/sessions/history-line.d.ts.map +1 -0
- package/dist/sessions/history-line.js +45 -0
- package/dist/sessions/history-line.js.map +1 -0
- package/dist/sessions/rotation.d.ts +2 -0
- package/dist/sessions/rotation.d.ts.map +1 -0
- package/dist/sessions/rotation.js +39 -0
- package/dist/sessions/rotation.js.map +1 -0
- package/dist/sessions/session-key.d.ts +33 -0
- package/dist/sessions/session-key.d.ts.map +1 -0
- package/dist/sessions/session-key.js +115 -0
- package/dist/sessions/session-key.js.map +1 -0
- package/dist/sessions/store.d.ts +15 -7
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +127 -36
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +19 -5
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings-mutation.d.ts +40 -0
- package/dist/settings-mutation.d.ts.map +1 -0
- package/dist/settings-mutation.js +61 -0
- package/dist/settings-mutation.js.map +1 -0
- package/dist/subagent-progress.d.ts +43 -0
- package/dist/subagent-progress.d.ts.map +1 -0
- package/dist/subagent-progress.js +220 -0
- package/dist/subagent-progress.js.map +1 -0
- package/dist/tools/bash.d.ts +3 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +26 -18
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +14 -13
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/event.d.ts +1 -1
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js +58 -45
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/generate-image.d.ts +23 -0
- package/dist/tools/generate-image.d.ts.map +1 -0
- package/dist/tools/generate-image.js +65 -0
- package/dist/tools/generate-image.js.map +1 -0
- package/dist/tools/host-fn-tool.d.ts +21 -0
- package/dist/tools/host-fn-tool.d.ts.map +1 -0
- package/dist/tools/host-fn-tool.js +32 -0
- package/dist/tools/host-fn-tool.js.map +1 -0
- package/dist/tools/index.d.ts +19 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +25 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/react.d.ts +15 -0
- package/dist/tools/react.d.ts.map +1 -0
- package/dist/tools/react.js +29 -0
- package/dist/tools/react.js.map +1 -0
- package/dist/tools/read.d.ts +1 -0
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +39 -33
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/sandbox.d.ts +2 -2
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +14 -9
- package/dist/tools/sandbox.js.map +1 -1
- package/dist/tools/subagent-slots.d.ts +28 -0
- package/dist/tools/subagent-slots.d.ts.map +1 -0
- package/dist/tools/subagent-slots.js +72 -0
- package/dist/tools/subagent-slots.js.map +1 -0
- package/dist/tools/subagent.d.ts +54 -0
- package/dist/tools/subagent.d.ts.map +1 -0
- package/dist/tools/subagent.js +411 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/tools/types.d.ts +40 -32
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +2 -8
- package/dist/tools/write.js.map +1 -1
- package/dist/trigger.d.ts +2 -1
- package/dist/trigger.d.ts.map +1 -1
- package/dist/trigger.js +6 -9
- package/dist/trigger.js.map +1 -1
- package/dist/types.d.ts +403 -59
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/file-guards.d.ts +9 -0
- package/dist/utils/file-guards.d.ts.map +1 -1
- package/dist/utils/file-guards.js +44 -1
- package/dist/utils/file-guards.js.map +1 -1
- package/dist/vault/disabled.d.ts +9 -0
- package/dist/vault/disabled.d.ts.map +1 -0
- package/dist/vault/disabled.js +25 -0
- package/dist/vault/disabled.js.map +1 -0
- package/dist/vault/index.d.ts +45 -2
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +127 -36
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/types.d.ts +6 -2
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/dist/web/admin/portal.d.ts +31 -3
- package/dist/web/admin/portal.d.ts.map +1 -1
- package/dist/web/admin/portal.js +846 -345
- package/dist/web/admin/portal.js.map +1 -1
- package/dist/web/admin/provider-models.js +1 -1
- package/dist/web/admin/provider-models.js.map +1 -1
- package/dist/web/admin/types.d.ts +23 -3
- package/dist/web/admin/types.d.ts.map +1 -1
- package/dist/web/admin/types.js.map +1 -1
- package/dist/web/login/oauth.d.ts +2 -3
- package/dist/web/login/oauth.d.ts.map +1 -1
- package/dist/web/login/oauth.js +1 -32
- package/dist/web/login/oauth.js.map +1 -1
- package/dist/web/login/portal.d.ts +1 -1
- package/dist/web/login/portal.d.ts.map +1 -1
- package/dist/web/login/portal.js +13 -36
- package/dist/web/login/portal.js.map +1 -1
- package/dist/web/login/types.d.ts +0 -11
- package/dist/web/login/types.d.ts.map +1 -1
- package/dist/web/login/types.js.map +1 -1
- package/dist/web/portal-shell.d.ts +21 -0
- package/dist/web/portal-shell.d.ts.map +1 -0
- package/dist/{portal-shell.js → web/portal-shell.js} +67 -2
- package/dist/web/portal-shell.js.map +1 -0
- package/dist/web/server.d.ts +3 -2
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +11 -4
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-view/portal.d.ts +1 -1
- package/dist/web/session-view/portal.d.ts.map +1 -1
- package/dist/web/session-view/portal.js +37 -28
- package/dist/web/session-view/portal.js.map +1 -1
- package/dist/web/session-view/service.d.ts +1 -1
- package/dist/web/session-view/service.d.ts.map +1 -1
- package/dist/web/session-view/service.js +61 -18
- package/dist/web/session-view/service.js.map +1 -1
- package/dist/web/session-view/types.d.ts +0 -3
- package/dist/web/session-view/types.d.ts.map +1 -1
- package/dist/web/session-view/types.js.map +1 -1
- package/dist/web/token-store.js +1 -1
- package/dist/web/token-store.js.map +1 -1
- package/dist/workspace-projection/index.d.ts +10 -0
- package/dist/workspace-projection/index.d.ts.map +1 -0
- package/dist/workspace-projection/index.js +120 -0
- package/dist/workspace-projection/index.js.map +1 -0
- package/dist/workspace-projection/types.d.ts +16 -0
- package/dist/workspace-projection/types.d.ts.map +1 -0
- package/dist/workspace-projection/types.js +2 -0
- package/dist/workspace-projection/types.js.map +1 -0
- package/package.json +67 -37
- package/dist/adapters/streaming.d.ts +0 -18
- package/dist/adapters/streaming.d.ts.map +0 -1
- package/dist/adapters/streaming.js +0 -44
- package/dist/adapters/streaming.js.map +0 -1
- package/dist/commands/parse.d.ts +0 -7
- package/dist/commands/parse.d.ts.map +0 -1
- package/dist/commands/parse.js +0 -14
- package/dist/commands/parse.js.map +0 -1
- package/dist/download.d.ts.map +0 -1
- package/dist/download.js.map +0 -1
- package/dist/model-registry.d.ts +0 -4
- package/dist/model-registry.d.ts.map +0 -1
- package/dist/model-registry.js +0 -7
- package/dist/model-registry.js.map +0 -1
- package/dist/portal-shell.d.ts +0 -4
- package/dist/portal-shell.d.ts.map +0 -1
- package/dist/portal-shell.js.map +0 -1
- package/dist/runtime/agent-run-controller.d.ts +0 -31
- package/dist/runtime/agent-run-controller.d.ts.map +0 -1
- package/dist/runtime/agent-run-controller.js +0 -195
- package/dist/runtime/agent-run-controller.js.map +0 -1
- package/dist/sandbox/path-context.d.ts +0 -3
- package/dist/sandbox/path-context.d.ts.map +0 -1
- package/dist/sandbox/path-context.js +0 -20
- package/dist/sandbox/path-context.js.map +0 -1
- package/dist/sessions/agent-memory-file-manager.d.ts +0 -19
- package/dist/sessions/agent-memory-file-manager.d.ts.map +0 -1
- package/dist/sessions/agent-memory-file-manager.js.map +0 -1
- package/dist/sessions/metadata.d.ts +0 -3
- package/dist/sessions/metadata.d.ts.map +0 -1
- package/dist/sessions/metadata.js +0 -11
- package/dist/sessions/metadata.js.map +0 -1
- package/dist/sessions/policy.d.ts +0 -6
- package/dist/sessions/policy.d.ts.map +0 -1
- package/dist/sessions/policy.js +0 -23
- package/dist/sessions/policy.js.map +0 -1
- package/dist/store.d.ts +0 -46
- package/dist/store.d.ts.map +0 -1
- package/dist/store.js +0 -177
- package/dist/store.js.map +0 -1
- package/dist/tools/truncate.d.ts +0 -33
- package/dist/tools/truncate.d.ts.map +0 -1
- package/dist/tools/truncate.js +0 -184
- package/dist/tools/truncate.js.map +0 -1
- package/dist/utils/date.d.ts +0 -10
- package/dist/utils/date.d.ts.map +0 -1
- package/dist/utils/date.js +0 -23
- package/dist/utils/date.js.map +0 -1
- package/dist/utils/env.d.ts +0 -3
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/env.js +0 -12
- package/dist/utils/env.js.map +0 -1
- package/dist/utils/fs-atomic.d.ts +0 -10
- package/dist/utils/fs-atomic.d.ts.map +0 -1
- package/dist/utils/fs-atomic.js +0 -45
- package/dist/utils/fs-atomic.js.map +0 -1
- package/dist/utils/html.d.ts +0 -2
- package/dist/utils/html.d.ts.map +0 -1
- package/dist/utils/html.js +0 -4
- package/dist/utils/html.js.map +0 -1
- package/dist/utils/http-body.d.ts +0 -10
- package/dist/utils/http-body.d.ts.map +0 -1
- package/dist/utils/http-body.js +0 -34
- package/dist/utils/http-body.js.map +0 -1
- package/dist/vault/routing.d.ts +0 -3
- package/dist/vault/routing.d.ts.map +0 -1
- package/dist/vault/routing.js +0 -13
- package/dist/vault/routing.js.map +0 -1
- package/dist/web/agent-events/portal.d.ts +0 -3
- package/dist/web/agent-events/portal.d.ts.map +0 -1
- package/dist/web/agent-events/portal.js +0 -18
- package/dist/web/agent-events/portal.js.map +0 -1
- package/dist/web/request.d.ts +0 -3
- package/dist/web/request.d.ts.map +0 -1
- package/dist/web/request.js +0 -13
- package/dist/web/request.js.map +0 -1
- package/dist/web/session-view/command.d.ts +0 -4
- package/dist/web/session-view/command.d.ts.map +0 -1
- package/dist/web/session-view/command.js +0 -7
- package/dist/web/session-view/command.js.map +0 -1
- /package/dist/{download.d.ts → cli/download.d.ts} +0 -0
|
@@ -12,31 +12,50 @@
|
|
|
12
12
|
* under mikan's state dir.
|
|
13
13
|
*
|
|
14
14
|
* Directories are scanned in order; all discovered extensions activate.
|
|
15
|
-
* Accepted layouts:
|
|
15
|
+
* Accepted layouts (entrypoint may be .mjs/.js/.ts/.mts — loaded via jiti):
|
|
16
16
|
*
|
|
17
|
-
* - `extensions/<name
|
|
18
|
-
* - `extensions/<name>/index
|
|
17
|
+
* - `extensions/<name>.<ext>` (bare file)
|
|
18
|
+
* - `extensions/<name>/index.<ext>` (directory + index)
|
|
19
|
+
* - `extensions/<name>/package.json` (mikan.extensions entrypoint;
|
|
20
|
+
* may carry npm dependencies in node_modules)
|
|
19
21
|
*
|
|
20
|
-
* Modules are imported with a cache
|
|
21
|
-
* picked up when a new harness instance is created
|
|
22
|
+
* Modules are imported with a fresh jiti instance (no cache) so edited
|
|
23
|
+
* extensions are picked up when a new harness instance is created.
|
|
22
24
|
*/
|
|
23
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "fs";
|
|
24
|
-
import { homedir } from "os";
|
|
25
|
-
import { basename,
|
|
26
|
-
import {
|
|
25
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
26
|
+
import { homedir } from "node:os";
|
|
27
|
+
import { basename, join } from "node:path";
|
|
28
|
+
import { createJiti } from "jiti";
|
|
27
29
|
import * as log from "../../log.js";
|
|
30
|
+
import { buildEventPayload } from "../event-format.js";
|
|
28
31
|
import { loadSkillsFromDir } from "../skills.js";
|
|
29
|
-
import { ExtensionRegistry } from "./registry.js";
|
|
30
|
-
|
|
32
|
+
import { ExtensionRegistry, namespaceActionIds } from "./registry.js";
|
|
33
|
+
import { officeStateDir } from "../../office/index.js";
|
|
34
|
+
const EXTENSION_FILE_PATTERN = /\.(mjs|js|ts|mts)$/;
|
|
35
|
+
const INDEX_FILE_PATTERN = /^index\.(mjs|js|ts|mts)$/;
|
|
36
|
+
const INDEX_CANDIDATES = ["index.mjs", "index.js", "index.ts", "index.mts"];
|
|
31
37
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* take that value.
|
|
38
|
+
* Import an extension entrypoint through jiti so it can be TypeScript and can
|
|
39
|
+
* use node_modules dependencies, transparently compiling on the fly. A fresh
|
|
40
|
+
* jiti instance with caching disabled is used per load so edited extensions
|
|
41
|
+
* are picked up when a new harness instance is created for a conversation.
|
|
37
42
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
43
|
+
async function importExtensionModule(entrypoint) {
|
|
44
|
+
const jiti = createJiti(import.meta.url, { moduleCache: false, fsCache: false });
|
|
45
|
+
return jiti.import(entrypoint);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Canonical host-only extension code directories for a conversation, in load
|
|
49
|
+
* order: `<stateDir>/global/extensions` (all conversations) then
|
|
50
|
+
* `<stateDir>/conversations/<office key>/extensions` (that conversation
|
|
51
|
+
* only). `global` and `conversations` are the two sibling scopes; see
|
|
52
|
+
* `LAYOUT.md`.
|
|
53
|
+
*/
|
|
54
|
+
export function defaultExtensionDirs(address, stateDir = join(homedir(), ".mikan")) {
|
|
55
|
+
return [
|
|
56
|
+
join(stateDir, "global", "extensions"),
|
|
57
|
+
join(officeStateDir(stateDir, address), "extensions"),
|
|
58
|
+
];
|
|
40
59
|
}
|
|
41
60
|
/**
|
|
42
61
|
* List installed extensions without importing or activating them — safe for
|
|
@@ -46,9 +65,9 @@ export function defaultExtensionDirs(conversationId, stateDir = join(homedir(),
|
|
|
46
65
|
export function listInstalledExtensions(dirs) {
|
|
47
66
|
const infos = [];
|
|
48
67
|
for (const dir of dirs) {
|
|
49
|
-
for (const entrypoint of discoverExtensionEntrypoints(dir)) {
|
|
50
|
-
const slug = extensionSlug(
|
|
51
|
-
const manifest = readManifest(
|
|
68
|
+
for (const { entrypoint, rootDir } of discoverExtensionEntrypoints(dir)) {
|
|
69
|
+
const slug = extensionSlug(rootDir);
|
|
70
|
+
const manifest = readManifest(rootDir);
|
|
52
71
|
infos.push({
|
|
53
72
|
name: manifest.name ?? slug,
|
|
54
73
|
slug,
|
|
@@ -56,7 +75,8 @@ export function listInstalledExtensions(dirs) {
|
|
|
56
75
|
dir,
|
|
57
76
|
version: manifest.version,
|
|
58
77
|
description: manifest.description,
|
|
59
|
-
skillNames: loadExtensionSkills(
|
|
78
|
+
skillNames: loadExtensionSkills(rootDir, slug).map((skill) => skill.name),
|
|
79
|
+
secrets: manifest.secrets ?? [],
|
|
60
80
|
});
|
|
61
81
|
}
|
|
62
82
|
}
|
|
@@ -65,11 +85,11 @@ export function listInstalledExtensions(dirs) {
|
|
|
65
85
|
function discoverExtensionEntrypoints(dir) {
|
|
66
86
|
if (!existsSync(dir))
|
|
67
87
|
return [];
|
|
68
|
-
const
|
|
88
|
+
const found = [];
|
|
69
89
|
for (const name of readdirSync(dir).toSorted()) {
|
|
70
90
|
if (name.startsWith("."))
|
|
71
91
|
continue;
|
|
72
|
-
if (
|
|
92
|
+
if (INDEX_FILE_PATTERN.test(name)) {
|
|
73
93
|
// An index file at the scan root means the extension's contents were
|
|
74
94
|
// copied into the scope directory itself; the slug would degenerate to
|
|
75
95
|
// the scope name (e.g. the conversation id), mis-keying its data dir,
|
|
@@ -86,55 +106,150 @@ function discoverExtensionEntrypoints(dir) {
|
|
|
86
106
|
continue;
|
|
87
107
|
}
|
|
88
108
|
if (stats.isFile() && EXTENSION_FILE_PATTERN.test(name)) {
|
|
89
|
-
|
|
109
|
+
// Bare-file form: the file is both entrypoint and (its own) root.
|
|
110
|
+
found.push({ entrypoint: fullPath, rootDir: fullPath, slug: extensionSlug(fullPath) });
|
|
90
111
|
continue;
|
|
91
112
|
}
|
|
92
113
|
if (stats.isDirectory()) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
entrypoints.push(indexPath);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
114
|
+
const entrypoint = resolveDirectoryEntrypoint(fullPath);
|
|
115
|
+
if (entrypoint) {
|
|
116
|
+
found.push({ entrypoint, rootDir: fullPath, slug: extensionSlug(fullPath) });
|
|
99
117
|
}
|
|
100
118
|
}
|
|
101
119
|
}
|
|
102
|
-
return
|
|
120
|
+
return found;
|
|
103
121
|
}
|
|
104
122
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
123
|
+
* Resolve a directory-form extension's entrypoint. A `package.json` with a
|
|
124
|
+
* `mikan.extensions` array (first entry, relative to the dir) wins — this is
|
|
125
|
+
* how an extension declares a TypeScript entry and pulls in npm dependencies.
|
|
126
|
+
* Otherwise fall back to an `index.{mjs,js,ts,mts}` file. Returns undefined
|
|
127
|
+
* when neither is present.
|
|
110
128
|
*/
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
function resolveDirectoryEntrypoint(dir) {
|
|
130
|
+
const declared = readMikanManifestEntrypoints(dir)[0];
|
|
131
|
+
if (declared) {
|
|
132
|
+
const resolved = join(dir, declared);
|
|
133
|
+
if (existsSync(resolved))
|
|
134
|
+
return resolved;
|
|
135
|
+
log.logWarning(`Extension package.json declares a missing entrypoint: ${resolved}`, "falling back to an index file");
|
|
136
|
+
}
|
|
137
|
+
for (const candidate of INDEX_CANDIDATES) {
|
|
138
|
+
const indexPath = join(dir, candidate);
|
|
139
|
+
if (existsSync(indexPath))
|
|
140
|
+
return indexPath;
|
|
141
|
+
}
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
const SECRET_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
145
|
+
/** Shape one `mikan.secrets` entry defensively; undefined when unusable. */
|
|
146
|
+
function readSecretDeclaration(entry) {
|
|
147
|
+
if (!entry || typeof entry !== "object")
|
|
148
|
+
return undefined;
|
|
149
|
+
const record = entry;
|
|
150
|
+
if (typeof record.key !== "string" || !SECRET_KEY_PATTERN.test(record.key))
|
|
151
|
+
return undefined;
|
|
152
|
+
return {
|
|
153
|
+
key: record.key,
|
|
154
|
+
...(typeof record.description === "string" ? { description: record.description } : {}),
|
|
155
|
+
...(typeof record.required === "boolean" ? { required: record.required } : {}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/** Read and shape a directory's package.json; undefined when absent/malformed. */
|
|
159
|
+
function readPackageJson(dir) {
|
|
160
|
+
const packageJsonPath = join(dir, "package.json");
|
|
161
|
+
if (!existsSync(packageJsonPath))
|
|
162
|
+
return undefined;
|
|
163
|
+
try {
|
|
164
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
165
|
+
if (!parsed || typeof parsed !== "object")
|
|
166
|
+
return undefined;
|
|
167
|
+
const record = parsed;
|
|
168
|
+
const mikanRaw = record.mikan;
|
|
169
|
+
return {
|
|
170
|
+
name: typeof record.name === "string" ? record.name : undefined,
|
|
171
|
+
version: typeof record.version === "string" ? record.version : undefined,
|
|
172
|
+
description: typeof record.description === "string" ? record.description : undefined,
|
|
173
|
+
mikan: {
|
|
174
|
+
extensions: Array.isArray(mikanRaw?.extensions)
|
|
175
|
+
? mikanRaw.extensions.filter((entry) => typeof entry === "string")
|
|
176
|
+
: undefined,
|
|
177
|
+
displayName: typeof mikanRaw?.displayName === "string" ? mikanRaw.displayName : undefined,
|
|
178
|
+
secrets: Array.isArray(mikanRaw?.secrets)
|
|
179
|
+
? mikanRaw.secrets.flatMap((entry) => readSecretDeclaration(entry) ?? [])
|
|
180
|
+
: undefined,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
log.logWarning(`Ignoring malformed package.json: ${packageJsonPath}`, String(err));
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/** Read the `mikan.extensions` entrypoint list from a directory's package.json. */
|
|
190
|
+
function readMikanManifestEntrypoints(dir) {
|
|
191
|
+
return readPackageJson(dir)?.mikan?.extensions ?? [];
|
|
192
|
+
}
|
|
193
|
+
/** The one filesystem-safe segment sanitizer for extension identity and schedule names. */
|
|
194
|
+
function sanitizeSegment(value) {
|
|
195
|
+
return value
|
|
116
196
|
.toLowerCase()
|
|
117
197
|
.replace(/[^a-z0-9_-]+/g, "-")
|
|
118
198
|
.replace(/^-+|-+$/g, "")
|
|
119
199
|
.slice(0, 64);
|
|
120
|
-
|
|
200
|
+
}
|
|
201
|
+
function sanitizeSlug(base) {
|
|
202
|
+
return sanitizeSegment(base) || "extension";
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Filesystem-safe identifier for an extension, derived from its root (the
|
|
206
|
+
* install directory, or the file path for a bare-file extension). The slug
|
|
207
|
+
* keys the extension's data dir, secrets vault, and schedule ownership —
|
|
208
|
+
* installing the same extension globally and per-conversation shares one
|
|
209
|
+
* slug and therefore one shared data dir. This is the only slug derivation:
|
|
210
|
+
* a second one keyed off a different input (e.g. the entrypoint, which for
|
|
211
|
+
* package.json-form extensions can live under dist/) would silently split an
|
|
212
|
+
* extension's identity.
|
|
213
|
+
*/
|
|
214
|
+
export function extensionSlug(rootDir) {
|
|
215
|
+
return EXTENSION_FILE_PATTERN.test(basename(rootDir))
|
|
216
|
+
? sanitizeSlug(basename(rootDir).replace(EXTENSION_FILE_PATTERN, ""))
|
|
217
|
+
: sanitizeSlug(basename(rootDir));
|
|
121
218
|
}
|
|
122
219
|
/** Sanitize an extension-chosen schedule name into a filename segment. */
|
|
123
220
|
function scheduleNameSegment(name) {
|
|
124
|
-
const segment = name
|
|
125
|
-
.toLowerCase()
|
|
126
|
-
.replace(/[^a-z0-9_-]+/g, "-")
|
|
127
|
-
.replace(/^-+|-+$/g, "")
|
|
128
|
-
.slice(0, 64);
|
|
221
|
+
const segment = sanitizeSegment(name);
|
|
129
222
|
if (!segment)
|
|
130
223
|
throw new Error(`Invalid schedule name: ${JSON.stringify(name)}`);
|
|
131
224
|
return segment;
|
|
132
225
|
}
|
|
133
|
-
/**
|
|
134
|
-
|
|
135
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Read display metadata (name/version/description) for a directory-form
|
|
228
|
+
* extension. `package.json` is the primary source — its standard `name`,
|
|
229
|
+
* `version`, `description`, plus an optional `mikan.displayName` that
|
|
230
|
+
* overrides the npm name for the user-facing label (npm names are
|
|
231
|
+
* lowercase/scoped; display names can be arbitrary). A `manifest.json` is a
|
|
232
|
+
* fallback for extensions that ship no package.json.
|
|
233
|
+
*/
|
|
234
|
+
function readManifest(rootDir) {
|
|
235
|
+
// Bare-file extensions (rootDir is a *.mjs/.ts file) have no manifest.
|
|
236
|
+
if (EXTENSION_FILE_PATTERN.test(basename(rootDir)))
|
|
136
237
|
return {};
|
|
137
|
-
const
|
|
238
|
+
const pkg = readPackageJson(rootDir);
|
|
239
|
+
if (pkg &&
|
|
240
|
+
(pkg.mikan?.displayName ??
|
|
241
|
+
pkg.name ??
|
|
242
|
+
pkg.version ??
|
|
243
|
+
pkg.description ??
|
|
244
|
+
pkg.mikan?.secrets?.length)) {
|
|
245
|
+
return {
|
|
246
|
+
name: pkg.mikan?.displayName ?? pkg.name,
|
|
247
|
+
version: pkg.version,
|
|
248
|
+
description: pkg.description,
|
|
249
|
+
...(pkg.mikan?.secrets?.length ? { secrets: pkg.mikan.secrets } : {}),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const manifestPath = join(rootDir, "manifest.json");
|
|
138
253
|
if (!existsSync(manifestPath))
|
|
139
254
|
return {};
|
|
140
255
|
try {
|
|
@@ -158,10 +273,11 @@ function readManifest(entrypoint) {
|
|
|
158
273
|
* Marked inline: extension files live under the host-only state dir, which
|
|
159
274
|
* sandbox containers cannot read, so skill bodies must ride in the prompt.
|
|
160
275
|
*/
|
|
161
|
-
function loadExtensionSkills(
|
|
162
|
-
|
|
276
|
+
function loadExtensionSkills(rootDir, slug) {
|
|
277
|
+
// Bare-file extensions (rootDir is a *.mjs/.ts file) ship no skills.
|
|
278
|
+
if (EXTENSION_FILE_PATTERN.test(basename(rootDir)))
|
|
163
279
|
return [];
|
|
164
|
-
const skillsDir = join(
|
|
280
|
+
const skillsDir = join(rootDir, "skills");
|
|
165
281
|
if (!existsSync(skillsDir))
|
|
166
282
|
return [];
|
|
167
283
|
const result = loadSkillsFromDir({ dir: skillsDir, source: `extension:${slug}` });
|
|
@@ -176,43 +292,35 @@ const SCHEDULE_FILE_SUFFIX = ".json";
|
|
|
176
292
|
function schedulePrefix(slug, conversationId) {
|
|
177
293
|
return `ext.${slug}.${scheduleNameSegment(conversationId)}.`;
|
|
178
294
|
}
|
|
179
|
-
function payloadFromSpec(spec, conversationId) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
type: "periodic",
|
|
186
|
-
conversationId,
|
|
187
|
-
text: spec.text,
|
|
188
|
-
schedule: spec.schedule,
|
|
189
|
-
timezone: spec.timezone,
|
|
190
|
-
...(spec.platform ? { platform: spec.platform } : {}),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
if (!spec.at)
|
|
194
|
-
throw new Error("one-shot schedule requires at");
|
|
195
|
-
return {
|
|
196
|
-
type: "one-shot",
|
|
295
|
+
function payloadFromSpec(spec, conversationId, defaultPlatform) {
|
|
296
|
+
// Per-type validation (schedule/timezone for periodic, at for one-shot)
|
|
297
|
+
// is owned by the event-format builder.
|
|
298
|
+
return buildEventPayload({
|
|
299
|
+
type: spec.type,
|
|
197
300
|
conversationId,
|
|
198
301
|
text: spec.text,
|
|
199
|
-
|
|
200
|
-
...(spec.
|
|
201
|
-
|
|
302
|
+
platform: spec.platform ?? defaultPlatform,
|
|
303
|
+
...(spec.type === "periodic"
|
|
304
|
+
? { schedule: spec.schedule, timezone: spec.timezone }
|
|
305
|
+
: { at: spec.at }),
|
|
306
|
+
});
|
|
202
307
|
}
|
|
203
308
|
function specFromPayload(payload) {
|
|
204
309
|
if (payload.type === "periodic") {
|
|
205
310
|
return {
|
|
206
311
|
type: "periodic",
|
|
207
|
-
schedule: payload.schedule
|
|
208
|
-
timezone: payload.timezone
|
|
312
|
+
schedule: payload.schedule,
|
|
313
|
+
timezone: payload.timezone,
|
|
209
314
|
text: payload.text,
|
|
210
315
|
...(payload.platform ? { platform: payload.platform } : {}),
|
|
211
316
|
};
|
|
212
317
|
}
|
|
318
|
+
// `immediate` payloads never appear under the schedules namespace (they
|
|
319
|
+
// live under "extrun."); tolerate them as an empty one-shot rather than
|
|
320
|
+
// widening the spec union.
|
|
213
321
|
return {
|
|
214
322
|
type: "one-shot",
|
|
215
|
-
at: payload.at
|
|
323
|
+
at: payload.type === "one-shot" ? payload.at : "",
|
|
216
324
|
text: payload.text,
|
|
217
325
|
...(payload.platform ? { platform: payload.platform } : {}),
|
|
218
326
|
};
|
|
@@ -222,20 +330,42 @@ function buildExtensionApi(params) {
|
|
|
222
330
|
const { name, slug, registry, context, services } = params;
|
|
223
331
|
const stateDir = services.stateDir ?? join(homedir(), ".mikan");
|
|
224
332
|
const conversationId = context.conversationId;
|
|
333
|
+
const conversationStateDir = officeStateDir(stateDir, context.address);
|
|
334
|
+
// Default platform for proactive messaging and schedules: the platform this
|
|
335
|
+
// conversation lives on. Extensions only name a platform explicitly when
|
|
336
|
+
// targeting a conversation on a different one.
|
|
337
|
+
const ownPlatform = context.address.platform;
|
|
225
338
|
const requireScheduleStore = () => {
|
|
226
339
|
if (!services.scheduleStore) {
|
|
227
340
|
throw new Error("api.schedules is unavailable: this context provides no schedule store");
|
|
228
341
|
}
|
|
229
342
|
return services.scheduleStore;
|
|
230
343
|
};
|
|
344
|
+
const requireCallbackScheduleStore = () => {
|
|
345
|
+
if (!services.callbackScheduleStore) {
|
|
346
|
+
throw new Error("api.schedules callback specs are unavailable: this context provides no callback-schedule store");
|
|
347
|
+
}
|
|
348
|
+
return services.callbackScheduleStore;
|
|
349
|
+
};
|
|
350
|
+
const scheduleFilename = (scheduleName) => `${schedulePrefix(slug, conversationId)}${scheduleNameSegment(scheduleName)}${SCHEDULE_FILE_SUFFIX}`;
|
|
231
351
|
return {
|
|
232
352
|
on: (hook, handler) => registry.register(name, hook, handler),
|
|
233
353
|
registerTool: (tool) => registry.registerTool(tool),
|
|
354
|
+
registerCommand: (command) => registry.registerCommand(name, command),
|
|
355
|
+
onDispose: (disposer) => registry.registerDisposer(name, disposer),
|
|
234
356
|
log: (message) => log.logInfo(`[extension:${name}] ${message}`),
|
|
235
357
|
context,
|
|
236
358
|
paths: {
|
|
237
359
|
get dataDir() {
|
|
238
|
-
|
|
360
|
+
// This conversation's own data, co-located with the conversation's
|
|
361
|
+
// other host-only assets; removed when the conversation is deleted.
|
|
362
|
+
const dir = join(conversationStateDir, "extension-data", slug);
|
|
363
|
+
mkdirSync(dir, { recursive: true });
|
|
364
|
+
return dir;
|
|
365
|
+
},
|
|
366
|
+
get sharedDataDir() {
|
|
367
|
+
// Cross-conversation data under the sibling `global` scope.
|
|
368
|
+
const dir = join(stateDir, "global", "extension-data", slug);
|
|
239
369
|
mkdirSync(dir, { recursive: true });
|
|
240
370
|
return dir;
|
|
241
371
|
},
|
|
@@ -246,40 +376,140 @@ function buildExtensionApi(params) {
|
|
|
246
376
|
},
|
|
247
377
|
schedules: {
|
|
248
378
|
upsert: async (scheduleName, spec) => {
|
|
379
|
+
const nameSegment = scheduleNameSegment(scheduleName);
|
|
380
|
+
// One name namespace across both action kinds: an upsert switches the
|
|
381
|
+
// schedule's kind by also dropping its counterpart in the other store.
|
|
382
|
+
if (spec.callback !== undefined) {
|
|
383
|
+
await requireCallbackScheduleStore().upsert(slug, nameSegment, spec);
|
|
384
|
+
await services.scheduleStore?.delete(scheduleFilename(scheduleName));
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
249
387
|
const store = requireScheduleStore();
|
|
250
|
-
|
|
251
|
-
await
|
|
388
|
+
await store.write(scheduleFilename(scheduleName), payloadFromSpec(spec, conversationId, ownPlatform));
|
|
389
|
+
await services.callbackScheduleStore?.delete(slug, nameSegment);
|
|
252
390
|
},
|
|
253
391
|
delete: async (scheduleName) => {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
392
|
+
if (!services.scheduleStore && !services.callbackScheduleStore)
|
|
393
|
+
requireScheduleStore();
|
|
394
|
+
const deletedCallback = (await services.callbackScheduleStore?.delete(slug, scheduleNameSegment(scheduleName))) ??
|
|
395
|
+
false;
|
|
396
|
+
const deletedText = (await services.scheduleStore?.delete(scheduleFilename(scheduleName))) ?? false;
|
|
397
|
+
return deletedCallback || deletedText;
|
|
257
398
|
},
|
|
258
399
|
list: async () => {
|
|
259
|
-
|
|
260
|
-
|
|
400
|
+
if (!services.scheduleStore && !services.callbackScheduleStore)
|
|
401
|
+
requireScheduleStore();
|
|
261
402
|
const infos = [];
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
403
|
+
if (services.scheduleStore) {
|
|
404
|
+
const prefix = schedulePrefix(slug, conversationId);
|
|
405
|
+
for (const entry of await services.scheduleStore.list()) {
|
|
406
|
+
if (!entry.filename.startsWith(prefix))
|
|
407
|
+
continue;
|
|
408
|
+
if (!entry.filename.endsWith(SCHEDULE_FILE_SUFFIX))
|
|
409
|
+
continue;
|
|
410
|
+
infos.push({
|
|
411
|
+
name: entry.filename.slice(prefix.length, -SCHEDULE_FILE_SUFFIX.length),
|
|
412
|
+
spec: specFromPayload(entry.payload),
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (services.callbackScheduleStore) {
|
|
417
|
+
infos.push(...(await services.callbackScheduleStore.list(slug)));
|
|
271
418
|
}
|
|
272
419
|
return infos;
|
|
273
420
|
},
|
|
421
|
+
onCallback: (callbackName, handler) => registry.registerScheduleCallback(slug, callbackName, handler),
|
|
422
|
+
},
|
|
423
|
+
subagent: {
|
|
424
|
+
run: async (request) => {
|
|
425
|
+
if (!services.runSubagent) {
|
|
426
|
+
throw new Error("api.subagent is unavailable: this context provides no subagent runner");
|
|
427
|
+
}
|
|
428
|
+
return services.runSubagent(request, registry.getContributedTools());
|
|
429
|
+
},
|
|
274
430
|
},
|
|
275
|
-
notify: async (text) => {
|
|
431
|
+
notify: async (text, options) => {
|
|
276
432
|
if (!services.postMessage) {
|
|
277
433
|
throw new Error("api.notify is unavailable: this context provides no platform messaging");
|
|
278
434
|
}
|
|
279
|
-
|
|
435
|
+
return services.postMessage(options?.conversationId ?? conversationId, text, {
|
|
436
|
+
platform: options?.platform ?? ownPlatform,
|
|
437
|
+
...(options?.threadTs ? { threadTs: options.threadTs } : {}),
|
|
438
|
+
});
|
|
439
|
+
},
|
|
440
|
+
openDm: async (userId) => {
|
|
441
|
+
if (!services.openDirectConversation) {
|
|
442
|
+
throw new Error("api.openDm is unavailable: this context provides no DM resolution");
|
|
443
|
+
}
|
|
444
|
+
return services.openDirectConversation(userId, ownPlatform);
|
|
445
|
+
},
|
|
446
|
+
fetchHistory: async (options) => {
|
|
447
|
+
if (!services.fetchHistory) {
|
|
448
|
+
throw new Error("api.fetchHistory is unavailable: this context provides no history reads");
|
|
449
|
+
}
|
|
450
|
+
const { conversationId: target, ...historyOptions } = options ?? {};
|
|
451
|
+
return services.fetchHistory(target ?? conversationId, {
|
|
452
|
+
...historyOptions,
|
|
453
|
+
platform: ownPlatform,
|
|
454
|
+
});
|
|
455
|
+
},
|
|
456
|
+
listUsers: async () => {
|
|
457
|
+
if (!services.listUsers) {
|
|
458
|
+
throw new Error("api.listUsers is unavailable: this context provides no user listings");
|
|
459
|
+
}
|
|
460
|
+
return services.listUsers(ownPlatform);
|
|
461
|
+
},
|
|
462
|
+
blockkit: {
|
|
463
|
+
post: async (message) => {
|
|
464
|
+
if (!services.postBlocks) {
|
|
465
|
+
throw new Error("api.blockkit is unavailable: this context provides no Block Kit messaging");
|
|
466
|
+
}
|
|
467
|
+
return services.postBlocks(conversationId, {
|
|
468
|
+
text: message.text,
|
|
469
|
+
blocks: namespaceActionIds(message.blocks, slug),
|
|
470
|
+
threadTs: message.threadTs,
|
|
471
|
+
}, ownPlatform);
|
|
472
|
+
},
|
|
473
|
+
update: async (messageTs, message) => {
|
|
474
|
+
if (!services.updateBlocks) {
|
|
475
|
+
throw new Error("api.blockkit is unavailable: this context provides no Block Kit messaging");
|
|
476
|
+
}
|
|
477
|
+
await services.updateBlocks(conversationId, messageTs, {
|
|
478
|
+
text: message.text,
|
|
479
|
+
blocks: namespaceActionIds(message.blocks, slug),
|
|
480
|
+
}, ownPlatform);
|
|
481
|
+
},
|
|
482
|
+
onAction: (actionId, handler) => registry.registerAction(slug, actionId, handler),
|
|
483
|
+
},
|
|
484
|
+
react: async (messageTs, emoji) => {
|
|
485
|
+
if (!services.addReaction) {
|
|
486
|
+
throw new Error("api.react is unavailable: this context provides no reaction support");
|
|
487
|
+
}
|
|
488
|
+
await services.addReaction(conversationId, messageTs, emoji, ownPlatform);
|
|
489
|
+
},
|
|
490
|
+
uploadFile: async (filePath, title) => {
|
|
491
|
+
if (!services.uploadFile) {
|
|
492
|
+
throw new Error("api.uploadFile is unavailable: this context provides no file uploads");
|
|
493
|
+
}
|
|
494
|
+
await services.uploadFile(conversationId, filePath, title, ownPlatform);
|
|
495
|
+
},
|
|
496
|
+
triggerRun: async (text) => {
|
|
497
|
+
const store = requireScheduleStore();
|
|
498
|
+
// Distinct "extrun." namespace: run files must never surface in
|
|
499
|
+
// api.schedules.list(), whose ownership filter is the "ext." prefix.
|
|
500
|
+
// The embedder's watcher fires and deletes the file immediately.
|
|
501
|
+
const filename = `extrun.${slug}.${scheduleNameSegment(conversationId)}.${Date.now()}-${runCounter++}${SCHEDULE_FILE_SUFFIX}`;
|
|
502
|
+
await store.write(filename, {
|
|
503
|
+
type: "immediate",
|
|
504
|
+
platform: ownPlatform,
|
|
505
|
+
conversationId,
|
|
506
|
+
text,
|
|
507
|
+
});
|
|
280
508
|
},
|
|
281
509
|
};
|
|
282
510
|
}
|
|
511
|
+
/** Monotonic suffix so rapid triggerRun calls in one process never collide. */
|
|
512
|
+
let runCounter = 0;
|
|
283
513
|
function resolveActivate(moduleExports) {
|
|
284
514
|
if (!moduleExports || typeof moduleExports !== "object")
|
|
285
515
|
return undefined;
|
|
@@ -309,49 +539,175 @@ export async function loadExtensions(options) {
|
|
|
309
539
|
const errors = [];
|
|
310
540
|
const skills = [];
|
|
311
541
|
const services = options.services ?? {};
|
|
312
|
-
for (const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
542
|
+
for (const { entrypoint, rootDir, slug } of collectExtensions(options)) {
|
|
543
|
+
try {
|
|
544
|
+
const manifest = readManifest(rootDir);
|
|
545
|
+
// Enforce declared-required secrets before importing: a clear
|
|
546
|
+
// provisioning hint beats whatever error the extension would throw at
|
|
547
|
+
// first `api.secrets.get` miss. Only enforceable when this context
|
|
548
|
+
// resolves secrets at all (`mikan ext dev` and secret-less embedders
|
|
549
|
+
// still activate; `api.secrets.get` returns undefined there).
|
|
550
|
+
if (services.resolveSecrets) {
|
|
551
|
+
const provisioned = services.resolveSecrets(slug);
|
|
552
|
+
const missing = (manifest.secrets ?? [])
|
|
553
|
+
.filter((secret) => secret.required && !(secret.key in provisioned))
|
|
554
|
+
.map((secret) => secret.key);
|
|
555
|
+
if (missing.length > 0) {
|
|
319
556
|
errors.push({
|
|
320
557
|
path: entrypoint,
|
|
321
|
-
error: "
|
|
558
|
+
error: `missing required secrets: ${missing.join(", ")} — provision them in the admin ` +
|
|
559
|
+
`portal or in <stateDir>/vaults/extensions/${slug}/env`,
|
|
322
560
|
});
|
|
323
561
|
continue;
|
|
324
562
|
}
|
|
325
|
-
const slug = extensionSlug(entrypoint);
|
|
326
|
-
const manifest = readManifest(entrypoint);
|
|
327
|
-
const name = manifest.name ?? extension.name ?? slug;
|
|
328
|
-
const api = buildExtensionApi({
|
|
329
|
-
name,
|
|
330
|
-
slug,
|
|
331
|
-
registry,
|
|
332
|
-
context: options.context,
|
|
333
|
-
services,
|
|
334
|
-
});
|
|
335
|
-
await extension.activate(api);
|
|
336
|
-
const extensionSkills = loadExtensionSkills(entrypoint, slug);
|
|
337
|
-
skills.push(...extensionSkills);
|
|
338
|
-
extensions.push({
|
|
339
|
-
name,
|
|
340
|
-
path: entrypoint,
|
|
341
|
-
slug,
|
|
342
|
-
version: manifest.version,
|
|
343
|
-
description: manifest.description,
|
|
344
|
-
skills: extensionSkills,
|
|
345
|
-
});
|
|
346
563
|
}
|
|
347
|
-
|
|
564
|
+
const moduleExports = await importExtensionModule(entrypoint);
|
|
565
|
+
const extension = resolveActivate(moduleExports);
|
|
566
|
+
if (!extension) {
|
|
348
567
|
errors.push({
|
|
349
568
|
path: entrypoint,
|
|
350
|
-
error:
|
|
569
|
+
error: "extension must export an activate function (default or named)",
|
|
351
570
|
});
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
const name = manifest.name ?? extension.name ?? slug;
|
|
574
|
+
const api = buildExtensionApi({
|
|
575
|
+
name,
|
|
576
|
+
slug,
|
|
577
|
+
registry,
|
|
578
|
+
context: options.context,
|
|
579
|
+
services,
|
|
580
|
+
});
|
|
581
|
+
const disposer = await extension.activate(api);
|
|
582
|
+
if (typeof disposer === "function")
|
|
583
|
+
registry.registerDisposer(name, disposer);
|
|
584
|
+
const extensionSkills = loadExtensionSkills(rootDir, slug);
|
|
585
|
+
skills.push(...extensionSkills);
|
|
586
|
+
extensions.push({
|
|
587
|
+
name,
|
|
588
|
+
path: entrypoint,
|
|
589
|
+
slug,
|
|
590
|
+
version: manifest.version,
|
|
591
|
+
description: manifest.description,
|
|
592
|
+
skills: extensionSkills,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
catch (err) {
|
|
596
|
+
errors.push({
|
|
597
|
+
path: entrypoint,
|
|
598
|
+
error: err instanceof Error ? err.message : String(err),
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return { registry, extensions, errors, skills, dispose: () => registry.dispose() };
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Everything to activate, in final order, with at most one entry per slug.
|
|
606
|
+
*
|
|
607
|
+
* Deduplication happens here rather than at activation time on purpose. The
|
|
608
|
+
* slug keys an extension's data dir, secrets, and schedules, so activating two
|
|
609
|
+
* copies of one extension would have them fight over the same state — and the
|
|
610
|
+
* registry's first-wins rule for commands would silently pick the opposite
|
|
611
|
+
* copy from the one that ran its hooks. Resolving to a single winner before
|
|
612
|
+
* anything is imported keeps those decisions consistent.
|
|
613
|
+
*
|
|
614
|
+
* Precedence follows scan order, so the narrowest scope wins: global
|
|
615
|
+
* directories first, then the conversation's, then explicit roots.
|
|
616
|
+
*/
|
|
617
|
+
function collectExtensions(options) {
|
|
618
|
+
const bySlug = new Map();
|
|
619
|
+
const candidates = [
|
|
620
|
+
...options.dirs.flatMap(discoverExtensionEntrypoints),
|
|
621
|
+
...(options.roots ?? []).flatMap(resolveExtensionRoot),
|
|
622
|
+
];
|
|
623
|
+
for (const candidate of candidates) {
|
|
624
|
+
const shadowed = bySlug.get(candidate.slug);
|
|
625
|
+
if (shadowed && shadowed.rootDir !== candidate.rootDir) {
|
|
626
|
+
log.logInfo(`Extension "${candidate.slug}" from ${candidate.rootDir} shadows ${shadowed.rootDir}`);
|
|
627
|
+
}
|
|
628
|
+
bySlug.set(candidate.slug, candidate);
|
|
629
|
+
}
|
|
630
|
+
return [...bySlug.values()];
|
|
631
|
+
}
|
|
632
|
+
/** Resolve one explicit extension root (directory with an entrypoint, or a bare file). */
|
|
633
|
+
function resolveExtensionRoot(rootDir) {
|
|
634
|
+
let stats;
|
|
635
|
+
try {
|
|
636
|
+
stats = statSync(rootDir);
|
|
637
|
+
}
|
|
638
|
+
catch {
|
|
639
|
+
log.logWarning(`Extension path does not exist: ${rootDir}`);
|
|
640
|
+
return [];
|
|
641
|
+
}
|
|
642
|
+
if (stats.isFile()) {
|
|
643
|
+
return EXTENSION_FILE_PATTERN.test(basename(rootDir))
|
|
644
|
+
? [{ entrypoint: rootDir, rootDir, slug: extensionSlug(rootDir) }]
|
|
645
|
+
: [];
|
|
646
|
+
}
|
|
647
|
+
const entrypoint = resolveDirectoryEntrypoint(rootDir);
|
|
648
|
+
if (!entrypoint) {
|
|
649
|
+
log.logWarning(`No extension entrypoint in ${rootDir}`, "expected an index.{mjs,js,ts,mts} or a package.json with mikan.extensions");
|
|
650
|
+
return [];
|
|
651
|
+
}
|
|
652
|
+
return [{ entrypoint, rootDir, slug: extensionSlug(rootDir) }];
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Validate an extension source path (a directory or a single file) WITHOUT
|
|
656
|
+
* activating it: resolves the entrypoint (package.json `mikan.extensions`,
|
|
657
|
+
* index file, or the file itself), imports it, and checks it exports an
|
|
658
|
+
* `activate` function. Used by `mikan ext install` as a preflight and by
|
|
659
|
+
* `mikan ext validate`. Importing runs top-level module code but not
|
|
660
|
+
* `activate`, so there are no schedule/tool side effects.
|
|
661
|
+
*/
|
|
662
|
+
export async function validateExtension(sourcePath) {
|
|
663
|
+
const errors = [];
|
|
664
|
+
const warnings = [];
|
|
665
|
+
const rootDir = sourcePath.replace(/[/\\]+$/, "");
|
|
666
|
+
const base = basename(rootDir);
|
|
667
|
+
if (INDEX_FILE_PATTERN.test(base)) {
|
|
668
|
+
warnings.push("Entry is a bare index file; install into a named directory so the slug is stable.");
|
|
669
|
+
}
|
|
670
|
+
let entrypoint;
|
|
671
|
+
if (!existsSync(rootDir)) {
|
|
672
|
+
errors.push(`Path does not exist: ${rootDir}`);
|
|
673
|
+
}
|
|
674
|
+
else if (statSync(rootDir).isDirectory()) {
|
|
675
|
+
entrypoint = resolveDirectoryEntrypoint(rootDir);
|
|
676
|
+
if (!entrypoint) {
|
|
677
|
+
errors.push("No entrypoint found: expected package.json with a mikan.extensions entry, or an index.{mjs,js,ts,mts}.");
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
else if (EXTENSION_FILE_PATTERN.test(base)) {
|
|
681
|
+
entrypoint = rootDir;
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
errors.push(`Not an extension file (expected .mjs/.js/.ts/.mts): ${rootDir}`);
|
|
685
|
+
}
|
|
686
|
+
const slug = extensionSlug(rootDir);
|
|
687
|
+
const manifest = readManifest(rootDir);
|
|
688
|
+
const skillNames = loadExtensionSkills(rootDir, slug).map((skill) => skill.name);
|
|
689
|
+
if (entrypoint) {
|
|
690
|
+
try {
|
|
691
|
+
const moduleExports = await importExtensionModule(entrypoint);
|
|
692
|
+
if (!resolveActivate(moduleExports)) {
|
|
693
|
+
errors.push("Module does not export an activate function (default or named).");
|
|
352
694
|
}
|
|
353
695
|
}
|
|
696
|
+
catch (err) {
|
|
697
|
+
errors.push(`Failed to import: ${err instanceof Error ? err.message : String(err)}`);
|
|
698
|
+
}
|
|
354
699
|
}
|
|
355
|
-
return {
|
|
700
|
+
return {
|
|
701
|
+
ok: errors.length === 0,
|
|
702
|
+
slug,
|
|
703
|
+
name: manifest.name ?? slug,
|
|
704
|
+
version: manifest.version,
|
|
705
|
+
description: manifest.description,
|
|
706
|
+
entrypoint,
|
|
707
|
+
skillNames,
|
|
708
|
+
secrets: manifest.secrets ?? [],
|
|
709
|
+
errors,
|
|
710
|
+
warnings,
|
|
711
|
+
};
|
|
356
712
|
}
|
|
357
713
|
//# sourceMappingURL=loader.js.map
|