@geminixiang/mikan 1.0.0-beta.76 → 1.0.0-beta.78
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 +39 -0
- package/dist/adapters/commands/login.d.ts.map +1 -1
- package/dist/adapters/commands/login.js +0 -9
- package/dist/adapters/commands/login.js.map +1 -1
- package/dist/adapters/commands/manifest.d.ts +0 -19
- package/dist/adapters/commands/manifest.d.ts.map +1 -1
- package/dist/adapters/commands/manifest.js +0 -34
- package/dist/adapters/commands/manifest.js.map +1 -1
- package/dist/adapters/commands/model.d.ts +0 -5
- package/dist/adapters/commands/model.d.ts.map +1 -1
- package/dist/adapters/commands/model.js +0 -5
- package/dist/adapters/commands/model.js.map +1 -1
- package/dist/adapters/commands/new.d.ts.map +1 -1
- package/dist/adapters/commands/new.js +0 -2
- package/dist/adapters/commands/new.js.map +1 -1
- package/dist/adapters/commands/registry.d.ts +0 -1
- package/dist/adapters/commands/registry.d.ts.map +1 -1
- package/dist/adapters/commands/registry.js +0 -8
- package/dist/adapters/commands/registry.js.map +1 -1
- package/dist/adapters/commands/session-view.d.ts.map +1 -1
- package/dist/adapters/commands/session-view.js +0 -2
- package/dist/adapters/commands/session-view.js.map +1 -1
- package/dist/adapters/commands/types.d.ts +0 -29
- package/dist/adapters/commands/types.d.ts.map +1 -1
- package/dist/adapters/commands/types.js.map +1 -1
- package/dist/adapters/commands/utils.d.ts +0 -3
- package/dist/adapters/commands/utils.d.ts.map +1 -1
- package/dist/adapters/commands/utils.js +0 -3
- package/dist/adapters/commands/utils.js.map +1 -1
- package/dist/adapters/discord/bot.d.ts +0 -4
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +5 -41
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/components.d.ts +0 -23
- package/dist/adapters/discord/components.d.ts.map +1 -1
- package/dist/adapters/discord/components.js +0 -23
- package/dist/adapters/discord/components.js.map +1 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +1 -11
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/discord/format.d.ts +0 -1
- package/dist/adapters/discord/format.d.ts.map +1 -1
- package/dist/adapters/discord/format.js +0 -37
- package/dist/adapters/discord/format.js.map +1 -1
- package/dist/adapters/github/bot.d.ts +0 -44
- package/dist/adapters/github/bot.d.ts.map +1 -1
- package/dist/adapters/github/bot.js +1 -120
- package/dist/adapters/github/bot.js.map +1 -1
- package/dist/adapters/github/client.d.ts +0 -57
- package/dist/adapters/github/client.d.ts.map +1 -1
- package/dist/adapters/github/client.js +0 -59
- package/dist/adapters/github/client.js.map +1 -1
- package/dist/adapters/github/context.d.ts.map +1 -1
- package/dist/adapters/github/context.js +1 -8
- package/dist/adapters/github/context.js.map +1 -1
- package/dist/adapters/github/github-ops.d.ts +0 -55
- package/dist/adapters/github/github-ops.d.ts.map +1 -1
- package/dist/adapters/github/github-ops.js +0 -59
- package/dist/adapters/github/github-ops.js.map +1 -1
- package/dist/adapters/github/ids.d.ts +0 -27
- package/dist/adapters/github/ids.d.ts.map +1 -1
- package/dist/adapters/github/ids.js +0 -29
- package/dist/adapters/github/ids.js.map +1 -1
- package/dist/adapters/github/repo.d.ts +0 -25
- package/dist/adapters/github/repo.d.ts.map +1 -1
- package/dist/adapters/github/repo.js +0 -49
- package/dist/adapters/github/repo.js.map +1 -1
- package/dist/adapters/github/tool-pack.d.ts +0 -10
- package/dist/adapters/github/tool-pack.d.ts.map +1 -1
- package/dist/adapters/github/tool-pack.js +0 -10
- package/dist/adapters/github/tool-pack.js.map +1 -1
- package/dist/adapters/github/tools/checks.d.ts +0 -6
- package/dist/adapters/github/tools/checks.d.ts.map +1 -1
- package/dist/adapters/github/tools/checks.js +0 -7
- package/dist/adapters/github/tools/checks.js.map +1 -1
- package/dist/adapters/github/tools/issue.d.ts +0 -5
- package/dist/adapters/github/tools/issue.d.ts.map +1 -1
- package/dist/adapters/github/tools/issue.js +0 -5
- package/dist/adapters/github/tools/issue.js.map +1 -1
- package/dist/adapters/github/tools/pr.d.ts +0 -7
- package/dist/adapters/github/tools/pr.d.ts.map +1 -1
- package/dist/adapters/github/tools/pr.js +0 -7
- package/dist/adapters/github/tools/pr.js.map +1 -1
- package/dist/adapters/github/tools/read.d.ts +0 -6
- package/dist/adapters/github/tools/read.d.ts.map +1 -1
- package/dist/adapters/github/tools/read.js +0 -8
- package/dist/adapters/github/tools/read.js.map +1 -1
- package/dist/adapters/github/tools/review-reply.d.ts +0 -5
- package/dist/adapters/github/tools/review-reply.d.ts.map +1 -1
- package/dist/adapters/github/tools/review-reply.js +0 -5
- package/dist/adapters/github/tools/review-reply.js.map +1 -1
- package/dist/adapters/github/tools/sync.d.ts +0 -6
- package/dist/adapters/github/tools/sync.d.ts.map +1 -1
- package/dist/adapters/github/tools/sync.js +0 -6
- package/dist/adapters/github/tools/sync.js.map +1 -1
- package/dist/adapters/github/types.d.ts +0 -88
- package/dist/adapters/github/types.d.ts.map +1 -1
- package/dist/adapters/github/types.js.map +1 -1
- package/dist/adapters/github/webhook.d.ts +0 -13
- package/dist/adapters/github/webhook.d.ts.map +1 -1
- package/dist/adapters/github/webhook.js +0 -16
- package/dist/adapters/github/webhook.js.map +1 -1
- package/dist/adapters/index.d.ts +3 -4
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/intake.d.ts +0 -17
- package/dist/adapters/intake.d.ts.map +1 -1
- package/dist/adapters/intake.js +6 -32
- package/dist/adapters/intake.js.map +1 -1
- package/dist/adapters/markdown-tables.d.ts +0 -10
- package/dist/adapters/markdown-tables.d.ts.map +1 -1
- package/dist/adapters/markdown-tables.js +1 -42
- package/dist/adapters/markdown-tables.js.map +1 -1
- package/dist/adapters/progressive-renderer.d.ts.map +1 -1
- package/dist/adapters/progressive-renderer.js +3 -25
- package/dist/adapters/progressive-renderer.js.map +1 -1
- package/dist/adapters/shared.d.ts +0 -57
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/shared.js +0 -71
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/slack/assistant.d.ts +0 -49
- package/dist/adapters/slack/assistant.d.ts.map +1 -1
- package/dist/adapters/slack/assistant.js +0 -97
- package/dist/adapters/slack/assistant.js.map +1 -1
- package/dist/adapters/slack/auto-reply-context.d.ts +0 -7
- package/dist/adapters/slack/auto-reply-context.d.ts.map +1 -1
- package/dist/adapters/slack/auto-reply-context.js +0 -7
- package/dist/adapters/slack/auto-reply-context.js.map +1 -1
- package/dist/adapters/slack/blocks.d.ts +0 -9
- package/dist/adapters/slack/blocks.d.ts.map +1 -1
- package/dist/adapters/slack/blocks.js +0 -20
- package/dist/adapters/slack/blocks.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +0 -116
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +7 -231
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +1 -3
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/jev-context.d.ts +0 -13
- package/dist/adapters/slack/jev-context.d.ts.map +1 -1
- package/dist/adapters/slack/jev-context.js +0 -12
- package/dist/adapters/slack/jev-context.js.map +1 -1
- package/dist/adapters/slack/markdown.d.ts +0 -1
- package/dist/adapters/slack/markdown.d.ts.map +1 -1
- package/dist/adapters/slack/markdown.js +0 -5
- package/dist/adapters/slack/markdown.js.map +1 -1
- package/dist/adapters/slack/persona.d.ts +0 -9
- package/dist/adapters/slack/persona.d.ts.map +1 -1
- package/dist/adapters/slack/persona.js +0 -9
- package/dist/adapters/slack/persona.js.map +1 -1
- package/dist/adapters/slack/response-lifecycle.d.ts.map +1 -1
- package/dist/adapters/slack/response-lifecycle.js +1 -45
- package/dist/adapters/slack/response-lifecycle.js.map +1 -1
- package/dist/adapters/slack/session.d.ts +2 -1
- package/dist/adapters/slack/session.d.ts.map +1 -1
- package/dist/adapters/slack/session.js +2 -2
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/stream-limits.d.ts +0 -25
- package/dist/adapters/slack/stream-limits.d.ts.map +1 -1
- package/dist/adapters/slack/stream-limits.js +0 -34
- package/dist/adapters/slack/stream-limits.js.map +1 -1
- package/dist/adapters/slack/task-intent.d.ts +0 -13
- package/dist/adapters/slack/task-intent.d.ts.map +1 -1
- package/dist/adapters/slack/task-intent.js +0 -7
- package/dist/adapters/slack/task-intent.js.map +1 -1
- package/dist/adapters/slack/task-status.d.ts +0 -1
- package/dist/adapters/slack/task-status.d.ts.map +1 -1
- package/dist/adapters/slack/task-status.js +1 -9
- package/dist/adapters/slack/task-status.js.map +1 -1
- package/dist/adapters/slack/tool-pack.d.ts +0 -6
- package/dist/adapters/slack/tool-pack.d.ts.map +1 -1
- package/dist/adapters/slack/tool-pack.js +0 -6
- package/dist/adapters/slack/tool-pack.js.map +1 -1
- package/dist/adapters/slack/tools/blockkit.d.ts.map +1 -1
- package/dist/adapters/slack/tools/blockkit.js +0 -11
- package/dist/adapters/slack/tools/blockkit.js.map +1 -1
- package/dist/adapters/slack/types.d.ts +0 -19
- package/dist/adapters/slack/types.d.ts.map +1 -1
- package/dist/adapters/slack/types.js.map +1 -1
- package/dist/adapters/slack/update-diagnostics.d.ts +0 -1
- package/dist/adapters/slack/update-diagnostics.d.ts.map +1 -1
- package/dist/adapters/slack/update-diagnostics.js +1 -7
- package/dist/adapters/slack/update-diagnostics.js.map +1 -1
- package/dist/adapters/telegram/bot.d.ts +0 -6
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +1 -50
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +1 -8
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/types.d.ts +0 -57
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/adapters/web/admin/client-assets.d.ts +4 -0
- package/dist/adapters/web/admin/client-assets.d.ts.map +1 -0
- package/dist/adapters/web/admin/client-assets.js +1765 -0
- package/dist/adapters/web/admin/client-assets.js.map +1 -0
- package/dist/adapters/web/admin/portal.d.ts +0 -10
- package/dist/adapters/web/admin/portal.d.ts.map +1 -1
- package/dist/adapters/web/admin/portal.js +6 -1909
- package/dist/adapters/web/admin/portal.js.map +1 -1
- package/dist/adapters/web/admin/types.d.ts +0 -3
- package/dist/adapters/web/admin/types.d.ts.map +1 -1
- package/dist/adapters/web/admin/types.js.map +1 -1
- package/dist/adapters/web/login/oauth.d.ts.map +1 -1
- package/dist/adapters/web/login/oauth.js +3 -7
- package/dist/adapters/web/login/oauth.js.map +1 -1
- package/dist/adapters/web/login/portal.d.ts +0 -10
- package/dist/adapters/web/login/portal.d.ts.map +1 -1
- package/dist/adapters/web/login/portal.js +4 -37
- package/dist/adapters/web/login/portal.js.map +1 -1
- package/dist/adapters/web/login/types.d.ts +0 -5
- package/dist/adapters/web/login/types.d.ts.map +1 -1
- package/dist/adapters/web/login/types.js.map +1 -1
- package/dist/adapters/web/portal-shell.d.ts +0 -12
- package/dist/adapters/web/portal-shell.d.ts.map +1 -1
- package/dist/adapters/web/portal-shell.js +8 -25
- package/dist/adapters/web/portal-shell.js.map +1 -1
- package/dist/adapters/web/server.d.ts +0 -1
- package/dist/adapters/web/server.d.ts.map +1 -1
- package/dist/adapters/web/server.js +0 -2
- package/dist/adapters/web/server.js.map +1 -1
- package/dist/adapters/web/session-view/portal.d.ts.map +1 -1
- package/dist/adapters/web/session-view/portal.js +13 -24
- package/dist/adapters/web/session-view/portal.js.map +1 -1
- package/dist/adapters/web/session-view/types.d.ts.map +1 -1
- package/dist/adapters/web/session-view/types.js.map +1 -1
- package/dist/adapters/web/token-store.d.ts +0 -2
- package/dist/adapters/web/token-store.d.ts.map +1 -1
- package/dist/adapters/web/token-store.js +0 -2
- package/dist/adapters/web/token-store.js.map +1 -1
- package/dist/cli/arg-grammar.d.ts +0 -3
- package/dist/cli/arg-grammar.d.ts.map +1 -1
- package/dist/cli/arg-grammar.js +0 -3
- package/dist/cli/arg-grammar.js.map +1 -1
- package/dist/cli/boot.d.ts.map +1 -1
- package/dist/cli/boot.js +3 -12
- package/dist/cli/boot.js.map +1 -1
- package/dist/cli/download.d.ts.map +1 -1
- package/dist/cli/download.js +2 -6
- package/dist/cli/download.js.map +1 -1
- package/dist/cli/office.d.ts.map +1 -1
- package/dist/cli/office.js +0 -31
- package/dist/cli/office.js.map +1 -1
- package/dist/cli/onboard.d.ts +0 -2
- package/dist/cli/onboard.d.ts.map +1 -1
- package/dist/cli/onboard.js +0 -30
- package/dist/cli/onboard.js.map +1 -1
- package/dist/cli/process-lifecycle.d.ts +0 -5
- package/dist/cli/process-lifecycle.d.ts.map +1 -1
- package/dist/cli/process-lifecycle.js +0 -6
- package/dist/cli/process-lifecycle.js.map +1 -1
- package/dist/cli/sandbox.d.ts +3 -0
- package/dist/cli/sandbox.d.ts.map +1 -0
- package/dist/cli/sandbox.js +79 -0
- package/dist/cli/sandbox.js.map +1 -0
- package/dist/cli/sessions.d.ts.map +1 -1
- package/dist/cli/sessions.js +0 -11
- package/dist/cli/sessions.js.map +1 -1
- package/dist/cli/types.d.ts +2 -6
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli/types.js.map +1 -1
- package/dist/env-manifest.d.ts +0 -21
- package/dist/env-manifest.d.ts.map +1 -1
- package/dist/env-manifest.js +0 -11
- package/dist/env-manifest.js.map +1 -1
- package/dist/events/index.d.ts +0 -51
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +0 -42
- package/dist/events/index.js.map +1 -1
- package/dist/events/scheduler.d.ts +0 -8
- package/dist/events/scheduler.d.ts.map +1 -1
- package/dist/events/scheduler.js +0 -8
- package/dist/events/scheduler.js.map +1 -1
- package/dist/file-guards.d.ts +0 -15
- package/dist/file-guards.d.ts.map +1 -1
- package/dist/file-guards.js +2 -26
- package/dist/file-guards.js.map +1 -1
- package/dist/harness/execution-env.d.ts +0 -15
- package/dist/harness/execution-env.d.ts.map +1 -1
- package/dist/harness/execution-env.js +4 -55
- package/dist/harness/execution-env.js.map +1 -1
- package/dist/harness/http.d.ts +0 -12
- package/dist/harness/http.d.ts.map +1 -1
- package/dist/harness/http.js +0 -34
- package/dist/harness/http.js.map +1 -1
- package/dist/harness/index.d.ts +4 -7
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +4 -7
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/jev.d.ts +0 -28
- package/dist/harness/jev.d.ts.map +1 -1
- package/dist/harness/jev.js +0 -45
- package/dist/harness/jev.js.map +1 -1
- package/dist/harness/mcp-result.d.ts +20 -0
- package/dist/harness/mcp-result.d.ts.map +1 -0
- package/dist/harness/mcp-result.js +171 -0
- package/dist/harness/mcp-result.js.map +1 -0
- package/dist/harness/mcp.d.ts +0 -19
- package/dist/harness/mcp.d.ts.map +1 -1
- package/dist/harness/mcp.js +7 -66
- package/dist/harness/mcp.js.map +1 -1
- package/dist/harness/models.d.ts +0 -19
- package/dist/harness/models.d.ts.map +1 -1
- package/dist/harness/models.js +0 -52
- package/dist/harness/models.js.map +1 -1
- package/dist/harness/open-connector.d.ts +0 -12
- package/dist/harness/open-connector.d.ts.map +1 -1
- package/dist/harness/open-connector.js +0 -22
- package/dist/harness/open-connector.js.map +1 -1
- package/dist/harness/presenter.d.ts +1 -0
- package/dist/harness/presenter.d.ts.map +1 -1
- package/dist/harness/presenter.js +16 -66
- package/dist/harness/presenter.js.map +1 -1
- package/dist/harness/prompt.d.ts +0 -11
- package/dist/harness/prompt.d.ts.map +1 -1
- package/dist/harness/prompt.js +1 -18
- package/dist/harness/prompt.js.map +1 -1
- package/dist/harness/runner.d.ts.map +1 -1
- package/dist/harness/runner.js +8 -28
- package/dist/harness/runner.js.map +1 -1
- package/dist/harness/session.d.ts +11 -28
- package/dist/harness/session.d.ts.map +1 -1
- package/dist/harness/session.js +100 -38
- package/dist/harness/session.js.map +1 -1
- package/dist/harness/skills.d.ts +0 -22
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +0 -20
- package/dist/harness/skills.js.map +1 -1
- package/dist/harness/subagent-profiles.d.ts +0 -4
- package/dist/harness/subagent-profiles.d.ts.map +1 -1
- package/dist/harness/subagent-profiles.js +0 -29
- package/dist/harness/subagent-profiles.js.map +1 -1
- package/dist/harness/subagent.d.ts +0 -25
- package/dist/harness/subagent.d.ts.map +1 -1
- package/dist/harness/subagent.js +1 -70
- package/dist/harness/subagent.js.map +1 -1
- package/dist/harness/tools/event.d.ts.map +1 -1
- package/dist/harness/tools/event.js +0 -9
- package/dist/harness/tools/event.js.map +1 -1
- package/dist/harness/tools/generate-image.d.ts +0 -6
- package/dist/harness/tools/generate-image.d.ts.map +1 -1
- package/dist/harness/tools/generate-image.js.map +1 -1
- package/dist/harness/tools/host-fn-tool.d.ts +0 -17
- package/dist/harness/tools/host-fn-tool.d.ts.map +1 -1
- package/dist/harness/tools/host-fn-tool.js +0 -16
- package/dist/harness/tools/host-fn-tool.js.map +1 -1
- package/dist/harness/tools/index.d.ts +1 -7
- package/dist/harness/tools/index.d.ts.map +1 -1
- package/dist/harness/tools/index.js +3 -14
- package/dist/harness/tools/index.js.map +1 -1
- package/dist/harness/tools/jev-browser.d.ts +4 -94
- package/dist/harness/tools/jev-browser.d.ts.map +1 -1
- package/dist/harness/tools/jev-browser.js +203 -92
- package/dist/harness/tools/jev-browser.js.map +1 -1
- package/dist/harness/tools/jev.d.ts +0 -8
- package/dist/harness/tools/jev.d.ts.map +1 -1
- package/dist/harness/tools/jev.js +0 -11
- package/dist/harness/tools/jev.js.map +1 -1
- package/dist/harness/tools/pi-tools.d.ts +1 -11
- package/dist/harness/tools/pi-tools.d.ts.map +1 -1
- package/dist/harness/tools/pi-tools.js +1 -30
- package/dist/harness/tools/pi-tools.js.map +1 -1
- package/dist/harness/tools/react.d.ts +0 -5
- package/dist/harness/tools/react.d.ts.map +1 -1
- package/dist/harness/tools/react.js +0 -5
- package/dist/harness/tools/react.js.map +1 -1
- package/dist/harness/tools/secret-redaction.d.ts +0 -25
- package/dist/harness/tools/secret-redaction.d.ts.map +1 -1
- package/dist/harness/tools/secret-redaction.js +3 -36
- package/dist/harness/tools/secret-redaction.js.map +1 -1
- package/dist/harness/tools/subagent.d.ts +0 -34
- package/dist/harness/tools/subagent.d.ts.map +1 -1
- package/dist/harness/tools/subagent.js +0 -92
- package/dist/harness/tools/subagent.js.map +1 -1
- package/dist/harness/tools/task.d.ts +0 -1
- package/dist/harness/tools/task.d.ts.map +1 -1
- package/dist/harness/tools/task.js +0 -1
- package/dist/harness/tools/task.js.map +1 -1
- package/dist/harness/tools/types.d.ts +0 -16
- package/dist/harness/tools/types.d.ts.map +1 -1
- package/dist/harness/tools/types.js.map +1 -1
- package/dist/harness/types.d.ts +1 -77
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +0 -13
- package/dist/log.js.map +1 -1
- package/dist/main.js +7 -52
- package/dist/main.js.map +1 -1
- package/dist/memory-capture/index.d.ts +16 -0
- package/dist/memory-capture/index.d.ts.map +1 -0
- package/dist/memory-capture/index.js +194 -0
- package/dist/memory-capture/index.js.map +1 -0
- package/dist/memory-capture/types.d.ts +27 -0
- package/dist/memory-capture/types.d.ts.map +1 -0
- package/dist/memory-capture/types.js.map +1 -0
- package/dist/observability/index.d.ts +0 -9
- package/dist/observability/index.d.ts.map +1 -1
- package/dist/observability/index.js +0 -9
- package/dist/observability/index.js.map +1 -1
- package/dist/observability/instrument.js +0 -5
- package/dist/observability/instrument.js.map +1 -1
- package/dist/observability/otel.js +0 -1
- package/dist/observability/otel.js.map +1 -1
- package/dist/observability/sentry.d.ts +0 -18
- package/dist/observability/sentry.d.ts.map +1 -1
- package/dist/observability/sentry.js +0 -36
- package/dist/observability/sentry.js.map +1 -1
- package/dist/observability/types.d.ts +1 -10
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/observability/types.js.map +1 -1
- package/dist/office/index.d.ts +0 -76
- package/dist/office/index.d.ts.map +1 -1
- package/dist/office/index.js +4 -154
- package/dist/office/index.js.map +1 -1
- package/dist/office/projection.d.ts +0 -29
- package/dist/office/projection.d.ts.map +1 -1
- package/dist/office/projection.js +5 -41
- package/dist/office/projection.js.map +1 -1
- package/dist/office/types.d.ts +0 -66
- package/dist/office/types.d.ts.map +1 -1
- package/dist/office/types.js.map +1 -1
- package/dist/runtime/conversation-runtime.d.ts.map +1 -1
- package/dist/runtime/conversation-runtime.js +22 -83
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/session-lifecycle.d.ts +0 -10
- package/dist/runtime/session-lifecycle.d.ts.map +1 -1
- package/dist/runtime/session-lifecycle.js +0 -12
- package/dist/runtime/session-lifecycle.js.map +1 -1
- package/dist/runtime/types.d.ts +2 -29
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +2 -1
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +21 -15
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +0 -2
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/identity.d.ts +0 -28
- package/dist/sandbox/identity.d.ts.map +1 -1
- package/dist/sandbox/identity.js +0 -28
- package/dist/sandbox/identity.js.map +1 -1
- package/dist/sandbox/index.d.ts +0 -18
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +2 -19
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/layout.d.ts +7 -0
- package/dist/sandbox/layout.d.ts.map +1 -0
- package/dist/sandbox/layout.js +13 -0
- package/dist/sandbox/layout.js.map +1 -0
- package/dist/sandbox/provisioner.d.ts +24 -65
- package/dist/sandbox/provisioner.d.ts.map +1 -1
- package/dist/sandbox/provisioner.js +213 -125
- package/dist/sandbox/provisioner.js.map +1 -1
- package/dist/sandbox/types.d.ts +0 -39
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sandbox/utils.d.ts +2 -5
- package/dist/sandbox/utils.d.ts.map +1 -1
- package/dist/sandbox/utils.js +31 -31
- package/dist/sandbox/utils.js.map +1 -1
- package/dist/sessions/chat-history-sync.d.ts +0 -6
- package/dist/sessions/chat-history-sync.d.ts.map +1 -1
- package/dist/sessions/chat-history-sync.js +1 -33
- package/dist/sessions/chat-history-sync.js.map +1 -1
- package/dist/sessions/history-line.d.ts +0 -20
- package/dist/sessions/history-line.d.ts.map +1 -1
- package/dist/sessions/history-line.js +0 -20
- package/dist/sessions/history-line.js.map +1 -1
- package/dist/sessions/migrate-common.d.ts +0 -15
- package/dist/sessions/migrate-common.d.ts.map +1 -1
- package/dist/sessions/migrate-common.js +0 -19
- package/dist/sessions/migrate-common.js.map +1 -1
- package/dist/sessions/migrate-pi-084.d.ts.map +1 -1
- package/dist/sessions/migrate-pi-084.js +0 -7
- package/dist/sessions/migrate-pi-084.js.map +1 -1
- package/dist/sessions/migrate-v3.d.ts +0 -7
- package/dist/sessions/migrate-v3.d.ts.map +1 -1
- package/dist/sessions/migrate-v3.js +1 -67
- package/dist/sessions/migrate-v3.js.map +1 -1
- package/dist/sessions/session-key.d.ts +3 -17
- package/dist/sessions/session-key.d.ts.map +1 -1
- package/dist/sessions/session-key.js +8 -35
- package/dist/sessions/session-key.js.map +1 -1
- package/dist/sessions/session-store.d.ts +1 -7
- package/dist/sessions/session-store.d.ts.map +1 -1
- package/dist/sessions/session-store.js +8 -50
- package/dist/sessions/session-store.js.map +1 -1
- package/dist/sessions/store.d.ts +0 -60
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +0 -113
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +0 -17
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js.map +1 -1
- package/dist/settings/apply.d.ts +0 -6
- package/dist/settings/apply.d.ts.map +1 -1
- package/dist/settings/apply.js +0 -29
- package/dist/settings/apply.js.map +1 -1
- package/dist/settings/index.d.ts +0 -53
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +0 -77
- package/dist/settings/index.js.map +1 -1
- package/dist/settings/migrate.d.ts +0 -5
- package/dist/settings/migrate.d.ts.map +1 -1
- package/dist/settings/migrate.js +0 -17
- package/dist/settings/migrate.js.map +1 -1
- package/dist/types.d.ts +9 -159
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vault/index.d.ts +2 -36
- package/dist/vault/index.d.ts.map +1 -1
- package/dist/vault/index.js +135 -65
- package/dist/vault/index.js.map +1 -1
- package/dist/vault/types.d.ts +0 -15
- package/dist/vault/types.d.ts.map +1 -1
- package/dist/vault/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/dream/index.d.ts +0 -20
- package/dist/dream/index.d.ts.map +0 -1
- package/dist/dream/index.js +0 -264
- package/dist/dream/index.js.map +0 -1
- package/dist/dream/types.d.ts +0 -30
- package/dist/dream/types.d.ts.map +0 -1
- package/dist/dream/types.js.map +0 -1
- /package/dist/{dream → memory-capture}/types.js +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
2
|
import { legacyConversationResourceKey, sanitizeIdentitySegment } from "./identity.js";
|
|
3
|
+
import { GUEST_HOME, GUEST_PUBLIC_OFFICES_DIR } from "./layout.js";
|
|
3
4
|
import { createHash } from "node:crypto";
|
|
4
5
|
import { readFileSync, statSync } from "node:fs";
|
|
5
6
|
import { promisify } from "node:util";
|
|
@@ -19,7 +20,6 @@ function isDockerNotFoundError(err) {
|
|
|
19
20
|
/network [^\n]+ not found/.test(haystack) ||
|
|
20
21
|
/error: no such [^\n]+/.test(haystack));
|
|
21
22
|
}
|
|
22
|
-
/** Parse `src:dst[:ro]` back into a ContainerMount for signature computation. */
|
|
23
23
|
function bindSpecToMount(bindSpec) {
|
|
24
24
|
const readOnly = bindSpec.endsWith(":ro");
|
|
25
25
|
const spec = readOnly ? bindSpec.slice(0, -3) : bindSpec;
|
|
@@ -43,6 +43,7 @@ export class DockerContainerManager {
|
|
|
43
43
|
this.state = new Map();
|
|
44
44
|
this.inflight = new Map();
|
|
45
45
|
this.layoutMigrations = new Map();
|
|
46
|
+
this.keyQueues = new Map();
|
|
46
47
|
this.boostedKeys = new Set();
|
|
47
48
|
this.overrideLimits = new Map();
|
|
48
49
|
this.limits = options.limits;
|
|
@@ -58,11 +59,25 @@ export class DockerContainerManager {
|
|
|
58
59
|
static networkName(containerKey) {
|
|
59
60
|
return `mikan-sandbox-net-${containerKey}`;
|
|
60
61
|
}
|
|
62
|
+
static homeVolumeName(containerKey) {
|
|
63
|
+
return `mikan-home-${containerKey}`;
|
|
64
|
+
}
|
|
65
|
+
serialize(containerKey, task) {
|
|
66
|
+
const previous = this.keyQueues.get(containerKey) ?? Promise.resolve();
|
|
67
|
+
const next = previous.then(task, task);
|
|
68
|
+
const settled = next.catch(() => undefined);
|
|
69
|
+
this.keyQueues.set(containerKey, settled);
|
|
70
|
+
void settled.then(() => {
|
|
71
|
+
if (this.keyQueues.get(containerKey) === settled)
|
|
72
|
+
this.keyQueues.delete(containerKey);
|
|
73
|
+
});
|
|
74
|
+
return next;
|
|
75
|
+
}
|
|
61
76
|
async provision(containerKey, options = {}) {
|
|
62
77
|
const existing = this.inflight.get(containerKey);
|
|
63
78
|
if (existing)
|
|
64
79
|
return existing;
|
|
65
|
-
const pending = this.provisionInner(containerKey, options).finally(() => {
|
|
80
|
+
const pending = this.serialize(containerKey, () => this.provisionInner(containerKey, options)).finally(() => {
|
|
66
81
|
this.inflight.delete(containerKey);
|
|
67
82
|
});
|
|
68
83
|
this.inflight.set(containerKey, pending);
|
|
@@ -71,15 +86,25 @@ export class DockerContainerManager {
|
|
|
71
86
|
async provisionInner(containerKey, options) {
|
|
72
87
|
const containerName = options.containerName ?? DockerContainerManager.containerName(containerKey);
|
|
73
88
|
const mounts = options.mounts ?? [];
|
|
74
|
-
// A container still on the pre-office layout must move its writable layer
|
|
75
|
-
// to the new mounts before the drift check below would recreate it from
|
|
76
|
-
// the base image and discard everything installed inside.
|
|
77
89
|
await this.migrateContainerLayout(containerName);
|
|
78
90
|
const status = await this.inspectStatus(containerName);
|
|
79
91
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
92
|
+
const binds = status === "missing" ? [] : await this.inspectBindMounts(containerName);
|
|
93
|
+
const homeVolume = this.hasHomeVolumeBind(containerKey, binds);
|
|
94
|
+
const drift = status === "missing"
|
|
95
|
+
? undefined
|
|
96
|
+
: await this.runtimeDrift(containerKey, containerName, mounts, {
|
|
97
|
+
binds,
|
|
98
|
+
status,
|
|
99
|
+
homeVolume,
|
|
100
|
+
});
|
|
101
|
+
if (drift && homeVolume) {
|
|
102
|
+
log.logInfo(`Container ${containerName} is out of date (${drift}); replacing container`);
|
|
103
|
+
await this.replaceHomeVolumeContainer(containerKey, containerName, mounts, options);
|
|
104
|
+
log.logInfo(`Container ${containerName} replaced from image ${this.image}`);
|
|
105
|
+
}
|
|
106
|
+
else if (drift) {
|
|
107
|
+
log.logInfo(`Container ${containerName} configuration changed (${drift}); recreating container`);
|
|
83
108
|
await this.recreateContainerPreservingContents(containerKey, containerName, mounts);
|
|
84
109
|
log.logInfo(`Container ${containerName} recreated`);
|
|
85
110
|
}
|
|
@@ -131,7 +156,10 @@ export class DockerContainerManager {
|
|
|
131
156
|
getBoostLimits() {
|
|
132
157
|
return this.boostLimits;
|
|
133
158
|
}
|
|
134
|
-
|
|
159
|
+
stop(containerKey) {
|
|
160
|
+
return this.serialize(containerKey, () => this.stopInner(containerKey));
|
|
161
|
+
}
|
|
162
|
+
async stopInner(containerKey) {
|
|
135
163
|
const containerName = this.getContainerName(containerKey);
|
|
136
164
|
try {
|
|
137
165
|
await this.execFileImpl("docker", ["stop", containerName]);
|
|
@@ -144,14 +172,14 @@ export class DockerContainerManager {
|
|
|
144
172
|
log.logWarning(`Failed to stop container ${containerName}`, err instanceof Error ? err.message : String(err));
|
|
145
173
|
}
|
|
146
174
|
}
|
|
147
|
-
|
|
175
|
+
remove(containerKey, options = {}) {
|
|
176
|
+
return this.serialize(containerKey, () => this.removeInner(containerKey, options));
|
|
177
|
+
}
|
|
178
|
+
async removeInner(containerKey, options) {
|
|
148
179
|
const containerName = this.getContainerName(containerKey);
|
|
149
180
|
const networkName = DockerContainerManager.networkName(containerKey);
|
|
150
181
|
const removed = await this.forceRemoveContainer(containerName, `Container ${containerName} removed`, `Failed to remove container ${containerName}`);
|
|
151
182
|
if (!removed) {
|
|
152
|
-
// The container may still be running with its old mounts. Keeping the
|
|
153
|
-
// ownership state (and throwing) is the honest outcome: callers such
|
|
154
|
-
// as credential refresh must not report a teardown that did not happen.
|
|
155
183
|
throw new Error(`Failed to remove container ${containerName}`);
|
|
156
184
|
}
|
|
157
185
|
try {
|
|
@@ -162,6 +190,8 @@ export class DockerContainerManager {
|
|
|
162
190
|
log.logWarning(`Failed to remove network ${networkName}`, err instanceof Error ? err.message : String(err));
|
|
163
191
|
}
|
|
164
192
|
await this.removeMigrateSnapshot(containerName);
|
|
193
|
+
if (options.purgeHome)
|
|
194
|
+
await this.removeHomeVolume(containerKey);
|
|
165
195
|
this.state.delete(containerKey);
|
|
166
196
|
this.boostedKeys.delete(containerKey);
|
|
167
197
|
this.overrideLimits.delete(containerKey);
|
|
@@ -176,12 +206,6 @@ export class DockerContainerManager {
|
|
|
176
206
|
}
|
|
177
207
|
await Promise.all(toStop.map((containerKey) => this.stop(containerKey)));
|
|
178
208
|
}
|
|
179
|
-
/**
|
|
180
|
-
* Force-remove every managed container belonging to the given conversation
|
|
181
|
-
* ids. The office layout migration renames the host directories a
|
|
182
|
-
* container's workspace mount points at, so a surviving container would keep
|
|
183
|
-
* writing through stale mounts while the runtime works in the new location.
|
|
184
|
-
*/
|
|
185
209
|
async removeContainersForConversations(conversationIds) {
|
|
186
210
|
if (conversationIds.size === 0)
|
|
187
211
|
return;
|
|
@@ -190,33 +214,20 @@ export class DockerContainerManager {
|
|
|
190
214
|
const details = await this.inspectContainerDetails(containerName);
|
|
191
215
|
if (!details?.conversationId || !conversationIds.has(details.conversationId))
|
|
192
216
|
return;
|
|
193
|
-
await this.forceRemoveContainer(containerName, `Removed container ${containerName} after office migration`, `Failed to remove container ${containerName} after office migration`);
|
|
217
|
+
const removed = await this.forceRemoveContainer(containerName, `Removed container ${containerName} after office migration`, `Failed to remove container ${containerName} after office migration`);
|
|
218
|
+
const containerKey = this.containerKeyFromContainerName(containerName);
|
|
219
|
+
if (removed && containerKey)
|
|
220
|
+
await this.removeHomeVolume(containerKey);
|
|
194
221
|
}));
|
|
195
222
|
}
|
|
196
|
-
/**
|
|
197
|
-
* Arm the office-layout container migration. Containers whose binds still
|
|
198
|
-
* reference legacy raw-id paths are moved to the office-key layout without
|
|
199
|
-
* losing their writable layer: commit → remove → create with translated
|
|
200
|
-
* binds, preserving everything installed inside. Idempotent per container
|
|
201
|
-
* and resumable — the pre-removal binds ride on the snapshot image label,
|
|
202
|
-
* so a crash between commit and create resumes from the snapshot.
|
|
203
|
-
*/
|
|
204
223
|
armContainerLayoutMigration(translator) {
|
|
205
224
|
this.bindTranslator = translator;
|
|
206
225
|
}
|
|
207
|
-
/**
|
|
208
|
-
* Sweep every managed container through the layout migration, serially and
|
|
209
|
-
* with a small gap, so the one-time cost never lands on the boot path or on
|
|
210
|
-
* a message. Safe to fire-and-forget; each unit is idempotent.
|
|
211
|
-
*/
|
|
212
226
|
async sweepContainerLayoutMigration(delayMs = 2000) {
|
|
213
227
|
if (!this.bindTranslator)
|
|
214
228
|
return;
|
|
215
229
|
let names;
|
|
216
230
|
try {
|
|
217
|
-
// Include snapshot names: a crash between commit and create leaves a
|
|
218
|
-
// snapshot with no container, which must resume before the GC below
|
|
219
|
-
// could mistake it for an orphan.
|
|
220
231
|
const containers = await this.listContainerNamesByLabel();
|
|
221
232
|
const snapshots = await this.listMigrateSnapshotContainerNames();
|
|
222
233
|
names = Array.from(new Set([...containers, ...snapshots]));
|
|
@@ -234,11 +245,8 @@ export class DockerContainerManager {
|
|
|
234
245
|
}
|
|
235
246
|
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
236
247
|
}
|
|
237
|
-
// Snapshot images whose container has since been recreated from the base
|
|
238
|
-
// image are no longer referenced; reclaim them.
|
|
239
248
|
await this.removeDanglingMigrateImages();
|
|
240
249
|
}
|
|
241
|
-
/** Move one container to the office-key layout; no-op when already there. */
|
|
242
250
|
migrateContainerLayout(containerName) {
|
|
243
251
|
const translator = this.bindTranslator;
|
|
244
252
|
if (!translator)
|
|
@@ -257,9 +265,6 @@ export class DockerContainerManager {
|
|
|
257
265
|
let originalBinds;
|
|
258
266
|
const status = await this.inspectStatus(containerName);
|
|
259
267
|
if (status === "missing") {
|
|
260
|
-
// Resume path: a previous run committed and removed the container but
|
|
261
|
-
// died before creating the replacement. The snapshot carries the
|
|
262
|
-
// pre-removal binds on its label.
|
|
263
268
|
const labeled = await this.readMigrateImageBinds(snapshotImage);
|
|
264
269
|
if (labeled === undefined)
|
|
265
270
|
return;
|
|
@@ -269,7 +274,7 @@ export class DockerContainerManager {
|
|
|
269
274
|
originalBinds = await this.inspectBindMounts(containerName);
|
|
270
275
|
const translated = originalBinds.map(translator);
|
|
271
276
|
if (this.sameBinds(translated.toSorted(), originalBinds.slice().toSorted())) {
|
|
272
|
-
return;
|
|
277
|
+
return;
|
|
273
278
|
}
|
|
274
279
|
log.logInfo(`Migrating container ${containerName} to the office layout`);
|
|
275
280
|
await this.execFileImpl("docker", [
|
|
@@ -282,25 +287,11 @@ export class DockerContainerManager {
|
|
|
282
287
|
await this.execFileImpl("docker", ["rm", "-f", containerName]);
|
|
283
288
|
}
|
|
284
289
|
await this.createContainerFromSnapshot(containerName, originalBinds.map(translator));
|
|
285
|
-
// The snapshot's only job was bridging commit → create; the new container
|
|
286
|
-
// already owns that content in its own writable layer; untagging it now
|
|
287
|
-
// (rather than waiting for a "natural recreation from the base image"
|
|
288
|
-
// that never happens — every recreation path here targets this same
|
|
289
|
-
// snapshot family) is what makes migration actually one-time instead of
|
|
290
|
-
// repeating on every future sweep that still finds the tag.
|
|
291
290
|
await this.removeMigrateSnapshot(containerName);
|
|
292
291
|
log.logInfo(`Container ${containerName} migrated to the office layout`);
|
|
293
292
|
}
|
|
294
|
-
/**
|
|
295
|
-
* Create `containerName` from its layout snapshot with `bindSpecs`,
|
|
296
|
-
* restoring the managed labels and recomputing the mount signature.
|
|
297
|
-
* `create`, not `run`: idle containers stay stopped exactly as they were;
|
|
298
|
-
* callers that need the container running start it themselves.
|
|
299
|
-
*/
|
|
300
293
|
async createContainerFromSnapshot(containerName, bindSpecs, knownContainerKey) {
|
|
301
294
|
const snapshotImage = `${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`;
|
|
302
|
-
// The sweep has only the container name and derives the key; the drift
|
|
303
|
-
// path knows the real key (container names can be caller-supplied).
|
|
304
295
|
const containerKey = knownContainerKey ?? this.containerKeyFromContainerName(containerName) ?? containerName;
|
|
305
296
|
const networkName = await this.ensureNetwork(containerKey);
|
|
306
297
|
const conversationId = await this.readImageLabel(snapshotImage, DockerContainerManager.CONVERSATION_ID_LABEL_KEY);
|
|
@@ -336,21 +327,14 @@ export class DockerContainerManager {
|
|
|
336
327
|
"infinity",
|
|
337
328
|
]);
|
|
338
329
|
}
|
|
339
|
-
/**
|
|
340
|
-
* `docker commit` captures the empty directories Docker created as bind
|
|
341
|
-
* targets, so a public office that stopped being mounted would linger in
|
|
342
|
-
* the snapshot as an empty `/workspace/public/<key>`. Remove any entry
|
|
343
|
-
* there that no current bind targets; only empty directories are removed,
|
|
344
|
-
* so a real file could never be deleted by this pass.
|
|
345
|
-
*/
|
|
346
330
|
async removeStaleMountpoints(containerName, bindSpecs) {
|
|
347
331
|
const keep = new Set(bindSpecs
|
|
348
332
|
.map((bind) => bindSpecToMount(bind).target)
|
|
349
|
-
.filter((target) => target.startsWith(
|
|
350
|
-
.map((target) => target.slice(
|
|
333
|
+
.filter((target) => target.startsWith(`${GUEST_PUBLIC_OFFICES_DIR}/`))
|
|
334
|
+
.map((target) => target.slice(GUEST_PUBLIC_OFFICES_DIR.length + 1)));
|
|
351
335
|
const script = [
|
|
352
|
-
|
|
353
|
-
"for d in
|
|
336
|
+
`cd ${GUEST_PUBLIC_OFFICES_DIR} 2>/dev/null || exit 0`,
|
|
337
|
+
"for d in *; do",
|
|
354
338
|
' [ -e "$d" ] || continue',
|
|
355
339
|
' case " $KEEP " in *" ${d##*/} "*) continue;; esac',
|
|
356
340
|
' rmdir "$d" 2>/dev/null || true',
|
|
@@ -371,15 +355,6 @@ export class DockerContainerManager {
|
|
|
371
355
|
log.logWarning(`Could not clean stale mountpoints in ${containerName}`, String(err));
|
|
372
356
|
}
|
|
373
357
|
}
|
|
374
|
-
/**
|
|
375
|
-
* Recreate a drifted container with the desired mounts while keeping its
|
|
376
|
-
* writable layer: commit — the new binds ride the snapshot label, so a
|
|
377
|
-
* crash at any point resumes through the layout-migration path — then
|
|
378
|
-
* remove, create from the snapshot, and start. The snapshot is untagged
|
|
379
|
-
* once the new container is confirmed up: its only job was bridging
|
|
380
|
-
* commit → create, and the container now owns that content in its own
|
|
381
|
-
* writable layer, so nothing still needs the tag.
|
|
382
|
-
*/
|
|
383
358
|
async recreateContainerPreservingContents(containerKey, containerName, mounts) {
|
|
384
359
|
const snapshotImage = `${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`;
|
|
385
360
|
const bindSpecs = mounts.map((mount) => this.toBindSpec(mount));
|
|
@@ -396,7 +371,6 @@ export class DockerContainerManager {
|
|
|
396
371
|
await this.removeStaleMountpoints(containerName, bindSpecs);
|
|
397
372
|
await this.removeMigrateSnapshot(containerName);
|
|
398
373
|
}
|
|
399
|
-
/** Binds recorded on a snapshot image, or undefined when no snapshot exists. */
|
|
400
374
|
async readMigrateImageBinds(snapshotImage) {
|
|
401
375
|
const raw = await this.readImageLabel(snapshotImage, DockerContainerManager.MIGRATE_BINDS_LABEL_KEY);
|
|
402
376
|
if (raw === undefined)
|
|
@@ -421,11 +395,6 @@ export class DockerContainerManager {
|
|
|
421
395
|
return undefined;
|
|
422
396
|
}
|
|
423
397
|
}
|
|
424
|
-
/**
|
|
425
|
-
* Delete a container's layout snapshot after an intentional removal, so a
|
|
426
|
-
* missing container plus a surviving snapshot can only mean a crash in the
|
|
427
|
-
* middle of the layout migration (the resume discriminator).
|
|
428
|
-
*/
|
|
429
398
|
async removeMigrateSnapshot(containerName) {
|
|
430
399
|
try {
|
|
431
400
|
await this.execFileImpl("docker", [
|
|
@@ -433,9 +402,7 @@ export class DockerContainerManager {
|
|
|
433
402
|
`${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`,
|
|
434
403
|
]);
|
|
435
404
|
}
|
|
436
|
-
catch {
|
|
437
|
-
// No snapshot for this container — the common case.
|
|
438
|
-
}
|
|
405
|
+
catch { }
|
|
439
406
|
}
|
|
440
407
|
async listMigrateSnapshotContainerNames() {
|
|
441
408
|
try {
|
|
@@ -451,17 +418,6 @@ export class DockerContainerManager {
|
|
|
451
418
|
return [];
|
|
452
419
|
}
|
|
453
420
|
}
|
|
454
|
-
/**
|
|
455
|
-
* Catch-up pass for snapshots the success path in
|
|
456
|
-
* `migrateContainerLayoutInner` did not get to remove itself — e.g. a
|
|
457
|
-
* crash between `createContainerFromSnapshot` and its own cleanup. A
|
|
458
|
-
* snapshot is only still needed while its container remains "missing"
|
|
459
|
-
* (the resume path in `migrateContainerLayoutInner` reads pre-removal
|
|
460
|
-
* binds off it); once the container exists again in any state, the
|
|
461
|
-
* snapshot has done its job regardless of whether that container's
|
|
462
|
-
* `Config.Image` still points at it — removing a tag never deletes
|
|
463
|
-
* layers a live container still uses.
|
|
464
|
-
*/
|
|
465
421
|
async removeDanglingMigrateImages() {
|
|
466
422
|
let stdout;
|
|
467
423
|
try {
|
|
@@ -479,7 +435,7 @@ export class DockerContainerManager {
|
|
|
479
435
|
const containerName = image.slice(DockerContainerManager.MIGRATE_IMAGE_PREFIX.length + 1);
|
|
480
436
|
const status = await this.inspectStatus(containerName);
|
|
481
437
|
if (status === "missing")
|
|
482
|
-
continue;
|
|
438
|
+
continue;
|
|
483
439
|
try {
|
|
484
440
|
await this.execFileImpl("docker", ["rmi", image]);
|
|
485
441
|
log.logInfo(`Removed layout-migration snapshot image ${image}`);
|
|
@@ -515,9 +471,6 @@ export class DockerContainerManager {
|
|
|
515
471
|
log.logWarning(`Skipping unmanaged-style container without container key`, containerName);
|
|
516
472
|
continue;
|
|
517
473
|
}
|
|
518
|
-
// Containers keyed under the pre-office raw-conversation resource key
|
|
519
|
-
// are unreachable now that resource identity is the office key: no
|
|
520
|
-
// provision will ever address them again, so reap rather than adopt.
|
|
521
474
|
if (containerKey === legacyConversationResourceKey(details.conversationId)) {
|
|
522
475
|
legacyRemovals.push(this.forceRemoveContainer(containerName, `Removed container ${containerName} keyed by pre-office resource identity`, `Failed to remove legacy-keyed container ${containerName}`).then(() => undefined));
|
|
523
476
|
continue;
|
|
@@ -542,13 +495,11 @@ export class DockerContainerManager {
|
|
|
542
495
|
return mounts.flatMap((mount) => ["-v", this.toBindSpec(mount)]);
|
|
543
496
|
}
|
|
544
497
|
toBindSpec(mount) {
|
|
545
|
-
// The `:ro` suffix is part of the bind spec, so it also flows into
|
|
546
|
-
// expectedBinds/mountSignature — flipping a mount's writability is drift
|
|
547
|
-
// and recreates the container rather than leaving a stale writable bind.
|
|
548
498
|
return `${mount.source}:${mount.target}${mount.readOnly ? ":ro" : ""}`;
|
|
549
499
|
}
|
|
550
500
|
async runContainer(containerKey, containerName, mounts, options) {
|
|
551
501
|
const networkName = await this.ensureNetwork(containerKey);
|
|
502
|
+
const homeVolume = await this.ensureHomeVolume(containerKey);
|
|
552
503
|
log.logInfo(`Creating container ${containerName} from image ${this.image}`);
|
|
553
504
|
const labels = [
|
|
554
505
|
"--label",
|
|
@@ -579,6 +530,8 @@ export class DockerContainerManager {
|
|
|
579
530
|
"1024",
|
|
580
531
|
...labels,
|
|
581
532
|
...this.resourceLimitArgs(this.effectiveLimits(containerKey)),
|
|
533
|
+
"-v",
|
|
534
|
+
`${homeVolume}:${GUEST_HOME}`,
|
|
582
535
|
...this.mountArgs(mounts),
|
|
583
536
|
this.image,
|
|
584
537
|
"sleep",
|
|
@@ -599,9 +552,6 @@ export class DockerContainerManager {
|
|
|
599
552
|
args.push("--cpus", limits.cpus);
|
|
600
553
|
if (limits?.memory) {
|
|
601
554
|
args.push("--memory", limits.memory);
|
|
602
|
-
// Keep Docker's no-extra-swap semantics explicit. Docker requires
|
|
603
|
-
// memory-swap to be updated together when raising an existing memory
|
|
604
|
-
// limit above the current swap limit.
|
|
605
555
|
args.push("--memory-swap", limits.memory);
|
|
606
556
|
}
|
|
607
557
|
return args;
|
|
@@ -631,18 +581,22 @@ export class DockerContainerManager {
|
|
|
631
581
|
});
|
|
632
582
|
}
|
|
633
583
|
}
|
|
634
|
-
async
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (await this.hasMountSignatureDrift(containerName, mounts))
|
|
639
|
-
return
|
|
584
|
+
async runtimeDrift(containerKey, containerName, mounts, current) {
|
|
585
|
+
const { binds, status, homeVolume } = current;
|
|
586
|
+
if (this.hasBindMountDrift(binds, mounts))
|
|
587
|
+
return "binds";
|
|
588
|
+
if (await this.hasMountSignatureDrift(containerName, mounts))
|
|
589
|
+
return "mount-content";
|
|
590
|
+
if (await this.hasNetworkModeDrift(containerKey, containerName))
|
|
591
|
+
return "network";
|
|
592
|
+
if (homeVolume && status === "stopped" && (await this.hasImageDrift(containerName))) {
|
|
593
|
+
return "image";
|
|
640
594
|
}
|
|
641
|
-
return
|
|
595
|
+
return undefined;
|
|
642
596
|
}
|
|
643
|
-
|
|
597
|
+
hasBindMountDrift(binds, mounts) {
|
|
644
598
|
const expected = this.expectedBinds(mounts);
|
|
645
|
-
const actual =
|
|
599
|
+
const actual = binds.filter((bind) => !this.isHomeVolumeBind(bind));
|
|
646
600
|
return !this.sameBinds(expected, actual);
|
|
647
601
|
}
|
|
648
602
|
expectedBinds(mounts) {
|
|
@@ -684,16 +638,8 @@ export class DockerContainerManager {
|
|
|
684
638
|
try {
|
|
685
639
|
const stat = statSync(source);
|
|
686
640
|
if (stat.isFile()) {
|
|
687
|
-
// Files are atomically replaced (rename), which leaves the container
|
|
688
|
-
// holding a stale inode — content changes must recreate the mount.
|
|
689
641
|
return createHash("sha256").update(readFileSync(source)).digest("hex");
|
|
690
642
|
}
|
|
691
|
-
// Directories: a bind mount follows changes inside the directory live,
|
|
692
|
-
// so only replacing the directory itself makes the mount stale.
|
|
693
|
-
// Size/mtime churn from ordinary activity — event files coming and
|
|
694
|
-
// going, children being created — must not read as drift. Identity is
|
|
695
|
-
// dev:ino plus birth time, because ext4 recycles inode numbers
|
|
696
|
-
// immediately and a same-path replacement can reuse the old one.
|
|
697
643
|
return `${stat.isDirectory() ? "dir" : "other"}:${stat.dev}:${stat.ino}:${stat.birthtimeMs}`;
|
|
698
644
|
}
|
|
699
645
|
catch {
|
|
@@ -717,6 +663,149 @@ export class DockerContainerManager {
|
|
|
717
663
|
}
|
|
718
664
|
return [...parsed].toSorted();
|
|
719
665
|
}
|
|
666
|
+
isHomeVolumeBind(bind) {
|
|
667
|
+
const separator = bind.indexOf(":");
|
|
668
|
+
if (separator === -1)
|
|
669
|
+
return false;
|
|
670
|
+
const source = bind.slice(0, separator);
|
|
671
|
+
const target = bind.slice(separator + 1).replace(/:r[ow]$/, "");
|
|
672
|
+
return source.startsWith(DockerContainerManager.homeVolumeName("")) && target === GUEST_HOME;
|
|
673
|
+
}
|
|
674
|
+
hasHomeVolumeBind(containerKey, binds) {
|
|
675
|
+
const expected = `${DockerContainerManager.homeVolumeName(containerKey)}:${GUEST_HOME}`;
|
|
676
|
+
return binds.includes(expected);
|
|
677
|
+
}
|
|
678
|
+
async hasHomeVolume(containerKey, containerName) {
|
|
679
|
+
return this.hasHomeVolumeBind(containerKey, await this.inspectBindMounts(containerName));
|
|
680
|
+
}
|
|
681
|
+
async hasImageDrift(containerName) {
|
|
682
|
+
const desired = await this.localImageId();
|
|
683
|
+
if (!desired)
|
|
684
|
+
return false;
|
|
685
|
+
const { stdout } = await this.execFileImpl("docker", [
|
|
686
|
+
"inspect",
|
|
687
|
+
"-f",
|
|
688
|
+
"{{.Image}}",
|
|
689
|
+
containerName,
|
|
690
|
+
]);
|
|
691
|
+
return stdout.trim() !== desired;
|
|
692
|
+
}
|
|
693
|
+
async localImageId() {
|
|
694
|
+
try {
|
|
695
|
+
const { stdout } = await this.execFileImpl("docker", [
|
|
696
|
+
"image",
|
|
697
|
+
"inspect",
|
|
698
|
+
"-f",
|
|
699
|
+
"{{.Id}}",
|
|
700
|
+
this.image,
|
|
701
|
+
]);
|
|
702
|
+
return this.normalizeDockerValue(stdout.trim());
|
|
703
|
+
}
|
|
704
|
+
catch {
|
|
705
|
+
return undefined;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
async ensureHomeVolume(containerKey) {
|
|
709
|
+
const volumeName = DockerContainerManager.homeVolumeName(containerKey);
|
|
710
|
+
await this.execFileImpl("docker", [
|
|
711
|
+
"volume",
|
|
712
|
+
"create",
|
|
713
|
+
"--label",
|
|
714
|
+
DockerContainerManager.MANAGED_LABEL,
|
|
715
|
+
"--label",
|
|
716
|
+
`${DockerContainerManager.VAULT_ID_LABEL_KEY}=${containerKey}`,
|
|
717
|
+
volumeName,
|
|
718
|
+
]);
|
|
719
|
+
return volumeName;
|
|
720
|
+
}
|
|
721
|
+
async removeHomeVolume(containerKey) {
|
|
722
|
+
const volumeName = DockerContainerManager.homeVolumeName(containerKey);
|
|
723
|
+
try {
|
|
724
|
+
await this.execFileImpl("docker", ["volume", "rm", volumeName]);
|
|
725
|
+
log.logInfo(`Home volume ${volumeName} removed`);
|
|
726
|
+
}
|
|
727
|
+
catch (err) {
|
|
728
|
+
if (isDockerNotFoundError(err))
|
|
729
|
+
return;
|
|
730
|
+
log.logWarning(`Failed to remove home volume ${volumeName}`, err instanceof Error ? err.message : String(err));
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async replaceHomeVolumeContainer(containerKey, containerName, mounts, options) {
|
|
734
|
+
const removed = await this.forceRemoveContainer(containerName, `Container ${containerName} removed for replacement`, `Failed to remove container ${containerName} for replacement`);
|
|
735
|
+
if (!removed)
|
|
736
|
+
throw new Error(`Failed to remove container ${containerName} for replacement`);
|
|
737
|
+
await this.runContainer(containerKey, containerName, mounts, options);
|
|
738
|
+
}
|
|
739
|
+
async inventory() {
|
|
740
|
+
const names = await this.listContainerNamesByLabel();
|
|
741
|
+
const entries = [];
|
|
742
|
+
for (const containerName of names) {
|
|
743
|
+
const containerKey = this.containerKeyFromContainerName(containerName);
|
|
744
|
+
const status = await this.inspectStatus(containerName);
|
|
745
|
+
if (status === "missing")
|
|
746
|
+
continue;
|
|
747
|
+
const homeVolume = containerKey
|
|
748
|
+
? await this.hasHomeVolume(containerKey, containerName)
|
|
749
|
+
: false;
|
|
750
|
+
entries.push({
|
|
751
|
+
containerName,
|
|
752
|
+
...(containerKey ? { containerKey } : {}),
|
|
753
|
+
running: status === "running",
|
|
754
|
+
homeVolume,
|
|
755
|
+
imageStale: await this.hasImageDrift(containerName),
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
return entries;
|
|
759
|
+
}
|
|
760
|
+
async systemChanges(containerName) {
|
|
761
|
+
const { stdout } = await this.execFileImpl("docker", ["diff", containerName]);
|
|
762
|
+
return this.parseNameLines(stdout).filter((line) => {
|
|
763
|
+
const path = line.slice(2);
|
|
764
|
+
return !this.isUnderGuestPath(path, GUEST_HOME) && !this.isUnderGuestPath(path, "/workspace");
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
isUnderGuestPath(path, root) {
|
|
768
|
+
return path === root || path.startsWith(`${root}/`);
|
|
769
|
+
}
|
|
770
|
+
migrateToHomeVolume(containerKey) {
|
|
771
|
+
return this.serialize(containerKey, () => this.migrateToHomeVolumeInner(containerKey));
|
|
772
|
+
}
|
|
773
|
+
async migrateToHomeVolumeInner(containerKey) {
|
|
774
|
+
const containerName = DockerContainerManager.containerName(containerKey);
|
|
775
|
+
const status = await this.inspectStatus(containerName);
|
|
776
|
+
if (status === "missing")
|
|
777
|
+
return "missing";
|
|
778
|
+
if (await this.hasHomeVolume(containerKey, containerName))
|
|
779
|
+
return "already-migrated";
|
|
780
|
+
const details = await this.inspectContainerDetails(containerName);
|
|
781
|
+
const mounts = (await this.inspectBindMounts(containerName))
|
|
782
|
+
.filter((bind) => !this.isHomeVolumeBind(bind))
|
|
783
|
+
.map(bindSpecToMount);
|
|
784
|
+
const snapshotImage = `${DockerContainerManager.MIGRATE_IMAGE_PREFIX}:${containerName}`;
|
|
785
|
+
log.logInfo(`Migrating container ${containerName} to a home volume`);
|
|
786
|
+
await this.execFileImpl("docker", ["commit", containerName, snapshotImage]);
|
|
787
|
+
const homeVolume = await this.ensureHomeVolume(containerKey);
|
|
788
|
+
await this.execFileImpl("docker", [
|
|
789
|
+
"run",
|
|
790
|
+
"--rm",
|
|
791
|
+
"--network",
|
|
792
|
+
"none",
|
|
793
|
+
"-v",
|
|
794
|
+
`${homeVolume}:${GUEST_HOME}`,
|
|
795
|
+
snapshotImage,
|
|
796
|
+
"true",
|
|
797
|
+
]);
|
|
798
|
+
const removed = await this.forceRemoveContainer(containerName, `Container ${containerName} removed for home-volume migration`, `Failed to remove container ${containerName} for home-volume migration`);
|
|
799
|
+
if (!removed)
|
|
800
|
+
throw new Error(`Failed to remove container ${containerName}`);
|
|
801
|
+
await this.runContainer(containerKey, containerName, mounts, details?.conversationId ? { conversationId: details.conversationId } : {});
|
|
802
|
+
if (status === "stopped")
|
|
803
|
+
await this.execFileImpl("docker", ["stop", containerName]);
|
|
804
|
+
await this.removeMigrateSnapshot(containerName);
|
|
805
|
+
this.setState(containerKey, status === "stopped" ? "stopped" : "running", containerName);
|
|
806
|
+
log.logInfo(`Container ${containerName} migrated to home volume ${homeVolume}`);
|
|
807
|
+
return "migrated";
|
|
808
|
+
}
|
|
720
809
|
async hasNetworkModeDrift(containerKey, containerName) {
|
|
721
810
|
const expected = DockerContainerManager.networkName(containerKey);
|
|
722
811
|
const { stdout } = await this.execFileImpl("docker", [
|
|
@@ -849,7 +938,6 @@ export class DockerContainerManager {
|
|
|
849
938
|
const containerKey = containerName.slice(prefix.length);
|
|
850
939
|
return containerKey.length > 0 ? containerKey : undefined;
|
|
851
940
|
}
|
|
852
|
-
/** @returns true when the container is gone (removed or already missing). */
|
|
853
941
|
async forceRemoveContainer(containerName, successLog, failureLog) {
|
|
854
942
|
try {
|
|
855
943
|
await this.execFileImpl("docker", ["rm", "-f", containerName]);
|