@build-astron-co/nimbus 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +268 -89
- package/README.md +26 -567
- package/dist/src/agent/compaction-agent.js +24 -12
- package/dist/src/agent/context-manager.js +2 -1
- package/dist/src/agent/expand-files.js +2 -1
- package/dist/src/agent/loop.js +71 -33
- package/dist/src/agent/permissions.js +4 -2
- package/dist/src/agent/system-prompt.js +34 -17
- package/dist/src/app.js +1 -1
- package/dist/src/auth/keychain.js +8 -4
- package/dist/src/auth/store.js +70 -107
- package/dist/src/cli/init.js +35 -19
- package/dist/src/cli/run.js +18 -10
- package/dist/src/cli/serve.js +4 -2
- package/dist/src/cli.js +52 -11
- package/dist/src/commands/alias.js +5 -3
- package/dist/src/commands/audit/index.js +2 -1
- package/dist/src/commands/aws-terraform.js +36 -18
- package/dist/src/commands/completions.js +1 -1
- package/dist/src/commands/config.js +3 -2
- package/dist/src/commands/connect-github.js +92 -0
- package/dist/src/commands/cost/index.js +3 -2
- package/dist/src/commands/deploy.js +15 -10
- package/dist/src/commands/doctor.js +9 -6
- package/dist/src/commands/drift/index.js +2 -1
- package/dist/src/commands/export.js +5 -3
- package/dist/src/commands/generate-terraform.js +110 -2
- package/dist/src/commands/import.js +3 -3
- package/dist/src/commands/incident.js +10 -5
- package/dist/src/commands/login.js +8 -93
- package/dist/src/commands/logs.js +16 -8
- package/dist/src/commands/onboarding.js +6 -4
- package/dist/src/commands/pipeline.js +6 -3
- package/dist/src/commands/plugin.js +3 -2
- package/dist/src/commands/profile.js +27 -14
- package/dist/src/commands/questionnaire.js +1 -1
- package/dist/src/commands/rollback.js +3 -2
- package/dist/src/commands/rollout.js +5 -3
- package/dist/src/commands/runbook.js +17 -10
- package/dist/src/commands/schedule.js +10 -5
- package/dist/src/commands/status.js +2 -1
- package/dist/src/commands/team-context.js +12 -7
- package/dist/src/commands/template.js +1 -1
- package/dist/src/commands/tf/index.js +6 -3
- package/dist/src/commands/upgrade.js +5 -3
- package/dist/src/commands/version.js +6 -3
- package/dist/src/commands/watch.js +6 -3
- package/dist/src/compat/sqlite.js +5 -3
- package/dist/src/config/mode-store.js +2 -1
- package/dist/src/config/profiles.js +4 -2
- package/dist/src/config/types.js +2 -1
- package/dist/src/engine/executor.js +8 -4
- package/dist/src/engine/planner.js +9 -5
- package/dist/src/llm/providers/anthropic.js +6 -3
- package/dist/src/llm/providers/ollama.js +1 -1
- package/dist/src/llm/router.js +22 -7
- package/dist/src/nimbus.js +1 -0
- package/dist/src/sessions/manager.js +6 -3
- package/dist/src/sharing/viewer.js +2 -1
- package/dist/src/tools/file-ops.js +1 -2
- package/dist/src/tools/schemas/devops.js +197 -108
- package/dist/src/tools/schemas/standard.js +1 -1
- package/dist/src/ui/App.js +25 -13
- package/dist/src/ui/FileDiffModal.js +22 -11
- package/dist/src/ui/HelpModal.js +2 -1
- package/dist/src/ui/InputBox.js +6 -3
- package/dist/src/ui/MessageList.js +40 -20
- package/dist/src/ui/TerminalPane.js +2 -1
- package/dist/src/ui/ToolCallDisplay.js +12 -6
- package/dist/src/ui/TreePane.js +2 -1
- package/dist/src/ui/ink/index.js +37 -21
- package/dist/src/version.js +1 -1
- package/dist/src/watcher/index.js +8 -4
- package/package.json +3 -5
- package/src/__tests__/alias.test.ts +0 -133
- package/src/__tests__/app.test.ts +0 -76
- package/src/__tests__/audit.test.ts +0 -877
- package/src/__tests__/circuit-breaker.test.ts +0 -116
- package/src/__tests__/cli-run.test.ts +0 -351
- package/src/__tests__/compat-sqlite.test.ts +0 -68
- package/src/__tests__/context-manager.test.ts +0 -632
- package/src/__tests__/context.test.ts +0 -242
- package/src/__tests__/devops-terminal-gaps.test.ts +0 -718
- package/src/__tests__/doctor.test.ts +0 -48
- package/src/__tests__/enterprise.test.ts +0 -401
- package/src/__tests__/export.test.ts +0 -236
- package/src/__tests__/gap-11-18-20.test.ts +0 -958
- package/src/__tests__/generator.test.ts +0 -433
- package/src/__tests__/helm-streaming.test.ts +0 -127
- package/src/__tests__/hooks.test.ts +0 -582
- package/src/__tests__/incident.test.ts +0 -179
- package/src/__tests__/init.test.ts +0 -487
- package/src/__tests__/intent-parser.test.ts +0 -229
- package/src/__tests__/llm-router.test.ts +0 -209
- package/src/__tests__/logs.test.ts +0 -107
- package/src/__tests__/loop-errors.test.ts +0 -244
- package/src/__tests__/lsp.test.ts +0 -293
- package/src/__tests__/modes.test.ts +0 -336
- package/src/__tests__/perf-optimizations.test.ts +0 -847
- package/src/__tests__/permissions.test.ts +0 -338
- package/src/__tests__/pipeline.test.ts +0 -50
- package/src/__tests__/polish-phase3.test.ts +0 -340
- package/src/__tests__/profile.test.ts +0 -237
- package/src/__tests__/rollback.test.ts +0 -83
- package/src/__tests__/runbook.test.ts +0 -219
- package/src/__tests__/schedule.test.ts +0 -206
- package/src/__tests__/serve.test.ts +0 -275
- package/src/__tests__/sessions.test.ts +0 -322
- package/src/__tests__/sharing.test.ts +0 -340
- package/src/__tests__/snapshots.test.ts +0 -581
- package/src/__tests__/standalone-migration.test.ts +0 -199
- package/src/__tests__/state-db.test.ts +0 -334
- package/src/__tests__/status.test.ts +0 -158
- package/src/__tests__/stream-with-tools.test.ts +0 -778
- package/src/__tests__/subagents.test.ts +0 -176
- package/src/__tests__/system-prompt.test.ts +0 -248
- package/src/__tests__/terminal-gap-v2.test.ts +0 -395
- package/src/__tests__/terminal-parity.test.ts +0 -393
- package/src/__tests__/tf-apply.test.ts +0 -187
- package/src/__tests__/tool-converter.test.ts +0 -256
- package/src/__tests__/tool-schemas.test.ts +0 -602
- package/src/__tests__/tools.test.ts +0 -144
- package/src/__tests__/version-json.test.ts +0 -184
- package/src/__tests__/version.test.ts +0 -49
- package/src/__tests__/watch.test.ts +0 -129
- package/src/agent/compaction-agent.ts +0 -266
- package/src/agent/context-manager.ts +0 -499
- package/src/agent/context.ts +0 -427
- package/src/agent/deploy-preview.ts +0 -487
- package/src/agent/expand-files.ts +0 -108
- package/src/agent/index.ts +0 -68
- package/src/agent/loop.ts +0 -1998
- package/src/agent/modes.ts +0 -429
- package/src/agent/permissions.ts +0 -513
- package/src/agent/subagents/base.ts +0 -116
- package/src/agent/subagents/cost.ts +0 -51
- package/src/agent/subagents/explore.ts +0 -42
- package/src/agent/subagents/general.ts +0 -54
- package/src/agent/subagents/index.ts +0 -102
- package/src/agent/subagents/infra.ts +0 -59
- package/src/agent/subagents/security.ts +0 -69
- package/src/agent/system-prompt.ts +0 -990
- package/src/app.ts +0 -180
- package/src/audit/activity-log.ts +0 -290
- package/src/audit/compliance-checker.ts +0 -540
- package/src/audit/cost-tracker.ts +0 -318
- package/src/audit/index.ts +0 -23
- package/src/audit/security-scanner.ts +0 -641
- package/src/auth/guard.ts +0 -75
- package/src/auth/index.ts +0 -56
- package/src/auth/keychain.ts +0 -82
- package/src/auth/oauth.ts +0 -465
- package/src/auth/providers.ts +0 -470
- package/src/auth/sso.ts +0 -113
- package/src/auth/store.ts +0 -505
- package/src/auth/types.ts +0 -187
- package/src/build.ts +0 -141
- package/src/cli/index.ts +0 -16
- package/src/cli/init.ts +0 -1227
- package/src/cli/openapi-spec.ts +0 -356
- package/src/cli/run.ts +0 -628
- package/src/cli/serve-auth.ts +0 -80
- package/src/cli/serve.ts +0 -539
- package/src/cli/web.ts +0 -71
- package/src/cli.ts +0 -1728
- package/src/clients/core-engine-client.ts +0 -227
- package/src/clients/enterprise-client.ts +0 -334
- package/src/clients/generator-client.ts +0 -351
- package/src/clients/git-client.ts +0 -627
- package/src/clients/github-client.ts +0 -410
- package/src/clients/helm-client.ts +0 -504
- package/src/clients/index.ts +0 -80
- package/src/clients/k8s-client.ts +0 -497
- package/src/clients/llm-client.ts +0 -161
- package/src/clients/rest-client.ts +0 -130
- package/src/clients/service-discovery.ts +0 -38
- package/src/clients/terraform-client.ts +0 -482
- package/src/clients/tools-client.ts +0 -1843
- package/src/clients/ws-client.ts +0 -115
- package/src/commands/alias.ts +0 -100
- package/src/commands/analyze/index.ts +0 -352
- package/src/commands/apply/helm.ts +0 -473
- package/src/commands/apply/index.ts +0 -213
- package/src/commands/apply/k8s.ts +0 -454
- package/src/commands/apply/terraform.ts +0 -582
- package/src/commands/ask.ts +0 -167
- package/src/commands/audit/index.ts +0 -357
- package/src/commands/auth-cloud.ts +0 -407
- package/src/commands/auth-list.ts +0 -134
- package/src/commands/auth-profile.ts +0 -121
- package/src/commands/auth-refresh.ts +0 -187
- package/src/commands/auth-status.ts +0 -141
- package/src/commands/aws/ec2.ts +0 -501
- package/src/commands/aws/iam.ts +0 -397
- package/src/commands/aws/index.ts +0 -133
- package/src/commands/aws/lambda.ts +0 -396
- package/src/commands/aws/rds.ts +0 -439
- package/src/commands/aws/s3.ts +0 -439
- package/src/commands/aws/vpc.ts +0 -393
- package/src/commands/aws-discover.ts +0 -542
- package/src/commands/aws-terraform.ts +0 -755
- package/src/commands/azure/aks.ts +0 -376
- package/src/commands/azure/functions.ts +0 -253
- package/src/commands/azure/index.ts +0 -116
- package/src/commands/azure/storage.ts +0 -478
- package/src/commands/azure/vm.ts +0 -355
- package/src/commands/billing/index.ts +0 -256
- package/src/commands/chat.ts +0 -320
- package/src/commands/completions.ts +0 -268
- package/src/commands/config.ts +0 -372
- package/src/commands/cost/cloud-cost-estimator.ts +0 -266
- package/src/commands/cost/estimator.ts +0 -79
- package/src/commands/cost/index.ts +0 -810
- package/src/commands/cost/parsers/terraform.ts +0 -273
- package/src/commands/cost/parsers/types.ts +0 -25
- package/src/commands/cost/pricing/aws.ts +0 -544
- package/src/commands/cost/pricing/azure.ts +0 -499
- package/src/commands/cost/pricing/gcp.ts +0 -396
- package/src/commands/cost/pricing/index.ts +0 -40
- package/src/commands/demo.ts +0 -250
- package/src/commands/deploy.ts +0 -260
- package/src/commands/doctor.ts +0 -1386
- package/src/commands/drift/index.ts +0 -787
- package/src/commands/explain.ts +0 -277
- package/src/commands/export.ts +0 -146
- package/src/commands/feedback.ts +0 -389
- package/src/commands/fix.ts +0 -324
- package/src/commands/fs/index.ts +0 -402
- package/src/commands/gcp/compute.ts +0 -325
- package/src/commands/gcp/functions.ts +0 -271
- package/src/commands/gcp/gke.ts +0 -438
- package/src/commands/gcp/iam.ts +0 -344
- package/src/commands/gcp/index.ts +0 -129
- package/src/commands/gcp/storage.ts +0 -284
- package/src/commands/generate-helm.ts +0 -1249
- package/src/commands/generate-k8s.ts +0 -1508
- package/src/commands/generate-terraform.ts +0 -1202
- package/src/commands/gh/index.ts +0 -863
- package/src/commands/git/index.ts +0 -1343
- package/src/commands/helm/index.ts +0 -1126
- package/src/commands/help.ts +0 -715
- package/src/commands/history.ts +0 -149
- package/src/commands/import.ts +0 -868
- package/src/commands/incident.ts +0 -166
- package/src/commands/index.ts +0 -367
- package/src/commands/init.ts +0 -1051
- package/src/commands/k8s/index.ts +0 -1137
- package/src/commands/login.ts +0 -716
- package/src/commands/logout.ts +0 -83
- package/src/commands/logs.ts +0 -167
- package/src/commands/onboarding.ts +0 -405
- package/src/commands/pipeline.ts +0 -186
- package/src/commands/plan/display.ts +0 -279
- package/src/commands/plan/index.ts +0 -599
- package/src/commands/plugin.ts +0 -398
- package/src/commands/preview.ts +0 -452
- package/src/commands/profile.ts +0 -342
- package/src/commands/questionnaire.ts +0 -1172
- package/src/commands/resume.ts +0 -47
- package/src/commands/rollback.ts +0 -315
- package/src/commands/rollout.ts +0 -88
- package/src/commands/runbook.ts +0 -346
- package/src/commands/schedule.ts +0 -236
- package/src/commands/status.ts +0 -252
- package/src/commands/team/index.ts +0 -346
- package/src/commands/team-context.ts +0 -220
- package/src/commands/template.ts +0 -233
- package/src/commands/tf/index.ts +0 -1093
- package/src/commands/upgrade.ts +0 -607
- package/src/commands/usage/index.ts +0 -134
- package/src/commands/version.ts +0 -174
- package/src/commands/watch.ts +0 -153
- package/src/compat/index.ts +0 -2
- package/src/compat/runtime.ts +0 -12
- package/src/compat/sqlite.ts +0 -177
- package/src/config/index.ts +0 -17
- package/src/config/manager.ts +0 -530
- package/src/config/mode-store.ts +0 -62
- package/src/config/profiles.ts +0 -84
- package/src/config/safety-policy.ts +0 -358
- package/src/config/schema.ts +0 -125
- package/src/config/types.ts +0 -609
- package/src/config/workspace-state.ts +0 -53
- package/src/context/context-db.ts +0 -199
- package/src/demo/index.ts +0 -349
- package/src/demo/scenarios/full-journey.ts +0 -229
- package/src/demo/scenarios/getting-started.ts +0 -127
- package/src/demo/scenarios/helm-release.ts +0 -341
- package/src/demo/scenarios/k8s-deployment.ts +0 -194
- package/src/demo/scenarios/terraform-vpc.ts +0 -170
- package/src/demo/types.ts +0 -92
- package/src/engine/cost-estimator.ts +0 -480
- package/src/engine/diagram-generator.ts +0 -256
- package/src/engine/drift-detector.ts +0 -902
- package/src/engine/executor.ts +0 -1066
- package/src/engine/index.ts +0 -76
- package/src/engine/orchestrator.ts +0 -636
- package/src/engine/planner.ts +0 -787
- package/src/engine/safety.ts +0 -743
- package/src/engine/verifier.ts +0 -770
- package/src/enterprise/audit.ts +0 -348
- package/src/enterprise/auth.ts +0 -270
- package/src/enterprise/billing.ts +0 -822
- package/src/enterprise/index.ts +0 -17
- package/src/enterprise/teams.ts +0 -443
- package/src/generator/best-practices.ts +0 -1608
- package/src/generator/helm.ts +0 -630
- package/src/generator/index.ts +0 -37
- package/src/generator/intent-parser.ts +0 -514
- package/src/generator/kubernetes.ts +0 -976
- package/src/generator/terraform.ts +0 -1875
- package/src/history/index.ts +0 -8
- package/src/history/manager.ts +0 -250
- package/src/history/types.ts +0 -34
- package/src/hooks/config.ts +0 -432
- package/src/hooks/engine.ts +0 -392
- package/src/hooks/index.ts +0 -4
- package/src/llm/auth-bridge.ts +0 -198
- package/src/llm/circuit-breaker.ts +0 -140
- package/src/llm/config-loader.ts +0 -201
- package/src/llm/cost-calculator.ts +0 -171
- package/src/llm/index.ts +0 -8
- package/src/llm/model-aliases.ts +0 -115
- package/src/llm/provider-registry.ts +0 -63
- package/src/llm/providers/anthropic.ts +0 -462
- package/src/llm/providers/bedrock.ts +0 -477
- package/src/llm/providers/google.ts +0 -405
- package/src/llm/providers/ollama.ts +0 -767
- package/src/llm/providers/openai-compatible.ts +0 -340
- package/src/llm/providers/openai.ts +0 -328
- package/src/llm/providers/openrouter.ts +0 -338
- package/src/llm/router.ts +0 -1104
- package/src/llm/types.ts +0 -232
- package/src/lsp/client.ts +0 -298
- package/src/lsp/languages.ts +0 -119
- package/src/lsp/manager.ts +0 -294
- package/src/mcp/client.ts +0 -402
- package/src/mcp/index.ts +0 -5
- package/src/mcp/manager.ts +0 -133
- package/src/nimbus.ts +0 -233
- package/src/plugins/index.ts +0 -27
- package/src/plugins/loader.ts +0 -334
- package/src/plugins/manager.ts +0 -376
- package/src/plugins/types.ts +0 -284
- package/src/scanners/cicd-scanner.ts +0 -258
- package/src/scanners/cloud-scanner.ts +0 -466
- package/src/scanners/framework-scanner.ts +0 -469
- package/src/scanners/iac-scanner.ts +0 -388
- package/src/scanners/index.ts +0 -539
- package/src/scanners/language-scanner.ts +0 -276
- package/src/scanners/package-manager-scanner.ts +0 -277
- package/src/scanners/types.ts +0 -172
- package/src/sessions/manager.ts +0 -472
- package/src/sessions/types.ts +0 -44
- package/src/sharing/sync.ts +0 -300
- package/src/sharing/viewer.ts +0 -163
- package/src/snapshots/index.ts +0 -2
- package/src/snapshots/manager.ts +0 -530
- package/src/state/artifacts.ts +0 -147
- package/src/state/audit.ts +0 -137
- package/src/state/billing.ts +0 -240
- package/src/state/checkpoints.ts +0 -117
- package/src/state/config.ts +0 -67
- package/src/state/conversations.ts +0 -14
- package/src/state/credentials.ts +0 -154
- package/src/state/db.ts +0 -58
- package/src/state/index.ts +0 -26
- package/src/state/messages.ts +0 -115
- package/src/state/projects.ts +0 -123
- package/src/state/schema.ts +0 -236
- package/src/state/sessions.ts +0 -147
- package/src/state/teams.ts +0 -200
- package/src/telemetry.ts +0 -108
- package/src/tools/aws-ops.ts +0 -952
- package/src/tools/azure-ops.ts +0 -579
- package/src/tools/file-ops.ts +0 -615
- package/src/tools/gcp-ops.ts +0 -625
- package/src/tools/git-ops.ts +0 -773
- package/src/tools/github-ops.ts +0 -799
- package/src/tools/helm-ops.ts +0 -943
- package/src/tools/index.ts +0 -17
- package/src/tools/k8s-ops.ts +0 -819
- package/src/tools/schemas/converter.ts +0 -184
- package/src/tools/schemas/devops.ts +0 -3502
- package/src/tools/schemas/index.ts +0 -73
- package/src/tools/schemas/standard.ts +0 -1148
- package/src/tools/schemas/types.ts +0 -735
- package/src/tools/spawn-exec.ts +0 -148
- package/src/tools/terraform-ops.ts +0 -862
- package/src/types/ambient.d.ts +0 -193
- package/src/types/config.ts +0 -83
- package/src/types/drift.ts +0 -116
- package/src/types/enterprise.ts +0 -335
- package/src/types/index.ts +0 -20
- package/src/types/plan.ts +0 -44
- package/src/types/request.ts +0 -65
- package/src/types/response.ts +0 -54
- package/src/types/service.ts +0 -51
- package/src/ui/App.tsx +0 -2114
- package/src/ui/DeployPreview.tsx +0 -174
- package/src/ui/FileDiffModal.tsx +0 -162
- package/src/ui/Header.tsx +0 -131
- package/src/ui/HelpModal.tsx +0 -57
- package/src/ui/InputBox.tsx +0 -503
- package/src/ui/MessageList.tsx +0 -1032
- package/src/ui/PermissionPrompt.tsx +0 -163
- package/src/ui/StatusBar.tsx +0 -277
- package/src/ui/TerminalPane.tsx +0 -84
- package/src/ui/ToolCallDisplay.tsx +0 -643
- package/src/ui/TreePane.tsx +0 -132
- package/src/ui/chat-ui.ts +0 -850
- package/src/ui/index.ts +0 -33
- package/src/ui/ink/index.ts +0 -1444
- package/src/ui/streaming.ts +0 -176
- package/src/ui/theme.ts +0 -104
- package/src/ui/types.ts +0 -75
- package/src/utils/analytics.ts +0 -72
- package/src/utils/cost-warning.ts +0 -27
- package/src/utils/env.ts +0 -46
- package/src/utils/errors.ts +0 -69
- package/src/utils/event-bus.ts +0 -38
- package/src/utils/index.ts +0 -24
- package/src/utils/logger.ts +0 -171
- package/src/utils/rate-limiter.ts +0 -121
- package/src/utils/service-auth.ts +0 -49
- package/src/utils/validation.ts +0 -53
- package/src/version.ts +0 -4
- package/src/watcher/index.ts +0 -214
- package/src/wizard/approval.ts +0 -383
- package/src/wizard/index.ts +0 -25
- package/src/wizard/prompts.ts +0 -338
- package/src/wizard/types.ts +0 -172
- package/src/wizard/ui.ts +0 -556
- package/src/wizard/wizard.ts +0 -304
- package/tsconfig.json +0 -24
|
@@ -1,643 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ToolCallDisplay Component
|
|
3
|
-
*
|
|
4
|
-
* Renders one or more tool invocations inline with the conversation. Each tool
|
|
5
|
-
* call is shown in a bordered box with a header containing the tool name and
|
|
6
|
-
* status indicator. While a tool is running the box shows a Spinner; on
|
|
7
|
-
* completion or failure it shows a condensed result summary.
|
|
8
|
-
*
|
|
9
|
-
* Specialised renderers exist for common tools:
|
|
10
|
-
* - read_file: filename + optional line range
|
|
11
|
-
* - edit_file: unified diff with context lines, red/green colouring
|
|
12
|
-
* - bash: command + expandable/collapsible output
|
|
13
|
-
* - terraform: resource table
|
|
14
|
-
*
|
|
15
|
-
* All other tools fall through to a generic key/value display.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import React, { useState, useEffect } from 'react';
|
|
19
|
-
import { Box, Text, useInput } from 'ink';
|
|
20
|
-
import Spinner from 'ink-spinner';
|
|
21
|
-
import { parseTerraformPlanOutput } from '../agent/deploy-preview';
|
|
22
|
-
import type { UIToolCall } from './types';
|
|
23
|
-
|
|
24
|
-
/** Props accepted by the ToolCallDisplay component. */
|
|
25
|
-
export interface ToolCallDisplayProps {
|
|
26
|
-
toolCalls: UIToolCall[];
|
|
27
|
-
/** Whether tool call detail is expanded. Defaults to true. */
|
|
28
|
-
expanded?: boolean;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Maximum number of output lines shown for bash tool results. */
|
|
32
|
-
const MAX_BASH_OUTPUT_LINES = 50;
|
|
33
|
-
/** Lines shown in collapsed view. */
|
|
34
|
-
const COLLAPSED_LINES = 20;
|
|
35
|
-
|
|
36
|
-
/* ---------------------------------------------------------------------------
|
|
37
|
-
* Status badge
|
|
38
|
-
* -------------------------------------------------------------------------*/
|
|
39
|
-
|
|
40
|
-
/** Long-running tools that get a context hint about expected duration. */
|
|
41
|
-
const LONG_RUNNING_TOOLS = new Set([
|
|
42
|
-
'terraform', 'terraform_plan_analyze', 'deploy_preview', 'drift_detect',
|
|
43
|
-
'helm', 'k8s_rbac', 'cfn', 'gitops',
|
|
44
|
-
]);
|
|
45
|
-
|
|
46
|
-
function StatusBadge({ status, startTime }: { status: UIToolCall['status']; startTime?: number }) {
|
|
47
|
-
const [elapsed, setElapsed] = useState(0);
|
|
48
|
-
|
|
49
|
-
useEffect(() => {
|
|
50
|
-
if (status !== 'running' || !startTime) return;
|
|
51
|
-
const initial = Math.floor((Date.now() - startTime) / 1000);
|
|
52
|
-
setElapsed(initial);
|
|
53
|
-
const id = setInterval(() => {
|
|
54
|
-
setElapsed(Math.floor((Date.now() - startTime) / 1000));
|
|
55
|
-
}, 1000);
|
|
56
|
-
return () => clearInterval(id);
|
|
57
|
-
}, [status, startTime]);
|
|
58
|
-
|
|
59
|
-
switch (status) {
|
|
60
|
-
case 'pending':
|
|
61
|
-
return <Text dimColor>[pending]</Text>;
|
|
62
|
-
case 'running':
|
|
63
|
-
return (
|
|
64
|
-
<Text color="cyan">
|
|
65
|
-
<Spinner type="dots" />
|
|
66
|
-
{startTime && elapsed > 0 ? ` ${elapsed}s` : ''}
|
|
67
|
-
</Text>
|
|
68
|
-
);
|
|
69
|
-
case 'completed':
|
|
70
|
-
return <Text color="green">[done]</Text>;
|
|
71
|
-
case 'failed':
|
|
72
|
-
return <Text color="red">[failed]</Text>;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/* ---------------------------------------------------------------------------
|
|
77
|
-
* Per-tool body renderers
|
|
78
|
-
* -------------------------------------------------------------------------*/
|
|
79
|
-
|
|
80
|
-
function ReadFileBody({
|
|
81
|
-
input,
|
|
82
|
-
result,
|
|
83
|
-
}: {
|
|
84
|
-
input: Record<string, unknown>;
|
|
85
|
-
result?: UIToolCall['result'];
|
|
86
|
-
}) {
|
|
87
|
-
const filePath = String(input.file_path ?? input.path ?? '');
|
|
88
|
-
const startLine = input.start_line as number | undefined;
|
|
89
|
-
const endLine = input.end_line as number | undefined;
|
|
90
|
-
const rangeLabel =
|
|
91
|
-
startLine != null
|
|
92
|
-
? endLine != null
|
|
93
|
-
? ` (lines ${startLine}-${endLine})`
|
|
94
|
-
: ` (from line ${startLine})`
|
|
95
|
-
: '';
|
|
96
|
-
|
|
97
|
-
return (
|
|
98
|
-
<Box flexDirection="column">
|
|
99
|
-
<Text>
|
|
100
|
-
<Text dimColor>file: </Text>
|
|
101
|
-
<Text color="cyan">{filePath}</Text>
|
|
102
|
-
<Text dimColor>{rangeLabel}</Text>
|
|
103
|
-
</Text>
|
|
104
|
-
{result && !result.isError && (
|
|
105
|
-
<Text dimColor>{result.output.split('\n').length} lines read</Text>
|
|
106
|
-
)}
|
|
107
|
-
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
108
|
-
</Box>
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Compute a minimal unified diff between old and new text with context lines.
|
|
114
|
-
*/
|
|
115
|
-
function computeDiff(oldStr: string, newStr: string): React.ReactNode[] {
|
|
116
|
-
const oldLines = oldStr.split('\n');
|
|
117
|
-
const newLines = newStr.split('\n');
|
|
118
|
-
const elements: React.ReactNode[] = [];
|
|
119
|
-
|
|
120
|
-
// Find common prefix
|
|
121
|
-
let prefixLen = 0;
|
|
122
|
-
while (
|
|
123
|
-
prefixLen < oldLines.length &&
|
|
124
|
-
prefixLen < newLines.length &&
|
|
125
|
-
oldLines[prefixLen] === newLines[prefixLen]
|
|
126
|
-
) {
|
|
127
|
-
prefixLen++;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Find common suffix (from the end, but not overlapping with prefix)
|
|
131
|
-
let suffixLen = 0;
|
|
132
|
-
while (
|
|
133
|
-
suffixLen < oldLines.length - prefixLen &&
|
|
134
|
-
suffixLen < newLines.length - prefixLen &&
|
|
135
|
-
oldLines[oldLines.length - 1 - suffixLen] === newLines[newLines.length - 1 - suffixLen]
|
|
136
|
-
) {
|
|
137
|
-
suffixLen++;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Context: show up to 2 lines before the diff
|
|
141
|
-
const contextStart = Math.max(0, prefixLen - 2);
|
|
142
|
-
for (let i = contextStart; i < prefixLen; i++) {
|
|
143
|
-
elements.push(
|
|
144
|
-
<Text key={`ctx-pre-${i}`} dimColor>
|
|
145
|
-
{' '}
|
|
146
|
-
{oldLines[i]}
|
|
147
|
-
</Text>
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Removed lines (from old)
|
|
152
|
-
const oldDiffEnd = oldLines.length - suffixLen;
|
|
153
|
-
for (let i = prefixLen; i < oldDiffEnd; i++) {
|
|
154
|
-
elements.push(
|
|
155
|
-
<Text key={`rm-${i}`} color="red">
|
|
156
|
-
- {oldLines[i]}
|
|
157
|
-
</Text>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Added lines (from new)
|
|
162
|
-
const newDiffEnd = newLines.length - suffixLen;
|
|
163
|
-
for (let i = prefixLen; i < newDiffEnd; i++) {
|
|
164
|
-
elements.push(
|
|
165
|
-
<Text key={`add-${i}`} color="green">
|
|
166
|
-
+ {newLines[i]}
|
|
167
|
-
</Text>
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Context: show up to 2 lines after the diff
|
|
172
|
-
const contextEnd = Math.min(oldLines.length, oldDiffEnd + 2);
|
|
173
|
-
for (let i = oldDiffEnd; i < contextEnd; i++) {
|
|
174
|
-
elements.push(
|
|
175
|
-
<Text key={`ctx-post-${i}`} dimColor>
|
|
176
|
-
{' '}
|
|
177
|
-
{oldLines[i]}
|
|
178
|
-
</Text>
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return elements;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function EditFileBody({
|
|
186
|
-
input,
|
|
187
|
-
result,
|
|
188
|
-
}: {
|
|
189
|
-
input: Record<string, unknown>;
|
|
190
|
-
result?: UIToolCall['result'];
|
|
191
|
-
}) {
|
|
192
|
-
const filePath = String(input.file_path ?? input.path ?? '');
|
|
193
|
-
const oldStr = String(input.old_string ?? '');
|
|
194
|
-
const newStr = String(input.new_string ?? '');
|
|
195
|
-
const replaceAll = input.replace_all === true;
|
|
196
|
-
|
|
197
|
-
return (
|
|
198
|
-
<Box flexDirection="column">
|
|
199
|
-
<Text>
|
|
200
|
-
<Text dimColor>file: </Text>
|
|
201
|
-
<Text color="cyan">{filePath}</Text>
|
|
202
|
-
{replaceAll && <Text dimColor> (replace all)</Text>}
|
|
203
|
-
</Text>
|
|
204
|
-
{oldStr && (
|
|
205
|
-
<Box flexDirection="column" marginTop={1}>
|
|
206
|
-
{computeDiff(oldStr, newStr)}
|
|
207
|
-
</Box>
|
|
208
|
-
)}
|
|
209
|
-
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
210
|
-
</Box>
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function BashBody({
|
|
215
|
-
input,
|
|
216
|
-
result,
|
|
217
|
-
}: {
|
|
218
|
-
input: Record<string, unknown>;
|
|
219
|
-
result?: UIToolCall['result'];
|
|
220
|
-
}) {
|
|
221
|
-
const command = String(input.command ?? '');
|
|
222
|
-
const [expanded, setExpanded] = useState(false);
|
|
223
|
-
|
|
224
|
-
useInput((_input, key) => {
|
|
225
|
-
if (_input === 'e' && !key.ctrl && !key.meta) {
|
|
226
|
-
setExpanded(prev => !prev);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
return (
|
|
231
|
-
<Box flexDirection="column">
|
|
232
|
-
<Text>
|
|
233
|
-
<Text dimColor>$ </Text>
|
|
234
|
-
<Text bold>{command}</Text>
|
|
235
|
-
</Text>
|
|
236
|
-
{result && (
|
|
237
|
-
<Box flexDirection="column" marginTop={1}>
|
|
238
|
-
{(() => {
|
|
239
|
-
const lines = result.output.split('\n');
|
|
240
|
-
const showLimit = expanded ? MAX_BASH_OUTPUT_LINES : COLLAPSED_LINES;
|
|
241
|
-
const truncated = lines.length > showLimit;
|
|
242
|
-
const visible = truncated ? lines.slice(0, showLimit) : lines;
|
|
243
|
-
return (
|
|
244
|
-
<>
|
|
245
|
-
{visible.map((line, i) => (
|
|
246
|
-
<Text
|
|
247
|
-
key={i}
|
|
248
|
-
color={result.isError ? 'red' : undefined}
|
|
249
|
-
dimColor={!result.isError}
|
|
250
|
-
>
|
|
251
|
-
{line}
|
|
252
|
-
</Text>
|
|
253
|
-
))}
|
|
254
|
-
{truncated && (
|
|
255
|
-
<Text dimColor italic>
|
|
256
|
-
... {lines.length - showLimit} more lines{' '}
|
|
257
|
-
{expanded ? "(press 'e' to collapse)" : "(press 'e' to expand)"}
|
|
258
|
-
</Text>
|
|
259
|
-
)}
|
|
260
|
-
{!truncated && lines.length > COLLAPSED_LINES && expanded && (
|
|
261
|
-
<Text dimColor italic>
|
|
262
|
-
(press 'e' to collapse)
|
|
263
|
-
</Text>
|
|
264
|
-
)}
|
|
265
|
-
</>
|
|
266
|
-
);
|
|
267
|
-
})()}
|
|
268
|
-
</Box>
|
|
269
|
-
)}
|
|
270
|
-
</Box>
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function TerraformBody({
|
|
275
|
-
input,
|
|
276
|
-
result,
|
|
277
|
-
}: {
|
|
278
|
-
input: Record<string, unknown>;
|
|
279
|
-
result?: UIToolCall['result'];
|
|
280
|
-
}) {
|
|
281
|
-
const action = String(input.action ?? input.command ?? input.subcommand ?? 'plan');
|
|
282
|
-
|
|
283
|
-
// Gap 8: Show structured plan summary when output contains plan data
|
|
284
|
-
const isPlan = action === 'plan' || (result?.output ?? '').includes('Plan:');
|
|
285
|
-
const changes = isPlan && result && !result.isError
|
|
286
|
-
? parseTerraformPlanOutput(result.output)
|
|
287
|
-
: [];
|
|
288
|
-
|
|
289
|
-
const creates = changes.filter(c => c.action === 'create').length;
|
|
290
|
-
const updates = changes.filter(c => c.action === 'update').length;
|
|
291
|
-
const destroys = changes.filter(c => c.action === 'destroy').length;
|
|
292
|
-
const replaces = changes.filter(c => c.action === 'replace').length;
|
|
293
|
-
|
|
294
|
-
return (
|
|
295
|
-
<Box flexDirection="column">
|
|
296
|
-
<Text>
|
|
297
|
-
<Text dimColor>terraform </Text>
|
|
298
|
-
<Text bold>{action}</Text>
|
|
299
|
-
</Text>
|
|
300
|
-
|
|
301
|
-
{/* Gap 8: Structured plan summary panel */}
|
|
302
|
-
{isPlan && changes.length > 0 && result && !result.isError && (
|
|
303
|
-
<Box flexDirection="column" marginTop={1} borderStyle="single" borderColor="gray" paddingX={1}>
|
|
304
|
-
<Text bold>Plan Summary</Text>
|
|
305
|
-
<Box>
|
|
306
|
-
{creates > 0 && <Text color="green">+{creates} create </Text>}
|
|
307
|
-
{updates > 0 && <Text color="yellow">~{updates} change </Text>}
|
|
308
|
-
{destroys > 0 && <Text color="red">-{destroys} destroy </Text>}
|
|
309
|
-
{replaces > 0 && <Text color="magenta">±{replaces} replace </Text>}
|
|
310
|
-
{creates === 0 && updates === 0 && destroys === 0 && replaces === 0 && (
|
|
311
|
-
<Text dimColor>No changes</Text>
|
|
312
|
-
)}
|
|
313
|
-
</Box>
|
|
314
|
-
{changes.slice(0, 10).map((c, i) => {
|
|
315
|
-
const icon = c.action === 'create' ? '+' : c.action === 'destroy' ? '-' : c.action === 'replace' ? '±' : '~';
|
|
316
|
-
const color = c.action === 'create' ? 'green' : c.action === 'destroy' ? 'red' : c.action === 'replace' ? 'magenta' : 'yellow';
|
|
317
|
-
return (
|
|
318
|
-
<Text key={i} color={color}>
|
|
319
|
-
{icon} {c.resource}
|
|
320
|
-
</Text>
|
|
321
|
-
);
|
|
322
|
-
})}
|
|
323
|
-
{changes.length > 10 && <Text dimColor>... and {changes.length - 10} more</Text>}
|
|
324
|
-
</Box>
|
|
325
|
-
)}
|
|
326
|
-
|
|
327
|
-
{/* H1: Fallback raw line coloring — show up to 200 lines with indicator for truncation */}
|
|
328
|
-
{!(isPlan && changes.length > 0) && result && !result.isError && (
|
|
329
|
-
<Box flexDirection="column" marginTop={1}>
|
|
330
|
-
{(() => {
|
|
331
|
-
const lines = result.output.split('\n');
|
|
332
|
-
const MAX_LINES = 200;
|
|
333
|
-
const displayLines = lines.slice(0, MAX_LINES);
|
|
334
|
-
return (
|
|
335
|
-
<>
|
|
336
|
-
{displayLines.map((line, i) => {
|
|
337
|
-
let color: string | undefined;
|
|
338
|
-
if (line.startsWith('+') || line.includes('will be created')) {
|
|
339
|
-
color = 'green';
|
|
340
|
-
} else if (line.startsWith('-') || line.includes('will be destroyed')) {
|
|
341
|
-
color = 'red';
|
|
342
|
-
} else if (line.startsWith('~') || line.includes('will be updated')) {
|
|
343
|
-
color = 'yellow';
|
|
344
|
-
}
|
|
345
|
-
return (
|
|
346
|
-
<Text key={i} color={color} dimColor={!color}>
|
|
347
|
-
{line}
|
|
348
|
-
</Text>
|
|
349
|
-
);
|
|
350
|
-
})}
|
|
351
|
-
{lines.length > MAX_LINES && (
|
|
352
|
-
<Text dimColor>... {lines.length - MAX_LINES} more lines (full output saved to tool history)</Text>
|
|
353
|
-
)}
|
|
354
|
-
</>
|
|
355
|
-
);
|
|
356
|
-
})()}
|
|
357
|
-
</Box>
|
|
358
|
-
)}
|
|
359
|
-
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
360
|
-
</Box>
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/** G12: Kubectl output renderer with status colorization */
|
|
365
|
-
function KubectlBody({
|
|
366
|
-
input,
|
|
367
|
-
result,
|
|
368
|
-
}: {
|
|
369
|
-
input: Record<string, unknown>;
|
|
370
|
-
result?: UIToolCall['result'];
|
|
371
|
-
}) {
|
|
372
|
-
const action = String(input.action ?? input.command ?? 'get');
|
|
373
|
-
|
|
374
|
-
const colorizeKubectlLine = (line: string, i: number): React.ReactNode => {
|
|
375
|
-
// Status coloring for kubectl get output
|
|
376
|
-
if (/\bRunning\b/.test(line)) {
|
|
377
|
-
return <Text key={i} color="green">{line}</Text>;
|
|
378
|
-
}
|
|
379
|
-
if (/\b(Pending|ContainerCreating|Init:|PodInitializing)\b/.test(line)) {
|
|
380
|
-
return <Text key={i} color="yellow">{line}</Text>;
|
|
381
|
-
}
|
|
382
|
-
if (/\b(CrashLoopBackOff|Error|Failed|OOMKilled|ImagePullBackOff|ErrImagePull)\b/.test(line)) {
|
|
383
|
-
return <Text key={i} color="red">{line}</Text>;
|
|
384
|
-
}
|
|
385
|
-
if (/\bCompleted\b/.test(line)) {
|
|
386
|
-
return <Text key={i} color="green" dimColor>{line}</Text>;
|
|
387
|
-
}
|
|
388
|
-
if (/\bTerminating\b/.test(line)) {
|
|
389
|
-
return <Text key={i} color="yellow" dimColor>{line}</Text>;
|
|
390
|
-
}
|
|
391
|
-
return <Text key={i} dimColor>{line}</Text>;
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
return (
|
|
395
|
-
<Box flexDirection="column">
|
|
396
|
-
<Text>
|
|
397
|
-
<Text dimColor>kubectl </Text>
|
|
398
|
-
<Text bold>{action}</Text>
|
|
399
|
-
</Text>
|
|
400
|
-
{result && !result.isError && (
|
|
401
|
-
<Box flexDirection="column" marginTop={1}>
|
|
402
|
-
{/* M1: Increased from 40 to 80 lines for better kubectl output visibility */}
|
|
403
|
-
{result.output.split('\n').slice(0, 80).map((line, i) => colorizeKubectlLine(line, i))}
|
|
404
|
-
</Box>
|
|
405
|
-
)}
|
|
406
|
-
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
407
|
-
</Box>
|
|
408
|
-
);
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/** M2: Docker build progress renderer */
|
|
412
|
-
function DockerBuildBody({
|
|
413
|
-
input,
|
|
414
|
-
result,
|
|
415
|
-
streamingOutput,
|
|
416
|
-
}: {
|
|
417
|
-
input: Record<string, unknown>;
|
|
418
|
-
result?: UIToolCall['result'];
|
|
419
|
-
streamingOutput?: string;
|
|
420
|
-
}) {
|
|
421
|
-
const action = String(input.action ?? '');
|
|
422
|
-
if (action !== 'build') {
|
|
423
|
-
// Non-build actions: show raw output
|
|
424
|
-
if (result && !result.isError) {
|
|
425
|
-
return (
|
|
426
|
-
<Box flexDirection="column" marginTop={1}>
|
|
427
|
-
{result.output.split('\n').slice(0, 20).map((line, i) => (
|
|
428
|
-
<Text key={i} dimColor>{line}</Text>
|
|
429
|
-
))}
|
|
430
|
-
</Box>
|
|
431
|
-
);
|
|
432
|
-
}
|
|
433
|
-
if (result?.isError) return <Text color="red">{result.output}</Text>;
|
|
434
|
-
return null;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Parse step progress from streaming output or result
|
|
438
|
-
const outputText = streamingOutput || result?.output || '';
|
|
439
|
-
const stepMatch = outputText.match(/Step\s+(\d+)\/(\d+)/gi);
|
|
440
|
-
const lastStep = stepMatch ? stepMatch[stepMatch.length - 1] : null;
|
|
441
|
-
const totalSteps = lastStep ? parseInt(lastStep.match(/\/(\d+)/)![1]) : 0;
|
|
442
|
-
const currentStep = lastStep ? parseInt(lastStep.match(/Step\s+(\d+)/i)![1]) : 0;
|
|
443
|
-
const succeeded = outputText.includes('Successfully built') || outputText.includes('Successfully tagged');
|
|
444
|
-
const failed = result?.isError || false;
|
|
445
|
-
|
|
446
|
-
return (
|
|
447
|
-
<Box flexDirection="column" marginTop={1}>
|
|
448
|
-
{totalSteps > 0 && (
|
|
449
|
-
<Box>
|
|
450
|
-
<Text color={succeeded ? 'green' : failed ? 'red' : 'cyan'}>
|
|
451
|
-
{succeeded ? '[ok] ' : failed ? '[xx] ' : '[..] '}
|
|
452
|
-
[{currentStep}/{totalSteps} steps]
|
|
453
|
-
</Text>
|
|
454
|
-
</Box>
|
|
455
|
-
)}
|
|
456
|
-
{outputText.split('\n').filter(l => l.trim()).slice(-5).map((line, i) => {
|
|
457
|
-
const isStep = /^Step\s+\d+\/\d+/i.test(line.trim());
|
|
458
|
-
const isSuccess = /Successfully/i.test(line);
|
|
459
|
-
const isError = /error/i.test(line);
|
|
460
|
-
return (
|
|
461
|
-
<Text key={i} color={isSuccess ? 'green' : isError ? 'red' : isStep ? 'cyan' : undefined} dimColor={!isStep && !isSuccess && !isError}>
|
|
462
|
-
{line}
|
|
463
|
-
</Text>
|
|
464
|
-
);
|
|
465
|
-
})}
|
|
466
|
-
{result?.isError && <Text color="red">{result.output}</Text>}
|
|
467
|
-
</Box>
|
|
468
|
-
);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
function GenericBody({
|
|
472
|
-
input,
|
|
473
|
-
result,
|
|
474
|
-
}: {
|
|
475
|
-
input: Record<string, unknown>;
|
|
476
|
-
result?: UIToolCall['result'];
|
|
477
|
-
}) {
|
|
478
|
-
const entries = Object.entries(input).slice(0, 6);
|
|
479
|
-
const omitted = Object.keys(input).length - entries.length;
|
|
480
|
-
return (
|
|
481
|
-
<Box flexDirection="column">
|
|
482
|
-
{entries.map(([key, value]) => {
|
|
483
|
-
const str = String(value);
|
|
484
|
-
const truncated = str.length > 120;
|
|
485
|
-
return (
|
|
486
|
-
<Text key={key}>
|
|
487
|
-
<Text dimColor>{key}: </Text>
|
|
488
|
-
<Text>{truncated ? `${str.slice(0, 120)}...` : str}</Text>
|
|
489
|
-
</Text>
|
|
490
|
-
);
|
|
491
|
-
})}
|
|
492
|
-
{omitted > 0 && (
|
|
493
|
-
<Text dimColor italic>
|
|
494
|
-
... {omitted} more fields
|
|
495
|
-
</Text>
|
|
496
|
-
)}
|
|
497
|
-
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
498
|
-
{result && !result.isError && (
|
|
499
|
-
<Text dimColor>
|
|
500
|
-
{result.output.length > 120 ? `${result.output.slice(0, 120)}...` : result.output}
|
|
501
|
-
</Text>
|
|
502
|
-
)}
|
|
503
|
-
</Box>
|
|
504
|
-
);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/* ---------------------------------------------------------------------------
|
|
508
|
-
* Single tool call box
|
|
509
|
-
* -------------------------------------------------------------------------*/
|
|
510
|
-
|
|
511
|
-
function ToolCallBox({ toolCall, expanded }: { toolCall: UIToolCall; expanded: boolean }) {
|
|
512
|
-
const durationLabel = toolCall.duration != null ? ` (${toolCall.duration}ms)` : '';
|
|
513
|
-
const isLongRunning = LONG_RUNNING_TOOLS.has(toolCall.name.toLowerCase());
|
|
514
|
-
|
|
515
|
-
// Choose specialised body renderer based on tool name
|
|
516
|
-
const renderBody = () => {
|
|
517
|
-
if (!expanded && toolCall.status === 'completed') {
|
|
518
|
-
return (
|
|
519
|
-
<Text dimColor>
|
|
520
|
-
{toolCall.result
|
|
521
|
-
? toolCall.result.isError
|
|
522
|
-
? toolCall.result.output.slice(0, 80)
|
|
523
|
-
: 'completed'
|
|
524
|
-
: 'completed'}
|
|
525
|
-
</Text>
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const name = toolCall.name.toLowerCase();
|
|
530
|
-
const props = { input: toolCall.input, result: toolCall.result };
|
|
531
|
-
|
|
532
|
-
if (name === 'read_file' || name === 'read') {
|
|
533
|
-
return <ReadFileBody {...props} />;
|
|
534
|
-
}
|
|
535
|
-
if (name === 'edit_file' || name === 'edit') {
|
|
536
|
-
return <EditFileBody {...props} />;
|
|
537
|
-
}
|
|
538
|
-
if (name === 'bash' || name === 'execute' || name === 'run_command') {
|
|
539
|
-
return <BashBody {...props} />;
|
|
540
|
-
}
|
|
541
|
-
if (name.startsWith('terraform') || name === 'tf_plan' || name === 'tf_apply') {
|
|
542
|
-
return <TerraformBody {...props} />;
|
|
543
|
-
}
|
|
544
|
-
if (name === 'kubectl' || name === 'k8s') {
|
|
545
|
-
return <KubectlBody {...props} />;
|
|
546
|
-
}
|
|
547
|
-
if (name === 'docker') {
|
|
548
|
-
return <DockerBuildBody input={toolCall.input} result={toolCall.result} streamingOutput={toolCall.streamingOutput} />;
|
|
549
|
-
}
|
|
550
|
-
return <GenericBody {...props} />;
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
return (
|
|
554
|
-
<Box
|
|
555
|
-
flexDirection="column"
|
|
556
|
-
borderStyle="single"
|
|
557
|
-
borderColor={toolCall.status === 'failed' ? 'red' : 'gray'}
|
|
558
|
-
paddingX={1}
|
|
559
|
-
marginBottom={1}
|
|
560
|
-
>
|
|
561
|
-
{/* Header */}
|
|
562
|
-
<Box>
|
|
563
|
-
<StatusBadge status={toolCall.status} startTime={toolCall.startTime} />
|
|
564
|
-
<Text bold> {toolCall.name}</Text>
|
|
565
|
-
<Text dimColor>{durationLabel}</Text>
|
|
566
|
-
{/* M4: Highlight duration prominently when operation took > 5 seconds */}
|
|
567
|
-
{toolCall.status === 'completed' && toolCall.duration != null && toolCall.duration > 5000 && (
|
|
568
|
-
<Text dimColor> [{(toolCall.duration / 1000).toFixed(1)}s]</Text>
|
|
569
|
-
)}
|
|
570
|
-
{toolCall.status === 'running' && toolCall.name === 'logs' && (
|
|
571
|
-
<Text color="cyan"> ● LIVE</Text>
|
|
572
|
-
)}
|
|
573
|
-
</Box>
|
|
574
|
-
|
|
575
|
-
{/* Long-running hint */}
|
|
576
|
-
{toolCall.status === 'running' && isLongRunning && (
|
|
577
|
-
<Text dimColor italic>
|
|
578
|
-
This may take several minutes for large infrastructure changes.
|
|
579
|
-
</Text>
|
|
580
|
-
)}
|
|
581
|
-
|
|
582
|
-
{/* Streaming output — shown while tool is running */}
|
|
583
|
-
{toolCall.status === 'running' && toolCall.streamingOutput && toolCall.streamingOutput.trim() && (
|
|
584
|
-
<Box flexDirection="column" marginTop={1} marginLeft={2}>
|
|
585
|
-
<Box>
|
|
586
|
-
<Text color="green" bold>[LIVE] </Text>
|
|
587
|
-
<Text>{'─'.repeat(34)}</Text>
|
|
588
|
-
</Box>
|
|
589
|
-
{(() => {
|
|
590
|
-
const allLines = toolCall.streamingOutput!.split('\n');
|
|
591
|
-
const isTerraformOrKubectl = toolCall.name === 'terraform' || toolCall.name === 'kubectl' || toolCall.name === 'logs';
|
|
592
|
-
// M1: Increased streaming window — 60 lines for terraform/kubectl/logs, 40 for others
|
|
593
|
-
const windowSize = isTerraformOrKubectl ? 60 : 40;
|
|
594
|
-
const visibleLines = allLines.slice(-windowSize);
|
|
595
|
-
// Pad to minimum 4 lines so the live area is always visible
|
|
596
|
-
while (visibleLines.length < 4) visibleLines.push('');
|
|
597
|
-
const hiddenCount = Math.max(0, allLines.length - windowSize);
|
|
598
|
-
return (
|
|
599
|
-
<>
|
|
600
|
-
{hiddenCount > 0 && (
|
|
601
|
-
<Text dimColor>... {hiddenCount} earlier lines</Text>
|
|
602
|
-
)}
|
|
603
|
-
{visibleLines.map((line, i) => {
|
|
604
|
-
// M2: Color terraform/kubectl streaming output lines
|
|
605
|
-
let lineColor: string | undefined;
|
|
606
|
-
if (line.match(/^\s*\+/) || line.includes('will be created') || line.includes(' created')) lineColor = 'green';
|
|
607
|
-
else if (line.match(/^\s*-/) || line.includes('will be destroyed') || line.includes(' destroyed')) lineColor = 'red';
|
|
608
|
-
else if (line.match(/^\s*~/) || line.includes('will be updated') || line.includes(' modified')) lineColor = 'yellow';
|
|
609
|
-
return <Text key={i} color={lineColor ?? 'gray'} dimColor={!lineColor}>{line}</Text>;
|
|
610
|
-
})}
|
|
611
|
-
</>
|
|
612
|
-
);
|
|
613
|
-
})()}
|
|
614
|
-
</Box>
|
|
615
|
-
)}
|
|
616
|
-
|
|
617
|
-
{/* Body */}
|
|
618
|
-
<Box marginTop={1}>{renderBody()}</Box>
|
|
619
|
-
</Box>
|
|
620
|
-
);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
/* ---------------------------------------------------------------------------
|
|
624
|
-
* Public component
|
|
625
|
-
* -------------------------------------------------------------------------*/
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* ToolCallDisplay renders a list of tool invocations. When `expanded` is
|
|
629
|
-
* false, completed calls are collapsed to a single summary line.
|
|
630
|
-
*/
|
|
631
|
-
export function ToolCallDisplay({ toolCalls, expanded = true }: ToolCallDisplayProps) {
|
|
632
|
-
if (toolCalls.length === 0) {
|
|
633
|
-
return null;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
return (
|
|
637
|
-
<Box flexDirection="column" paddingX={1}>
|
|
638
|
-
{toolCalls.map(tc => (
|
|
639
|
-
<ToolCallBox key={tc.id} toolCall={tc} expanded={expanded} />
|
|
640
|
-
))}
|
|
641
|
-
</Box>
|
|
642
|
-
);
|
|
643
|
-
}
|