indusagi 0.13.5 → 0.13.7
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/LICENSE +661 -0
- package/README.md +7 -1
- package/dist/cli.js +114 -23
- package/package.json +56 -45
- package/dist/agent.js +0 -28713
- package/dist/ai.js +0 -19964
- package/dist/capabilities.js +0 -2730
- package/dist/connectors-saas.js +0 -3355
- package/dist/index.js +0 -16644
- package/dist/interop.js +0 -3247
- package/dist/knowledge/guides/authoring-an-agent.md +0 -53
- package/dist/knowledge/guides/choosing-tools.md +0 -49
- package/dist/knowledge/guides/model-selection.md +0 -51
- package/dist/knowledge/guides/writing-system-prompts.md +0 -53
- package/dist/knowledge/index.ts +0 -19
- package/dist/knowledge/loader.ts +0 -200
- package/dist/knowledge/manifest.json +0 -29
- package/dist/llmgateway.js +0 -3243
- package/dist/mcp.js +0 -1639
- package/dist/memory.js +0 -0
- package/dist/react-host/index.js +0 -101
- package/dist/react-host/ink.js +0 -97
- package/dist/react-host/jsx-runtime.js +0 -95
- package/dist/react-ink.js +0 -3834
- package/dist/runtime.js +0 -4421
- package/dist/shell-app.js +0 -12333
- package/dist/smithy.js +0 -8033
- package/dist/swarm.js +0 -8818
- package/dist/tracing.js +0 -724
- package/dist/tui.js +0 -2213
- package/dist/types/capabilities/backends/index.d.ts +0 -10
- package/dist/types/capabilities/backends/node-backends.d.ts +0 -30
- package/dist/types/capabilities/capabilities.test.d.ts +0 -14
- package/dist/types/capabilities/files/diff.d.ts +0 -49
- package/dist/types/capabilities/files/edit.d.ts +0 -21
- package/dist/types/capabilities/files/ls.d.ts +0 -16
- package/dist/types/capabilities/files/read-state-gate.d.ts +0 -69
- package/dist/types/capabilities/files/read-state-gate.test.d.ts +0 -14
- package/dist/types/capabilities/files/read.d.ts +0 -15
- package/dist/types/capabilities/files/write.d.ts +0 -16
- package/dist/types/capabilities/index.d.ts +0 -29
- package/dist/types/capabilities/kernel/backends.d.ts +0 -119
- package/dist/types/capabilities/kernel/context.d.ts +0 -52
- package/dist/types/capabilities/kernel/index.d.ts +0 -24
- package/dist/types/capabilities/kernel/output.d.ts +0 -40
- package/dist/types/capabilities/kernel/registry.d.ts +0 -61
- package/dist/types/capabilities/kernel/spec.d.ts +0 -168
- package/dist/types/capabilities/planning/todo.d.ts +0 -62
- package/dist/types/capabilities/registry.d.ts +0 -44
- package/dist/types/capabilities/search/find.d.ts +0 -33
- package/dist/types/capabilities/search/grep.d.ts +0 -30
- package/dist/types/capabilities/shell/bash.d.ts +0 -18
- package/dist/types/capabilities/shell/process.d.ts +0 -33
- package/dist/types/capabilities/web/webfetch.d.ts +0 -25
- package/dist/types/capabilities/web/websearch.d.ts +0 -23
- package/dist/types/connectors-saas/connectors-saas.test.d.ts +0 -12
- package/dist/types/connectors-saas/index.d.ts +0 -16
- package/dist/types/connectors-saas/saas/adapter/composio-backend.d.ts +0 -60
- package/dist/types/connectors-saas/saas/control/connect.d.ts +0 -114
- package/dist/types/connectors-saas/saas/control/tools.d.ts +0 -67
- package/dist/types/connectors-saas/saas/core/builder.d.ts +0 -86
- package/dist/types/connectors-saas/saas/core/cache.d.ts +0 -53
- package/dist/types/connectors-saas/saas/core/index.d.ts +0 -14
- package/dist/types/connectors-saas/saas/core/port.d.ts +0 -157
- package/dist/types/connectors-saas/saas/core/scope-planner.d.ts +0 -74
- package/dist/types/connectors-saas/saas/gateway.d.ts +0 -133
- package/dist/types/connectors-saas/saas/render/format.d.ts +0 -54
- package/dist/types/connectors-saas/saas/render/index.d.ts +0 -19
- package/dist/types/connectors-saas/saas/render/summarizers.d.ts +0 -58
- package/dist/types/facade/agent.d.ts +0 -1
- package/dist/types/facade/ai.d.ts +0 -1
- package/dist/types/facade/bot/actions/bash.d.ts +0 -71
- package/dist/types/facade/bot/actions/bash.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/checkpoint.d.ts +0 -49
- package/dist/types/facade/bot/actions/checkpoint.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/composio/accounts.d.ts +0 -22
- package/dist/types/facade/bot/actions/composio/client.d.ts +0 -39
- package/dist/types/facade/bot/actions/composio/connect.d.ts +0 -19
- package/dist/types/facade/bot/actions/composio/enable.d.ts +0 -25
- package/dist/types/facade/bot/actions/composio/execute.d.ts +0 -26
- package/dist/types/facade/bot/actions/composio/helpers.d.ts +0 -16
- package/dist/types/facade/bot/actions/composio/index.d.ts +0 -9
- package/dist/types/facade/bot/actions/composio/provider.d.ts +0 -8
- package/dist/types/facade/bot/actions/composio/toolkits.d.ts +0 -22
- package/dist/types/facade/bot/actions/composio/tools.d.ts +0 -28
- package/dist/types/facade/bot/actions/composio/types.d.ts +0 -137
- package/dist/types/facade/bot/actions/crew/activity-tracker.d.ts +0 -65
- package/dist/types/facade/bot/actions/crew/cleanup.d.ts +0 -50
- package/dist/types/facade/bot/actions/crew/fs-lock.d.ts +0 -11
- package/dist/types/facade/bot/actions/crew/index.d.ts +0 -11
- package/dist/types/facade/bot/actions/crew/mailbox.d.ts +0 -20
- package/dist/types/facade/bot/actions/crew/model-policy.d.ts +0 -22
- package/dist/types/facade/bot/actions/crew/names.d.ts +0 -27
- package/dist/types/facade/bot/actions/crew/protocol.d.ts +0 -74
- package/dist/types/facade/bot/actions/crew/task-store.d.ts +0 -88
- package/dist/types/facade/bot/actions/crew/team-attach-claim.d.ts +0 -35
- package/dist/types/facade/bot/actions/crew/team-config.d.ts +0 -54
- package/dist/types/facade/bot/actions/crew/worktree.d.ts +0 -39
- package/dist/types/facade/bot/actions/edit-diff.d.ts +0 -66
- package/dist/types/facade/bot/actions/edit-utils.d.ts +0 -86
- package/dist/types/facade/bot/actions/edit.d.ts +0 -59
- package/dist/types/facade/bot/actions/edit.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/find.d.ts +0 -27
- package/dist/types/facade/bot/actions/find.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/grep.d.ts +0 -53
- package/dist/types/facade/bot/actions/grep.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/index.d.ts +0 -316
- package/dist/types/facade/bot/actions/kit/hook-runner.d.ts +0 -12
- package/dist/types/facade/bot/actions/kit/image-resize.d.ts +0 -19
- package/dist/types/facade/bot/actions/kit/mime.d.ts +0 -1
- package/dist/types/facade/bot/actions/kit/shell.d.ts +0 -12
- package/dist/types/facade/bot/actions/ls.d.ts +0 -41
- package/dist/types/facade/bot/actions/path-utils.d.ts +0 -8
- package/dist/types/facade/bot/actions/process-controller.d.ts +0 -14
- package/dist/types/facade/bot/actions/process-manager.d.ts +0 -59
- package/dist/types/facade/bot/actions/process-types.d.ts +0 -73
- package/dist/types/facade/bot/actions/process.d.ts +0 -37
- package/dist/types/facade/bot/actions/read-state.d.ts +0 -83
- package/dist/types/facade/bot/actions/read-state.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/read.d.ts +0 -43
- package/dist/types/facade/bot/actions/read.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/registry.d.ts +0 -20
- package/dist/types/facade/bot/actions/sandbox-backend.d.ts +0 -99
- package/dist/types/facade/bot/actions/sandbox-backend.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/todo-store.d.ts +0 -76
- package/dist/types/facade/bot/actions/todo-types.d.ts +0 -72
- package/dist/types/facade/bot/actions/todo.d.ts +0 -76
- package/dist/types/facade/bot/actions/truncate.d.ts +0 -78
- package/dist/types/facade/bot/actions/webfetch.d.ts +0 -35
- package/dist/types/facade/bot/actions/websearch.d.ts +0 -37
- package/dist/types/facade/bot/actions/websearch.test.d.ts +0 -1
- package/dist/types/facade/bot/actions/write.d.ts +0 -45
- package/dist/types/facade/bot/agent-loop.d.ts +0 -30
- package/dist/types/facade/bot/agent-loop.test.d.ts +0 -1
- package/dist/types/facade/bot/agent.d.ts +0 -140
- package/dist/types/facade/bot/error-handler.d.ts +0 -7
- package/dist/types/facade/bot/event-bus.d.ts +0 -8
- package/dist/types/facade/bot/index.d.ts +0 -7
- package/dist/types/facade/bot/messages.d.ts +0 -83
- package/dist/types/facade/bot/permission-gate.test.d.ts +0 -1
- package/dist/types/facade/bot/proxy.d.ts +0 -70
- package/dist/types/facade/bot/session-manager.d.ts +0 -409
- package/dist/types/facade/bot/state-manager.d.ts +0 -21
- package/dist/types/facade/bot/telemetry.d.ts +0 -6
- package/dist/types/facade/bot/types.d.ts +0 -267
- package/dist/types/facade/mcp-core/client-pool.d.ts +0 -105
- package/dist/types/facade/mcp-core/client.d.ts +0 -213
- package/dist/types/facade/mcp-core/client.test.d.ts +0 -18
- package/dist/types/facade/mcp-core/config.d.ts +0 -60
- package/dist/types/facade/mcp-core/errors.d.ts +0 -103
- package/dist/types/facade/mcp-core/index.d.ts +0 -55
- package/dist/types/facade/mcp-core/schema-converter.d.ts +0 -67
- package/dist/types/facade/mcp-core/server.d.ts +0 -110
- package/dist/types/facade/mcp-core/tool-factory.d.ts +0 -62
- package/dist/types/facade/mcp-core/types.d.ts +0 -298
- package/dist/types/facade/mcp.d.ts +0 -1
- package/dist/types/facade/memory.d.ts +0 -1
- package/dist/types/facade/ml/adapters/amazon-bedrock.d.ts +0 -32
- package/dist/types/facade/ml/adapters/anthropic-retry.test.d.ts +0 -1
- package/dist/types/facade/ml/adapters/anthropic.d.ts +0 -78
- package/dist/types/facade/ml/adapters/azure-openai-responses.d.ts +0 -14
- package/dist/types/facade/ml/adapters/google-shared.d.ts +0 -99
- package/dist/types/facade/ml/adapters/google-vertex.d.ts +0 -14
- package/dist/types/facade/ml/adapters/google.d.ts +0 -15
- package/dist/types/facade/ml/adapters/kimi.d.ts +0 -21
- package/dist/types/facade/ml/adapters/mock.d.ts +0 -9
- package/dist/types/facade/ml/adapters/nvidia.d.ts +0 -12
- package/dist/types/facade/ml/adapters/openai-codex-responses.d.ts +0 -8
- package/dist/types/facade/ml/adapters/openai-completions.d.ts +0 -24
- package/dist/types/facade/ml/adapters/openai-responses-shared.d.ts +0 -25
- package/dist/types/facade/ml/adapters/openai-responses.d.ts +0 -12
- package/dist/types/facade/ml/adapters/openai-scaffold.d.ts +0 -3
- package/dist/types/facade/ml/adapters/register-builtins.d.ts +0 -2
- package/dist/types/facade/ml/adapters/simple-options.d.ts +0 -39
- package/dist/types/facade/ml/adapters/simple-options.test.d.ts +0 -1
- package/dist/types/facade/ml/adapters/transform-messages.d.ts +0 -23
- package/dist/types/facade/ml/api-registry.d.ts +0 -49
- package/dist/types/facade/ml/cli.d.ts +0 -2
- package/dist/types/facade/ml/env-api-keys.d.ts +0 -19
- package/dist/types/facade/ml/index.d.ts +0 -27
- package/dist/types/facade/ml/kit/auth/anthropic.d.ts +0 -17
- package/dist/types/facade/ml/kit/auth/github-copilot.d.ts +0 -22
- package/dist/types/facade/ml/kit/auth/index.d.ts +0 -50
- package/dist/types/facade/ml/kit/auth/kimi.d.ts +0 -23
- package/dist/types/facade/ml/kit/auth/oauth-page.d.ts +0 -2
- package/dist/types/facade/ml/kit/auth/openai-codex.d.ts +0 -36
- package/dist/types/facade/ml/kit/auth/pkce.d.ts +0 -12
- package/dist/types/facade/ml/kit/auth/types.d.ts +0 -67
- package/dist/types/facade/ml/kit/base-stream-handler.d.ts +0 -30
- package/dist/types/facade/ml/kit/event-stream.d.ts +0 -63
- package/dist/types/facade/ml/kit/index.d.ts +0 -14
- package/dist/types/facade/ml/kit/json-parse.d.ts +0 -23
- package/dist/types/facade/ml/kit/message-transform.d.ts +0 -32
- package/dist/types/facade/ml/kit/output-factory.d.ts +0 -8
- package/dist/types/facade/ml/kit/overflow.d.ts +0 -9
- package/dist/types/facade/ml/kit/provider-adapter.d.ts +0 -56
- package/dist/types/facade/ml/kit/provider-client-builder.d.ts +0 -36
- package/dist/types/facade/ml/kit/provider-consolidation.d.ts +0 -3
- package/dist/types/facade/ml/kit/provider-constants.d.ts +0 -34
- package/dist/types/facade/ml/kit/provider-errors.d.ts +0 -52
- package/dist/types/facade/ml/kit/sanitize-unicode.d.ts +0 -2
- package/dist/types/facade/ml/kit/stream-event-helper.d.ts +0 -38
- package/dist/types/facade/ml/kit/stream-handler-types.d.ts +0 -46
- package/dist/types/facade/ml/kit/streaming-state-manager.d.ts +0 -42
- package/dist/types/facade/ml/kit/tool-converter.d.ts +0 -49
- package/dist/types/facade/ml/kit/typebox-helpers.d.ts +0 -24
- package/dist/types/facade/ml/kit/validation.d.ts +0 -26
- package/dist/types/facade/ml/models.d.ts +0 -41
- package/dist/types/facade/ml/models.generated.d.ts +0 -12405
- package/dist/types/facade/ml/stream.d.ts +0 -27
- package/dist/types/facade/ml/types.d.ts +0 -269
- package/dist/types/index.d.ts +0 -16
- package/dist/types/interop/index.d.ts +0 -12
- package/dist/types/interop/interop.test.d.ts +0 -19
- package/dist/types/interop/protocol-bridge/bridge.d.ts +0 -52
- package/dist/types/interop/protocol-bridge/contract.d.ts +0 -249
- package/dist/types/interop/protocol-bridge/endpoint.d.ts +0 -124
- package/dist/types/interop/protocol-bridge/fleet.d.ts +0 -92
- package/dist/types/interop/protocol-bridge/host.d.ts +0 -61
- package/dist/types/interop/protocol-bridge/index.d.ts +0 -16
- package/dist/types/interop/protocol-bridge/schema.d.ts +0 -29
- package/dist/types/llmgateway/catalog/cards.d.ts +0 -18
- package/dist/types/llmgateway/catalog/cost.d.ts +0 -15
- package/dist/types/llmgateway/catalog/index.d.ts +0 -7
- package/dist/types/llmgateway/catalog/query.d.ts +0 -40
- package/dist/types/llmgateway/connectors/anthropic.d.ts +0 -35
- package/dist/types/llmgateway/connectors/azure-openai.d.ts +0 -33
- package/dist/types/llmgateway/connectors/bedrock.d.ts +0 -113
- package/dist/types/llmgateway/connectors/google-vertex.d.ts +0 -38
- package/dist/types/llmgateway/connectors/google.d.ts +0 -40
- package/dist/types/llmgateway/connectors/index.d.ts +0 -26
- package/dist/types/llmgateway/connectors/kimi.d.ts +0 -28
- package/dist/types/llmgateway/connectors/mock.d.ts +0 -37
- package/dist/types/llmgateway/connectors/nvidia.d.ts +0 -27
- package/dist/types/llmgateway/connectors/ollama.d.ts +0 -45
- package/dist/types/llmgateway/connectors/openai-chat.d.ts +0 -25
- package/dist/types/llmgateway/connectors/openai-responses.d.ts +0 -49
- package/dist/types/llmgateway/contract/connector.d.ts +0 -32
- package/dist/types/llmgateway/contract/conversation.d.ts +0 -86
- package/dist/types/llmgateway/contract/emission.d.ts +0 -55
- package/dist/types/llmgateway/contract/errors.d.ts +0 -27
- package/dist/types/llmgateway/contract/index.d.ts +0 -13
- package/dist/types/llmgateway/contract/model-card.d.ts +0 -42
- package/dist/types/llmgateway/contract/options.d.ts +0 -31
- package/dist/types/llmgateway/contract/reply.d.ts +0 -33
- package/dist/types/llmgateway/conversion/index.d.ts +0 -10
- package/dist/types/llmgateway/conversion/mappers.d.ts +0 -65
- package/dist/types/llmgateway/conversion/openai-compatible.d.ts +0 -46
- package/dist/types/llmgateway/conversion/reduce.d.ts +0 -20
- package/dist/types/llmgateway/credentials/oauth.d.ts +0 -73
- package/dist/types/llmgateway/credentials/pkce.d.ts +0 -52
- package/dist/types/llmgateway/credentials/secrets.d.ts +0 -74
- package/dist/types/llmgateway/gateway.d.ts +0 -34
- package/dist/types/llmgateway/gateway.test.d.ts +0 -14
- package/dist/types/llmgateway/index.d.ts +0 -11
- package/dist/types/llmgateway/streaming/channel.d.ts +0 -24
- package/dist/types/llmgateway/streaming/index.d.ts +0 -10
- package/dist/types/llmgateway/streaming/ndjson.d.ts +0 -17
- package/dist/types/llmgateway/streaming/sse.d.ts +0 -31
- package/dist/types/react-host/index.d.ts +0 -9
- package/dist/types/react-host/ink.d.ts +0 -5
- package/dist/types/react-host/jsx-runtime.d.ts +0 -4
- package/dist/types/react-host/loader.d.ts +0 -3
- package/dist/types/react-ink/components/ChangelogBlock.d.ts +0 -8
- package/dist/types/react-ink/components/DisplayBlockView.d.ts +0 -8
- package/dist/types/react-ink/components/Footer.d.ts +0 -11
- package/dist/types/react-ink/components/MessageList.d.ts +0 -14
- package/dist/types/react-ink/components/MessageRow.d.ts +0 -13
- package/dist/types/react-ink/components/StatusLine.d.ts +0 -18
- package/dist/types/react-ink/components/TaskPanel.d.ts +0 -11
- package/dist/types/react-ink/components/ToolEventBlock.d.ts +0 -48
- package/dist/types/react-ink/components/ToolEventBlock.test.d.ts +0 -1
- package/dist/types/react-ink/components/dialogs/DialogFrame.d.ts +0 -8
- package/dist/types/react-ink/components/dialogs/LoginDialog.d.ts +0 -14
- package/dist/types/react-ink/components/dialogs/ModelDialog.d.ts +0 -9
- package/dist/types/react-ink/components/dialogs/OAuthDialog.d.ts +0 -9
- package/dist/types/react-ink/components/dialogs/ScopedModelsDialog.d.ts +0 -9
- package/dist/types/react-ink/components/dialogs/SelectableDialog.d.ts +0 -22
- package/dist/types/react-ink/components/dialogs/SessionDialog.d.ts +0 -13
- package/dist/types/react-ink/components/dialogs/SettingsDialog.d.ts +0 -14
- package/dist/types/react-ink/components/dialogs/StartupSessionPicker.d.ts +0 -9
- package/dist/types/react-ink/components/dialogs/ThemeDialog.d.ts +0 -26
- package/dist/types/react-ink/components/dialogs/TreeDialog.d.ts +0 -8
- package/dist/types/react-ink/components/dialogs/UserMessageDialog.d.ts +0 -8
- package/dist/types/react-ink/components/messages/AssistantMessage.d.ts +0 -12
- package/dist/types/react-ink/components/messages/BashMessage.d.ts +0 -8
- package/dist/types/react-ink/components/messages/BranchSummaryMessage.d.ts +0 -8
- package/dist/types/react-ink/components/messages/CompactionMessage.d.ts +0 -8
- package/dist/types/react-ink/components/messages/CustomMessage.d.ts +0 -9
- package/dist/types/react-ink/components/messages/SkillInvocationMessage.d.ts +0 -7
- package/dist/types/react-ink/components/messages/ToolCallMessage.d.ts +0 -8
- package/dist/types/react-ink/components/messages/ToolResultBlock.d.ts +0 -12
- package/dist/types/react-ink/components/messages/UserMessage.d.ts +0 -9
- package/dist/types/react-ink/diff/Diff.d.ts +0 -22
- package/dist/types/react-ink/diff/diff.test.d.ts +0 -1
- package/dist/types/react-ink/diff/structured.d.ts +0 -41
- package/dist/types/react-ink/diff/word-diff.d.ts +0 -27
- package/dist/types/react-ink/index.d.ts +0 -42
- package/dist/types/react-ink/markdown/Markdown.d.ts +0 -23
- package/dist/types/react-ink/markdown/MarkdownTable.d.ts +0 -19
- package/dist/types/react-ink/markdown/StreamingMarkdown.d.ts +0 -34
- package/dist/types/react-ink/markdown/format-token.d.ts +0 -39
- package/dist/types/react-ink/markdown/highlight.d.ts +0 -31
- package/dist/types/react-ink/theme-adapter.d.ts +0 -66
- package/dist/types/react-ink/types.d.ts +0 -133
- package/dist/types/react-ink/utils/message-groups.d.ts +0 -25
- package/dist/types/react-ink/utils/selection-dialog.d.ts +0 -2
- package/dist/types/react-ink/utils/session-browser.d.ts +0 -27
- package/dist/types/react-ink/utils/tool-display.d.ts +0 -37
- package/dist/types/runtime/cadence/cadence.test.d.ts +0 -6
- package/dist/types/runtime/cadence/fold.d.ts +0 -48
- package/dist/types/runtime/cadence/index.d.ts +0 -12
- package/dist/types/runtime/cadence/reducer.d.ts +0 -44
- package/dist/types/runtime/conductor/agent.d.ts +0 -71
- package/dist/types/runtime/conductor/index.d.ts +0 -11
- package/dist/types/runtime/contract/config.d.ts +0 -44
- package/dist/types/runtime/contract/effect.d.ts +0 -41
- package/dist/types/runtime/contract/errors.d.ts +0 -22
- package/dist/types/runtime/contract/events.d.ts +0 -63
- package/dist/types/runtime/contract/index.d.ts +0 -18
- package/dist/types/runtime/contract/run-state.d.ts +0 -57
- package/dist/types/runtime/contract/session.d.ts +0 -42
- package/dist/types/runtime/contract/signal.d.ts +0 -49
- package/dist/types/runtime/contract/tools.d.ts +0 -45
- package/dist/types/runtime/dispatch/index.d.ts +0 -9
- package/dist/types/runtime/dispatch/scheduler.d.ts +0 -53
- package/dist/types/runtime/index.d.ts +0 -22
- package/dist/types/runtime/ledger/accumulator.d.ts +0 -44
- package/dist/types/runtime/ledger/bus.d.ts +0 -50
- package/dist/types/runtime/ledger/index.d.ts +0 -11
- package/dist/types/runtime/memory/compactor.d.ts +0 -56
- package/dist/types/runtime/memory/estimate.d.ts +0 -21
- package/dist/types/runtime/memory/index.d.ts +0 -8
- package/dist/types/runtime/runtime.test.d.ts +0 -15
- package/dist/types/runtime/store/dag.d.ts +0 -72
- package/dist/types/runtime/store/hash.d.ts +0 -18
- package/dist/types/runtime/store/index.d.ts +0 -12
- package/dist/types/runtime/store/persist.d.ts +0 -49
- package/dist/types/runtime/turn/driver.d.ts +0 -32
- package/dist/types/runtime/turn/index.d.ts +0 -8
- package/dist/types/runtime/wire/index.d.ts +0 -10
- package/dist/types/runtime/wire/projectors.d.ts +0 -53
- package/dist/types/shell-app/auth-cli/index.d.ts +0 -9
- package/dist/types/shell-app/auth-cli/oauth-cli.d.ts +0 -73
- package/dist/types/shell-app/boot/context.d.ts +0 -108
- package/dist/types/shell-app/boot/index.d.ts +0 -13
- package/dist/types/shell-app/boot/pipeline.d.ts +0 -66
- package/dist/types/shell-app/boot/stages.d.ts +0 -77
- package/dist/types/shell-app/cli.d.ts +0 -75
- package/dist/types/shell-app/config/index.d.ts +0 -11
- package/dist/types/shell-app/config/locator.d.ts +0 -85
- package/dist/types/shell-app/config/settings.d.ts +0 -91
- package/dist/types/shell-app/index.d.ts +0 -26
- package/dist/types/shell-app/invocation/flags.d.ts +0 -89
- package/dist/types/shell-app/invocation/parse.d.ts +0 -89
- package/dist/types/shell-app/locate/brand.d.ts +0 -71
- package/dist/types/shell-app/locate/index.d.ts +0 -12
- package/dist/types/shell-app/locate/locator.d.ts +0 -122
- package/dist/types/shell-app/runners/contract.d.ts +0 -116
- package/dist/types/shell-app/runners/index.d.ts +0 -15
- package/dist/types/shell-app/runners/one-shot.d.ts +0 -21
- package/dist/types/shell-app/runners/registry.d.ts +0 -34
- package/dist/types/shell-app/runners/repl.d.ts +0 -51
- package/dist/types/shell-app/runners/wire.d.ts +0 -34
- package/dist/types/shell-app/shell-app.test.d.ts +0 -14
- package/dist/types/shell-app/upgrade/index.d.ts +0 -9
- package/dist/types/shell-app/upgrade/upgrades.d.ts +0 -62
- package/dist/types/smithy/config/flag-reader.d.ts +0 -128
- package/dist/types/smithy/config/index.d.ts +0 -9
- package/dist/types/smithy/forge.d.ts +0 -135
- package/dist/types/smithy/index.d.ts +0 -36
- package/dist/types/smithy/knowledge/index.d.ts +0 -10
- package/dist/types/smithy/knowledge/loader.d.ts +0 -64
- package/dist/types/smithy/persona/blueprint.d.ts +0 -75
- package/dist/types/smithy/persona/define-agent.d.ts +0 -51
- package/dist/types/smithy/persona/index.d.ts +0 -14
- package/dist/types/smithy/persona/profiles.d.ts +0 -44
- package/dist/types/smithy/runtime/index.d.ts +0 -9
- package/dist/types/smithy/runtime/tool-ledger.d.ts +0 -130
- package/dist/types/smithy/smithy.test.d.ts +0 -20
- package/dist/types/smithy/ui/index.d.ts +0 -11
- package/dist/types/smithy/ui/transcript.d.ts +0 -183
- package/dist/types/swarm/coordinator.d.ts +0 -192
- package/dist/types/swarm/index.d.ts +0 -33
- package/dist/types/swarm/isolation/index.d.ts +0 -14
- package/dist/types/swarm/isolation/runner.d.ts +0 -61
- package/dist/types/swarm/isolation/worktree.d.ts +0 -142
- package/dist/types/swarm/kernel/faults.d.ts +0 -52
- package/dist/types/swarm/kernel/ids.d.ts +0 -25
- package/dist/types/swarm/kernel/index.d.ts +0 -26
- package/dist/types/swarm/kernel/json-cell.d.ts +0 -113
- package/dist/types/swarm/kernel/jsonl-log.d.ts +0 -81
- package/dist/types/swarm/postbox/channel.d.ts +0 -88
- package/dist/types/swarm/postbox/codecs.d.ts +0 -253
- package/dist/types/swarm/postbox/index.d.ts +0 -16
- package/dist/types/swarm/roster/index.d.ts +0 -16
- package/dist/types/swarm/roster/manifest.d.ts +0 -185
- package/dist/types/swarm/swarm.test.d.ts +0 -24
- package/dist/types/swarm/telemetry/activity.d.ts +0 -143
- package/dist/types/swarm/workboard/board.d.ts +0 -174
- package/dist/types/swarm/workboard/dep-graph.d.ts +0 -77
- package/dist/types/swarm/workboard/index.d.ts +0 -12
- package/dist/types/tracing/adapter/index.d.ts +0 -12
- package/dist/types/tracing/adapter/runtime-trace.d.ts +0 -54
- package/dist/types/tracing/channel/index.d.ts +0 -9
- package/dist/types/tracing/channel/signal.d.ts +0 -93
- package/dist/types/tracing/index.d.ts +0 -25
- package/dist/types/tracing/recorder/index.d.ts +0 -12
- package/dist/types/tracing/recorder/recorder.d.ts +0 -75
- package/dist/types/tracing/recorder/sampling.d.ts +0 -55
- package/dist/types/tracing/redaction/index.d.ts +0 -8
- package/dist/types/tracing/redaction/secret-scrubber.d.ts +0 -95
- package/dist/types/tracing/registry/hub.d.ts +0 -57
- package/dist/types/tracing/registry/index.d.ts +0 -7
- package/dist/types/tracing/signal/handle.d.ts +0 -73
- package/dist/types/tracing/signal/index.d.ts +0 -12
- package/dist/types/tracing/signal/segment.d.ts +0 -124
- package/dist/types/tracing/sinks/base.d.ts +0 -51
- package/dist/types/tracing/sinks/console.d.ts +0 -44
- package/dist/types/tracing/sinks/file.d.ts +0 -47
- package/dist/types/tracing/sinks/index.d.ts +0 -16
- package/dist/types/tracing/sinks/stream.d.ts +0 -46
- package/dist/types/tracing/tracing.test.d.ts +0 -7
- package/dist/types/ui/autocomplete.d.ts +0 -59
- package/dist/types/ui/contracts.d.ts +0 -38
- package/dist/types/ui/editor-component.d.ts +0 -100
- package/dist/types/ui/fuzzy.d.ts +0 -29
- package/dist/types/ui/index.d.ts +0 -8
- package/dist/types/ui/keybindings.d.ts +0 -62
- package/dist/types/ui/keys.d.ts +0 -171
- package/dist/types/ui/theme-types.d.ts +0 -36
- package/dist/types/ui/utils.d.ts +0 -101
- package/dist/types/ui-bridge/InteractiveApp.d.ts +0 -38
- package/dist/types/ui-bridge/adapter.d.ts +0 -90
- package/dist/types/ui-bridge/index.d.ts +0 -37
package/dist/react-ink.js
DELETED
|
@@ -1,3834 +0,0 @@
|
|
|
1
|
-
// src/react-ink/theme-adapter.ts
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import stripAnsi from "strip-ansi";
|
|
4
|
-
var DEFAULT_ROLE_KEYS = {
|
|
5
|
-
codeInline: "codeInline",
|
|
6
|
-
heading: "heading",
|
|
7
|
-
blockquoteBar: "blockquoteBar",
|
|
8
|
-
diffAddedBg: "diffAddedBg",
|
|
9
|
-
diffRemovedBg: "diffRemovedBg",
|
|
10
|
-
diffAddedText: "diffAddedText",
|
|
11
|
-
diffRemovedText: "diffRemovedText",
|
|
12
|
-
synKeyword: "synKeyword",
|
|
13
|
-
synString: "synString",
|
|
14
|
-
synNumber: "synNumber",
|
|
15
|
-
synComment: "synComment",
|
|
16
|
-
synType: "synType"
|
|
17
|
-
};
|
|
18
|
-
var ROLE_FALLBACK_KEYS = {
|
|
19
|
-
codeInline: "accent",
|
|
20
|
-
heading: "accent",
|
|
21
|
-
blockquoteBar: "muted",
|
|
22
|
-
diffAddedBg: "success",
|
|
23
|
-
diffRemovedBg: "error",
|
|
24
|
-
diffAddedText: "success",
|
|
25
|
-
diffRemovedText: "error",
|
|
26
|
-
synKeyword: "accent",
|
|
27
|
-
synString: "success",
|
|
28
|
-
synNumber: "warning",
|
|
29
|
-
synComment: "muted",
|
|
30
|
-
synType: "info"
|
|
31
|
-
};
|
|
32
|
-
function applyForeground(color, text) {
|
|
33
|
-
if (!color) return text;
|
|
34
|
-
try {
|
|
35
|
-
return chalk.hex(color)(text);
|
|
36
|
-
} catch {
|
|
37
|
-
return text;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function resolveColorToken(value, fallback) {
|
|
41
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
|
-
return fallback;
|
|
45
|
-
}
|
|
46
|
-
function applyBackground(background, foreground, text) {
|
|
47
|
-
if (!background) return applyForeground(foreground, text);
|
|
48
|
-
try {
|
|
49
|
-
let styled = chalk.bgHex(background);
|
|
50
|
-
if (foreground) {
|
|
51
|
-
styled = styled.hex(foreground);
|
|
52
|
-
}
|
|
53
|
-
return styled(text);
|
|
54
|
-
} catch {
|
|
55
|
-
return applyForeground(foreground, text);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function createThemeAdapter(themeName, colors, roleOverrides) {
|
|
59
|
-
const fallback = colors.text ?? "#e5e5e7";
|
|
60
|
-
const roles = { ...DEFAULT_ROLE_KEYS, ...roleOverrides };
|
|
61
|
-
const resolveRoleColor = (role) => resolveColorToken(
|
|
62
|
-
colors[roles[role]],
|
|
63
|
-
resolveColorToken(colors[ROLE_FALLBACK_KEYS[role]], fallback)
|
|
64
|
-
);
|
|
65
|
-
return {
|
|
66
|
-
name: themeName,
|
|
67
|
-
colors,
|
|
68
|
-
roles,
|
|
69
|
-
color: (key, text) => applyForeground(resolveColorToken(colors[key], fallback), text),
|
|
70
|
-
background: (key, text, textKey = "text") => applyBackground(resolveColorToken(colors[key]), resolveColorToken(colors[textKey], fallback), ` ${stripAnsi(text)} `),
|
|
71
|
-
dim: (text) => applyForeground(resolveColorToken(colors.dim, "#666666"), text),
|
|
72
|
-
muted: (text) => applyForeground(resolveColorToken(colors.muted, "#808080"), text),
|
|
73
|
-
role: (role, text) => applyForeground(resolveRoleColor(role), text),
|
|
74
|
-
roleBackground: (role, text, foregroundRole) => applyBackground(
|
|
75
|
-
resolveRoleColor(role),
|
|
76
|
-
foregroundRole ? resolveRoleColor(foregroundRole) : void 0,
|
|
77
|
-
text
|
|
78
|
-
)
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// src/react-host/loader.ts
|
|
83
|
-
import { createRequire } from "node:module";
|
|
84
|
-
import fs from "node:fs";
|
|
85
|
-
import path from "node:path";
|
|
86
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
87
|
-
function findPackageRoot(start) {
|
|
88
|
-
let current = path.resolve(start);
|
|
89
|
-
while (true) {
|
|
90
|
-
const packageJson = path.join(current, "package.json");
|
|
91
|
-
if (fs.existsSync(packageJson)) {
|
|
92
|
-
return current;
|
|
93
|
-
}
|
|
94
|
-
const parent = path.dirname(current);
|
|
95
|
-
if (parent === current) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
current = parent;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
function createPackageRequire(packageRoot) {
|
|
102
|
-
return createRequire(path.join(packageRoot, "package.json"));
|
|
103
|
-
}
|
|
104
|
-
function candidatePackageRoots() {
|
|
105
|
-
const roots = /* @__PURE__ */ new Set();
|
|
106
|
-
const addCandidate = (candidate) => {
|
|
107
|
-
if (!candidate) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const root = findPackageRoot(candidate);
|
|
111
|
-
if (root) {
|
|
112
|
-
roots.add(root);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
const argv1 = process.argv[1];
|
|
116
|
-
let argv1Real;
|
|
117
|
-
if (argv1) {
|
|
118
|
-
try {
|
|
119
|
-
argv1Real = fs.realpathSync(argv1);
|
|
120
|
-
} catch {
|
|
121
|
-
argv1Real = argv1;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const packageRoot = fileURLToPath(new URL("../../..", import.meta.url));
|
|
125
|
-
addCandidate(process.env.INDUSAGI_REACT_HOST_ROOT);
|
|
126
|
-
addCandidate(argv1Real ? path.dirname(argv1Real) : void 0);
|
|
127
|
-
addCandidate(argv1 ? path.dirname(argv1) : void 0);
|
|
128
|
-
addCandidate(process.env.INIT_CWD);
|
|
129
|
-
addCandidate(process.cwd());
|
|
130
|
-
addCandidate(packageRoot);
|
|
131
|
-
return [...roots];
|
|
132
|
-
}
|
|
133
|
-
function resolveHostModule(specifier) {
|
|
134
|
-
const failures = [];
|
|
135
|
-
for (const packageRoot of candidatePackageRoots()) {
|
|
136
|
-
try {
|
|
137
|
-
return createPackageRequire(packageRoot).resolve(specifier);
|
|
138
|
-
} catch (error) {
|
|
139
|
-
failures.push(`${packageRoot}: ${String(error.message ?? error)}`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
throw new Error(
|
|
143
|
-
`Unable to resolve host module "${specifier}" from any detected package root.
|
|
144
|
-
${failures.join("\n")}`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
function normalizeModuleNamespace(moduleNamespace) {
|
|
148
|
-
const defaultExport = moduleNamespace.default;
|
|
149
|
-
if (defaultExport && typeof defaultExport === "object") {
|
|
150
|
-
return { ...defaultExport, ...moduleNamespace };
|
|
151
|
-
}
|
|
152
|
-
return moduleNamespace;
|
|
153
|
-
}
|
|
154
|
-
async function importHostModule(specifier) {
|
|
155
|
-
const resolved = resolveHostModule(specifier);
|
|
156
|
-
const moduleNamespace = await import(pathToFileURL(resolved).href);
|
|
157
|
-
return normalizeModuleNamespace(moduleNamespace);
|
|
158
|
-
}
|
|
159
|
-
var reactInstance = null;
|
|
160
|
-
var jsxRuntimeInstance = null;
|
|
161
|
-
var inkInstance = null;
|
|
162
|
-
function loadHostReact() {
|
|
163
|
-
if (!reactInstance) {
|
|
164
|
-
reactInstance = importHostModule("react");
|
|
165
|
-
}
|
|
166
|
-
return reactInstance;
|
|
167
|
-
}
|
|
168
|
-
function loadHostJsxRuntime() {
|
|
169
|
-
if (!jsxRuntimeInstance) {
|
|
170
|
-
jsxRuntimeInstance = importHostModule("react/jsx-runtime");
|
|
171
|
-
}
|
|
172
|
-
return jsxRuntimeInstance;
|
|
173
|
-
}
|
|
174
|
-
function loadHostInk() {
|
|
175
|
-
if (!inkInstance) {
|
|
176
|
-
inkInstance = importHostModule("ink");
|
|
177
|
-
}
|
|
178
|
-
return inkInstance;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// src/react-host/ink.ts
|
|
182
|
-
var ink = await loadHostInk();
|
|
183
|
-
var Box = ink.Box;
|
|
184
|
-
var Text = ink.Text;
|
|
185
|
-
var render = ink.render;
|
|
186
|
-
var useInput = ink.useInput;
|
|
187
|
-
|
|
188
|
-
// src/react-host/jsx-runtime.ts
|
|
189
|
-
var jsxRuntime = await loadHostJsxRuntime();
|
|
190
|
-
var Fragment = jsxRuntime.Fragment;
|
|
191
|
-
var jsx = jsxRuntime.jsx;
|
|
192
|
-
var jsxs = jsxRuntime.jsxs;
|
|
193
|
-
|
|
194
|
-
// src/react-ink/components/ChangelogBlock.tsx
|
|
195
|
-
function renderInline(text, theme, keyPrefix) {
|
|
196
|
-
const nodes = [];
|
|
197
|
-
const tokenPattern = /(\*\*[^*]+\*\*|`[^`]+`)/g;
|
|
198
|
-
let cursor = 0;
|
|
199
|
-
let tokenIndex = 0;
|
|
200
|
-
for (const match of text.matchAll(tokenPattern)) {
|
|
201
|
-
const matchedText = match[0];
|
|
202
|
-
const start = match.index ?? cursor;
|
|
203
|
-
if (start > cursor) {
|
|
204
|
-
nodes.push(text.slice(cursor, start));
|
|
205
|
-
}
|
|
206
|
-
if (matchedText.startsWith("**")) {
|
|
207
|
-
nodes.push(
|
|
208
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", matchedText.slice(2, -2)) }, `${keyPrefix}-bold-${tokenIndex}`)
|
|
209
|
-
);
|
|
210
|
-
} else {
|
|
211
|
-
nodes.push(
|
|
212
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", matchedText.slice(1, -1)) }, `${keyPrefix}-code-${tokenIndex}`)
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
cursor = start + matchedText.length;
|
|
216
|
-
tokenIndex += 1;
|
|
217
|
-
}
|
|
218
|
-
if (cursor < text.length) {
|
|
219
|
-
nodes.push(text.slice(cursor));
|
|
220
|
-
}
|
|
221
|
-
return nodes.length > 0 ? nodes : [text];
|
|
222
|
-
}
|
|
223
|
-
function renderMarkdownLine(line, theme, key) {
|
|
224
|
-
const trimmed = line.trim();
|
|
225
|
-
if (trimmed.length === 0) {
|
|
226
|
-
return /* @__PURE__ */ jsx(Text, { children: " " }, key);
|
|
227
|
-
}
|
|
228
|
-
if (/^-{3,}$/.test(trimmed)) {
|
|
229
|
-
const width = Math.max(20, (process.stdout.columns ?? 80) - 4);
|
|
230
|
-
return /* @__PURE__ */ jsx(Text, { children: theme.color("borderMuted", "\u2500".repeat(width)) }, key);
|
|
231
|
-
}
|
|
232
|
-
if (trimmed.startsWith("## ")) {
|
|
233
|
-
return /* @__PURE__ */ jsx(Text, { children: theme.color("accent", trimmed.slice(3)) }, key);
|
|
234
|
-
}
|
|
235
|
-
if (trimmed.startsWith("### ")) {
|
|
236
|
-
return /* @__PURE__ */ jsx(Text, { children: theme.color("warning", trimmed.slice(4)) }, key);
|
|
237
|
-
}
|
|
238
|
-
const bulletMatch = line.match(/^(\s*)-\s+(.*)$/);
|
|
239
|
-
if (bulletMatch) {
|
|
240
|
-
const indent = " ".repeat(bulletMatch[1]?.length ?? 0);
|
|
241
|
-
const content = bulletMatch[2] ?? "";
|
|
242
|
-
const bulletColor = indent.length > 0 ? "muted" : "accent";
|
|
243
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
244
|
-
indent,
|
|
245
|
-
theme.color(bulletColor, "\u2022"),
|
|
246
|
-
" ",
|
|
247
|
-
renderInline(content, theme, key)
|
|
248
|
-
] }, key);
|
|
249
|
-
}
|
|
250
|
-
return /* @__PURE__ */ jsx(Text, { children: renderInline(line, theme, key) }, key);
|
|
251
|
-
}
|
|
252
|
-
function ChangelogBlock({ markdown, theme, title }) {
|
|
253
|
-
const dividerWidth = Math.max(20, (process.stdout.columns ?? 80) - 2);
|
|
254
|
-
const divider = "\u2500".repeat(dividerWidth);
|
|
255
|
-
const lines = markdown.trim().length > 0 ? markdown.trim().split("\n") : ["No changelog entries found."];
|
|
256
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
257
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("borderMuted", divider) }),
|
|
258
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", title) }),
|
|
259
|
-
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
260
|
-
lines.map((line, index) => renderMarkdownLine(line, theme, `${title}-${index}`)),
|
|
261
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("borderMuted", divider) })
|
|
262
|
-
] });
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// src/react-ink/components/DisplayBlockView.tsx
|
|
266
|
-
function DisplayBlockView({ block, theme }) {
|
|
267
|
-
switch (block.kind) {
|
|
268
|
-
case "changelog":
|
|
269
|
-
return /* @__PURE__ */ jsx(ChangelogBlock, { markdown: block.markdown, theme, title: block.title });
|
|
270
|
-
default:
|
|
271
|
-
return null;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// src/react-ink/components/Footer.tsx
|
|
276
|
-
import stripAnsi2 from "strip-ansi";
|
|
277
|
-
function toDisplayText(value) {
|
|
278
|
-
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
279
|
-
return String(value);
|
|
280
|
-
}
|
|
281
|
-
if (Array.isArray(value)) {
|
|
282
|
-
return value.map((entry) => toDisplayText(entry)).join("");
|
|
283
|
-
}
|
|
284
|
-
if (!value || typeof value !== "object") {
|
|
285
|
-
return "";
|
|
286
|
-
}
|
|
287
|
-
if ("props" in value) {
|
|
288
|
-
return toDisplayText(value.props?.children);
|
|
289
|
-
}
|
|
290
|
-
return "";
|
|
291
|
-
}
|
|
292
|
-
function sanitizeStatusText(value) {
|
|
293
|
-
return value.replace(/\s+/g, " ").trim();
|
|
294
|
-
}
|
|
295
|
-
function formatTokens(count) {
|
|
296
|
-
if (count < 1e3) return count.toString();
|
|
297
|
-
if (count < 1e4) return `${(count / 1e3).toFixed(1)}k`;
|
|
298
|
-
if (count < 1e6) return `${Math.round(count / 1e3)}k`;
|
|
299
|
-
if (count < 1e7) return `${(count / 1e6).toFixed(1)}M`;
|
|
300
|
-
return `${Math.round(count / 1e6)}M`;
|
|
301
|
-
}
|
|
302
|
-
function shortenPath(path2) {
|
|
303
|
-
const home = process.env.HOME || process.env.USERPROFILE;
|
|
304
|
-
if (home && path2.startsWith(home)) {
|
|
305
|
-
return `~${path2.slice(home.length)}`;
|
|
306
|
-
}
|
|
307
|
-
return path2;
|
|
308
|
-
}
|
|
309
|
-
function chunkLines(values, width) {
|
|
310
|
-
const lines = [];
|
|
311
|
-
let current = "";
|
|
312
|
-
for (const value of values) {
|
|
313
|
-
const next = current ? `${current} ${value}` : value;
|
|
314
|
-
if (stripAnsi2(next).length > width && current) {
|
|
315
|
-
lines.push(current);
|
|
316
|
-
current = value;
|
|
317
|
-
} else {
|
|
318
|
-
current = next;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
if (current) {
|
|
322
|
-
lines.push(current);
|
|
323
|
-
}
|
|
324
|
-
return lines;
|
|
325
|
-
}
|
|
326
|
-
function Footer({ availableProviderCount, branch, extensionStatuses, snapshot, theme }) {
|
|
327
|
-
const cwdLineParts = [shortenPath(snapshot.cwd)];
|
|
328
|
-
if (branch) {
|
|
329
|
-
cwdLineParts.push(`(${toDisplayText(branch)})`);
|
|
330
|
-
}
|
|
331
|
-
if (snapshot.sessionName) {
|
|
332
|
-
cwdLineParts.push(`\u2022 ${snapshot.sessionName}`);
|
|
333
|
-
}
|
|
334
|
-
const statsParts = [];
|
|
335
|
-
if (snapshot.stats.tokens.input > 0) statsParts.push(`\u2191${formatTokens(snapshot.stats.tokens.input)}`);
|
|
336
|
-
if (snapshot.stats.tokens.output > 0) statsParts.push(`\u2193${formatTokens(snapshot.stats.tokens.output)}`);
|
|
337
|
-
if (snapshot.stats.tokens.cacheRead > 0) statsParts.push(`R${formatTokens(snapshot.stats.tokens.cacheRead)}`);
|
|
338
|
-
if (snapshot.stats.tokens.cacheWrite > 0) statsParts.push(`W${formatTokens(snapshot.stats.tokens.cacheWrite)}`);
|
|
339
|
-
if (snapshot.stats.cost > 0) statsParts.push(`$${snapshot.stats.cost.toFixed(3)}`);
|
|
340
|
-
let contextPart = snapshot.contextUsage ? `ctx:${snapshot.contextUsage.percent.toFixed(1)}%/${formatTokens(snapshot.contextUsage.contextWindow)}` : void 0;
|
|
341
|
-
if (contextPart && snapshot.autoCompactEnabled) {
|
|
342
|
-
contextPart += " (auto)";
|
|
343
|
-
}
|
|
344
|
-
if (contextPart) {
|
|
345
|
-
if ((snapshot.contextUsage?.percent ?? 0) > 90) {
|
|
346
|
-
statsParts.push(toDisplayText(theme.color("error", contextPart)));
|
|
347
|
-
} else if ((snapshot.contextUsage?.percent ?? 0) > 70) {
|
|
348
|
-
statsParts.push(toDisplayText(theme.color("warning", contextPart)));
|
|
349
|
-
} else {
|
|
350
|
-
statsParts.push(contextPart);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
const modelParts = [
|
|
354
|
-
snapshot.model ? `${toDisplayText(snapshot.model.provider)}/${toDisplayText(snapshot.model.id)}` : "no-model",
|
|
355
|
-
`thinking:${toDisplayText(snapshot.thinkingLevel)}`,
|
|
356
|
-
snapshot.pendingMessageCount > 0 ? `pending:${snapshot.pendingMessageCount}` : void 0,
|
|
357
|
-
snapshot.pendingToolCallCount > 0 ? `tools:${snapshot.pendingToolCallCount}` : void 0,
|
|
358
|
-
availableProviderCount > 1 ? `providers:${availableProviderCount}` : void 0
|
|
359
|
-
];
|
|
360
|
-
const statusValues = Array.from(extensionStatuses?.entries() ?? []).sort(([left], [right]) => left.localeCompare(right)).map(([key, text]) => sanitizeStatusText(`${key}: ${text}`)).filter(Boolean);
|
|
361
|
-
const width = Math.max(40, (process.stdout.columns ?? 80) - 2);
|
|
362
|
-
const cwdLine = cwdLineParts.join(" ");
|
|
363
|
-
const statsLine = statsParts.join(" ");
|
|
364
|
-
const modelLine = modelParts.filter(Boolean).join(" | ");
|
|
365
|
-
const statusLines = chunkLines(statusValues, width);
|
|
366
|
-
const mutedColor = typeof theme.colors.muted === "string" && theme.colors.muted.trim().length > 0 ? theme.colors.muted : "gray";
|
|
367
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
368
|
-
/* @__PURE__ */ jsx(Text, { color: mutedColor, children: cwdLine }),
|
|
369
|
-
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", children: [
|
|
370
|
-
/* @__PURE__ */ jsx(Text, { color: mutedColor, children: statsLine }),
|
|
371
|
-
/* @__PURE__ */ jsx(Text, { color: mutedColor, children: modelLine })
|
|
372
|
-
] }),
|
|
373
|
-
statusLines.map((line, index) => /* @__PURE__ */ jsx(Text, { color: mutedColor, children: line }, `footer-status:${index}`))
|
|
374
|
-
] });
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// src/react-ink/utils/message-groups.ts
|
|
378
|
-
function parseSkillBlock(text) {
|
|
379
|
-
const match = text.match(/^<skill name="([^"]+)" location="([^"]+)">\n([\s\S]*?)\n<\/skill>(?:\n\n([\s\S]+))?$/);
|
|
380
|
-
if (!match) return null;
|
|
381
|
-
return {
|
|
382
|
-
name: match[1] ?? "",
|
|
383
|
-
location: match[2] ?? "",
|
|
384
|
-
content: match[3] ?? "",
|
|
385
|
-
userMessage: match[4]?.trim() || void 0
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
function isTextContent(value) {
|
|
389
|
-
return typeof value === "object" && value !== null && value.type === "text";
|
|
390
|
-
}
|
|
391
|
-
function isImageContent(value) {
|
|
392
|
-
return typeof value === "object" && value !== null && value.type === "image";
|
|
393
|
-
}
|
|
394
|
-
function isThinkingContent(value) {
|
|
395
|
-
return typeof value === "object" && value !== null && value.type === "thinking";
|
|
396
|
-
}
|
|
397
|
-
function isToolCall(value) {
|
|
398
|
-
return typeof value === "object" && value !== null && value.type === "toolCall";
|
|
399
|
-
}
|
|
400
|
-
function previewText(value, maxLength = 88) {
|
|
401
|
-
const normalized = value.replace(/\s+/g, " ").trim();
|
|
402
|
-
if (normalized.length <= maxLength) return normalized;
|
|
403
|
-
return `${normalized.slice(0, maxLength - 1)}...`;
|
|
404
|
-
}
|
|
405
|
-
function safeStringify(value) {
|
|
406
|
-
if (value === void 0) return "";
|
|
407
|
-
if (typeof value === "string") return value;
|
|
408
|
-
try {
|
|
409
|
-
const serialized = JSON.stringify(value, null, 2);
|
|
410
|
-
return typeof serialized === "string" ? serialized : "";
|
|
411
|
-
} catch {
|
|
412
|
-
return String(value);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
function parseJsonString(value) {
|
|
416
|
-
const trimmed = value.trim();
|
|
417
|
-
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
|
|
418
|
-
return void 0;
|
|
419
|
-
}
|
|
420
|
-
try {
|
|
421
|
-
return JSON.parse(trimmed);
|
|
422
|
-
} catch {
|
|
423
|
-
return void 0;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
function extractStructuredText(value, showImages, seen = /* @__PURE__ */ new WeakSet()) {
|
|
427
|
-
if (value == null) {
|
|
428
|
-
return [];
|
|
429
|
-
}
|
|
430
|
-
if (typeof value === "string") {
|
|
431
|
-
const parsed = parseJsonString(value);
|
|
432
|
-
if (parsed !== void 0) {
|
|
433
|
-
const extracted = extractStructuredText(parsed, showImages, seen);
|
|
434
|
-
if (extracted.length > 0) {
|
|
435
|
-
return extracted;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
return value.trim() ? [value] : [];
|
|
439
|
-
}
|
|
440
|
-
if (Array.isArray(value)) {
|
|
441
|
-
return value.flatMap((item) => extractStructuredText(item, showImages, seen));
|
|
442
|
-
}
|
|
443
|
-
if (typeof value !== "object") {
|
|
444
|
-
return [];
|
|
445
|
-
}
|
|
446
|
-
const record = value;
|
|
447
|
-
if (seen.has(record)) {
|
|
448
|
-
return [];
|
|
449
|
-
}
|
|
450
|
-
seen.add(record);
|
|
451
|
-
if (isTextContent(record)) {
|
|
452
|
-
return extractStructuredText(record.text, showImages, seen);
|
|
453
|
-
}
|
|
454
|
-
if (isImageContent(record)) {
|
|
455
|
-
return showImages ? [`[image: ${record.mimeType}]`] : [];
|
|
456
|
-
}
|
|
457
|
-
if ("content" in record) {
|
|
458
|
-
const extracted = extractStructuredText(record.content, showImages, seen);
|
|
459
|
-
if (extracted.length > 0) {
|
|
460
|
-
return extracted;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
if ("details" in record) {
|
|
464
|
-
const extracted = extractStructuredText(record.details, showImages, seen);
|
|
465
|
-
if (extracted.length > 0) {
|
|
466
|
-
return extracted;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
for (const key of ["text", "output", "stdout", "stderr", "message", "summary"]) {
|
|
470
|
-
if (!(key in record)) {
|
|
471
|
-
continue;
|
|
472
|
-
}
|
|
473
|
-
const extracted = extractStructuredText(record[key], showImages, seen);
|
|
474
|
-
if (extracted.length > 0) {
|
|
475
|
-
return extracted;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
return [];
|
|
479
|
-
}
|
|
480
|
-
function extractToolText(value, showImages) {
|
|
481
|
-
if (value == null) {
|
|
482
|
-
return "";
|
|
483
|
-
}
|
|
484
|
-
const extracted = extractStructuredText(value, showImages).map((part) => part.trimEnd()).filter((part) => part.length > 0);
|
|
485
|
-
if (extracted.length > 0) {
|
|
486
|
-
return extracted.join("\n").trim();
|
|
487
|
-
}
|
|
488
|
-
const fallback = safeStringify(value).trim();
|
|
489
|
-
return fallback === "{}" ? "" : fallback;
|
|
490
|
-
}
|
|
491
|
-
function previewMultiline(value, options = {}) {
|
|
492
|
-
const { maxChars = 800, maxLines = 6 } = options;
|
|
493
|
-
const normalized = value.replace(/\r\n/g, "\n").trim();
|
|
494
|
-
if (!normalized) {
|
|
495
|
-
return "";
|
|
496
|
-
}
|
|
497
|
-
const lines = normalized.split("\n");
|
|
498
|
-
const clippedLines = lines.slice(0, maxLines);
|
|
499
|
-
let preview = clippedLines.join("\n");
|
|
500
|
-
let truncated = lines.length > maxLines;
|
|
501
|
-
if (preview.length > maxChars) {
|
|
502
|
-
preview = `${preview.slice(0, Math.max(0, maxChars - 1)).trimEnd()}\u2026`;
|
|
503
|
-
truncated = true;
|
|
504
|
-
}
|
|
505
|
-
if (truncated) {
|
|
506
|
-
return `${preview}
|
|
507
|
-
...`;
|
|
508
|
-
}
|
|
509
|
-
return preview;
|
|
510
|
-
}
|
|
511
|
-
function formatUserContent(content, showImages) {
|
|
512
|
-
if (typeof content === "string") {
|
|
513
|
-
return content;
|
|
514
|
-
}
|
|
515
|
-
const lines = [];
|
|
516
|
-
for (const part of content) {
|
|
517
|
-
if (isTextContent(part)) lines.push(part.text);
|
|
518
|
-
if (showImages && isImageContent(part)) lines.push(`[image: ${part.mimeType}]`);
|
|
519
|
-
}
|
|
520
|
-
return lines.join("\n").trim();
|
|
521
|
-
}
|
|
522
|
-
function splitAssistantMessage(message, showThinking) {
|
|
523
|
-
const textParts = [];
|
|
524
|
-
const thinkingParts = [];
|
|
525
|
-
const toolCalls = [];
|
|
526
|
-
for (const part of message.content) {
|
|
527
|
-
if (isTextContent(part)) {
|
|
528
|
-
textParts.push(part.text);
|
|
529
|
-
continue;
|
|
530
|
-
}
|
|
531
|
-
if (showThinking && isThinkingContent(part)) {
|
|
532
|
-
thinkingParts.push(part.thinking);
|
|
533
|
-
continue;
|
|
534
|
-
}
|
|
535
|
-
if (isToolCall(part)) {
|
|
536
|
-
toolCalls.push(part);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
return {
|
|
540
|
-
text: textParts.join(""),
|
|
541
|
-
thinking: thinkingParts,
|
|
542
|
-
toolCalls
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
function formatToolCall(toolCall) {
|
|
546
|
-
const args = Object.keys(toolCall.arguments ?? {}).length > 0 ? safeStringify(toolCall.arguments) : "{}";
|
|
547
|
-
return `${toolCall.name}
|
|
548
|
-
${previewMultiline(args, { maxLines: 8, maxChars: 1600 })}`;
|
|
549
|
-
}
|
|
550
|
-
function formatToolResult(message, showImages) {
|
|
551
|
-
const contentText = extractToolText(message.content, showImages);
|
|
552
|
-
if (contentText) {
|
|
553
|
-
return contentText;
|
|
554
|
-
}
|
|
555
|
-
if (message.details !== void 0) {
|
|
556
|
-
return extractToolText(message.details, showImages);
|
|
557
|
-
}
|
|
558
|
-
return "";
|
|
559
|
-
}
|
|
560
|
-
function formatCustomContent(content, showImages) {
|
|
561
|
-
if (typeof content === "string") return content;
|
|
562
|
-
return content.map((part) => {
|
|
563
|
-
if (isTextContent(part)) return part.text;
|
|
564
|
-
if (showImages && isImageContent(part)) return `[image: ${part.mimeType}]`;
|
|
565
|
-
return "";
|
|
566
|
-
}).filter(Boolean).join("\n");
|
|
567
|
-
}
|
|
568
|
-
function formatMessageTimestamp(timestamp) {
|
|
569
|
-
return new Date(timestamp).toLocaleTimeString([], {
|
|
570
|
-
hour: "2-digit",
|
|
571
|
-
minute: "2-digit"
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
function extractMessagePreview(message) {
|
|
575
|
-
switch (message.role) {
|
|
576
|
-
case "user":
|
|
577
|
-
return previewText(formatUserContent(message.content, true));
|
|
578
|
-
case "assistant":
|
|
579
|
-
return previewText(splitAssistantMessage(message, false).text);
|
|
580
|
-
case "toolResult":
|
|
581
|
-
return previewText(formatToolResult(message, true));
|
|
582
|
-
case "bashExecution":
|
|
583
|
-
return previewText(`${message.command} ${message.output}`.trim());
|
|
584
|
-
case "branchSummary":
|
|
585
|
-
case "compactionSummary":
|
|
586
|
-
return previewText(message.summary);
|
|
587
|
-
case "custom":
|
|
588
|
-
return previewText(formatCustomContent(message.content, true));
|
|
589
|
-
default:
|
|
590
|
-
return previewText(safeStringify(message));
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
function parseSkillInvocation(content) {
|
|
594
|
-
const parsed = parseSkillBlock(content);
|
|
595
|
-
if (!parsed) return null;
|
|
596
|
-
return {
|
|
597
|
-
name: parsed.name,
|
|
598
|
-
location: parsed.location,
|
|
599
|
-
userMessage: parsed.userMessage
|
|
600
|
-
};
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// src/react-host/index.ts
|
|
604
|
-
var React = await loadHostReact();
|
|
605
|
-
var Fragment2 = React.Fragment;
|
|
606
|
-
var createElement = React.createElement;
|
|
607
|
-
var useEffect = React.useEffect;
|
|
608
|
-
var useMemo = React.useMemo;
|
|
609
|
-
var useState = React.useState;
|
|
610
|
-
|
|
611
|
-
// src/react-ink/markdown/format-token.ts
|
|
612
|
-
import chalk2 from "chalk";
|
|
613
|
-
import { marked } from "marked";
|
|
614
|
-
import stripAnsi3 from "strip-ansi";
|
|
615
|
-
|
|
616
|
-
// src/ui/utils.ts
|
|
617
|
-
import { eastAsianWidth } from "get-east-asian-width";
|
|
618
|
-
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
619
|
-
var TextWidthCalculator = class {
|
|
620
|
-
getWidth(text) {
|
|
621
|
-
return visibleWidth(text);
|
|
622
|
-
}
|
|
623
|
-
clearCache() {
|
|
624
|
-
widthCache.clear();
|
|
625
|
-
}
|
|
626
|
-
};
|
|
627
|
-
var textWidthCalculator = new TextWidthCalculator();
|
|
628
|
-
function looksLikeEmojiCandidate(segment) {
|
|
629
|
-
const cp = segment.codePointAt(0);
|
|
630
|
-
return cp >= 126976 && cp <= 130047 || // pictographs and emoji proper
|
|
631
|
-
cp >= 8960 && cp <= 9215 || // miscellaneous technical glyphs
|
|
632
|
-
cp >= 9728 && cp <= 10175 || // assorted symbols and dingbats
|
|
633
|
-
cp >= 11088 && cp <= 11093 || // a few star/circle characters
|
|
634
|
-
segment.includes("\uFE0F") || // carries VS16, the emoji-presentation selector
|
|
635
|
-
segment.length > 2;
|
|
636
|
-
}
|
|
637
|
-
function createUnicodeRegex(vPattern, uFallback) {
|
|
638
|
-
try {
|
|
639
|
-
return new RegExp(vPattern, "v");
|
|
640
|
-
} catch {
|
|
641
|
-
return new RegExp(uFallback, "u");
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
var zeroWidthRegex = createUnicodeRegex(
|
|
645
|
-
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$",
|
|
646
|
-
"^(?:\\p{Default_Ignorable_Code_Point}|\\p{Control}|\\p{Mark}|\\p{Surrogate})+$"
|
|
647
|
-
);
|
|
648
|
-
var leadingNonPrintingRegex = createUnicodeRegex(
|
|
649
|
-
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+",
|
|
650
|
-
"^[\\p{Default_Ignorable_Code_Point}\\p{Control}\\p{Format}\\p{Mark}\\p{Surrogate}]+"
|
|
651
|
-
);
|
|
652
|
-
var rgiEmojiRegex = createUnicodeRegex("^\\p{RGI_Emoji}$", "^\\p{Extended_Pictographic}$");
|
|
653
|
-
var AnsiStripper = {
|
|
654
|
-
strip(text) {
|
|
655
|
-
if (!text.includes("\x1B")) {
|
|
656
|
-
return text;
|
|
657
|
-
}
|
|
658
|
-
let cleaned = text;
|
|
659
|
-
cleaned = cleaned.replace(/\x1b\[[0-9;]*[mGKHJ]/g, "");
|
|
660
|
-
cleaned = cleaned.replace(/\x1b\]8;;[^\x07]*\x07/g, "");
|
|
661
|
-
cleaned = cleaned.replace(/\x1b_[^\x07\x1b]*(?:\x07|\x1b\\)/g, "");
|
|
662
|
-
return cleaned;
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
var WIDTH_CACHE_SIZE = 512;
|
|
666
|
-
var widthCache = /* @__PURE__ */ new Map();
|
|
667
|
-
function measureClusterWidth(segment) {
|
|
668
|
-
if (zeroWidthRegex.test(segment)) {
|
|
669
|
-
return 0;
|
|
670
|
-
}
|
|
671
|
-
if (looksLikeEmojiCandidate(segment) && rgiEmojiRegex.test(segment)) {
|
|
672
|
-
return 2;
|
|
673
|
-
}
|
|
674
|
-
const base = segment.replace(leadingNonPrintingRegex, "");
|
|
675
|
-
const cp = base.codePointAt(0);
|
|
676
|
-
if (cp === void 0) {
|
|
677
|
-
return 0;
|
|
678
|
-
}
|
|
679
|
-
let width = eastAsianWidth(cp);
|
|
680
|
-
if (segment.length > 1) {
|
|
681
|
-
for (const char of segment.slice(1)) {
|
|
682
|
-
const c = char.codePointAt(0);
|
|
683
|
-
if (c >= 65280 && c <= 65519) {
|
|
684
|
-
width += eastAsianWidth(c);
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
return width;
|
|
689
|
-
}
|
|
690
|
-
function visibleWidth(str) {
|
|
691
|
-
if (str.length === 0) {
|
|
692
|
-
return 0;
|
|
693
|
-
}
|
|
694
|
-
let isPureAscii = true;
|
|
695
|
-
for (let i = 0; i < str.length; i++) {
|
|
696
|
-
const code = str.charCodeAt(i);
|
|
697
|
-
if (code < 32 || code > 126) {
|
|
698
|
-
isPureAscii = false;
|
|
699
|
-
break;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
if (isPureAscii) {
|
|
703
|
-
return str.length;
|
|
704
|
-
}
|
|
705
|
-
const cached = widthCache.get(str);
|
|
706
|
-
if (cached !== void 0) {
|
|
707
|
-
return cached;
|
|
708
|
-
}
|
|
709
|
-
let clean = str;
|
|
710
|
-
if (str.includes(" ")) {
|
|
711
|
-
clean = clean.replace(/\t/g, " ");
|
|
712
|
-
}
|
|
713
|
-
clean = AnsiStripper.strip(clean);
|
|
714
|
-
let width = 0;
|
|
715
|
-
for (const { segment } of segmenter.segment(clean)) {
|
|
716
|
-
width += measureClusterWidth(segment);
|
|
717
|
-
}
|
|
718
|
-
if (widthCache.size >= WIDTH_CACHE_SIZE) {
|
|
719
|
-
const firstKey = widthCache.keys().next().value;
|
|
720
|
-
if (firstKey !== void 0) {
|
|
721
|
-
widthCache.delete(firstKey);
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
widthCache.set(str, width);
|
|
725
|
-
return width;
|
|
726
|
-
}
|
|
727
|
-
function extractAnsiCode(str, pos) {
|
|
728
|
-
if (pos >= str.length || str[pos] !== "\x1B") return null;
|
|
729
|
-
const next = str[pos + 1];
|
|
730
|
-
if (next === "[") {
|
|
731
|
-
let j = pos + 2;
|
|
732
|
-
while (j < str.length && !/[mGKHJ]/.test(str[j])) j++;
|
|
733
|
-
if (j < str.length) return { code: str.substring(pos, j + 1), length: j + 1 - pos };
|
|
734
|
-
return null;
|
|
735
|
-
}
|
|
736
|
-
if (next === "]") {
|
|
737
|
-
let j = pos + 2;
|
|
738
|
-
while (j < str.length) {
|
|
739
|
-
if (str[j] === "\x07") return { code: str.substring(pos, j + 1), length: j + 1 - pos };
|
|
740
|
-
if (str[j] === "\x1B" && str[j + 1] === "\\") return { code: str.substring(pos, j + 2), length: j + 2 - pos };
|
|
741
|
-
j++;
|
|
742
|
-
}
|
|
743
|
-
return null;
|
|
744
|
-
}
|
|
745
|
-
if (next === "_") {
|
|
746
|
-
let j = pos + 2;
|
|
747
|
-
while (j < str.length) {
|
|
748
|
-
if (str[j] === "\x07") return { code: str.substring(pos, j + 1), length: j + 1 - pos };
|
|
749
|
-
if (str[j] === "\x1B" && str[j + 1] === "\\") return { code: str.substring(pos, j + 2), length: j + 2 - pos };
|
|
750
|
-
j++;
|
|
751
|
-
}
|
|
752
|
-
return null;
|
|
753
|
-
}
|
|
754
|
-
return null;
|
|
755
|
-
}
|
|
756
|
-
var AnsiStateTracker = class {
|
|
757
|
-
// Each attribute is kept on its own flag, which lets us clear them one at a time.
|
|
758
|
-
_bold = false;
|
|
759
|
-
_dim = false;
|
|
760
|
-
italic = false;
|
|
761
|
-
underline = false;
|
|
762
|
-
blink = false;
|
|
763
|
-
inverse = false;
|
|
764
|
-
hidden = false;
|
|
765
|
-
strikethrough = false;
|
|
766
|
-
_colors = { fg: null, bg: null };
|
|
767
|
-
process(ansiCode) {
|
|
768
|
-
if (!ansiCode.endsWith("m")) {
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
const match = ansiCode.match(/\x1b\[([\d;]*)m/);
|
|
772
|
-
if (!match) return;
|
|
773
|
-
const params = match[1];
|
|
774
|
-
if (params === "" || params === "0") {
|
|
775
|
-
this.reset();
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
const parts = params.split(";");
|
|
779
|
-
let i = 0;
|
|
780
|
-
while (i < parts.length) {
|
|
781
|
-
const code = Number.parseInt(parts[i] ?? "", 10);
|
|
782
|
-
if (Number.isNaN(code)) {
|
|
783
|
-
i++;
|
|
784
|
-
continue;
|
|
785
|
-
}
|
|
786
|
-
const consumed = this.tryConsumeColorCode(parts, i, code);
|
|
787
|
-
if (consumed > 0) {
|
|
788
|
-
i += consumed;
|
|
789
|
-
continue;
|
|
790
|
-
}
|
|
791
|
-
this.applyStandardCode(code);
|
|
792
|
-
i++;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
tryConsumeColorCode(parts, index, code) {
|
|
796
|
-
if (code !== 38 && code !== 48) {
|
|
797
|
-
return 0;
|
|
798
|
-
}
|
|
799
|
-
if (parts[index + 1] === "5" && parts[index + 2] !== void 0) {
|
|
800
|
-
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]}`;
|
|
801
|
-
if (code === 38) {
|
|
802
|
-
this._colors.fg = colorCode;
|
|
803
|
-
} else {
|
|
804
|
-
this._colors.bg = colorCode;
|
|
805
|
-
}
|
|
806
|
-
return 3;
|
|
807
|
-
}
|
|
808
|
-
if (parts[index + 1] === "2" && parts[index + 4] !== void 0) {
|
|
809
|
-
const colorCode = `${parts[index]};${parts[index + 1]};${parts[index + 2]};${parts[index + 3]};${parts[index + 4]}`;
|
|
810
|
-
if (code === 38) {
|
|
811
|
-
this._colors.fg = colorCode;
|
|
812
|
-
} else {
|
|
813
|
-
this._colors.bg = colorCode;
|
|
814
|
-
}
|
|
815
|
-
return 5;
|
|
816
|
-
}
|
|
817
|
-
return 0;
|
|
818
|
-
}
|
|
819
|
-
applyStandardCode(code) {
|
|
820
|
-
switch (code) {
|
|
821
|
-
case 0:
|
|
822
|
-
this.reset();
|
|
823
|
-
return;
|
|
824
|
-
case 1:
|
|
825
|
-
this._bold = true;
|
|
826
|
-
return;
|
|
827
|
-
case 2:
|
|
828
|
-
this._dim = true;
|
|
829
|
-
return;
|
|
830
|
-
case 3:
|
|
831
|
-
this.italic = true;
|
|
832
|
-
return;
|
|
833
|
-
case 4:
|
|
834
|
-
this.underline = true;
|
|
835
|
-
return;
|
|
836
|
-
case 5:
|
|
837
|
-
this.blink = true;
|
|
838
|
-
return;
|
|
839
|
-
case 7:
|
|
840
|
-
this.inverse = true;
|
|
841
|
-
return;
|
|
842
|
-
case 8:
|
|
843
|
-
this.hidden = true;
|
|
844
|
-
return;
|
|
845
|
-
case 9:
|
|
846
|
-
this.strikethrough = true;
|
|
847
|
-
return;
|
|
848
|
-
case 21:
|
|
849
|
-
this._bold = false;
|
|
850
|
-
return;
|
|
851
|
-
case 22:
|
|
852
|
-
this._bold = false;
|
|
853
|
-
this._dim = false;
|
|
854
|
-
return;
|
|
855
|
-
case 23:
|
|
856
|
-
this.italic = false;
|
|
857
|
-
return;
|
|
858
|
-
case 24:
|
|
859
|
-
this.underline = false;
|
|
860
|
-
return;
|
|
861
|
-
case 25:
|
|
862
|
-
this.blink = false;
|
|
863
|
-
return;
|
|
864
|
-
case 27:
|
|
865
|
-
this.inverse = false;
|
|
866
|
-
return;
|
|
867
|
-
case 28:
|
|
868
|
-
this.hidden = false;
|
|
869
|
-
return;
|
|
870
|
-
case 29:
|
|
871
|
-
this.strikethrough = false;
|
|
872
|
-
return;
|
|
873
|
-
case 39:
|
|
874
|
-
this._colors.fg = null;
|
|
875
|
-
return;
|
|
876
|
-
case 49:
|
|
877
|
-
this._colors.bg = null;
|
|
878
|
-
return;
|
|
879
|
-
default:
|
|
880
|
-
if (code >= 30 && code <= 37 || code >= 90 && code <= 97) {
|
|
881
|
-
this._colors.fg = String(code);
|
|
882
|
-
return;
|
|
883
|
-
}
|
|
884
|
-
if (code >= 40 && code <= 47 || code >= 100 && code <= 107) {
|
|
885
|
-
this._colors.bg = String(code);
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
reset() {
|
|
890
|
-
this._bold = false;
|
|
891
|
-
this._dim = false;
|
|
892
|
-
this.italic = false;
|
|
893
|
-
this.underline = false;
|
|
894
|
-
this.blink = false;
|
|
895
|
-
this.inverse = false;
|
|
896
|
-
this.hidden = false;
|
|
897
|
-
this.strikethrough = false;
|
|
898
|
-
this._colors.fg = null;
|
|
899
|
-
this._colors.bg = null;
|
|
900
|
-
}
|
|
901
|
-
/** Wipe all tracked state so the instance can be reused. */
|
|
902
|
-
clear() {
|
|
903
|
-
this.reset();
|
|
904
|
-
}
|
|
905
|
-
getActiveCodes() {
|
|
906
|
-
const codes = [];
|
|
907
|
-
if (this._bold) codes.push("1");
|
|
908
|
-
if (this._dim) codes.push("2");
|
|
909
|
-
if (this.italic) codes.push("3");
|
|
910
|
-
if (this.underline) codes.push("4");
|
|
911
|
-
if (this.blink) codes.push("5");
|
|
912
|
-
if (this.inverse) codes.push("7");
|
|
913
|
-
if (this.hidden) codes.push("8");
|
|
914
|
-
if (this.strikethrough) codes.push("9");
|
|
915
|
-
if (this._colors.fg) codes.push(this._colors.fg);
|
|
916
|
-
if (this._colors.bg) codes.push(this._colors.bg);
|
|
917
|
-
if (codes.length === 0) return "";
|
|
918
|
-
return `\x1B[${codes.join(";")}m`;
|
|
919
|
-
}
|
|
920
|
-
hasActiveCodes() {
|
|
921
|
-
return this._bold || this._dim || this.italic || this.underline || this.blink || this.inverse || this.hidden || this.strikethrough || this._colors.fg !== null || this._colors.bg !== null;
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Produce the escape code needed to switch off any attribute that would
|
|
925
|
-
* otherwise smear into the padding at the end of a line. In practice that
|
|
926
|
-
* is just underline. Yields an empty string when nothing needs disabling.
|
|
927
|
-
*/
|
|
928
|
-
getLineEndReset() {
|
|
929
|
-
if (this.underline) {
|
|
930
|
-
return "\x1B[24m";
|
|
931
|
-
}
|
|
932
|
-
return "";
|
|
933
|
-
}
|
|
934
|
-
};
|
|
935
|
-
function mergeTextIntoTracker(text, tracker) {
|
|
936
|
-
let i = 0;
|
|
937
|
-
while (i < text.length) {
|
|
938
|
-
const ansiResult = extractAnsiCode(text, i);
|
|
939
|
-
if (ansiResult) {
|
|
940
|
-
tracker.process(ansiResult.code);
|
|
941
|
-
i += ansiResult.length;
|
|
942
|
-
} else {
|
|
943
|
-
i++;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
function tokenizeTextWithAnsi(text) {
|
|
948
|
-
const tokens = [];
|
|
949
|
-
let current = "";
|
|
950
|
-
let pendingAnsi = "";
|
|
951
|
-
let inWhitespace = false;
|
|
952
|
-
let i = 0;
|
|
953
|
-
while (i < text.length) {
|
|
954
|
-
const ansiResult = extractAnsiCode(text, i);
|
|
955
|
-
if (ansiResult) {
|
|
956
|
-
pendingAnsi += ansiResult.code;
|
|
957
|
-
i += ansiResult.length;
|
|
958
|
-
continue;
|
|
959
|
-
}
|
|
960
|
-
const char = text[i];
|
|
961
|
-
const charIsSpace = char === " ";
|
|
962
|
-
if (charIsSpace !== inWhitespace && current) {
|
|
963
|
-
tokens.push(current);
|
|
964
|
-
current = "";
|
|
965
|
-
}
|
|
966
|
-
if (pendingAnsi) {
|
|
967
|
-
current += pendingAnsi;
|
|
968
|
-
pendingAnsi = "";
|
|
969
|
-
}
|
|
970
|
-
inWhitespace = charIsSpace;
|
|
971
|
-
current += char;
|
|
972
|
-
i++;
|
|
973
|
-
}
|
|
974
|
-
if (pendingAnsi) {
|
|
975
|
-
current += pendingAnsi;
|
|
976
|
-
}
|
|
977
|
-
if (current) {
|
|
978
|
-
tokens.push(current);
|
|
979
|
-
}
|
|
980
|
-
return tokens;
|
|
981
|
-
}
|
|
982
|
-
var TextWrapper = class {
|
|
983
|
-
wrap(text, width) {
|
|
984
|
-
return wrapTextWithAnsi(text, width);
|
|
985
|
-
}
|
|
986
|
-
};
|
|
987
|
-
var textWrapper = new TextWrapper();
|
|
988
|
-
var TokenWrapEngine = {
|
|
989
|
-
wrap(tokens, width, tracker) {
|
|
990
|
-
const wrapped = [];
|
|
991
|
-
let currentLine = "";
|
|
992
|
-
let currentVisibleLength = 0;
|
|
993
|
-
for (const token of tokens) {
|
|
994
|
-
const tokenVisibleLength = visibleWidth(token);
|
|
995
|
-
const isWhitespace = token.trim() === "";
|
|
996
|
-
if (tokenVisibleLength > width && !isWhitespace) {
|
|
997
|
-
if (currentLine) {
|
|
998
|
-
const lineEndReset = tracker.getLineEndReset();
|
|
999
|
-
if (lineEndReset) {
|
|
1000
|
-
currentLine += lineEndReset;
|
|
1001
|
-
}
|
|
1002
|
-
wrapped.push(currentLine);
|
|
1003
|
-
currentLine = "";
|
|
1004
|
-
currentVisibleLength = 0;
|
|
1005
|
-
}
|
|
1006
|
-
const broken = splitLongToken(token, width, tracker);
|
|
1007
|
-
wrapped.push(...broken.slice(0, -1));
|
|
1008
|
-
currentLine = broken[broken.length - 1];
|
|
1009
|
-
currentVisibleLength = visibleWidth(currentLine);
|
|
1010
|
-
continue;
|
|
1011
|
-
}
|
|
1012
|
-
const totalNeeded = currentVisibleLength + tokenVisibleLength;
|
|
1013
|
-
if (totalNeeded > width && currentVisibleLength > 0) {
|
|
1014
|
-
let lineToWrap = currentLine.trimEnd();
|
|
1015
|
-
const lineEndReset = tracker.getLineEndReset();
|
|
1016
|
-
if (lineEndReset) {
|
|
1017
|
-
lineToWrap += lineEndReset;
|
|
1018
|
-
}
|
|
1019
|
-
wrapped.push(lineToWrap);
|
|
1020
|
-
if (isWhitespace) {
|
|
1021
|
-
currentLine = tracker.getActiveCodes();
|
|
1022
|
-
currentVisibleLength = 0;
|
|
1023
|
-
} else {
|
|
1024
|
-
currentLine = tracker.getActiveCodes() + token;
|
|
1025
|
-
currentVisibleLength = tokenVisibleLength;
|
|
1026
|
-
}
|
|
1027
|
-
} else {
|
|
1028
|
-
currentLine += token;
|
|
1029
|
-
currentVisibleLength += tokenVisibleLength;
|
|
1030
|
-
}
|
|
1031
|
-
mergeTextIntoTracker(token, tracker);
|
|
1032
|
-
}
|
|
1033
|
-
return { wrapped, currentLine, currentVisibleLength };
|
|
1034
|
-
}
|
|
1035
|
-
};
|
|
1036
|
-
function wrapTextWithAnsi(text, width) {
|
|
1037
|
-
if (!text) {
|
|
1038
|
-
return [""];
|
|
1039
|
-
}
|
|
1040
|
-
const inputLines = text.split("\n");
|
|
1041
|
-
const result = [];
|
|
1042
|
-
const tracker = new AnsiStateTracker();
|
|
1043
|
-
for (const inputLine of inputLines) {
|
|
1044
|
-
const prefix = result.length > 0 ? tracker.getActiveCodes() : "";
|
|
1045
|
-
result.push(...wrapLinePreservingAnsi(prefix + inputLine, width));
|
|
1046
|
-
mergeTextIntoTracker(inputLine, tracker);
|
|
1047
|
-
}
|
|
1048
|
-
return result.length > 0 ? result : [""];
|
|
1049
|
-
}
|
|
1050
|
-
function wrapLinePreservingAnsi(line, width) {
|
|
1051
|
-
if (!line) {
|
|
1052
|
-
return [""];
|
|
1053
|
-
}
|
|
1054
|
-
const visibleLength = visibleWidth(line);
|
|
1055
|
-
if (visibleLength <= width) {
|
|
1056
|
-
return [line];
|
|
1057
|
-
}
|
|
1058
|
-
const tracker = new AnsiStateTracker();
|
|
1059
|
-
const tokens = tokenizeTextWithAnsi(line);
|
|
1060
|
-
const { wrapped, currentLine } = TokenWrapEngine.wrap(tokens, width, tracker);
|
|
1061
|
-
if (currentLine) {
|
|
1062
|
-
wrapped.push(currentLine);
|
|
1063
|
-
}
|
|
1064
|
-
return wrapped.length > 0 ? wrapped.map((segmentLine) => segmentLine.trimEnd()) : [""];
|
|
1065
|
-
}
|
|
1066
|
-
function splitLongToken(word, width, tracker) {
|
|
1067
|
-
const lines = [];
|
|
1068
|
-
let currentLine = tracker.getActiveCodes();
|
|
1069
|
-
let currentWidth = 0;
|
|
1070
|
-
let i = 0;
|
|
1071
|
-
const segments = [];
|
|
1072
|
-
while (i < word.length) {
|
|
1073
|
-
const ansiResult = extractAnsiCode(word, i);
|
|
1074
|
-
if (ansiResult) {
|
|
1075
|
-
segments.push({ type: "ansi", value: ansiResult.code });
|
|
1076
|
-
i += ansiResult.length;
|
|
1077
|
-
} else {
|
|
1078
|
-
let end = i;
|
|
1079
|
-
while (end < word.length) {
|
|
1080
|
-
const nextAnsi = extractAnsiCode(word, end);
|
|
1081
|
-
if (nextAnsi) break;
|
|
1082
|
-
end++;
|
|
1083
|
-
}
|
|
1084
|
-
const textPortion = word.slice(i, end);
|
|
1085
|
-
for (const seg of segmenter.segment(textPortion)) {
|
|
1086
|
-
segments.push({ type: "grapheme", value: seg.segment });
|
|
1087
|
-
}
|
|
1088
|
-
i = end;
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
for (const seg of segments) {
|
|
1092
|
-
if (seg.type === "ansi") {
|
|
1093
|
-
currentLine += seg.value;
|
|
1094
|
-
tracker.process(seg.value);
|
|
1095
|
-
continue;
|
|
1096
|
-
}
|
|
1097
|
-
const grapheme = seg.value;
|
|
1098
|
-
if (!grapheme) continue;
|
|
1099
|
-
const clusterWidth = visibleWidth(grapheme);
|
|
1100
|
-
if (currentWidth + clusterWidth > width) {
|
|
1101
|
-
const lineEndReset = tracker.getLineEndReset();
|
|
1102
|
-
if (lineEndReset) {
|
|
1103
|
-
currentLine += lineEndReset;
|
|
1104
|
-
}
|
|
1105
|
-
lines.push(currentLine);
|
|
1106
|
-
currentLine = tracker.getActiveCodes();
|
|
1107
|
-
currentWidth = 0;
|
|
1108
|
-
}
|
|
1109
|
-
currentLine += grapheme;
|
|
1110
|
-
currentWidth += clusterWidth;
|
|
1111
|
-
}
|
|
1112
|
-
if (currentLine) {
|
|
1113
|
-
lines.push(currentLine);
|
|
1114
|
-
}
|
|
1115
|
-
return lines.length > 0 ? lines : [""];
|
|
1116
|
-
}
|
|
1117
|
-
var pooledStyleTracker = new AnsiStateTracker();
|
|
1118
|
-
|
|
1119
|
-
// src/react-ink/markdown/format-token.ts
|
|
1120
|
-
var EOL = "\n";
|
|
1121
|
-
var BLOCKQUOTE_BAR = "\u2502";
|
|
1122
|
-
var markedConfigured = false;
|
|
1123
|
-
function configureMarked() {
|
|
1124
|
-
if (markedConfigured) {
|
|
1125
|
-
return;
|
|
1126
|
-
}
|
|
1127
|
-
markedConfigured = true;
|
|
1128
|
-
marked.use({
|
|
1129
|
-
tokenizer: {
|
|
1130
|
-
del() {
|
|
1131
|
-
return void 0;
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
|
-
var TOKEN_CACHE_MAX = 500;
|
|
1137
|
-
var tokenCache = /* @__PURE__ */ new Map();
|
|
1138
|
-
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
1139
|
-
function hasMarkdownSyntax(text) {
|
|
1140
|
-
return MD_SYNTAX_RE.test(text.length > 500 ? text.slice(0, 500) : text);
|
|
1141
|
-
}
|
|
1142
|
-
function hashContent(content) {
|
|
1143
|
-
let hash = 2166136261;
|
|
1144
|
-
for (let i = 0; i < content.length; i++) {
|
|
1145
|
-
hash ^= content.charCodeAt(i);
|
|
1146
|
-
hash = Math.imul(hash, 16777619);
|
|
1147
|
-
}
|
|
1148
|
-
return (hash >>> 0).toString(36) + ":" + content.length.toString(36);
|
|
1149
|
-
}
|
|
1150
|
-
function cachedLexer(content) {
|
|
1151
|
-
configureMarked();
|
|
1152
|
-
if (!hasMarkdownSyntax(content)) {
|
|
1153
|
-
return [
|
|
1154
|
-
{
|
|
1155
|
-
type: "paragraph",
|
|
1156
|
-
raw: content,
|
|
1157
|
-
text: content,
|
|
1158
|
-
tokens: [{ type: "text", raw: content, text: content }]
|
|
1159
|
-
}
|
|
1160
|
-
];
|
|
1161
|
-
}
|
|
1162
|
-
const key = hashContent(content);
|
|
1163
|
-
const hit = tokenCache.get(key);
|
|
1164
|
-
if (hit) {
|
|
1165
|
-
tokenCache.delete(key);
|
|
1166
|
-
tokenCache.set(key, hit);
|
|
1167
|
-
return hit;
|
|
1168
|
-
}
|
|
1169
|
-
const tokens = marked.lexer(content);
|
|
1170
|
-
if (tokenCache.size >= TOKEN_CACHE_MAX) {
|
|
1171
|
-
const first = tokenCache.keys().next().value;
|
|
1172
|
-
if (first !== void 0) {
|
|
1173
|
-
tokenCache.delete(first);
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
tokenCache.set(key, tokens);
|
|
1177
|
-
return tokens;
|
|
1178
|
-
}
|
|
1179
|
-
function formatToken(token, theme, highlight = null, listDepth = 0, orderedListNumber = null, parent = null) {
|
|
1180
|
-
switch (token.type) {
|
|
1181
|
-
case "blockquote": {
|
|
1182
|
-
const inner = (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
1183
|
-
const bar = theme.dim(BLOCKQUOTE_BAR);
|
|
1184
|
-
return inner.split(EOL).map((line) => stripAnsi3(line).trim() ? `${bar} ${chalk2.italic(line)}` : line).join(EOL);
|
|
1185
|
-
}
|
|
1186
|
-
case "code": {
|
|
1187
|
-
const codeToken = token;
|
|
1188
|
-
if (!highlight) {
|
|
1189
|
-
return codeToken.text + EOL;
|
|
1190
|
-
}
|
|
1191
|
-
let language = "plaintext";
|
|
1192
|
-
if (codeToken.lang && highlight.supportsLanguage(codeToken.lang)) {
|
|
1193
|
-
language = codeToken.lang;
|
|
1194
|
-
}
|
|
1195
|
-
return highlight.highlight(codeToken.text, { language }) + EOL;
|
|
1196
|
-
}
|
|
1197
|
-
case "codespan":
|
|
1198
|
-
return theme.role("codeInline", token.text);
|
|
1199
|
-
case "em":
|
|
1200
|
-
return chalk2.italic(
|
|
1201
|
-
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
1202
|
-
);
|
|
1203
|
-
case "strong":
|
|
1204
|
-
return chalk2.bold(
|
|
1205
|
-
(token.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, parent)).join("")
|
|
1206
|
-
);
|
|
1207
|
-
case "heading": {
|
|
1208
|
-
const headingToken = token;
|
|
1209
|
-
const inner = (headingToken.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
1210
|
-
const colored = theme.role("heading", inner);
|
|
1211
|
-
if (headingToken.depth === 1) {
|
|
1212
|
-
return chalk2.bold.italic.underline(colored) + EOL + EOL;
|
|
1213
|
-
}
|
|
1214
|
-
return chalk2.bold(colored) + EOL + EOL;
|
|
1215
|
-
}
|
|
1216
|
-
case "hr":
|
|
1217
|
-
return "---";
|
|
1218
|
-
case "image":
|
|
1219
|
-
return token.href;
|
|
1220
|
-
case "link": {
|
|
1221
|
-
const linkToken = token;
|
|
1222
|
-
if (linkToken.href.startsWith("mailto:")) {
|
|
1223
|
-
return linkToken.href.replace(/^mailto:/, "");
|
|
1224
|
-
}
|
|
1225
|
-
const linkText = (linkToken.tokens ?? []).map((child) => formatToken(child, theme, highlight, 0, null, linkToken)).join("");
|
|
1226
|
-
const plainLinkText = stripAnsi3(linkText);
|
|
1227
|
-
const display = plainLinkText && plainLinkText !== linkToken.href ? linkText : linkToken.href;
|
|
1228
|
-
return `\x1B]8;;${linkToken.href}\x07${display}\x1B]8;;\x07`;
|
|
1229
|
-
}
|
|
1230
|
-
case "list": {
|
|
1231
|
-
const listToken = token;
|
|
1232
|
-
const start = typeof listToken.start === "number" ? listToken.start : Number(listToken.start) || 1;
|
|
1233
|
-
return listToken.items.map(
|
|
1234
|
-
(item, index) => formatToken(
|
|
1235
|
-
item,
|
|
1236
|
-
theme,
|
|
1237
|
-
highlight,
|
|
1238
|
-
listDepth,
|
|
1239
|
-
listToken.ordered ? start + index : null,
|
|
1240
|
-
listToken
|
|
1241
|
-
)
|
|
1242
|
-
).join("");
|
|
1243
|
-
}
|
|
1244
|
-
case "list_item":
|
|
1245
|
-
return (token.tokens ?? []).map(
|
|
1246
|
-
(child) => `${" ".repeat(listDepth)}${formatToken(child, theme, highlight, listDepth + 1, orderedListNumber, token)}`
|
|
1247
|
-
).join("");
|
|
1248
|
-
case "paragraph":
|
|
1249
|
-
return (token.tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("") + EOL;
|
|
1250
|
-
case "space":
|
|
1251
|
-
case "br":
|
|
1252
|
-
return EOL;
|
|
1253
|
-
case "text": {
|
|
1254
|
-
const textToken = token;
|
|
1255
|
-
if (parent?.type === "link") {
|
|
1256
|
-
return textToken.text;
|
|
1257
|
-
}
|
|
1258
|
-
if (parent?.type === "list_item") {
|
|
1259
|
-
const marker = orderedListNumber === null ? "-" : `${getListNumber(listDepth, orderedListNumber)}.`;
|
|
1260
|
-
const body = textToken.tokens ? textToken.tokens.map((child) => formatToken(child, theme, highlight, listDepth, orderedListNumber, token)).join("") : textToken.text;
|
|
1261
|
-
return `${marker} ${body}${EOL}`;
|
|
1262
|
-
}
|
|
1263
|
-
return textToken.text;
|
|
1264
|
-
}
|
|
1265
|
-
case "escape":
|
|
1266
|
-
return token.text;
|
|
1267
|
-
case "table":
|
|
1268
|
-
case "def":
|
|
1269
|
-
case "del":
|
|
1270
|
-
case "html":
|
|
1271
|
-
return "";
|
|
1272
|
-
default:
|
|
1273
|
-
return "";
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
function numberToLetter(n) {
|
|
1277
|
-
let result = "";
|
|
1278
|
-
while (n > 0) {
|
|
1279
|
-
n--;
|
|
1280
|
-
result = String.fromCharCode(97 + n % 26) + result;
|
|
1281
|
-
n = Math.floor(n / 26);
|
|
1282
|
-
}
|
|
1283
|
-
return result;
|
|
1284
|
-
}
|
|
1285
|
-
var ROMAN_VALUES = [
|
|
1286
|
-
[1e3, "m"],
|
|
1287
|
-
[900, "cm"],
|
|
1288
|
-
[500, "d"],
|
|
1289
|
-
[400, "cd"],
|
|
1290
|
-
[100, "c"],
|
|
1291
|
-
[90, "xc"],
|
|
1292
|
-
[50, "l"],
|
|
1293
|
-
[40, "xl"],
|
|
1294
|
-
[10, "x"],
|
|
1295
|
-
[9, "ix"],
|
|
1296
|
-
[5, "v"],
|
|
1297
|
-
[4, "iv"],
|
|
1298
|
-
[1, "i"]
|
|
1299
|
-
];
|
|
1300
|
-
function numberToRoman(n) {
|
|
1301
|
-
let result = "";
|
|
1302
|
-
for (const [value, numeral] of ROMAN_VALUES) {
|
|
1303
|
-
while (n >= value) {
|
|
1304
|
-
result += numeral;
|
|
1305
|
-
n -= value;
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
|
-
return result;
|
|
1309
|
-
}
|
|
1310
|
-
function getListNumber(listDepth, orderedListNumber) {
|
|
1311
|
-
switch (listDepth) {
|
|
1312
|
-
case 0:
|
|
1313
|
-
case 1:
|
|
1314
|
-
return orderedListNumber.toString();
|
|
1315
|
-
case 2:
|
|
1316
|
-
return numberToLetter(orderedListNumber);
|
|
1317
|
-
case 3:
|
|
1318
|
-
return numberToRoman(orderedListNumber);
|
|
1319
|
-
default:
|
|
1320
|
-
return orderedListNumber.toString();
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
function padAligned(content, displayWidth, targetWidth, align) {
|
|
1324
|
-
const padding = Math.max(0, targetWidth - displayWidth);
|
|
1325
|
-
if (align === "center") {
|
|
1326
|
-
const leftPad = Math.floor(padding / 2);
|
|
1327
|
-
return " ".repeat(leftPad) + content + " ".repeat(padding - leftPad);
|
|
1328
|
-
}
|
|
1329
|
-
if (align === "right") {
|
|
1330
|
-
return " ".repeat(padding) + content;
|
|
1331
|
-
}
|
|
1332
|
-
return content + " ".repeat(padding);
|
|
1333
|
-
}
|
|
1334
|
-
function stringWidth(text) {
|
|
1335
|
-
return visibleWidth(text);
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
// src/react-ink/markdown/highlight.ts
|
|
1339
|
-
import { extname } from "node:path";
|
|
1340
|
-
import hljs from "highlight.js";
|
|
1341
|
-
function scopeToRole(scope) {
|
|
1342
|
-
const head = scope.split(".")[0] ?? scope;
|
|
1343
|
-
switch (head) {
|
|
1344
|
-
case "keyword":
|
|
1345
|
-
case "built_in":
|
|
1346
|
-
case "literal":
|
|
1347
|
-
case "operator":
|
|
1348
|
-
return "synKeyword";
|
|
1349
|
-
case "string":
|
|
1350
|
-
case "regexp":
|
|
1351
|
-
case "symbol":
|
|
1352
|
-
case "char":
|
|
1353
|
-
case "meta":
|
|
1354
|
-
return "synString";
|
|
1355
|
-
case "number":
|
|
1356
|
-
return "synNumber";
|
|
1357
|
-
case "comment":
|
|
1358
|
-
case "quote":
|
|
1359
|
-
return "synComment";
|
|
1360
|
-
case "type":
|
|
1361
|
-
case "class":
|
|
1362
|
-
case "title":
|
|
1363
|
-
case "tag":
|
|
1364
|
-
case "name":
|
|
1365
|
-
case "attr":
|
|
1366
|
-
case "attribute":
|
|
1367
|
-
case "selector":
|
|
1368
|
-
return "synType";
|
|
1369
|
-
default:
|
|
1370
|
-
return null;
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
var HTML_ENTITIES = {
|
|
1374
|
-
"&": "&",
|
|
1375
|
-
"<": "<",
|
|
1376
|
-
">": ">",
|
|
1377
|
-
""": '"',
|
|
1378
|
-
"'": "'",
|
|
1379
|
-
"'": "'"
|
|
1380
|
-
};
|
|
1381
|
-
function decodeEntities(text) {
|
|
1382
|
-
return text.replace(/&(?:amp|lt|gt|quot|#x27|#39);/g, (match) => HTML_ENTITIES[match] ?? match);
|
|
1383
|
-
}
|
|
1384
|
-
function parseHljsHtml(html) {
|
|
1385
|
-
const nodes = [];
|
|
1386
|
-
const scopeStack = [];
|
|
1387
|
-
const tagRe = /<span class="hljs-([^"]+)">|<\/span>/g;
|
|
1388
|
-
let lastIndex = 0;
|
|
1389
|
-
let match;
|
|
1390
|
-
const pushText = (raw) => {
|
|
1391
|
-
if (!raw) return;
|
|
1392
|
-
const currentScope = scopeStack.length > 0 ? scopeStack[scopeStack.length - 1] : null;
|
|
1393
|
-
const scope = currentScope ? currentScope.split(/\s+/)[0].replace(/_$/, "") : null;
|
|
1394
|
-
nodes.push({ text: decodeEntities(raw), scope });
|
|
1395
|
-
};
|
|
1396
|
-
while ((match = tagRe.exec(html)) !== null) {
|
|
1397
|
-
pushText(html.slice(lastIndex, match.index));
|
|
1398
|
-
lastIndex = tagRe.lastIndex;
|
|
1399
|
-
if (match[0] === "</span>") {
|
|
1400
|
-
scopeStack.pop();
|
|
1401
|
-
} else if (match[1]) {
|
|
1402
|
-
scopeStack.push(match[1]);
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
pushText(html.slice(lastIndex));
|
|
1406
|
-
return nodes;
|
|
1407
|
-
}
|
|
1408
|
-
function createHighlighter(theme) {
|
|
1409
|
-
return {
|
|
1410
|
-
supportsLanguage: (language) => {
|
|
1411
|
-
if (!language || language === "plaintext" || language === "text") {
|
|
1412
|
-
return false;
|
|
1413
|
-
}
|
|
1414
|
-
try {
|
|
1415
|
-
return hljs.getLanguage(language) !== void 0;
|
|
1416
|
-
} catch {
|
|
1417
|
-
return false;
|
|
1418
|
-
}
|
|
1419
|
-
},
|
|
1420
|
-
highlight: (code, options) => {
|
|
1421
|
-
const language = options.language;
|
|
1422
|
-
if (!language || language === "plaintext" || language === "text") {
|
|
1423
|
-
return code;
|
|
1424
|
-
}
|
|
1425
|
-
try {
|
|
1426
|
-
if (hljs.getLanguage(language) === void 0) {
|
|
1427
|
-
return code;
|
|
1428
|
-
}
|
|
1429
|
-
const { value } = hljs.highlight(code, { language, ignoreIllegals: true });
|
|
1430
|
-
return parseHljsHtml(value).map((node) => {
|
|
1431
|
-
const role = node.scope ? scopeToRole(node.scope) : null;
|
|
1432
|
-
return role ? theme.role(role, node.text) : node.text;
|
|
1433
|
-
}).join("");
|
|
1434
|
-
} catch {
|
|
1435
|
-
return code;
|
|
1436
|
-
}
|
|
1437
|
-
}
|
|
1438
|
-
};
|
|
1439
|
-
}
|
|
1440
|
-
function highlightByPath(code, filePath, theme) {
|
|
1441
|
-
const language = languageFromPath(filePath);
|
|
1442
|
-
if (!language) {
|
|
1443
|
-
return code;
|
|
1444
|
-
}
|
|
1445
|
-
const highlighter = createHighlighter(theme);
|
|
1446
|
-
if (!highlighter.supportsLanguage(language)) {
|
|
1447
|
-
return code;
|
|
1448
|
-
}
|
|
1449
|
-
return highlighter.highlight(code, { language });
|
|
1450
|
-
}
|
|
1451
|
-
var EXTENSION_LANGUAGES = {
|
|
1452
|
-
ts: "typescript",
|
|
1453
|
-
tsx: "typescript",
|
|
1454
|
-
mts: "typescript",
|
|
1455
|
-
cts: "typescript",
|
|
1456
|
-
js: "javascript",
|
|
1457
|
-
jsx: "javascript",
|
|
1458
|
-
mjs: "javascript",
|
|
1459
|
-
cjs: "javascript",
|
|
1460
|
-
py: "python",
|
|
1461
|
-
rb: "ruby",
|
|
1462
|
-
rs: "rust",
|
|
1463
|
-
go: "go",
|
|
1464
|
-
java: "java",
|
|
1465
|
-
kt: "kotlin",
|
|
1466
|
-
c: "c",
|
|
1467
|
-
h: "c",
|
|
1468
|
-
cc: "cpp",
|
|
1469
|
-
cpp: "cpp",
|
|
1470
|
-
hpp: "cpp",
|
|
1471
|
-
cs: "csharp",
|
|
1472
|
-
sh: "bash",
|
|
1473
|
-
bash: "bash",
|
|
1474
|
-
zsh: "bash",
|
|
1475
|
-
yml: "yaml",
|
|
1476
|
-
yaml: "yaml",
|
|
1477
|
-
json: "json",
|
|
1478
|
-
md: "markdown",
|
|
1479
|
-
html: "xml",
|
|
1480
|
-
xml: "xml",
|
|
1481
|
-
css: "css",
|
|
1482
|
-
scss: "scss",
|
|
1483
|
-
sql: "sql",
|
|
1484
|
-
toml: "ini",
|
|
1485
|
-
ini: "ini",
|
|
1486
|
-
php: "php",
|
|
1487
|
-
swift: "swift"
|
|
1488
|
-
};
|
|
1489
|
-
function languageFromPath(filePath) {
|
|
1490
|
-
const ext = extname(filePath).slice(1).toLowerCase();
|
|
1491
|
-
if (!ext) {
|
|
1492
|
-
return null;
|
|
1493
|
-
}
|
|
1494
|
-
const mapped = EXTENSION_LANGUAGES[ext];
|
|
1495
|
-
if (mapped) {
|
|
1496
|
-
return mapped;
|
|
1497
|
-
}
|
|
1498
|
-
try {
|
|
1499
|
-
return hljs.getLanguage(ext) !== void 0 ? ext : null;
|
|
1500
|
-
} catch {
|
|
1501
|
-
return null;
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
// src/react-ink/markdown/MarkdownTable.tsx
|
|
1506
|
-
import chalk3 from "chalk";
|
|
1507
|
-
import stripAnsi4 from "strip-ansi";
|
|
1508
|
-
var MIN_COLUMN_WIDTH = 3;
|
|
1509
|
-
var COLUMN_GAP = 2;
|
|
1510
|
-
function MarkdownTable({ token, theme, highlight = null }) {
|
|
1511
|
-
const formatCell = (tokens) => (tokens ?? []).map((child) => formatToken(child, theme, highlight)).join("");
|
|
1512
|
-
const displayWidth = (tokens) => stringWidth(stripAnsi4(formatCell(tokens)));
|
|
1513
|
-
const columnCount = token.header.length;
|
|
1514
|
-
const columnWidths = token.header.map((header, index) => {
|
|
1515
|
-
let max = displayWidth(header.tokens);
|
|
1516
|
-
for (const row of token.rows) {
|
|
1517
|
-
max = Math.max(max, displayWidth(row[index]?.tokens));
|
|
1518
|
-
}
|
|
1519
|
-
return Math.max(max, MIN_COLUMN_WIDTH);
|
|
1520
|
-
});
|
|
1521
|
-
const renderRow = (cells, key, bold) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
1522
|
-
const cell = cells[index];
|
|
1523
|
-
const content = formatCell(cell?.tokens);
|
|
1524
|
-
const visible = stringWidth(stripAnsi4(content));
|
|
1525
|
-
const align = token.align?.[index];
|
|
1526
|
-
const padded = padAligned(content, visible, width, align ?? "left");
|
|
1527
|
-
const styled = bold ? chalk3.bold(padded) : padded;
|
|
1528
|
-
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
1529
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
1530
|
-
styled,
|
|
1531
|
-
gap
|
|
1532
|
-
] }, index);
|
|
1533
|
-
}) }, key);
|
|
1534
|
-
const separator = /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: columnWidths.map((width, index) => {
|
|
1535
|
-
const gap = index < columnCount - 1 ? " ".repeat(COLUMN_GAP) : "";
|
|
1536
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
1537
|
-
theme.dim("-".repeat(width)),
|
|
1538
|
-
gap
|
|
1539
|
-
] }, index);
|
|
1540
|
-
}) });
|
|
1541
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1542
|
-
renderRow(token.header, "header", true),
|
|
1543
|
-
separator,
|
|
1544
|
-
token.rows.map((row, rowIndex) => renderRow(row, `row-${rowIndex}`, false))
|
|
1545
|
-
] });
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
// src/react-ink/markdown/Markdown.tsx
|
|
1549
|
-
function stripPromptXMLTags(text) {
|
|
1550
|
-
return text.replace(/<\/?(?:system-reminder|prompt|context)[^>]*>/g, "");
|
|
1551
|
-
}
|
|
1552
|
-
function Markdown({ children, theme, highlightCode = true, dim = false }) {
|
|
1553
|
-
const highlight = useMemo(
|
|
1554
|
-
() => highlightCode ? createHighlighter(theme) : null,
|
|
1555
|
-
[highlightCode, theme]
|
|
1556
|
-
);
|
|
1557
|
-
const elements = useMemo(() => {
|
|
1558
|
-
configureMarked();
|
|
1559
|
-
const tokens = cachedLexer(stripPromptXMLTags(children));
|
|
1560
|
-
const out = [];
|
|
1561
|
-
let buffer = "";
|
|
1562
|
-
const flush = () => {
|
|
1563
|
-
if (buffer) {
|
|
1564
|
-
const text = buffer.replace(/\n+$/, "");
|
|
1565
|
-
if (text) {
|
|
1566
|
-
out.push(
|
|
1567
|
-
/* @__PURE__ */ jsx(Text, { children: dim ? theme.dim(text) : text }, out.length)
|
|
1568
|
-
);
|
|
1569
|
-
}
|
|
1570
|
-
buffer = "";
|
|
1571
|
-
}
|
|
1572
|
-
};
|
|
1573
|
-
for (const token of tokens) {
|
|
1574
|
-
if (token.type === "table") {
|
|
1575
|
-
flush();
|
|
1576
|
-
out.push(
|
|
1577
|
-
/* @__PURE__ */ jsx(
|
|
1578
|
-
MarkdownTable,
|
|
1579
|
-
{
|
|
1580
|
-
token,
|
|
1581
|
-
theme,
|
|
1582
|
-
highlight
|
|
1583
|
-
},
|
|
1584
|
-
out.length
|
|
1585
|
-
)
|
|
1586
|
-
);
|
|
1587
|
-
} else {
|
|
1588
|
-
buffer += formatToken(token, theme, highlight);
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
flush();
|
|
1592
|
-
return out;
|
|
1593
|
-
}, [children, dim, highlight, theme]);
|
|
1594
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: elements });
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
// src/react-ink/utils/tool-display.ts
|
|
1598
|
-
import { homedir } from "node:os";
|
|
1599
|
-
|
|
1600
|
-
// src/react-ink/diff/structured.ts
|
|
1601
|
-
import { structuredPatch } from "diff";
|
|
1602
|
-
|
|
1603
|
-
// src/react-ink/diff/word-diff.ts
|
|
1604
|
-
import { diffWordsWithSpace } from "diff";
|
|
1605
|
-
var CHANGE_THRESHOLD = 0.4;
|
|
1606
|
-
function wordDiffLine(oldLine, newLine, side) {
|
|
1607
|
-
const lineText = side === "removed" ? oldLine : newLine;
|
|
1608
|
-
if (oldLine.length === 0 || newLine.length === 0) {
|
|
1609
|
-
return [{ text: lineText, changed: true }];
|
|
1610
|
-
}
|
|
1611
|
-
let changes;
|
|
1612
|
-
try {
|
|
1613
|
-
changes = diffWordsWithSpace(oldLine, newLine);
|
|
1614
|
-
} catch {
|
|
1615
|
-
return [{ text: lineText, changed: true }];
|
|
1616
|
-
}
|
|
1617
|
-
let changedChars = 0;
|
|
1618
|
-
let totalChars = 0;
|
|
1619
|
-
for (const change of changes) {
|
|
1620
|
-
totalChars += change.value.length;
|
|
1621
|
-
if (change.added || change.removed) {
|
|
1622
|
-
changedChars += change.value.length;
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
const fraction = totalChars === 0 ? 0 : changedChars / totalChars;
|
|
1626
|
-
if (fraction > CHANGE_THRESHOLD) {
|
|
1627
|
-
return [{ text: lineText, changed: true }];
|
|
1628
|
-
}
|
|
1629
|
-
const spans = [];
|
|
1630
|
-
for (const change of changes) {
|
|
1631
|
-
const belongs = side === "removed" ? !change.added : !change.removed;
|
|
1632
|
-
if (!belongs) {
|
|
1633
|
-
continue;
|
|
1634
|
-
}
|
|
1635
|
-
spans.push({ text: change.value, changed: Boolean(change.added || change.removed) });
|
|
1636
|
-
}
|
|
1637
|
-
return spans.length > 0 ? spans : [{ text: lineText, changed: false }];
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
// src/react-ink/diff/structured.ts
|
|
1641
|
-
var CONTEXT_LINES = 3;
|
|
1642
|
-
function buildStructuredDiff(oldStr, newStr, filePath = "") {
|
|
1643
|
-
if (oldStr === newStr) {
|
|
1644
|
-
return null;
|
|
1645
|
-
}
|
|
1646
|
-
let patch;
|
|
1647
|
-
try {
|
|
1648
|
-
patch = structuredPatch(filePath, filePath, oldStr, newStr, "", "", { context: CONTEXT_LINES });
|
|
1649
|
-
} catch {
|
|
1650
|
-
return null;
|
|
1651
|
-
}
|
|
1652
|
-
const hunks = [];
|
|
1653
|
-
let addedCount = 0;
|
|
1654
|
-
let removedCount = 0;
|
|
1655
|
-
for (const hunk of patch.hunks) {
|
|
1656
|
-
const lines = classifyHunkLines(hunk);
|
|
1657
|
-
for (const line of lines) {
|
|
1658
|
-
if (line.kind === "added") addedCount += 1;
|
|
1659
|
-
else if (line.kind === "removed") removedCount += 1;
|
|
1660
|
-
}
|
|
1661
|
-
if (lines.length > 0) {
|
|
1662
|
-
hunks.push({ oldStart: hunk.oldStart, newStart: hunk.newStart, lines });
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
if (hunks.length === 0) {
|
|
1666
|
-
return null;
|
|
1667
|
-
}
|
|
1668
|
-
return { hunks, addedCount, removedCount };
|
|
1669
|
-
}
|
|
1670
|
-
function classifyHunkLines(hunk) {
|
|
1671
|
-
const out = [];
|
|
1672
|
-
let oldNum = hunk.oldStart;
|
|
1673
|
-
let newNum = hunk.newStart;
|
|
1674
|
-
const rawLines = hunk.lines.filter((line) => !line.startsWith("\\"));
|
|
1675
|
-
let removedRun = [];
|
|
1676
|
-
let removedRunStart = -1;
|
|
1677
|
-
const flushPairing = (addedRun2) => {
|
|
1678
|
-
const pairs = Math.min(removedRun.length, addedRun2.length);
|
|
1679
|
-
for (let i = 0; i < pairs; i += 1) {
|
|
1680
|
-
const removed = removedRun[i];
|
|
1681
|
-
const added = addedRun2[i];
|
|
1682
|
-
removed.spans = wordDiffLine(removed.text, added.text, "removed");
|
|
1683
|
-
added.spans = wordDiffLine(removed.text, added.text, "added");
|
|
1684
|
-
}
|
|
1685
|
-
removedRun = [];
|
|
1686
|
-
removedRunStart = -1;
|
|
1687
|
-
};
|
|
1688
|
-
let addedRun = [];
|
|
1689
|
-
for (const raw of rawLines) {
|
|
1690
|
-
const marker = raw[0];
|
|
1691
|
-
const text = raw.slice(1);
|
|
1692
|
-
if (marker === "-") {
|
|
1693
|
-
if (addedRun.length > 0) {
|
|
1694
|
-
addedRun = [];
|
|
1695
|
-
}
|
|
1696
|
-
const line = { kind: "removed", oldLine: oldNum, text };
|
|
1697
|
-
out.push(line);
|
|
1698
|
-
if (removedRunStart === -1) removedRunStart = out.length - 1;
|
|
1699
|
-
removedRun.push(line);
|
|
1700
|
-
oldNum += 1;
|
|
1701
|
-
} else if (marker === "+") {
|
|
1702
|
-
const line = { kind: "added", newLine: newNum, text };
|
|
1703
|
-
out.push(line);
|
|
1704
|
-
addedRun.push(line);
|
|
1705
|
-
newNum += 1;
|
|
1706
|
-
} else {
|
|
1707
|
-
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
1708
|
-
flushPairing(addedRun);
|
|
1709
|
-
}
|
|
1710
|
-
removedRun = [];
|
|
1711
|
-
removedRunStart = -1;
|
|
1712
|
-
addedRun = [];
|
|
1713
|
-
out.push({ kind: "context", oldLine: oldNum, newLine: newNum, text });
|
|
1714
|
-
oldNum += 1;
|
|
1715
|
-
newNum += 1;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
if (removedRun.length > 0 && addedRun.length > 0) {
|
|
1719
|
-
flushPairing(addedRun);
|
|
1720
|
-
}
|
|
1721
|
-
return out;
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
// src/react-ink/utils/tool-display.ts
|
|
1725
|
-
function asRecord(value) {
|
|
1726
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1727
|
-
}
|
|
1728
|
-
function asString(value) {
|
|
1729
|
-
return typeof value === "string" ? value : void 0;
|
|
1730
|
-
}
|
|
1731
|
-
function asNumber(value) {
|
|
1732
|
-
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1733
|
-
}
|
|
1734
|
-
function hasOutput(value) {
|
|
1735
|
-
return value !== void 0;
|
|
1736
|
-
}
|
|
1737
|
-
function shortenPath2(path2) {
|
|
1738
|
-
const home = homedir();
|
|
1739
|
-
return path2.startsWith(home) ? `~${path2.slice(home.length)}` : path2;
|
|
1740
|
-
}
|
|
1741
|
-
function titleCase(value) {
|
|
1742
|
-
return value.split(/[\s_-]+/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
|
|
1743
|
-
}
|
|
1744
|
-
function friendlyToolName(toolName) {
|
|
1745
|
-
switch (toolName) {
|
|
1746
|
-
case "ls":
|
|
1747
|
-
return "LS";
|
|
1748
|
-
case "read":
|
|
1749
|
-
return "Read";
|
|
1750
|
-
case "write":
|
|
1751
|
-
return "Write";
|
|
1752
|
-
case "edit":
|
|
1753
|
-
return "Edit";
|
|
1754
|
-
case "find":
|
|
1755
|
-
return "Find";
|
|
1756
|
-
case "grep":
|
|
1757
|
-
return "Grep";
|
|
1758
|
-
case "bash":
|
|
1759
|
-
return "Bash";
|
|
1760
|
-
case "task":
|
|
1761
|
-
return "Task";
|
|
1762
|
-
case "todoread":
|
|
1763
|
-
return "Todo Read";
|
|
1764
|
-
case "todowrite":
|
|
1765
|
-
return "Todo Write";
|
|
1766
|
-
default:
|
|
1767
|
-
return titleCase(toolName.replace(/^composio__/, "composio "));
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
function summarizeCommand(command) {
|
|
1771
|
-
return command ? previewText(command.replace(/\s+/g, " "), 88) : void 0;
|
|
1772
|
-
}
|
|
1773
|
-
function toolText(value, showImages = false) {
|
|
1774
|
-
return extractToolText(value, showImages).trim();
|
|
1775
|
-
}
|
|
1776
|
-
function containsImage(value) {
|
|
1777
|
-
if (Array.isArray(value)) {
|
|
1778
|
-
return value.some((item) => containsImage(item));
|
|
1779
|
-
}
|
|
1780
|
-
const record = asRecord(value);
|
|
1781
|
-
if (!record) {
|
|
1782
|
-
return false;
|
|
1783
|
-
}
|
|
1784
|
-
if (record.type === "image") {
|
|
1785
|
-
return true;
|
|
1786
|
-
}
|
|
1787
|
-
return Object.values(record).some((item) => containsImage(item));
|
|
1788
|
-
}
|
|
1789
|
-
function countMeaningfulLines(value) {
|
|
1790
|
-
if (!value?.trim()) {
|
|
1791
|
-
return 0;
|
|
1792
|
-
}
|
|
1793
|
-
return value.split(/\r?\n/).filter((line) => line.trim().length > 0).length;
|
|
1794
|
-
}
|
|
1795
|
-
function firstMeaningfulLine(value) {
|
|
1796
|
-
if (!value?.trim()) {
|
|
1797
|
-
return void 0;
|
|
1798
|
-
}
|
|
1799
|
-
return value.split(/\r?\n/).map((line) => line.trim()).find(Boolean);
|
|
1800
|
-
}
|
|
1801
|
-
function clipBody(value, maxLines = 8, maxChars = 1400) {
|
|
1802
|
-
if (!value?.trim()) {
|
|
1803
|
-
return void 0;
|
|
1804
|
-
}
|
|
1805
|
-
return previewMultiline(value, { maxLines, maxChars });
|
|
1806
|
-
}
|
|
1807
|
-
function highlightedBody(body, filePath, theme) {
|
|
1808
|
-
if (!body || !theme || !filePath || languageFromPath(filePath) === null) {
|
|
1809
|
-
return { body };
|
|
1810
|
-
}
|
|
1811
|
-
return { body: highlightByPath(body, filePath, theme), preformatted: true };
|
|
1812
|
-
}
|
|
1813
|
-
function extractDetails(value) {
|
|
1814
|
-
return asRecord(asRecord(value)?.details);
|
|
1815
|
-
}
|
|
1816
|
-
function normalizeTodoStatus(value) {
|
|
1817
|
-
switch (value) {
|
|
1818
|
-
case "completed":
|
|
1819
|
-
case "in_progress":
|
|
1820
|
-
case "cancelled":
|
|
1821
|
-
case "pending":
|
|
1822
|
-
return value;
|
|
1823
|
-
default:
|
|
1824
|
-
return "pending";
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
function normalizeTodoPriority(value) {
|
|
1828
|
-
switch (value) {
|
|
1829
|
-
case "high":
|
|
1830
|
-
case "medium":
|
|
1831
|
-
case "low":
|
|
1832
|
-
return value;
|
|
1833
|
-
default:
|
|
1834
|
-
return "medium";
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
function extractTodos(args, output) {
|
|
1838
|
-
const detailTodos = extractDetails(output)?.todos;
|
|
1839
|
-
const argTodos = asRecord(args)?.todos;
|
|
1840
|
-
const source = Array.isArray(detailTodos) ? detailTodos : Array.isArray(argTodos) ? argTodos : [];
|
|
1841
|
-
return source.map((todo) => {
|
|
1842
|
-
const record = asRecord(todo);
|
|
1843
|
-
const content = asString(record?.content)?.trim();
|
|
1844
|
-
if (!content) return void 0;
|
|
1845
|
-
return {
|
|
1846
|
-
content,
|
|
1847
|
-
priority: normalizeTodoPriority(record?.priority),
|
|
1848
|
-
status: normalizeTodoStatus(record?.status)
|
|
1849
|
-
};
|
|
1850
|
-
}).filter((todo) => Boolean(todo));
|
|
1851
|
-
}
|
|
1852
|
-
function formatTodos(todos) {
|
|
1853
|
-
if (todos.length === 0) return void 0;
|
|
1854
|
-
const lines = todos.slice(0, 6).map((todo) => {
|
|
1855
|
-
const statusLabel = todo.status === "completed" ? "[done]" : todo.status === "in_progress" ? "[doing]" : todo.status === "cancelled" ? "[skip]" : "[todo]";
|
|
1856
|
-
return `${statusLabel} ${todo.priority} ${todo.content}`;
|
|
1857
|
-
});
|
|
1858
|
-
if (todos.length > lines.length) {
|
|
1859
|
-
lines.push(`... ${todos.length - lines.length} more item(s)`);
|
|
1860
|
-
}
|
|
1861
|
-
return lines.join("\n");
|
|
1862
|
-
}
|
|
1863
|
-
function fallbackSummary(args, fallbackArgsText) {
|
|
1864
|
-
if (fallbackArgsText?.trim()) {
|
|
1865
|
-
return previewText(fallbackArgsText, 88);
|
|
1866
|
-
}
|
|
1867
|
-
const record = asRecord(args);
|
|
1868
|
-
if (!record) return void 0;
|
|
1869
|
-
return previewText(safeStringify(record), 88);
|
|
1870
|
-
}
|
|
1871
|
-
function fallbackBody(output, fallbackOutputText, showImages = false) {
|
|
1872
|
-
const extracted = toolText(output, showImages);
|
|
1873
|
-
if (extracted) {
|
|
1874
|
-
return clipBody(extracted);
|
|
1875
|
-
}
|
|
1876
|
-
return clipBody(fallbackOutputText);
|
|
1877
|
-
}
|
|
1878
|
-
function describeToolSource(source) {
|
|
1879
|
-
const { args, fallbackArgsText, fallbackOutputText, output, showImages = false, theme, toolName } = source;
|
|
1880
|
-
const argsRecord = asRecord(args);
|
|
1881
|
-
const details = extractDetails(output);
|
|
1882
|
-
const outputText = toolText(output, showImages);
|
|
1883
|
-
const hasResult = hasOutput(output);
|
|
1884
|
-
const title = friendlyToolName(toolName);
|
|
1885
|
-
switch (toolName) {
|
|
1886
|
-
case "read": {
|
|
1887
|
-
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
1888
|
-
const offset = asNumber(argsRecord?.offset);
|
|
1889
|
-
const limit = asNumber(argsRecord?.limit);
|
|
1890
|
-
let summary = rawPath ? shortenPath2(rawPath) : void 0;
|
|
1891
|
-
if (summary && (offset !== void 0 || limit !== void 0)) {
|
|
1892
|
-
const start = offset ?? 1;
|
|
1893
|
-
const end = limit !== void 0 ? start + limit - 1 : void 0;
|
|
1894
|
-
summary += `:${start}${end ? `-${end}` : ""}`;
|
|
1895
|
-
}
|
|
1896
|
-
const responseSummary = containsImage(output) ? firstMeaningfulLine(outputText) ?? "Read image" : /unchanged/i.test(outputText) ? "Unchanged since last read" : countMeaningfulLines(outputText) > 0 ? `Read ${countMeaningfulLines(outputText)} ${countMeaningfulLines(outputText) === 1 ? "line" : "lines"}` : "Read file";
|
|
1897
|
-
const readBody = hasResult && !containsImage(output) ? highlightedBody(clipBody(outputText, 10, 1800), rawPath, theme) : { body: hasResult ? clipBody(outputText, 10, 1800) : void 0 };
|
|
1898
|
-
return {
|
|
1899
|
-
title,
|
|
1900
|
-
summary: hasResult ? responseSummary : summary,
|
|
1901
|
-
body: readBody.body,
|
|
1902
|
-
preformatted: readBody.preformatted,
|
|
1903
|
-
emptyText: "Reading file..."
|
|
1904
|
-
};
|
|
1905
|
-
}
|
|
1906
|
-
case "write": {
|
|
1907
|
-
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
1908
|
-
const content = asString(argsRecord?.content);
|
|
1909
|
-
const responseSummary = firstMeaningfulLine(outputText) ?? "Wrote file";
|
|
1910
|
-
const writeDiff = !hasResult && content !== void 0 && content.length > 0 ? buildStructuredDiff("", content, rawPath) ?? void 0 : void 0;
|
|
1911
|
-
const writeBody = hasResult ? { body: clipBody(outputText, 8, 1500) } : highlightedBody(clipBody(content, 8, 1500), rawPath, theme);
|
|
1912
|
-
return {
|
|
1913
|
-
title,
|
|
1914
|
-
summary: hasResult ? responseSummary : rawPath ? shortenPath2(rawPath) : void 0,
|
|
1915
|
-
body: writeDiff ? void 0 : writeBody.body,
|
|
1916
|
-
preformatted: writeDiff ? void 0 : writeBody.preformatted,
|
|
1917
|
-
diff: writeDiff,
|
|
1918
|
-
emptyText: "Preparing file write..."
|
|
1919
|
-
};
|
|
1920
|
-
}
|
|
1921
|
-
case "edit": {
|
|
1922
|
-
const rawPath = asString(argsRecord?.file_path) ?? asString(argsRecord?.path) ?? "";
|
|
1923
|
-
const oldText = asString(argsRecord?.oldText);
|
|
1924
|
-
const newText = asString(argsRecord?.newText);
|
|
1925
|
-
const replacementPreview = oldText || newText ? clipBody(
|
|
1926
|
-
[
|
|
1927
|
-
oldText ? `- ${previewText(oldText, 90)}` : void 0,
|
|
1928
|
-
newText ? `+ ${previewText(newText, 90)}` : void 0
|
|
1929
|
-
].filter(Boolean).join("\n"),
|
|
1930
|
-
4,
|
|
1931
|
-
400
|
|
1932
|
-
) : void 0;
|
|
1933
|
-
const responseSummary = firstMeaningfulLine(outputText) ?? "Applied edit";
|
|
1934
|
-
const editDiff = oldText !== void 0 && newText !== void 0 ? buildStructuredDiff(oldText, newText, rawPath) ?? void 0 : void 0;
|
|
1935
|
-
const editBody = hasResult ? highlightedBody(clipBody(outputText, 8, 1500), rawPath, theme) : { body: replacementPreview };
|
|
1936
|
-
const editChangeSummary = editDiff ? `+${editDiff.addedCount} -${editDiff.removedCount}` : void 0;
|
|
1937
|
-
return {
|
|
1938
|
-
title,
|
|
1939
|
-
summary: hasResult ? editChangeSummary ?? responseSummary : editChangeSummary ?? (rawPath ? shortenPath2(rawPath) : void 0),
|
|
1940
|
-
body: editDiff ? void 0 : editBody.body,
|
|
1941
|
-
preformatted: editDiff ? void 0 : editBody.preformatted,
|
|
1942
|
-
diff: editDiff,
|
|
1943
|
-
emptyText: "Applying edit..."
|
|
1944
|
-
};
|
|
1945
|
-
}
|
|
1946
|
-
case "ls": {
|
|
1947
|
-
const rawPath = asString(argsRecord?.path) ?? ".";
|
|
1948
|
-
const entryCount = countMeaningfulLines(outputText);
|
|
1949
|
-
return {
|
|
1950
|
-
title,
|
|
1951
|
-
summary: hasResult ? `Listed ${entryCount} ${entryCount === 1 ? "entry" : "entries"}` : shortenPath2(rawPath),
|
|
1952
|
-
body: hasResult ? clipBody(outputText, 10, 1400) : void 0,
|
|
1953
|
-
emptyText: "Listing files..."
|
|
1954
|
-
};
|
|
1955
|
-
}
|
|
1956
|
-
case "find": {
|
|
1957
|
-
const pattern = asString(argsRecord?.pattern);
|
|
1958
|
-
const rawPath = asString(argsRecord?.path) ?? ".";
|
|
1959
|
-
const matchCount = countMeaningfulLines(outputText);
|
|
1960
|
-
return {
|
|
1961
|
-
title,
|
|
1962
|
-
summary: hasResult ? `Found ${matchCount} ${matchCount === 1 ? "path" : "paths"}` : pattern ? `${pattern} in ${shortenPath2(rawPath)}` : shortenPath2(rawPath),
|
|
1963
|
-
body: hasResult ? clipBody(outputText, 10, 1400) : void 0,
|
|
1964
|
-
emptyText: "Searching files..."
|
|
1965
|
-
};
|
|
1966
|
-
}
|
|
1967
|
-
case "grep": {
|
|
1968
|
-
const pattern = asString(argsRecord?.pattern);
|
|
1969
|
-
const rawPath = asString(argsRecord?.path) ?? ".";
|
|
1970
|
-
const responseSummary = /no matches found/i.test(outputText) ? "Found 0 matches" : firstMeaningfulLine(outputText) ? "Search results" : "Search complete";
|
|
1971
|
-
return {
|
|
1972
|
-
title,
|
|
1973
|
-
summary: hasResult ? responseSummary : pattern ? `/${pattern}/ in ${shortenPath2(rawPath)}` : shortenPath2(rawPath),
|
|
1974
|
-
body: hasResult ? clipBody(outputText, 10, 1400) : void 0,
|
|
1975
|
-
emptyText: "Searching text..."
|
|
1976
|
-
};
|
|
1977
|
-
}
|
|
1978
|
-
case "bash": {
|
|
1979
|
-
const command = summarizeCommand(asString(argsRecord?.command));
|
|
1980
|
-
const firstLine = firstMeaningfulLine(outputText);
|
|
1981
|
-
const responseSummary = firstLine ? previewText(firstLine, 88) : "Command finished";
|
|
1982
|
-
return {
|
|
1983
|
-
title,
|
|
1984
|
-
summary: hasResult ? responseSummary : command,
|
|
1985
|
-
body: clipBody(outputText, 8, 1800),
|
|
1986
|
-
emptyText: "Running shell command..."
|
|
1987
|
-
};
|
|
1988
|
-
}
|
|
1989
|
-
case "task": {
|
|
1990
|
-
const subagentType = asString(details?.subagentType) ?? asString(argsRecord?.subagent_type) ?? "subagent";
|
|
1991
|
-
const description = asString(details?.description) ?? asString(argsRecord?.description);
|
|
1992
|
-
const responseSummary = firstMeaningfulLine(outputText || asString(details?.result)) ?? "Task finished";
|
|
1993
|
-
return {
|
|
1994
|
-
title,
|
|
1995
|
-
summary: hasResult ? responseSummary : [subagentType, description].filter(Boolean).join(" - "),
|
|
1996
|
-
body: hasResult ? clipBody(outputText || asString(details?.result), 8, 1400) : void 0,
|
|
1997
|
-
emptyText: "Delegating to subagent..."
|
|
1998
|
-
};
|
|
1999
|
-
}
|
|
2000
|
-
case "todoread":
|
|
2001
|
-
case "todowrite": {
|
|
2002
|
-
const todos = extractTodos(args, output);
|
|
2003
|
-
const incompleteCount = asNumber(details?.incompleteCount) ?? todos.filter((todo) => todo.status !== "completed").length;
|
|
2004
|
-
const summary = todos.length > 0 ? `${todos.length} item(s) | ${incompleteCount} open` : fallbackSummary(args, fallbackArgsText);
|
|
2005
|
-
return {
|
|
2006
|
-
title,
|
|
2007
|
-
summary: summary ?? (toolName === "todoread" ? "Read todo list" : "Updated todo list"),
|
|
2008
|
-
body: hasResult ? formatTodos(todos) ?? fallbackBody(output, fallbackOutputText, showImages) : void 0,
|
|
2009
|
-
emptyText: toolName === "todoread" ? "Reading todo list..." : "Updating todo list..."
|
|
2010
|
-
};
|
|
2011
|
-
}
|
|
2012
|
-
default:
|
|
2013
|
-
return {
|
|
2014
|
-
title,
|
|
2015
|
-
summary: hasResult ? firstMeaningfulLine(outputText) ?? "Completed" : fallbackSummary(args, fallbackArgsText),
|
|
2016
|
-
body: fallbackBody(output, fallbackOutputText, showImages),
|
|
2017
|
-
emptyText: "Working..."
|
|
2018
|
-
};
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
function describeToolExecution(tool) {
|
|
2022
|
-
const callDescriptor = describeToolSource({
|
|
2023
|
-
toolName: tool.toolName,
|
|
2024
|
-
args: tool.args,
|
|
2025
|
-
fallbackArgsText: tool.argsText
|
|
2026
|
-
});
|
|
2027
|
-
return {
|
|
2028
|
-
...callDescriptor,
|
|
2029
|
-
body: clipBody(tool.outputText, 8, 1800),
|
|
2030
|
-
emptyText: tool.status === "running" ? callDescriptor.emptyText : tool.status === "error" ? "Tool failed." : "Tool finished."
|
|
2031
|
-
};
|
|
2032
|
-
}
|
|
2033
|
-
function describeToolCall(toolCall) {
|
|
2034
|
-
return describeToolSource({
|
|
2035
|
-
toolName: toolCall.name,
|
|
2036
|
-
args: toolCall.arguments
|
|
2037
|
-
});
|
|
2038
|
-
}
|
|
2039
|
-
function describeToolResult(message, showImages, args, theme) {
|
|
2040
|
-
return describeToolSource({
|
|
2041
|
-
args,
|
|
2042
|
-
toolName: message.toolName,
|
|
2043
|
-
output: {
|
|
2044
|
-
content: message.content,
|
|
2045
|
-
details: message.details
|
|
2046
|
-
},
|
|
2047
|
-
showImages,
|
|
2048
|
-
theme
|
|
2049
|
-
});
|
|
2050
|
-
}
|
|
2051
|
-
|
|
2052
|
-
// src/react-ink/components/ToolEventBlock.tsx
|
|
2053
|
-
import stripAnsi5 from "strip-ansi";
|
|
2054
|
-
var STATUS_DOT = "\u25CF";
|
|
2055
|
-
var COLLAPSED_CONTENT_LINES = 2;
|
|
2056
|
-
var EXPANDED_CONTENT_LINES = 20;
|
|
2057
|
-
function contentConnector(isFirst) {
|
|
2058
|
-
return isFirst ? "\u2514 " : " ";
|
|
2059
|
-
}
|
|
2060
|
-
function statusColorKey(status) {
|
|
2061
|
-
switch (status) {
|
|
2062
|
-
case "error":
|
|
2063
|
-
return "error";
|
|
2064
|
-
case "success":
|
|
2065
|
-
return "success";
|
|
2066
|
-
default:
|
|
2067
|
-
return "accent";
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
function plainToolText(text) {
|
|
2071
|
-
return stripAnsi5(text);
|
|
2072
|
-
}
|
|
2073
|
-
function splitVisibleLines(text) {
|
|
2074
|
-
return (text ?? "").split(/\r?\n/).map((line) => line.trimEnd()).filter((line, index, lines) => {
|
|
2075
|
-
if (stripAnsi5(line).length > 0) {
|
|
2076
|
-
return true;
|
|
2077
|
-
}
|
|
2078
|
-
return index !== 0 && index !== lines.length - 1;
|
|
2079
|
-
});
|
|
2080
|
-
}
|
|
2081
|
-
function clampContentLines(lines, maxContentLines) {
|
|
2082
|
-
if (maxContentLines <= 0) {
|
|
2083
|
-
return {
|
|
2084
|
-
visibleLines: [],
|
|
2085
|
-
hiddenLineCount: lines.length
|
|
2086
|
-
};
|
|
2087
|
-
}
|
|
2088
|
-
if (lines.length <= maxContentLines) {
|
|
2089
|
-
return {
|
|
2090
|
-
visibleLines: lines,
|
|
2091
|
-
hiddenLineCount: 0
|
|
2092
|
-
};
|
|
2093
|
-
}
|
|
2094
|
-
const visibleLimit = Math.max(0, maxContentLines - 1);
|
|
2095
|
-
return {
|
|
2096
|
-
visibleLines: lines.slice(0, visibleLimit),
|
|
2097
|
-
hiddenLineCount: lines.length - visibleLimit
|
|
2098
|
-
};
|
|
2099
|
-
}
|
|
2100
|
-
function ToolEventBlock({
|
|
2101
|
-
detail,
|
|
2102
|
-
emptyText,
|
|
2103
|
-
indent = 0,
|
|
2104
|
-
marginBottom = 1,
|
|
2105
|
-
maxContentLines = COLLAPSED_CONTENT_LINES,
|
|
2106
|
-
moreHint,
|
|
2107
|
-
preformatted = false,
|
|
2108
|
-
showSummaryInline = false,
|
|
2109
|
-
showTitle = true,
|
|
2110
|
-
status,
|
|
2111
|
-
summary,
|
|
2112
|
-
theme,
|
|
2113
|
-
title
|
|
2114
|
-
}) {
|
|
2115
|
-
const normalizedSummary = summary?.trim();
|
|
2116
|
-
const normalizedDetail = detail?.trim();
|
|
2117
|
-
const responseText = showSummaryInline ? void 0 : normalizedSummary ?? emptyText?.trim();
|
|
2118
|
-
const detailText = showSummaryInline ? normalizedDetail ?? emptyText?.trim() : normalizedDetail;
|
|
2119
|
-
const responseLines = splitVisibleLines(responseText);
|
|
2120
|
-
const detailLines = splitVisibleLines(detailText).filter((line) => !responseLines.includes(line));
|
|
2121
|
-
const combinedLines = [
|
|
2122
|
-
...responseLines.map((text) => ({ kind: "response", text })),
|
|
2123
|
-
...detailLines.map((text) => ({ kind: "detail", text }))
|
|
2124
|
-
];
|
|
2125
|
-
const { visibleLines, hiddenLineCount } = clampContentLines(combinedLines, maxContentLines);
|
|
2126
|
-
const contentIndent = showTitle ? 2 : 0;
|
|
2127
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom, marginLeft: indent, children: [
|
|
2128
|
-
showTitle ? /* @__PURE__ */ jsxs(Box, { children: [
|
|
2129
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color(statusColorKey(status), `${STATUS_DOT} `) }),
|
|
2130
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: theme.color("text", plainToolText(title)) }),
|
|
2131
|
-
showSummaryInline && normalizedSummary ? /* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(` (${normalizedSummary})`)) }) : null
|
|
2132
|
-
] }) : null,
|
|
2133
|
-
visibleLines.map((line, index) => /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
|
|
2134
|
-
/* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(index === 0)) }),
|
|
2135
|
-
preformatted ? /* @__PURE__ */ jsx(Text, { children: line.text }) : /* @__PURE__ */ jsx(Text, { children: theme.color("text", plainToolText(line.text)) })
|
|
2136
|
-
] }, `${line.kind}:${index}:${stripAnsi5(line.text)}`)),
|
|
2137
|
-
hiddenLineCount > 0 ? /* @__PURE__ */ jsxs(Box, { marginLeft: contentIndent, children: [
|
|
2138
|
-
/* @__PURE__ */ jsx(Text, { children: theme.dim(contentConnector(visibleLines.length === 0)) }),
|
|
2139
|
-
/* @__PURE__ */ jsx(Text, { children: theme.muted(plainToolText(`\u2026 ${hiddenLineCount} more line(s)`)) }),
|
|
2140
|
-
moreHint ? /* @__PURE__ */ jsx(Text, { children: theme.dim(plainToolText(` \xB7 ${moreHint}`)) }) : null
|
|
2141
|
-
] }) : null
|
|
2142
|
-
] });
|
|
2143
|
-
}
|
|
2144
|
-
|
|
2145
|
-
// src/react-ink/components/messages/ToolCallMessage.tsx
|
|
2146
|
-
function ToolCallMessage({ theme, toolCall }) {
|
|
2147
|
-
const descriptor = describeToolCall(toolCall);
|
|
2148
|
-
return /* @__PURE__ */ jsx(
|
|
2149
|
-
ToolEventBlock,
|
|
2150
|
-
{
|
|
2151
|
-
detail: void 0,
|
|
2152
|
-
emptyText: void 0,
|
|
2153
|
-
indent: 2,
|
|
2154
|
-
marginBottom: 0,
|
|
2155
|
-
showSummaryInline: true,
|
|
2156
|
-
status: "running",
|
|
2157
|
-
summary: descriptor.summary,
|
|
2158
|
-
theme,
|
|
2159
|
-
title: descriptor.title
|
|
2160
|
-
}
|
|
2161
|
-
);
|
|
2162
|
-
}
|
|
2163
|
-
|
|
2164
|
-
// src/react-ink/diff/Diff.tsx
|
|
2165
|
-
import chalk4 from "chalk";
|
|
2166
|
-
function lineMarker(kind) {
|
|
2167
|
-
switch (kind) {
|
|
2168
|
-
case "added":
|
|
2169
|
-
return "+";
|
|
2170
|
-
case "removed":
|
|
2171
|
-
return "-";
|
|
2172
|
-
default:
|
|
2173
|
-
return " ";
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
function gutterWidth(diff) {
|
|
2177
|
-
let max = 1;
|
|
2178
|
-
for (const hunk of diff.hunks) {
|
|
2179
|
-
for (const line of hunk.lines) {
|
|
2180
|
-
const num = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
2181
|
-
if (num !== void 0) {
|
|
2182
|
-
max = Math.max(max, stringWidth(String(num)));
|
|
2183
|
-
}
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
return max;
|
|
2187
|
-
}
|
|
2188
|
-
function renderLineText(line, theme, bgRole, fgRole) {
|
|
2189
|
-
const paintSpan = (text, changed) => {
|
|
2190
|
-
const fg = theme.role(fgRole, text);
|
|
2191
|
-
return changed ? chalk4.bold(fg) : fg;
|
|
2192
|
-
};
|
|
2193
|
-
let body;
|
|
2194
|
-
if (line.spans && line.spans.length > 0) {
|
|
2195
|
-
body = line.spans.map((span) => paintSpan(span.text, span.changed)).join("");
|
|
2196
|
-
} else {
|
|
2197
|
-
body = theme.role(fgRole, line.text);
|
|
2198
|
-
}
|
|
2199
|
-
return bgRole ? theme.roleBackground(bgRole, body) : body;
|
|
2200
|
-
}
|
|
2201
|
-
function Diff({ diff, theme, indent = 0, marginBottom = 0 }) {
|
|
2202
|
-
const gutter = gutterWidth(diff);
|
|
2203
|
-
const renderLine = (line, key) => {
|
|
2204
|
-
const num = line.kind === "removed" ? line.oldLine : line.newLine;
|
|
2205
|
-
const gutterText = (num !== void 0 ? String(num) : "").padStart(gutter);
|
|
2206
|
-
const marker = lineMarker(line.kind);
|
|
2207
|
-
const bgRole = line.kind === "added" ? "diffAddedBg" : line.kind === "removed" ? "diffRemovedBg" : null;
|
|
2208
|
-
const fgRole = line.kind === "added" ? "diffAddedText" : line.kind === "removed" ? "diffRemovedText" : "blockquoteBar";
|
|
2209
|
-
const gutterStyled = theme.dim(`${gutterText} `);
|
|
2210
|
-
const markerStyled = line.kind === "context" ? theme.dim(`${marker} `) : theme.role(fgRole, `${marker} `);
|
|
2211
|
-
const text = renderLineText(line, theme, bgRole, fgRole);
|
|
2212
|
-
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
2213
|
-
gutterStyled,
|
|
2214
|
-
markerStyled,
|
|
2215
|
-
text
|
|
2216
|
-
] }) }, key);
|
|
2217
|
-
};
|
|
2218
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginLeft: indent, marginBottom, children: diff.hunks.map((hunk, hunkIndex) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2219
|
-
hunkIndex > 0 ? /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: theme.dim("...") }) }) : null,
|
|
2220
|
-
hunk.lines.map((line, lineIndex) => renderLine(line, `${hunkIndex}-${lineIndex}`))
|
|
2221
|
-
] }, `hunk-${hunkIndex}`)) });
|
|
2222
|
-
}
|
|
2223
|
-
|
|
2224
|
-
// src/react-ink/components/messages/ToolResultBlock.tsx
|
|
2225
|
-
function ToolResultBlock({ expanded = false, message, nested = false, showImages, theme, toolCall }) {
|
|
2226
|
-
const descriptor = describeToolResult(message, showImages, toolCall?.arguments, theme);
|
|
2227
|
-
const indent = nested ? 4 : 2;
|
|
2228
|
-
if (descriptor.diff) {
|
|
2229
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 0, children: [
|
|
2230
|
-
/* @__PURE__ */ jsx(
|
|
2231
|
-
ToolEventBlock,
|
|
2232
|
-
{
|
|
2233
|
-
detail: void 0,
|
|
2234
|
-
emptyText: descriptor.emptyText,
|
|
2235
|
-
indent,
|
|
2236
|
-
marginBottom: 0,
|
|
2237
|
-
maxContentLines: 1,
|
|
2238
|
-
showSummaryInline: false,
|
|
2239
|
-
showTitle: !nested,
|
|
2240
|
-
status: message.isError ? "error" : "success",
|
|
2241
|
-
summary: descriptor.summary,
|
|
2242
|
-
theme,
|
|
2243
|
-
title: descriptor.title
|
|
2244
|
-
}
|
|
2245
|
-
),
|
|
2246
|
-
/* @__PURE__ */ jsx(Diff, { diff: descriptor.diff, theme, indent: indent + 2 })
|
|
2247
|
-
] });
|
|
2248
|
-
}
|
|
2249
|
-
return /* @__PURE__ */ jsx(
|
|
2250
|
-
ToolEventBlock,
|
|
2251
|
-
{
|
|
2252
|
-
detail: descriptor.body,
|
|
2253
|
-
emptyText: descriptor.emptyText,
|
|
2254
|
-
indent,
|
|
2255
|
-
marginBottom: 0,
|
|
2256
|
-
maxContentLines: expanded ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
|
|
2257
|
-
moreHint: expanded ? "ctrl+o to collapse" : "ctrl+o to expand",
|
|
2258
|
-
preformatted: descriptor.preformatted,
|
|
2259
|
-
showSummaryInline: false,
|
|
2260
|
-
showTitle: !nested,
|
|
2261
|
-
status: message.isError ? "error" : "success",
|
|
2262
|
-
summary: descriptor.summary,
|
|
2263
|
-
theme,
|
|
2264
|
-
title: descriptor.title
|
|
2265
|
-
}
|
|
2266
|
-
);
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
// src/react-ink/components/messages/AssistantMessage.tsx
|
|
2270
|
-
function AssistantMessageView({
|
|
2271
|
-
expandToolOutputs = false,
|
|
2272
|
-
message,
|
|
2273
|
-
showImages,
|
|
2274
|
-
showThinking,
|
|
2275
|
-
theme,
|
|
2276
|
-
toolResults = []
|
|
2277
|
-
}) {
|
|
2278
|
-
const parts = splitAssistantMessage(message, showThinking);
|
|
2279
|
-
const toolResultsByCallId = new Map(toolResults.map((toolResult) => [toolResult.toolCallId, toolResult]));
|
|
2280
|
-
const matchedToolResultIds = /* @__PURE__ */ new Set();
|
|
2281
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2282
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Assistant ${message.provider}/${message.model} ${formatMessageTimestamp(message.timestamp)}`) }),
|
|
2283
|
-
parts.text ? /* @__PURE__ */ jsx(Markdown, { theme, children: parts.text }) : null,
|
|
2284
|
-
parts.thinking.map((thinking, index) => /* @__PURE__ */ jsx(Text, { children: theme.muted(`[thinking] ${thinking}`) }, index)),
|
|
2285
|
-
parts.toolCalls.map((toolCall) => {
|
|
2286
|
-
const toolResult = toolResultsByCallId.get(toolCall.id);
|
|
2287
|
-
if (toolResult) {
|
|
2288
|
-
matchedToolResultIds.add(toolResult.toolCallId);
|
|
2289
|
-
}
|
|
2290
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2291
|
-
/* @__PURE__ */ jsx(ToolCallMessage, { toolCall, theme }),
|
|
2292
|
-
toolResult ? /* @__PURE__ */ jsx(
|
|
2293
|
-
ToolResultBlock,
|
|
2294
|
-
{
|
|
2295
|
-
expanded: expandToolOutputs,
|
|
2296
|
-
message: toolResult,
|
|
2297
|
-
nested: true,
|
|
2298
|
-
showImages,
|
|
2299
|
-
theme,
|
|
2300
|
-
toolCall
|
|
2301
|
-
}
|
|
2302
|
-
) : null
|
|
2303
|
-
] }, toolCall.id);
|
|
2304
|
-
}),
|
|
2305
|
-
toolResults.filter((toolResult) => !matchedToolResultIds.has(toolResult.toolCallId)).map((toolResult) => /* @__PURE__ */ jsx(
|
|
2306
|
-
ToolResultBlock,
|
|
2307
|
-
{
|
|
2308
|
-
expanded: expandToolOutputs,
|
|
2309
|
-
message: toolResult,
|
|
2310
|
-
nested: true,
|
|
2311
|
-
showImages,
|
|
2312
|
-
theme
|
|
2313
|
-
},
|
|
2314
|
-
toolResult.toolCallId
|
|
2315
|
-
)),
|
|
2316
|
-
message.stopReason === "error" && message.errorMessage ? /* @__PURE__ */ jsx(Text, { children: theme.color("error", message.errorMessage) }) : null
|
|
2317
|
-
] });
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
// src/react-ink/components/messages/BashMessage.tsx
|
|
2321
|
-
function BashMessageView({ message, theme }) {
|
|
2322
|
-
const status = message.cancelled ? "cancelled" : message.exitCode === void 0 ? "running" : `exit ${message.exitCode}`;
|
|
2323
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2324
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("bashBorder", `Bash ${status} ${message.command}`) }),
|
|
2325
|
-
message.output ? /* @__PURE__ */ jsx(Text, { children: message.output }) : /* @__PURE__ */ jsx(Text, { children: theme.muted("(no output)") })
|
|
2326
|
-
] });
|
|
2327
|
-
}
|
|
2328
|
-
|
|
2329
|
-
// src/react-ink/components/messages/BranchSummaryMessage.tsx
|
|
2330
|
-
function BranchSummaryMessageView({ message, theme }) {
|
|
2331
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2332
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("warning", "Branch Summary") }),
|
|
2333
|
-
/* @__PURE__ */ jsx(Text, { children: message.summary })
|
|
2334
|
-
] });
|
|
2335
|
-
}
|
|
2336
|
-
|
|
2337
|
-
// src/react-ink/components/messages/CompactionMessage.tsx
|
|
2338
|
-
function CompactionMessageView({ message, theme }) {
|
|
2339
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2340
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("success", `Compaction Summary ${message.tokensBefore} tokens before`) }),
|
|
2341
|
-
/* @__PURE__ */ jsx(Text, { children: message.summary })
|
|
2342
|
-
] });
|
|
2343
|
-
}
|
|
2344
|
-
|
|
2345
|
-
// src/react-ink/components/messages/CustomMessage.tsx
|
|
2346
|
-
function CustomMessageView({ message, showImages, theme }) {
|
|
2347
|
-
if (!message.display) return null;
|
|
2348
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2349
|
-
/* @__PURE__ */ jsx(Text, { children: theme.background("customMessage", ` ${message.customType} `, "customMessageText") }),
|
|
2350
|
-
/* @__PURE__ */ jsx(Text, { children: formatCustomContent(message.content, showImages) })
|
|
2351
|
-
] });
|
|
2352
|
-
}
|
|
2353
|
-
|
|
2354
|
-
// src/react-ink/components/messages/SkillInvocationMessage.tsx
|
|
2355
|
-
function SkillInvocationMessage({ content, theme }) {
|
|
2356
|
-
const parsed = parseSkillInvocation(content);
|
|
2357
|
-
if (!parsed) return null;
|
|
2358
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2359
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Skill ${parsed.name}`) }),
|
|
2360
|
-
/* @__PURE__ */ jsx(Text, { children: parsed.location }),
|
|
2361
|
-
parsed.userMessage ? /* @__PURE__ */ jsx(Text, { children: parsed.userMessage }) : null
|
|
2362
|
-
] });
|
|
2363
|
-
}
|
|
2364
|
-
|
|
2365
|
-
// src/react-ink/components/messages/UserMessage.tsx
|
|
2366
|
-
function UserMessageView({ message, showImages, theme }) {
|
|
2367
|
-
const content = formatUserContent(message.content, showImages);
|
|
2368
|
-
const lines = content.length > 0 ? content.split("\n") : [""];
|
|
2369
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
2370
|
-
/* @__PURE__ */ jsx(Text, { children: theme.background("userMessage", `You ${formatMessageTimestamp(message.timestamp)}`, "userMessageText") }),
|
|
2371
|
-
lines.map((line, index) => /* @__PURE__ */ jsx(Text, { children: theme.background("userMessage", line.length > 0 ? line : " ", "userMessageText") }, `user-message:${message.timestamp}:${index}`))
|
|
2372
|
-
] });
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
|
-
// src/react-ink/components/MessageRow.tsx
|
|
2376
|
-
function MessageRow({
|
|
2377
|
-
message,
|
|
2378
|
-
expandToolOutputs = false,
|
|
2379
|
-
showImages,
|
|
2380
|
-
showThinking,
|
|
2381
|
-
theme,
|
|
2382
|
-
toolResults = []
|
|
2383
|
-
}) {
|
|
2384
|
-
switch (message.role) {
|
|
2385
|
-
case "user": {
|
|
2386
|
-
const content = typeof message.content === "string" ? message.content : formatUserContent(message.content, showImages);
|
|
2387
|
-
const skill = typeof content === "string" ? parseSkillInvocation(content) : null;
|
|
2388
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2389
|
-
skill ? /* @__PURE__ */ jsx(SkillInvocationMessage, { content, theme }) : null,
|
|
2390
|
-
/* @__PURE__ */ jsx(UserMessageView, { message, showImages, theme })
|
|
2391
|
-
] });
|
|
2392
|
-
}
|
|
2393
|
-
case "assistant":
|
|
2394
|
-
return /* @__PURE__ */ jsx(
|
|
2395
|
-
AssistantMessageView,
|
|
2396
|
-
{
|
|
2397
|
-
expandToolOutputs,
|
|
2398
|
-
message,
|
|
2399
|
-
showImages,
|
|
2400
|
-
showThinking,
|
|
2401
|
-
theme,
|
|
2402
|
-
toolResults
|
|
2403
|
-
}
|
|
2404
|
-
);
|
|
2405
|
-
case "toolResult":
|
|
2406
|
-
return /* @__PURE__ */ jsx(ToolResultBlock, { expanded: expandToolOutputs, message, showImages, theme });
|
|
2407
|
-
case "bashExecution":
|
|
2408
|
-
return /* @__PURE__ */ jsx(BashMessageView, { message, theme });
|
|
2409
|
-
case "branchSummary":
|
|
2410
|
-
return /* @__PURE__ */ jsx(BranchSummaryMessageView, { message, theme });
|
|
2411
|
-
case "compactionSummary":
|
|
2412
|
-
return /* @__PURE__ */ jsx(CompactionMessageView, { message, theme });
|
|
2413
|
-
case "custom":
|
|
2414
|
-
return /* @__PURE__ */ jsx(CustomMessageView, { message, showImages, theme });
|
|
2415
|
-
default:
|
|
2416
|
-
return /* @__PURE__ */ jsx(Text, { children: String(message.role ?? "message") });
|
|
2417
|
-
}
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
|
-
// src/react-ink/components/MessageList.tsx
|
|
2421
|
-
function hasToolCalls(message) {
|
|
2422
|
-
return message.role === "assistant" && message.content.some((part) => part.type === "toolCall");
|
|
2423
|
-
}
|
|
2424
|
-
function groupMessages(messages) {
|
|
2425
|
-
const entries = [];
|
|
2426
|
-
for (let index = 0; index < messages.length; index++) {
|
|
2427
|
-
const message = messages[index];
|
|
2428
|
-
if (hasToolCalls(message)) {
|
|
2429
|
-
const toolResults = [];
|
|
2430
|
-
let nextIndex = index + 1;
|
|
2431
|
-
while (nextIndex < messages.length && messages[nextIndex]?.role === "toolResult") {
|
|
2432
|
-
toolResults.push(messages[nextIndex]);
|
|
2433
|
-
nextIndex += 1;
|
|
2434
|
-
}
|
|
2435
|
-
entries.push({ type: "message", message, toolResults });
|
|
2436
|
-
index = nextIndex - 1;
|
|
2437
|
-
continue;
|
|
2438
|
-
}
|
|
2439
|
-
if (message.role === "toolResult") {
|
|
2440
|
-
entries.push({ type: "message", message, toolResults: [message] });
|
|
2441
|
-
continue;
|
|
2442
|
-
}
|
|
2443
|
-
entries.push({ type: "message", message, toolResults: [] });
|
|
2444
|
-
}
|
|
2445
|
-
return entries;
|
|
2446
|
-
}
|
|
2447
|
-
function getEntryTimestamp(entry) {
|
|
2448
|
-
return entry.type === "message" ? entry.message.timestamp : entry.block.timestamp;
|
|
2449
|
-
}
|
|
2450
|
-
function MessageList({
|
|
2451
|
-
displayBlocks = [],
|
|
2452
|
-
expandToolOutputs = false,
|
|
2453
|
-
maxItems,
|
|
2454
|
-
messages,
|
|
2455
|
-
showImages,
|
|
2456
|
-
showThinking,
|
|
2457
|
-
theme
|
|
2458
|
-
}) {
|
|
2459
|
-
const visible = [
|
|
2460
|
-
...groupMessages(messages),
|
|
2461
|
-
...displayBlocks.map((block) => ({ type: "displayBlock", block }))
|
|
2462
|
-
].sort((left, right) => getEntryTimestamp(left) - getEntryTimestamp(right)).slice(-maxItems);
|
|
2463
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: visible.map((entry, index) => entry.type === "message" ? /* @__PURE__ */ jsx(
|
|
2464
|
-
MessageRow,
|
|
2465
|
-
{
|
|
2466
|
-
message: entry.message,
|
|
2467
|
-
expandToolOutputs,
|
|
2468
|
-
showImages,
|
|
2469
|
-
showThinking,
|
|
2470
|
-
theme,
|
|
2471
|
-
toolResults: entry.toolResults
|
|
2472
|
-
},
|
|
2473
|
-
`${entry.message.role}:${entry.message.timestamp}:${index}`
|
|
2474
|
-
) : /* @__PURE__ */ jsx(
|
|
2475
|
-
DisplayBlockView,
|
|
2476
|
-
{
|
|
2477
|
-
block: entry.block,
|
|
2478
|
-
theme
|
|
2479
|
-
},
|
|
2480
|
-
`${entry.block.kind}:${entry.block.timestamp}:${entry.block.id}`
|
|
2481
|
-
)) });
|
|
2482
|
-
}
|
|
2483
|
-
|
|
2484
|
-
// src/react-ink/components/StatusLine.tsx
|
|
2485
|
-
function StatusLine({ snapshot, status, theme, showBusyText = true }) {
|
|
2486
|
-
let text = status?.text;
|
|
2487
|
-
let tone = status?.kind ?? "info";
|
|
2488
|
-
if (!text) {
|
|
2489
|
-
if (showBusyText && snapshot.isCompacting) {
|
|
2490
|
-
text = "Compacting conversation context...";
|
|
2491
|
-
tone = "busy";
|
|
2492
|
-
} else if (showBusyText && snapshot.isBashRunning) {
|
|
2493
|
-
text = "Running bash command...";
|
|
2494
|
-
tone = "busy";
|
|
2495
|
-
} else if (showBusyText && (snapshot.pendingToolCallCount > 0 || snapshot.pendingMessageCount > 0)) {
|
|
2496
|
-
text = "Agent working...";
|
|
2497
|
-
tone = "busy";
|
|
2498
|
-
} else if (showBusyText && snapshot.isStreaming) {
|
|
2499
|
-
text = "Agent working...";
|
|
2500
|
-
tone = "busy";
|
|
2501
|
-
} else if (snapshot.error) {
|
|
2502
|
-
text = snapshot.error;
|
|
2503
|
-
tone = "error";
|
|
2504
|
-
}
|
|
2505
|
-
}
|
|
2506
|
-
if (!text) return null;
|
|
2507
|
-
const styled = tone === "error" ? theme.color("error", text) : tone === "warning" ? theme.color("warning", text) : tone === "success" ? theme.color("success", text) : theme.muted(text);
|
|
2508
|
-
return /* @__PURE__ */ jsx(Text, { children: styled });
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
// src/react-ink/components/TaskPanel.tsx
|
|
2512
|
-
function TaskPanel({ expandToolOutputs = false, pendingMessages = [], snapshot, theme, toolExecutions }) {
|
|
2513
|
-
const recent = Object.values(toolExecutions).sort((left, right) => {
|
|
2514
|
-
if (left.status === "running" && right.status !== "running") return -1;
|
|
2515
|
-
if (left.status !== "running" && right.status === "running") return 1;
|
|
2516
|
-
return right.updatedAt - left.updatedAt;
|
|
2517
|
-
}).slice(0, 6);
|
|
2518
|
-
if (recent.length === 0 && pendingMessages.length === 0 && snapshot.pendingMessageCount === 0) {
|
|
2519
|
-
return null;
|
|
2520
|
-
}
|
|
2521
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, marginTop: 1, children: [
|
|
2522
|
-
recent.length > 0 ? /* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Tool Activity ${recent.length}`) }) : null,
|
|
2523
|
-
recent.map((tool) => {
|
|
2524
|
-
const descriptor = describeToolExecution(tool);
|
|
2525
|
-
return /* @__PURE__ */ jsx(
|
|
2526
|
-
ToolEventBlock,
|
|
2527
|
-
{
|
|
2528
|
-
detail: descriptor.body,
|
|
2529
|
-
emptyText: descriptor.emptyText,
|
|
2530
|
-
indent: 1,
|
|
2531
|
-
marginBottom: 0,
|
|
2532
|
-
maxContentLines: expandToolOutputs ? EXPANDED_CONTENT_LINES : COLLAPSED_CONTENT_LINES,
|
|
2533
|
-
moreHint: expandToolOutputs ? "ctrl+o to collapse" : "ctrl+o to expand",
|
|
2534
|
-
showSummaryInline: true,
|
|
2535
|
-
status: tool.status,
|
|
2536
|
-
summary: descriptor.summary,
|
|
2537
|
-
theme,
|
|
2538
|
-
title: descriptor.title
|
|
2539
|
-
},
|
|
2540
|
-
tool.toolCallId
|
|
2541
|
-
);
|
|
2542
|
-
}),
|
|
2543
|
-
pendingMessages.length > 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: recent.length > 0 ? 1 : 0, children: [
|
|
2544
|
-
/* @__PURE__ */ jsx(Text, { children: theme.color("accent", `Queued Messages ${pendingMessages.length}`) }),
|
|
2545
|
-
pendingMessages.slice(0, 6).map((message) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
2546
|
-
theme.muted(` ${message.mode === "steer" ? "Steering" : "Follow-up"}: `),
|
|
2547
|
-
message.text.length > 90 ? `${message.text.slice(0, 87)}...` : message.text
|
|
2548
|
-
] }, message.id)),
|
|
2549
|
-
/* @__PURE__ */ jsx(Text, { children: theme.muted(" Ctrl+X runs the newest queued message now \xB7 Alt+Up restores it to the prompt") })
|
|
2550
|
-
] }) : snapshot.pendingMessageCount > 0 ? /* @__PURE__ */ jsx(Text, { children: theme.muted(`${snapshot.pendingMessageCount} queued message(s) waiting for the next turn`) }) : null
|
|
2551
|
-
] });
|
|
2552
|
-
}
|
|
2553
|
-
|
|
2554
|
-
// src/react-ink/components/dialogs/DialogFrame.tsx
|
|
2555
|
-
function DialogFrame({ children, footer, subtitle, title }) {
|
|
2556
|
-
return /* @__PURE__ */ jsxs(Box, { borderStyle: "round", flexDirection: "column", marginTop: 1, paddingX: 1, paddingY: 0, children: [
|
|
2557
|
-
/* @__PURE__ */ jsx(Text, { children: title }),
|
|
2558
|
-
subtitle ? /* @__PURE__ */ jsx(Text, { children: subtitle }) : null,
|
|
2559
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children }),
|
|
2560
|
-
footer ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: footer }) : null
|
|
2561
|
-
] });
|
|
2562
|
-
}
|
|
2563
|
-
|
|
2564
|
-
// src/react-ink/utils/selection-dialog.ts
|
|
2565
|
-
function matchesSearchQuery(value, query) {
|
|
2566
|
-
if (!query.trim()) {
|
|
2567
|
-
return true;
|
|
2568
|
-
}
|
|
2569
|
-
const haystack = value.toLowerCase();
|
|
2570
|
-
return query.toLowerCase().split(/\s+/).filter(Boolean).every((term) => haystack.includes(term));
|
|
2571
|
-
}
|
|
2572
|
-
function wrapSelectionIndex(current, direction, length) {
|
|
2573
|
-
if (length <= 0) {
|
|
2574
|
-
return 0;
|
|
2575
|
-
}
|
|
2576
|
-
return (current + direction + length) % length;
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
|
-
// src/react-ink/components/dialogs/SelectableDialog.tsx
|
|
2580
|
-
function SelectableDialog({
|
|
2581
|
-
title,
|
|
2582
|
-
subtitle,
|
|
2583
|
-
items,
|
|
2584
|
-
isActive = true,
|
|
2585
|
-
searchEnabled = true,
|
|
2586
|
-
emptyText,
|
|
2587
|
-
noSearchResultsText = "No options matched the current search.",
|
|
2588
|
-
onClose,
|
|
2589
|
-
onSelect,
|
|
2590
|
-
onHighlight,
|
|
2591
|
-
getSearchText,
|
|
2592
|
-
renderItem
|
|
2593
|
-
}) {
|
|
2594
|
-
const [query, setQuery] = useState("");
|
|
2595
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
2596
|
-
const filteredItems = useMemo(() => {
|
|
2597
|
-
if (!searchEnabled) {
|
|
2598
|
-
return items;
|
|
2599
|
-
}
|
|
2600
|
-
return items.filter((item) => matchesSearchQuery(getSearchText ? getSearchText(item) : String(item), query));
|
|
2601
|
-
}, [getSearchText, items, query, searchEnabled]);
|
|
2602
|
-
useEffect(() => {
|
|
2603
|
-
setSelectedIndex(0);
|
|
2604
|
-
}, [query]);
|
|
2605
|
-
useEffect(() => {
|
|
2606
|
-
if (selectedIndex >= filteredItems.length) {
|
|
2607
|
-
setSelectedIndex(0);
|
|
2608
|
-
}
|
|
2609
|
-
}, [filteredItems.length, selectedIndex]);
|
|
2610
|
-
const highlighted = filteredItems[selectedIndex];
|
|
2611
|
-
useEffect(() => {
|
|
2612
|
-
if (isActive && onHighlight && highlighted !== void 0) {
|
|
2613
|
-
onHighlight(highlighted, selectedIndex);
|
|
2614
|
-
}
|
|
2615
|
-
}, [highlighted, isActive]);
|
|
2616
|
-
const maxVisible = useMemo(() => Math.max(8, (process.stdout.rows ?? 24) - 16), []);
|
|
2617
|
-
const windowStart = Math.max(
|
|
2618
|
-
0,
|
|
2619
|
-
Math.min(selectedIndex - Math.floor(maxVisible / 2), Math.max(0, filteredItems.length - maxVisible))
|
|
2620
|
-
);
|
|
2621
|
-
const visibleItems = filteredItems.slice(windowStart, windowStart + maxVisible);
|
|
2622
|
-
const showSearch = searchEnabled && items.length > 0;
|
|
2623
|
-
useInput(
|
|
2624
|
-
(input, key) => {
|
|
2625
|
-
if (key.escape) {
|
|
2626
|
-
onClose();
|
|
2627
|
-
return;
|
|
2628
|
-
}
|
|
2629
|
-
if (key.upArrow) {
|
|
2630
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, -1, filteredItems.length));
|
|
2631
|
-
return;
|
|
2632
|
-
}
|
|
2633
|
-
if (key.downArrow) {
|
|
2634
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, 1, filteredItems.length));
|
|
2635
|
-
return;
|
|
2636
|
-
}
|
|
2637
|
-
if (searchEnabled && (key.backspace || key.delete)) {
|
|
2638
|
-
setQuery((current) => current.slice(0, -1));
|
|
2639
|
-
return;
|
|
2640
|
-
}
|
|
2641
|
-
if (searchEnabled && key.ctrl && input === "u") {
|
|
2642
|
-
setQuery("");
|
|
2643
|
-
return;
|
|
2644
|
-
}
|
|
2645
|
-
if (key.return) {
|
|
2646
|
-
const item = filteredItems[selectedIndex];
|
|
2647
|
-
if (item) {
|
|
2648
|
-
void onSelect(item);
|
|
2649
|
-
}
|
|
2650
|
-
return;
|
|
2651
|
-
}
|
|
2652
|
-
if (searchEnabled && !key.ctrl && !key.meta && input) {
|
|
2653
|
-
setQuery((current) => current + input);
|
|
2654
|
-
}
|
|
2655
|
-
},
|
|
2656
|
-
{ isActive }
|
|
2657
|
-
);
|
|
2658
|
-
return /* @__PURE__ */ jsxs(
|
|
2659
|
-
DialogFrame,
|
|
2660
|
-
{
|
|
2661
|
-
title,
|
|
2662
|
-
subtitle,
|
|
2663
|
-
footer: /* @__PURE__ */ jsx(Text, { children: searchEnabled ? "Type to filter, Up/Down wraps, Enter selects, Ctrl+U clears, Esc closes" : "Up/Down wraps, Enter selects, Esc closes" }),
|
|
2664
|
-
children: [
|
|
2665
|
-
showSearch ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2666
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2667
|
-
"Search: ",
|
|
2668
|
-
query || " "
|
|
2669
|
-
] }),
|
|
2670
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2671
|
-
filteredItems.length,
|
|
2672
|
-
" match",
|
|
2673
|
-
filteredItems.length === 1 ? "" : "es"
|
|
2674
|
-
] })
|
|
2675
|
-
] }) : null,
|
|
2676
|
-
items.length === 0 ? /* @__PURE__ */ jsx(Box, { marginTop: showSearch ? 1 : 0, children: /* @__PURE__ */ jsx(Text, { children: emptyText }) }) : filteredItems.length === 0 ? /* @__PURE__ */ jsx(Box, { marginTop: showSearch ? 1 : 0, children: /* @__PURE__ */ jsx(Text, { children: noSearchResultsText }) }) : /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: showSearch ? 1 : 0, children: visibleItems.map((item, index) => {
|
|
2677
|
-
const actualIndex = windowStart + index;
|
|
2678
|
-
return /* @__PURE__ */ jsx(Box, { children: renderItem(item, actualIndex === selectedIndex, actualIndex) }, actualIndex);
|
|
2679
|
-
}) })
|
|
2680
|
-
]
|
|
2681
|
-
}
|
|
2682
|
-
);
|
|
2683
|
-
}
|
|
2684
|
-
|
|
2685
|
-
// src/react-ink/components/dialogs/LoginDialog.tsx
|
|
2686
|
-
function LoginDialog(props) {
|
|
2687
|
-
if (props.mode === "logout") {
|
|
2688
|
-
return /* @__PURE__ */ jsx(
|
|
2689
|
-
SelectableDialog,
|
|
2690
|
-
{
|
|
2691
|
-
title: "Saved Credentials",
|
|
2692
|
-
items: props.accounts,
|
|
2693
|
-
emptyText: "No saved credentials were found.",
|
|
2694
|
-
onClose: props.onClose,
|
|
2695
|
-
onSelect: props.onSelect,
|
|
2696
|
-
getSearchText: (account) => account.label,
|
|
2697
|
-
renderItem: (account, selected) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
2698
|
-
selected ? "> " : " ",
|
|
2699
|
-
account.label
|
|
2700
|
-
] })
|
|
2701
|
-
}
|
|
2702
|
-
);
|
|
2703
|
-
}
|
|
2704
|
-
return /* @__PURE__ */ jsx(
|
|
2705
|
-
SelectableDialog,
|
|
2706
|
-
{
|
|
2707
|
-
title: "Login Providers",
|
|
2708
|
-
items: props.providers,
|
|
2709
|
-
emptyText: "No authenticated providers are configured.",
|
|
2710
|
-
onClose: props.onClose,
|
|
2711
|
-
onSelect: props.onSelect,
|
|
2712
|
-
getSearchText: (provider) => `${provider.label} ${provider.authKind}`,
|
|
2713
|
-
renderItem: (provider, selected) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
2714
|
-
selected ? "> " : " ",
|
|
2715
|
-
provider.label,
|
|
2716
|
-
" (",
|
|
2717
|
-
provider.authKind,
|
|
2718
|
-
")"
|
|
2719
|
-
] })
|
|
2720
|
-
}
|
|
2721
|
-
);
|
|
2722
|
-
}
|
|
2723
|
-
|
|
2724
|
-
// src/react-ink/components/dialogs/ModelDialog.tsx
|
|
2725
|
-
function matchesModel(model, search) {
|
|
2726
|
-
return matchesSearchQuery(`${model.provider} ${model.id} ${model.name ?? ""}`, search);
|
|
2727
|
-
}
|
|
2728
|
-
function ModelDialog({ models, onClose, onSelect, search }) {
|
|
2729
|
-
const [query, setQuery] = useState(search ?? "");
|
|
2730
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
2731
|
-
useEffect(() => {
|
|
2732
|
-
setQuery(search ?? "");
|
|
2733
|
-
}, [search]);
|
|
2734
|
-
const filtered = useMemo(
|
|
2735
|
-
() => models.filter((model) => matchesModel(model, query)),
|
|
2736
|
-
[models, query]
|
|
2737
|
-
);
|
|
2738
|
-
useEffect(() => {
|
|
2739
|
-
setSelectedIndex(0);
|
|
2740
|
-
}, [query]);
|
|
2741
|
-
useEffect(() => {
|
|
2742
|
-
if (selectedIndex >= filtered.length) {
|
|
2743
|
-
setSelectedIndex(0);
|
|
2744
|
-
}
|
|
2745
|
-
}, [filtered.length, selectedIndex]);
|
|
2746
|
-
const maxVisible = Math.max(8, (process.stdout.rows ?? 24) - 16);
|
|
2747
|
-
const windowStart = Math.max(
|
|
2748
|
-
0,
|
|
2749
|
-
Math.min(selectedIndex - Math.floor(maxVisible / 2), Math.max(0, filtered.length - maxVisible))
|
|
2750
|
-
);
|
|
2751
|
-
const visibleModels = filtered.slice(windowStart, windowStart + maxVisible);
|
|
2752
|
-
useInput((input, key) => {
|
|
2753
|
-
if (key.escape) {
|
|
2754
|
-
onClose();
|
|
2755
|
-
return;
|
|
2756
|
-
}
|
|
2757
|
-
if (key.upArrow) {
|
|
2758
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, -1, filtered.length));
|
|
2759
|
-
return;
|
|
2760
|
-
}
|
|
2761
|
-
if (key.downArrow) {
|
|
2762
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, 1, filtered.length));
|
|
2763
|
-
return;
|
|
2764
|
-
}
|
|
2765
|
-
if (key.backspace || key.delete) {
|
|
2766
|
-
setQuery((current) => current.slice(0, -1));
|
|
2767
|
-
return;
|
|
2768
|
-
}
|
|
2769
|
-
if (key.ctrl && input === "u") {
|
|
2770
|
-
setQuery("");
|
|
2771
|
-
return;
|
|
2772
|
-
}
|
|
2773
|
-
if (key.return) {
|
|
2774
|
-
const selected = filtered[selectedIndex];
|
|
2775
|
-
if (selected) {
|
|
2776
|
-
void onSelect(selected);
|
|
2777
|
-
}
|
|
2778
|
-
return;
|
|
2779
|
-
}
|
|
2780
|
-
if (!key.ctrl && !key.meta && input) {
|
|
2781
|
-
setQuery((current) => current + input);
|
|
2782
|
-
}
|
|
2783
|
-
});
|
|
2784
|
-
return /* @__PURE__ */ jsxs(
|
|
2785
|
-
DialogFrame,
|
|
2786
|
-
{
|
|
2787
|
-
title: "Models",
|
|
2788
|
-
subtitle: "Type to search models by provider, id, or name",
|
|
2789
|
-
footer: /* @__PURE__ */ jsx(Text, { children: "Type to filter, Up/Down to move, Enter to select, Ctrl+U clears, Esc closes" }),
|
|
2790
|
-
children: [
|
|
2791
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2792
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2793
|
-
"Search: ",
|
|
2794
|
-
query || " "
|
|
2795
|
-
] }),
|
|
2796
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2797
|
-
filtered.length,
|
|
2798
|
-
" match",
|
|
2799
|
-
filtered.length === 1 ? "" : "es"
|
|
2800
|
-
] })
|
|
2801
|
-
] }),
|
|
2802
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: filtered.length === 0 ? /* @__PURE__ */ jsx(Text, { children: "No models matched the current search." }) : visibleModels.map((model, index) => {
|
|
2803
|
-
const actualIndex = windowStart + index;
|
|
2804
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
2805
|
-
actualIndex === selectedIndex ? "> " : " ",
|
|
2806
|
-
model.provider,
|
|
2807
|
-
"/",
|
|
2808
|
-
model.id,
|
|
2809
|
-
model.name ? ` (${model.name})` : ""
|
|
2810
|
-
] }, `${model.provider}/${model.id}`);
|
|
2811
|
-
}) })
|
|
2812
|
-
]
|
|
2813
|
-
}
|
|
2814
|
-
);
|
|
2815
|
-
}
|
|
2816
|
-
|
|
2817
|
-
// src/react-ink/components/dialogs/OAuthDialog.tsx
|
|
2818
|
-
function OAuthDialog({ onChange, onClose, onSubmit, state }) {
|
|
2819
|
-
useInput((input, key) => {
|
|
2820
|
-
if (key.escape) {
|
|
2821
|
-
onClose();
|
|
2822
|
-
return;
|
|
2823
|
-
}
|
|
2824
|
-
if (key.return) {
|
|
2825
|
-
void onSubmit();
|
|
2826
|
-
return;
|
|
2827
|
-
}
|
|
2828
|
-
if (key.backspace || key.delete) {
|
|
2829
|
-
onChange({ inputValue: state.inputValue.slice(0, -1) });
|
|
2830
|
-
return;
|
|
2831
|
-
}
|
|
2832
|
-
if (input && !key.ctrl && !key.meta) {
|
|
2833
|
-
onChange({ inputValue: state.inputValue + input });
|
|
2834
|
-
}
|
|
2835
|
-
});
|
|
2836
|
-
return /* @__PURE__ */ jsxs(
|
|
2837
|
-
DialogFrame,
|
|
2838
|
-
{
|
|
2839
|
-
title: `${state.mode === "oauth" ? "OAuth Login" : "API Key Login"}: ${state.providerName}`,
|
|
2840
|
-
footer: /* @__PURE__ */ jsx(Text, { children: "Type to edit, Enter to submit, Esc to cancel" }),
|
|
2841
|
-
children: [
|
|
2842
|
-
state.progress ? /* @__PURE__ */ jsx(Text, { children: state.progress }) : null,
|
|
2843
|
-
state.authInfo ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
2844
|
-
/* @__PURE__ */ jsx(Text, { children: state.authInfo.instructions ?? "Open this URL in your browser to continue:" }),
|
|
2845
|
-
/* @__PURE__ */ jsx(Text, { children: state.authInfo.url })
|
|
2846
|
-
] }) : null,
|
|
2847
|
-
state.prompt ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: state.prompt.message }) }) : null,
|
|
2848
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
2849
|
-
/* @__PURE__ */ jsx(Text, { children: state.inputLabel }),
|
|
2850
|
-
/* @__PURE__ */ jsx(Text, { children: state.inputValue || " " })
|
|
2851
|
-
] })
|
|
2852
|
-
]
|
|
2853
|
-
}
|
|
2854
|
-
);
|
|
2855
|
-
}
|
|
2856
|
-
|
|
2857
|
-
// src/react-ink/components/dialogs/ScopedModelsDialog.tsx
|
|
2858
|
-
function modelKey(model) {
|
|
2859
|
-
return `${model.provider}/${model.id}`;
|
|
2860
|
-
}
|
|
2861
|
-
function ScopedModelsDialog({ models, onClose, onSave, selectedIds }) {
|
|
2862
|
-
const [query, setQuery] = useState("");
|
|
2863
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
2864
|
-
const [enabledIds, setEnabledIds] = useState(() => new Set(selectedIds));
|
|
2865
|
-
useEffect(() => {
|
|
2866
|
-
setSelectedIndex(0);
|
|
2867
|
-
setQuery("");
|
|
2868
|
-
setEnabledIds(new Set(selectedIds));
|
|
2869
|
-
}, [selectedIds]);
|
|
2870
|
-
const filteredModels = useMemo(
|
|
2871
|
-
() => models.filter((model) => matchesSearchQuery(`${model.provider} ${model.id} ${model.name ?? ""}`, query)),
|
|
2872
|
-
[models, query]
|
|
2873
|
-
);
|
|
2874
|
-
useEffect(() => {
|
|
2875
|
-
setSelectedIndex(0);
|
|
2876
|
-
}, [query]);
|
|
2877
|
-
useEffect(() => {
|
|
2878
|
-
if (selectedIndex >= filteredModels.length) {
|
|
2879
|
-
setSelectedIndex(0);
|
|
2880
|
-
}
|
|
2881
|
-
}, [filteredModels.length, selectedIndex]);
|
|
2882
|
-
const maxVisible = useMemo(() => Math.max(8, (process.stdout.rows ?? 24) - 18), []);
|
|
2883
|
-
const windowStart = Math.max(
|
|
2884
|
-
0,
|
|
2885
|
-
Math.min(selectedIndex - Math.floor(maxVisible / 2), Math.max(0, filteredModels.length - maxVisible))
|
|
2886
|
-
);
|
|
2887
|
-
const visibleModels = filteredModels.slice(windowStart, windowStart + maxVisible);
|
|
2888
|
-
const toggleSelectedModel = () => {
|
|
2889
|
-
const model = filteredModels[selectedIndex];
|
|
2890
|
-
if (!model) {
|
|
2891
|
-
return;
|
|
2892
|
-
}
|
|
2893
|
-
const id = modelKey(model);
|
|
2894
|
-
setEnabledIds((current) => {
|
|
2895
|
-
const next = new Set(current);
|
|
2896
|
-
if (next.has(id)) {
|
|
2897
|
-
next.delete(id);
|
|
2898
|
-
} else {
|
|
2899
|
-
next.add(id);
|
|
2900
|
-
}
|
|
2901
|
-
return next;
|
|
2902
|
-
});
|
|
2903
|
-
};
|
|
2904
|
-
useInput((input, key) => {
|
|
2905
|
-
if (key.escape) {
|
|
2906
|
-
onClose();
|
|
2907
|
-
return;
|
|
2908
|
-
}
|
|
2909
|
-
if (key.upArrow) {
|
|
2910
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, -1, filteredModels.length));
|
|
2911
|
-
return;
|
|
2912
|
-
}
|
|
2913
|
-
if (key.downArrow) {
|
|
2914
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, 1, filteredModels.length));
|
|
2915
|
-
return;
|
|
2916
|
-
}
|
|
2917
|
-
if (key.backspace || key.delete) {
|
|
2918
|
-
setQuery((current) => current.slice(0, -1));
|
|
2919
|
-
return;
|
|
2920
|
-
}
|
|
2921
|
-
if (key.ctrl && input === "u") {
|
|
2922
|
-
setQuery("");
|
|
2923
|
-
return;
|
|
2924
|
-
}
|
|
2925
|
-
if (key.ctrl && input === "a") {
|
|
2926
|
-
setEnabledIds(new Set(models.map(modelKey)));
|
|
2927
|
-
return;
|
|
2928
|
-
}
|
|
2929
|
-
if (key.ctrl && input === "k") {
|
|
2930
|
-
setEnabledIds(/* @__PURE__ */ new Set());
|
|
2931
|
-
return;
|
|
2932
|
-
}
|
|
2933
|
-
if (input === " ") {
|
|
2934
|
-
toggleSelectedModel();
|
|
2935
|
-
return;
|
|
2936
|
-
}
|
|
2937
|
-
if (key.return) {
|
|
2938
|
-
void onSave([...enabledIds].sort());
|
|
2939
|
-
return;
|
|
2940
|
-
}
|
|
2941
|
-
if (!key.ctrl && !key.meta && input && input !== " ") {
|
|
2942
|
-
setQuery((current) => current + input);
|
|
2943
|
-
}
|
|
2944
|
-
});
|
|
2945
|
-
return /* @__PURE__ */ jsx(
|
|
2946
|
-
DialogFrame,
|
|
2947
|
-
{
|
|
2948
|
-
title: "Scoped Models",
|
|
2949
|
-
subtitle: "Choose which models Ctrl+P cycles through",
|
|
2950
|
-
footer: /* @__PURE__ */ jsxs(Text, { children: [
|
|
2951
|
-
"Type to filter, Up/Down wraps, Space toggles, Ctrl+A selects all, Ctrl+K clears,",
|
|
2952
|
-
" ",
|
|
2953
|
-
"Ctrl+U clears search, Enter saves, Esc closes"
|
|
2954
|
-
] }),
|
|
2955
|
-
children: models.length === 0 ? /* @__PURE__ */ jsx(Text, { children: "No authenticated models are currently available." }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
2956
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2957
|
-
"Search: ",
|
|
2958
|
-
query || " "
|
|
2959
|
-
] }),
|
|
2960
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
2961
|
-
filteredModels.length,
|
|
2962
|
-
" match",
|
|
2963
|
-
filteredModels.length === 1 ? "" : "es"
|
|
2964
|
-
] }),
|
|
2965
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
2966
|
-
"Selected: ",
|
|
2967
|
-
enabledIds.size === 0 ? "all available models" : `${enabledIds.size} model(s)`
|
|
2968
|
-
] }),
|
|
2969
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: filteredModels.length === 0 ? /* @__PURE__ */ jsx(Text, { children: "No models matched the current search." }) : visibleModels.map((model, index) => {
|
|
2970
|
-
const actualIndex = windowStart + index;
|
|
2971
|
-
const id = modelKey(model);
|
|
2972
|
-
const checked = enabledIds.has(id);
|
|
2973
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
2974
|
-
actualIndex === selectedIndex ? "> " : " ",
|
|
2975
|
-
"[",
|
|
2976
|
-
checked ? "x" : " ",
|
|
2977
|
-
"] ",
|
|
2978
|
-
id
|
|
2979
|
-
] }, id);
|
|
2980
|
-
}) })
|
|
2981
|
-
] })
|
|
2982
|
-
}
|
|
2983
|
-
);
|
|
2984
|
-
}
|
|
2985
|
-
|
|
2986
|
-
// src/react-ink/utils/session-browser.ts
|
|
2987
|
-
function wrapSelectionIndex2(current, direction, length) {
|
|
2988
|
-
if (length <= 0) {
|
|
2989
|
-
return 0;
|
|
2990
|
-
}
|
|
2991
|
-
return (current + direction + length) % length;
|
|
2992
|
-
}
|
|
2993
|
-
function normalizeQueryText(text) {
|
|
2994
|
-
return text.toLowerCase().replace(/\s+/g, " ").trim();
|
|
2995
|
-
}
|
|
2996
|
-
function fuzzyScore(needle, haystack) {
|
|
2997
|
-
const query = needle.toLowerCase().trim();
|
|
2998
|
-
const text = haystack.toLowerCase();
|
|
2999
|
-
if (!query) {
|
|
3000
|
-
return { matches: true, score: 0 };
|
|
3001
|
-
}
|
|
3002
|
-
let score = 0;
|
|
3003
|
-
let searchIndex = 0;
|
|
3004
|
-
let firstMatch = -1;
|
|
3005
|
-
for (const char of query) {
|
|
3006
|
-
const index = text.indexOf(char, searchIndex);
|
|
3007
|
-
if (index < 0) {
|
|
3008
|
-
return { matches: false, score: 0 };
|
|
3009
|
-
}
|
|
3010
|
-
if (firstMatch < 0) {
|
|
3011
|
-
firstMatch = index;
|
|
3012
|
-
}
|
|
3013
|
-
score += index - searchIndex;
|
|
3014
|
-
searchIndex = index + 1;
|
|
3015
|
-
}
|
|
3016
|
-
return { matches: true, score: score + Math.max(firstMatch, 0) * 0.1 };
|
|
3017
|
-
}
|
|
3018
|
-
function buildSearchText(session) {
|
|
3019
|
-
return [
|
|
3020
|
-
session.id,
|
|
3021
|
-
session.name ?? "",
|
|
3022
|
-
session.firstMessage ?? "",
|
|
3023
|
-
session.allMessagesText ?? "",
|
|
3024
|
-
session.cwd ?? "",
|
|
3025
|
-
session.path,
|
|
3026
|
-
new Date(session.lastModified).toLocaleString()
|
|
3027
|
-
].join(" ").trim();
|
|
3028
|
-
}
|
|
3029
|
-
function tokenizeQuotedQuery(query) {
|
|
3030
|
-
const tokens = [];
|
|
3031
|
-
let buffer = "";
|
|
3032
|
-
let inQuote = false;
|
|
3033
|
-
const pushBuffer = (kind) => {
|
|
3034
|
-
const value = buffer.trim();
|
|
3035
|
-
buffer = "";
|
|
3036
|
-
if (value) {
|
|
3037
|
-
tokens.push({ kind, value });
|
|
3038
|
-
}
|
|
3039
|
-
};
|
|
3040
|
-
for (const char of query) {
|
|
3041
|
-
if (char === '"') {
|
|
3042
|
-
pushBuffer(inQuote ? "phrase" : "fuzzy");
|
|
3043
|
-
inQuote = !inQuote;
|
|
3044
|
-
continue;
|
|
3045
|
-
}
|
|
3046
|
-
if (!inQuote && /\s/.test(char)) {
|
|
3047
|
-
pushBuffer("fuzzy");
|
|
3048
|
-
continue;
|
|
3049
|
-
}
|
|
3050
|
-
buffer += char;
|
|
3051
|
-
}
|
|
3052
|
-
if (!inQuote) {
|
|
3053
|
-
pushBuffer("fuzzy");
|
|
3054
|
-
}
|
|
3055
|
-
return { tokens, hadUnclosedQuote: inQuote };
|
|
3056
|
-
}
|
|
3057
|
-
function fallbackWhitespaceTokens(query) {
|
|
3058
|
-
return query.split(/\s+/).map((token) => token.trim()).filter(Boolean).map((value) => ({ kind: "fuzzy", value }));
|
|
3059
|
-
}
|
|
3060
|
-
function createRegexQuery(query) {
|
|
3061
|
-
const pattern = query.slice(3).trim();
|
|
3062
|
-
if (!pattern) {
|
|
3063
|
-
return { mode: "regex", tokens: [], regex: null, error: "Empty regex" };
|
|
3064
|
-
}
|
|
3065
|
-
try {
|
|
3066
|
-
return { mode: "regex", tokens: [], regex: new RegExp(pattern, "i") };
|
|
3067
|
-
} catch (error) {
|
|
3068
|
-
return {
|
|
3069
|
-
mode: "regex",
|
|
3070
|
-
tokens: [],
|
|
3071
|
-
regex: null,
|
|
3072
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3073
|
-
};
|
|
3074
|
-
}
|
|
3075
|
-
}
|
|
3076
|
-
function parseSessionSearchQuery(query) {
|
|
3077
|
-
const trimmed = query.trim();
|
|
3078
|
-
if (!trimmed) {
|
|
3079
|
-
return { mode: "tokens", tokens: [], regex: null };
|
|
3080
|
-
}
|
|
3081
|
-
if (trimmed.startsWith("re:")) {
|
|
3082
|
-
return createRegexQuery(trimmed);
|
|
3083
|
-
}
|
|
3084
|
-
const tokenized = tokenizeQuotedQuery(trimmed);
|
|
3085
|
-
return {
|
|
3086
|
-
mode: "tokens",
|
|
3087
|
-
tokens: tokenized.hadUnclosedQuote ? fallbackWhitespaceTokens(trimmed) : tokenized.tokens,
|
|
3088
|
-
regex: null
|
|
3089
|
-
};
|
|
3090
|
-
}
|
|
3091
|
-
function scoreRegexMatch(text, regex) {
|
|
3092
|
-
if (!regex) {
|
|
3093
|
-
return { matches: false, score: 0 };
|
|
3094
|
-
}
|
|
3095
|
-
const index = text.search(regex);
|
|
3096
|
-
return index < 0 ? { matches: false, score: 0 } : { matches: true, score: index * 0.1 };
|
|
3097
|
-
}
|
|
3098
|
-
function scoreTokenMatch(text, parsed) {
|
|
3099
|
-
if (parsed.tokens.length === 0) {
|
|
3100
|
-
return { matches: true, score: 0 };
|
|
3101
|
-
}
|
|
3102
|
-
let totalScore = 0;
|
|
3103
|
-
let normalizedText;
|
|
3104
|
-
for (const token of parsed.tokens) {
|
|
3105
|
-
if (token.kind === "phrase") {
|
|
3106
|
-
normalizedText ??= normalizeQueryText(text);
|
|
3107
|
-
const phraseIndex = normalizedText.indexOf(normalizeQueryText(token.value));
|
|
3108
|
-
if (phraseIndex < 0) {
|
|
3109
|
-
return { matches: false, score: 0 };
|
|
3110
|
-
}
|
|
3111
|
-
totalScore += phraseIndex * 0.1;
|
|
3112
|
-
continue;
|
|
3113
|
-
}
|
|
3114
|
-
const fuzzy = fuzzyScore(token.value, text);
|
|
3115
|
-
if (!fuzzy.matches) {
|
|
3116
|
-
return { matches: false, score: 0 };
|
|
3117
|
-
}
|
|
3118
|
-
totalScore += fuzzy.score;
|
|
3119
|
-
}
|
|
3120
|
-
return { matches: true, score: totalScore };
|
|
3121
|
-
}
|
|
3122
|
-
function filterAndSortSessions(sessions, query, sortMode) {
|
|
3123
|
-
const parsed = parseSessionSearchQuery(query);
|
|
3124
|
-
if (parsed.error) {
|
|
3125
|
-
return { items: [], error: parsed.error };
|
|
3126
|
-
}
|
|
3127
|
-
if (!query.trim()) {
|
|
3128
|
-
const items = [...sessions].sort((left, right) => right.lastModified - left.lastModified);
|
|
3129
|
-
return { items };
|
|
3130
|
-
}
|
|
3131
|
-
const scored = sessions.map((session) => {
|
|
3132
|
-
const text = buildSearchText(session);
|
|
3133
|
-
const match = parsed.mode === "regex" ? scoreRegexMatch(text, parsed.regex) : scoreTokenMatch(text, parsed);
|
|
3134
|
-
return { session, match };
|
|
3135
|
-
}).filter((entry) => entry.match.matches);
|
|
3136
|
-
scored.sort((left, right) => {
|
|
3137
|
-
if (sortMode === "relevance" && left.match.score !== right.match.score) {
|
|
3138
|
-
return left.match.score - right.match.score;
|
|
3139
|
-
}
|
|
3140
|
-
return right.session.lastModified - left.session.lastModified;
|
|
3141
|
-
});
|
|
3142
|
-
return { items: scored.map((entry) => entry.session) };
|
|
3143
|
-
}
|
|
3144
|
-
function formatSessionAge(lastModified) {
|
|
3145
|
-
const ageMs = Date.now() - lastModified;
|
|
3146
|
-
const seconds = ageMs / 1e3;
|
|
3147
|
-
const minutes = seconds / 60;
|
|
3148
|
-
const hours = minutes / 60;
|
|
3149
|
-
const days = hours / 24;
|
|
3150
|
-
if (days >= 1) return `${Math.floor(days)}d ago`;
|
|
3151
|
-
if (hours >= 1) return `${Math.floor(hours)}h ago`;
|
|
3152
|
-
if (minutes >= 1) return `${Math.floor(minutes)}m ago`;
|
|
3153
|
-
return `${Math.max(0, Math.floor(seconds))}s ago`;
|
|
3154
|
-
}
|
|
3155
|
-
function formatSessionSize(bytes) {
|
|
3156
|
-
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
3157
|
-
if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
3158
|
-
return `${bytes} B`;
|
|
3159
|
-
}
|
|
3160
|
-
function shrinkSessionId(id) {
|
|
3161
|
-
return id.length > 16 ? `${id.slice(0, 8)}...${id.slice(-4)}` : id;
|
|
3162
|
-
}
|
|
3163
|
-
|
|
3164
|
-
// src/react-ink/components/dialogs/SessionDialog.tsx
|
|
3165
|
-
var VISIBLE_SESSION_COUNT = 5;
|
|
3166
|
-
function buildMetadata(session, showPath) {
|
|
3167
|
-
const parts = [
|
|
3168
|
-
formatSessionAge(session.lastModified),
|
|
3169
|
-
typeof session.messageCount === "number" ? `${session.messageCount} msg` : void 0,
|
|
3170
|
-
typeof session.size === "number" ? formatSessionSize(session.size) : void 0,
|
|
3171
|
-
session.cwd || void 0
|
|
3172
|
-
];
|
|
3173
|
-
if (showPath) {
|
|
3174
|
-
parts.push(session.path);
|
|
3175
|
-
}
|
|
3176
|
-
return parts.filter(Boolean).join(" | ");
|
|
3177
|
-
}
|
|
3178
|
-
function SessionDialog({
|
|
3179
|
-
currentSessionPath,
|
|
3180
|
-
currentSessions,
|
|
3181
|
-
onClose,
|
|
3182
|
-
onDeleteSession,
|
|
3183
|
-
onLoadAllSessions,
|
|
3184
|
-
onRenameSession,
|
|
3185
|
-
onSelect
|
|
3186
|
-
}) {
|
|
3187
|
-
const [scope, setScope] = useState("current");
|
|
3188
|
-
const [sortMode, setSortMode] = useState("relevance");
|
|
3189
|
-
const [showPath, setShowPath] = useState(false);
|
|
3190
|
-
const [query, setQuery] = useState("");
|
|
3191
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
3192
|
-
const [allSessions, setAllSessions] = useState(null);
|
|
3193
|
-
const [loadingAll, setLoadingAll] = useState(false);
|
|
3194
|
-
const [progress, setProgress] = useState(null);
|
|
3195
|
-
const [loadError, setLoadError] = useState();
|
|
3196
|
-
const [confirmDeletePath, setConfirmDeletePath] = useState(null);
|
|
3197
|
-
const [renamePath, setRenamePath] = useState(null);
|
|
3198
|
-
const [renameValue, setRenameValue] = useState("");
|
|
3199
|
-
useEffect(() => {
|
|
3200
|
-
if (scope !== "all" || allSessions || loadingAll) {
|
|
3201
|
-
return;
|
|
3202
|
-
}
|
|
3203
|
-
let cancelled = false;
|
|
3204
|
-
setLoadingAll(true);
|
|
3205
|
-
setLoadError(void 0);
|
|
3206
|
-
setProgress(null);
|
|
3207
|
-
void onLoadAllSessions((next) => {
|
|
3208
|
-
if (!cancelled) {
|
|
3209
|
-
setProgress(next);
|
|
3210
|
-
}
|
|
3211
|
-
}).then((sessions) => {
|
|
3212
|
-
if (!cancelled) {
|
|
3213
|
-
setAllSessions(sessions);
|
|
3214
|
-
}
|
|
3215
|
-
}).catch((error) => {
|
|
3216
|
-
if (!cancelled) {
|
|
3217
|
-
setLoadError(error instanceof Error ? error.message : String(error));
|
|
3218
|
-
}
|
|
3219
|
-
}).finally(() => {
|
|
3220
|
-
if (!cancelled) {
|
|
3221
|
-
setLoadingAll(false);
|
|
3222
|
-
}
|
|
3223
|
-
});
|
|
3224
|
-
return () => {
|
|
3225
|
-
cancelled = true;
|
|
3226
|
-
};
|
|
3227
|
-
}, [allSessions, loadingAll, onLoadAllSessions, scope]);
|
|
3228
|
-
const sourceSessions = scope === "all" ? allSessions ?? [] : currentSessions;
|
|
3229
|
-
const filtered = useMemo(() => filterAndSortSessions(sourceSessions, query, sortMode), [query, sortMode, sourceSessions]);
|
|
3230
|
-
useEffect(() => {
|
|
3231
|
-
setSelectedIndex(0);
|
|
3232
|
-
setConfirmDeletePath(null);
|
|
3233
|
-
}, [query, scope, sortMode]);
|
|
3234
|
-
useEffect(() => {
|
|
3235
|
-
if (selectedIndex >= filtered.items.length) {
|
|
3236
|
-
setSelectedIndex(0);
|
|
3237
|
-
}
|
|
3238
|
-
}, [filtered.items.length, selectedIndex]);
|
|
3239
|
-
const selectedSession = filtered.items[selectedIndex];
|
|
3240
|
-
const windowStart = Math.max(
|
|
3241
|
-
0,
|
|
3242
|
-
Math.min(selectedIndex - Math.floor(VISIBLE_SESSION_COUNT / 2), Math.max(0, filtered.items.length - VISIBLE_SESSION_COUNT))
|
|
3243
|
-
);
|
|
3244
|
-
const visibleSessions = filtered.items.slice(windowStart, windowStart + VISIBLE_SESSION_COUNT);
|
|
3245
|
-
const statusLine = scope === "all" && loadingAll ? progress ? `Loading all sessions ${progress.loaded}/${progress.total}` : "Loading all sessions..." : loadError ? loadError : filtered.error ? `Search error: ${filtered.error}` : filtered.items.length === 0 ? "0 matches" : `Showing ${windowStart + 1}-${windowStart + visibleSessions.length} of ${filtered.items.length} matches`;
|
|
3246
|
-
const beginRename = () => {
|
|
3247
|
-
if (!selectedSession || !onRenameSession) {
|
|
3248
|
-
return;
|
|
3249
|
-
}
|
|
3250
|
-
setRenamePath(selectedSession.path);
|
|
3251
|
-
setRenameValue(selectedSession.name ?? "");
|
|
3252
|
-
};
|
|
3253
|
-
const confirmRename = async () => {
|
|
3254
|
-
if (!selectedSession || !onRenameSession || renamePath !== selectedSession.path) {
|
|
3255
|
-
setRenamePath(null);
|
|
3256
|
-
return;
|
|
3257
|
-
}
|
|
3258
|
-
await onRenameSession(selectedSession, renameValue.trim());
|
|
3259
|
-
setRenamePath(null);
|
|
3260
|
-
};
|
|
3261
|
-
useInput((input, key) => {
|
|
3262
|
-
if (renamePath) {
|
|
3263
|
-
if (key.escape || key.ctrl && input === "c") {
|
|
3264
|
-
setRenamePath(null);
|
|
3265
|
-
return;
|
|
3266
|
-
}
|
|
3267
|
-
if (key.return) {
|
|
3268
|
-
void confirmRename();
|
|
3269
|
-
return;
|
|
3270
|
-
}
|
|
3271
|
-
if (key.backspace || key.delete) {
|
|
3272
|
-
setRenameValue((current) => current.slice(0, -1));
|
|
3273
|
-
return;
|
|
3274
|
-
}
|
|
3275
|
-
if (!key.ctrl && !key.meta && input) {
|
|
3276
|
-
setRenameValue((current) => current + input);
|
|
3277
|
-
}
|
|
3278
|
-
return;
|
|
3279
|
-
}
|
|
3280
|
-
if (confirmDeletePath) {
|
|
3281
|
-
if (key.escape || key.ctrl && input === "c") {
|
|
3282
|
-
setConfirmDeletePath(null);
|
|
3283
|
-
return;
|
|
3284
|
-
}
|
|
3285
|
-
if (key.return && selectedSession && onDeleteSession && confirmDeletePath === selectedSession.path) {
|
|
3286
|
-
void onDeleteSession(selectedSession);
|
|
3287
|
-
setConfirmDeletePath(null);
|
|
3288
|
-
}
|
|
3289
|
-
return;
|
|
3290
|
-
}
|
|
3291
|
-
if (key.escape || key.ctrl && input === "c") {
|
|
3292
|
-
onClose();
|
|
3293
|
-
return;
|
|
3294
|
-
}
|
|
3295
|
-
if (key.tab) {
|
|
3296
|
-
setScope((current) => current === "current" ? "all" : "current");
|
|
3297
|
-
return;
|
|
3298
|
-
}
|
|
3299
|
-
if (key.ctrl && input === "s") {
|
|
3300
|
-
setSortMode((current) => current === "recent" ? "relevance" : "recent");
|
|
3301
|
-
return;
|
|
3302
|
-
}
|
|
3303
|
-
if (key.ctrl && input === "p") {
|
|
3304
|
-
setShowPath((current) => !current);
|
|
3305
|
-
return;
|
|
3306
|
-
}
|
|
3307
|
-
if (key.ctrl && input === "r") {
|
|
3308
|
-
beginRename();
|
|
3309
|
-
return;
|
|
3310
|
-
}
|
|
3311
|
-
if (key.ctrl && input === "d") {
|
|
3312
|
-
if (selectedSession && selectedSession.path !== currentSessionPath && onDeleteSession) {
|
|
3313
|
-
setConfirmDeletePath(selectedSession.path);
|
|
3314
|
-
}
|
|
3315
|
-
return;
|
|
3316
|
-
}
|
|
3317
|
-
if (key.upArrow) {
|
|
3318
|
-
setSelectedIndex((current) => wrapSelectionIndex2(current, -1, filtered.items.length));
|
|
3319
|
-
return;
|
|
3320
|
-
}
|
|
3321
|
-
if (key.downArrow) {
|
|
3322
|
-
setSelectedIndex((current) => wrapSelectionIndex2(current, 1, filtered.items.length));
|
|
3323
|
-
return;
|
|
3324
|
-
}
|
|
3325
|
-
if (key.pageUp) {
|
|
3326
|
-
setSelectedIndex((current) => Math.max(0, current - VISIBLE_SESSION_COUNT));
|
|
3327
|
-
return;
|
|
3328
|
-
}
|
|
3329
|
-
if (key.pageDown) {
|
|
3330
|
-
setSelectedIndex((current) => Math.min(filtered.items.length - 1, current + VISIBLE_SESSION_COUNT));
|
|
3331
|
-
return;
|
|
3332
|
-
}
|
|
3333
|
-
if (key.return) {
|
|
3334
|
-
if (selectedSession) {
|
|
3335
|
-
void onSelect(selectedSession);
|
|
3336
|
-
}
|
|
3337
|
-
return;
|
|
3338
|
-
}
|
|
3339
|
-
if (key.backspace || key.delete) {
|
|
3340
|
-
setQuery((current) => current.slice(0, -1));
|
|
3341
|
-
return;
|
|
3342
|
-
}
|
|
3343
|
-
if (key.ctrl && input === "u") {
|
|
3344
|
-
setQuery("");
|
|
3345
|
-
return;
|
|
3346
|
-
}
|
|
3347
|
-
if (!key.ctrl && !key.meta && input) {
|
|
3348
|
-
setQuery((current) => current + input);
|
|
3349
|
-
}
|
|
3350
|
-
});
|
|
3351
|
-
return /* @__PURE__ */ jsxs(
|
|
3352
|
-
DialogFrame,
|
|
3353
|
-
{
|
|
3354
|
-
title: scope === "current" ? "Resume Session (Current Folder)" : "Resume Session (All)",
|
|
3355
|
-
subtitle: statusLine,
|
|
3356
|
-
footer: /* @__PURE__ */ jsx(Text, { children: 'Tab scope, Ctrl+S sort, Ctrl+P path, Ctrl+R rename, Ctrl+D delete, re:pattern regex, "phrase" exact' }),
|
|
3357
|
-
children: [
|
|
3358
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3359
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3360
|
-
"Search: ",
|
|
3361
|
-
renamePath ? "(rename active)" : query || " "
|
|
3362
|
-
] }),
|
|
3363
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3364
|
-
"Scope: ",
|
|
3365
|
-
scope,
|
|
3366
|
-
" | Sort: ",
|
|
3367
|
-
sortMode,
|
|
3368
|
-
" | Path: ",
|
|
3369
|
-
showPath ? "on" : "off"
|
|
3370
|
-
] })
|
|
3371
|
-
] }),
|
|
3372
|
-
renamePath ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
3373
|
-
/* @__PURE__ */ jsx(Text, { children: "Rename session" }),
|
|
3374
|
-
/* @__PURE__ */ jsx(Text, { children: renameValue || " " }),
|
|
3375
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Enter saves, Esc cancels" })
|
|
3376
|
-
] }) : confirmDeletePath ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: "Delete this session? Enter confirms, Esc cancels." }) }) : filtered.items.length === 0 ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: scope === "current" ? "No sessions matched in the current folder." : "No sessions matched." }) }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
3377
|
-
windowStart > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " ..." }) : null,
|
|
3378
|
-
visibleSessions.map((session, index) => {
|
|
3379
|
-
const actualIndex = windowStart + index;
|
|
3380
|
-
const selected = actualIndex === selectedIndex;
|
|
3381
|
-
const locked = session.path === currentSessionPath;
|
|
3382
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3383
|
-
/* @__PURE__ */ jsxs(Text, { color: selected ? "cyan" : "white", children: [
|
|
3384
|
-
selected ? "> " : " ",
|
|
3385
|
-
session.name ? `${session.name} ` : "",
|
|
3386
|
-
shrinkSessionId(session.id),
|
|
3387
|
-
locked ? " (current)" : ""
|
|
3388
|
-
] }),
|
|
3389
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3390
|
-
selected ? " " : " ",
|
|
3391
|
-
buildMetadata(session, showPath)
|
|
3392
|
-
] })
|
|
3393
|
-
] }, session.path);
|
|
3394
|
-
}),
|
|
3395
|
-
windowStart + visibleSessions.length < filtered.items.length ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " ..." }) : null
|
|
3396
|
-
] })
|
|
3397
|
-
]
|
|
3398
|
-
}
|
|
3399
|
-
);
|
|
3400
|
-
}
|
|
3401
|
-
|
|
3402
|
-
// src/react-ink/components/dialogs/SettingsDialog.tsx
|
|
3403
|
-
function getNextValue(values, currentValue, direction) {
|
|
3404
|
-
if (values.length === 0) {
|
|
3405
|
-
return void 0;
|
|
3406
|
-
}
|
|
3407
|
-
const currentIndex = Math.max(0, values.indexOf(currentValue));
|
|
3408
|
-
const nextIndex = (currentIndex + direction + values.length) % values.length;
|
|
3409
|
-
return values[nextIndex];
|
|
3410
|
-
}
|
|
3411
|
-
function SettingsDialog({ items, onClose }) {
|
|
3412
|
-
const [query, setQuery] = useState("");
|
|
3413
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
3414
|
-
const filteredItems = useMemo(
|
|
3415
|
-
() => items.filter(
|
|
3416
|
-
(item) => matchesSearchQuery(`${item.label} ${item.description} ${item.value} ${item.values.join(" ")}`, query)
|
|
3417
|
-
),
|
|
3418
|
-
[items, query]
|
|
3419
|
-
);
|
|
3420
|
-
useEffect(() => {
|
|
3421
|
-
setSelectedIndex(0);
|
|
3422
|
-
}, [query]);
|
|
3423
|
-
useEffect(() => {
|
|
3424
|
-
if (selectedIndex >= filteredItems.length) {
|
|
3425
|
-
setSelectedIndex(0);
|
|
3426
|
-
}
|
|
3427
|
-
}, [filteredItems.length, selectedIndex]);
|
|
3428
|
-
const maxVisible = useMemo(() => Math.max(8, (process.stdout.rows ?? 24) - 18), []);
|
|
3429
|
-
const selectedItem = filteredItems[selectedIndex];
|
|
3430
|
-
const windowStart = Math.max(
|
|
3431
|
-
0,
|
|
3432
|
-
Math.min(selectedIndex - Math.floor(maxVisible / 2), Math.max(0, filteredItems.length - maxVisible))
|
|
3433
|
-
);
|
|
3434
|
-
const visibleItems = filteredItems.slice(windowStart, windowStart + maxVisible);
|
|
3435
|
-
const cycleValue = (direction) => {
|
|
3436
|
-
const item = filteredItems[selectedIndex];
|
|
3437
|
-
if (!item) {
|
|
3438
|
-
return;
|
|
3439
|
-
}
|
|
3440
|
-
const nextValue = getNextValue(item.values, item.value, direction);
|
|
3441
|
-
if (!nextValue || nextValue === item.value) {
|
|
3442
|
-
return;
|
|
3443
|
-
}
|
|
3444
|
-
void item.onChange(nextValue);
|
|
3445
|
-
};
|
|
3446
|
-
useInput((input, key) => {
|
|
3447
|
-
if (key.escape) {
|
|
3448
|
-
onClose();
|
|
3449
|
-
return;
|
|
3450
|
-
}
|
|
3451
|
-
if (key.upArrow) {
|
|
3452
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, -1, filteredItems.length));
|
|
3453
|
-
return;
|
|
3454
|
-
}
|
|
3455
|
-
if (key.downArrow) {
|
|
3456
|
-
setSelectedIndex((current) => wrapSelectionIndex(current, 1, filteredItems.length));
|
|
3457
|
-
return;
|
|
3458
|
-
}
|
|
3459
|
-
if (key.backspace || key.delete) {
|
|
3460
|
-
setQuery((current) => current.slice(0, -1));
|
|
3461
|
-
return;
|
|
3462
|
-
}
|
|
3463
|
-
if (key.ctrl && input === "u") {
|
|
3464
|
-
setQuery("");
|
|
3465
|
-
return;
|
|
3466
|
-
}
|
|
3467
|
-
if (key.leftArrow) {
|
|
3468
|
-
cycleValue(-1);
|
|
3469
|
-
return;
|
|
3470
|
-
}
|
|
3471
|
-
if (key.rightArrow || key.return) {
|
|
3472
|
-
cycleValue(1);
|
|
3473
|
-
return;
|
|
3474
|
-
}
|
|
3475
|
-
if (!key.ctrl && !key.meta && input) {
|
|
3476
|
-
setQuery((current) => current + input);
|
|
3477
|
-
}
|
|
3478
|
-
});
|
|
3479
|
-
return /* @__PURE__ */ jsx(
|
|
3480
|
-
DialogFrame,
|
|
3481
|
-
{
|
|
3482
|
-
title: "Settings",
|
|
3483
|
-
footer: /* @__PURE__ */ jsx(Text, { children: "Type to filter, Up/Down wraps, Left/Right or Enter changes, Ctrl+U clears, Esc closes" }),
|
|
3484
|
-
children: items.length === 0 ? /* @__PURE__ */ jsx(Text, { children: "No settings are available." }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3485
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3486
|
-
"Search: ",
|
|
3487
|
-
query || " "
|
|
3488
|
-
] }),
|
|
3489
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3490
|
-
filteredItems.length,
|
|
3491
|
-
" match",
|
|
3492
|
-
filteredItems.length === 1 ? "" : "es"
|
|
3493
|
-
] }),
|
|
3494
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, flexDirection: "column", children: filteredItems.length === 0 ? /* @__PURE__ */ jsx(Text, { children: "No settings matched the current search." }) : visibleItems.map((item, index) => {
|
|
3495
|
-
const actualIndex = windowStart + index;
|
|
3496
|
-
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
3497
|
-
actualIndex === selectedIndex ? "> " : " ",
|
|
3498
|
-
item.label,
|
|
3499
|
-
": ",
|
|
3500
|
-
item.value
|
|
3501
|
-
] }, item.id);
|
|
3502
|
-
}) }),
|
|
3503
|
-
selectedItem ? /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
3504
|
-
/* @__PURE__ */ jsx(Text, { children: selectedItem.description }),
|
|
3505
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3506
|
-
"Choices: ",
|
|
3507
|
-
selectedItem.values.join(" \xB7 ")
|
|
3508
|
-
] })
|
|
3509
|
-
] }) : null
|
|
3510
|
-
] })
|
|
3511
|
-
}
|
|
3512
|
-
);
|
|
3513
|
-
}
|
|
3514
|
-
|
|
3515
|
-
// src/react-ink/components/dialogs/StartupSessionPicker.tsx
|
|
3516
|
-
var VISIBLE_SESSION_COUNT2 = 5;
|
|
3517
|
-
function metadata(session, showPath) {
|
|
3518
|
-
const parts = [
|
|
3519
|
-
formatSessionAge(session.lastModified),
|
|
3520
|
-
typeof session.messageCount === "number" ? `${session.messageCount} msg` : void 0,
|
|
3521
|
-
typeof session.size === "number" ? formatSessionSize(session.size) : void 0,
|
|
3522
|
-
session.cwd || void 0
|
|
3523
|
-
];
|
|
3524
|
-
if (showPath) {
|
|
3525
|
-
parts.push(session.path);
|
|
3526
|
-
}
|
|
3527
|
-
return parts.filter(Boolean).join(" | ");
|
|
3528
|
-
}
|
|
3529
|
-
function StartupSessionPicker({ onClose, onSelect, sessions, totalCount }) {
|
|
3530
|
-
const [query, setQuery] = useState("");
|
|
3531
|
-
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
3532
|
-
const [sortMode, setSortMode] = useState("relevance");
|
|
3533
|
-
const [showPath, setShowPath] = useState(false);
|
|
3534
|
-
const filtered = useMemo(() => filterAndSortSessions(sessions, query, sortMode), [query, sessions, sortMode]);
|
|
3535
|
-
useEffect(() => {
|
|
3536
|
-
setSelectedIndex(0);
|
|
3537
|
-
}, [query, sortMode]);
|
|
3538
|
-
useEffect(() => {
|
|
3539
|
-
if (selectedIndex >= filtered.items.length) {
|
|
3540
|
-
setSelectedIndex(0);
|
|
3541
|
-
}
|
|
3542
|
-
}, [filtered.items.length, selectedIndex]);
|
|
3543
|
-
const windowStart = Math.max(
|
|
3544
|
-
0,
|
|
3545
|
-
Math.min(selectedIndex - Math.floor(VISIBLE_SESSION_COUNT2 / 2), Math.max(0, filtered.items.length - VISIBLE_SESSION_COUNT2))
|
|
3546
|
-
);
|
|
3547
|
-
const visibleSessions = filtered.items.slice(windowStart, windowStart + VISIBLE_SESSION_COUNT2);
|
|
3548
|
-
const visibleRangeStart = filtered.items.length === 0 ? 0 : windowStart + 1;
|
|
3549
|
-
const visibleRangeEnd = filtered.items.length === 0 ? 0 : windowStart + visibleSessions.length;
|
|
3550
|
-
useInput((input, key) => {
|
|
3551
|
-
if (key.ctrl && input === "c") {
|
|
3552
|
-
onClose();
|
|
3553
|
-
return;
|
|
3554
|
-
}
|
|
3555
|
-
if (key.escape) {
|
|
3556
|
-
onClose();
|
|
3557
|
-
return;
|
|
3558
|
-
}
|
|
3559
|
-
if (key.ctrl && input === "s") {
|
|
3560
|
-
setSortMode((current) => current === "recent" ? "relevance" : "recent");
|
|
3561
|
-
return;
|
|
3562
|
-
}
|
|
3563
|
-
if (key.ctrl && input === "p") {
|
|
3564
|
-
setShowPath((current) => !current);
|
|
3565
|
-
return;
|
|
3566
|
-
}
|
|
3567
|
-
if (key.upArrow) {
|
|
3568
|
-
setSelectedIndex((current) => wrapSelectionIndex2(current, -1, filtered.items.length));
|
|
3569
|
-
return;
|
|
3570
|
-
}
|
|
3571
|
-
if (key.downArrow) {
|
|
3572
|
-
setSelectedIndex((current) => wrapSelectionIndex2(current, 1, filtered.items.length));
|
|
3573
|
-
return;
|
|
3574
|
-
}
|
|
3575
|
-
if (key.pageUp) {
|
|
3576
|
-
setSelectedIndex((current) => Math.max(0, current - VISIBLE_SESSION_COUNT2));
|
|
3577
|
-
return;
|
|
3578
|
-
}
|
|
3579
|
-
if (key.pageDown) {
|
|
3580
|
-
setSelectedIndex((current) => Math.min(filtered.items.length - 1, current + VISIBLE_SESSION_COUNT2));
|
|
3581
|
-
return;
|
|
3582
|
-
}
|
|
3583
|
-
if (key.return) {
|
|
3584
|
-
const session = filtered.items[selectedIndex];
|
|
3585
|
-
if (session) {
|
|
3586
|
-
void onSelect(session);
|
|
3587
|
-
}
|
|
3588
|
-
return;
|
|
3589
|
-
}
|
|
3590
|
-
if (key.backspace || key.delete) {
|
|
3591
|
-
setQuery((current) => current.slice(0, -1));
|
|
3592
|
-
return;
|
|
3593
|
-
}
|
|
3594
|
-
if (key.ctrl && input === "u") {
|
|
3595
|
-
setQuery("");
|
|
3596
|
-
return;
|
|
3597
|
-
}
|
|
3598
|
-
if (!key.ctrl && !key.meta && input) {
|
|
3599
|
-
setQuery((current) => current + input);
|
|
3600
|
-
}
|
|
3601
|
-
});
|
|
3602
|
-
const subtitle = totalCount > 0 ? `${totalCount} session${totalCount === 1 ? "" : "s"} available` : void 0;
|
|
3603
|
-
return /* @__PURE__ */ jsxs(
|
|
3604
|
-
DialogFrame,
|
|
3605
|
-
{
|
|
3606
|
-
title: "Resume Session",
|
|
3607
|
-
subtitle,
|
|
3608
|
-
footer: /* @__PURE__ */ jsx(Text, { children: "Type to filter, Ctrl+S sort, Ctrl+P path, Up/Down wraps, Enter selects, Ctrl+U clears, Esc closes" }),
|
|
3609
|
-
children: [
|
|
3610
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3611
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3612
|
-
"Search: ",
|
|
3613
|
-
query || " "
|
|
3614
|
-
] }),
|
|
3615
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: filtered.error ? `Search error: ${filtered.error}` : filtered.items.length === 0 ? "0 matches" : `Showing ${visibleRangeStart}-${visibleRangeEnd} of ${filtered.items.length} matches | sort:${sortMode} path:${showPath ? "on" : "off"}` })
|
|
3616
|
-
] }),
|
|
3617
|
-
filtered.items.length === 0 ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: sessions.length === 0 ? "No saved sessions were found." : "No sessions matched the current search." }) }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
3618
|
-
windowStart > 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " ..." }) : null,
|
|
3619
|
-
visibleSessions.map((session, index) => {
|
|
3620
|
-
const actualIndex = windowStart + index;
|
|
3621
|
-
const selected = actualIndex === selectedIndex;
|
|
3622
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3623
|
-
/* @__PURE__ */ jsxs(Text, { color: selected ? "cyan" : "white", children: [
|
|
3624
|
-
selected ? "> " : " ",
|
|
3625
|
-
session.name ? `${session.name} ` : "",
|
|
3626
|
-
shrinkSessionId(session.id)
|
|
3627
|
-
] }),
|
|
3628
|
-
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3629
|
-
selected ? " " : " ",
|
|
3630
|
-
metadata(session, showPath)
|
|
3631
|
-
] })
|
|
3632
|
-
] }, session.path);
|
|
3633
|
-
}),
|
|
3634
|
-
windowStart + visibleSessions.length < filtered.items.length ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: " ..." }) : null
|
|
3635
|
-
] })
|
|
3636
|
-
]
|
|
3637
|
-
}
|
|
3638
|
-
);
|
|
3639
|
-
}
|
|
3640
|
-
|
|
3641
|
-
// src/react-ink/components/dialogs/ThemeDialog.tsx
|
|
3642
|
-
function toItem(entry) {
|
|
3643
|
-
return typeof entry === "string" ? { id: entry, label: entry } : entry;
|
|
3644
|
-
}
|
|
3645
|
-
function ThemeDialog({ themes, onClose, onSelect, onHighlight }) {
|
|
3646
|
-
const items = themes.map(toItem);
|
|
3647
|
-
return /* @__PURE__ */ jsx(
|
|
3648
|
-
SelectableDialog,
|
|
3649
|
-
{
|
|
3650
|
-
title: "Themes",
|
|
3651
|
-
items,
|
|
3652
|
-
emptyText: "No themes are available.",
|
|
3653
|
-
onClose,
|
|
3654
|
-
onSelect: (item) => onSelect(item.id),
|
|
3655
|
-
onHighlight: onHighlight ? (item) => onHighlight(item.id) : void 0,
|
|
3656
|
-
getSearchText: (item) => `${item.label} ${item.description ?? ""}`,
|
|
3657
|
-
renderItem: (item, selected) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
3658
|
-
/* @__PURE__ */ jsxs(Text, { children: [
|
|
3659
|
-
selected ? "> " : " ",
|
|
3660
|
-
item.label
|
|
3661
|
-
] }),
|
|
3662
|
-
item.description ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
3663
|
-
" ",
|
|
3664
|
-
item.description
|
|
3665
|
-
] }) : null
|
|
3666
|
-
] })
|
|
3667
|
-
}
|
|
3668
|
-
);
|
|
3669
|
-
}
|
|
3670
|
-
|
|
3671
|
-
// src/react-ink/components/dialogs/TreeDialog.tsx
|
|
3672
|
-
function TreeDialog({ items, onClose, onSelect }) {
|
|
3673
|
-
return /* @__PURE__ */ jsx(
|
|
3674
|
-
SelectableDialog,
|
|
3675
|
-
{
|
|
3676
|
-
title: "Session Tree",
|
|
3677
|
-
items,
|
|
3678
|
-
emptyText: "This session does not have any navigable entries yet.",
|
|
3679
|
-
onClose,
|
|
3680
|
-
onSelect,
|
|
3681
|
-
getSearchText: (item) => item.label,
|
|
3682
|
-
renderItem: (item, selected) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
3683
|
-
selected ? "> " : " ",
|
|
3684
|
-
item.isCurrent ? "* " : "",
|
|
3685
|
-
item.label
|
|
3686
|
-
] })
|
|
3687
|
-
}
|
|
3688
|
-
);
|
|
3689
|
-
}
|
|
3690
|
-
|
|
3691
|
-
// src/react-ink/components/dialogs/UserMessageDialog.tsx
|
|
3692
|
-
function UserMessageDialog({ items, onClose, onSelect }) {
|
|
3693
|
-
return /* @__PURE__ */ jsx(
|
|
3694
|
-
SelectableDialog,
|
|
3695
|
-
{
|
|
3696
|
-
title: "Fork From Message",
|
|
3697
|
-
items,
|
|
3698
|
-
emptyText: "No user messages are available for forking.",
|
|
3699
|
-
onClose,
|
|
3700
|
-
onSelect,
|
|
3701
|
-
getSearchText: (item) => item.preview,
|
|
3702
|
-
renderItem: (item, selected) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
3703
|
-
selected ? "> " : " ",
|
|
3704
|
-
item.preview
|
|
3705
|
-
] })
|
|
3706
|
-
}
|
|
3707
|
-
);
|
|
3708
|
-
}
|
|
3709
|
-
|
|
3710
|
-
// src/react-ink/markdown/StreamingMarkdown.tsx
|
|
3711
|
-
function lastStableBoundary(content) {
|
|
3712
|
-
let boundary = 0;
|
|
3713
|
-
let inFence = false;
|
|
3714
|
-
let lineStart = 0;
|
|
3715
|
-
let sawBlankRun = false;
|
|
3716
|
-
for (let i = 0; i <= content.length; i++) {
|
|
3717
|
-
const atEnd = i === content.length;
|
|
3718
|
-
const ch = atEnd ? "\n" : content[i];
|
|
3719
|
-
if (ch !== "\n" && !atEnd) {
|
|
3720
|
-
continue;
|
|
3721
|
-
}
|
|
3722
|
-
const line = content.slice(lineStart, i);
|
|
3723
|
-
if (line.trimStart().startsWith("```")) {
|
|
3724
|
-
inFence = !inFence;
|
|
3725
|
-
sawBlankRun = false;
|
|
3726
|
-
} else if (line.trim() === "") {
|
|
3727
|
-
if (!inFence) {
|
|
3728
|
-
sawBlankRun = true;
|
|
3729
|
-
}
|
|
3730
|
-
} else {
|
|
3731
|
-
if (sawBlankRun && !inFence) {
|
|
3732
|
-
boundary = lineStart;
|
|
3733
|
-
}
|
|
3734
|
-
sawBlankRun = false;
|
|
3735
|
-
}
|
|
3736
|
-
lineStart = i + 1;
|
|
3737
|
-
if (atEnd) {
|
|
3738
|
-
break;
|
|
3739
|
-
}
|
|
3740
|
-
}
|
|
3741
|
-
return boundary;
|
|
3742
|
-
}
|
|
3743
|
-
function StreamingMarkdown({
|
|
3744
|
-
children,
|
|
3745
|
-
theme,
|
|
3746
|
-
highlightCode = true,
|
|
3747
|
-
dim = false
|
|
3748
|
-
}) {
|
|
3749
|
-
const boundary = useMemo(() => lastStableBoundary(children), [children]);
|
|
3750
|
-
const stablePrefix = useMemo(
|
|
3751
|
-
() => children.slice(0, boundary).replace(/\n+$/, ""),
|
|
3752
|
-
[children, boundary]
|
|
3753
|
-
);
|
|
3754
|
-
const unstableSuffix = useMemo(() => children.slice(boundary), [children, boundary]);
|
|
3755
|
-
const stableNode = useMemo(
|
|
3756
|
-
() => stablePrefix ? /* @__PURE__ */ jsx(Markdown, { theme, highlightCode, dim, children: stablePrefix }) : null,
|
|
3757
|
-
[stablePrefix, theme, highlightCode, dim]
|
|
3758
|
-
);
|
|
3759
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3760
|
-
stableNode,
|
|
3761
|
-
unstableSuffix ? /* @__PURE__ */ jsx(Markdown, { theme, highlightCode, dim, children: unstableSuffix }) : null
|
|
3762
|
-
] });
|
|
3763
|
-
}
|
|
3764
|
-
export {
|
|
3765
|
-
AssistantMessageView,
|
|
3766
|
-
BashMessageView,
|
|
3767
|
-
BranchSummaryMessageView,
|
|
3768
|
-
CHANGE_THRESHOLD,
|
|
3769
|
-
COLLAPSED_CONTENT_LINES,
|
|
3770
|
-
CONTEXT_LINES,
|
|
3771
|
-
ChangelogBlock,
|
|
3772
|
-
CompactionMessageView,
|
|
3773
|
-
CustomMessageView,
|
|
3774
|
-
DialogFrame,
|
|
3775
|
-
Diff,
|
|
3776
|
-
DisplayBlockView,
|
|
3777
|
-
EXPANDED_CONTENT_LINES,
|
|
3778
|
-
Footer,
|
|
3779
|
-
LoginDialog,
|
|
3780
|
-
Markdown,
|
|
3781
|
-
MarkdownTable,
|
|
3782
|
-
MessageList,
|
|
3783
|
-
MessageRow,
|
|
3784
|
-
ModelDialog,
|
|
3785
|
-
OAuthDialog,
|
|
3786
|
-
ScopedModelsDialog,
|
|
3787
|
-
SelectableDialog,
|
|
3788
|
-
SessionDialog,
|
|
3789
|
-
SettingsDialog,
|
|
3790
|
-
SkillInvocationMessage,
|
|
3791
|
-
StartupSessionPicker,
|
|
3792
|
-
StatusLine,
|
|
3793
|
-
StreamingMarkdown,
|
|
3794
|
-
TaskPanel,
|
|
3795
|
-
ThemeDialog,
|
|
3796
|
-
ToolCallMessage,
|
|
3797
|
-
ToolEventBlock,
|
|
3798
|
-
ToolResultBlock,
|
|
3799
|
-
TreeDialog,
|
|
3800
|
-
UserMessageDialog,
|
|
3801
|
-
UserMessageView,
|
|
3802
|
-
buildStructuredDiff,
|
|
3803
|
-
cachedLexer,
|
|
3804
|
-
configureMarked,
|
|
3805
|
-
createHighlighter,
|
|
3806
|
-
createThemeAdapter,
|
|
3807
|
-
describeToolCall,
|
|
3808
|
-
describeToolExecution,
|
|
3809
|
-
describeToolResult,
|
|
3810
|
-
describeToolSource,
|
|
3811
|
-
extractMessagePreview,
|
|
3812
|
-
extractToolText,
|
|
3813
|
-
formatCustomContent,
|
|
3814
|
-
formatMessageTimestamp,
|
|
3815
|
-
formatToken,
|
|
3816
|
-
formatToolCall,
|
|
3817
|
-
formatToolResult,
|
|
3818
|
-
formatUserContent,
|
|
3819
|
-
getListNumber,
|
|
3820
|
-
hasMarkdownSyntax,
|
|
3821
|
-
highlightByPath,
|
|
3822
|
-
languageFromPath,
|
|
3823
|
-
matchesSearchQuery,
|
|
3824
|
-
padAligned,
|
|
3825
|
-
parseSkillInvocation,
|
|
3826
|
-
previewMultiline,
|
|
3827
|
-
previewText,
|
|
3828
|
-
safeStringify,
|
|
3829
|
-
splitAssistantMessage,
|
|
3830
|
-
statusColorKey,
|
|
3831
|
-
stringWidth,
|
|
3832
|
-
wordDiffLine,
|
|
3833
|
-
wrapSelectionIndex
|
|
3834
|
-
};
|