@defai.digital/ax-cli 4.4.6 → 4.4.10
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/bin/ax-cli +1 -5
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +158 -9
- package/dist/index.js.map +1 -1
- package/dist/setup.d.ts +27 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +591 -0
- package/dist/setup.js.map +1 -0
- package/package.json +43 -135
- package/LICENSE +0 -22
- package/README.md +0 -387
- package/config-defaults/messages.yaml +0 -75
- package/config-defaults/models.yaml +0 -57
- package/config-defaults/prompts.yaml +0 -948
- package/config-defaults/settings.yaml +0 -157
- package/dist/agent/agent-executor.d.ts +0 -61
- package/dist/agent/agent-executor.js +0 -194
- package/dist/agent/agent-executor.js.map +0 -1
- package/dist/agent/agent-router.d.ts +0 -68
- package/dist/agent/agent-router.js +0 -242
- package/dist/agent/agent-router.js.map +0 -1
- package/dist/agent/context-manager.d.ts +0 -122
- package/dist/agent/context-manager.js +0 -406
- package/dist/agent/context-manager.js.map +0 -1
- package/dist/agent/core/index.d.ts +0 -8
- package/dist/agent/core/index.js +0 -9
- package/dist/agent/core/index.js.map +0 -1
- package/dist/agent/core/types.d.ts +0 -92
- package/dist/agent/core/types.js +0 -11
- package/dist/agent/core/types.js.map +0 -1
- package/dist/agent/dependency-resolver.d.ts +0 -90
- package/dist/agent/dependency-resolver.js +0 -366
- package/dist/agent/dependency-resolver.js.map +0 -1
- package/dist/agent/execution/index.d.ts +0 -9
- package/dist/agent/execution/index.js +0 -9
- package/dist/agent/execution/index.js.map +0 -1
- package/dist/agent/execution/tool-executor.d.ts +0 -93
- package/dist/agent/execution/tool-executor.js +0 -552
- package/dist/agent/execution/tool-executor.js.map +0 -1
- package/dist/agent/index.d.ts +0 -14
- package/dist/agent/index.js +0 -145
- package/dist/agent/index.js.map +0 -1
- package/dist/agent/llm-agent.d.ts +0 -368
- package/dist/agent/llm-agent.js +0 -1931
- package/dist/agent/llm-agent.js.map +0 -1
- package/dist/agent/loop-detector.d.ts +0 -72
- package/dist/agent/loop-detector.js +0 -335
- package/dist/agent/loop-detector.js.map +0 -1
- package/dist/agent/parallel-tools.d.ts +0 -69
- package/dist/agent/parallel-tools.js +0 -188
- package/dist/agent/parallel-tools.js.map +0 -1
- package/dist/agent/planning/index.d.ts +0 -9
- package/dist/agent/planning/index.js +0 -9
- package/dist/agent/planning/index.js.map +0 -1
- package/dist/agent/planning/plan-executor.d.ts +0 -79
- package/dist/agent/planning/plan-executor.js +0 -240
- package/dist/agent/planning/plan-executor.js.map +0 -1
- package/dist/agent/progress-tracker.d.ts +0 -94
- package/dist/agent/progress-tracker.js +0 -225
- package/dist/agent/progress-tracker.js.map +0 -1
- package/dist/agent/specialized/analysis-agent.d.ts +0 -11
- package/dist/agent/specialized/analysis-agent.js +0 -24
- package/dist/agent/specialized/analysis-agent.js.map +0 -1
- package/dist/agent/specialized/debug-agent.d.ts +0 -11
- package/dist/agent/specialized/debug-agent.js +0 -46
- package/dist/agent/specialized/debug-agent.js.map +0 -1
- package/dist/agent/specialized/documentation-agent.d.ts +0 -11
- package/dist/agent/specialized/documentation-agent.js +0 -24
- package/dist/agent/specialized/documentation-agent.js.map +0 -1
- package/dist/agent/specialized/index.d.ts +0 -11
- package/dist/agent/specialized/index.js +0 -12
- package/dist/agent/specialized/index.js.map +0 -1
- package/dist/agent/specialized/performance-agent.d.ts +0 -11
- package/dist/agent/specialized/performance-agent.js +0 -24
- package/dist/agent/specialized/performance-agent.js.map +0 -1
- package/dist/agent/specialized/refactoring-agent.d.ts +0 -11
- package/dist/agent/specialized/refactoring-agent.js +0 -24
- package/dist/agent/specialized/refactoring-agent.js.map +0 -1
- package/dist/agent/specialized/testing-agent.d.ts +0 -11
- package/dist/agent/specialized/testing-agent.js +0 -24
- package/dist/agent/specialized/testing-agent.js.map +0 -1
- package/dist/agent/status-reporter.d.ts +0 -114
- package/dist/agent/status-reporter.js +0 -335
- package/dist/agent/status-reporter.js.map +0 -1
- package/dist/agent/streaming/index.d.ts +0 -9
- package/dist/agent/streaming/index.js +0 -9
- package/dist/agent/streaming/index.js.map +0 -1
- package/dist/agent/streaming/stream-handler.d.ts +0 -62
- package/dist/agent/streaming/stream-handler.js +0 -217
- package/dist/agent/streaming/stream-handler.js.map +0 -1
- package/dist/agent/subagent-orchestrator.d.ts +0 -166
- package/dist/agent/subagent-orchestrator.js +0 -487
- package/dist/agent/subagent-orchestrator.js.map +0 -1
- package/dist/agent/subagent-types.d.ts +0 -261
- package/dist/agent/subagent-types.js +0 -257
- package/dist/agent/subagent-types.js.map +0 -1
- package/dist/agent/subagent.d.ts +0 -116
- package/dist/agent/subagent.js +0 -507
- package/dist/agent/subagent.js.map +0 -1
- package/dist/checkpoint/index.d.ts +0 -9
- package/dist/checkpoint/index.js +0 -11
- package/dist/checkpoint/index.js.map +0 -1
- package/dist/checkpoint/manager.d.ts +0 -101
- package/dist/checkpoint/manager.js +0 -407
- package/dist/checkpoint/manager.js.map +0 -1
- package/dist/checkpoint/storage.d.ts +0 -39
- package/dist/checkpoint/storage.js +0 -350
- package/dist/checkpoint/storage.js.map +0 -1
- package/dist/checkpoint/types.d.ts +0 -111
- package/dist/checkpoint/types.js +0 -17
- package/dist/checkpoint/types.js.map +0 -1
- package/dist/commands/cache.d.ts +0 -7
- package/dist/commands/cache.js +0 -284
- package/dist/commands/cache.js.map +0 -1
- package/dist/commands/custom-commands.d.ts +0 -77
- package/dist/commands/custom-commands.js +0 -251
- package/dist/commands/custom-commands.js.map +0 -1
- package/dist/commands/design.d.ts +0 -18
- package/dist/commands/design.js +0 -511
- package/dist/commands/design.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -6
- package/dist/commands/doctor.js +0 -773
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/frontend.d.ts +0 -9
- package/dist/commands/frontend.js +0 -645
- package/dist/commands/frontend.js.map +0 -1
- package/dist/commands/init/wizard.d.ts +0 -55
- package/dist/commands/init/wizard.js +0 -189
- package/dist/commands/init/wizard.js.map +0 -1
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.js +0 -195
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/mcp-migrate.d.ts +0 -9
- package/dist/commands/mcp-migrate.js +0 -175
- package/dist/commands/mcp-migrate.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -2
- package/dist/commands/mcp.js +0 -1292
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/memory.d.ts +0 -6
- package/dist/commands/memory.js +0 -555
- package/dist/commands/memory.js.map +0 -1
- package/dist/commands/models.d.ts +0 -5
- package/dist/commands/models.js +0 -213
- package/dist/commands/models.js.map +0 -1
- package/dist/commands/plan.d.ts +0 -43
- package/dist/commands/plan.js +0 -362
- package/dist/commands/plan.js.map +0 -1
- package/dist/commands/rewind.d.ts +0 -19
- package/dist/commands/rewind.js +0 -221
- package/dist/commands/rewind.js.map +0 -1
- package/dist/commands/setup.d.ts +0 -14
- package/dist/commands/setup.js +0 -733
- package/dist/commands/setup.js.map +0 -1
- package/dist/commands/status.d.ts +0 -7
- package/dist/commands/status.js +0 -437
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/templates.d.ts +0 -5
- package/dist/commands/templates.js +0 -245
- package/dist/commands/templates.js.map +0 -1
- package/dist/commands/update.d.ts +0 -49
- package/dist/commands/update.js +0 -366
- package/dist/commands/update.js.map +0 -1
- package/dist/commands/usage.d.ts +0 -8
- package/dist/commands/usage.js +0 -264
- package/dist/commands/usage.js.map +0 -1
- package/dist/commands/vscode.d.ts +0 -7
- package/dist/commands/vscode.js +0 -419
- package/dist/commands/vscode.js.map +0 -1
- package/dist/constants.d.ts +0 -236
- package/dist/constants.js +0 -288
- package/dist/constants.js.map +0 -1
- package/dist/design/figma-alias.d.ts +0 -170
- package/dist/design/figma-alias.js +0 -577
- package/dist/design/figma-alias.js.map +0 -1
- package/dist/design/figma-audit.d.ts +0 -40
- package/dist/design/figma-audit.js +0 -383
- package/dist/design/figma-audit.js.map +0 -1
- package/dist/design/figma-client.d.ts +0 -131
- package/dist/design/figma-client.js +0 -369
- package/dist/design/figma-client.js.map +0 -1
- package/dist/design/figma-map.d.ts +0 -29
- package/dist/design/figma-map.js +0 -346
- package/dist/design/figma-map.js.map +0 -1
- package/dist/design/figma-tokens.d.ts +0 -73
- package/dist/design/figma-tokens.js +0 -448
- package/dist/design/figma-tokens.js.map +0 -1
- package/dist/design/index.d.ts +0 -13
- package/dist/design/index.js +0 -20
- package/dist/design/index.js.map +0 -1
- package/dist/design/types.d.ts +0 -98
- package/dist/design/types.js +0 -9
- package/dist/design/types.js.map +0 -1
- package/dist/hooks/hook-runner.d.ts +0 -142
- package/dist/hooks/hook-runner.js +0 -436
- package/dist/hooks/hook-runner.js.map +0 -1
- package/dist/hooks/index.d.ts +0 -9
- package/dist/hooks/index.js +0 -10
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/manager.d.ts +0 -84
- package/dist/hooks/manager.js +0 -348
- package/dist/hooks/manager.js.map +0 -1
- package/dist/hooks/types.d.ts +0 -134
- package/dist/hooks/types.js +0 -9
- package/dist/hooks/types.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/ipc/index.d.ts +0 -9
- package/dist/ipc/index.js +0 -10
- package/dist/ipc/index.js.map +0 -1
- package/dist/ipc/vscode-client.d.ts +0 -200
- package/dist/ipc/vscode-client.js +0 -495
- package/dist/ipc/vscode-client.js.map +0 -1
- package/dist/llm/client.d.ts +0 -205
- package/dist/llm/client.js +0 -735
- package/dist/llm/client.js.map +0 -1
- package/dist/llm/tools.d.ts +0 -102
- package/dist/llm/tools.js +0 -275
- package/dist/llm/tools.js.map +0 -1
- package/dist/llm/types.d.ts +0 -428
- package/dist/llm/types.js +0 -194
- package/dist/llm/types.js.map +0 -1
- package/dist/mcp/automatosx-auto-discovery.d.ts +0 -66
- package/dist/mcp/automatosx-auto-discovery.js +0 -169
- package/dist/mcp/automatosx-auto-discovery.js.map +0 -1
- package/dist/mcp/automatosx-loader.d.ts +0 -99
- package/dist/mcp/automatosx-loader.js +0 -250
- package/dist/mcp/automatosx-loader.js.map +0 -1
- package/dist/mcp/cancellation.d.ts +0 -182
- package/dist/mcp/cancellation.js +0 -275
- package/dist/mcp/cancellation.js.map +0 -1
- package/dist/mcp/client-v2.d.ts +0 -500
- package/dist/mcp/client-v2.js +0 -1433
- package/dist/mcp/client-v2.js.map +0 -1
- package/dist/mcp/client.d.ts +0 -170
- package/dist/mcp/client.js +0 -232
- package/dist/mcp/client.js.map +0 -1
- package/dist/mcp/config-detector.d.ts +0 -90
- package/dist/mcp/config-detector.js +0 -250
- package/dist/mcp/config-detector.js.map +0 -1
- package/dist/mcp/config-migrator.d.ts +0 -68
- package/dist/mcp/config-migrator.js +0 -291
- package/dist/mcp/config-migrator.js.map +0 -1
- package/dist/mcp/config.d.ts +0 -24
- package/dist/mcp/config.js +0 -273
- package/dist/mcp/config.js.map +0 -1
- package/dist/mcp/constants.d.ts +0 -66
- package/dist/mcp/constants.js +0 -85
- package/dist/mcp/constants.js.map +0 -1
- package/dist/mcp/content-length-transport.d.ts +0 -106
- package/dist/mcp/content-length-transport.js +0 -413
- package/dist/mcp/content-length-transport.js.map +0 -1
- package/dist/mcp/debug.d.ts +0 -211
- package/dist/mcp/debug.js +0 -404
- package/dist/mcp/debug.js.map +0 -1
- package/dist/mcp/error-formatter.d.ts +0 -40
- package/dist/mcp/error-formatter.js +0 -207
- package/dist/mcp/error-formatter.js.map +0 -1
- package/dist/mcp/error-remediation.d.ts +0 -45
- package/dist/mcp/error-remediation.js +0 -291
- package/dist/mcp/error-remediation.js.map +0 -1
- package/dist/mcp/health.d.ts +0 -120
- package/dist/mcp/health.js +0 -267
- package/dist/mcp/health.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -56
- package/dist/mcp/index.js +0 -89
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/invariants.d.ts +0 -141
- package/dist/mcp/invariants.js +0 -243
- package/dist/mcp/invariants.js.map +0 -1
- package/dist/mcp/mutex-safe.d.ts +0 -151
- package/dist/mcp/mutex-safe.js +0 -260
- package/dist/mcp/mutex-safe.js.map +0 -1
- package/dist/mcp/progress.d.ts +0 -155
- package/dist/mcp/progress.js +0 -252
- package/dist/mcp/progress.js.map +0 -1
- package/dist/mcp/prompts.d.ts +0 -68
- package/dist/mcp/prompts.js +0 -129
- package/dist/mcp/prompts.js.map +0 -1
- package/dist/mcp/provider-mcp-loader.d.ts +0 -130
- package/dist/mcp/provider-mcp-loader.js +0 -292
- package/dist/mcp/provider-mcp-loader.js.map +0 -1
- package/dist/mcp/reconnection.d.ts +0 -101
- package/dist/mcp/reconnection.js +0 -253
- package/dist/mcp/reconnection.js.map +0 -1
- package/dist/mcp/registry.d.ts +0 -75
- package/dist/mcp/registry.js +0 -276
- package/dist/mcp/registry.js.map +0 -1
- package/dist/mcp/resources.d.ts +0 -58
- package/dist/mcp/resources.js +0 -144
- package/dist/mcp/resources.js.map +0 -1
- package/dist/mcp/schema-validator.d.ts +0 -82
- package/dist/mcp/schema-validator.js +0 -161
- package/dist/mcp/schema-validator.js.map +0 -1
- package/dist/mcp/ssrf-protection.d.ts +0 -86
- package/dist/mcp/ssrf-protection.js +0 -311
- package/dist/mcp/ssrf-protection.js.map +0 -1
- package/dist/mcp/subscriptions.d.ts +0 -168
- package/dist/mcp/subscriptions.js +0 -248
- package/dist/mcp/subscriptions.js.map +0 -1
- package/dist/mcp/templates.d.ts +0 -52
- package/dist/mcp/templates.js +0 -627
- package/dist/mcp/templates.js.map +0 -1
- package/dist/mcp/transports.d.ts +0 -80
- package/dist/mcp/transports.js +0 -237
- package/dist/mcp/transports.js.map +0 -1
- package/dist/mcp/type-safety.d.ts +0 -225
- package/dist/mcp/type-safety.js +0 -237
- package/dist/mcp/type-safety.js.map +0 -1
- package/dist/mcp/validation.d.ts +0 -29
- package/dist/mcp/validation.js +0 -339
- package/dist/mcp/validation.js.map +0 -1
- package/dist/mcp/zai-detector.d.ts +0 -63
- package/dist/mcp/zai-detector.js +0 -193
- package/dist/mcp/zai-detector.js.map +0 -1
- package/dist/mcp/zai-templates.d.ts +0 -90
- package/dist/mcp/zai-templates.js +0 -157
- package/dist/mcp/zai-templates.js.map +0 -1
- package/dist/memory/context-generator.d.ts +0 -84
- package/dist/memory/context-generator.js +0 -546
- package/dist/memory/context-generator.js.map +0 -1
- package/dist/memory/context-injector.d.ts +0 -97
- package/dist/memory/context-injector.js +0 -159
- package/dist/memory/context-injector.js.map +0 -1
- package/dist/memory/context-store.d.ts +0 -103
- package/dist/memory/context-store.js +0 -264
- package/dist/memory/context-store.js.map +0 -1
- package/dist/memory/index.d.ts +0 -43
- package/dist/memory/index.js +0 -49
- package/dist/memory/index.js.map +0 -1
- package/dist/memory/provider-context-store.d.ts +0 -127
- package/dist/memory/provider-context-store.js +0 -385
- package/dist/memory/provider-context-store.js.map +0 -1
- package/dist/memory/schemas.d.ts +0 -118
- package/dist/memory/schemas.js +0 -106
- package/dist/memory/schemas.js.map +0 -1
- package/dist/memory/stats-collector.d.ts +0 -73
- package/dist/memory/stats-collector.js +0 -170
- package/dist/memory/stats-collector.js.map +0 -1
- package/dist/memory/types.d.ts +0 -177
- package/dist/memory/types.js +0 -73
- package/dist/memory/types.js.map +0 -1
- package/dist/permissions/index.d.ts +0 -6
- package/dist/permissions/index.js +0 -7
- package/dist/permissions/index.js.map +0 -1
- package/dist/permissions/permission-manager.d.ts +0 -149
- package/dist/permissions/permission-manager.js +0 -410
- package/dist/permissions/permission-manager.js.map +0 -1
- package/dist/planner/dependency-resolver.d.ts +0 -72
- package/dist/planner/dependency-resolver.js +0 -272
- package/dist/planner/dependency-resolver.js.map +0 -1
- package/dist/planner/index.d.ts +0 -12
- package/dist/planner/index.js +0 -28
- package/dist/planner/index.js.map +0 -1
- package/dist/planner/plan-generator.d.ts +0 -74
- package/dist/planner/plan-generator.js +0 -244
- package/dist/planner/plan-generator.js.map +0 -1
- package/dist/planner/plan-storage.d.ts +0 -113
- package/dist/planner/plan-storage.js +0 -398
- package/dist/planner/plan-storage.js.map +0 -1
- package/dist/planner/prompts/planning-prompt.d.ts +0 -62
- package/dist/planner/prompts/planning-prompt.js +0 -414
- package/dist/planner/prompts/planning-prompt.js.map +0 -1
- package/dist/planner/task-planner.d.ts +0 -139
- package/dist/planner/task-planner.js +0 -532
- package/dist/planner/task-planner.js.map +0 -1
- package/dist/planner/token-estimator.d.ts +0 -63
- package/dist/planner/token-estimator.js +0 -295
- package/dist/planner/token-estimator.js.map +0 -1
- package/dist/planner/types.d.ts +0 -425
- package/dist/planner/types.js +0 -213
- package/dist/planner/types.js.map +0 -1
- package/dist/provider/config.d.ts +0 -227
- package/dist/provider/config.js +0 -430
- package/dist/provider/config.js.map +0 -1
- package/dist/schemas/api-schemas.d.ts +0 -45
- package/dist/schemas/api-schemas.js +0 -129
- package/dist/schemas/api-schemas.js.map +0 -1
- package/dist/schemas/confirmation-schemas.d.ts +0 -39
- package/dist/schemas/confirmation-schemas.js +0 -48
- package/dist/schemas/confirmation-schemas.js.map +0 -1
- package/dist/schemas/index-unified.d.ts +0 -12
- package/dist/schemas/index-unified.js +0 -17
- package/dist/schemas/index-unified.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -83
- package/dist/schemas/index.js +0 -139
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/settings-schemas.d.ts +0 -186
- package/dist/schemas/settings-schemas.js +0 -324
- package/dist/schemas/settings-schemas.js.map +0 -1
- package/dist/schemas/tool-schemas.d.ts +0 -127
- package/dist/schemas/tool-schemas.js +0 -84
- package/dist/schemas/tool-schemas.js.map +0 -1
- package/dist/schemas/yaml-schemas.d.ts +0 -231
- package/dist/schemas/yaml-schemas.js +0 -199
- package/dist/schemas/yaml-schemas.js.map +0 -1
- package/dist/sdk/errors.d.ts +0 -100
- package/dist/sdk/errors.js +0 -138
- package/dist/sdk/errors.js.map +0 -1
- package/dist/sdk/index.d.ts +0 -901
- package/dist/sdk/index.js +0 -1272
- package/dist/sdk/index.js.map +0 -1
- package/dist/sdk/progress-reporter.d.ts +0 -123
- package/dist/sdk/progress-reporter.js +0 -220
- package/dist/sdk/progress-reporter.js.map +0 -1
- package/dist/sdk/testing.d.ts +0 -427
- package/dist/sdk/testing.js +0 -725
- package/dist/sdk/testing.js.map +0 -1
- package/dist/sdk/tool-registry.d.ts +0 -194
- package/dist/sdk/tool-registry.js +0 -326
- package/dist/sdk/tool-registry.js.map +0 -1
- package/dist/sdk/types.d.ts +0 -53
- package/dist/sdk/types.js +0 -8
- package/dist/sdk/types.js.map +0 -1
- package/dist/sdk/unified-logger.d.ts +0 -173
- package/dist/sdk/unified-logger.js +0 -327
- package/dist/sdk/unified-logger.js.map +0 -1
- package/dist/sdk/version.d.ts +0 -163
- package/dist/sdk/version.js +0 -205
- package/dist/sdk/version.js.map +0 -1
- package/dist/tools/ask-user.d.ts +0 -126
- package/dist/tools/ask-user.js +0 -290
- package/dist/tools/ask-user.js.map +0 -1
- package/dist/tools/ax-agent.d.ts +0 -71
- package/dist/tools/ax-agent.js +0 -283
- package/dist/tools/ax-agent.js.map +0 -1
- package/dist/tools/bash-output.d.ts +0 -25
- package/dist/tools/bash-output.js +0 -146
- package/dist/tools/bash-output.js.map +0 -1
- package/dist/tools/bash.d.ts +0 -67
- package/dist/tools/bash.js +0 -522
- package/dist/tools/bash.js.map +0 -1
- package/dist/tools/confirmation-tool.d.ts +0 -16
- package/dist/tools/confirmation-tool.js +0 -76
- package/dist/tools/confirmation-tool.js.map +0 -1
- package/dist/tools/definitions/ask-user.d.ts +0 -8
- package/dist/tools/definitions/ask-user.js +0 -168
- package/dist/tools/definitions/ask-user.js.map +0 -1
- package/dist/tools/definitions/ax-agent.d.ts +0 -8
- package/dist/tools/definitions/ax-agent.js +0 -276
- package/dist/tools/definitions/ax-agent.js.map +0 -1
- package/dist/tools/definitions/bash-output.d.ts +0 -7
- package/dist/tools/definitions/bash-output.js +0 -78
- package/dist/tools/definitions/bash-output.js.map +0 -1
- package/dist/tools/definitions/bash.d.ts +0 -8
- package/dist/tools/definitions/bash.js +0 -152
- package/dist/tools/definitions/bash.js.map +0 -1
- package/dist/tools/definitions/create-file.d.ts +0 -7
- package/dist/tools/definitions/create-file.js +0 -129
- package/dist/tools/definitions/create-file.js.map +0 -1
- package/dist/tools/definitions/design.d.ts +0 -12
- package/dist/tools/definitions/design.js +0 -368
- package/dist/tools/definitions/design.js.map +0 -1
- package/dist/tools/definitions/index.d.ts +0 -49
- package/dist/tools/definitions/index.js +0 -87
- package/dist/tools/definitions/index.js.map +0 -1
- package/dist/tools/definitions/multi-edit.d.ts +0 -7
- package/dist/tools/definitions/multi-edit.js +0 -123
- package/dist/tools/definitions/multi-edit.js.map +0 -1
- package/dist/tools/definitions/search.d.ts +0 -7
- package/dist/tools/definitions/search.js +0 -159
- package/dist/tools/definitions/search.js.map +0 -1
- package/dist/tools/definitions/str-replace-editor.d.ts +0 -7
- package/dist/tools/definitions/str-replace-editor.js +0 -145
- package/dist/tools/definitions/str-replace-editor.js.map +0 -1
- package/dist/tools/definitions/todo.d.ts +0 -8
- package/dist/tools/definitions/todo.js +0 -261
- package/dist/tools/definitions/todo.js.map +0 -1
- package/dist/tools/definitions/view-file.d.ts +0 -7
- package/dist/tools/definitions/view-file.js +0 -111
- package/dist/tools/definitions/view-file.js.map +0 -1
- package/dist/tools/design-tool.d.ts +0 -68
- package/dist/tools/design-tool.js +0 -299
- package/dist/tools/design-tool.js.map +0 -1
- package/dist/tools/format-generators.d.ts +0 -62
- package/dist/tools/format-generators.js +0 -291
- package/dist/tools/format-generators.js.map +0 -1
- package/dist/tools/index.d.ts +0 -8
- package/dist/tools/index.js +0 -11
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/priority-registry.d.ts +0 -124
- package/dist/tools/priority-registry.js +0 -401
- package/dist/tools/priority-registry.js.map +0 -1
- package/dist/tools/priority.d.ts +0 -158
- package/dist/tools/priority.js +0 -350
- package/dist/tools/priority.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -146
- package/dist/tools/registry.js +0 -171
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/search.d.ts +0 -85
- package/dist/tools/search.js +0 -430
- package/dist/tools/search.js.map +0 -1
- package/dist/tools/text-editor.d.ts +0 -87
- package/dist/tools/text-editor.js +0 -1369
- package/dist/tools/text-editor.js.map +0 -1
- package/dist/tools/todo-tool.d.ts +0 -20
- package/dist/tools/todo-tool.js +0 -186
- package/dist/tools/todo-tool.js.map +0 -1
- package/dist/tools/types.d.ts +0 -175
- package/dist/tools/types.js +0 -11
- package/dist/tools/types.js.map +0 -1
- package/dist/types/index.d.ts +0 -30
- package/dist/types/index.js +0 -2
- package/dist/types/index.js.map +0 -1
- package/dist/types/project-analysis.d.ts +0 -84
- package/dist/types/project-analysis.js +0 -5
- package/dist/types/project-analysis.js.map +0 -1
- package/dist/types/template.d.ts +0 -53
- package/dist/types/template.js +0 -5
- package/dist/types/template.js.map +0 -1
- package/dist/ui/app.d.ts +0 -7
- package/dist/ui/app.js +0 -102
- package/dist/ui/app.js.map +0 -1
- package/dist/ui/components/api-key-input.d.ts +0 -7
- package/dist/ui/components/api-key-input.js +0 -92
- package/dist/ui/components/api-key-input.js.map +0 -1
- package/dist/ui/components/chat-history.d.ts +0 -12
- package/dist/ui/components/chat-history.js +0 -391
- package/dist/ui/components/chat-history.js.map +0 -1
- package/dist/ui/components/chat-input.d.ts +0 -13
- package/dist/ui/components/chat-input.js +0 -179
- package/dist/ui/components/chat-input.js.map +0 -1
- package/dist/ui/components/chat-interface.d.ts +0 -11
- package/dist/ui/components/chat-interface.js +0 -830
- package/dist/ui/components/chat-interface.js.map +0 -1
- package/dist/ui/components/collapsible-tool-result.d.ts +0 -42
- package/dist/ui/components/collapsible-tool-result.js +0 -216
- package/dist/ui/components/collapsible-tool-result.js.map +0 -1
- package/dist/ui/components/command-suggestions.d.ts +0 -29
- package/dist/ui/components/command-suggestions.js +0 -88
- package/dist/ui/components/command-suggestions.js.map +0 -1
- package/dist/ui/components/confirmation-dialog.d.ts +0 -11
- package/dist/ui/components/confirmation-dialog.js +0 -100
- package/dist/ui/components/confirmation-dialog.js.map +0 -1
- package/dist/ui/components/context-breakdown.d.ts +0 -23
- package/dist/ui/components/context-breakdown.js +0 -124
- package/dist/ui/components/context-breakdown.js.map +0 -1
- package/dist/ui/components/diff-renderer.d.ts +0 -13
- package/dist/ui/components/diff-renderer.js +0 -192
- package/dist/ui/components/diff-renderer.js.map +0 -1
- package/dist/ui/components/index.d.ts +0 -18
- package/dist/ui/components/index.js +0 -20
- package/dist/ui/components/index.js.map +0 -1
- package/dist/ui/components/keyboard-help.d.ts +0 -17
- package/dist/ui/components/keyboard-help.js +0 -122
- package/dist/ui/components/keyboard-help.js.map +0 -1
- package/dist/ui/components/keyboard-hints.d.ts +0 -35
- package/dist/ui/components/keyboard-hints.js +0 -142
- package/dist/ui/components/keyboard-hints.js.map +0 -1
- package/dist/ui/components/loading-spinner.d.ts +0 -9
- package/dist/ui/components/loading-spinner.js +0 -120
- package/dist/ui/components/loading-spinner.js.map +0 -1
- package/dist/ui/components/mcp-dashboard.d.ts +0 -15
- package/dist/ui/components/mcp-dashboard.js +0 -520
- package/dist/ui/components/mcp-dashboard.js.map +0 -1
- package/dist/ui/components/mcp-status.d.ts +0 -5
- package/dist/ui/components/mcp-status.js +0 -58
- package/dist/ui/components/mcp-status.js.map +0 -1
- package/dist/ui/components/model-selection.d.ts +0 -12
- package/dist/ui/components/model-selection.js +0 -17
- package/dist/ui/components/model-selection.js.map +0 -1
- package/dist/ui/components/phase-progress.d.ts +0 -21
- package/dist/ui/components/phase-progress.js +0 -185
- package/dist/ui/components/phase-progress.js.map +0 -1
- package/dist/ui/components/question-dialog.d.ts +0 -17
- package/dist/ui/components/question-dialog.js +0 -181
- package/dist/ui/components/question-dialog.js.map +0 -1
- package/dist/ui/components/quick-actions.d.ts +0 -12
- package/dist/ui/components/quick-actions.js +0 -171
- package/dist/ui/components/quick-actions.js.map +0 -1
- package/dist/ui/components/reasoning-display.d.ts +0 -36
- package/dist/ui/components/reasoning-display.js +0 -46
- package/dist/ui/components/reasoning-display.js.map +0 -1
- package/dist/ui/components/status-bar.d.ts +0 -47
- package/dist/ui/components/status-bar.js +0 -310
- package/dist/ui/components/status-bar.js.map +0 -1
- package/dist/ui/components/subagent-monitor.d.ts +0 -41
- package/dist/ui/components/subagent-monitor.js +0 -122
- package/dist/ui/components/subagent-monitor.js.map +0 -1
- package/dist/ui/components/toast-notification.d.ts +0 -197
- package/dist/ui/components/toast-notification.js +0 -190
- package/dist/ui/components/toast-notification.js.map +0 -1
- package/dist/ui/components/tool-group-display.d.ts +0 -19
- package/dist/ui/components/tool-group-display.js +0 -222
- package/dist/ui/components/tool-group-display.js.map +0 -1
- package/dist/ui/components/virtualized-chat-history.d.ts +0 -33
- package/dist/ui/components/virtualized-chat-history.js +0 -182
- package/dist/ui/components/virtualized-chat-history.js.map +0 -1
- package/dist/ui/components/welcome-panel.d.ts +0 -11
- package/dist/ui/components/welcome-panel.js +0 -225
- package/dist/ui/components/welcome-panel.js.map +0 -1
- package/dist/ui/hooks/use-chat-reducer.d.ts +0 -69
- package/dist/ui/hooks/use-chat-reducer.js +0 -118
- package/dist/ui/hooks/use-chat-reducer.js.map +0 -1
- package/dist/ui/hooks/use-enhanced-input.d.ts +0 -53
- package/dist/ui/hooks/use-enhanced-input.js +0 -1275
- package/dist/ui/hooks/use-enhanced-input.js.map +0 -1
- package/dist/ui/hooks/use-input-handler.d.ts +0 -79
- package/dist/ui/hooks/use-input-handler.js +0 -2251
- package/dist/ui/hooks/use-input-handler.js.map +0 -1
- package/dist/ui/hooks/use-input-history.d.ts +0 -9
- package/dist/ui/hooks/use-input-history.js +0 -168
- package/dist/ui/hooks/use-input-history.js.map +0 -1
- package/dist/ui/shared/max-sized-box.d.ts +0 -17
- package/dist/ui/shared/max-sized-box.js +0 -14
- package/dist/ui/shared/max-sized-box.js.map +0 -1
- package/dist/ui/themes/index.d.ts +0 -5
- package/dist/ui/themes/index.js +0 -5
- package/dist/ui/themes/index.js.map +0 -1
- package/dist/ui/themes/theme-registry.d.ts +0 -55
- package/dist/ui/themes/theme-registry.js +0 -202
- package/dist/ui/themes/theme-registry.js.map +0 -1
- package/dist/ui/utils/bracketed-paste-handler.d.ts +0 -97
- package/dist/ui/utils/bracketed-paste-handler.js +0 -322
- package/dist/ui/utils/bracketed-paste-handler.js.map +0 -1
- package/dist/ui/utils/change-summarizer.d.ts +0 -20
- package/dist/ui/utils/change-summarizer.js +0 -282
- package/dist/ui/utils/change-summarizer.js.map +0 -1
- package/dist/ui/utils/code-colorizer.d.ts +0 -9
- package/dist/ui/utils/code-colorizer.js +0 -13
- package/dist/ui/utils/code-colorizer.js.map +0 -1
- package/dist/ui/utils/colors.d.ts +0 -41
- package/dist/ui/utils/colors.js +0 -80
- package/dist/ui/utils/colors.js.map +0 -1
- package/dist/ui/utils/image-handler.d.ts +0 -29
- package/dist/ui/utils/image-handler.js +0 -129
- package/dist/ui/utils/image-handler.js.map +0 -1
- package/dist/ui/utils/markdown-renderer.d.ts +0 -4
- package/dist/ui/utils/markdown-renderer.js +0 -40
- package/dist/ui/utils/markdown-renderer.js.map +0 -1
- package/dist/ui/utils/semantic-action-detector.d.ts +0 -49
- package/dist/ui/utils/semantic-action-detector.js +0 -339
- package/dist/ui/utils/semantic-action-detector.js.map +0 -1
- package/dist/ui/utils/tool-grouper.d.ts +0 -94
- package/dist/ui/utils/tool-grouper.js +0 -618
- package/dist/ui/utils/tool-grouper.js.map +0 -1
- package/dist/utils/api-error.d.ts +0 -61
- package/dist/utils/api-error.js +0 -176
- package/dist/utils/api-error.js.map +0 -1
- package/dist/utils/audit-logger.d.ts +0 -206
- package/dist/utils/audit-logger.js +0 -286
- package/dist/utils/audit-logger.js.map +0 -1
- package/dist/utils/auto-accept-logger.d.ts +0 -175
- package/dist/utils/auto-accept-logger.js +0 -423
- package/dist/utils/auto-accept-logger.js.map +0 -1
- package/dist/utils/automatosx-detector.d.ts +0 -19
- package/dist/utils/automatosx-detector.js +0 -52
- package/dist/utils/automatosx-detector.js.map +0 -1
- package/dist/utils/background-task-manager.d.ts +0 -114
- package/dist/utils/background-task-manager.js +0 -470
- package/dist/utils/background-task-manager.js.map +0 -1
- package/dist/utils/cache.d.ts +0 -77
- package/dist/utils/cache.js +0 -180
- package/dist/utils/cache.js.map +0 -1
- package/dist/utils/command-security.d.ts +0 -85
- package/dist/utils/command-security.js +0 -210
- package/dist/utils/command-security.js.map +0 -1
- package/dist/utils/config-loader.d.ts +0 -190
- package/dist/utils/config-loader.js +0 -108
- package/dist/utils/config-loader.js.map +0 -1
- package/dist/utils/confirmation-service.d.ts +0 -51
- package/dist/utils/confirmation-service.js +0 -220
- package/dist/utils/confirmation-service.js.map +0 -1
- package/dist/utils/console-messenger.d.ts +0 -80
- package/dist/utils/console-messenger.js +0 -142
- package/dist/utils/console-messenger.js.map +0 -1
- package/dist/utils/custom-instructions.d.ts +0 -1
- package/dist/utils/custom-instructions.js +0 -24
- package/dist/utils/custom-instructions.js.map +0 -1
- package/dist/utils/encryption.d.ts +0 -86
- package/dist/utils/encryption.js +0 -236
- package/dist/utils/encryption.js.map +0 -1
- package/dist/utils/enhanced-error-messages.d.ts +0 -33
- package/dist/utils/enhanced-error-messages.js +0 -440
- package/dist/utils/enhanced-error-messages.js.map +0 -1
- package/dist/utils/error-handler.d.ts +0 -65
- package/dist/utils/error-handler.js +0 -148
- package/dist/utils/error-handler.js.map +0 -1
- package/dist/utils/error-translator.d.ts +0 -25
- package/dist/utils/error-translator.js +0 -203
- package/dist/utils/error-translator.js.map +0 -1
- package/dist/utils/external-editor.d.ts +0 -47
- package/dist/utils/external-editor.js +0 -179
- package/dist/utils/external-editor.js.map +0 -1
- package/dist/utils/file-cache.d.ts +0 -148
- package/dist/utils/file-cache.js +0 -413
- package/dist/utils/file-cache.js.map +0 -1
- package/dist/utils/file-lock.d.ts +0 -141
- package/dist/utils/file-lock.js +0 -554
- package/dist/utils/file-lock.js.map +0 -1
- package/dist/utils/file-mentions.d.ts +0 -68
- package/dist/utils/file-mentions.js +0 -225
- package/dist/utils/file-mentions.js.map +0 -1
- package/dist/utils/history-manager.d.ts +0 -52
- package/dist/utils/history-manager.js +0 -211
- package/dist/utils/history-manager.js.map +0 -1
- package/dist/utils/history-migration.d.ts +0 -9
- package/dist/utils/history-migration.js +0 -37
- package/dist/utils/history-migration.js.map +0 -1
- package/dist/utils/image-processor.d.ts +0 -33
- package/dist/utils/image-processor.js +0 -124
- package/dist/utils/image-processor.js.map +0 -1
- package/dist/utils/index.d.ts +0 -92
- package/dist/utils/index.js +0 -111
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/init-previewer.d.ts +0 -56
- package/dist/utils/init-previewer.js +0 -239
- package/dist/utils/init-previewer.js.map +0 -1
- package/dist/utils/init-validator.d.ts +0 -65
- package/dist/utils/init-validator.js +0 -252
- package/dist/utils/init-validator.js.map +0 -1
- package/dist/utils/input-sanitizer.d.ts +0 -210
- package/dist/utils/input-sanitizer.js +0 -362
- package/dist/utils/input-sanitizer.js.map +0 -1
- package/dist/utils/instruction-generator.d.ts +0 -21
- package/dist/utils/instruction-generator.js +0 -233
- package/dist/utils/instruction-generator.js.map +0 -1
- package/dist/utils/json-utils.d.ts +0 -72
- package/dist/utils/json-utils.js +0 -226
- package/dist/utils/json-utils.js.map +0 -1
- package/dist/utils/llm-optimized-instruction-generator.d.ts +0 -36
- package/dist/utils/llm-optimized-instruction-generator.js +0 -365
- package/dist/utils/llm-optimized-instruction-generator.js.map +0 -1
- package/dist/utils/message-optimizer.d.ts +0 -100
- package/dist/utils/message-optimizer.js +0 -297
- package/dist/utils/message-optimizer.js.map +0 -1
- package/dist/utils/onboarding-manager.d.ts +0 -45
- package/dist/utils/onboarding-manager.js +0 -131
- package/dist/utils/onboarding-manager.js.map +0 -1
- package/dist/utils/parallel-analyzer.d.ts +0 -123
- package/dist/utils/parallel-analyzer.js +0 -241
- package/dist/utils/parallel-analyzer.js.map +0 -1
- package/dist/utils/paste-utils.d.ts +0 -99
- package/dist/utils/paste-utils.js +0 -295
- package/dist/utils/paste-utils.js.map +0 -1
- package/dist/utils/path-helpers.d.ts +0 -8
- package/dist/utils/path-helpers.js +0 -35
- package/dist/utils/path-helpers.js.map +0 -1
- package/dist/utils/path-security.d.ts +0 -92
- package/dist/utils/path-security.js +0 -300
- package/dist/utils/path-security.js.map +0 -1
- package/dist/utils/path-utils.d.ts +0 -83
- package/dist/utils/path-utils.js +0 -122
- package/dist/utils/path-utils.js.map +0 -1
- package/dist/utils/path-validator.d.ts +0 -66
- package/dist/utils/path-validator.js +0 -141
- package/dist/utils/path-validator.js.map +0 -1
- package/dist/utils/performance.d.ts +0 -74
- package/dist/utils/performance.js +0 -133
- package/dist/utils/performance.js.map +0 -1
- package/dist/utils/process-pool.d.ts +0 -109
- package/dist/utils/process-pool.js +0 -332
- package/dist/utils/process-pool.js.map +0 -1
- package/dist/utils/progress-tracker.d.ts +0 -51
- package/dist/utils/progress-tracker.js +0 -152
- package/dist/utils/progress-tracker.js.map +0 -1
- package/dist/utils/project-analyzer.d.ts +0 -49
- package/dist/utils/project-analyzer.js +0 -396
- package/dist/utils/project-analyzer.js.map +0 -1
- package/dist/utils/prompt-builder.d.ts +0 -14
- package/dist/utils/prompt-builder.js +0 -100
- package/dist/utils/prompt-builder.js.map +0 -1
- package/dist/utils/provider-context.d.ts +0 -243
- package/dist/utils/provider-context.js +0 -421
- package/dist/utils/provider-context.js.map +0 -1
- package/dist/utils/provider-file-cache.d.ts +0 -91
- package/dist/utils/provider-file-cache.js +0 -165
- package/dist/utils/provider-file-cache.js.map +0 -1
- package/dist/utils/provider-settings.d.ts +0 -181
- package/dist/utils/provider-settings.js +0 -450
- package/dist/utils/provider-settings.js.map +0 -1
- package/dist/utils/rate-limiter.d.ts +0 -222
- package/dist/utils/rate-limiter.js +0 -338
- package/dist/utils/rate-limiter.js.map +0 -1
- package/dist/utils/retry-helper.d.ts +0 -81
- package/dist/utils/retry-helper.js +0 -244
- package/dist/utils/retry-helper.js.map +0 -1
- package/dist/utils/safety-rules.d.ts +0 -64
- package/dist/utils/safety-rules.js +0 -225
- package/dist/utils/safety-rules.js.map +0 -1
- package/dist/utils/settings-manager.d.ts +0 -256
- package/dist/utils/settings-manager.js +0 -967
- package/dist/utils/settings-manager.js.map +0 -1
- package/dist/utils/setup-validator.d.ts +0 -47
- package/dist/utils/setup-validator.js +0 -304
- package/dist/utils/setup-validator.js.map +0 -1
- package/dist/utils/string-utils.d.ts +0 -19
- package/dist/utils/string-utils.js +0 -28
- package/dist/utils/string-utils.js.map +0 -1
- package/dist/utils/template-manager.d.ts +0 -62
- package/dist/utils/template-manager.js +0 -366
- package/dist/utils/template-manager.js.map +0 -1
- package/dist/utils/text-utils.d.ts +0 -82
- package/dist/utils/text-utils.js +0 -203
- package/dist/utils/text-utils.js.map +0 -1
- package/dist/utils/token-counter.d.ts +0 -76
- package/dist/utils/token-counter.js +0 -231
- package/dist/utils/token-counter.js.map +0 -1
- package/dist/utils/usage-tracker.d.ts +0 -78
- package/dist/utils/usage-tracker.js +0 -126
- package/dist/utils/usage-tracker.js.map +0 -1
- package/dist/utils/version.d.ts +0 -14
- package/dist/utils/version.js +0 -70
- package/dist/utils/version.js.map +0 -1
|
@@ -1,1275 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback, useRef, useEffect } from "react";
|
|
2
|
-
import { deleteCharBefore, deleteCharAfter, deleteWordBefore, deleteWordAfter, insertText, moveToLineStart, moveToPreviousWord, moveToNextWord, } from "../../utils/text-utils.js";
|
|
3
|
-
import { useInputHistory } from "./use-input-history.js";
|
|
4
|
-
import { PasteDetector, shouldCollapsePaste, createPastedBlock, generatePlaceholder, findBlockAtCursor, expandAllPlaceholders, } from "../../utils/paste-utils.js";
|
|
5
|
-
import { getSettingsManager } from "../../utils/settings-manager.js";
|
|
6
|
-
import { BracketedPasteHandler } from "../utils/bracketed-paste-handler.js";
|
|
7
|
-
/** Check if currently inside any string literal */
|
|
8
|
-
function isInsideString(state) {
|
|
9
|
-
return state.inSingleQuote || state.inDoubleQuote || state.inBacktick;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Parse text with escape-aware quote tracking.
|
|
13
|
-
* Calls onChar for each non-escaped character with current string state.
|
|
14
|
-
* Returns final string state after processing.
|
|
15
|
-
*/
|
|
16
|
-
function parseWithStringState(text, onChar) {
|
|
17
|
-
let inSingleQuote = false;
|
|
18
|
-
let inDoubleQuote = false;
|
|
19
|
-
let inBacktick = false;
|
|
20
|
-
let isEscaped = false;
|
|
21
|
-
for (const char of text) {
|
|
22
|
-
if (isEscaped) {
|
|
23
|
-
isEscaped = false;
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
if (char === '\\') {
|
|
27
|
-
isEscaped = true;
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
// Update quote state
|
|
31
|
-
if (char === "'" && !inDoubleQuote && !inBacktick)
|
|
32
|
-
inSingleQuote = !inSingleQuote;
|
|
33
|
-
else if (char === '"' && !inSingleQuote && !inBacktick)
|
|
34
|
-
inDoubleQuote = !inDoubleQuote;
|
|
35
|
-
else if (char === '`' && !inSingleQuote && !inDoubleQuote)
|
|
36
|
-
inBacktick = !inBacktick;
|
|
37
|
-
// Call handler if provided; return early if it returns true
|
|
38
|
-
if (onChar) {
|
|
39
|
-
const outsideString = !inSingleQuote && !inDoubleQuote && !inBacktick;
|
|
40
|
-
if (onChar(char, outsideString) === true) {
|
|
41
|
-
return { inSingleQuote, inDoubleQuote, inBacktick };
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return { inSingleQuote, inDoubleQuote, inBacktick };
|
|
46
|
-
}
|
|
47
|
-
/** Get final string state after parsing text */
|
|
48
|
-
function getStringState(text) {
|
|
49
|
-
return parseWithStringState(text);
|
|
50
|
-
}
|
|
51
|
-
/** Check if any of the given characters appear outside of strings */
|
|
52
|
-
function hasCharOutsideStrings(text, chars) {
|
|
53
|
-
let found = false;
|
|
54
|
-
parseWithStringState(text, (char, outsideString) => {
|
|
55
|
-
if (outsideString && chars.includes(char)) {
|
|
56
|
-
found = true;
|
|
57
|
-
return true; // Stop parsing early
|
|
58
|
-
}
|
|
59
|
-
return undefined;
|
|
60
|
-
});
|
|
61
|
-
return found;
|
|
62
|
-
}
|
|
63
|
-
// Cached constant arrays for isIncompleteInput (avoid recreating on every call)
|
|
64
|
-
const TRAILING_OPERATORS = [
|
|
65
|
-
'===', '!==', '...', '&&', '||', '==', '!=', '<=', '>=', '=>',
|
|
66
|
-
'..', '+', '-', '*', '/', '%', '=', '<', '>', '&', '|', '^',
|
|
67
|
-
'?', ':', ',', '.',
|
|
68
|
-
];
|
|
69
|
-
const INCOMPLETE_KEYWORDS = new Set([
|
|
70
|
-
'if', 'else', 'for', 'while', 'do', 'switch', 'case',
|
|
71
|
-
'function', 'const', 'let', 'var', 'class', 'interface',
|
|
72
|
-
'type', 'enum', 'import', 'export', 'return', 'throw',
|
|
73
|
-
'try', 'catch', 'finally', 'async', 'await',
|
|
74
|
-
]);
|
|
75
|
-
/**
|
|
76
|
-
* Check if input appears incomplete and should not be submitted
|
|
77
|
-
* Used for smart mode to auto-insert newlines for incomplete input
|
|
78
|
-
*/
|
|
79
|
-
function isIncompleteInput(text, smartDetection) {
|
|
80
|
-
if (!smartDetection?.enabled)
|
|
81
|
-
return false;
|
|
82
|
-
const trimmed = text.trimEnd();
|
|
83
|
-
if (!trimmed)
|
|
84
|
-
return false;
|
|
85
|
-
// Check for unclosed brackets using shared parser
|
|
86
|
-
if (smartDetection.checkBrackets) {
|
|
87
|
-
const brackets = { '(': 0, '[': 0, '{': 0 };
|
|
88
|
-
parseWithStringState(trimmed, (char, outsideString) => {
|
|
89
|
-
if (outsideString) {
|
|
90
|
-
if (char === '(')
|
|
91
|
-
brackets['(']++;
|
|
92
|
-
else if (char === ')')
|
|
93
|
-
brackets['(']--;
|
|
94
|
-
else if (char === '[')
|
|
95
|
-
brackets['[']++;
|
|
96
|
-
else if (char === ']')
|
|
97
|
-
brackets['[']--;
|
|
98
|
-
else if (char === '{')
|
|
99
|
-
brackets['{']++;
|
|
100
|
-
else if (char === '}')
|
|
101
|
-
brackets['{']--;
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
if (brackets['('] > 0 || brackets['['] > 0 || brackets['{'] > 0) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// Compute lastLine once for both operator and statement checks (avoid duplicate split)
|
|
109
|
-
const needsLastLine = smartDetection.checkOperators || smartDetection.checkStatements;
|
|
110
|
-
const lastLine = needsLastLine ? (trimmed.split('\n').pop() || '') : '';
|
|
111
|
-
const lastLineState = needsLastLine ? getStringState(lastLine) : null;
|
|
112
|
-
// Check for trailing operators
|
|
113
|
-
if (smartDetection.checkOperators && lastLineState && !isInsideString(lastLineState)) {
|
|
114
|
-
for (const op of TRAILING_OPERATORS) {
|
|
115
|
-
if (trimmed.endsWith(op))
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
// Check for incomplete statements
|
|
120
|
-
if (smartDetection.checkStatements && lastLineState) {
|
|
121
|
-
const state = lastLineState;
|
|
122
|
-
if (!isInsideString(state)) {
|
|
123
|
-
const words = lastLine.trim().split(/\s+/);
|
|
124
|
-
const lastWord = words[words.length - 1];
|
|
125
|
-
if (INCOMPLETE_KEYWORDS.has(lastWord))
|
|
126
|
-
return true;
|
|
127
|
-
// Check for statement keywords at start without closing
|
|
128
|
-
const firstWord = words[0];
|
|
129
|
-
if (INCOMPLETE_KEYWORDS.has(firstWord)) {
|
|
130
|
-
if (!hasCharOutsideStrings(lastLine, ['{', ';'])) {
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
// Normalize Shift+Enter detection across terminals (Ink, CSI-u, xterm modifiers)
|
|
139
|
-
export function isShiftEnterKey(_inputChar, key) {
|
|
140
|
-
if (key.shift && key.return) {
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
const sequence = key.sequence;
|
|
144
|
-
if (!sequence) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
const shiftEnterPatterns = [
|
|
148
|
-
/\u001b\[13;2u/, // Kitty/WezTerm CSI-u
|
|
149
|
-
/\u001b\[13;2~/, // xterm modifyOtherKeys
|
|
150
|
-
/\u001bO2M/, // SS3 modifier form some terminals emit
|
|
151
|
-
];
|
|
152
|
-
if (shiftEnterPatterns.some(pattern => pattern.test(sequence))) {
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
// Some environments drop the leading ESC in key.sequence
|
|
156
|
-
if (sequence.startsWith('[13;2') && (sequence.endsWith('u') || sequence.endsWith('~'))) {
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
return false;
|
|
160
|
-
}
|
|
161
|
-
export function useEnhancedInput({ onSubmit, onEscape, onSpecialKey, onVerboseToggle, onQuickActions, onBackgroundModeToggle, onCopyLastResponse, onAutoAcceptToggle, onThinkingModeToggle, onExternalEditor, onLargePaste, onPasteTruncated, onKeyboardHelp, projectDir, disabled = false, multiline = false, } = {}) {
|
|
162
|
-
const [input, setInputState] = useState("");
|
|
163
|
-
const [cursorPosition, setCursorPositionState] = useState(0);
|
|
164
|
-
const [pastedBlocks, setPastedBlocks] = useState([]);
|
|
165
|
-
// BUG FIX: Use ref instead of state to prevent race conditions with concurrent pastes
|
|
166
|
-
const pasteCounterRef = useRef(0);
|
|
167
|
-
// BUG FIX: Use ref for pastedBlocks to ensure expandPlaceholdersForSubmit always has current value
|
|
168
|
-
// This prevents race conditions when paste + submit happen rapidly before React re-renders
|
|
169
|
-
const pastedBlocksRef = useRef(pastedBlocks);
|
|
170
|
-
const [currentBlockAtCursor, setCurrentBlockAtCursor] = useState(null);
|
|
171
|
-
const [isPasting, setIsPasting] = useState(false);
|
|
172
|
-
// Load input configuration from settings
|
|
173
|
-
const [inputConfig] = useState(() => {
|
|
174
|
-
return getSettingsManager().getInputConfig();
|
|
175
|
-
});
|
|
176
|
-
// Load paste configuration from settings (v3.8.0)
|
|
177
|
-
const [pasteConfig] = useState(() => {
|
|
178
|
-
return getSettingsManager().getPasteSettings();
|
|
179
|
-
});
|
|
180
|
-
const isMultilineRef = useRef(multiline);
|
|
181
|
-
const pasteDetectorRef = useRef(new PasteDetector());
|
|
182
|
-
const pasteTimeoutRef = useRef(null);
|
|
183
|
-
const bracketedPasteHandlerRef = useRef(new BracketedPasteHandler());
|
|
184
|
-
// Fallback paste accumulation buffer (for terminals that send paste in chunks)
|
|
185
|
-
const fallbackPasteBufferRef = useRef('');
|
|
186
|
-
const fallbackPasteTimeoutRef = useRef(null);
|
|
187
|
-
const fallbackPasteLastChunkTimeRef = useRef(0); // Track when last chunk arrived
|
|
188
|
-
// FIX: Paste safety timeout - prevents premature submit when Enter arrives immediately after paste
|
|
189
|
-
// Based on Gemini CLI's approach: 40ms is faster than any human can type (200 WPM = ~50ms/keystroke)
|
|
190
|
-
// If Enter arrives within 40ms of paste completion, it was likely part of the paste
|
|
191
|
-
const pasteCompletionTimeRef = useRef(null);
|
|
192
|
-
const PASTE_SAFETY_TIMEOUT_MS = 40; // 40ms safety window after paste completes
|
|
193
|
-
// BUG FIX: Use refs for callbacks used in setTimeout to avoid stale closures
|
|
194
|
-
const onLargePasteRef = useRef(onLargePaste);
|
|
195
|
-
const onPasteTruncatedRef = useRef(onPasteTruncated);
|
|
196
|
-
// BUG FIX: Track mounted state for async operations
|
|
197
|
-
const isMountedRef = useRef(true);
|
|
198
|
-
// Double-ESC detection: track last escape press time
|
|
199
|
-
const lastEscapeTimeRef = useRef(0);
|
|
200
|
-
const DOUBLE_ESCAPE_WINDOW_MS = 500;
|
|
201
|
-
// Keep ref in sync with prop to avoid stale closure
|
|
202
|
-
isMultilineRef.current = multiline;
|
|
203
|
-
onLargePasteRef.current = onLargePaste;
|
|
204
|
-
onPasteTruncatedRef.current = onPasteTruncated;
|
|
205
|
-
const { addToHistory, navigateHistory, resetHistory, setOriginalInput, isNavigatingHistory, } = useInputHistory(projectDir);
|
|
206
|
-
const setInput = useCallback((text) => {
|
|
207
|
-
setInputState(text);
|
|
208
|
-
// Use functional update to get the current cursor position, avoiding stale closure
|
|
209
|
-
const newCursor = Math.min(text.length, cursorPositionRef.current);
|
|
210
|
-
setCursorPositionState(newCursor);
|
|
211
|
-
if (!isNavigatingHistory()) {
|
|
212
|
-
setOriginalInput(text);
|
|
213
|
-
}
|
|
214
|
-
// BUG FIX: Clear pasted blocks when input is completely replaced
|
|
215
|
-
// The old block metadata is no longer valid for the new text
|
|
216
|
-
pastedBlocksRef.current = [];
|
|
217
|
-
setPastedBlocks([]);
|
|
218
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
219
|
-
inputRef.current = text;
|
|
220
|
-
cursorPositionRef.current = newCursor;
|
|
221
|
-
}, [isNavigatingHistory, setOriginalInput]);
|
|
222
|
-
const setCursorPosition = useCallback((position) => {
|
|
223
|
-
// BUG FIX: Use inputRef for bounds checking instead of nested state update with queueMicrotask
|
|
224
|
-
// This avoids race conditions where input changes between scheduling and execution
|
|
225
|
-
const currentInputLength = inputRef.current.length;
|
|
226
|
-
const boundedPosition = Math.max(0, Math.min(currentInputLength, position));
|
|
227
|
-
setCursorPositionState(boundedPosition);
|
|
228
|
-
// BUG FIX: Synchronously update ref to prevent stale reads
|
|
229
|
-
cursorPositionRef.current = boundedPosition;
|
|
230
|
-
}, []);
|
|
231
|
-
const clearInput = useCallback(() => {
|
|
232
|
-
setInputState("");
|
|
233
|
-
setCursorPositionState(0);
|
|
234
|
-
setOriginalInput("");
|
|
235
|
-
pastedBlocksRef.current = [];
|
|
236
|
-
setPastedBlocks([]);
|
|
237
|
-
pasteCounterRef.current = 0; // BUG FIX: Reset counter ref
|
|
238
|
-
setIsPasting(false);
|
|
239
|
-
pasteDetectorRef.current.reset();
|
|
240
|
-
bracketedPasteHandlerRef.current.reset();
|
|
241
|
-
// Clear fallback paste buffer and timeout
|
|
242
|
-
fallbackPasteBufferRef.current = '';
|
|
243
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
244
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
245
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
246
|
-
fallbackPasteTimeoutRef.current = null;
|
|
247
|
-
}
|
|
248
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
249
|
-
inputRef.current = '';
|
|
250
|
-
cursorPositionRef.current = 0;
|
|
251
|
-
}, [setOriginalInput]);
|
|
252
|
-
const insertAtCursor = useCallback((text) => {
|
|
253
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
254
|
-
// This ensures insertAtCursor sees the latest input/cursor even if called
|
|
255
|
-
// rapidly after other state updates
|
|
256
|
-
const currentInput = inputRef.current;
|
|
257
|
-
const currentCursor = cursorPositionRef.current;
|
|
258
|
-
const result = insertText(currentInput, currentCursor, text);
|
|
259
|
-
setInputState(result.text);
|
|
260
|
-
setCursorPositionState(result.position);
|
|
261
|
-
setOriginalInput(result.text);
|
|
262
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
263
|
-
inputRef.current = result.text;
|
|
264
|
-
cursorPositionRef.current = result.position;
|
|
265
|
-
}, [setOriginalInput]);
|
|
266
|
-
// Handle paste completion
|
|
267
|
-
// Note: No timeout or accumulation needed - Ink batches the entire paste for us
|
|
268
|
-
// BUG FIX: Create refs to track latest values without causing re-renders
|
|
269
|
-
const inputRef = useRef(input);
|
|
270
|
-
const cursorPositionRef = useRef(cursorPosition);
|
|
271
|
-
// Keep refs in sync with state
|
|
272
|
-
useEffect(() => {
|
|
273
|
-
inputRef.current = input;
|
|
274
|
-
cursorPositionRef.current = cursorPosition;
|
|
275
|
-
}, [input, cursorPosition]);
|
|
276
|
-
// BUG FIX: Keep pastedBlocksRef in sync with state
|
|
277
|
-
useEffect(() => {
|
|
278
|
-
pastedBlocksRef.current = pastedBlocks;
|
|
279
|
-
}, [pastedBlocks]);
|
|
280
|
-
const handlePasteComplete = useCallback((pastedContent) => {
|
|
281
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
282
|
-
const currentInput = inputRef.current;
|
|
283
|
-
const currentCursor = cursorPositionRef.current;
|
|
284
|
-
// FIX: Set paste completion timestamp for safety timeout
|
|
285
|
-
// This prevents premature submit if Enter arrives immediately after paste
|
|
286
|
-
pasteCompletionTimeRef.current = Date.now();
|
|
287
|
-
// Preserve all formatting - no trimming or normalization
|
|
288
|
-
// This ensures JSON indentation, newlines, and whitespace are intact
|
|
289
|
-
// Check if should collapse based on line count or character count
|
|
290
|
-
if (shouldCollapsePaste(pastedContent)) {
|
|
291
|
-
// BUG FIX: Use ref and increment immediately to prevent race conditions
|
|
292
|
-
const blockId = pasteCounterRef.current++;
|
|
293
|
-
// Create pasted block with CURRENT cursor position
|
|
294
|
-
const block = createPastedBlock(blockId, pastedContent, currentCursor);
|
|
295
|
-
// BUG FIX: Sync ref immediately so expandPlaceholdersForSubmit has current value
|
|
296
|
-
// even if submit happens before React processes the state update
|
|
297
|
-
const newBlocks = [...pastedBlocksRef.current, block];
|
|
298
|
-
pastedBlocksRef.current = newBlocks;
|
|
299
|
-
setPastedBlocks(newBlocks);
|
|
300
|
-
// Insert placeholder instead of full content
|
|
301
|
-
const placeholder = generatePlaceholder(block);
|
|
302
|
-
const result = insertText(currentInput, currentCursor, placeholder);
|
|
303
|
-
setInputState(result.text);
|
|
304
|
-
setCursorPositionState(result.position);
|
|
305
|
-
setOriginalInput(result.text);
|
|
306
|
-
// BUG FIX: Synchronously update refs to prevent stale reads in rapid operations
|
|
307
|
-
inputRef.current = result.text;
|
|
308
|
-
cursorPositionRef.current = result.position;
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
// Insert normally (below threshold) with all formatting preserved
|
|
312
|
-
const result = insertText(currentInput, currentCursor, pastedContent);
|
|
313
|
-
setInputState(result.text);
|
|
314
|
-
setCursorPositionState(result.position);
|
|
315
|
-
setOriginalInput(result.text);
|
|
316
|
-
// BUG FIX: Synchronously update refs to prevent stale reads in rapid operations
|
|
317
|
-
inputRef.current = result.text;
|
|
318
|
-
cursorPositionRef.current = result.position;
|
|
319
|
-
}
|
|
320
|
-
}, [setOriginalInput]);
|
|
321
|
-
// Toggle collapse/expand for block at cursor
|
|
322
|
-
const toggleBlockAtCursor = useCallback(() => {
|
|
323
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
324
|
-
const currentInput = inputRef.current;
|
|
325
|
-
const currentCursor = cursorPositionRef.current;
|
|
326
|
-
// BUG FIX: Use pastedBlocksRef.current instead of pastedBlocks to avoid stale closure
|
|
327
|
-
const block = findBlockAtCursor(currentInput, currentCursor, pastedBlocksRef.current);
|
|
328
|
-
if (!block)
|
|
329
|
-
return;
|
|
330
|
-
const placeholder = generatePlaceholder(block);
|
|
331
|
-
if (block.collapsed) {
|
|
332
|
-
// Expand: find the specific occurrence near cursor and replace it
|
|
333
|
-
let searchStart = 0;
|
|
334
|
-
let targetStart = -1;
|
|
335
|
-
// Find the occurrence that contains the cursor
|
|
336
|
-
while (searchStart < currentInput.length) {
|
|
337
|
-
const occurrenceStart = currentInput.indexOf(placeholder, searchStart);
|
|
338
|
-
if (occurrenceStart === -1)
|
|
339
|
-
break;
|
|
340
|
-
const occurrenceEnd = occurrenceStart + placeholder.length;
|
|
341
|
-
if (currentCursor >= occurrenceStart && currentCursor <= occurrenceEnd) {
|
|
342
|
-
targetStart = occurrenceStart;
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
searchStart = occurrenceStart + 1;
|
|
346
|
-
}
|
|
347
|
-
if (targetStart === -1)
|
|
348
|
-
return; // Should not happen
|
|
349
|
-
// Replace only this specific occurrence
|
|
350
|
-
const newInput = currentInput.substring(0, targetStart) +
|
|
351
|
-
block.content +
|
|
352
|
-
currentInput.substring(targetStart + placeholder.length);
|
|
353
|
-
setInputState(newInput);
|
|
354
|
-
// Keep cursor at same position or adjust if needed
|
|
355
|
-
const newCursor = currentCursor + (block.content.length - placeholder.length);
|
|
356
|
-
const boundedCursor = Math.min(newInput.length, newCursor);
|
|
357
|
-
setCursorPositionState(boundedCursor);
|
|
358
|
-
setOriginalInput(newInput);
|
|
359
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
360
|
-
inputRef.current = newInput;
|
|
361
|
-
cursorPositionRef.current = boundedCursor;
|
|
362
|
-
// Update block state
|
|
363
|
-
// BUG FIX: Sync ref immediately for expandPlaceholdersForSubmit
|
|
364
|
-
const updatedBlocks = pastedBlocksRef.current.map(b => b.id === block.id ? { ...b, collapsed: false } : b);
|
|
365
|
-
pastedBlocksRef.current = updatedBlocks;
|
|
366
|
-
setPastedBlocks(updatedBlocks);
|
|
367
|
-
}
|
|
368
|
-
else {
|
|
369
|
-
// Collapse: find the specific occurrence near cursor and replace it
|
|
370
|
-
let searchStart = 0;
|
|
371
|
-
let targetStart = -1;
|
|
372
|
-
// Find the occurrence that contains the cursor
|
|
373
|
-
while (searchStart < currentInput.length) {
|
|
374
|
-
const occurrenceStart = currentInput.indexOf(block.content, searchStart);
|
|
375
|
-
if (occurrenceStart === -1)
|
|
376
|
-
break;
|
|
377
|
-
const occurrenceEnd = occurrenceStart + block.content.length;
|
|
378
|
-
if (currentCursor >= occurrenceStart && currentCursor <= occurrenceEnd) {
|
|
379
|
-
targetStart = occurrenceStart;
|
|
380
|
-
break;
|
|
381
|
-
}
|
|
382
|
-
searchStart = occurrenceStart + 1;
|
|
383
|
-
}
|
|
384
|
-
if (targetStart === -1)
|
|
385
|
-
return; // Should not happen
|
|
386
|
-
// Replace only this specific occurrence
|
|
387
|
-
const newInput = currentInput.substring(0, targetStart) +
|
|
388
|
-
placeholder +
|
|
389
|
-
currentInput.substring(targetStart + block.content.length);
|
|
390
|
-
setInputState(newInput);
|
|
391
|
-
// Adjust cursor to end of placeholder
|
|
392
|
-
const newCursor = targetStart + placeholder.length;
|
|
393
|
-
setCursorPositionState(newCursor);
|
|
394
|
-
setOriginalInput(newInput);
|
|
395
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
396
|
-
inputRef.current = newInput;
|
|
397
|
-
cursorPositionRef.current = newCursor;
|
|
398
|
-
// Update block state
|
|
399
|
-
// BUG FIX: Sync ref immediately for expandPlaceholdersForSubmit
|
|
400
|
-
const updatedBlocks = pastedBlocksRef.current.map(b => b.id === block.id ? { ...b, collapsed: true } : b);
|
|
401
|
-
pastedBlocksRef.current = updatedBlocks;
|
|
402
|
-
setPastedBlocks(updatedBlocks);
|
|
403
|
-
}
|
|
404
|
-
// BUG FIX: Remove pastedBlocks from dependencies - we use pastedBlocksRef.current instead
|
|
405
|
-
}, [setOriginalInput]);
|
|
406
|
-
// Expand all placeholders for submission
|
|
407
|
-
// BUG FIX: Use ref to always get current pastedBlocks, avoiding stale closure
|
|
408
|
-
// This ensures rapid paste + submit sequences work correctly before React re-renders
|
|
409
|
-
const expandPlaceholdersForSubmit = useCallback((text) => {
|
|
410
|
-
return expandAllPlaceholders(text, pastedBlocksRef.current);
|
|
411
|
-
}, []);
|
|
412
|
-
const handleSubmit = useCallback(() => {
|
|
413
|
-
// BUG FIX: Check for active bracketed paste mode before submitting
|
|
414
|
-
// If we're in the middle of receiving a bracketed paste, don't submit yet
|
|
415
|
-
if (bracketedPasteHandlerRef.current.isAccumulating()) {
|
|
416
|
-
// Bracketed paste is in progress - wait for it to complete
|
|
417
|
-
// The enter key will be part of the paste content
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
// BUG FIX: Check for pending fallback paste accumulation before submitting
|
|
421
|
-
if (fallbackPasteBufferRef.current.length > 0) {
|
|
422
|
-
// There's accumulated paste content - flush it first
|
|
423
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
424
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
425
|
-
fallbackPasteTimeoutRef.current = null;
|
|
426
|
-
}
|
|
427
|
-
const accumulatedPaste = fallbackPasteBufferRef.current;
|
|
428
|
-
fallbackPasteBufferRef.current = '';
|
|
429
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
430
|
-
// Add accumulated paste to input before submitting
|
|
431
|
-
try {
|
|
432
|
-
handlePasteComplete(accumulatedPaste);
|
|
433
|
-
}
|
|
434
|
-
catch {
|
|
435
|
-
// BUG FIX: Silently ignore paste errors to avoid cluttering CLI output
|
|
436
|
-
// The paste data is already cleared, so we just proceed
|
|
437
|
-
}
|
|
438
|
-
// Don't submit yet - let the paste complete first
|
|
439
|
-
// User can hit Enter again to submit
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
// FIX: Paste safety timeout - prevent premature submit after paste
|
|
443
|
-
// If Enter arrives within 40ms of paste completion, it was likely part of the paste
|
|
444
|
-
// (trailing newline). Insert newline instead of submitting.
|
|
445
|
-
if (pasteCompletionTimeRef.current !== null) {
|
|
446
|
-
const elapsed = Date.now() - pasteCompletionTimeRef.current;
|
|
447
|
-
if (elapsed < PASTE_SAFETY_TIMEOUT_MS) {
|
|
448
|
-
// Enter arrived too soon after paste - treat as newline, not submit
|
|
449
|
-
// This prevents accidental submission when paste includes trailing newline
|
|
450
|
-
const currentInput = inputRef.current;
|
|
451
|
-
const currentCursor = cursorPositionRef.current;
|
|
452
|
-
const result = insertText(currentInput, currentCursor, "\n");
|
|
453
|
-
setInputState(result.text);
|
|
454
|
-
setCursorPositionState(result.position);
|
|
455
|
-
setOriginalInput(result.text);
|
|
456
|
-
inputRef.current = result.text;
|
|
457
|
-
cursorPositionRef.current = result.position;
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
// Clear the timestamp since we're past the safety window
|
|
461
|
-
pasteCompletionTimeRef.current = null;
|
|
462
|
-
}
|
|
463
|
-
// BUG FIX: Use inputRef.current to get the latest input value
|
|
464
|
-
// This ensures we see updates from handlePasteComplete or other operations
|
|
465
|
-
const currentInput = inputRef.current;
|
|
466
|
-
if (currentInput.trim()) {
|
|
467
|
-
// Expand all placeholders before submission
|
|
468
|
-
const expandedInput = expandPlaceholdersForSubmit(currentInput);
|
|
469
|
-
addToHistory(expandedInput);
|
|
470
|
-
onSubmit?.(expandedInput);
|
|
471
|
-
clearInput();
|
|
472
|
-
}
|
|
473
|
-
}, [addToHistory, onSubmit, clearInput, expandPlaceholdersForSubmit, handlePasteComplete, setOriginalInput]);
|
|
474
|
-
const handleInput = useCallback((inputChar, key) => {
|
|
475
|
-
if (disabled)
|
|
476
|
-
return;
|
|
477
|
-
const shiftEnterDetected = isShiftEnterKey(inputChar, key);
|
|
478
|
-
// BUG FIX: Detect Enter from multiple sources:
|
|
479
|
-
// 1. key.return (standard Ink detection)
|
|
480
|
-
// 2. inputChar === '\r' (carriage return - some terminals send this for Enter)
|
|
481
|
-
// 3. inputChar === '\n' without Ctrl modifier (newline - other terminals send this for Enter)
|
|
482
|
-
// Note: Ctrl+J sends '\n' but should insert newline, not submit, so we exclude Ctrl modifier
|
|
483
|
-
const isPlainEnter = inputChar === '\r' || (inputChar === '\n' && !key.ctrl);
|
|
484
|
-
const enterPressed = key.return || shiftEnterDetected || isPlainEnter;
|
|
485
|
-
// Handle Ctrl+C - check multiple ways it could be detected
|
|
486
|
-
if ((key.ctrl && inputChar === "c") || inputChar === "\x03") {
|
|
487
|
-
setInputState("");
|
|
488
|
-
setCursorPositionState(0);
|
|
489
|
-
setOriginalInput("");
|
|
490
|
-
// BUG FIX: Clear pasted blocks when input is cleared
|
|
491
|
-
pastedBlocksRef.current = [];
|
|
492
|
-
setPastedBlocks([]);
|
|
493
|
-
// BUG FIX: Also clear pending paste accumulation to avoid unexpected behavior
|
|
494
|
-
fallbackPasteBufferRef.current = '';
|
|
495
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
496
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
497
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
498
|
-
fallbackPasteTimeoutRef.current = null;
|
|
499
|
-
}
|
|
500
|
-
setIsPasting(false);
|
|
501
|
-
bracketedPasteHandlerRef.current.reset();
|
|
502
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
503
|
-
inputRef.current = '';
|
|
504
|
-
cursorPositionRef.current = 0;
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
// Handle Ctrl+P: Toggle expand/collapse for paste at cursor
|
|
508
|
-
// Check both key.ctrl with 'p' and raw ASCII code \x10 (Ctrl+P = ASCII 16)
|
|
509
|
-
if ((key.ctrl && inputChar === "p") || inputChar === "\x10") {
|
|
510
|
-
toggleBlockAtCursor();
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
// Handle Escape key with double-ESC detection for clearing input
|
|
514
|
-
if (key.escape) {
|
|
515
|
-
const now = Date.now();
|
|
516
|
-
// Let special key handler try first (close menus, abort operations)
|
|
517
|
-
if (onSpecialKey?.(key)) {
|
|
518
|
-
// An action was taken (menu closed, operation aborted)
|
|
519
|
-
// Reset double-ESC timer since we did something
|
|
520
|
-
lastEscapeTimeRef.current = 0;
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
// Check for double-ESC to clear input
|
|
524
|
-
const inputHasText = inputRef.current.length > 0;
|
|
525
|
-
const isDoubleEscape = lastEscapeTimeRef.current > 0 &&
|
|
526
|
-
(now - lastEscapeTimeRef.current) < DOUBLE_ESCAPE_WINDOW_MS;
|
|
527
|
-
if (inputHasText && isDoubleEscape) {
|
|
528
|
-
// Double-ESC detected with text in input - clear it
|
|
529
|
-
clearInput();
|
|
530
|
-
lastEscapeTimeRef.current = 0;
|
|
531
|
-
return;
|
|
532
|
-
}
|
|
533
|
-
// Record escape time for potential double-ESC
|
|
534
|
-
lastEscapeTimeRef.current = now;
|
|
535
|
-
onEscape?.();
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
// Allow special key handler to override default behavior for non-escape keys
|
|
539
|
-
if (onSpecialKey?.(key)) {
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
542
|
-
// FIX: Handle Ctrl+J - reliable newline insertion across all terminals
|
|
543
|
-
// This is the vi/Unix convention: Ctrl+J sends Line Feed (0x0A)
|
|
544
|
-
// Unlike Shift+Enter which is undetectable in most terminals, Ctrl+J always works
|
|
545
|
-
if (key.ctrl && (inputChar === "\n" || inputChar === "\x0a" || inputChar === "j")) {
|
|
546
|
-
const currentInput = inputRef.current;
|
|
547
|
-
const currentCursor = cursorPositionRef.current;
|
|
548
|
-
const result = insertText(currentInput, currentCursor, "\n");
|
|
549
|
-
setInputState(result.text);
|
|
550
|
-
setCursorPositionState(result.position);
|
|
551
|
-
setOriginalInput(result.text);
|
|
552
|
-
inputRef.current = result.text;
|
|
553
|
-
cursorPositionRef.current = result.position;
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
// Handle Enter/Return - configurable multi-line input
|
|
557
|
-
if (enterPressed) {
|
|
558
|
-
const enterBehavior = inputConfig?.enterBehavior || 'submit';
|
|
559
|
-
// Check if user pressed Shift+Enter (submit key in newline mode)
|
|
560
|
-
const isShiftEnter = shiftEnterDetected;
|
|
561
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
562
|
-
const currentInput = inputRef.current;
|
|
563
|
-
const currentCursor = cursorPositionRef.current;
|
|
564
|
-
// FIX: Backslash escape for newline - universal shell convention
|
|
565
|
-
// If there's a backslash immediately before cursor, remove it and insert newline
|
|
566
|
-
// This works in all terminals regardless of Shift+Enter support
|
|
567
|
-
if (currentCursor > 0 && currentInput[currentCursor - 1] === '\\') {
|
|
568
|
-
// Remove the backslash and insert newline instead
|
|
569
|
-
const beforeBackslash = currentInput.slice(0, currentCursor - 1);
|
|
570
|
-
const afterCursor = currentInput.slice(currentCursor);
|
|
571
|
-
const newInput = beforeBackslash + "\n" + afterCursor;
|
|
572
|
-
const newCursor = currentCursor; // Cursor stays at same position (after newline)
|
|
573
|
-
setInputState(newInput);
|
|
574
|
-
setCursorPositionState(newCursor);
|
|
575
|
-
setOriginalInput(newInput);
|
|
576
|
-
inputRef.current = newInput;
|
|
577
|
-
cursorPositionRef.current = newCursor;
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
if (enterBehavior === 'newline') {
|
|
581
|
-
// Newline mode: Enter inserts newline, Shift+Enter submits
|
|
582
|
-
if (isShiftEnter) {
|
|
583
|
-
handleSubmit();
|
|
584
|
-
}
|
|
585
|
-
else {
|
|
586
|
-
const result = insertText(currentInput, currentCursor, "\n");
|
|
587
|
-
setInputState(result.text);
|
|
588
|
-
setCursorPositionState(result.position);
|
|
589
|
-
setOriginalInput(result.text);
|
|
590
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
591
|
-
inputRef.current = result.text;
|
|
592
|
-
cursorPositionRef.current = result.position;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
else if (enterBehavior === 'submit') {
|
|
596
|
-
// Submit mode (legacy): Enter submits, Shift+Enter inserts newline
|
|
597
|
-
if (isShiftEnter) {
|
|
598
|
-
const result = insertText(currentInput, currentCursor, "\n");
|
|
599
|
-
setInputState(result.text);
|
|
600
|
-
setCursorPositionState(result.position);
|
|
601
|
-
setOriginalInput(result.text);
|
|
602
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
603
|
-
inputRef.current = result.text;
|
|
604
|
-
cursorPositionRef.current = result.position;
|
|
605
|
-
}
|
|
606
|
-
else {
|
|
607
|
-
handleSubmit();
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
else if (enterBehavior === 'smart') {
|
|
611
|
-
// Smart mode: Auto-detect incomplete input
|
|
612
|
-
// Shift+Enter always submits, otherwise check if input is incomplete
|
|
613
|
-
if (isShiftEnter) {
|
|
614
|
-
// Explicit submit with Shift+Enter
|
|
615
|
-
handleSubmit();
|
|
616
|
-
}
|
|
617
|
-
else if (isIncompleteInput(currentInput, inputConfig?.smartDetection)) {
|
|
618
|
-
// Input appears incomplete, insert newline
|
|
619
|
-
const result = insertText(currentInput, currentCursor, "\n");
|
|
620
|
-
setInputState(result.text);
|
|
621
|
-
setCursorPositionState(result.position);
|
|
622
|
-
setOriginalInput(result.text);
|
|
623
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
624
|
-
inputRef.current = result.text;
|
|
625
|
-
cursorPositionRef.current = result.position;
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
// Input looks complete, submit
|
|
629
|
-
handleSubmit();
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
// Handle history navigation
|
|
635
|
-
if ((key.upArrow || key.name === 'up') && !key.ctrl && !key.meta) {
|
|
636
|
-
const historyInput = navigateHistory("up");
|
|
637
|
-
if (historyInput !== null) {
|
|
638
|
-
setInputState(historyInput);
|
|
639
|
-
setCursorPositionState(historyInput.length);
|
|
640
|
-
// BUG FIX: Clear pasted blocks when navigating history
|
|
641
|
-
// History entries don't have associated paste blocks
|
|
642
|
-
pastedBlocksRef.current = [];
|
|
643
|
-
setPastedBlocks([]);
|
|
644
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
645
|
-
inputRef.current = historyInput;
|
|
646
|
-
cursorPositionRef.current = historyInput.length;
|
|
647
|
-
}
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
if ((key.downArrow || key.name === 'down') && !key.ctrl && !key.meta) {
|
|
651
|
-
const historyInput = navigateHistory("down");
|
|
652
|
-
if (historyInput !== null) {
|
|
653
|
-
setInputState(historyInput);
|
|
654
|
-
setCursorPositionState(historyInput.length);
|
|
655
|
-
// BUG FIX: Clear pasted blocks when navigating history
|
|
656
|
-
// History entries don't have associated paste blocks
|
|
657
|
-
pastedBlocksRef.current = [];
|
|
658
|
-
setPastedBlocks([]);
|
|
659
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
660
|
-
inputRef.current = historyInput;
|
|
661
|
-
cursorPositionRef.current = historyInput.length;
|
|
662
|
-
}
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
665
|
-
// Handle cursor movement - ignore meta flag for arrows as it's unreliable in terminals
|
|
666
|
-
// Only do word movement if ctrl is pressed AND no arrow escape sequence is in inputChar
|
|
667
|
-
if ((key.leftArrow || key.name === 'left') && key.ctrl && !inputChar.includes('[')) {
|
|
668
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
669
|
-
const newPos = moveToPreviousWord(inputRef.current, cursorPositionRef.current);
|
|
670
|
-
setCursorPositionState(newPos);
|
|
671
|
-
// BUG FIX: Synchronously update ref to prevent stale reads
|
|
672
|
-
cursorPositionRef.current = newPos;
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
if ((key.rightArrow || key.name === 'right') && key.ctrl && !inputChar.includes('[')) {
|
|
676
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
677
|
-
const newPos = moveToNextWord(inputRef.current, cursorPositionRef.current);
|
|
678
|
-
setCursorPositionState(newPos);
|
|
679
|
-
// BUG FIX: Synchronously update ref to prevent stale reads
|
|
680
|
-
cursorPositionRef.current = newPos;
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
// Handle regular cursor movement - single character (ignore meta flag)
|
|
684
|
-
if (key.leftArrow || key.name === 'left') {
|
|
685
|
-
// BUG FIX: Use ref to get CURRENT cursor position, avoiding stale closure
|
|
686
|
-
const newPos = Math.max(0, cursorPositionRef.current - 1);
|
|
687
|
-
setCursorPositionState(newPos);
|
|
688
|
-
// BUG FIX: Synchronously update ref to prevent stale reads
|
|
689
|
-
cursorPositionRef.current = newPos;
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
if (key.rightArrow || key.name === 'right') {
|
|
693
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
694
|
-
const newPos = Math.min(inputRef.current.length, cursorPositionRef.current + 1);
|
|
695
|
-
setCursorPositionState(newPos);
|
|
696
|
-
// BUG FIX: Synchronously update ref to prevent stale reads
|
|
697
|
-
cursorPositionRef.current = newPos;
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
// Handle Home/End keys or Ctrl+A/E
|
|
701
|
-
if ((key.ctrl && inputChar === "a") || key.name === "home") {
|
|
702
|
-
setCursorPositionState(0); // Simple start of input
|
|
703
|
-
// BUG FIX: Synchronously update ref to prevent stale reads
|
|
704
|
-
cursorPositionRef.current = 0;
|
|
705
|
-
return;
|
|
706
|
-
}
|
|
707
|
-
if ((key.ctrl && inputChar === "e") || key.name === "end") {
|
|
708
|
-
// BUG FIX: Use ref to get CURRENT input length, avoiding stale closure
|
|
709
|
-
const endPos = inputRef.current.length;
|
|
710
|
-
setCursorPositionState(endPos); // Simple end of input
|
|
711
|
-
// BUG FIX: Synchronously update ref to prevent stale reads
|
|
712
|
-
cursorPositionRef.current = endPos;
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
// Handle deletion - check multiple ways backspace might be detected
|
|
716
|
-
// Backspace can be detected in different ways depending on terminal
|
|
717
|
-
// In some terminals, backspace shows up as delete:true with empty inputChar
|
|
718
|
-
const isBackspace = key.backspace ||
|
|
719
|
-
key.name === 'backspace' ||
|
|
720
|
-
inputChar === '\b' ||
|
|
721
|
-
inputChar === '\x7f' ||
|
|
722
|
-
(key.delete && inputChar === '' && !key.shift);
|
|
723
|
-
if (isBackspace) {
|
|
724
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
725
|
-
const currentInput = inputRef.current;
|
|
726
|
-
const currentCursor = cursorPositionRef.current;
|
|
727
|
-
if (key.ctrl || key.meta) {
|
|
728
|
-
// Ctrl/Cmd + Backspace: Delete word before cursor
|
|
729
|
-
const result = deleteWordBefore(currentInput, currentCursor);
|
|
730
|
-
setInputState(result.text);
|
|
731
|
-
setCursorPositionState(result.position);
|
|
732
|
-
setOriginalInput(result.text);
|
|
733
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
734
|
-
inputRef.current = result.text;
|
|
735
|
-
cursorPositionRef.current = result.position;
|
|
736
|
-
}
|
|
737
|
-
else {
|
|
738
|
-
// Regular backspace
|
|
739
|
-
const result = deleteCharBefore(currentInput, currentCursor);
|
|
740
|
-
setInputState(result.text);
|
|
741
|
-
setCursorPositionState(result.position);
|
|
742
|
-
setOriginalInput(result.text);
|
|
743
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
744
|
-
inputRef.current = result.text;
|
|
745
|
-
cursorPositionRef.current = result.position;
|
|
746
|
-
}
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
// Handle forward delete (Del key) - but not if it was already handled as backspace above
|
|
750
|
-
// Note: Ctrl+D is also treated as delete character (standard terminal behavior)
|
|
751
|
-
if (key.delete && inputChar !== '') {
|
|
752
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
753
|
-
const currentInput = inputRef.current;
|
|
754
|
-
const currentCursor = cursorPositionRef.current;
|
|
755
|
-
if (key.ctrl || key.meta) {
|
|
756
|
-
// Ctrl/Cmd + Delete: Delete word after cursor
|
|
757
|
-
const result = deleteWordAfter(currentInput, currentCursor);
|
|
758
|
-
setInputState(result.text);
|
|
759
|
-
setCursorPositionState(result.position);
|
|
760
|
-
setOriginalInput(result.text);
|
|
761
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
762
|
-
inputRef.current = result.text;
|
|
763
|
-
cursorPositionRef.current = result.position;
|
|
764
|
-
}
|
|
765
|
-
else {
|
|
766
|
-
// Regular delete
|
|
767
|
-
const result = deleteCharAfter(currentInput, currentCursor);
|
|
768
|
-
setInputState(result.text);
|
|
769
|
-
setCursorPositionState(result.position);
|
|
770
|
-
setOriginalInput(result.text);
|
|
771
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
772
|
-
inputRef.current = result.text;
|
|
773
|
-
cursorPositionRef.current = result.position;
|
|
774
|
-
}
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
// Handle Ctrl+D: Delete character after cursor (standard terminal behavior)
|
|
778
|
-
if (key.ctrl && inputChar === "d") {
|
|
779
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
780
|
-
const result = deleteCharAfter(inputRef.current, cursorPositionRef.current);
|
|
781
|
-
setInputState(result.text);
|
|
782
|
-
setCursorPositionState(result.position);
|
|
783
|
-
setOriginalInput(result.text);
|
|
784
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
785
|
-
inputRef.current = result.text;
|
|
786
|
-
cursorPositionRef.current = result.position;
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
// Handle Ctrl+K: Open quick actions menu
|
|
790
|
-
// Check both key.ctrl with 'k' and raw ASCII code \x0b (Ctrl+K = ASCII 11)
|
|
791
|
-
if ((key.ctrl && inputChar === "k") || inputChar === "\x0b") {
|
|
792
|
-
onQuickActions?.();
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
// Handle Ctrl+U: Delete from cursor to start of line
|
|
796
|
-
// Check both key.ctrl with 'u' and raw ASCII code \x15 (Ctrl+U = ASCII 21)
|
|
797
|
-
if ((key.ctrl && inputChar === "u") || inputChar === "\x15") {
|
|
798
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
799
|
-
const currentInput = inputRef.current;
|
|
800
|
-
const currentCursor = cursorPositionRef.current;
|
|
801
|
-
const lineStart = moveToLineStart(currentInput, currentCursor);
|
|
802
|
-
const newText = currentInput.slice(0, lineStart) + currentInput.slice(currentCursor);
|
|
803
|
-
setInputState(newText);
|
|
804
|
-
setCursorPositionState(lineStart);
|
|
805
|
-
setOriginalInput(newText);
|
|
806
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
807
|
-
inputRef.current = newText;
|
|
808
|
-
cursorPositionRef.current = lineStart;
|
|
809
|
-
return;
|
|
810
|
-
}
|
|
811
|
-
// Handle Ctrl+W: Delete word before cursor
|
|
812
|
-
// Check both key.ctrl with 'w' and raw ASCII code \x17 (Ctrl+W = ASCII 23)
|
|
813
|
-
if ((key.ctrl && inputChar === "w") || inputChar === "\x17") {
|
|
814
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
815
|
-
const result = deleteWordBefore(inputRef.current, cursorPositionRef.current);
|
|
816
|
-
setInputState(result.text);
|
|
817
|
-
setCursorPositionState(result.position);
|
|
818
|
-
setOriginalInput(result.text);
|
|
819
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
820
|
-
inputRef.current = result.text;
|
|
821
|
-
cursorPositionRef.current = result.position;
|
|
822
|
-
return;
|
|
823
|
-
}
|
|
824
|
-
// Handle Ctrl+O: Toggle verbose mode
|
|
825
|
-
// Check both key.ctrl with 'o' and raw ASCII code \x0f (Ctrl+O = ASCII 15)
|
|
826
|
-
if ((key.ctrl && inputChar === "o") || inputChar === "\x0f") {
|
|
827
|
-
onVerboseToggle?.();
|
|
828
|
-
return;
|
|
829
|
-
}
|
|
830
|
-
// Handle Ctrl+B: Toggle background mode
|
|
831
|
-
// Check both key.ctrl with 'b' and raw ASCII code \x02 (Ctrl+B = ASCII 2)
|
|
832
|
-
if ((key.ctrl && inputChar === "b") || inputChar === "\x02") {
|
|
833
|
-
onBackgroundModeToggle?.();
|
|
834
|
-
return;
|
|
835
|
-
}
|
|
836
|
-
// Handle Ctrl+Y: Copy last response to clipboard
|
|
837
|
-
// Check both key.ctrl with 'y' and raw ASCII code \x19 (Ctrl+Y = ASCII 25)
|
|
838
|
-
if ((key.ctrl && inputChar === "y") || inputChar === "\x19") {
|
|
839
|
-
onCopyLastResponse?.();
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
// Handle Ctrl+X: Clear entire input
|
|
843
|
-
// Check both key.ctrl with 'x' and raw ASCII code \x18 (Ctrl+X = ASCII 24)
|
|
844
|
-
if ((key.ctrl && inputChar === "x") || inputChar === "\x18") {
|
|
845
|
-
setInputState("");
|
|
846
|
-
setCursorPositionState(0);
|
|
847
|
-
setOriginalInput("");
|
|
848
|
-
// BUG FIX: Clear pasted blocks when input is cleared
|
|
849
|
-
pastedBlocksRef.current = [];
|
|
850
|
-
setPastedBlocks([]);
|
|
851
|
-
// BUG FIX: Also clear pending paste accumulation to avoid unexpected behavior
|
|
852
|
-
fallbackPasteBufferRef.current = '';
|
|
853
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
854
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
855
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
856
|
-
fallbackPasteTimeoutRef.current = null;
|
|
857
|
-
}
|
|
858
|
-
setIsPasting(false);
|
|
859
|
-
bracketedPasteHandlerRef.current.reset();
|
|
860
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
861
|
-
inputRef.current = '';
|
|
862
|
-
cursorPositionRef.current = 0;
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
// Handle Shift+Tab: Toggle auto-accept mode
|
|
866
|
-
if (key.shift && key.tab) {
|
|
867
|
-
onAutoAcceptToggle?.();
|
|
868
|
-
return;
|
|
869
|
-
}
|
|
870
|
-
// Handle Tab (alone): Toggle thinking mode (only when input is empty)
|
|
871
|
-
// BUG FIX: Use inputRef.current to check current input length, avoiding stale closure
|
|
872
|
-
if (key.tab && !key.shift && !key.ctrl && !key.meta && inputRef.current.length === 0) {
|
|
873
|
-
onThinkingModeToggle?.();
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
// Handle Ctrl+G: Open external editor
|
|
877
|
-
if ((key.ctrl && inputChar === "g") || inputChar === "\x07") {
|
|
878
|
-
// BUG FIX: Use inputRef.current to get the latest input value
|
|
879
|
-
// This ensures the external editor receives current content even if
|
|
880
|
-
// there were rapid updates just before Ctrl+G was pressed
|
|
881
|
-
const currentInput = inputRef.current;
|
|
882
|
-
// Call async external editor handler
|
|
883
|
-
onExternalEditor?.(currentInput).then((editedContent) => {
|
|
884
|
-
// BUG FIX: Check if component is still mounted before updating state
|
|
885
|
-
if (!isMountedRef.current)
|
|
886
|
-
return;
|
|
887
|
-
if (editedContent !== null) {
|
|
888
|
-
setInputState(editedContent);
|
|
889
|
-
setCursorPositionState(editedContent.length);
|
|
890
|
-
// BUG FIX: Also update original input for history tracking
|
|
891
|
-
setOriginalInput(editedContent);
|
|
892
|
-
// BUG FIX: Clear pasted blocks - external editor returns fully expanded content
|
|
893
|
-
// The old block metadata is no longer valid
|
|
894
|
-
pastedBlocksRef.current = [];
|
|
895
|
-
setPastedBlocks([]);
|
|
896
|
-
// BUG FIX: Clear pending paste accumulation to prevent it from overwriting
|
|
897
|
-
// the external editor content when timeout fires
|
|
898
|
-
fallbackPasteBufferRef.current = '';
|
|
899
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
900
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
901
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
902
|
-
fallbackPasteTimeoutRef.current = null;
|
|
903
|
-
}
|
|
904
|
-
setIsPasting(false);
|
|
905
|
-
bracketedPasteHandlerRef.current.reset();
|
|
906
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
907
|
-
inputRef.current = editedContent;
|
|
908
|
-
cursorPositionRef.current = editedContent.length;
|
|
909
|
-
}
|
|
910
|
-
}).catch(() => {
|
|
911
|
-
// Ignore errors - user will see error in UI
|
|
912
|
-
});
|
|
913
|
-
return;
|
|
914
|
-
}
|
|
915
|
-
// Handle ? key: Show keyboard shortcuts help (only when input is empty)
|
|
916
|
-
// BUG FIX: Use inputRef.current to check current input length, avoiding stale closure
|
|
917
|
-
if (inputChar === "?" && inputRef.current.length === 0) {
|
|
918
|
-
onKeyboardHelp?.();
|
|
919
|
-
return;
|
|
920
|
-
}
|
|
921
|
-
// Handle regular character input
|
|
922
|
-
if (inputChar && !key.ctrl && !key.meta) {
|
|
923
|
-
// Bracketed Paste Mode Detection
|
|
924
|
-
// Uses industry-standard escape sequences for reliable paste detection
|
|
925
|
-
// Falls back to simple batched detection if not supported
|
|
926
|
-
const { enableBracketedPaste, enableFallback } = pasteConfig;
|
|
927
|
-
// Use bracketed paste handler if enabled
|
|
928
|
-
if (enableBracketedPaste) {
|
|
929
|
-
// BUG FIX: Check for orphaned content from timeout first
|
|
930
|
-
const orphanedContent = bracketedPasteHandlerRef.current.retrieveOrphanedContent();
|
|
931
|
-
if (orphanedContent) {
|
|
932
|
-
// Timeout occurred and we have accumulated content without end marker
|
|
933
|
-
// Process it as a paste
|
|
934
|
-
try {
|
|
935
|
-
handlePasteComplete(orphanedContent);
|
|
936
|
-
}
|
|
937
|
-
catch {
|
|
938
|
-
// BUG FIX: Silently ignore errors to avoid cluttering CLI output
|
|
939
|
-
// Continue despite error - don't block current input
|
|
940
|
-
}
|
|
941
|
-
// Continue processing current input normally
|
|
942
|
-
}
|
|
943
|
-
const result = bracketedPasteHandlerRef.current.handleInput(inputChar);
|
|
944
|
-
// Update pasting state for visual indicator
|
|
945
|
-
if (result.isAccumulating !== isPasting) {
|
|
946
|
-
setIsPasting(result.isAccumulating);
|
|
947
|
-
}
|
|
948
|
-
// If still accumulating, don't process yet
|
|
949
|
-
if (result.isAccumulating) {
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
// If paste detected and complete via bracketed paste mode
|
|
953
|
-
if (result.isPaste && result.content) {
|
|
954
|
-
const pastedContent = result.content;
|
|
955
|
-
// Large paste handling with truncation
|
|
956
|
-
const settingsManager = getSettingsManager();
|
|
957
|
-
const pasteSettings = settingsManager.getPasteSettings();
|
|
958
|
-
const { allowLargePaste, maxPasteLength, warningThreshold } = pasteSettings;
|
|
959
|
-
if (pastedContent.length >= warningThreshold) {
|
|
960
|
-
onLargePaste?.(pastedContent.length);
|
|
961
|
-
}
|
|
962
|
-
let finalContent = pastedContent;
|
|
963
|
-
if (!allowLargePaste && pastedContent.length > maxPasteLength) {
|
|
964
|
-
finalContent = pastedContent.slice(0, maxPasteLength);
|
|
965
|
-
onPasteTruncated?.(pastedContent.length, maxPasteLength);
|
|
966
|
-
}
|
|
967
|
-
handlePasteComplete(finalContent);
|
|
968
|
-
return;
|
|
969
|
-
}
|
|
970
|
-
// Not detected via bracketed paste mode - use fallback if enabled
|
|
971
|
-
// FIX: Only use fallback if bracketed paste is NOT currently accumulating
|
|
972
|
-
// This prevents race conditions where fallback creates duplicate blocks
|
|
973
|
-
if (enableFallback && result.content && result.content.length > 1 &&
|
|
974
|
-
!bracketedPasteHandlerRef.current.isAccumulating()) {
|
|
975
|
-
// BUG FIX: Accumulate chunks with timeout instead of immediate processing
|
|
976
|
-
// This prevents multiple blocks when paste arrives in chunks (SSH, tmux, etc)
|
|
977
|
-
const now = Date.now();
|
|
978
|
-
const isActiveAccumulation = fallbackPasteBufferRef.current.length > 0;
|
|
979
|
-
const timeSinceLastChunk = now - fallbackPasteLastChunkTimeRef.current;
|
|
980
|
-
// BUG FIX: Check buffer size to prevent overflow (100MB limit)
|
|
981
|
-
const MAX_BUFFER_SIZE = 100 * 1024 * 1024;
|
|
982
|
-
if (fallbackPasteBufferRef.current.length + result.content.length > MAX_BUFFER_SIZE) {
|
|
983
|
-
// Buffer overflow - process what we have immediately
|
|
984
|
-
const accumulatedContent = fallbackPasteBufferRef.current;
|
|
985
|
-
fallbackPasteBufferRef.current = '';
|
|
986
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
987
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
988
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
989
|
-
fallbackPasteTimeoutRef.current = null;
|
|
990
|
-
}
|
|
991
|
-
// BUG FIX: Apply paste settings like other paste paths
|
|
992
|
-
const settingsManager = getSettingsManager();
|
|
993
|
-
const pasteSettings = settingsManager.getPasteSettings();
|
|
994
|
-
const { allowLargePaste, maxPasteLength, warningThreshold } = pasteSettings;
|
|
995
|
-
// Check if paste exceeds warning threshold
|
|
996
|
-
if (accumulatedContent.length >= warningThreshold) {
|
|
997
|
-
onLargePaste?.(accumulatedContent.length);
|
|
998
|
-
}
|
|
999
|
-
// Handle truncation if needed
|
|
1000
|
-
let finalContent = accumulatedContent;
|
|
1001
|
-
if (!allowLargePaste && accumulatedContent.length > maxPasteLength) {
|
|
1002
|
-
finalContent = accumulatedContent.slice(0, maxPasteLength);
|
|
1003
|
-
onPasteTruncated?.(accumulatedContent.length, maxPasteLength);
|
|
1004
|
-
}
|
|
1005
|
-
// Process accumulated content
|
|
1006
|
-
try {
|
|
1007
|
-
handlePasteComplete(finalContent);
|
|
1008
|
-
}
|
|
1009
|
-
catch {
|
|
1010
|
-
// BUG FIX: Silently ignore - avoid cluttering CLI
|
|
1011
|
-
}
|
|
1012
|
-
return;
|
|
1013
|
-
}
|
|
1014
|
-
// Add to accumulation buffer
|
|
1015
|
-
fallbackPasteBufferRef.current += result.content;
|
|
1016
|
-
fallbackPasteLastChunkTimeRef.current = now;
|
|
1017
|
-
// Clear existing timeout
|
|
1018
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
1019
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
1020
|
-
}
|
|
1021
|
-
// Dynamic timeout: Use longer window if we're actively accumulating a paste
|
|
1022
|
-
// Initial chunk: 200ms (fast for single-burst pastes)
|
|
1023
|
-
// Subsequent chunks: 500ms (handles slow terminals/networks)
|
|
1024
|
-
const timeoutMs = isActiveAccumulation && timeSinceLastChunk < 1000 ? 500 : 200;
|
|
1025
|
-
// Set new timeout - if no more chunks arrive, process the paste
|
|
1026
|
-
fallbackPasteTimeoutRef.current = setTimeout(() => {
|
|
1027
|
-
// BUG FIX: Check if component is still mounted
|
|
1028
|
-
if (!isMountedRef.current)
|
|
1029
|
-
return;
|
|
1030
|
-
// BUG FIX: Clear refs FIRST to prevent race conditions
|
|
1031
|
-
const accumulatedContent = fallbackPasteBufferRef.current;
|
|
1032
|
-
fallbackPasteBufferRef.current = '';
|
|
1033
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
1034
|
-
fallbackPasteTimeoutRef.current = null;
|
|
1035
|
-
if (!accumulatedContent)
|
|
1036
|
-
return;
|
|
1037
|
-
const pastedContent = accumulatedContent.replace(/\r/g, '\n');
|
|
1038
|
-
const settingsManager = getSettingsManager();
|
|
1039
|
-
const pasteSettings = settingsManager.getPasteSettings();
|
|
1040
|
-
const { allowLargePaste, maxPasteLength, warningThreshold } = pasteSettings;
|
|
1041
|
-
if (pastedContent.length >= warningThreshold) {
|
|
1042
|
-
onLargePasteRef.current?.(pastedContent.length);
|
|
1043
|
-
}
|
|
1044
|
-
let finalContent = pastedContent;
|
|
1045
|
-
if (!allowLargePaste && pastedContent.length > maxPasteLength) {
|
|
1046
|
-
finalContent = pastedContent.slice(0, maxPasteLength);
|
|
1047
|
-
onPasteTruncatedRef.current?.(pastedContent.length, maxPasteLength);
|
|
1048
|
-
}
|
|
1049
|
-
try {
|
|
1050
|
-
handlePasteComplete(finalContent);
|
|
1051
|
-
}
|
|
1052
|
-
catch {
|
|
1053
|
-
// BUG FIX: Silently ignore - avoid cluttering CLI
|
|
1054
|
-
}
|
|
1055
|
-
}, timeoutMs);
|
|
1056
|
-
return;
|
|
1057
|
-
}
|
|
1058
|
-
// Normal single character input
|
|
1059
|
-
if (result.content) {
|
|
1060
|
-
// BUG FIX: If there's a pending paste accumulation, add character to it
|
|
1061
|
-
// This prevents splitting user input into paste + character
|
|
1062
|
-
if (fallbackPasteBufferRef.current.length > 0) {
|
|
1063
|
-
// Add single character to accumulation buffer
|
|
1064
|
-
fallbackPasteBufferRef.current += result.content;
|
|
1065
|
-
// Extend timeout slightly (paste likely complete, but give it 100ms more)
|
|
1066
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
1067
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
1068
|
-
}
|
|
1069
|
-
fallbackPasteTimeoutRef.current = setTimeout(() => {
|
|
1070
|
-
// BUG FIX: Check if component is still mounted
|
|
1071
|
-
if (!isMountedRef.current)
|
|
1072
|
-
return;
|
|
1073
|
-
const accumulatedContent = fallbackPasteBufferRef.current;
|
|
1074
|
-
fallbackPasteBufferRef.current = '';
|
|
1075
|
-
fallbackPasteTimeoutRef.current = null;
|
|
1076
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
1077
|
-
if (accumulatedContent) {
|
|
1078
|
-
// BUG FIX: Apply paste settings (truncation/warnings) like other paste paths
|
|
1079
|
-
const settingsManager = getSettingsManager();
|
|
1080
|
-
const pasteSettings = settingsManager.getPasteSettings();
|
|
1081
|
-
const { allowLargePaste, maxPasteLength, warningThreshold } = pasteSettings;
|
|
1082
|
-
// Check if paste exceeds warning threshold
|
|
1083
|
-
if (accumulatedContent.length >= warningThreshold) {
|
|
1084
|
-
onLargePasteRef.current?.(accumulatedContent.length);
|
|
1085
|
-
}
|
|
1086
|
-
// Handle truncation if needed
|
|
1087
|
-
let finalContent = accumulatedContent;
|
|
1088
|
-
if (!allowLargePaste && accumulatedContent.length > maxPasteLength) {
|
|
1089
|
-
finalContent = accumulatedContent.slice(0, maxPasteLength);
|
|
1090
|
-
onPasteTruncatedRef.current?.(accumulatedContent.length, maxPasteLength);
|
|
1091
|
-
}
|
|
1092
|
-
try {
|
|
1093
|
-
handlePasteComplete(finalContent);
|
|
1094
|
-
}
|
|
1095
|
-
catch {
|
|
1096
|
-
// BUG FIX: Catch errors to prevent timeout callback crash
|
|
1097
|
-
// BUG FIX: Silently ignore - avoid cluttering CLI
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
}, 100); // Short timeout for single char after paste
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
// No pending paste - process normal input
|
|
1104
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
1105
|
-
const result2 = insertText(inputRef.current, cursorPositionRef.current, result.content);
|
|
1106
|
-
setInputState(result2.text);
|
|
1107
|
-
setCursorPositionState(result2.position);
|
|
1108
|
-
setOriginalInput(result2.text);
|
|
1109
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
1110
|
-
inputRef.current = result2.text;
|
|
1111
|
-
cursorPositionRef.current = result2.position;
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
else if (enableFallback) {
|
|
1115
|
-
// Fallback: Simple batched detection (legacy behavior when bracketed paste disabled)
|
|
1116
|
-
// When inputChar.length > 1, it's likely pasted content
|
|
1117
|
-
const isPaste = inputChar.length > 1;
|
|
1118
|
-
if (isPaste) {
|
|
1119
|
-
// BUG FIX: Use same dynamic accumulation as bracketed paste fallback
|
|
1120
|
-
// This ensures consistent behavior regardless of bracketed paste support
|
|
1121
|
-
const now = Date.now();
|
|
1122
|
-
const isActiveAccumulation = fallbackPasteBufferRef.current.length > 0;
|
|
1123
|
-
const timeSinceLastChunk = now - fallbackPasteLastChunkTimeRef.current;
|
|
1124
|
-
// Normalize line endings: convert \r to \n
|
|
1125
|
-
const normalizedInput = inputChar.replace(/\r/g, '\n');
|
|
1126
|
-
// BUG FIX: Check buffer size to prevent overflow (100MB limit)
|
|
1127
|
-
const MAX_BUFFER_SIZE = 100 * 1024 * 1024;
|
|
1128
|
-
if (fallbackPasteBufferRef.current.length + normalizedInput.length > MAX_BUFFER_SIZE) {
|
|
1129
|
-
// Buffer overflow - process what we have immediately
|
|
1130
|
-
const accumulatedContent = fallbackPasteBufferRef.current;
|
|
1131
|
-
fallbackPasteBufferRef.current = '';
|
|
1132
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
1133
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
1134
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
1135
|
-
fallbackPasteTimeoutRef.current = null;
|
|
1136
|
-
}
|
|
1137
|
-
// BUG FIX: Apply paste settings like other paste paths
|
|
1138
|
-
const settingsManager = getSettingsManager();
|
|
1139
|
-
const pasteSettings = settingsManager.getPasteSettings();
|
|
1140
|
-
const { allowLargePaste, maxPasteLength, warningThreshold } = pasteSettings;
|
|
1141
|
-
// Check if paste exceeds warning threshold
|
|
1142
|
-
if (accumulatedContent.length >= warningThreshold) {
|
|
1143
|
-
onLargePaste?.(accumulatedContent.length);
|
|
1144
|
-
}
|
|
1145
|
-
// Handle truncation if needed
|
|
1146
|
-
let finalContent = accumulatedContent;
|
|
1147
|
-
if (!allowLargePaste && accumulatedContent.length > maxPasteLength) {
|
|
1148
|
-
finalContent = accumulatedContent.slice(0, maxPasteLength);
|
|
1149
|
-
onPasteTruncated?.(accumulatedContent.length, maxPasteLength);
|
|
1150
|
-
}
|
|
1151
|
-
// Process accumulated content
|
|
1152
|
-
try {
|
|
1153
|
-
handlePasteComplete(finalContent);
|
|
1154
|
-
}
|
|
1155
|
-
catch {
|
|
1156
|
-
// BUG FIX: Silently ignore - avoid cluttering CLI
|
|
1157
|
-
}
|
|
1158
|
-
return;
|
|
1159
|
-
}
|
|
1160
|
-
// Add to accumulation buffer
|
|
1161
|
-
fallbackPasteBufferRef.current += normalizedInput;
|
|
1162
|
-
fallbackPasteLastChunkTimeRef.current = now;
|
|
1163
|
-
// Clear existing timeout
|
|
1164
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
1165
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
1166
|
-
}
|
|
1167
|
-
// Dynamic timeout: Use longer window if we're actively accumulating a paste
|
|
1168
|
-
const timeoutMs = isActiveAccumulation && timeSinceLastChunk < 1000 ? 500 : 200;
|
|
1169
|
-
// Set new timeout - if no more chunks arrive, process the paste
|
|
1170
|
-
fallbackPasteTimeoutRef.current = setTimeout(() => {
|
|
1171
|
-
// BUG FIX: Check if component is still mounted
|
|
1172
|
-
if (!isMountedRef.current)
|
|
1173
|
-
return;
|
|
1174
|
-
// BUG FIX: Clear refs FIRST to prevent race conditions
|
|
1175
|
-
const accumulatedContent = fallbackPasteBufferRef.current;
|
|
1176
|
-
fallbackPasteBufferRef.current = '';
|
|
1177
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
1178
|
-
fallbackPasteTimeoutRef.current = null;
|
|
1179
|
-
if (!accumulatedContent)
|
|
1180
|
-
return;
|
|
1181
|
-
const settingsManager = getSettingsManager();
|
|
1182
|
-
const pasteSettings = settingsManager.getPasteSettings();
|
|
1183
|
-
const { allowLargePaste, maxPasteLength, warningThreshold } = pasteSettings;
|
|
1184
|
-
if (accumulatedContent.length >= warningThreshold) {
|
|
1185
|
-
onLargePasteRef.current?.(accumulatedContent.length);
|
|
1186
|
-
}
|
|
1187
|
-
let finalContent = accumulatedContent;
|
|
1188
|
-
if (!allowLargePaste && accumulatedContent.length > maxPasteLength) {
|
|
1189
|
-
finalContent = accumulatedContent.slice(0, maxPasteLength);
|
|
1190
|
-
onPasteTruncatedRef.current?.(accumulatedContent.length, maxPasteLength);
|
|
1191
|
-
}
|
|
1192
|
-
// Handle entire accumulated paste at once
|
|
1193
|
-
// Note: handlePasteComplete will use CURRENT input/cursor values from React state
|
|
1194
|
-
try {
|
|
1195
|
-
handlePasteComplete(finalContent);
|
|
1196
|
-
}
|
|
1197
|
-
catch {
|
|
1198
|
-
// BUG FIX: Catch errors to prevent timeout callback crash
|
|
1199
|
-
// BUG FIX: Silently ignore - avoid cluttering CLI
|
|
1200
|
-
// Don't attempt fallback - state might be inconsistent
|
|
1201
|
-
// The paste content is lost but system remains stable
|
|
1202
|
-
}
|
|
1203
|
-
}, timeoutMs);
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
|
-
else {
|
|
1207
|
-
// Normal single character input
|
|
1208
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
1209
|
-
const result = insertText(inputRef.current, cursorPositionRef.current, inputChar);
|
|
1210
|
-
setInputState(result.text);
|
|
1211
|
-
setCursorPositionState(result.position);
|
|
1212
|
-
setOriginalInput(result.text);
|
|
1213
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
1214
|
-
inputRef.current = result.text;
|
|
1215
|
-
cursorPositionRef.current = result.position;
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
else {
|
|
1219
|
-
// Both bracketed paste and fallback disabled - normal input only
|
|
1220
|
-
// BUG FIX: Use refs to get CURRENT values, avoiding stale closures
|
|
1221
|
-
const result = insertText(inputRef.current, cursorPositionRef.current, inputChar);
|
|
1222
|
-
setInputState(result.text);
|
|
1223
|
-
setCursorPositionState(result.position);
|
|
1224
|
-
setOriginalInput(result.text);
|
|
1225
|
-
// BUG FIX: Synchronously update refs to prevent stale reads
|
|
1226
|
-
inputRef.current = result.text;
|
|
1227
|
-
cursorPositionRef.current = result.position;
|
|
1228
|
-
}
|
|
1229
|
-
}
|
|
1230
|
-
}, [disabled, onSpecialKey, onVerboseToggle, onQuickActions, onBackgroundModeToggle, onCopyLastResponse, onAutoAcceptToggle, onThinkingModeToggle, onKeyboardHelp, onLargePaste, onPasteTruncated, onExternalEditor, onEscape, inputConfig, multiline, handleSubmit, navigateHistory, setOriginalInput, toggleBlockAtCursor, handlePasteComplete, pasteConfig, isPasting]);
|
|
1231
|
-
// Update current block at cursor when cursor position or input changes
|
|
1232
|
-
useEffect(() => {
|
|
1233
|
-
const block = findBlockAtCursor(input, cursorPosition, pastedBlocks);
|
|
1234
|
-
setCurrentBlockAtCursor(block);
|
|
1235
|
-
}, [input, cursorPosition, pastedBlocks]);
|
|
1236
|
-
// BUG FIX: Comprehensive cleanup on unmount
|
|
1237
|
-
useEffect(() => {
|
|
1238
|
-
isMountedRef.current = true;
|
|
1239
|
-
return () => {
|
|
1240
|
-
// BUG FIX: Set mounted flag to false first to prevent async state updates
|
|
1241
|
-
isMountedRef.current = false;
|
|
1242
|
-
// Clear all timeouts
|
|
1243
|
-
if (pasteTimeoutRef.current) {
|
|
1244
|
-
clearTimeout(pasteTimeoutRef.current);
|
|
1245
|
-
pasteTimeoutRef.current = null;
|
|
1246
|
-
}
|
|
1247
|
-
if (fallbackPasteTimeoutRef.current) {
|
|
1248
|
-
clearTimeout(fallbackPasteTimeoutRef.current);
|
|
1249
|
-
fallbackPasteTimeoutRef.current = null;
|
|
1250
|
-
}
|
|
1251
|
-
// Reset all detectors and handlers
|
|
1252
|
-
pasteDetectorRef.current.reset();
|
|
1253
|
-
bracketedPasteHandlerRef.current.dispose();
|
|
1254
|
-
// Clear buffers
|
|
1255
|
-
fallbackPasteBufferRef.current = '';
|
|
1256
|
-
fallbackPasteLastChunkTimeRef.current = 0;
|
|
1257
|
-
};
|
|
1258
|
-
}, []);
|
|
1259
|
-
return {
|
|
1260
|
-
input,
|
|
1261
|
-
cursorPosition,
|
|
1262
|
-
isMultiline: isMultilineRef.current,
|
|
1263
|
-
pastedBlocks,
|
|
1264
|
-
currentBlockAtCursor,
|
|
1265
|
-
isPasting,
|
|
1266
|
-
setInput,
|
|
1267
|
-
setCursorPosition,
|
|
1268
|
-
clearInput,
|
|
1269
|
-
insertAtCursor,
|
|
1270
|
-
resetHistory,
|
|
1271
|
-
handleInput,
|
|
1272
|
-
expandPlaceholdersForSubmit,
|
|
1273
|
-
};
|
|
1274
|
-
}
|
|
1275
|
-
//# sourceMappingURL=use-enhanced-input.js.map
|