@build-astron-co/nimbus 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +628 -0
- package/bin/nimbus +38 -0
- package/package.json +80 -0
- package/src/__tests__/app.test.ts +76 -0
- package/src/__tests__/audit.test.ts +877 -0
- package/src/__tests__/circuit-breaker.test.ts +116 -0
- package/src/__tests__/cli-run.test.ts +115 -0
- package/src/__tests__/context-manager.test.ts +502 -0
- package/src/__tests__/context.test.ts +242 -0
- package/src/__tests__/enterprise.test.ts +401 -0
- package/src/__tests__/generator.test.ts +433 -0
- package/src/__tests__/hooks.test.ts +582 -0
- package/src/__tests__/init.test.ts +436 -0
- package/src/__tests__/intent-parser.test.ts +229 -0
- package/src/__tests__/llm-router.test.ts +209 -0
- package/src/__tests__/lsp.test.ts +293 -0
- package/src/__tests__/modes.test.ts +336 -0
- package/src/__tests__/permissions.test.ts +338 -0
- package/src/__tests__/serve.test.ts +275 -0
- package/src/__tests__/sessions.test.ts +227 -0
- package/src/__tests__/sharing.test.ts +288 -0
- package/src/__tests__/snapshots.test.ts +581 -0
- package/src/__tests__/state-db.test.ts +334 -0
- package/src/__tests__/stream-with-tools.test.ts +732 -0
- package/src/__tests__/subagents.test.ts +176 -0
- package/src/__tests__/system-prompt.test.ts +169 -0
- package/src/__tests__/tool-converter.test.ts +256 -0
- package/src/__tests__/tool-schemas.test.ts +397 -0
- package/src/__tests__/tools.test.ts +143 -0
- package/src/__tests__/version.test.ts +49 -0
- package/src/agent/compaction-agent.ts +227 -0
- package/src/agent/context-manager.ts +435 -0
- package/src/agent/context.ts +427 -0
- package/src/agent/deploy-preview.ts +426 -0
- package/src/agent/index.ts +68 -0
- package/src/agent/loop.ts +717 -0
- package/src/agent/modes.ts +429 -0
- package/src/agent/permissions.ts +466 -0
- package/src/agent/subagents/base.ts +116 -0
- package/src/agent/subagents/cost.ts +51 -0
- package/src/agent/subagents/explore.ts +42 -0
- package/src/agent/subagents/general.ts +54 -0
- package/src/agent/subagents/index.ts +102 -0
- package/src/agent/subagents/infra.ts +59 -0
- package/src/agent/subagents/security.ts +69 -0
- package/src/agent/system-prompt.ts +436 -0
- package/src/app.ts +122 -0
- package/src/audit/activity-log.ts +290 -0
- package/src/audit/compliance-checker.ts +540 -0
- package/src/audit/cost-tracker.ts +318 -0
- package/src/audit/index.ts +23 -0
- package/src/audit/security-scanner.ts +596 -0
- package/src/auth/guard.ts +75 -0
- package/src/auth/index.ts +56 -0
- package/src/auth/oauth.ts +455 -0
- package/src/auth/providers.ts +470 -0
- package/src/auth/sso.ts +113 -0
- package/src/auth/store.ts +505 -0
- package/src/auth/types.ts +187 -0
- package/src/build.ts +141 -0
- package/src/cli/index.ts +16 -0
- package/src/cli/init.ts +854 -0
- package/src/cli/openapi-spec.ts +356 -0
- package/src/cli/run.ts +237 -0
- package/src/cli/serve-auth.ts +80 -0
- package/src/cli/serve.ts +462 -0
- package/src/cli/web.ts +67 -0
- package/src/cli.ts +1417 -0
- package/src/clients/core-engine-client.ts +227 -0
- package/src/clients/enterprise-client.ts +334 -0
- package/src/clients/generator-client.ts +351 -0
- package/src/clients/git-client.ts +627 -0
- package/src/clients/github-client.ts +410 -0
- package/src/clients/helm-client.ts +504 -0
- package/src/clients/index.ts +80 -0
- package/src/clients/k8s-client.ts +497 -0
- package/src/clients/llm-client.ts +161 -0
- package/src/clients/rest-client.ts +130 -0
- package/src/clients/service-discovery.ts +33 -0
- package/src/clients/terraform-client.ts +482 -0
- package/src/clients/tools-client.ts +1843 -0
- package/src/clients/ws-client.ts +115 -0
- package/src/commands/analyze/index.ts +352 -0
- package/src/commands/apply/helm.ts +473 -0
- package/src/commands/apply/index.ts +213 -0
- package/src/commands/apply/k8s.ts +454 -0
- package/src/commands/apply/terraform.ts +582 -0
- package/src/commands/ask.ts +167 -0
- package/src/commands/audit/index.ts +238 -0
- package/src/commands/auth-cloud.ts +294 -0
- package/src/commands/auth-list.ts +134 -0
- package/src/commands/auth-profile.ts +121 -0
- package/src/commands/auth-status.ts +141 -0
- package/src/commands/aws/ec2.ts +501 -0
- package/src/commands/aws/iam.ts +397 -0
- package/src/commands/aws/index.ts +133 -0
- package/src/commands/aws/lambda.ts +396 -0
- package/src/commands/aws/rds.ts +439 -0
- package/src/commands/aws/s3.ts +439 -0
- package/src/commands/aws/vpc.ts +393 -0
- package/src/commands/aws-discover.ts +649 -0
- package/src/commands/aws-terraform.ts +805 -0
- package/src/commands/azure/aks.ts +376 -0
- package/src/commands/azure/functions.ts +253 -0
- package/src/commands/azure/index.ts +116 -0
- package/src/commands/azure/storage.ts +478 -0
- package/src/commands/azure/vm.ts +355 -0
- package/src/commands/billing/index.ts +256 -0
- package/src/commands/chat.ts +314 -0
- package/src/commands/config.ts +346 -0
- package/src/commands/cost/cloud-cost-estimator.ts +266 -0
- package/src/commands/cost/estimator.ts +79 -0
- package/src/commands/cost/index.ts +594 -0
- package/src/commands/cost/parsers/terraform.ts +273 -0
- package/src/commands/cost/parsers/types.ts +25 -0
- package/src/commands/cost/pricing/aws.ts +544 -0
- package/src/commands/cost/pricing/azure.ts +499 -0
- package/src/commands/cost/pricing/gcp.ts +396 -0
- package/src/commands/cost/pricing/index.ts +40 -0
- package/src/commands/demo.ts +250 -0
- package/src/commands/doctor.ts +794 -0
- package/src/commands/drift/index.ts +439 -0
- package/src/commands/explain.ts +277 -0
- package/src/commands/feedback.ts +389 -0
- package/src/commands/fix.ts +324 -0
- package/src/commands/fs/index.ts +402 -0
- package/src/commands/gcp/compute.ts +325 -0
- package/src/commands/gcp/functions.ts +271 -0
- package/src/commands/gcp/gke.ts +438 -0
- package/src/commands/gcp/iam.ts +344 -0
- package/src/commands/gcp/index.ts +129 -0
- package/src/commands/gcp/storage.ts +284 -0
- package/src/commands/generate-helm.ts +1249 -0
- package/src/commands/generate-k8s.ts +1560 -0
- package/src/commands/generate-terraform.ts +1460 -0
- package/src/commands/gh/index.ts +863 -0
- package/src/commands/git/index.ts +1343 -0
- package/src/commands/helm/index.ts +1126 -0
- package/src/commands/help.ts +539 -0
- package/src/commands/history.ts +142 -0
- package/src/commands/import.ts +868 -0
- package/src/commands/index.ts +367 -0
- package/src/commands/init.ts +1046 -0
- package/src/commands/k8s/index.ts +1137 -0
- package/src/commands/login.ts +631 -0
- package/src/commands/logout.ts +83 -0
- package/src/commands/onboarding.ts +228 -0
- package/src/commands/plan/display.ts +279 -0
- package/src/commands/plan/index.ts +599 -0
- package/src/commands/preview.ts +452 -0
- package/src/commands/questionnaire.ts +1270 -0
- package/src/commands/resume.ts +55 -0
- package/src/commands/team/index.ts +346 -0
- package/src/commands/template.ts +232 -0
- package/src/commands/tf/index.ts +1034 -0
- package/src/commands/upgrade.ts +550 -0
- package/src/commands/usage/index.ts +134 -0
- package/src/commands/version.ts +170 -0
- package/src/compat/index.ts +2 -0
- package/src/compat/runtime.ts +12 -0
- package/src/compat/sqlite.ts +107 -0
- package/src/config/index.ts +17 -0
- package/src/config/manager.ts +530 -0
- package/src/config/safety-policy.ts +358 -0
- package/src/config/schema.ts +125 -0
- package/src/config/types.ts +527 -0
- package/src/context/context-db.ts +199 -0
- package/src/demo/index.ts +349 -0
- package/src/demo/scenarios/full-journey.ts +229 -0
- package/src/demo/scenarios/getting-started.ts +127 -0
- package/src/demo/scenarios/helm-release.ts +341 -0
- package/src/demo/scenarios/k8s-deployment.ts +194 -0
- package/src/demo/scenarios/terraform-vpc.ts +170 -0
- package/src/demo/types.ts +92 -0
- package/src/engine/cost-estimator.ts +438 -0
- package/src/engine/diagram-generator.ts +256 -0
- package/src/engine/drift-detector.ts +902 -0
- package/src/engine/executor.ts +1035 -0
- package/src/engine/index.ts +76 -0
- package/src/engine/orchestrator.ts +636 -0
- package/src/engine/planner.ts +720 -0
- package/src/engine/safety.ts +743 -0
- package/src/engine/verifier.ts +770 -0
- package/src/enterprise/audit.ts +348 -0
- package/src/enterprise/auth.ts +270 -0
- package/src/enterprise/billing.ts +822 -0
- package/src/enterprise/index.ts +17 -0
- package/src/enterprise/teams.ts +443 -0
- package/src/generator/best-practices.ts +1608 -0
- package/src/generator/helm.ts +630 -0
- package/src/generator/index.ts +37 -0
- package/src/generator/intent-parser.ts +514 -0
- package/src/generator/kubernetes.ts +976 -0
- package/src/generator/terraform.ts +1867 -0
- package/src/history/index.ts +8 -0
- package/src/history/manager.ts +322 -0
- package/src/history/types.ts +34 -0
- package/src/hooks/config.ts +432 -0
- package/src/hooks/engine.ts +391 -0
- package/src/hooks/index.ts +4 -0
- package/src/llm/auth-bridge.ts +198 -0
- package/src/llm/circuit-breaker.ts +140 -0
- package/src/llm/config-loader.ts +201 -0
- package/src/llm/cost-calculator.ts +171 -0
- package/src/llm/index.ts +8 -0
- package/src/llm/model-aliases.ts +115 -0
- package/src/llm/provider-registry.ts +63 -0
- package/src/llm/providers/anthropic.ts +433 -0
- package/src/llm/providers/bedrock.ts +477 -0
- package/src/llm/providers/google.ts +405 -0
- package/src/llm/providers/ollama.ts +767 -0
- package/src/llm/providers/openai-compatible.ts +340 -0
- package/src/llm/providers/openai.ts +328 -0
- package/src/llm/providers/openrouter.ts +338 -0
- package/src/llm/router.ts +1035 -0
- package/src/llm/types.ts +232 -0
- package/src/lsp/client.ts +298 -0
- package/src/lsp/languages.ts +116 -0
- package/src/lsp/manager.ts +278 -0
- package/src/mcp/client.ts +402 -0
- package/src/mcp/index.ts +5 -0
- package/src/mcp/manager.ts +133 -0
- package/src/nimbus.ts +214 -0
- package/src/plugins/index.ts +27 -0
- package/src/plugins/loader.ts +334 -0
- package/src/plugins/manager.ts +376 -0
- package/src/plugins/types.ts +284 -0
- package/src/scanners/cicd-scanner.ts +258 -0
- package/src/scanners/cloud-scanner.ts +466 -0
- package/src/scanners/framework-scanner.ts +469 -0
- package/src/scanners/iac-scanner.ts +388 -0
- package/src/scanners/index.ts +539 -0
- package/src/scanners/language-scanner.ts +276 -0
- package/src/scanners/package-manager-scanner.ts +277 -0
- package/src/scanners/types.ts +172 -0
- package/src/sessions/manager.ts +365 -0
- package/src/sessions/types.ts +44 -0
- package/src/sharing/sync.ts +296 -0
- package/src/sharing/viewer.ts +97 -0
- package/src/snapshots/index.ts +2 -0
- package/src/snapshots/manager.ts +530 -0
- package/src/state/artifacts.ts +147 -0
- package/src/state/audit.ts +137 -0
- package/src/state/billing.ts +240 -0
- package/src/state/checkpoints.ts +117 -0
- package/src/state/config.ts +67 -0
- package/src/state/conversations.ts +14 -0
- package/src/state/credentials.ts +154 -0
- package/src/state/db.ts +58 -0
- package/src/state/index.ts +26 -0
- package/src/state/messages.ts +115 -0
- package/src/state/projects.ts +123 -0
- package/src/state/schema.ts +236 -0
- package/src/state/sessions.ts +147 -0
- package/src/state/teams.ts +200 -0
- package/src/telemetry.ts +108 -0
- package/src/tools/aws-ops.ts +952 -0
- package/src/tools/azure-ops.ts +579 -0
- package/src/tools/file-ops.ts +593 -0
- package/src/tools/gcp-ops.ts +625 -0
- package/src/tools/git-ops.ts +773 -0
- package/src/tools/github-ops.ts +799 -0
- package/src/tools/helm-ops.ts +943 -0
- package/src/tools/index.ts +17 -0
- package/src/tools/k8s-ops.ts +819 -0
- package/src/tools/schemas/converter.ts +184 -0
- package/src/tools/schemas/devops.ts +612 -0
- package/src/tools/schemas/index.ts +73 -0
- package/src/tools/schemas/standard.ts +1144 -0
- package/src/tools/schemas/types.ts +705 -0
- package/src/tools/terraform-ops.ts +862 -0
- package/src/types/ambient.d.ts +193 -0
- package/src/types/config.ts +83 -0
- package/src/types/drift.ts +116 -0
- package/src/types/enterprise.ts +335 -0
- package/src/types/index.ts +20 -0
- package/src/types/plan.ts +44 -0
- package/src/types/request.ts +65 -0
- package/src/types/response.ts +54 -0
- package/src/types/service.ts +51 -0
- package/src/ui/App.tsx +997 -0
- package/src/ui/DeployPreview.tsx +169 -0
- package/src/ui/Header.tsx +68 -0
- package/src/ui/InputBox.tsx +350 -0
- package/src/ui/MessageList.tsx +585 -0
- package/src/ui/PermissionPrompt.tsx +151 -0
- package/src/ui/StatusBar.tsx +158 -0
- package/src/ui/ToolCallDisplay.tsx +409 -0
- package/src/ui/chat-ui.ts +853 -0
- package/src/ui/index.ts +33 -0
- package/src/ui/ink/index.ts +711 -0
- package/src/ui/streaming.ts +176 -0
- package/src/ui/types.ts +57 -0
- package/src/utils/analytics.ts +72 -0
- package/src/utils/cost-warning.ts +27 -0
- package/src/utils/env.ts +46 -0
- package/src/utils/errors.ts +69 -0
- package/src/utils/event-bus.ts +38 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/logger.ts +171 -0
- package/src/utils/rate-limiter.ts +121 -0
- package/src/utils/service-auth.ts +49 -0
- package/src/utils/validation.ts +53 -0
- package/src/version.ts +4 -0
- package/src/watcher/index.ts +163 -0
- package/src/wizard/approval.ts +383 -0
- package/src/wizard/index.ts +25 -0
- package/src/wizard/prompts.ts +338 -0
- package/src/wizard/types.ts +171 -0
- package/src/wizard/ui.ts +556 -0
- package/src/wizard/wizard.ts +304 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,409 @@
|
|
|
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 } from 'react';
|
|
19
|
+
import { Box, Text, useInput } from 'ink';
|
|
20
|
+
import Spinner from 'ink-spinner';
|
|
21
|
+
import type { UIToolCall } from './types';
|
|
22
|
+
|
|
23
|
+
/** Props accepted by the ToolCallDisplay component. */
|
|
24
|
+
export interface ToolCallDisplayProps {
|
|
25
|
+
toolCalls: UIToolCall[];
|
|
26
|
+
/** Whether tool call detail is expanded. Defaults to true. */
|
|
27
|
+
expanded?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Maximum number of output lines shown for bash tool results. */
|
|
31
|
+
const MAX_BASH_OUTPUT_LINES = 50;
|
|
32
|
+
/** Lines shown in collapsed view. */
|
|
33
|
+
const COLLAPSED_LINES = 20;
|
|
34
|
+
|
|
35
|
+
/* ---------------------------------------------------------------------------
|
|
36
|
+
* Status badge
|
|
37
|
+
* -------------------------------------------------------------------------*/
|
|
38
|
+
|
|
39
|
+
function StatusBadge({ status }: { status: UIToolCall['status'] }) {
|
|
40
|
+
switch (status) {
|
|
41
|
+
case 'pending':
|
|
42
|
+
return <Text dimColor>[pending]</Text>;
|
|
43
|
+
case 'running':
|
|
44
|
+
return (
|
|
45
|
+
<Text color="cyan">
|
|
46
|
+
<Spinner type="dots" />
|
|
47
|
+
</Text>
|
|
48
|
+
);
|
|
49
|
+
case 'completed':
|
|
50
|
+
return <Text color="green">[done]</Text>;
|
|
51
|
+
case 'failed':
|
|
52
|
+
return <Text color="red">[failed]</Text>;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* ---------------------------------------------------------------------------
|
|
57
|
+
* Per-tool body renderers
|
|
58
|
+
* -------------------------------------------------------------------------*/
|
|
59
|
+
|
|
60
|
+
function ReadFileBody({
|
|
61
|
+
input,
|
|
62
|
+
result,
|
|
63
|
+
}: {
|
|
64
|
+
input: Record<string, unknown>;
|
|
65
|
+
result?: UIToolCall['result'];
|
|
66
|
+
}) {
|
|
67
|
+
const filePath = String(input.file_path ?? input.path ?? '');
|
|
68
|
+
const startLine = input.start_line as number | undefined;
|
|
69
|
+
const endLine = input.end_line as number | undefined;
|
|
70
|
+
const rangeLabel =
|
|
71
|
+
startLine != null
|
|
72
|
+
? endLine != null
|
|
73
|
+
? ` (lines ${startLine}-${endLine})`
|
|
74
|
+
: ` (from line ${startLine})`
|
|
75
|
+
: '';
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<Box flexDirection="column">
|
|
79
|
+
<Text>
|
|
80
|
+
<Text dimColor>file: </Text>
|
|
81
|
+
<Text color="cyan">{filePath}</Text>
|
|
82
|
+
<Text dimColor>{rangeLabel}</Text>
|
|
83
|
+
</Text>
|
|
84
|
+
{result && !result.isError && (
|
|
85
|
+
<Text dimColor>{result.output.split('\n').length} lines read</Text>
|
|
86
|
+
)}
|
|
87
|
+
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
88
|
+
</Box>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Compute a minimal unified diff between old and new text with context lines.
|
|
94
|
+
*/
|
|
95
|
+
function computeDiff(oldStr: string, newStr: string): React.ReactNode[] {
|
|
96
|
+
const oldLines = oldStr.split('\n');
|
|
97
|
+
const newLines = newStr.split('\n');
|
|
98
|
+
const elements: React.ReactNode[] = [];
|
|
99
|
+
|
|
100
|
+
// Find common prefix
|
|
101
|
+
let prefixLen = 0;
|
|
102
|
+
while (
|
|
103
|
+
prefixLen < oldLines.length &&
|
|
104
|
+
prefixLen < newLines.length &&
|
|
105
|
+
oldLines[prefixLen] === newLines[prefixLen]
|
|
106
|
+
) {
|
|
107
|
+
prefixLen++;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Find common suffix (from the end, but not overlapping with prefix)
|
|
111
|
+
let suffixLen = 0;
|
|
112
|
+
while (
|
|
113
|
+
suffixLen < oldLines.length - prefixLen &&
|
|
114
|
+
suffixLen < newLines.length - prefixLen &&
|
|
115
|
+
oldLines[oldLines.length - 1 - suffixLen] === newLines[newLines.length - 1 - suffixLen]
|
|
116
|
+
) {
|
|
117
|
+
suffixLen++;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Context: show up to 2 lines before the diff
|
|
121
|
+
const contextStart = Math.max(0, prefixLen - 2);
|
|
122
|
+
for (let i = contextStart; i < prefixLen; i++) {
|
|
123
|
+
elements.push(
|
|
124
|
+
<Text key={`ctx-pre-${i}`} dimColor>
|
|
125
|
+
{' '}
|
|
126
|
+
{oldLines[i]}
|
|
127
|
+
</Text>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Removed lines (from old)
|
|
132
|
+
const oldDiffEnd = oldLines.length - suffixLen;
|
|
133
|
+
for (let i = prefixLen; i < oldDiffEnd; i++) {
|
|
134
|
+
elements.push(
|
|
135
|
+
<Text key={`rm-${i}`} color="red">
|
|
136
|
+
- {oldLines[i]}
|
|
137
|
+
</Text>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Added lines (from new)
|
|
142
|
+
const newDiffEnd = newLines.length - suffixLen;
|
|
143
|
+
for (let i = prefixLen; i < newDiffEnd; i++) {
|
|
144
|
+
elements.push(
|
|
145
|
+
<Text key={`add-${i}`} color="green">
|
|
146
|
+
+ {newLines[i]}
|
|
147
|
+
</Text>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Context: show up to 2 lines after the diff
|
|
152
|
+
const contextEnd = Math.min(oldLines.length, oldDiffEnd + 2);
|
|
153
|
+
for (let i = oldDiffEnd; i < contextEnd; i++) {
|
|
154
|
+
elements.push(
|
|
155
|
+
<Text key={`ctx-post-${i}`} dimColor>
|
|
156
|
+
{' '}
|
|
157
|
+
{oldLines[i]}
|
|
158
|
+
</Text>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return elements;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function EditFileBody({
|
|
166
|
+
input,
|
|
167
|
+
result,
|
|
168
|
+
}: {
|
|
169
|
+
input: Record<string, unknown>;
|
|
170
|
+
result?: UIToolCall['result'];
|
|
171
|
+
}) {
|
|
172
|
+
const filePath = String(input.file_path ?? input.path ?? '');
|
|
173
|
+
const oldStr = String(input.old_string ?? '');
|
|
174
|
+
const newStr = String(input.new_string ?? '');
|
|
175
|
+
const replaceAll = input.replace_all === true;
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<Box flexDirection="column">
|
|
179
|
+
<Text>
|
|
180
|
+
<Text dimColor>file: </Text>
|
|
181
|
+
<Text color="cyan">{filePath}</Text>
|
|
182
|
+
{replaceAll && <Text dimColor> (replace all)</Text>}
|
|
183
|
+
</Text>
|
|
184
|
+
{oldStr && (
|
|
185
|
+
<Box flexDirection="column" marginTop={1}>
|
|
186
|
+
{computeDiff(oldStr, newStr)}
|
|
187
|
+
</Box>
|
|
188
|
+
)}
|
|
189
|
+
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
190
|
+
</Box>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function BashBody({
|
|
195
|
+
input,
|
|
196
|
+
result,
|
|
197
|
+
}: {
|
|
198
|
+
input: Record<string, unknown>;
|
|
199
|
+
result?: UIToolCall['result'];
|
|
200
|
+
}) {
|
|
201
|
+
const command = String(input.command ?? '');
|
|
202
|
+
const [expanded, setExpanded] = useState(false);
|
|
203
|
+
|
|
204
|
+
useInput((_input, key) => {
|
|
205
|
+
if (_input === 'e' && !key.ctrl && !key.meta) {
|
|
206
|
+
setExpanded(prev => !prev);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<Box flexDirection="column">
|
|
212
|
+
<Text>
|
|
213
|
+
<Text dimColor>$ </Text>
|
|
214
|
+
<Text bold>{command}</Text>
|
|
215
|
+
</Text>
|
|
216
|
+
{result && (
|
|
217
|
+
<Box flexDirection="column" marginTop={1}>
|
|
218
|
+
{(() => {
|
|
219
|
+
const lines = result.output.split('\n');
|
|
220
|
+
const showLimit = expanded ? MAX_BASH_OUTPUT_LINES : COLLAPSED_LINES;
|
|
221
|
+
const truncated = lines.length > showLimit;
|
|
222
|
+
const visible = truncated ? lines.slice(0, showLimit) : lines;
|
|
223
|
+
return (
|
|
224
|
+
<>
|
|
225
|
+
{visible.map((line, i) => (
|
|
226
|
+
<Text
|
|
227
|
+
key={i}
|
|
228
|
+
color={result.isError ? 'red' : undefined}
|
|
229
|
+
dimColor={!result.isError}
|
|
230
|
+
>
|
|
231
|
+
{line}
|
|
232
|
+
</Text>
|
|
233
|
+
))}
|
|
234
|
+
{truncated && (
|
|
235
|
+
<Text dimColor italic>
|
|
236
|
+
... {lines.length - showLimit} more lines{' '}
|
|
237
|
+
{expanded ? "(press 'e' to collapse)" : "(press 'e' to expand)"}
|
|
238
|
+
</Text>
|
|
239
|
+
)}
|
|
240
|
+
{!truncated && lines.length > COLLAPSED_LINES && expanded && (
|
|
241
|
+
<Text dimColor italic>
|
|
242
|
+
(press 'e' to collapse)
|
|
243
|
+
</Text>
|
|
244
|
+
)}
|
|
245
|
+
</>
|
|
246
|
+
);
|
|
247
|
+
})()}
|
|
248
|
+
</Box>
|
|
249
|
+
)}
|
|
250
|
+
</Box>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function TerraformBody({
|
|
255
|
+
input,
|
|
256
|
+
result,
|
|
257
|
+
}: {
|
|
258
|
+
input: Record<string, unknown>;
|
|
259
|
+
result?: UIToolCall['result'];
|
|
260
|
+
}) {
|
|
261
|
+
const subcommand = String(input.command ?? input.subcommand ?? 'plan');
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<Box flexDirection="column">
|
|
265
|
+
<Text>
|
|
266
|
+
<Text dimColor>terraform </Text>
|
|
267
|
+
<Text bold>{subcommand}</Text>
|
|
268
|
+
</Text>
|
|
269
|
+
{result && !result.isError && (
|
|
270
|
+
<Box flexDirection="column" marginTop={1}>
|
|
271
|
+
{result.output.split('\n').map((line, i) => {
|
|
272
|
+
let color: string | undefined;
|
|
273
|
+
if (line.startsWith('+') || line.includes('will be created')) {
|
|
274
|
+
color = 'green';
|
|
275
|
+
} else if (line.startsWith('-') || line.includes('will be destroyed')) {
|
|
276
|
+
color = 'red';
|
|
277
|
+
} else if (line.startsWith('~') || line.includes('will be updated')) {
|
|
278
|
+
color = 'yellow';
|
|
279
|
+
}
|
|
280
|
+
return (
|
|
281
|
+
<Text key={i} color={color} dimColor={!color}>
|
|
282
|
+
{line}
|
|
283
|
+
</Text>
|
|
284
|
+
);
|
|
285
|
+
})}
|
|
286
|
+
</Box>
|
|
287
|
+
)}
|
|
288
|
+
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
289
|
+
</Box>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function GenericBody({
|
|
294
|
+
input,
|
|
295
|
+
result,
|
|
296
|
+
}: {
|
|
297
|
+
input: Record<string, unknown>;
|
|
298
|
+
result?: UIToolCall['result'];
|
|
299
|
+
}) {
|
|
300
|
+
const entries = Object.entries(input).slice(0, 6);
|
|
301
|
+
const omitted = Object.keys(input).length - entries.length;
|
|
302
|
+
return (
|
|
303
|
+
<Box flexDirection="column">
|
|
304
|
+
{entries.map(([key, value]) => {
|
|
305
|
+
const str = String(value);
|
|
306
|
+
const truncated = str.length > 120;
|
|
307
|
+
return (
|
|
308
|
+
<Text key={key}>
|
|
309
|
+
<Text dimColor>{key}: </Text>
|
|
310
|
+
<Text>{truncated ? `${str.slice(0, 120)}...` : str}</Text>
|
|
311
|
+
</Text>
|
|
312
|
+
);
|
|
313
|
+
})}
|
|
314
|
+
{omitted > 0 && (
|
|
315
|
+
<Text dimColor italic>
|
|
316
|
+
... {omitted} more fields
|
|
317
|
+
</Text>
|
|
318
|
+
)}
|
|
319
|
+
{result && result.isError && <Text color="red">{result.output}</Text>}
|
|
320
|
+
{result && !result.isError && (
|
|
321
|
+
<Text dimColor>
|
|
322
|
+
{result.output.length > 120 ? `${result.output.slice(0, 120)}...` : result.output}
|
|
323
|
+
</Text>
|
|
324
|
+
)}
|
|
325
|
+
</Box>
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* ---------------------------------------------------------------------------
|
|
330
|
+
* Single tool call box
|
|
331
|
+
* -------------------------------------------------------------------------*/
|
|
332
|
+
|
|
333
|
+
function ToolCallBox({ toolCall, expanded }: { toolCall: UIToolCall; expanded: boolean }) {
|
|
334
|
+
const durationLabel = toolCall.duration != null ? ` (${toolCall.duration}ms)` : '';
|
|
335
|
+
|
|
336
|
+
// Choose specialised body renderer based on tool name
|
|
337
|
+
const renderBody = () => {
|
|
338
|
+
if (!expanded && toolCall.status === 'completed') {
|
|
339
|
+
return (
|
|
340
|
+
<Text dimColor>
|
|
341
|
+
{toolCall.result
|
|
342
|
+
? toolCall.result.isError
|
|
343
|
+
? toolCall.result.output.slice(0, 80)
|
|
344
|
+
: 'completed'
|
|
345
|
+
: 'completed'}
|
|
346
|
+
</Text>
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const name = toolCall.name.toLowerCase();
|
|
351
|
+
const props = { input: toolCall.input, result: toolCall.result };
|
|
352
|
+
|
|
353
|
+
if (name === 'read_file' || name === 'read') {
|
|
354
|
+
return <ReadFileBody {...props} />;
|
|
355
|
+
}
|
|
356
|
+
if (name === 'edit_file' || name === 'edit') {
|
|
357
|
+
return <EditFileBody {...props} />;
|
|
358
|
+
}
|
|
359
|
+
if (name === 'bash' || name === 'execute' || name === 'run_command') {
|
|
360
|
+
return <BashBody {...props} />;
|
|
361
|
+
}
|
|
362
|
+
if (name.startsWith('terraform') || name === 'tf_plan' || name === 'tf_apply') {
|
|
363
|
+
return <TerraformBody {...props} />;
|
|
364
|
+
}
|
|
365
|
+
return <GenericBody {...props} />;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
return (
|
|
369
|
+
<Box
|
|
370
|
+
flexDirection="column"
|
|
371
|
+
borderStyle="single"
|
|
372
|
+
borderColor={toolCall.status === 'failed' ? 'red' : 'gray'}
|
|
373
|
+
paddingX={1}
|
|
374
|
+
marginBottom={1}
|
|
375
|
+
>
|
|
376
|
+
{/* Header */}
|
|
377
|
+
<Box>
|
|
378
|
+
<StatusBadge status={toolCall.status} />
|
|
379
|
+
<Text bold> {toolCall.name}</Text>
|
|
380
|
+
<Text dimColor>{durationLabel}</Text>
|
|
381
|
+
</Box>
|
|
382
|
+
|
|
383
|
+
{/* Body */}
|
|
384
|
+
<Box marginTop={1}>{renderBody()}</Box>
|
|
385
|
+
</Box>
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* ---------------------------------------------------------------------------
|
|
390
|
+
* Public component
|
|
391
|
+
* -------------------------------------------------------------------------*/
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* ToolCallDisplay renders a list of tool invocations. When `expanded` is
|
|
395
|
+
* false, completed calls are collapsed to a single summary line.
|
|
396
|
+
*/
|
|
397
|
+
export function ToolCallDisplay({ toolCalls, expanded = true }: ToolCallDisplayProps) {
|
|
398
|
+
if (toolCalls.length === 0) {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
<Box flexDirection="column" paddingX={1}>
|
|
404
|
+
{toolCalls.map(tc => (
|
|
405
|
+
<ToolCallBox key={tc.id} toolCall={tc} expanded={expanded} />
|
|
406
|
+
))}
|
|
407
|
+
</Box>
|
|
408
|
+
);
|
|
409
|
+
}
|