@nullplatform/mcp 0.1.7 → 0.1.9

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/dist/i18n.js CHANGED
@@ -340,6 +340,7 @@ const english = {
340
340
  "createApp.form": "To create an application I need a git repository URL and a name (the form collects them).\nNamespaces: {namespaces}.",
341
341
  "createApp.noName": "Couldn't derive a name from {url} — pass name.",
342
342
  "createApp.noNamespaceMatch": 'No namespace matching "{namespace}". Namespaces: {names}.',
343
+ "createApp.noAccountMatch": 'No account matching "{account}". Accounts: {names}.',
343
344
  "createApp.whichNamespace": "Which namespace?",
344
345
  "createApp.whichNamespaceFor": "Which namespace should own **{name}**?",
345
346
  "createApp.namespaceHint": '`application_create namespace:"<name>"`',
@@ -347,6 +348,7 @@ const english = {
347
348
  "createApp.created": "**{name}** created (#{id}) in namespace **{namespace}**, linked to {repo}.",
348
349
  "createApp.alreadyLinked": "**{name}** (#{id}) is already linked to {repo} — nothing to create.",
349
350
  "createApp.createdHint": "push a commit to trigger the first build, then `application_deployment_create`.",
351
+ "createApp.createdHintNew": "the repo was scaffolded for you — clone {repo} into a folder, add your code there, and push so CI builds it, then `application_deployment_create`.",
350
352
  "createApp.pending": "⏳ **{name}** created (#{id}), provisioning is still running (status: {status}).",
351
353
  "createApp.pendingHint": '`application_get app:"#{id}"` to check on it.',
352
354
  "createApp.errorLabel": "Couldn't create the application",
@@ -704,6 +706,7 @@ const spanish = {
704
706
  "createApp.form": "Para crear una aplicación necesito la URL de un repo git y un nombre (el formulario los pide).\nNamespaces: {namespaces}.",
705
707
  "createApp.noName": "No pude derivar un nombre desde {url} — pasá name.",
706
708
  "createApp.noNamespaceMatch": 'Ningún namespace coincide con "{namespace}". Namespaces: {names}.',
709
+ "createApp.noAccountMatch": 'Ninguna cuenta coincide con "{account}". Cuentas: {names}.',
707
710
  "createApp.whichNamespace": "¿Qué namespace?",
708
711
  "createApp.whichNamespaceFor": "¿Qué namespace debería ser dueño de **{name}**?",
709
712
  "createApp.namespaceHint": '`application_create namespace:"<nombre>"`',
@@ -711,6 +714,7 @@ const spanish = {
711
714
  "createApp.created": "**{name}** creada (#{id}) en el namespace **{namespace}**, vinculada a {repo}.",
712
715
  "createApp.alreadyLinked": "**{name}** (#{id}) ya está vinculada a {repo} — no hay nada que crear.",
713
716
  "createApp.createdHint": "pusheá un commit para disparar el primer build y después `application_deployment_create`.",
717
+ "createApp.createdHintNew": "el repo fue scaffoldeado — cloná {repo} en una carpeta, agregá tu código ahí y pusheá para que CI buildee, después `application_deployment_create`.",
714
718
  "createApp.pending": "⏳ **{name}** creada (#{id}), el aprovisionamiento sigue corriendo (estado: {status}).",
715
719
  "createApp.pendingHint": '`application_get app:"#{id}"` para revisarla.',
716
720
  "createApp.errorLabel": "No pude crear la aplicación",
@@ -751,8 +755,392 @@ const spanish = {
751
755
  Cerrá con un veredicto de un párrafo: sano / degradado / en problemas, y la próxima acción más útil.`,
752
756
  "prompt.rollback": `Algo está mal — revertí {app} ya mismo: encontrá su rollout activo, corré application_deployment_update action:"rollback" y confirmá con application_get que la versión anterior está sirviendo tráfico; resumí qué se revirtió.`,
753
757
  };
754
- const catalogs = { en: english, es: spanish };
755
- const SUPPORTED = ["en", "es"];
758
+ const portuguese = {
759
+ // resolution (which app?) —
760
+ "resolve.ambiguous": "Várias aplicações coincidem — diga qual (nome ou `#id`):",
761
+ "resolve.noId": "Nenhuma aplicação com id {id}.",
762
+ "resolve.noMatch": 'Nenhuma aplicação correspondente a "{ref}".',
763
+ "resolve.repoUnlinked": 'Este repositório ({url}) não está vinculado a nenhuma aplicação nullplatform. Passe app:"<nome>" ou rode application_create para vinculá-lo.',
764
+ "resolve.noInput": 'Nenhuma app informada e nenhum remote git encontrado no workspace. Passe app:"<nome>" (ou um id como "#123").',
765
+ "resolve.noNrn": "Não consigo resolver o NRN da aplicação para **{app}**.",
766
+ // — scope selection —
767
+ "scope.which": "Qual scope?",
768
+ "scope.none": "Esta app ainda não tem scopes.",
769
+ "scope.noneHint": '`application_scope_create name:"dev"` primeiro — depois `application_deployment_create`.',
770
+ "scope.noMatch": 'Nenhum scope correspondente a "{wanted}". Scopes: {names}.',
771
+ "scope.noMatchDetailed": 'Nenhum scope correspondente a "{wanted}" (por nome ou dimensão). Scopes:',
772
+ "scope.createHint": '`application_scope_create name:"{name}"` para criá-lo.',
773
+ "scope.deployHint": '`application_deployment_create scope:"<nome ou dimensão, ex. environment=production>"`',
774
+ "scope.perScope": "{noun} são por scope — qual?",
775
+ "scope.readHint": '`{tool} scope:"{name}"`',
776
+ // — table headers —
777
+ "header.app": "App",
778
+ "header.id": "Id",
779
+ "header.namespace": "Namespace",
780
+ "header.account": "Conta",
781
+ "header.status": "Status",
782
+ "header.scope": "Scope",
783
+ "header.dimensions": "Dimensões",
784
+ "header.name": "Nome",
785
+ "header.variable": "Variável",
786
+ "header.type": "Tipo",
787
+ "header.secret": "Secret",
788
+ "header.value": "Valor",
789
+ "header.values": "Valores",
790
+ "header.source": "Origem",
791
+ "header.metric": "Métrica",
792
+ "header.now": "Agora",
793
+ "header.avg": "Méd",
794
+ "header.max": "Máx",
795
+ "header.trend": "Tendência",
796
+ "header.asset": "Asset",
797
+ "header.platform": "Plataforma",
798
+ "header.deployment": "Deployment",
799
+ "header.provider": "Provider",
800
+ "header.live": "No ar",
801
+ "header.traffic": "Tráfego",
802
+ "header.when": "Quando",
803
+ "header.version": "Versão",
804
+ "header.build": "Build",
805
+ "header.release": "Release",
806
+ // — markdown design language —
807
+ "md.next": "Próximo",
808
+ "md.none": "_nenhum_",
809
+ "md.justNow": "agora mesmo",
810
+ "md.minutesAgo": "há {count}m",
811
+ "md.hoursAgo": "há {count}h",
812
+ "md.daysAgo": "há {count}d",
813
+ "md.dashboard": "dashboard",
814
+ "md.unknown": "desconhecido",
815
+ // — platform status words (fallback: raw status with underscores spaced) —
816
+ "status.active": "ativo",
817
+ "status.successful": "bem-sucedido",
818
+ "status.finalized": "finalizado",
819
+ "status.running": "em execução",
820
+ "status.pending": "pendente",
821
+ "status.creating": "criando",
822
+ "status.updating": "atualizando",
823
+ "status.building": "em build",
824
+ "status.waiting_for_instances": "aguardando instâncias",
825
+ "status.switching_traffic": "trocando tráfego",
826
+ "status.finalizing": "finalizando",
827
+ "status.cancelling": "cancelando",
828
+ "status.rolling_back": "revertendo",
829
+ "status.creating_approval": "aguardando aprovação",
830
+ "status.failed": "falhou",
831
+ "status.cancelled": "cancelado",
832
+ "status.rolled_back": "revertido",
833
+ "status.deleted": "deletado",
834
+ "status.inactive": "inativo",
835
+ "status.creating_approval_denied": "aprovação negada",
836
+ // — status view —
837
+ "render.noScopes": "_Ainda sem scopes — nada para fazer deploy._",
838
+ "render.nothingDeployed": "_nada em deploy_",
839
+ "render.noBuilds": "_nenhum — faça push para o CI_",
840
+ "render.latestBuild": "Último build",
841
+ "render.releases": "Releases",
842
+ "render.liveOn": "no ar em {scopes}",
843
+ "render.deployment": "**Deployment**",
844
+ "render.deploying": "🚀 **Fazendo deploy**",
845
+ "render.release": "Release",
846
+ "render.started": "iniciado {when}",
847
+ "render.now": "agora",
848
+ "render.desired": "→ desejado {pct}%",
849
+ // — next-step hints (status) —
850
+ "hint.rolloutTraffic": 'deployment #{id} em **{scope}** está com {traffic}% de tráfego — `application_deployment_update percent:<n>` para avançar, `application_deployment_update action:"finalize"` quando pronto, `application_deployment_update action:"rollback"` para reverter.',
851
+ "hint.rolloutStatus": "deployment #{id} em **{scope}** está {status} — `application_get deployment:{id}` para acompanhar.",
852
+ "hint.noScopes": 'ainda sem scopes — `application_scope_create name:"dev"` para ter onde fazer deploy.',
853
+ "hint.buildNewer": "build #{id} ({branch} @{commit}) é mais novo que a release {semver} — `application_deployment_create` faz o deploy (cria a release para você).",
854
+ "hint.buildUnreleased": "build #{id} ainda não tem release — `application_deployment_create` faz o deploy (cria a release para você).",
855
+ "hint.releaseNotLive": "a release {semver} ainda não está no ar — `application_deployment_create` para publicá-la.",
856
+ "hint.noBuilds": "ainda sem builds — faça push de um commit para o CI gerar um, depois `application_deployment_create`.",
857
+ "hint.upToDate": "está tudo atualizado ✅",
858
+ "hint.watch": "`application_get deployment:{id}` para acompanhar.",
859
+ // — next-step hints (rollout) —
860
+ "rollout.full": 'todo o tráfego na nova versão — `application_deployment_update action:"finalize"` para aposentar a antiga.',
861
+ "rollout.moving": "tráfego indo de {from}% → {to}% — `application_get deployment:{id}` para acompanhar.",
862
+ "rollout.at": 'tráfego em {traffic}% — `application_deployment_update percent:<n>` para avançar (marcas: 1,5,10,25,50,75,90,95,99,100), `application_deployment_update action:"rollback"` para reverter.',
863
+ "rollout.instances": "as instâncias estão subindo — `application_get deployment:{id}` para acompanhar.",
864
+ "rollout.switching": "o tráfego está sendo trocado — `application_get deployment:{id}` para acompanhar.",
865
+ "rollout.finalizing": "finalizando — as instâncias antigas estão sendo aposentadas.",
866
+ "rollout.done": "pronto — a release está totalmente no ar ✅",
867
+ "rollout.approval": "aguardando uma aprovação ✋ — um aprovador precisa liberar este deployment (dashboard → Aprovações).",
868
+ "rollout.failed": 'o deployment falhou — `application_log_list` para ver a saída, `application_deployment_update action:"rollback"` se o tráfego se moveu.',
869
+ "rollout.rolledBack": "revertido — a versão anterior está atendendo todo o tráfego.",
870
+ // — application_get tool —
871
+ "status.errorLabel": "Não foi possível carregar o status",
872
+ // — application_list tool —
873
+ "findApps.noneMatching": "Nenhuma aplicação{matching}{inNamespace}.",
874
+ "findApps.matching": ' correspondente a "{query}"',
875
+ "findApps.inNamespace": ' nos namespaces ~"{namespace}"',
876
+ "findApps.createHint": "`application_create` vincula este repositório como uma nova aplicação.",
877
+ "findApps.count.one": "1 aplicação",
878
+ "findApps.count.many": "{count} aplicações",
879
+ "findApps.statusHint": '`application_get app:"<nome>"` para o panorama completo de uma.',
880
+ "findApps.truncated": "Mostrando as primeiras {shown} — refine com uma query ou namespace para ver o resto.",
881
+ "findApps.errorLabel": "Busca falhou",
882
+ // — application_parameter_list tool —
883
+ "params.unavailable": "A listagem de parâmetros não está disponível aqui. `application_parameter_create` ainda funciona.",
884
+ "params.viewInDashboard": "ver no dashboard",
885
+ "params.none": "**{app}** não tem parâmetros.",
886
+ "params.noneHint": "`application_parameter_create` para adicionar variáveis de ambiente ou arquivos.",
887
+ "params.count.one": "**{app}** · 1 parâmetro",
888
+ "params.count.many": "**{app}** · {count} parâmetros",
889
+ "params.unset": "_não definido_",
890
+ "params.applyHint": "valores alterados aplicam no próximo `application_deployment_create`.",
891
+ "params.effectiveFor": "**{app}** · parâmetros efetivos para **{scope}**",
892
+ "params.ctxApplication": "Aplicação",
893
+ "params.ctxScope": "{scope} (scope)",
894
+ "params.errorLabel": "Não foi possível listar os parâmetros",
895
+ // — application_log_list tool —
896
+ "logs.noun": "Logs",
897
+ "logs.noScopes": "**{app}** não tem scopes, então ainda não há logs de runtime.",
898
+ "logs.noScopesHint": "`application_deployment_create` depois de criar um scope — os logs aparecem quando algo roda.",
899
+ "logs.empty": "Nenhuma linha de log retornada para **{app}**{scope}.",
900
+ "logs.openInDashboard": "abrir logs no dashboard",
901
+ "logs.lastLines.one": "**{app}**{scope} — última linha",
902
+ "logs.lastLines.many": "**{app}**{scope} — últimas {count} linhas",
903
+ "logs.errorLabel": "Não foi possível ler os logs",
904
+ "logs.errorSuffix": "A visão de Logs do dashboard ainda pode tê-los.",
905
+ // — application_metric_list tool —
906
+ "metrics.noun": "Métricas",
907
+ "metrics.noScopes": "**{app}** não tem scopes, então ainda não há métricas de runtime.",
908
+ "metrics.noScopesHint": "`application_deployment_create` depois de criar um scope.",
909
+ "metrics.empty": "Nenhum datapoint de métrica para **{app}** · {scope} nos últimos {window} — o scope pode ser recente ou o agente de métricas não está configurado.",
910
+ "metrics.openInDashboard": "performance no dashboard",
911
+ "metrics.title": "**{app}** · {scope} — últimos {window}",
912
+ "metrics.errorLabel": "Não foi possível carregar as métricas",
913
+ // — application_build_list tool —
914
+ "builds.title.one": "**{app}** · 1 build recente",
915
+ "builds.title.many": "**{app}** · {count} builds recentes",
916
+ "builds.branch": "Branch",
917
+ "builds.commit": "Commit",
918
+ "builds.released": "Com release",
919
+ "builds.none": "**{app}** ainda não tem builds.",
920
+ "builds.noneForCommit": "Nenhum build em **{app}** para o commit `{commit}` — pode não ter buildado ainda, ou o commit não está em uma branch buildada.",
921
+ "builds.noneHint": "faça push de um commit para o CI gerar um, depois `application_deployment_create`.",
922
+ "builds.deployHint": "`application_deployment_create build_id:{build}` faz o deploy (corta a release para você).",
923
+ "builds.waiting": "o build #{build} ainda está rodando — `application_build_list` de novo em instantes para checar.",
924
+ "builds.upToDate": "o último build bem-sucedido já tem release.",
925
+ "builds.assetsTitle": "Assets do build #{build}",
926
+ "builds.noAssets": "O build #{build} não tem assets.",
927
+ "builds.noAssetsRunning": "O build #{build} ainda não tem assets — ainda está buildando.",
928
+ "builds.noAssetsFailed": "O build #{build} falhou antes de produzir qualquer asset.",
929
+ "builds.errorLabel": "Não foi possível listar os builds",
930
+ "releaseList.title.one": "**{app}** · 1 release",
931
+ "releaseList.title.many": "**{app}** · {count} releases",
932
+ "releaseList.none": "**{app}** ainda não tem releases.",
933
+ "releaseList.noneHint": "corte uma a partir de um build bem-sucedido com `application_release_create`, ou simplesmente `application_deployment_create`.",
934
+ "releaseList.deployHint": 'faça deploy de uma release ativa com `application_deployment_create version:"x.y.z"`.',
935
+ "releaseList.errorLabel": "Não foi possível listar as releases",
936
+ "deploymentList.title.one": "**{app}** · 1 deployment",
937
+ "deploymentList.title.many": "**{app}** · {count} deployments",
938
+ "deploymentList.none": "**{app}** ainda não tem deployments.",
939
+ "deploymentList.group": "{count} scopes (grupo)",
940
+ "deploymentList.hint": "`application_get` para o panorama ao vivo, ou `application_deployment_update` para conduzir um rollout.",
941
+ "deploymentList.errorLabel": "Não foi possível listar os deployments",
942
+ // — organization_get tool —
943
+ "overview.title.one": "Visão geral da organização · 1 aplicação escaneada",
944
+ "overview.title.many": "Visão geral da organização · {count} aplicações escaneadas",
945
+ "overview.truncated": '_(mostrando as primeiras {count} — refine com `organization_get query:"..."`)_',
946
+ "overview.activeRollouts": "Rollouts ativos ({count})",
947
+ "overview.trouble": "Precisa de atenção ({count})",
948
+ "overview.hintActive": '`application_get app:"{app}"` para acompanhar um rollout, ou `application_deployment_update` para conduzir um.',
949
+ "overview.hintTrouble": '`application_log_list app:"{app}"` para investigar, `application_deployment_update action:"rollback"` se necessário.',
950
+ "overview.hintCalm": "está tudo estável — nada em rollout, nada falhou.",
951
+ "overview.errorLabel": "Não foi possível montar a visão geral",
952
+ // — application_approval_list tool —
953
+ "approvals.title.one": "**{app}** · 1 aprovação",
954
+ "approvals.title.many": "**{app}** · {count} aprovações",
955
+ "approvals.action": "Ação",
956
+ "approvals.entity": "Entidade",
957
+ "approvals.requestedBy": "Solicitado por",
958
+ "approvals.none": "Nenhuma aprovação pendente para **{app}**.",
959
+ "approvals.needId": "Passe `approval_id` junto com a ação.",
960
+ "approvals.invalidId": "Isso não parece um approval id válido — copie-o da lista do `application_approval_list`.",
961
+ "approvals.approved": "Aprovado {id} — a ação bloqueada pode prosseguir.",
962
+ "approvals.cancelled": "Aprovação {id} cancelada.",
963
+ "approvals.actHint": '`application_approval_list action:"approve" approval_id:"{id}"` para liberá-la (usa suas permissões).',
964
+ "approvals.errorLabel": "Não foi possível carregar as aprovações",
965
+ // — application_service_list tool —
966
+ "services.attached.one": "**{app}** · 1 serviço de dependência",
967
+ "services.attached.many": "**{app}** · {count} serviços de dependência",
968
+ "services.specification": "Tipo",
969
+ "services.none": "**{app}** não tem serviços de dependência anexados.",
970
+ "services.catalog": "Disponíveis para provisionar: {catalog}.",
971
+ "services.provisionHint": "provisionar uma dependência é um fluxo guiado — crie uma no dashboard.",
972
+ "services.errorLabel": "Não foi possível carregar os serviços",
973
+ // — application_service_create tool —
974
+ "createService.errorLabel": "Não foi possível provisionar o serviço",
975
+ "createService.noSpecs": "**{app}** não tem tipos de dependência disponíveis para provisionar aqui.",
976
+ "createService.pickSpec": "**{app}** — qual dependência provisionar? ({count} disponíveis)",
977
+ "createService.matchAmbiguous": 'Várias dependências coincidem com "{query}" — escolha uma:',
978
+ "createService.category": "Categoria",
979
+ "createService.provider": "Provider",
980
+ "createService.pickHint": '`application_service_create type:"<nome>"` para provisionar uma.',
981
+ "createService.form": "Pronto para provisionar **{spec}** para **{app}** — confirme para criar (isso cria recursos cloud reais).",
982
+ "createService.formHint": "confirme no painel para provisionar, ou passe `provision:true` com os parâmetros.",
983
+ "createService.provisioning": "Provisionando **{spec}** como **{name}** — {status}. Recursos reais estão sendo criados.",
984
+ "createService.reused": "**{name}** já existe ({status}) — reusando, não provisionando um segundo.",
985
+ "createService.provisioningHint": "`application_link_create` para linkar **{name}** a um scope — seus parâmetros de conexão aparecem após o link, no próximo deploy.",
986
+ // — application_link_create tool —
987
+ "createLink.errorLabel": "Não foi possível criar o link",
988
+ "createLink.noServices": "**{app}** ainda não tem serviços provisionados para linkar.",
989
+ "createLink.noServicesHint": "`application_service_create` para provisionar uma dependência primeiro.",
990
+ "createLink.pickService": "Qual serviço linkar a **{app}**?",
991
+ "createLink.matchAmbiguous": "Vários serviços coincidem — escolha um:",
992
+ "createLink.pickHint": '`application_link_create service:"<nome>"` para linkar um.',
993
+ "createLink.noLinkSpec": "Nenhuma link specification disponível para **{service}** nesta org.",
994
+ "createLink.form": "Pronto para linkar **{service}** a **{app}** — confirme para criar o link (um link de credenciais provisiona um usuário de banco de dados).",
995
+ "createLink.formHint": "confirme no painel para criar o link, ou passe `create:true` com os parâmetros.",
996
+ "createLink.linking": "Linkando **{service}** a {target} — {status}.",
997
+ "createLink.reused": "**{service}** já está linkado a {target} ({status}) — reusando esse link.",
998
+ "createLink.linkedHint": "refaça o deploy do scope para que os novos parâmetros de conexão cheguem ao runtime.",
999
+ // — application_service_update / application_link_update (run a custom action) —
1000
+ "runAction.errorLabel": "Não foi possível rodar a ação",
1001
+ "runAction.noServices": "**{app}** não tem serviços provisionados para rodar uma ação.",
1002
+ "runAction.noServicesHint": "`application_service_create` para provisionar uma dependência primeiro.",
1003
+ "runAction.noLinks": "**{app}** não tem links para rodar uma ação.",
1004
+ "runAction.noLinksHint": "`application_link_create` para linkar um serviço primeiro.",
1005
+ "runAction.pickService": "Em qual serviço rodar uma ação, em **{app}**?",
1006
+ "runAction.serviceAmbiguous": "Vários serviços coincidem — escolha um:",
1007
+ "runAction.pickServiceHint": '`application_service_update service:"<nome>"` para escolher um.',
1008
+ "runAction.pickLink": "Em qual link rodar uma ação, em **{app}**?",
1009
+ "runAction.linkAmbiguous": "Vários links coincidem — escolha um:",
1010
+ "runAction.pickLinkHint": '`application_link_update link:"<nome>"` para escolher um.',
1011
+ "runAction.noActions": "**{name}** não expõe ações executáveis.",
1012
+ "runAction.pickAction": "Qual ação rodar em **{name}**?",
1013
+ "runAction.matchAmbiguous": "Várias ações coincidem — escolha uma:",
1014
+ "runAction.paramsHeader": "Parâmetros",
1015
+ "runAction.pickHint": 'Passe `action:"<nome>"` para escolher uma.',
1016
+ "runAction.form": "Pronto para rodar **{action}** em **{name}** — confirme para executar.",
1017
+ "runAction.formHint": "confirme no painel para executar, ou passe `run:true` com os parâmetros.",
1018
+ "runAction.running": "Rodando **{action}** em **{name}** — {status}.",
1019
+ "runAction.ranHint": "a ação roda de forma assíncrona; seu resultado aparece quando termina.",
1020
+ // — application_service_delete / application_link_delete (deprovision) —
1021
+ "deleteEntity.serviceErrorLabel": "Não foi possível deletar o serviço",
1022
+ "deleteEntity.linkErrorLabel": "Não foi possível deletar o link",
1023
+ "deleteEntity.noServices": "**{app}** não tem serviços provisionados para deletar.",
1024
+ "deleteEntity.noLinks": "**{app}** não tem links para deletar.",
1025
+ "deleteEntity.pickService": "Qual serviço deletar, em **{app}**?",
1026
+ "deleteEntity.serviceAmbiguous": "Vários serviços coincidem — escolha um:",
1027
+ "deleteEntity.pickServiceHint": '`application_service_delete service:"<nome>"` para escolher um.',
1028
+ "deleteEntity.pickLink": "Qual link deletar, em **{app}**?",
1029
+ "deleteEntity.linkAmbiguous": "Vários links coincidem — escolha um:",
1030
+ "deleteEntity.pickLinkHint": '`application_link_delete link:"<nome>"` para escolher um.',
1031
+ "deleteEntity.hasLinks": "**{name}** ainda tem {count} link(s) ativo(s) — ficariam órfãos.",
1032
+ "deleteEntity.hasLinksHint": "delete os links primeiro com `application_link_delete`, depois o serviço.",
1033
+ "deleteEntity.confirm": "Pronto para deletar **{name}** e destruir seus recursos — confirme para prosseguir.",
1034
+ "deleteEntity.confirmHint": "confirme no painel para deletar, ou passe `confirm:true`.",
1035
+ "deleteEntity.removed": "**{name}** foi deletado.",
1036
+ "deleteEntity.deprovisioning": "Deletando **{name}** — um agente está desprovisionando seus recursos.",
1037
+ "deleteEntity.deprovisioningHint": "o registro é removido quando o desprovisionamento termina.",
1038
+ // — application_parameter_delete tool —
1039
+ "deleteParam.errorLabel": "Não foi possível deletar o parâmetro",
1040
+ "deleteParam.absent": "**{name}** não está definido em **{app}** — nada para deletar.",
1041
+ "deleteParam.readOnly": "**{name}** é somente leitura — um link de serviço o injeta.",
1042
+ "deleteParam.readOnlyHint": "delete o link que o exporta com `application_link_delete`.",
1043
+ "deleteParam.confirm": "Pronto para deletar **{name}** de **{app}** — confirme para prosseguir.",
1044
+ "deleteParam.confirmHint": "confirme no painel para deletar, ou passe `confirm:true`.",
1045
+ "deleteParam.deleted": "Deletei **{name}** de **{app}**.",
1046
+ "deleteParam.deletedHint": "a mudança aplica no próximo deploy.",
1047
+ "deleteParam.failed": "Não foi possível deletar **{name}**: {message}",
1048
+ // — application_deployment_create tool —
1049
+ "deploy.noScopeTypes": "Esta app ainda não tem scopes. Tipos de scope disponíveis: {types}.",
1050
+ "deploy.createScopeHint": '`application_scope_create name:"dev" type:"{type}"`',
1051
+ "deploy.usingRelease": "Usando a release existente **{semver}** (#{id}). ",
1052
+ "deploy.createdRelease": "Criei a release **{semver}** a partir do build #{build}. ",
1053
+ "deploy.createdReleaseFrom": "Criei a release **{semver}** a partir do build #{build} ({branch} @{commit}). ",
1054
+ "deploy.noSuchVersion": "Não existe a release **{version}**{known} e não há build bem-sucedido para cortá-la.",
1055
+ "deploy.knownVersions": " (conhecidas: {versions})",
1056
+ "deploy.nothing": "Nada para fazer deploy: nenhuma release ativa e nenhum build bem-sucedido.",
1057
+ "deploy.nothingHint": "faça push de um commit para o CI gerar um build, depois `application_deployment_create` de novo.",
1058
+ "deploy.multiAsset": "O build #{build} tem vários assets — qual vai para **{scope}** ({type})?",
1059
+ "deploy.assetHint": '`application_deployment_create asset:"{name}"`',
1060
+ "deploy.errorLabel": "Deploy falhou",
1061
+ "deploy.alreadyRolling": "Esta release já está em rollout em **{scope}** — mostrando esse deployment.",
1062
+ "deploy.rejected": 'Deploy rejeitado: {message}\nIsso geralmente é a escolha do asset, não os ids — o build provavelmente tem vários assets. Tente de novo com `application_deployment_create asset:"<nome>"` (veja-os via `application_get`).',
1063
+ // — application_deployment_update tool —
1064
+ "traffic.sayWhat": 'Diga o que fazer: `percent:<0-100>`, `action:"finalize"` ou `action:"rollback"`.',
1065
+ "traffic.noActive": "Nenhum rollout ativo em **{app}** — `application_deployment_create` inicia um.",
1066
+ "traffic.several": "Vários rollouts estão ativos — passe deployment_id:",
1067
+ "traffic.snapped": "({requested}% ajustado para {snapped}%)",
1068
+ "traffic.errorLabel": "Ação de tráfego falhou",
1069
+ // — application_release_create tool —
1070
+ "createRelease.noBuilds": "Nenhum build bem-sucedido em **{app}** — faça push de um commit para o CI gerar um.",
1071
+ "createRelease.done": "Release **{semver}** criada{from}.",
1072
+ "createRelease.exists": "A release **{semver}** já existe para o build #{build} — reusando.",
1073
+ "createRelease.from": " a partir do build #{build} ({branch} @{commit}, {when})",
1074
+ "createRelease.deployHint": "`application_deployment_create release_id:{id}` para fazer o deploy.",
1075
+ "createRelease.errorLabel": "Não foi possível criar a release",
1076
+ // — application_parameter_create tool —
1077
+ "setParams.created.one": "Defini 1 novo parâmetro em **{app}**: {names}.",
1078
+ "setParams.created.many": "Defini {count} novos parâmetros em **{app}**: {names}.",
1079
+ "setParams.updated.one": "Atualizei 1 parâmetro existente em **{app}**: {names}.",
1080
+ "setParams.updated.many": "Atualizei {count} parâmetros existentes em **{app}**: {names}.",
1081
+ "setParams.mixed": "Defini {total} parâmetros em **{app}** (novos: {created}, atualizados: {updated}): {names}.",
1082
+ "setParams.applyHint": "os valores aplicam no próximo `application_deployment_create`.",
1083
+ "setParams.scopeDimConflict": "Não dá para mirar um scope e dimensões ao mesmo tempo para `{name}` — um scope já localiza o valor. Escolha um.",
1084
+ "setParams.partial": "A atualização de parâmetros falhou no meio: {message}\nOs parâmetros já criados permanecem — `application_parameter_list` para inspecionar.",
1085
+ "setParams.errorLabel": "Atualização de parâmetros falhou",
1086
+ // — application_create tool —
1087
+ "createApp.form": "Para criar uma aplicação eu preciso de uma URL de repositório git e um nome (o formulário os coleta).\nNamespaces: {namespaces}.",
1088
+ "createApp.noName": "Não consegui derivar um nome de {url} — passe name.",
1089
+ "createApp.noNamespaceMatch": 'Nenhum namespace correspondente a "{namespace}". Namespaces: {names}.',
1090
+ "createApp.noAccountMatch": 'Nenhuma conta correspondente a "{account}". Contas: {names}.',
1091
+ "createApp.whichNamespace": "Qual namespace?",
1092
+ "createApp.whichNamespaceFor": "Qual namespace deve conter **{name}**?",
1093
+ "createApp.namespaceHint": '`application_create namespace:"<nome>"`',
1094
+ "createApp.noNamespaces": "Esta organização ainda não tem namespaces — crie um no dashboard primeiro.",
1095
+ "createApp.created": "**{name}** criada (#{id}) no namespace **{namespace}**, vinculada a {repo}.",
1096
+ "createApp.alreadyLinked": "**{name}** (#{id}) já está vinculada a {repo} — nada para criar.",
1097
+ "createApp.createdHint": "faça push de um commit para disparar o primeiro build, depois `application_deployment_create`.",
1098
+ "createApp.createdHintNew": "o repo foi scaffoldado para você — clone {repo} em uma pasta, adicione seu código lá e faça push para o CI buildar, depois `application_deployment_create`.",
1099
+ "createApp.pending": "⏳ **{name}** criada (#{id}), o provisionamento ainda está rodando (status: {status}).",
1100
+ "createApp.pendingHint": '`application_get app:"#{id}"` para checá-la.',
1101
+ "createApp.errorLabel": "Não foi possível criar a aplicação",
1102
+ // — playbook_get tool —
1103
+ "playbook.errorLabel": "Não foi possível carregar o playbook",
1104
+ // — application_scope_create tool —
1105
+ "createScope.whichType": "Qual tipo de scope para **{name}**?",
1106
+ "createScope.typeHint": '`application_scope_create name:"{name}" type:"<tipo>"`',
1107
+ "createScope.noTypes": 'Nenhum tipo de scope disponível — passe type explicitamente (ex. type:"web_pool").',
1108
+ "createScope.provisioning": "⏳ O scope **{name}** (#{id}, {type}{dimensions}) está provisionando — a infraestrutura está sendo criada.",
1109
+ "createScope.exists": "O scope **{name}** (#{id}) já existe ({status}) — nada para criar.",
1110
+ "createScope.provisioningHint": '`application_get` o mostra; quando ativo, `application_deployment_create scope:"{name}"`.',
1111
+ "createScope.errorLabel": "Não foi possível criar o scope",
1112
+ // — auth & transport —
1113
+ "error.credentialRejected": "nullplatform rejeitou a credencial ({status}) — verifique sua NP_API_KEY",
1114
+ "error.permission": "seu usuário nullplatform não tem permissão para esta ação (403)",
1115
+ "error.bearerNoOrg": "o bearer não é um token emitido pela nullplatform (sem claim de organização)",
1116
+ "http.authRequired": "autenticação necessária",
1117
+ "http.authHint": "envie sua própria credencial nullplatform: `Authorization: Bearer <NP_API_KEY>` (ou X-NP-API-Key)",
1118
+ "http.originDenied": "origem não permitida",
1119
+ "http.bodyTooLarge": "corpo da requisição muito grande",
1120
+ "http.invalidJson": "corpo JSON inválido",
1121
+ "http.verifyUnavailable": "não foi possível verificar a credencial com a nullplatform",
1122
+ "http.rateLimited": "requisições demais — diminua o ritmo",
1123
+ // — prompts (inserted as the user's message) —
1124
+ "prompt.ship": `Faça o deploy do código mais recente de {app}{scope}.
1125
+ 1. Rode o status primeiro e me diga o que vai ser publicado (build/release).
1126
+ 2. faça o deploy.
1127
+ 3. Aumente o tráfego em etapas — 25%, depois 50%, depois 100% — checando o status entre as etapas; pare e me avise se algo parecer não saudável.
1128
+ 4. Quando 100% estiver saudável, finalize e confirme com um status final.`,
1129
+ "prompt.ship.toScope": ' para o scope "{scope}"',
1130
+ "prompt.thisRepoApp": "a aplicação vinculada a este repositório",
1131
+ "prompt.setup": `Conecte este repositório à nullplatform:
1132
+ 1. Rode application_get — se o repositório já estiver vinculado a uma aplicação, apenas me mostre onde estou.
1133
+ 2. Se não estiver vinculado, verifique application_list por uma app com o nome deste repositório antes de criar qualquer coisa.
1134
+ 3. Se nenhuma existir, application_create para vinculá-lo, depois mostre application_get e me diga o que acontece a seguir (primeiro build via CI, depois deploy).`,
1135
+ "prompt.health": `Me dê um health check de {app}:
1136
+ 1. status — o que está no ar e onde, algo em rollout?
1137
+ 2. métricas (janela de 3h) — aponte qualquer coisa incomum em throughput, tempo de resposta, taxa de erro, CPU ou memória.
1138
+ 3. logs — escaneie as linhas recentes por erros ou avisos.
1139
+ Termine com um veredito de um parágrafo: saudável / degradado / com problemas, e a única ação seguinte mais útil.`,
1140
+ "prompt.rollback": `Algo está errado — reverta {app} agora mesmo: encontre seu rollout ativo, rode application_deployment_update action:"rollback", depois confirme com application_get que a versão anterior está atendendo o tráfego e resuma o que foi revertido.`,
1141
+ };
1142
+ const catalogs = { en: english, es: spanish, pt: portuguese };
1143
+ const SUPPORTED = ["en", "es", "pt"];
756
1144
  let defaultLocale = "en";
757
1145
  const localeScope = new AsyncLocalStorage();
758
1146
  /** Process-wide default (stdio: from NP_LANG/LANG at startup). */
@@ -775,6 +1163,9 @@ const LANGUAGE_NAMES = {
775
1163
  español: "es",
776
1164
  espanol: "es",
777
1165
  castellano: "es",
1166
+ portuguese: "pt",
1167
+ português: "pt",
1168
+ portugues: "pt",
778
1169
  };
779
1170
  /** "es-AR, en;q=0.9" / "es_AR.UTF-8" / "es" / "Spanish" -> a supported locale, or undefined. */
780
1171
  export function matchLocale(input) {
@@ -48,6 +48,10 @@ export const createAppTool = defineTool({
48
48
  errorKey: "createApp.errorLabel",
49
49
  inputSchema: {
50
50
  name: z.string().optional().describe("App name (default: the repo name)"),
51
+ account: z
52
+ .string()
53
+ .optional()
54
+ .describe("Account name to place the app under — narrows the namespace choice to that account (a namespace name can repeat across accounts). Pick the best-fitting account from context when it isn't given."),
51
55
  namespace: z.string().optional().describe("Namespace name (prefer namespace_id when known)"),
52
56
  namespace_id: z.number().optional().describe("Namespace id to create the app in"),
53
57
  repository_url: z
@@ -104,26 +108,39 @@ export const createAppTool = defineTool({
104
108
  ?.replace(/\.git$/, "");
105
109
  if (!name)
106
110
  return fail(translate("createApp.noName", { url: repoUrl }));
107
- // Resolve the target namespace. If it can't be pinned down and there's a real choice, fall
108
- // back to the form (rendered as a picker in the widget) rather than a dead-end ask.
111
+ // Resolve where the app lives an (account, namespace) pair. Narrow to the named account first
112
+ // (a namespace name can repeat across accounts), then match/auto-pick the namespace inside it.
113
+ // If it still can't be pinned down and there's a real choice, fall back to the form (a picker)
114
+ // rather than a dead-end ask.
109
115
  const skeleton = await context.org.getSkeleton();
116
+ const accountQuery = args.account?.toLowerCase();
117
+ const candidates = accountQuery
118
+ ? skeleton.namespaces.filter((candidate) => (candidate.account_name ?? "").toLowerCase().includes(accountQuery))
119
+ : skeleton.namespaces;
120
+ if (accountQuery && candidates.length === 0) {
121
+ const accounts = [
122
+ ...new Set(skeleton.namespaces.map((candidate) => candidate.account_name).filter(Boolean)),
123
+ ];
124
+ return fail(translate("createApp.noAccountMatch", { account: args.account ?? "", names: accounts.join(", ") }));
125
+ }
110
126
  let namespace = args.namespace_id
111
- ? skeleton.namespaces.find((candidate) => candidate.id === args.namespace_id)
127
+ ? candidates.find((candidate) => candidate.id === args.namespace_id)
112
128
  : undefined;
113
129
  if (!namespace && args.namespace) {
114
130
  const query = args.namespace.toLowerCase();
115
- const matches = skeleton.namespaces.filter((candidate) => candidate.name.toLowerCase().includes(query));
131
+ const matches = candidates.filter((candidate) => candidate.name.toLowerCase().includes(query));
116
132
  if (matches.length === 1)
117
133
  namespace = matches[0];
118
134
  else if (matches.length === 0) {
119
135
  return fail(translate("createApp.noNamespaceMatch", {
120
136
  namespace: args.namespace,
121
- names: skeleton.namespaces.map((candidate) => candidate.name).join(", "),
137
+ names: candidates.map((candidate) => candidate.name).join(", "),
122
138
  }));
123
139
  }
124
140
  }
125
- if (!namespace && skeleton.namespaces.length === 1)
126
- namespace = skeleton.namespaces[0];
141
+ // One namespace in scope (the whole org, or the chosen account) → auto-pick it.
142
+ if (!namespace && candidates.length === 1)
143
+ namespace = candidates[0];
127
144
  if (!namespace) {
128
145
  if (skeleton.namespaces.length === 0)
129
146
  return fail(translate("createApp.noNamespaces"));
@@ -174,10 +191,21 @@ export const createAppTool = defineTool({
174
191
  .slice(-3)
175
192
  .map((entry) => `- ${entry.message ?? JSON.stringify(entry)}`)
176
193
  .join("\n");
177
- const structured = { application: { id: app.id, name, status: app.status, nrn: app.nrn } };
194
+ // A new repo scaffolded from a template is a fresh REMOTE repo the developer has never cloned —
195
+ // the next move is to pull it into a folder and build there. An import is already local, so its
196
+ // next move is just to push. The two paths get different guidance.
197
+ const scaffolded = args.template_id !== undefined;
198
+ const structured = {
199
+ application: { id: app.id, name, status: app.status, nrn: app.nrn },
200
+ scaffolded,
201
+ repository_url: repoUrl,
202
+ };
203
+ const createdHint = scaffolded
204
+ ? translate("createApp.createdHintNew", { repo: repoUrl })
205
+ : translate("createApp.createdHint");
178
206
  if (app.status === "active") {
179
207
  return reply(`${glyph("active")} ${translate("createApp.created", { name, id: app.id, namespace: namespace.name, repo: repoUrl })}${recentMessages ? `\n${recentMessages}` : ""}` +
180
- next(translate("createApp.createdHint")) +
208
+ next(createdHint) +
181
209
  dashboard, structured);
182
210
  }
183
211
  return reply(`${translate("createApp.pending", { name, id: app.id, status: app.status })}${recentMessages ? `\n${recentMessages}` : ""}` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nullplatform/mcp",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "nullplatform from your code assistant — an MCP server that replaces the dashboard for the everyday developer journey",
5
5
  "license": "MIT",
6
6
  "author": "nullplatform",
@@ -13,11 +13,19 @@ platform you haven't proven yet.
13
13
 
14
14
  ## 1. Place it before you create it
15
15
 
16
- `application_create` opens a pre-filled form but *where* it goes is a real decision, not a
17
- default. Read the request for the home it implies (a demo for a banking client in Argentina is not
18
- the same namespace as a throwaway): list the namespaces the form offers and pick the account +
19
- namespace that fits, and confirm that choice for anything that isn't obviously disposable. New repo
20
- vs. importing an existing one is the other fork the form covers; it derives the repo URL for new ones.
16
+ An app lives in an **account + namespace** pair `application_create` opens a pre-filled form, but
17
+ *where* it goes is a real decision, not a default. Read the request for the home it implies (a demo
18
+ for a banking client in Argentina is not the same namespace as a throwaway) and pick the best-fitting
19
+ pair from that context rather than the first on the list; pass `account` to disambiguate when a
20
+ namespace name repeats across accounts, and `namespace`/`namespace_id` for the namespace. Confirm the
21
+ choice for anything that isn't obviously disposable, and never drop it in the default namespace
22
+ without checking it fits. New repo vs. importing an existing one is the other fork the form covers;
23
+ it derives the repo URL for new ones.
24
+
25
+ For a **new** repo the form also offers scaffolding **templates** — read them and pick the best fit
26
+ for the stack (a React/SPA template for a UI, a Node/Express template for an API). If none fits
27
+ cleanly, say so and offer the closest, or fall back to importing an existing repo — don't force a
28
+ mismatched template. (Importing skips the template entirely: you bring a repo you already have.)
21
29
 
22
30
  A request often implies **more than one app** (a frontend *and* its API). Create them one at a time
23
31
  in the same namespace, named so the pair reads as a set — there is no batch-create, and that's fine:
@@ -45,10 +53,15 @@ Once a service is linked, its connection details arrive **automatically as read-
45
53
  hard-code them or re-create them by hand. New parameters only reach a running scope on the **next
46
54
  deploy**.
47
55
 
48
- ## 4. Hand off to the build
56
+ ## 4. Pull the repo, then build
49
57
 
50
- The platform's job is done when the app exists, runs, and its dependencies are wired and surfaced as
51
- parameters. Writing the REST API, the UI, the schema or its codegen that is your craft, not this
58
+ A new-from-template app is a fresh **remote** repo you've never cloned so the move is forward, not
59
+ backwards: **clone it into a folder and continue the work there**, rather than writing code first and
60
+ retrofitting it onto the platform. (An imported app is already local; nothing to clone.) The create
61
+ reply carries the repo URL; clone it, and if the request implied a pair (a frontend *and* its API),
62
+ clone each into its own folder.
63
+
64
+ Then the code is your own craft — writing the REST API, the UI, the schema or its codegen is not this
52
65
  playbook's job (same boundary as `working-from-a-ticket`). Build against the injected env vars, keep
53
66
  the work on a branch with the issue key (`tracing-a-change`), push so CI produces a build, and ship
54
67
  it with `deploying-safely`.