@build-astron-co/nimbus 0.2.0 → 0.4.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/bin/nimbus +26 -10
- package/bin/nimbus.cmd +41 -0
- package/bin/nimbus.mjs +70 -0
- package/completions/nimbus.bash +38 -0
- package/completions/nimbus.fish +48 -0
- package/completions/nimbus.zsh +81 -0
- package/dist/src/agent/compaction-agent.js +215 -0
- package/dist/src/agent/context-manager.js +385 -0
- package/dist/src/agent/context.js +322 -0
- package/dist/src/agent/deploy-preview.js +395 -0
- package/dist/src/agent/expand-files.js +95 -0
- package/dist/src/agent/index.js +18 -0
- package/dist/src/agent/loop.js +1535 -0
- package/dist/src/agent/modes.js +347 -0
- package/dist/src/agent/permissions.js +396 -0
- package/dist/src/agent/subagents/base.js +67 -0
- package/dist/src/agent/subagents/cost.js +45 -0
- package/dist/src/agent/subagents/explore.js +36 -0
- package/dist/src/agent/subagents/general.js +41 -0
- package/dist/src/agent/subagents/index.js +88 -0
- package/dist/src/agent/subagents/infra.js +52 -0
- package/dist/src/agent/subagents/security.js +60 -0
- package/dist/src/agent/system-prompt.js +860 -0
- package/dist/src/app.js +152 -0
- package/dist/src/audit/activity-log.js +209 -0
- package/dist/src/audit/compliance-checker.js +419 -0
- package/dist/src/audit/cost-tracker.js +231 -0
- package/dist/src/audit/index.js +10 -0
- package/dist/src/audit/security-scanner.js +490 -0
- package/dist/src/auth/guard.js +64 -0
- package/dist/src/auth/index.js +19 -0
- package/dist/src/auth/keychain.js +79 -0
- package/dist/src/auth/oauth.js +389 -0
- package/dist/src/auth/providers.js +415 -0
- package/dist/src/auth/sso.js +87 -0
- package/dist/src/auth/store.js +424 -0
- package/dist/src/auth/types.js +5 -0
- package/dist/src/cli/index.js +8 -0
- package/dist/src/cli/init.js +1048 -0
- package/dist/src/cli/openapi-spec.js +346 -0
- package/dist/src/cli/run.js +505 -0
- package/dist/src/cli/serve-auth.js +56 -0
- package/dist/src/cli/serve.js +432 -0
- package/dist/src/cli/web.js +50 -0
- package/dist/src/cli.js +1574 -0
- package/dist/src/clients/core-engine-client.js +156 -0
- package/dist/src/clients/enterprise-client.js +246 -0
- package/dist/src/clients/generator-client.js +219 -0
- package/dist/src/clients/git-client.js +367 -0
- package/dist/src/clients/github-client.js +229 -0
- package/dist/src/clients/helm-client.js +299 -0
- package/dist/src/clients/index.js +18 -0
- package/dist/src/clients/k8s-client.js +270 -0
- package/dist/src/clients/llm-client.js +119 -0
- package/dist/src/clients/rest-client.js +104 -0
- package/dist/src/clients/service-discovery.js +35 -0
- package/dist/src/clients/terraform-client.js +302 -0
- package/dist/src/clients/tools-client.js +1227 -0
- package/dist/src/clients/ws-client.js +93 -0
- package/dist/src/commands/alias.js +91 -0
- package/dist/src/commands/analyze/index.js +313 -0
- package/dist/src/commands/apply/helm.js +375 -0
- package/dist/src/commands/apply/index.js +176 -0
- package/dist/src/commands/apply/k8s.js +350 -0
- package/dist/src/commands/apply/terraform.js +465 -0
- package/dist/src/commands/ask.js +137 -0
- package/dist/src/commands/audit/index.js +322 -0
- package/dist/src/commands/auth-cloud.js +345 -0
- package/dist/src/commands/auth-list.js +112 -0
- package/dist/src/commands/auth-profile.js +104 -0
- package/dist/src/commands/auth-refresh.js +161 -0
- package/dist/src/commands/auth-status.js +122 -0
- package/dist/src/commands/aws/ec2.js +402 -0
- package/dist/src/commands/aws/iam.js +304 -0
- package/dist/src/commands/aws/index.js +108 -0
- package/dist/src/commands/aws/lambda.js +317 -0
- package/dist/src/commands/aws/rds.js +345 -0
- package/dist/src/commands/aws/s3.js +346 -0
- package/dist/src/commands/aws/vpc.js +302 -0
- package/dist/src/commands/aws-discover.js +413 -0
- package/dist/src/commands/aws-terraform.js +618 -0
- package/dist/src/commands/azure/aks.js +305 -0
- package/dist/src/commands/azure/functions.js +200 -0
- package/dist/src/commands/azure/index.js +93 -0
- package/dist/src/commands/azure/storage.js +378 -0
- package/dist/src/commands/azure/vm.js +291 -0
- package/dist/src/commands/billing/index.js +224 -0
- package/dist/src/commands/chat.js +259 -0
- package/dist/src/commands/completions.js +255 -0
- package/dist/src/commands/config.js +291 -0
- package/dist/src/commands/cost/cloud-cost-estimator.js +211 -0
- package/dist/src/commands/cost/estimator.js +73 -0
- package/dist/src/commands/cost/index.js +625 -0
- package/dist/src/commands/cost/parsers/terraform.js +234 -0
- package/dist/src/commands/cost/parsers/types.js +4 -0
- package/dist/src/commands/cost/pricing/aws.js +501 -0
- package/dist/src/commands/cost/pricing/azure.js +462 -0
- package/dist/src/commands/cost/pricing/gcp.js +359 -0
- package/dist/src/commands/cost/pricing/index.js +24 -0
- package/dist/src/commands/demo.js +196 -0
- package/dist/src/commands/deploy.js +215 -0
- package/dist/src/commands/doctor.js +1291 -0
- package/dist/src/commands/drift/index.js +674 -0
- package/dist/src/commands/explain.js +235 -0
- package/dist/src/commands/export.js +120 -0
- package/dist/src/commands/feedback.js +319 -0
- package/dist/src/commands/fix.js +263 -0
- package/dist/src/commands/fs/index.js +338 -0
- package/dist/src/commands/gcp/compute.js +266 -0
- package/dist/src/commands/gcp/functions.js +221 -0
- package/dist/src/commands/gcp/gke.js +357 -0
- package/dist/src/commands/gcp/iam.js +295 -0
- package/dist/src/commands/gcp/index.js +105 -0
- package/dist/src/commands/gcp/storage.js +232 -0
- package/dist/src/commands/generate-helm.js +1026 -0
- package/dist/src/commands/generate-k8s.js +1263 -0
- package/dist/src/commands/generate-terraform.js +1058 -0
- package/dist/src/commands/gh/index.js +663 -0
- package/dist/src/commands/git/index.js +1208 -0
- package/dist/src/commands/helm/index.js +985 -0
- package/dist/src/commands/help.js +639 -0
- package/dist/src/commands/history.js +120 -0
- package/dist/src/commands/import.js +782 -0
- package/dist/src/commands/incident.js +144 -0
- package/dist/src/commands/index.js +109 -0
- package/dist/src/commands/init.js +955 -0
- package/dist/src/commands/k8s/index.js +979 -0
- package/dist/src/commands/login.js +588 -0
- package/dist/src/commands/logout.js +61 -0
- package/dist/src/commands/logs.js +160 -0
- package/dist/src/commands/onboarding.js +382 -0
- package/dist/src/commands/pipeline.js +153 -0
- package/dist/src/commands/plan/display.js +216 -0
- package/dist/src/commands/plan/index.js +525 -0
- package/dist/src/commands/plugin.js +325 -0
- package/dist/src/commands/preview.js +356 -0
- package/dist/src/commands/profile.js +297 -0
- package/dist/src/commands/questionnaire.js +1021 -0
- package/dist/src/commands/resume.js +35 -0
- package/dist/src/commands/rollback.js +259 -0
- package/dist/src/commands/rollout.js +74 -0
- package/dist/src/commands/runbook.js +307 -0
- package/dist/src/commands/schedule.js +202 -0
- package/dist/src/commands/status.js +213 -0
- package/dist/src/commands/team/index.js +309 -0
- package/dist/src/commands/team-context.js +200 -0
- package/dist/src/commands/template.js +204 -0
- package/dist/src/commands/tf/index.js +989 -0
- package/dist/src/commands/upgrade.js +515 -0
- package/dist/src/commands/usage/index.js +118 -0
- package/dist/src/commands/version.js +145 -0
- package/dist/src/commands/watch.js +127 -0
- package/dist/src/compat/index.js +2 -0
- package/dist/src/compat/runtime.js +10 -0
- package/dist/src/compat/sqlite.js +144 -0
- package/dist/src/config/index.js +6 -0
- package/dist/src/config/manager.js +469 -0
- package/dist/src/config/mode-store.js +57 -0
- package/dist/src/config/profiles.js +66 -0
- package/dist/src/config/safety-policy.js +251 -0
- package/dist/src/config/schema.js +107 -0
- package/dist/src/config/types.js +311 -0
- package/dist/src/config/workspace-state.js +38 -0
- package/dist/src/context/context-db.js +138 -0
- package/dist/src/demo/index.js +295 -0
- package/dist/src/demo/scenarios/full-journey.js +226 -0
- package/dist/src/demo/scenarios/getting-started.js +124 -0
- package/dist/src/demo/scenarios/helm-release.js +334 -0
- package/dist/src/demo/scenarios/k8s-deployment.js +190 -0
- package/dist/src/demo/scenarios/terraform-vpc.js +167 -0
- package/dist/src/demo/types.js +6 -0
- package/dist/src/engine/cost-estimator.js +334 -0
- package/dist/src/engine/diagram-generator.js +192 -0
- package/dist/src/engine/drift-detector.js +688 -0
- package/dist/src/engine/executor.js +832 -0
- package/dist/src/engine/index.js +39 -0
- package/dist/src/engine/orchestrator.js +436 -0
- package/dist/src/engine/planner.js +616 -0
- package/dist/src/engine/safety.js +609 -0
- package/dist/src/engine/verifier.js +664 -0
- package/dist/src/enterprise/audit.js +241 -0
- package/dist/src/enterprise/auth.js +189 -0
- package/dist/src/enterprise/billing.js +512 -0
- package/dist/src/enterprise/index.js +16 -0
- package/dist/src/enterprise/teams.js +315 -0
- package/dist/src/generator/best-practices.js +1375 -0
- package/dist/src/generator/helm.js +495 -0
- package/dist/src/generator/index.js +11 -0
- package/dist/src/generator/intent-parser.js +420 -0
- package/dist/src/generator/kubernetes.js +773 -0
- package/dist/src/generator/terraform.js +1472 -0
- package/dist/src/history/index.js +6 -0
- package/dist/src/history/manager.js +199 -0
- package/dist/src/history/types.js +6 -0
- package/dist/src/hooks/config.js +318 -0
- package/dist/src/hooks/engine.js +317 -0
- package/dist/src/hooks/index.js +2 -0
- package/dist/src/llm/auth-bridge.js +157 -0
- package/dist/src/llm/circuit-breaker.js +116 -0
- package/dist/src/llm/config-loader.js +172 -0
- package/dist/src/llm/cost-calculator.js +137 -0
- package/dist/src/llm/index.js +7 -0
- package/dist/src/llm/model-aliases.js +99 -0
- package/dist/src/llm/provider-registry.js +57 -0
- package/dist/src/llm/providers/anthropic.js +430 -0
- package/dist/src/llm/providers/bedrock.js +409 -0
- package/dist/src/llm/providers/google.js +344 -0
- package/dist/src/llm/providers/ollama.js +661 -0
- package/dist/src/llm/providers/openai-compatible.js +289 -0
- package/dist/src/llm/providers/openai.js +284 -0
- package/dist/src/llm/providers/openrouter.js +293 -0
- package/dist/src/llm/router.js +844 -0
- package/dist/src/llm/types.js +69 -0
- package/dist/src/lsp/client.js +239 -0
- package/dist/src/lsp/languages.js +95 -0
- package/dist/src/lsp/manager.js +243 -0
- package/dist/src/mcp/client.js +289 -0
- package/dist/src/mcp/index.js +5 -0
- package/dist/src/mcp/manager.js +113 -0
- package/dist/src/nimbus.js +212 -0
- package/dist/src/plugins/index.js +13 -0
- package/dist/src/plugins/loader.js +280 -0
- package/dist/src/plugins/manager.js +282 -0
- package/dist/src/plugins/types.js +23 -0
- package/dist/src/scanners/cicd-scanner.js +230 -0
- package/dist/src/scanners/cloud-scanner.js +415 -0
- package/dist/src/scanners/framework-scanner.js +430 -0
- package/dist/src/scanners/iac-scanner.js +350 -0
- package/dist/src/scanners/index.js +454 -0
- package/dist/src/scanners/language-scanner.js +258 -0
- package/dist/src/scanners/package-manager-scanner.js +252 -0
- package/dist/src/scanners/types.js +6 -0
- package/dist/src/sessions/manager.js +395 -0
- package/dist/src/sessions/types.js +4 -0
- package/dist/src/sharing/sync.js +238 -0
- package/dist/src/sharing/viewer.js +131 -0
- package/dist/src/snapshots/index.js +1 -0
- package/dist/src/snapshots/manager.js +432 -0
- package/dist/src/state/artifacts.js +94 -0
- package/dist/src/state/audit.js +73 -0
- package/dist/src/state/billing.js +126 -0
- package/dist/src/state/checkpoints.js +81 -0
- package/dist/src/state/config.js +58 -0
- package/dist/src/state/conversations.js +7 -0
- package/dist/src/state/credentials.js +96 -0
- package/dist/src/state/db.js +53 -0
- package/dist/src/state/index.js +23 -0
- package/dist/src/state/messages.js +76 -0
- package/dist/src/state/projects.js +92 -0
- package/dist/src/state/schema.js +233 -0
- package/dist/src/state/sessions.js +79 -0
- package/dist/src/state/teams.js +131 -0
- package/dist/src/telemetry.js +91 -0
- package/dist/src/tools/aws-ops.js +747 -0
- package/dist/src/tools/azure-ops.js +491 -0
- package/dist/src/tools/file-ops.js +451 -0
- package/dist/src/tools/gcp-ops.js +559 -0
- package/dist/src/tools/git-ops.js +557 -0
- package/dist/src/tools/github-ops.js +460 -0
- package/dist/src/tools/helm-ops.js +634 -0
- package/dist/src/tools/index.js +16 -0
- package/dist/src/tools/k8s-ops.js +579 -0
- package/dist/src/tools/schemas/converter.js +129 -0
- package/dist/src/tools/schemas/devops.js +3319 -0
- package/dist/src/tools/schemas/index.js +19 -0
- package/dist/src/tools/schemas/standard.js +966 -0
- package/dist/src/tools/schemas/types.js +409 -0
- package/dist/src/tools/spawn-exec.js +109 -0
- package/dist/src/tools/terraform-ops.js +627 -0
- package/dist/src/types/config.js +1 -0
- package/dist/src/types/drift.js +4 -0
- package/dist/src/types/enterprise.js +5 -0
- package/dist/src/types/index.js +14 -0
- package/dist/src/types/plan.js +1 -0
- package/dist/src/types/request.js +1 -0
- package/dist/src/types/response.js +1 -0
- package/dist/src/types/service.js +1 -0
- package/dist/src/ui/App.js +1672 -0
- package/dist/src/ui/DeployPreview.js +60 -0
- package/dist/src/ui/FileDiffModal.js +108 -0
- package/dist/src/ui/Header.js +46 -0
- package/dist/src/ui/HelpModal.js +9 -0
- package/dist/src/ui/InputBox.js +408 -0
- package/dist/src/ui/MessageList.js +795 -0
- package/dist/src/ui/PermissionPrompt.js +72 -0
- package/dist/src/ui/StatusBar.js +109 -0
- package/dist/src/ui/TerminalPane.js +31 -0
- package/dist/src/ui/ToolCallDisplay.js +303 -0
- package/dist/src/ui/TreePane.js +83 -0
- package/dist/src/ui/chat-ui.js +721 -0
- package/dist/src/ui/index.js +11 -0
- package/dist/src/ui/ink/index.js +1325 -0
- package/dist/src/ui/streaming.js +137 -0
- package/dist/src/ui/theme.js +78 -0
- package/dist/src/ui/types.js +7 -0
- package/dist/src/utils/analytics.js +61 -0
- package/dist/src/utils/cost-warning.js +25 -0
- package/dist/src/utils/env.js +42 -0
- package/dist/src/utils/errors.js +54 -0
- package/dist/src/utils/event-bus.js +22 -0
- package/dist/src/utils/index.js +16 -0
- package/dist/src/utils/logger.js +150 -0
- package/dist/src/utils/rate-limiter.js +90 -0
- package/dist/src/utils/service-auth.js +36 -0
- package/dist/src/utils/validation.js +39 -0
- package/dist/src/version.js +3 -0
- package/dist/src/watcher/index.js +192 -0
- package/dist/src/wizard/approval.js +275 -0
- package/dist/src/wizard/index.js +13 -0
- package/dist/src/wizard/prompts.js +273 -0
- package/dist/src/wizard/types.js +4 -0
- package/dist/src/wizard/ui.js +453 -0
- package/dist/src/wizard/wizard.js +227 -0
- package/package.json +31 -23
- package/src/__tests__/alias.test.ts +133 -0
- package/src/__tests__/app.test.ts +1 -1
- package/src/__tests__/audit.test.ts +1 -1
- package/src/__tests__/circuit-breaker.test.ts +1 -1
- package/src/__tests__/cli-run.test.ts +237 -1
- package/src/__tests__/compat-sqlite.test.ts +68 -0
- package/src/__tests__/context-manager.test.ts +131 -1
- package/src/__tests__/context.test.ts +1 -1
- package/src/__tests__/devops-terminal-gaps.test.ts +718 -0
- package/src/__tests__/doctor.test.ts +48 -0
- package/src/__tests__/enterprise.test.ts +1 -1
- package/src/__tests__/export.test.ts +236 -0
- package/src/__tests__/gap-11-18-20.test.ts +958 -0
- package/src/__tests__/generator.test.ts +1 -1
- package/src/__tests__/helm-streaming.test.ts +127 -0
- package/src/__tests__/hooks.test.ts +1 -1
- package/src/__tests__/incident.test.ts +179 -0
- package/src/__tests__/init.test.ts +55 -4
- package/src/__tests__/intent-parser.test.ts +1 -1
- package/src/__tests__/llm-router.test.ts +1 -1
- package/src/__tests__/logs.test.ts +107 -0
- package/src/__tests__/loop-errors.test.ts +244 -0
- package/src/__tests__/lsp.test.ts +1 -1
- package/src/__tests__/modes.test.ts +1 -1
- package/src/__tests__/perf-optimizations.test.ts +847 -0
- package/src/__tests__/permissions.test.ts +1 -1
- package/src/__tests__/pipeline.test.ts +50 -0
- package/src/__tests__/polish-phase3.test.ts +340 -0
- package/src/__tests__/profile.test.ts +237 -0
- package/src/__tests__/rollback.test.ts +83 -0
- package/src/__tests__/runbook.test.ts +219 -0
- package/src/__tests__/schedule.test.ts +206 -0
- package/src/__tests__/serve.test.ts +1 -1
- package/src/__tests__/sessions.test.ts +96 -1
- package/src/__tests__/sharing.test.ts +53 -1
- package/src/__tests__/snapshots.test.ts +1 -1
- package/src/__tests__/standalone-migration.test.ts +199 -0
- package/src/__tests__/state-db.test.ts +1 -1
- package/src/__tests__/status.test.ts +158 -0
- package/src/__tests__/stream-with-tools.test.ts +71 -25
- package/src/__tests__/subagents.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +82 -3
- package/src/__tests__/terminal-gap-v2.test.ts +395 -0
- package/src/__tests__/terminal-parity.test.ts +393 -0
- package/src/__tests__/tf-apply.test.ts +187 -0
- package/src/__tests__/tool-converter.test.ts +1 -1
- package/src/__tests__/tool-schemas.test.ts +209 -4
- package/src/__tests__/tools.test.ts +4 -3
- package/src/__tests__/version-json.test.ts +184 -0
- package/src/__tests__/version.test.ts +1 -1
- package/src/__tests__/watch.test.ts +129 -0
- package/src/agent/compaction-agent.ts +40 -1
- package/src/agent/context-manager.ts +67 -3
- package/src/agent/deploy-preview.ts +62 -1
- package/src/agent/expand-files.ts +108 -0
- package/src/agent/loop.ts +1312 -31
- package/src/agent/permissions.ts +51 -4
- package/src/agent/system-prompt.ts +573 -19
- package/src/app.ts +58 -0
- package/src/audit/security-scanner.ts +45 -0
- package/src/auth/keychain.ts +82 -0
- package/src/auth/oauth.ts +15 -5
- package/src/cli/init.ts +378 -5
- package/src/cli/run.ts +407 -16
- package/src/cli/serve.ts +78 -1
- package/src/cli/web.ts +10 -6
- package/src/cli.ts +312 -1
- package/src/clients/service-discovery.ts +30 -25
- package/src/commands/alias.ts +100 -0
- package/src/commands/audit/index.ts +121 -2
- package/src/commands/auth-cloud.ts +113 -0
- package/src/commands/auth-refresh.ts +187 -0
- package/src/commands/aws-discover.ts +144 -251
- package/src/commands/aws-terraform.ts +68 -118
- package/src/commands/chat.ts +9 -3
- package/src/commands/completions.ts +268 -0
- package/src/commands/config.ts +26 -0
- package/src/commands/cost/index.ts +218 -2
- package/src/commands/deploy.ts +260 -0
- package/src/commands/doctor.ts +744 -152
- package/src/commands/drift/index.ts +371 -23
- package/src/commands/export.ts +146 -0
- package/src/commands/generate-k8s.ts +9 -61
- package/src/commands/generate-terraform.ts +191 -449
- package/src/commands/help.ts +212 -36
- package/src/commands/history.ts +8 -1
- package/src/commands/incident.ts +166 -0
- package/src/commands/init.ts +5 -0
- package/src/commands/login.ts +86 -1
- package/src/commands/logs.ts +167 -0
- package/src/commands/onboarding.ts +211 -34
- package/src/commands/pipeline.ts +186 -0
- package/src/commands/plugin.ts +398 -0
- package/src/commands/profile.ts +342 -0
- package/src/commands/questionnaire.ts +0 -98
- package/src/commands/resume.ts +26 -34
- package/src/commands/rollback.ts +315 -0
- package/src/commands/rollout.ts +88 -0
- package/src/commands/runbook.ts +346 -0
- package/src/commands/schedule.ts +236 -0
- package/src/commands/status.ts +252 -0
- package/src/commands/team-context.ts +220 -0
- package/src/commands/template.ts +58 -57
- package/src/commands/tf/index.ts +70 -11
- package/src/commands/upgrade.ts +57 -0
- package/src/commands/version.ts +54 -50
- package/src/commands/watch.ts +153 -0
- package/src/compat/runtime.ts +1 -1
- package/src/compat/sqlite.ts +75 -5
- package/src/config/mode-store.ts +62 -0
- package/src/config/profiles.ts +84 -0
- package/src/config/types.ts +83 -1
- package/src/config/workspace-state.ts +53 -0
- package/src/engine/cost-estimator.ts +52 -10
- package/src/engine/executor.ts +33 -2
- package/src/engine/planner.ts +68 -1
- package/src/generator/terraform.ts +8 -0
- package/src/history/manager.ts +2 -74
- package/src/hooks/engine.ts +5 -4
- package/src/llm/cost-calculator.ts +2 -2
- package/src/llm/providers/anthropic.ts +50 -21
- package/src/llm/router.ts +76 -7
- package/src/lsp/languages.ts +3 -0
- package/src/lsp/manager.ts +21 -5
- package/src/nimbus.ts +37 -18
- package/src/sessions/manager.ts +108 -1
- package/src/sharing/sync.ts +4 -0
- package/src/sharing/viewer.ts +66 -0
- package/src/tools/file-ops.ts +22 -0
- package/src/tools/schemas/devops.ts +3007 -117
- package/src/tools/schemas/standard.ts +5 -1
- package/src/tools/schemas/types.ts +31 -1
- package/src/tools/spawn-exec.ts +148 -0
- package/src/ui/App.tsx +1183 -66
- package/src/ui/DeployPreview.tsx +62 -57
- package/src/ui/FileDiffModal.tsx +162 -0
- package/src/ui/Header.tsx +87 -24
- package/src/ui/HelpModal.tsx +57 -0
- package/src/ui/InputBox.tsx +163 -10
- package/src/ui/MessageList.tsx +487 -40
- package/src/ui/PermissionPrompt.tsx +17 -5
- package/src/ui/StatusBar.tsx +122 -3
- package/src/ui/TerminalPane.tsx +84 -0
- package/src/ui/ToolCallDisplay.tsx +252 -18
- package/src/ui/TreePane.tsx +132 -0
- package/src/ui/chat-ui.ts +41 -44
- package/src/ui/ink/index.ts +771 -38
- package/src/ui/streaming.ts +1 -1
- package/src/ui/theme.ts +104 -0
- package/src/ui/types.ts +18 -0
- package/src/version.ts +1 -1
- package/src/watcher/index.ts +66 -15
- package/src/wizard/types.ts +1 -0
- package/src/wizard/ui.ts +1 -1
- package/tsconfig.json +2 -2
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team Commands
|
|
3
|
+
* Team collaboration CLI commands
|
|
4
|
+
*/
|
|
5
|
+
import { ui } from '../../wizard/ui';
|
|
6
|
+
import { teamClient } from '../../clients/enterprise-client';
|
|
7
|
+
import { getAuthStore } from '../../auth';
|
|
8
|
+
/**
|
|
9
|
+
* Get current user ID from auth store
|
|
10
|
+
*/
|
|
11
|
+
function getCurrentUserId() {
|
|
12
|
+
const authStore = getAuthStore();
|
|
13
|
+
const auth = authStore.load();
|
|
14
|
+
const userId = auth?.identity?.github?.username;
|
|
15
|
+
if (!userId) {
|
|
16
|
+
throw new Error('Not authenticated. Run `nimbus login` first.');
|
|
17
|
+
}
|
|
18
|
+
return userId;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get current team ID from config or environment
|
|
22
|
+
*/
|
|
23
|
+
function getCurrentTeamId() {
|
|
24
|
+
return process.env.NIMBUS_TEAM_ID || null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse team create options
|
|
28
|
+
*/
|
|
29
|
+
export function parseTeamCreateOptions(args) {
|
|
30
|
+
const options = {};
|
|
31
|
+
for (let i = 0; i < args.length; i++) {
|
|
32
|
+
const arg = args[i];
|
|
33
|
+
if (arg === '--non-interactive') {
|
|
34
|
+
options.nonInteractive = true;
|
|
35
|
+
}
|
|
36
|
+
else if (!arg.startsWith('-') && !options.name) {
|
|
37
|
+
options.name = arg;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return options;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parse team invite options
|
|
44
|
+
*/
|
|
45
|
+
export function parseTeamInviteOptions(args) {
|
|
46
|
+
const options = {};
|
|
47
|
+
for (let i = 0; i < args.length; i++) {
|
|
48
|
+
const arg = args[i];
|
|
49
|
+
if (arg === '--role' && args[i + 1]) {
|
|
50
|
+
options.role = args[++i];
|
|
51
|
+
}
|
|
52
|
+
else if (arg === '--non-interactive') {
|
|
53
|
+
options.nonInteractive = true;
|
|
54
|
+
}
|
|
55
|
+
else if (!arg.startsWith('-') && !options.email) {
|
|
56
|
+
options.email = arg;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return options;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse team members options
|
|
63
|
+
*/
|
|
64
|
+
export function parseTeamMembersOptions(args) {
|
|
65
|
+
const options = {};
|
|
66
|
+
for (let i = 0; i < args.length; i++) {
|
|
67
|
+
const arg = args[i];
|
|
68
|
+
if (arg === '--json') {
|
|
69
|
+
options.json = true;
|
|
70
|
+
}
|
|
71
|
+
else if (arg === '--non-interactive') {
|
|
72
|
+
options.nonInteractive = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return options;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Parse team remove options
|
|
79
|
+
*/
|
|
80
|
+
export function parseTeamRemoveOptions(args) {
|
|
81
|
+
const options = {};
|
|
82
|
+
for (let i = 0; i < args.length; i++) {
|
|
83
|
+
const arg = args[i];
|
|
84
|
+
if (arg === '--force' || arg === '-f') {
|
|
85
|
+
options.force = true;
|
|
86
|
+
}
|
|
87
|
+
else if (arg === '--non-interactive') {
|
|
88
|
+
options.nonInteractive = true;
|
|
89
|
+
}
|
|
90
|
+
else if (!arg.startsWith('-') && !options.email) {
|
|
91
|
+
options.email = arg;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return options;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Parse team switch options
|
|
98
|
+
*/
|
|
99
|
+
export function parseTeamSwitchOptions(args) {
|
|
100
|
+
const options = {};
|
|
101
|
+
for (let i = 0; i < args.length; i++) {
|
|
102
|
+
const arg = args[i];
|
|
103
|
+
if (arg === '--non-interactive') {
|
|
104
|
+
options.nonInteractive = true;
|
|
105
|
+
}
|
|
106
|
+
else if (!arg.startsWith('-') && !options.teamId) {
|
|
107
|
+
options.teamId = arg;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return options;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Team create command
|
|
114
|
+
*/
|
|
115
|
+
export async function teamCreateCommand(options) {
|
|
116
|
+
try {
|
|
117
|
+
const name = options.name;
|
|
118
|
+
if (!name) {
|
|
119
|
+
ui.error('Team name is required');
|
|
120
|
+
ui.info('Usage: nimbus team create <name>');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const userId = getCurrentUserId();
|
|
124
|
+
ui.startSpinner({ message: 'Creating team...' });
|
|
125
|
+
const team = await teamClient.createTeam({ name, ownerId: userId });
|
|
126
|
+
ui.stopSpinnerSuccess(`Team "${team.name}" created`);
|
|
127
|
+
ui.newLine();
|
|
128
|
+
ui.info(`Team ID: ${team.id}`);
|
|
129
|
+
ui.info(`To use this team, run: nimbus team switch ${team.id}`);
|
|
130
|
+
ui.info(`Or set environment variable: export NIMBUS_TEAM_ID=${team.id}`);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
ui.stopSpinnerFail('Failed to create team');
|
|
134
|
+
ui.error(error.message);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Team invite command
|
|
139
|
+
*/
|
|
140
|
+
export async function teamInviteCommand(options) {
|
|
141
|
+
try {
|
|
142
|
+
const email = options.email;
|
|
143
|
+
if (!email) {
|
|
144
|
+
ui.error('Email is required');
|
|
145
|
+
ui.info('Usage: nimbus team invite <email> [--role member|admin|viewer]');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const teamId = getCurrentTeamId();
|
|
149
|
+
if (!teamId) {
|
|
150
|
+
ui.error('No team selected. Run `nimbus team switch <team-id>` first.');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
ui.startSpinner({ message: `Inviting ${email}...` });
|
|
154
|
+
const member = await teamClient.inviteMember(teamId, {
|
|
155
|
+
email,
|
|
156
|
+
role: options.role || 'member',
|
|
157
|
+
});
|
|
158
|
+
ui.stopSpinnerSuccess(`Invited ${email} as ${member.role}`);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
ui.stopSpinnerFail('Failed to invite member');
|
|
162
|
+
ui.error(error.message);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Team members command
|
|
167
|
+
*/
|
|
168
|
+
export async function teamMembersCommand(options) {
|
|
169
|
+
try {
|
|
170
|
+
const teamId = getCurrentTeamId();
|
|
171
|
+
if (!teamId) {
|
|
172
|
+
ui.error('No team selected. Run `nimbus team switch <team-id>` first.');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
ui.startSpinner({ message: 'Fetching members...' });
|
|
176
|
+
const members = await teamClient.listMembers(teamId);
|
|
177
|
+
ui.stopSpinnerSuccess(`Found ${members.length} members`);
|
|
178
|
+
if (options.json) {
|
|
179
|
+
console.log(JSON.stringify(members, null, 2));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
ui.newLine();
|
|
183
|
+
ui.table({
|
|
184
|
+
columns: [
|
|
185
|
+
{ key: 'email', header: 'Email' },
|
|
186
|
+
{ key: 'role', header: 'Role' },
|
|
187
|
+
{ key: 'joinedAt', header: 'Joined' },
|
|
188
|
+
],
|
|
189
|
+
data: members.map(m => ({
|
|
190
|
+
email: m.user?.email || m.userId,
|
|
191
|
+
role: m.role,
|
|
192
|
+
joinedAt: new Date(m.joinedAt).toLocaleDateString(),
|
|
193
|
+
})),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
ui.stopSpinnerFail('Failed to list members');
|
|
198
|
+
ui.error(error.message);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Team remove command
|
|
203
|
+
*/
|
|
204
|
+
export async function teamRemoveCommand(options) {
|
|
205
|
+
try {
|
|
206
|
+
const email = options.email;
|
|
207
|
+
if (!email) {
|
|
208
|
+
ui.error('Email is required');
|
|
209
|
+
ui.info('Usage: nimbus team remove <email>');
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const teamId = getCurrentTeamId();
|
|
213
|
+
if (!teamId) {
|
|
214
|
+
ui.error('No team selected. Run `nimbus team switch <team-id>` first.');
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// First, find the user ID by email from members list
|
|
218
|
+
const members = await teamClient.listMembers(teamId);
|
|
219
|
+
const member = members.find(m => m.user?.email === email);
|
|
220
|
+
if (!member) {
|
|
221
|
+
ui.error(`Member with email ${email} not found`);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
ui.startSpinner({ message: `Removing ${email}...` });
|
|
225
|
+
await teamClient.removeMember(teamId, member.userId);
|
|
226
|
+
ui.stopSpinnerSuccess(`Removed ${email} from team`);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
ui.stopSpinnerFail('Failed to remove member');
|
|
230
|
+
ui.error(error.message);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Team switch command
|
|
235
|
+
*/
|
|
236
|
+
export async function teamSwitchCommand(options) {
|
|
237
|
+
try {
|
|
238
|
+
const userId = getCurrentUserId();
|
|
239
|
+
// If no team ID provided, list teams for selection
|
|
240
|
+
if (!options.teamId) {
|
|
241
|
+
ui.startSpinner({ message: 'Fetching teams...' });
|
|
242
|
+
const teams = await teamClient.listTeams(userId);
|
|
243
|
+
ui.stopSpinnerSuccess(`Found ${teams.length} teams`);
|
|
244
|
+
if (teams.length === 0) {
|
|
245
|
+
ui.info('No teams found. Create one with `nimbus team create <name>`');
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
ui.newLine();
|
|
249
|
+
ui.info('Available teams:');
|
|
250
|
+
for (const team of teams) {
|
|
251
|
+
ui.print(` ${team.id} - ${team.name} (${team.plan})`);
|
|
252
|
+
}
|
|
253
|
+
ui.newLine();
|
|
254
|
+
ui.info('To switch: nimbus team switch <team-id>');
|
|
255
|
+
ui.info('Or set: export NIMBUS_TEAM_ID=<team-id>');
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// Verify team exists and user has access
|
|
259
|
+
ui.startSpinner({ message: 'Switching team...' });
|
|
260
|
+
const team = await teamClient.getTeam(options.teamId);
|
|
261
|
+
if (!team) {
|
|
262
|
+
ui.stopSpinnerFail('Team not found');
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
ui.stopSpinnerSuccess(`Switched to team "${team.name}"`);
|
|
266
|
+
ui.newLine();
|
|
267
|
+
ui.info(`Set this environment variable to persist:`);
|
|
268
|
+
ui.print(` export NIMBUS_TEAM_ID=${team.id}`);
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
ui.stopSpinnerFail('Failed to switch team');
|
|
272
|
+
ui.error(error.message);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Main team command dispatcher
|
|
277
|
+
*/
|
|
278
|
+
export async function teamCommand(subcommand, args) {
|
|
279
|
+
switch (subcommand) {
|
|
280
|
+
case 'create':
|
|
281
|
+
await teamCreateCommand(parseTeamCreateOptions(args));
|
|
282
|
+
break;
|
|
283
|
+
case 'invite':
|
|
284
|
+
await teamInviteCommand(parseTeamInviteOptions(args));
|
|
285
|
+
break;
|
|
286
|
+
case 'members':
|
|
287
|
+
await teamMembersCommand(parseTeamMembersOptions(args));
|
|
288
|
+
break;
|
|
289
|
+
case 'remove':
|
|
290
|
+
await teamRemoveCommand(parseTeamRemoveOptions(args));
|
|
291
|
+
break;
|
|
292
|
+
case 'switch':
|
|
293
|
+
await teamSwitchCommand(parseTeamSwitchOptions(args));
|
|
294
|
+
break;
|
|
295
|
+
case 'list':
|
|
296
|
+
await teamSwitchCommand(parseTeamSwitchOptions([])); // List mode
|
|
297
|
+
break;
|
|
298
|
+
default:
|
|
299
|
+
ui.error(`Unknown team command: ${subcommand}`);
|
|
300
|
+
ui.newLine();
|
|
301
|
+
ui.info('Available team commands:');
|
|
302
|
+
ui.print(' nimbus team create <name> - Create a new team');
|
|
303
|
+
ui.print(' nimbus team invite <email> - Invite a member');
|
|
304
|
+
ui.print(' nimbus team members - List team members');
|
|
305
|
+
ui.print(' nimbus team remove <email> - Remove a member');
|
|
306
|
+
ui.print(' nimbus team switch [team-id] - Switch to a team');
|
|
307
|
+
ui.print(' nimbus team list - List your teams');
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Team NIMBUS.md Distribution (L6)
|
|
3
|
+
*
|
|
4
|
+
* Share project context files with team members.
|
|
5
|
+
*
|
|
6
|
+
* nimbus team-context push — share current NIMBUS.md via sharing service
|
|
7
|
+
* nimbus team-context pull <url> — download NIMBUS.md, show diff, prompt before overwrite
|
|
8
|
+
*
|
|
9
|
+
* Also supports NIMBUS_INSTRUCTIONS_URL env var: on startup, fetch that URL
|
|
10
|
+
* and use as NIMBUS.md if local file not present.
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import { ui } from '../wizard/ui';
|
|
15
|
+
const NIMBUS_MD_PATHS = [
|
|
16
|
+
path.join(process.cwd(), 'NIMBUS.md'),
|
|
17
|
+
path.join(process.cwd(), '.nimbus', 'NIMBUS.md'),
|
|
18
|
+
];
|
|
19
|
+
function findLocalNimbusMd() {
|
|
20
|
+
for (const p of NIMBUS_MD_PATHS) {
|
|
21
|
+
if (fs.existsSync(p))
|
|
22
|
+
return p;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
function computeDiff(oldContent, newContent) {
|
|
27
|
+
const oldLines = oldContent.split('\n');
|
|
28
|
+
const newLines = newContent.split('\n');
|
|
29
|
+
const lines = [];
|
|
30
|
+
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
31
|
+
for (let i = 0; i < maxLen; i++) {
|
|
32
|
+
const old = oldLines[i];
|
|
33
|
+
const newLine = newLines[i];
|
|
34
|
+
if (old === undefined) {
|
|
35
|
+
lines.push(`+ ${newLine}`);
|
|
36
|
+
}
|
|
37
|
+
else if (newLine === undefined) {
|
|
38
|
+
lines.push(`- ${old}`);
|
|
39
|
+
}
|
|
40
|
+
else if (old !== newLine) {
|
|
41
|
+
lines.push(`- ${old}`);
|
|
42
|
+
lines.push(`+ ${newLine}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return lines.join('\n');
|
|
46
|
+
}
|
|
47
|
+
/** Path to the team.md file in the current project's .nimbus/ directory */
|
|
48
|
+
const TEAM_MD_PATH = path.join(process.cwd(), '.nimbus', 'team.md');
|
|
49
|
+
/** Regex to strip lines containing sensitive info */
|
|
50
|
+
const SENSITIVE_PATTERN = /SENSITIVE:/i;
|
|
51
|
+
/** Strip lines containing "SENSITIVE:" from NIMBUS.md before sharing */
|
|
52
|
+
function stripSensitiveLines(content) {
|
|
53
|
+
return content
|
|
54
|
+
.split('\n')
|
|
55
|
+
.filter(line => !SENSITIVE_PATTERN.test(line))
|
|
56
|
+
.join('\n');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Merge non-duplicate sections from teamContent into localContent.
|
|
60
|
+
* Sections are identified by Markdown headings (## ...).
|
|
61
|
+
*/
|
|
62
|
+
function mergeSections(localContent, teamContent) {
|
|
63
|
+
// Split into sections by heading
|
|
64
|
+
const sectionRegex = /(?=^#{1,3} .+$)/m;
|
|
65
|
+
const localSections = localContent.split(sectionRegex);
|
|
66
|
+
const teamSections = teamContent.split(sectionRegex);
|
|
67
|
+
const localHeadings = new Set(localSections
|
|
68
|
+
.map(s => s.match(/^(#{1,3} .+)$/m)?.[1]?.trim())
|
|
69
|
+
.filter(Boolean));
|
|
70
|
+
const newSections = teamSections.filter(s => {
|
|
71
|
+
const heading = s.match(/^(#{1,3} .+)$/m)?.[1]?.trim();
|
|
72
|
+
return heading && !localHeadings.has(heading);
|
|
73
|
+
});
|
|
74
|
+
if (newSections.length === 0)
|
|
75
|
+
return localContent;
|
|
76
|
+
const merged = localContent.trimEnd() + '\n\n' + newSections.join('\n').trimStart();
|
|
77
|
+
return merged;
|
|
78
|
+
}
|
|
79
|
+
export async function teamContextCommand(subcommand, args) {
|
|
80
|
+
switch (subcommand) {
|
|
81
|
+
case 'push': {
|
|
82
|
+
// Git-based push: read NIMBUS.md, strip SENSITIVE lines, write to .nimbus/team.md
|
|
83
|
+
const localPath = findLocalNimbusMd();
|
|
84
|
+
if (!localPath) {
|
|
85
|
+
ui.warning('No NIMBUS.md found in current directory. Run `nimbus init` first.');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const content = fs.readFileSync(localPath, 'utf-8');
|
|
89
|
+
const sanitized = stripSensitiveLines(content);
|
|
90
|
+
// Ensure .nimbus/ directory exists
|
|
91
|
+
const nimbusDir = path.dirname(TEAM_MD_PATH);
|
|
92
|
+
if (!fs.existsSync(nimbusDir)) {
|
|
93
|
+
fs.mkdirSync(nimbusDir, { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
fs.writeFileSync(TEAM_MD_PATH, sanitized, 'utf-8');
|
|
96
|
+
ui.print(`${ui.color('✓', 'green')} Written sanitized context to ${TEAM_MD_PATH}`);
|
|
97
|
+
ui.dim(`Removed all lines containing "SENSITIVE:"`);
|
|
98
|
+
ui.newLine();
|
|
99
|
+
// Stage the file with git
|
|
100
|
+
try {
|
|
101
|
+
const { execFileSync } = await import('node:child_process');
|
|
102
|
+
execFileSync('git', ['add', TEAM_MD_PATH], {
|
|
103
|
+
encoding: 'utf-8',
|
|
104
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
105
|
+
timeout: 10_000,
|
|
106
|
+
});
|
|
107
|
+
ui.print(`${ui.color('✓', 'green')} Staged .nimbus/team.md with git`);
|
|
108
|
+
ui.print(' Next step: git commit -m "chore: update team context" && git push');
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
ui.dim('(git stage skipped — not a git repo or git not in PATH)');
|
|
112
|
+
ui.print(' Copy .nimbus/team.md to your repository and commit/push it manually.');
|
|
113
|
+
}
|
|
114
|
+
ui.newLine();
|
|
115
|
+
ui.info('Note: Add .nimbus/team.md to version control (do NOT add .nimbus/team.md to .gitignore).');
|
|
116
|
+
ui.dim('Add NIMBUS.md to .gitignore if it contains sensitive local config.');
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
case 'pull': {
|
|
120
|
+
// Git-based pull: read .nimbus/team.md from cwd, diff, merge
|
|
121
|
+
if (!fs.existsSync(TEAM_MD_PATH)) {
|
|
122
|
+
ui.error(`.nimbus/team.md not found in ${process.cwd()}`);
|
|
123
|
+
ui.dim('Run `git pull` to fetch the latest team context, then re-run this command.');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const teamContent = fs.readFileSync(TEAM_MD_PATH, 'utf-8');
|
|
127
|
+
const targetPath = NIMBUS_MD_PATHS[0];
|
|
128
|
+
const existing = fs.existsSync(targetPath) ? fs.readFileSync(targetPath, 'utf-8') : null;
|
|
129
|
+
if (existing) {
|
|
130
|
+
const diff = computeDiff(existing, teamContent);
|
|
131
|
+
if (!diff) {
|
|
132
|
+
ui.info('NIMBUS.md is already up to date with team.md.');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
ui.header('NIMBUS.md vs .nimbus/team.md diff');
|
|
136
|
+
for (const line of diff.split('\n')) {
|
|
137
|
+
if (line.startsWith('+')) {
|
|
138
|
+
ui.print(ui.color(line, 'green'));
|
|
139
|
+
}
|
|
140
|
+
else if (line.startsWith('-')) {
|
|
141
|
+
ui.print(ui.color(line, 'red'));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
ui.print(line);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
ui.newLine();
|
|
148
|
+
// Prompt for confirmation
|
|
149
|
+
const { input: inputPrompt } = await import('../wizard/prompts');
|
|
150
|
+
const answer = await inputPrompt({
|
|
151
|
+
message: 'Merge new sections from team.md into NIMBUS.md? [y/N]',
|
|
152
|
+
defaultValue: 'N',
|
|
153
|
+
});
|
|
154
|
+
if (answer.toLowerCase() !== 'y') {
|
|
155
|
+
ui.info('Aborted — NIMBUS.md not changed.');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Merge: append non-duplicate sections
|
|
159
|
+
const merged = mergeSections(existing, teamContent);
|
|
160
|
+
fs.writeFileSync(targetPath, merged, 'utf-8');
|
|
161
|
+
ui.print(`${ui.color('✓', 'green')} Merged team context into ${targetPath}`);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// No local NIMBUS.md — use team.md as starting point
|
|
165
|
+
fs.writeFileSync(targetPath, teamContent, 'utf-8');
|
|
166
|
+
ui.print(`${ui.color('✓', 'green')} Created ${targetPath} from .nimbus/team.md`);
|
|
167
|
+
}
|
|
168
|
+
ui.newLine();
|
|
169
|
+
ui.dim('Note: Add NIMBUS.md to .gitignore to keep local config private.');
|
|
170
|
+
ui.dim('Add .nimbus/team.md to version control to share project context with team.');
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
default:
|
|
174
|
+
ui.print('Usage: nimbus team-context <push|pull>');
|
|
175
|
+
ui.print('');
|
|
176
|
+
ui.print(' push Strip SENSITIVE: lines from NIMBUS.md, write to .nimbus/team.md, and git add');
|
|
177
|
+
ui.print(' pull Read .nimbus/team.md, diff against NIMBUS.md, merge on confirmation');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Fetch NIMBUS.md from NIMBUS_INSTRUCTIONS_URL env var.
|
|
182
|
+
* Called on startup when no local NIMBUS.md exists.
|
|
183
|
+
*/
|
|
184
|
+
export async function fetchRemoteNimbusMd() {
|
|
185
|
+
const url = process.env.NIMBUS_INSTRUCTIONS_URL;
|
|
186
|
+
if (!url)
|
|
187
|
+
return null;
|
|
188
|
+
const localPath = findLocalNimbusMd();
|
|
189
|
+
if (localPath)
|
|
190
|
+
return null; // local file takes priority
|
|
191
|
+
try {
|
|
192
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
193
|
+
if (!response.ok)
|
|
194
|
+
return null;
|
|
195
|
+
return await response.text();
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|