@renanlido/tia-openness-mcp 1.1.1 → 1.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.
Files changed (2) hide show
  1. package/dist/index.js +396 -396
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -30989,7 +30989,7 @@ async function tiaFetch(path, init = {}, opts = {}) {
30989
30989
  } catch (cause) {
30990
30990
  const isTimeout = cause instanceof Error && (cause.name === "AbortError" || cause.name === "TimeoutError");
30991
30991
  throw new TiaApiError(
30992
- isTimeout ? `Tempo esgotado no CLIENTE ap\xF3s ${timeout}ms aguardando ${BASE}${path}. O host N\xC3O est\xE1 necessariamente inacess\xEDvel: a opera\xE7\xE3o pode AINDA estar rodando no serve (opera\xE7\xE3o lenta do Openness, ou o worker serial ocupado com uma chamada anterior). Aumente TIA_SLOW_TIMEOUT_MS/TIA_API_TIMEOUT_MS ou repita; antes de repetir uma cria\xE7\xE3o/compile, verifique o estado (a 1\xAA tentativa pode ter conclu\xEDdo).` : `N\xE3o foi poss\xEDvel conectar \xE0 API TIA em ${BASE}. O 'serve' est\xE1 rodando e acess\xEDvel a partir desta m\xE1quina?`,
30992
+ isTimeout ? `CLIENT timeout after ${timeout}ms waiting for ${BASE}${path}. The host is NOT necessarily unreachable: the operation may STILL be running on serve (a slow Openness operation, or the serial worker busy with a previous call). Increase TIA_SLOW_TIMEOUT_MS/TIA_API_TIMEOUT_MS or retry; before repeating a create/compile, check the state first (the 1st attempt may have completed).` : `Could not connect to the TIA API at ${BASE}. Is 'serve' running and reachable from this machine?`,
30993
30993
  { kind: isTimeout ? "timeout" : "connection_refused", cause }
30994
30994
  );
30995
30995
  } finally {
@@ -31020,17 +31020,17 @@ async function tiaFetch(path, init = {}, opts = {}) {
31020
31020
  function hintFor(err) {
31021
31021
  switch (err.kind) {
31022
31022
  case "timeout":
31023
- return "A opera\xE7\xE3o pode AINDA estar rodando no serve (worker serial). Aumente TIA_SLOW_TIMEOUT_MS; s\xF3 investigue conectividade (IP/porta/firewall/VM) se GET /health tamb\xE9m falhar.";
31023
+ return "The operation may STILL be running on serve (serial worker). Increase TIA_SLOW_TIMEOUT_MS; only investigate connectivity (IP/port/firewall/VM) if GET /health also fails.";
31024
31024
  case "connection_refused":
31025
- return "Suba a API no host do serve: `TIAOpenness.exe serve 5000 --host 0.0.0.0` e confira TIA_API_BASE.";
31025
+ return "Start the API on the serve host: `TIAOpenness.exe serve 5000 --host 0.0.0.0` and check TIA_API_BASE.";
31026
31026
  case "license_required":
31027
- return "Servidor n\xE3o ativado: configure a chave de API na GUI do TIAOpenness (aba 'Licen\xE7a').";
31027
+ return "Server not activated: configure the API key in the TIAOpenness GUI ('License' tab).";
31028
31028
  case "not_connected":
31029
- return "Nenhum projeto conectado \u2014 conecte/abra um projeto antes desta opera\xE7\xE3o.";
31029
+ return "No project connected \u2014 connect/open a project before this operation.";
31030
31030
  case "not_found":
31031
- return "Recurso n\xE3o encontrado \u2014 redescubra via uma ferramenta de listagem.";
31031
+ return "Resource not found \u2014 rediscover it via a listing tool.";
31032
31032
  }
31033
- if (err.status === 403) return "Servidor n\xE3o ativado \u2014 configure a licen\xE7a na GUI do TIAOpenness.";
31033
+ if (err.status === 403) return "Server not activated \u2014 configure the license in the TIAOpenness GUI.";
31034
31034
  return null;
31035
31035
  }
31036
31036
  function textResult(payload, isError = false) {
@@ -31055,8 +31055,8 @@ function registerReadOnlyTools(server2) {
31055
31055
  server2.registerTool(
31056
31056
  "tia_instances",
31057
31057
  {
31058
- title: "TIA \u2014 inst\xE2ncias em execu\xE7\xE3o",
31059
- description: "Lista as sess\xF5es/inst\xE2ncias do TIA Portal em execu\xE7\xE3o no host do serve (PID, modo, caminho do projeto). Mapeia GET /instances. Read-only (classe R).",
31058
+ title: "TIA \u2014 running instances",
31059
+ description: "Lists the TIA Portal sessions/instances running on the serve host (PID, mode, project path). Maps to GET /instances. Read-only (class R).",
31060
31060
  inputSchema: {}
31061
31061
  },
31062
31062
  async () => getResult("/instances")
@@ -31064,8 +31064,8 @@ function registerReadOnlyTools(server2) {
31064
31064
  server2.registerTool(
31065
31065
  "tia_status",
31066
31066
  {
31067
- title: "TIA \u2014 status da conex\xE3o",
31068
- description: "Status da conex\xE3o atual do serve com o TIA Portal (inst\xE2ncia anexada, projeto ativo). Mapeia GET /tia. Read-only (classe R).",
31067
+ title: "TIA \u2014 connection status",
31068
+ description: "Current status of serve's connection to TIA Portal (attached instance, active project). Maps to GET /tia. Read-only (class R).",
31069
31069
  inputSchema: {}
31070
31070
  },
31071
31071
  async () => getResult("/tia")
@@ -31073,10 +31073,10 @@ function registerReadOnlyTools(server2) {
31073
31073
  server2.registerTool(
31074
31074
  "tia_projects",
31075
31075
  {
31076
- title: "TIA \u2014 projetos numa pasta",
31077
- description: "Lista os arquivos de projeto TIA (.ap*) numa pasta do host do serve. Mapeia GET /tia/projects?folder=<pasta>. Read-only (classe R).",
31076
+ title: "TIA \u2014 projects in a folder",
31077
+ description: "Lists TIA project files (.ap*) in a folder on the serve host. Maps to GET /tia/projects?folder=<folder>. Read-only (class R).",
31078
31078
  inputSchema: {
31079
- folder: external_exports.string().describe("caminho da pasta a varrer no host do serve (obrigat\xF3rio)")
31079
+ folder: external_exports.string().describe("path of the folder to scan on the serve host (required)")
31080
31080
  }
31081
31081
  },
31082
31082
  async ({ folder }) => getResult(`/tia/projects?folder=${encodeURIComponent(folder)}`)
@@ -31084,8 +31084,8 @@ function registerReadOnlyTools(server2) {
31084
31084
  server2.registerTool(
31085
31085
  "tia_project_info",
31086
31086
  {
31087
- title: "TIA \u2014 info do projeto ativo",
31088
- description: "Informa\xE7\xF5es do projeto atualmente conectado (nome, caminho, autor). Requer projeto conectado. Mapeia GET /project. Read-only (classe R).",
31087
+ title: "TIA \u2014 active project info",
31088
+ description: "Information about the currently connected project (name, path, author). Requires a connected project. Maps to GET /project. Read-only (class R).",
31089
31089
  inputSchema: {}
31090
31090
  },
31091
31091
  async () => getResult("/project")
@@ -31093,8 +31093,8 @@ function registerReadOnlyTools(server2) {
31093
31093
  server2.registerTool(
31094
31094
  "tia_project_languages",
31095
31095
  {
31096
- title: "TIA \u2014 idiomas do projeto",
31097
- description: "Lista os idiomas (culturas) configurados no projeto ativo. Requer projeto conectado. Mapeia GET /project/languages. Read-only (classe R).",
31096
+ title: "TIA \u2014 project languages",
31097
+ description: "Lists the languages (cultures) configured in the active project. Requires a connected project. Maps to GET /project/languages. Read-only (class R).",
31098
31098
  inputSchema: {}
31099
31099
  },
31100
31100
  async () => getResult("/project/languages")
@@ -31102,8 +31102,8 @@ function registerReadOnlyTools(server2) {
31102
31102
  server2.registerTool(
31103
31103
  "tia_plcs",
31104
31104
  {
31105
- title: "TIA \u2014 lista de CLPs",
31106
- description: "Lista os CLPs (PlcSoftware) do projeto ativo. Requer projeto conectado. Mapeia GET /plcs. Read-only (classe R).",
31105
+ title: "TIA \u2014 list of PLCs",
31106
+ description: "Lists the PLCs (PlcSoftware) of the active project. Requires a connected project. Maps to GET /plcs. Read-only (class R).",
31107
31107
  inputSchema: {}
31108
31108
  },
31109
31109
  async () => getResult("/plcs")
@@ -31111,8 +31111,8 @@ function registerReadOnlyTools(server2) {
31111
31111
  server2.registerTool(
31112
31112
  "tia_devices",
31113
31113
  {
31114
- title: "TIA \u2014 lista de devices",
31115
- description: "Lista os devices do projeto e seus itens. Requer projeto conectado. Mapeia GET /devices. Read-only (classe R).",
31114
+ title: "TIA \u2014 list of devices",
31115
+ description: "Lists the project's devices and their items. Requires a connected project. Maps to GET /devices. Read-only (class R).",
31116
31116
  inputSchema: {}
31117
31117
  },
31118
31118
  async () => getResult("/devices")
@@ -31120,10 +31120,10 @@ function registerReadOnlyTools(server2) {
31120
31120
  server2.registerTool(
31121
31121
  "tia_device_tree",
31122
31122
  {
31123
- title: "TIA \u2014 \xE1rvore de um device",
31124
- description: "\xC1rvore de hardware de um device (racks/slots/m\xF3dulos). Requer projeto conectado. Mapeia GET /devices/{device}/tree. Read-only (classe R).",
31123
+ title: "TIA \u2014 device tree",
31124
+ description: "Hardware tree of a device (racks/slots/modules). Requires a connected project. Maps to GET /devices/{device}/tree. Read-only (class R).",
31125
31125
  inputSchema: {
31126
- device: external_exports.string().describe("nome do device")
31126
+ device: external_exports.string().describe("device name")
31127
31127
  }
31128
31128
  },
31129
31129
  async ({ device }) => getResult(`/devices/${seg(device)}/tree`)
@@ -31131,10 +31131,10 @@ function registerReadOnlyTools(server2) {
31131
31131
  server2.registerTool(
31132
31132
  "tia_device_connections",
31133
31133
  {
31134
- title: "TIA \u2014 conex\xF5es de um device",
31135
- description: "Lista as conex\xF5es de comunica\xE7\xE3o (S7 etc.) de um device. Requer projeto conectado. Mapeia GET /devices/{device}/connections. Read-only (classe R).",
31134
+ title: "TIA \u2014 device connections",
31135
+ description: "Lists the communication connections (S7 etc.) of a device. Requires a connected project. Maps to GET /devices/{device}/connections. Read-only (class R).",
31136
31136
  inputSchema: {
31137
- device: external_exports.string().describe("nome do device")
31137
+ device: external_exports.string().describe("device name")
31138
31138
  }
31139
31139
  },
31140
31140
  async ({ device }) => getResult(`/devices/${seg(device)}/connections`)
@@ -31142,10 +31142,10 @@ function registerReadOnlyTools(server2) {
31142
31142
  server2.registerTool(
31143
31143
  "tia_plc_blocks",
31144
31144
  {
31145
- title: "TIA \u2014 blocos de um CLP",
31146
- description: "Lista os blocos de um CLP (name, type, language, number, isConsistent, isKnowHowProtected). Requer projeto conectado. Mapeia GET /plcs/{plc}/blocks. Read-only (classe R).",
31145
+ title: "TIA \u2014 blocks of a PLC",
31146
+ description: "Lists the blocks of a PLC (name, type, language, number, isConsistent, isKnowHowProtected). Requires a connected project. Maps to GET /plcs/{plc}/blocks. Read-only (class R).",
31147
31147
  inputSchema: {
31148
- plc: external_exports.string().describe("nome do CLP")
31148
+ plc: external_exports.string().describe("PLC name")
31149
31149
  }
31150
31150
  },
31151
31151
  async ({ plc }) => getResult(`/plcs/${seg(plc)}/blocks`)
@@ -31153,10 +31153,10 @@ function registerReadOnlyTools(server2) {
31153
31153
  server2.registerTool(
31154
31154
  "tia_plc_types",
31155
31155
  {
31156
- title: "TIA \u2014 tipos (UDTs) de um CLP",
31157
- description: "Lista os tipos de dados de usu\xE1rio (UDTs) de um CLP. Requer projeto conectado. Mapeia GET /plcs/{plc}/types. Read-only (classe R).",
31156
+ title: "TIA \u2014 types (UDTs) of a PLC",
31157
+ description: "Lists the user data types (UDTs) of a PLC. Requires a connected project. Maps to GET /plcs/{plc}/types. Read-only (class R).",
31158
31158
  inputSchema: {
31159
- plc: external_exports.string().describe("nome do CLP")
31159
+ plc: external_exports.string().describe("PLC name")
31160
31160
  }
31161
31161
  },
31162
31162
  async ({ plc }) => getResult(`/plcs/${seg(plc)}/types`)
@@ -31164,10 +31164,10 @@ function registerReadOnlyTools(server2) {
31164
31164
  server2.registerTool(
31165
31165
  "tia_plc_tags",
31166
31166
  {
31167
- title: "TIA \u2014 tabelas de tags de um CLP",
31168
- description: "Lista as tabelas de tags e suas tags de um CLP. Requer projeto conectado. Mapeia GET /plcs/{plc}/tags. Read-only (classe R).",
31167
+ title: "TIA \u2014 tag tables of a PLC",
31168
+ description: "Lists the tag tables and their tags for a PLC. Requires a connected project. Maps to GET /plcs/{plc}/tags. Read-only (class R).",
31169
31169
  inputSchema: {
31170
- plc: external_exports.string().describe("nome do CLP")
31170
+ plc: external_exports.string().describe("PLC name")
31171
31171
  }
31172
31172
  },
31173
31173
  async ({ plc }) => getResult(`/plcs/${seg(plc)}/tags`)
@@ -31175,10 +31175,10 @@ function registerReadOnlyTools(server2) {
31175
31175
  server2.registerTool(
31176
31176
  "tia_plc_watchtables",
31177
31177
  {
31178
- title: "TIA \u2014 watch tables de um CLP",
31179
- description: "Lista as watch tables (tabelas de observa\xE7\xE3o) de um CLP. Requer projeto conectado. Mapeia GET /plcs/{plc}/watchtables. Read-only (classe R).",
31178
+ title: "TIA \u2014 watch tables of a PLC",
31179
+ description: "Lists the watch tables of a PLC. Requires a connected project. Maps to GET /plcs/{plc}/watchtables. Read-only (class R).",
31180
31180
  inputSchema: {
31181
- plc: external_exports.string().describe("nome do CLP")
31181
+ plc: external_exports.string().describe("PLC name")
31182
31182
  }
31183
31183
  },
31184
31184
  async ({ plc }) => getResult(`/plcs/${seg(plc)}/watchtables`)
@@ -31186,12 +31186,12 @@ function registerReadOnlyTools(server2) {
31186
31186
  server2.registerTool(
31187
31187
  "tia_catalog",
31188
31188
  {
31189
- title: "TIA \u2014 pesquisa no cat\xE1logo de hardware",
31190
- description: "Pesquisa no cat\xE1logo de hardware (article number, type identifier, vers\xE3o). Requer TIA conectado. Por padr\xE3o a 'description' (longa) \xE9 OMITIDA \u2014 em filtros amplos ela estoura o payload (description \xD7 variantes de firmware); passe verbose:true COM um filtro espec\xEDfico p/ inclu\xED-la. Mapeia GET /catalog?filter=&typeIdentifier=&verbose=. Read-only (R).",
31189
+ title: "TIA \u2014 search the hardware catalog",
31190
+ description: "Searches the hardware catalog (article number, type identifier, version). Requires TIA connected. By default the (long) 'description' is OMITTED \u2014 on broad filters it blows up the payload (description \xD7 firmware variants); pass verbose:true WITH a specific filter to include it. Maps to GET /catalog?filter=&typeIdentifier=&verbose=. Read-only (R).",
31191
31191
  inputSchema: {
31192
- filter: external_exports.string().describe("texto de filtro: n\xBA de artigo, descri\xE7\xE3o etc. (opcional)").optional(),
31193
- typeIdentifier: external_exports.string().describe("type identifier para filtrar (opcional)").optional(),
31194
- verbose: external_exports.boolean().describe("incluir a 'description' completa (off por padr\xE3o; em filtros amplos estoura o payload \u2014 use com filtro espec\xEDfico)").optional()
31192
+ filter: external_exports.string().describe("filter text: article no., description, etc. (optional)").optional(),
31193
+ typeIdentifier: external_exports.string().describe("type identifier to filter by (optional)").optional(),
31194
+ verbose: external_exports.boolean().describe("include the full 'description' (off by default; on broad filters it blows up the payload \u2014 use with a specific filter)").optional()
31195
31195
  }
31196
31196
  },
31197
31197
  async ({ filter, typeIdentifier, verbose }) => {
@@ -31206,11 +31206,11 @@ function registerReadOnlyTools(server2) {
31206
31206
  server2.registerTool(
31207
31207
  "tia_connections_diagnose",
31208
31208
  {
31209
- title: "TIA \u2014 diagn\xF3stico de conex\xE3o S7",
31210
- description: "Diagn\xF3stico p/ uma conex\xE3o S7 entre dois devices: interfaces, n\xF3s e creationinfos dispon\xEDveis. Requer projeto conectado. Mapeia GET /connections/diagnose?localDevice=&partnerDevice= (ambos obrigat\xF3rios). Read-only (classe R).",
31209
+ title: "TIA \u2014 S7 connection diagnostics",
31210
+ description: "Diagnostic for an S7 connection between two devices: available interfaces, nodes, and creationinfos. Requires a connected project. Maps to GET /connections/diagnose?localDevice=&partnerDevice= (both required). Read-only (class R).",
31211
31211
  inputSchema: {
31212
- localDevice: external_exports.string().describe("nome do device local (obrigat\xF3rio)"),
31213
- partnerDevice: external_exports.string().describe("nome do device parceiro (obrigat\xF3rio)")
31212
+ localDevice: external_exports.string().describe("local device name (required)"),
31213
+ partnerDevice: external_exports.string().describe("partner device name (required)")
31214
31214
  }
31215
31215
  },
31216
31216
  async ({ localDevice, partnerDevice }) => getResult(`/connections/diagnose?localDevice=${encodeURIComponent(localDevice)}&partnerDevice=${encodeURIComponent(partnerDevice)}`)
@@ -31218,8 +31218,8 @@ function registerReadOnlyTools(server2) {
31218
31218
  server2.registerTool(
31219
31219
  "tia_subnets",
31220
31220
  {
31221
- title: "TIA \u2014 lista de subnets",
31222
- description: "Lista as subnets do projeto ativo. Requer projeto conectado. Mapeia GET /subnets. Read-only (classe R).",
31221
+ title: "TIA \u2014 list of subnets",
31222
+ description: "Lists the active project's subnets. Requires a connected project. Maps to GET /subnets. Read-only (class R).",
31223
31223
  inputSchema: {}
31224
31224
  },
31225
31225
  async () => getResult("/subnets")
@@ -31227,8 +31227,8 @@ function registerReadOnlyTools(server2) {
31227
31227
  server2.registerTool(
31228
31228
  "tia_obj_roots",
31229
31229
  {
31230
- title: "TIA \u2014 ra\xEDzes do modelo de objetos",
31231
- description: "Handles das ra\xEDzes do modelo gen\xE9rico de objetos (project, devices, subnets). Requer projeto conectado. Mapeia GET /obj/roots. Read-only (classe R).",
31230
+ title: "TIA \u2014 object model roots",
31231
+ description: "Handles of the roots of the generic object model (project, devices, subnets). Requires a connected project. Maps to GET /obj/roots. Read-only (class R).",
31232
31232
  inputSchema: {}
31233
31233
  },
31234
31234
  async () => getResult("/obj/roots")
@@ -31236,10 +31236,10 @@ function registerReadOnlyTools(server2) {
31236
31236
  server2.registerTool(
31237
31237
  "tia_obj_get",
31238
31238
  {
31239
- title: "TIA \u2014 objeto por handle",
31240
- description: "Detalhes de um objeto pelo handle (tipo, nome, atributos, composi\xE7\xF5es). Requer projeto conectado. Mapeia GET /obj/{handle}. Read-only (classe R).",
31239
+ title: "TIA \u2014 object by handle",
31240
+ description: "Details of an object by handle (type, name, attributes, compositions). Requires a connected project. Maps to GET /obj/{handle}. Read-only (class R).",
31241
31241
  inputSchema: {
31242
- handle: external_exports.string().describe("handle inteiro do objeto (obtido em /obj/roots ou /obj/{h}/items/{comp})")
31242
+ handle: external_exports.string().describe("integer handle of the object (obtained from /obj/roots or /obj/{h}/items/{comp})")
31243
31243
  }
31244
31244
  },
31245
31245
  async ({ handle }) => getResult(`/obj/${seg(handle)}`)
@@ -31247,11 +31247,11 @@ function registerReadOnlyTools(server2) {
31247
31247
  server2.registerTool(
31248
31248
  "tia_obj_items",
31249
31249
  {
31250
- title: "TIA \u2014 filhos de uma composi\xE7\xE3o",
31251
- description: "Handles dos filhos de um objeto numa composi\xE7\xE3o. Requer projeto conectado. Mapeia GET /obj/{handle}/items/{composition}. Read-only (classe R).",
31250
+ title: "TIA \u2014 children of a composition",
31251
+ description: "Handles of an object's children in a composition. Requires a connected project. Maps to GET /obj/{handle}/items/{composition}. Read-only (class R).",
31252
31252
  inputSchema: {
31253
- handle: external_exports.string().describe("handle inteiro do objeto pai"),
31254
- composition: external_exports.string().describe("nome da composi\xE7\xE3o a enumerar")
31253
+ handle: external_exports.string().describe("integer handle of the parent object"),
31254
+ composition: external_exports.string().describe("name of the composition to enumerate")
31255
31255
  }
31256
31256
  },
31257
31257
  async ({ handle, composition }) => getResult(`/obj/${seg(handle)}/items/${seg(composition)}`)
@@ -31259,10 +31259,10 @@ function registerReadOnlyTools(server2) {
31259
31259
  server2.registerTool(
31260
31260
  "tia_obj_info",
31261
31261
  {
31262
- title: "TIA \u2014 info de um objeto",
31263
- description: "Composi\xE7\xF5es e invoca\xE7\xF5es dispon\xEDveis de um objeto. Requer projeto conectado. Mapeia GET /obj/{handle}/info. Read-only (classe R).",
31262
+ title: "TIA \u2014 object info",
31263
+ description: "Available compositions and invocations of an object. Requires a connected project. Maps to GET /obj/{handle}/info. Read-only (class R).",
31264
31264
  inputSchema: {
31265
- handle: external_exports.string().describe("handle inteiro do objeto")
31265
+ handle: external_exports.string().describe("integer handle of the object")
31266
31266
  }
31267
31267
  },
31268
31268
  async ({ handle }) => getResult(`/obj/${seg(handle)}/info`)
@@ -31270,11 +31270,11 @@ function registerReadOnlyTools(server2) {
31270
31270
  server2.registerTool(
31271
31271
  "tia_obj_creationinfos",
31272
31272
  {
31273
- title: "TIA \u2014 infos de cria\xE7\xE3o de uma composi\xE7\xE3o",
31274
- description: "Types cri\xE1veis numa composi\xE7\xE3o e seus par\xE2metros (mandat\xF3rio/tipos suportados). Requer projeto conectado. Mapeia GET /obj/{handle}/creationinfos/{composition}. Read-only (classe R).",
31273
+ title: "TIA \u2014 creation info for a composition",
31274
+ description: "Creatable types in a composition and their parameters (mandatory/supported types). Requires a connected project. Maps to GET /obj/{handle}/creationinfos/{composition}. Read-only (class R).",
31275
31275
  inputSchema: {
31276
- handle: external_exports.string().describe("handle inteiro do objeto pai"),
31277
- composition: external_exports.string().describe("nome da composi\xE7\xE3o")
31276
+ handle: external_exports.string().describe("integer handle of the parent object"),
31277
+ composition: external_exports.string().describe("composition name")
31278
31278
  }
31279
31279
  },
31280
31280
  async ({ handle, composition }) => getResult(`/obj/${seg(handle)}/creationinfos/${seg(composition)}`)
@@ -31282,10 +31282,10 @@ function registerReadOnlyTools(server2) {
31282
31282
  server2.registerTool(
31283
31283
  "tia_obj_services",
31284
31284
  {
31285
- title: "TIA \u2014 servi\xE7os de um objeto",
31286
- description: "Lista os servi\xE7os (GetService<T>) dispon\xEDveis num objeto. Requer projeto conectado. Mapeia GET /obj/{handle}/services. Read-only (classe R).",
31285
+ title: "TIA \u2014 services of an object",
31286
+ description: "Lists the services (GetService<T>) available on an object. Requires a connected project. Maps to GET /obj/{handle}/services. Read-only (class R).",
31287
31287
  inputSchema: {
31288
- handle: external_exports.string().describe("handle inteiro do objeto")
31288
+ handle: external_exports.string().describe("integer handle of the object")
31289
31289
  }
31290
31290
  },
31291
31291
  async ({ handle }) => getResult(`/obj/${seg(handle)}/services`)
@@ -31335,11 +31335,11 @@ function trustHandoff(projectPath, err) {
31335
31335
  gate: "trust_dialog",
31336
31336
  state: "WAITING_FOR_TRUST",
31337
31337
  canDo: `connect ${projectPath}`,
31338
- youMustDo: 'Um humano precisa confirmar o di\xE1logo de CONFIAN\xC7A/SEGURAN\xC7A do TIA Openness NO HOST DO SERVE (clicar "Sim, para tudo" / "Yes to all"). \xC9 exigido na 1\xAA conex\xE3o de cada processo `serve` e N\xC3O pode ser automatizado (por seguran\xE7a).',
31338
+ youMustDo: 'A human needs to confirm the TIA Openness TRUST/SECURITY dialog ON THE SERVE HOST (click "Sim, para tudo" / "Yes to all"). It is required on the 1st connection of each `serve` process and CANNOT be automated (for security reasons).',
31339
31339
  nextSteps: [
31340
- "1. Se o TIA est\xE1 headless, chame tia_show_ui para relan\xE7\xE1-lo VIS\xCDVEL e renderizar o di\xE1logo na tela.",
31341
- "2. Pe\xE7a a um humano para confirmar o di\xE1logo de confian\xE7a no host do serve.",
31342
- "3. Re-chame tia_connect com o MESMO projectPath e este resumeToken."
31340
+ "1. If TIA is headless, call tia_show_ui to relaunch it VISIBLE and render the dialog on screen.",
31341
+ "2. Ask a human to confirm the trust dialog on the serve host.",
31342
+ "3. Re-call tia_connect with the SAME projectPath and this resumeToken."
31343
31343
  ],
31344
31344
  blockingError: err.message,
31345
31345
  resumeToken
@@ -31376,10 +31376,10 @@ function registerLifecycleTools(server2) {
31376
31376
  server2.registerTool(
31377
31377
  "tia_start",
31378
31378
  {
31379
- title: "TIA \u2014 iniciar/anexar (sem projeto)",
31380
- description: "Inicia o TIA Portal (ou anexa a uma inst\xE2ncia ociosa) SEM abrir projeto. Classe M-off (muta\xE7\xE3o offline). `headless` s\xF3 vale ao CRIAR uma inst\xE2ncia nova (ao anexar, herda o modo existente). Passo 1 do fluxo proativo do GATE de confian\xE7a: tia_start \u2192 tia_show_ui \u2192 tia_connect. Mapeia POST /tia/start.",
31379
+ title: "TIA \u2014 start/attach (no project)",
31380
+ description: "Starts TIA Portal (or attaches to an idle instance) WITHOUT opening a project. Class M-off (offline mutation). `headless` only applies when CREATING a new instance (when attaching, it inherits the existing mode). Step 1 of the proactive trust-GATE flow: tia_start \u2192 tia_show_ui \u2192 tia_connect. Maps to POST /tia/start.",
31381
31381
  inputSchema: {
31382
- headless: external_exports.boolean().optional().describe("true = sem janela (autoria offline r\xE1pida); false (default) = com janela. S\xF3 ao criar inst\xE2ncia nova.")
31382
+ headless: external_exports.boolean().optional().describe("true = no window (fast offline authoring); false (default) = with window. Only when creating a new instance.")
31383
31383
  }
31384
31384
  },
31385
31385
  async ({ headless }) => postResult("/tia/start", jsonBody({ headless }))
@@ -31387,8 +31387,8 @@ function registerLifecycleTools(server2) {
31387
31387
  server2.registerTool(
31388
31388
  "tia_show_ui",
31389
31389
  {
31390
- title: "TIA \u2014 tornar vis\xEDvel (habilita o GATE de confian\xE7a)",
31391
- description: "Relan\xE7a a inst\xE2ncia HEADLESS que n\xF3s iniciamos como VIS\xCDVEL, reabrindo o mesmo projeto, para RENDERIZAR na tela o di\xE1logo de confian\xE7a da 1\xAA conex\xE3o (o handoff concreto do GATE G1) \u2014 assim um humano consegue confirm\xE1-lo. S\xF3 funciona se o serve for dono do portal (n\xE3o em inst\xE2ncia anexada). Mapeia POST /tia/show-ui. Use ANTES de tia_connect quando iniciou headless.",
31390
+ title: "TIA \u2014 make visible (enables the trust GATE)",
31391
+ description: "Relaunches the HEADLESS instance we started as VISIBLE, reopening the same project, to RENDER the 1st-connection trust dialog on screen (the concrete handoff of GATE G1) \u2014 so a human can confirm it. Only works if serve owns the portal (not on an attached instance). Maps to POST /tia/show-ui. Use BEFORE tia_connect when you started headless.",
31392
31392
  inputSchema: {}
31393
31393
  },
31394
31394
  async () => postResult("/tia/show-ui")
@@ -31396,15 +31396,15 @@ function registerLifecycleTools(server2) {
31396
31396
  server2.registerTool(
31397
31397
  "tia_connect",
31398
31398
  {
31399
- title: "TIA \u2014 conectar/abrir projeto (GATE de confian\xE7a G1)",
31400
- description: "Abre/anexa um projeto TIA (.ap*) no host do serve. Classe M-off. ATEN\xC7\xC3O: a 1\xAA conex\xE3o por processo `serve` pode BLOQUEAR no GATE de confian\xE7a (G1) \u2014 se o di\xE1logo n\xE3o estiver confirmado, esta tool N\xC3O faz retry-storm: devolve um envelope `requires_human_action` (gate trust_dialog, com resumeToken) pedindo que um humano confirme o di\xE1logo no host. Fluxo proativo: tia_start \u2192 tia_show_ui \u2192 (humano confirma) \u2192 tia_connect. UMAC (umacUser/umacPassword) \xE9 o GATE G6: forne\xE7a SOMENTE se um humano deu as credenciais \u2014 NUNCA invente. Mapeia POST /connect.",
31399
+ title: "TIA \u2014 connect/open project (trust GATE G1)",
31400
+ description: "Opens/attaches a TIA project (.ap*) on the serve host. Class M-off. WARNING: the 1st connection per `serve` process can BLOCK on the trust GATE (G1) \u2014 if the dialog hasn't been confirmed, this tool does NOT retry-storm: it returns a `requires_human_action` envelope (gate trust_dialog, with resumeToken) asking a human to confirm the dialog on the host. Proactive flow: tia_start \u2192 tia_show_ui \u2192 (human confirms) \u2192 tia_connect. UMAC (umacUser/umacPassword) is GATE G6: provide it ONLY if a human gave the credentials \u2014 NEVER make them up. Maps to POST /connect.",
31401
31401
  inputSchema: {
31402
- projectPath: external_exports.string().describe("caminho do arquivo de projeto (.ap*) no host do serve (obrigat\xF3rio)"),
31403
- withUserInterface: external_exports.boolean().optional().describe("abrir com a UI do TIA vis\xEDvel (default true)"),
31404
- umacUser: external_exports.string().optional().describe("usu\xE1rio UMAC (GATE G6; s\xF3 se um humano forneceu \u2014 nunca inventar)"),
31405
- umacPassword: external_exports.string().optional().describe("senha UMAC (GATE G6; s\xF3 se um humano forneceu \u2014 nunca inventar)"),
31406
- umacType: external_exports.string().optional().describe('tipo de credencial UMAC (default "Project")'),
31407
- resumeToken: external_exports.string().optional().describe("token devolvido pelo handoff do GATE; re-chame com ele DEPOIS que um humano confirmou o di\xE1logo")
31402
+ projectPath: external_exports.string().describe("path to the project file (.ap*) on the serve host (required)"),
31403
+ withUserInterface: external_exports.boolean().optional().describe("open with the TIA UI visible (default true)"),
31404
+ umacUser: external_exports.string().optional().describe("UMAC user (GATE G6; only if a human provided it \u2014 never make it up)"),
31405
+ umacPassword: external_exports.string().optional().describe("UMAC password (GATE G6; only if a human provided it \u2014 never make it up)"),
31406
+ umacType: external_exports.string().optional().describe('UMAC credential type (default "Project")'),
31407
+ resumeToken: external_exports.string().optional().describe("token returned by the GATE handoff; re-call with it AFTER a human has confirmed the dialog")
31408
31408
  }
31409
31409
  },
31410
31410
  async (args) => connectFlow(args)
@@ -31412,8 +31412,8 @@ function registerLifecycleTools(server2) {
31412
31412
  server2.registerTool(
31413
31413
  "tia_disconnect",
31414
31414
  {
31415
- title: "TIA \u2014 desconectar",
31416
- description: "Desconecta do TIA. ATEN\xC7\xC3O (Gd3): numa inst\xE2ncia ANEXADA, /disconnect N\xC3O fecha o projeto \u2014 para LIBERAR o lock do projeto use tia_project_close. Mapeia POST /disconnect.",
31415
+ title: "TIA \u2014 disconnect",
31416
+ description: "Disconnects from TIA. WARNING (Gd3): on an ATTACHED instance, /disconnect does NOT close the project \u2014 to RELEASE the project lock use tia_project_close. Maps to POST /disconnect.",
31417
31417
  inputSchema: {}
31418
31418
  },
31419
31419
  async () => postResult("/disconnect")
@@ -31421,12 +31421,12 @@ function registerLifecycleTools(server2) {
31421
31421
  server2.registerTool(
31422
31422
  "tia_project_create",
31423
31423
  {
31424
- title: "TIA \u2014 criar projeto",
31425
- description: "Cria um novo projeto TIA. Guard Gd4: o diret\xF3rio de destino deve estar VAZIO \u2014 se n\xE3o estiver, o serve retorna 409 conflict (esta tool repassa o erro; redescubra/escolha outro diret\xF3rio). Mapeia POST /project/create.",
31424
+ title: "TIA \u2014 create project",
31425
+ description: "Creates a new TIA project. Guard Gd4: the target directory must be EMPTY \u2014 if it isn't, serve returns 409 conflict (this tool passes the error through; rediscover/choose another directory). Maps to POST /project/create.",
31426
31426
  inputSchema: {
31427
- directory: external_exports.string().describe("diret\xF3rio de destino (deve estar vazio \u2014 Gd4) (obrigat\xF3rio)"),
31428
- name: external_exports.string().describe("nome do projeto (obrigat\xF3rio)"),
31429
- withUserInterface: external_exports.boolean().optional().describe("criar com a UI do TIA vis\xEDvel (default true)")
31427
+ directory: external_exports.string().describe("target directory (must be empty \u2014 Gd4) (required)"),
31428
+ name: external_exports.string().describe("project name (required)"),
31429
+ withUserInterface: external_exports.boolean().optional().describe("create with the TIA UI visible (default true)")
31430
31430
  }
31431
31431
  },
31432
31432
  async ({ directory, name, withUserInterface }) => postResult("/project/create", jsonBody({ directory, name, withUserInterface }))
@@ -31434,8 +31434,8 @@ function registerLifecycleTools(server2) {
31434
31434
  server2.registerTool(
31435
31435
  "tia_project_save",
31436
31436
  {
31437
- title: "TIA \u2014 salvar projeto",
31438
- description: "Salva o projeto aberto. Mapeia POST /project/save.",
31437
+ title: "TIA \u2014 save project",
31438
+ description: "Saves the open project. Maps to POST /project/save.",
31439
31439
  inputSchema: {}
31440
31440
  },
31441
31441
  async () => postResult("/project/save")
@@ -31443,10 +31443,10 @@ function registerLifecycleTools(server2) {
31443
31443
  server2.registerTool(
31444
31444
  "tia_project_saveas",
31445
31445
  {
31446
- title: "TIA \u2014 salvar projeto como",
31447
- description: "Salva o projeto aberto em outro diret\xF3rio. Mapeia POST /project/saveas.",
31446
+ title: "TIA \u2014 save project as",
31447
+ description: "Saves the open project to another directory. Maps to POST /project/saveas.",
31448
31448
  inputSchema: {
31449
- directory: external_exports.string().optional().describe("diret\xF3rio de destino do 'salvar como'")
31449
+ directory: external_exports.string().optional().describe("target directory for 'save as'")
31450
31450
  }
31451
31451
  },
31452
31452
  async ({ directory }) => postResult("/project/saveas", jsonBody({ directory }))
@@ -31454,8 +31454,8 @@ function registerLifecycleTools(server2) {
31454
31454
  server2.registerTool(
31455
31455
  "tia_project_close",
31456
31456
  {
31457
- title: "TIA \u2014 fechar projeto",
31458
- description: "Fecha o projeto aberto e LIBERA o lock (Gd3: use isto, n\xE3o tia_disconnect, para liberar o projeto). Mapeia POST /project/close.",
31457
+ title: "TIA \u2014 close project",
31458
+ description: "Closes the open project and RELEASES the lock (Gd3: use this, not tia_disconnect, to release the project). Maps to POST /project/close.",
31459
31459
  inputSchema: {}
31460
31460
  },
31461
31461
  async () => postResult("/project/close")
@@ -31463,12 +31463,12 @@ function registerLifecycleTools(server2) {
31463
31463
  server2.registerTool(
31464
31464
  "tia_project_archive",
31465
31465
  {
31466
- title: "TIA \u2014 arquivar projeto",
31467
- description: "Arquiva o projeto aberto (.zap*). Mapeia POST /project/archive.",
31466
+ title: "TIA \u2014 archive project",
31467
+ description: "Archives the open project (.zap*). Maps to POST /project/archive.",
31468
31468
  inputSchema: {
31469
- directory: external_exports.string().optional().describe("diret\xF3rio de destino do arquivo"),
31470
- name: external_exports.string().optional().describe("nome do arquivo"),
31471
- mode: external_exports.string().optional().describe("modo de arquivamento (ex.: Compressed)")
31469
+ directory: external_exports.string().optional().describe("target directory for the archive"),
31470
+ name: external_exports.string().optional().describe("archive file name"),
31471
+ mode: external_exports.string().optional().describe("archive mode (e.g., Compressed)")
31472
31472
  }
31473
31473
  },
31474
31474
  async ({ directory, name, mode }) => postResult("/project/archive", jsonBody({ directory, name, mode }))
@@ -31491,7 +31491,7 @@ function errorResult2(err) {
31491
31491
  function gd5Violation(typeIdentifier) {
31492
31492
  if (!typeIdentifier) return null;
31493
31493
  if (/:V\d/.test(typeIdentifier)) {
31494
- return `Gd5: o typeIdentifier usa ':V' (forma drift) antes da vers\xE3o de firmware. Use '/V' (barra) \u2014 ex.: "OrderNumber:6ES7 511-1AK02-0AB0/V2.9". Resolva o valor exato com tia_catalog.`;
31494
+ return `Gd5: the typeIdentifier uses ':V' (drift form) before the firmware version. Use '/V' (slash) \u2014 e.g.: "OrderNumber:6ES7 511-1AK02-0AB0/V2.9". Resolve the exact value with tia_catalog.`;
31495
31495
  }
31496
31496
  return null;
31497
31497
  }
@@ -31503,7 +31503,7 @@ function guardError(guard, message, context) {
31503
31503
  guard,
31504
31504
  blockedBeforeOpenness: true,
31505
31505
  context,
31506
- hint: "Corrija a entrada e tente de novo \u2014 nada foi alterado no projeto."
31506
+ hint: "Fix the input and try again \u2014 nothing was changed in the project."
31507
31507
  },
31508
31508
  true
31509
31509
  );
@@ -31517,7 +31517,7 @@ async function mutate(method, path, body, opts) {
31517
31517
  action: `${method} ${path}`,
31518
31518
  summary: opts.summary,
31519
31519
  body: body ?? null,
31520
- note: "Plano validado (guards OK). NADA foi alterado. Rode de novo com dryRun:false para aplicar."
31520
+ note: "Plan validated (guards OK). NOTHING was changed. Run again with dryRun:false to apply."
31521
31521
  },
31522
31522
  false
31523
31523
  );
@@ -31536,7 +31536,7 @@ async function deviceCreateFlow(args) {
31536
31536
  if (bad) return guardError("Gd5", bad, { typeIdentifier: args.typeIdentifier });
31537
31537
  return mutate("POST", "/devices", jsonBody2({ typeIdentifier: args.typeIdentifier, deviceItemName: args.deviceItemName, deviceName: args.deviceName }), {
31538
31538
  dryRun: args.dryRun,
31539
- summary: `criar device "${args.deviceName ?? args.deviceItemName ?? "?"}" (${args.typeIdentifier})`
31539
+ summary: `create device "${args.deviceName ?? args.deviceItemName ?? "?"}" (${args.typeIdentifier})`
31540
31540
  });
31541
31541
  }
31542
31542
  async function deviceChangeVersionFlow(args) {
@@ -31544,22 +31544,22 @@ async function deviceChangeVersionFlow(args) {
31544
31544
  if (bad) return guardError("Gd5", bad, { typeIdentifier: args.typeIdentifier });
31545
31545
  return mutate("POST", `/plcs/${seg2(args.plc)}/device/changeversion`, jsonBody2({ typeIdentifier: args.typeIdentifier, dryRun: args.dryRun }), {
31546
31546
  dryRun: args.dryRun,
31547
- summary: `trocar firmware da CPU "${args.plc}" para ${args.typeIdentifier}`
31547
+ summary: `change firmware of CPU "${args.plc}" to ${args.typeIdentifier}`
31548
31548
  });
31549
31549
  }
31550
31550
  var dryRunField = {
31551
- dryRun: external_exports.boolean().optional().describe("Gd11: plano-sem-aplicar \u2014 valida os guards e descreve a a\xE7\xE3o SEM mutar o projeto")
31551
+ dryRun: external_exports.boolean().optional().describe("Gd11: plan-without-applying \u2014 validates the guards and describes the action WITHOUT mutating the project")
31552
31552
  };
31553
31553
  function registerAuthoringTools(server2) {
31554
31554
  server2.registerTool(
31555
31555
  "tia_device_create",
31556
31556
  {
31557
- title: "TIA \u2014 criar device",
31558
- description: "Cria um device (CPU/HMI/IO) por typeIdentifier. Guard Gd5: '/V<fw>' (barra), nunca ':V' \u2014 resolva via tia_catalog. Mapeia POST /devices. Classe M-off.",
31557
+ title: "TIA \u2014 create device",
31558
+ description: "Creates a device (CPU/HMI/IO) by typeIdentifier. Guard Gd5: '/V<fw>' (slash), never ':V' \u2014 resolve via tia_catalog. Maps to POST /devices. Class M-off.",
31559
31559
  inputSchema: {
31560
- typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw> (Gd5; resolva via tia_catalog)"),
31561
- deviceItemName: external_exports.string().optional().describe("nome do device item (ex.: o m\xF3dulo/CPU)"),
31562
- deviceName: external_exports.string().optional().describe("nome do device (esta\xE7\xE3o)"),
31560
+ typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw> (Gd5; resolve via tia_catalog)"),
31561
+ deviceItemName: external_exports.string().optional().describe("device item name (e.g., the module/CPU)"),
31562
+ deviceName: external_exports.string().optional().describe("device name (station)"),
31563
31563
  ...dryRunField
31564
31564
  }
31565
31565
  },
@@ -31568,11 +31568,11 @@ function registerAuthoringTools(server2) {
31568
31568
  server2.registerTool(
31569
31569
  "tia_device_change_version",
31570
31570
  {
31571
- title: "TIA \u2014 trocar firmware da CPU (in-place)",
31572
- description: "Troca a vers\xE3o de FIRMWARE da CPU IN-PLACE (wrap do DeviceItem.ChangeType), PRESERVANDO o programa \u2014 alternativa ao delete+recreate (habilita o 'auto-FW-match'). Guard Gd5: o typeIdentifier segue 'OrderNumber:<MLFB>/V<fw>' com '/V' (barra), nunca ':V' \u2014 resolva via tia_catalog. Regra: a vers\xE3o de firmware do PROJETO deve ser \u2264 a do DEVICE f\xEDsico (project FW \u2264 device FW). dryRun (Gd11) devolve o plano sem mutar. Mapeia POST /plcs/{plc}/device/changeversion. Classe M-off.",
31571
+ title: "TIA \u2014 change CPU firmware (in-place)",
31572
+ description: "Changes the CPU's FIRMWARE version IN-PLACE (wraps DeviceItem.ChangeType), PRESERVING the program \u2014 an alternative to delete+recreate (enables 'auto-FW-match'). Guard Gd5: the typeIdentifier follows 'OrderNumber:<MLFB>/V<fw>' with '/V' (slash), never ':V' \u2014 resolve via tia_catalog. Rule: the PROJECT's firmware version must be \u2264 the physical DEVICE's (project FW \u2264 device FW). dryRun (Gd11) returns the plan without mutating. Maps to POST /plcs/{plc}/device/changeversion. Class M-off.",
31573
31573
  inputSchema: {
31574
- plc: external_exports.string().describe("nome do CLP (CPU) cujo firmware ser\xE1 trocado"),
31575
- typeIdentifier: external_exports.string().describe('OrderNumber:<MLFB>/V<fw> do firmware destino (Gd5; resolva via tia_catalog) \u2014 ex.: "OrderNumber:6ES7 214-1HG40-0XB0/V4.4"'),
31574
+ plc: external_exports.string().describe("name of the PLC (CPU) whose firmware will be changed"),
31575
+ typeIdentifier: external_exports.string().describe('OrderNumber:<MLFB>/V<fw> of the target firmware (Gd5; resolve via tia_catalog) \u2014 e.g.: "OrderNumber:6ES7 214-1HG40-0XB0/V4.4"'),
31576
31576
  ...dryRunField
31577
31577
  }
31578
31578
  },
@@ -31581,14 +31581,14 @@ function registerAuthoringTools(server2) {
31581
31581
  server2.registerTool(
31582
31582
  "tia_device_plug",
31583
31583
  {
31584
- title: "TIA \u2014 plugar m\xF3dulo",
31585
- description: "Pluga um m\xF3dulo num device existente por typeIdentifier (Gd5: '/V', nunca ':V'; resolva via tia_catalog). Mapeia POST /devices/{device}/plug. M-off.",
31584
+ title: "TIA \u2014 plug module",
31585
+ description: "Plugs a module into an existing device by typeIdentifier (Gd5: '/V', never ':V'; resolve via tia_catalog). Maps to POST /devices/{device}/plug. M-off.",
31586
31586
  inputSchema: {
31587
- device: external_exports.string().describe("nome do device alvo"),
31588
- typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw> do m\xF3dulo (Gd5)"),
31589
- name: external_exports.string().optional().describe("nome do m\xF3dulo plugado"),
31590
- position: external_exports.number().int().optional().describe("slot/posi\xE7\xE3o (default: pr\xF3xima livre)"),
31591
- host: external_exports.string().optional().describe("device item host (rack/rail), se aplic\xE1vel"),
31587
+ device: external_exports.string().describe("target device name"),
31588
+ typeIdentifier: external_exports.string().describe("OrderNumber:<MLFB>/V<fw> of the module (Gd5)"),
31589
+ name: external_exports.string().optional().describe("name of the plugged module"),
31590
+ position: external_exports.number().int().optional().describe("slot/position (default: next free)"),
31591
+ host: external_exports.string().optional().describe("device item host (rack/rail), if applicable"),
31592
31592
  ...dryRunField
31593
31593
  }
31594
31594
  },
@@ -31597,367 +31597,367 @@ function registerAuthoringTools(server2) {
31597
31597
  if (bad) return guardError("Gd5", bad, { typeIdentifier });
31598
31598
  return mutate("POST", `/devices/${seg2(device)}/plug`, jsonBody2({ typeIdentifier, name, position, host }), {
31599
31599
  dryRun,
31600
- summary: `plugar "${name ?? typeIdentifier}" em ${device}`
31600
+ summary: `plug "${name ?? typeIdentifier}" into ${device}`
31601
31601
  });
31602
31602
  }
31603
31603
  );
31604
31604
  server2.registerTool(
31605
31605
  "tia_device_unplug",
31606
31606
  {
31607
- title: "TIA \u2014 desplugar m\xF3dulo",
31608
- description: "Remove um device item (m\xF3dulo). Mapeia DELETE /devices/{device}/items/{item}. M-off.",
31607
+ title: "TIA \u2014 unplug module",
31608
+ description: "Removes a device item (module). Maps to DELETE /devices/{device}/items/{item}. M-off.",
31609
31609
  inputSchema: {
31610
- device: external_exports.string().describe("nome do device"),
31611
- item: external_exports.string().describe("nome do device item a remover"),
31610
+ device: external_exports.string().describe("device name"),
31611
+ item: external_exports.string().describe("name of the device item to remove"),
31612
31612
  ...dryRunField
31613
31613
  }
31614
31614
  },
31615
- async ({ device, item, dryRun }) => mutate("DELETE", `/devices/${seg2(device)}/items/${seg2(item)}`, void 0, { dryRun, summary: `desplugar ${item} de ${device}` })
31615
+ async ({ device, item, dryRun }) => mutate("DELETE", `/devices/${seg2(device)}/items/${seg2(item)}`, void 0, { dryRun, summary: `unplug ${item} from ${device}` })
31616
31616
  );
31617
31617
  server2.registerTool(
31618
31618
  "tia_device_group_create",
31619
31619
  {
31620
- title: "TIA \u2014 criar grupo de devices",
31621
- description: "Cria um grupo de devices. Mapeia POST /devicegroups. M-off.",
31622
- inputSchema: { name: external_exports.string().describe("nome do grupo"), ...dryRunField }
31620
+ title: "TIA \u2014 create device group",
31621
+ description: "Creates a device group. Maps to POST /devicegroups. M-off.",
31622
+ inputSchema: { name: external_exports.string().describe("group name"), ...dryRunField }
31623
31623
  },
31624
- async ({ name, dryRun }) => mutate("POST", "/devicegroups", jsonBody2({ name }), { dryRun, summary: `criar grupo de devices ${name}` })
31624
+ async ({ name, dryRun }) => mutate("POST", "/devicegroups", jsonBody2({ name }), { dryRun, summary: `create device group ${name}` })
31625
31625
  );
31626
31626
  server2.registerTool(
31627
31627
  "tia_subnet_create",
31628
31628
  {
31629
- title: "TIA \u2014 criar subnet",
31630
- description: "Cria uma subnet por typeIdentifier (Gd5: '/V', nunca ':V'). Mapeia POST /subnets. M-off.",
31629
+ title: "TIA \u2014 create subnet",
31630
+ description: "Creates a subnet by typeIdentifier (Gd5: '/V', never ':V'). Maps to POST /subnets. M-off.",
31631
31631
  inputSchema: {
31632
- typeIdentifier: external_exports.string().describe("typeIdentifier da subnet (Gd5)"),
31633
- name: external_exports.string().optional().describe("nome da subnet"),
31632
+ typeIdentifier: external_exports.string().describe("subnet typeIdentifier (Gd5)"),
31633
+ name: external_exports.string().optional().describe("subnet name"),
31634
31634
  ...dryRunField
31635
31635
  }
31636
31636
  },
31637
31637
  async ({ typeIdentifier, name, dryRun }) => {
31638
31638
  const bad = gd5Violation(typeIdentifier);
31639
31639
  if (bad) return guardError("Gd5", bad, { typeIdentifier });
31640
- return mutate("POST", "/subnets", jsonBody2({ typeIdentifier, name }), { dryRun, summary: `criar subnet ${name ?? typeIdentifier}` });
31640
+ return mutate("POST", "/subnets", jsonBody2({ typeIdentifier, name }), { dryRun, summary: `create subnet ${name ?? typeIdentifier}` });
31641
31641
  }
31642
31642
  );
31643
31643
  server2.registerTool(
31644
31644
  "tia_network_connect",
31645
31645
  {
31646
- title: "TIA \u2014 conectar \xE0 subnet",
31647
- description: "Conecta a interface de um device a uma subnet (com IP; opcionalmente cria IO-system). CPU e IO-devices DEVEM ficar na MESMA subnet. Mapeia POST /network/connect. M-off.",
31646
+ title: "TIA \u2014 connect to subnet",
31647
+ description: "Connects a device's interface to a subnet (with IP; optionally creates an IO-system). CPU and IO-devices MUST be on the SAME subnet. Maps to POST /network/connect. M-off.",
31648
31648
  inputSchema: {
31649
- device: external_exports.string().describe("nome do device"),
31650
- subnet: external_exports.string().describe("nome da subnet"),
31651
- ip: external_exports.string().optional().describe("endere\xE7o IP (ex.: 192.168.0.1)"),
31652
- createIoSystem: external_exports.boolean().optional().describe("criar um IO-system nesta conex\xE3o"),
31653
- ioSystemName: external_exports.string().optional().describe("nome do IO-system (se createIoSystem)"),
31649
+ device: external_exports.string().describe("device name"),
31650
+ subnet: external_exports.string().describe("subnet name"),
31651
+ ip: external_exports.string().optional().describe("IP address (e.g., 192.168.0.1)"),
31652
+ createIoSystem: external_exports.boolean().optional().describe("create an IO-system on this connection"),
31653
+ ioSystemName: external_exports.string().optional().describe("IO-system name (if createIoSystem)"),
31654
31654
  ...dryRunField
31655
31655
  }
31656
31656
  },
31657
31657
  async ({ device, subnet, ip, createIoSystem, ioSystemName, dryRun }) => mutate("POST", "/network/connect", jsonBody2({ device, subnet, ip, createIoSystem, ioSystemName }), {
31658
31658
  dryRun,
31659
- summary: `conectar ${device} \xE0 subnet ${subnet}${ip ? " @" + ip : ""}`
31659
+ summary: `connect ${device} to subnet ${subnet}${ip ? " @" + ip : ""}`
31660
31660
  })
31661
31661
  );
31662
31662
  server2.registerTool(
31663
31663
  "tia_network_address",
31664
31664
  {
31665
- title: "TIA \u2014 definir endere\xE7o de rede",
31666
- description: "Define atributos de endere\xE7o (IP/m\xE1scara/etc.) da interface de um device. Mapeia POST /network/address. M-off.",
31665
+ title: "TIA \u2014 set network address",
31666
+ description: "Sets address attributes (IP/mask/etc.) of a device's interface. Maps to POST /network/address. M-off.",
31667
31667
  inputSchema: {
31668
- device: external_exports.string().describe("nome do device"),
31669
- attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("atributos de endere\xE7o (ex.: { Address: '192.168.0.1' })"),
31668
+ device: external_exports.string().describe("device name"),
31669
+ attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("address attributes (e.g., { Address: '192.168.0.1' })"),
31670
31670
  ...dryRunField
31671
31671
  }
31672
31672
  },
31673
- async ({ device, attributes, dryRun }) => mutate("POST", "/network/address", jsonBody2({ device, attributes }), { dryRun, summary: `endere\xE7ar ${device}` })
31673
+ async ({ device, attributes, dryRun }) => mutate("POST", "/network/address", jsonBody2({ device, attributes }), { dryRun, summary: `address ${device}` })
31674
31674
  );
31675
31675
  server2.registerTool(
31676
31676
  "tia_network_disconnect",
31677
31677
  {
31678
- title: "TIA \u2014 desconectar da subnet",
31679
- description: "Desconecta a interface de um device da subnet. Mapeia POST /network/disconnect. M-off.",
31680
- inputSchema: { device: external_exports.string().describe("nome do device"), ...dryRunField }
31678
+ title: "TIA \u2014 disconnect from subnet",
31679
+ description: "Disconnects a device's interface from the subnet. Maps to POST /network/disconnect. M-off.",
31680
+ inputSchema: { device: external_exports.string().describe("device name"), ...dryRunField }
31681
31681
  },
31682
- async ({ device, dryRun }) => mutate("POST", "/network/disconnect", jsonBody2({ device }), { dryRun, summary: `desconectar ${device} da subnet` })
31682
+ async ({ device, dryRun }) => mutate("POST", "/network/disconnect", jsonBody2({ device }), { dryRun, summary: `disconnect ${device} from the subnet` })
31683
31683
  );
31684
31684
  server2.registerTool(
31685
31685
  "tia_tagtable_create",
31686
31686
  {
31687
- title: "TIA \u2014 criar tabela de tags",
31688
- description: "Cria uma tabela de tags num CLP. Mapeia POST /plcs/{plc}/tagtables. M-off.",
31689
- inputSchema: { plc: external_exports.string().describe("nome do CLP"), name: external_exports.string().describe("nome da tabela"), ...dryRunField }
31687
+ title: "TIA \u2014 create tag table",
31688
+ description: "Creates a tag table on a PLC. Maps to POST /plcs/{plc}/tagtables. M-off.",
31689
+ inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("table name"), ...dryRunField }
31690
31690
  },
31691
- async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tagtables`, jsonBody2({ name }), { dryRun, summary: `criar tabela de tags ${name} em ${plc}` })
31691
+ async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tagtables`, jsonBody2({ name }), { dryRun, summary: `create tag table ${name} on ${plc}` })
31692
31692
  );
31693
31693
  server2.registerTool(
31694
31694
  "tia_tag_create",
31695
31695
  {
31696
- title: "TIA \u2014 criar tag",
31697
- description: "Cria uma tag numa tabela. Mapeia POST /plcs/{plc}/tags. M-off.",
31696
+ title: "TIA \u2014 create tag",
31697
+ description: "Creates a tag in a table. Maps to POST /plcs/{plc}/tags. M-off.",
31698
31698
  inputSchema: {
31699
- plc: external_exports.string().describe("nome do CLP"),
31700
- table: external_exports.string().optional().describe("tabela de tags (default: a padr\xE3o)"),
31701
- name: external_exports.string().describe("nome da tag"),
31702
- dataType: external_exports.string().describe("tipo de dado (ex.: Bool, Int, Word)"),
31703
- address: external_exports.string().optional().describe("endere\xE7o (ex.: %I0.0, %M10.0)"),
31699
+ plc: external_exports.string().describe("PLC name"),
31700
+ table: external_exports.string().optional().describe("tag table (default: the standard one)"),
31701
+ name: external_exports.string().describe("tag name"),
31702
+ dataType: external_exports.string().describe("data type (e.g., Bool, Int, Word)"),
31703
+ address: external_exports.string().optional().describe("address (e.g., %I0.0, %M10.0)"),
31704
31704
  ...dryRunField
31705
31705
  }
31706
31706
  },
31707
- async ({ plc, table, name, dataType, address, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tags`, jsonBody2({ table, name, dataType, address }), { dryRun, summary: `criar tag ${name}:${dataType} em ${plc}` })
31707
+ async ({ plc, table, name, dataType, address, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/tags`, jsonBody2({ table, name, dataType, address }), { dryRun, summary: `create tag ${name}:${dataType} on ${plc}` })
31708
31708
  );
31709
31709
  server2.registerTool(
31710
31710
  "tia_tag_delete",
31711
31711
  {
31712
- title: "TIA \u2014 excluir tag",
31713
- description: "Exclui uma tag de uma tabela. Mapeia DELETE /plcs/{plc}/tagtables/{table}/tags/{tag}. M-off.",
31712
+ title: "TIA \u2014 delete tag",
31713
+ description: "Deletes a tag from a table. Maps to DELETE /plcs/{plc}/tagtables/{table}/tags/{tag}. M-off.",
31714
31714
  inputSchema: {
31715
- plc: external_exports.string().describe("nome do CLP"),
31716
- table: external_exports.string().describe("tabela de tags"),
31717
- tag: external_exports.string().describe("nome da tag"),
31715
+ plc: external_exports.string().describe("PLC name"),
31716
+ table: external_exports.string().describe("tag table"),
31717
+ tag: external_exports.string().describe("tag name"),
31718
31718
  ...dryRunField
31719
31719
  }
31720
31720
  },
31721
- async ({ plc, table, tag, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/tagtables/${seg2(table)}/tags/${seg2(tag)}`, void 0, { dryRun, summary: `excluir tag ${tag}` })
31721
+ async ({ plc, table, tag, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/tagtables/${seg2(table)}/tags/${seg2(tag)}`, void 0, { dryRun, summary: `delete tag ${tag}` })
31722
31722
  );
31723
31723
  server2.registerTool(
31724
31724
  "tia_constant_create",
31725
31725
  {
31726
- title: "TIA \u2014 criar constante",
31727
- description: "Cria uma constante de usu\xE1rio numa tabela de tags. Mapeia POST /plcs/{plc}/constants. M-off.",
31726
+ title: "TIA \u2014 create constant",
31727
+ description: "Creates a user constant in a tag table. Maps to POST /plcs/{plc}/constants. M-off.",
31728
31728
  inputSchema: {
31729
- plc: external_exports.string().describe("nome do CLP"),
31730
- table: external_exports.string().optional().describe("tabela de tags (default: a padr\xE3o)"),
31731
- name: external_exports.string().describe("nome da constante"),
31732
- dataType: external_exports.string().describe("tipo de dado"),
31733
- value: external_exports.string().describe("valor"),
31729
+ plc: external_exports.string().describe("PLC name"),
31730
+ table: external_exports.string().optional().describe("tag table (default: the standard one)"),
31731
+ name: external_exports.string().describe("constant name"),
31732
+ dataType: external_exports.string().describe("data type"),
31733
+ value: external_exports.string().describe("value"),
31734
31734
  ...dryRunField
31735
31735
  }
31736
31736
  },
31737
- async ({ plc, table, name, dataType, value, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/constants`, jsonBody2({ table, name, dataType, value }), { dryRun, summary: `criar constante ${name} em ${plc}` })
31737
+ async ({ plc, table, name, dataType, value, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/constants`, jsonBody2({ table, name, dataType, value }), { dryRun, summary: `create constant ${name} on ${plc}` })
31738
31738
  );
31739
31739
  server2.registerTool(
31740
31740
  "tia_fb_create",
31741
31741
  {
31742
- title: "TIA \u2014 criar FB",
31743
- description: "Cria um Function Block. Gd6: para L\xD3GICA use linguagem textual (SCL) via tia_source_put, ou gr\xE1fica (LAD/FBD) via tia_import_xml. Mapeia POST /plcs/{plc}/fbs. M-off.",
31742
+ title: "TIA \u2014 create FB",
31743
+ description: "Creates a Function Block. Gd6: for LOGIC use a textual language (SCL) via tia_source_put, or graphical (LAD/FBD) via tia_import_xml. Maps to POST /plcs/{plc}/fbs. M-off.",
31744
31744
  inputSchema: {
31745
- plc: external_exports.string().describe("nome do CLP"),
31746
- name: external_exports.string().describe("nome do FB"),
31747
- language: external_exports.string().optional().describe("linguagem (ex.: SCL, LAD, FBD; default do projeto)"),
31748
- autoNumber: external_exports.boolean().optional().describe("numera\xE7\xE3o autom\xE1tica (default true; omita 'number' para auto)"),
31749
- number: external_exports.number().int().optional().describe("n\xFAmero do bloco \u22651 (s\xF3 com autoNumber=false); omitido ou 0 \u21D2 numera\xE7\xE3o autom\xE1tica"),
31750
- group: external_exports.string().optional().describe("grupo de blocos de destino"),
31745
+ plc: external_exports.string().describe("PLC name"),
31746
+ name: external_exports.string().describe("FB name"),
31747
+ language: external_exports.string().optional().describe("language (e.g., SCL, LAD, FBD; project default)"),
31748
+ autoNumber: external_exports.boolean().optional().describe("automatic numbering (default true; omit 'number' for auto)"),
31749
+ number: external_exports.number().int().optional().describe("block number \u22651 (only with autoNumber=false); omitted or 0 \u21D2 automatic numbering"),
31750
+ group: external_exports.string().optional().describe("target block group"),
31751
31751
  ...dryRunField
31752
31752
  }
31753
31753
  },
31754
- async ({ plc, name, language, autoNumber, number: number4, group, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/fbs`, jsonBody2({ name, language, autoNumber, number: number4, group }), { dryRun, summary: `criar FB ${name} em ${plc}` })
31754
+ async ({ plc, name, language, autoNumber, number: number4, group, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/fbs`, jsonBody2({ name, language, autoNumber, number: number4, group }), { dryRun, summary: `create FB ${name} on ${plc}` })
31755
31755
  );
31756
31756
  server2.registerTool(
31757
31757
  "tia_instancedb_create",
31758
31758
  {
31759
- title: "TIA \u2014 criar DB de inst\xE2ncia",
31760
- description: "Cria um DB de inst\xE2ncia de um FB. Mapeia POST /plcs/{plc}/instancedbs. M-off.",
31759
+ title: "TIA \u2014 create instance DB",
31760
+ description: "Creates an instance DB of an FB. Maps to POST /plcs/{plc}/instancedbs. M-off.",
31761
31761
  inputSchema: {
31762
- plc: external_exports.string().describe("nome do CLP"),
31763
- name: external_exports.string().describe("nome do DB de inst\xE2ncia"),
31764
- instanceOf: external_exports.string().describe("nome do FB do qual instanciar"),
31765
- autoNumber: external_exports.boolean().optional().describe("numera\xE7\xE3o autom\xE1tica (default true; omita 'number' para auto)"),
31766
- number: external_exports.number().int().optional().describe("n\xFAmero do bloco \u22651 (s\xF3 com autoNumber=false); omitido ou 0 \u21D2 numera\xE7\xE3o autom\xE1tica"),
31767
- group: external_exports.string().optional().describe("grupo de blocos de destino"),
31762
+ plc: external_exports.string().describe("PLC name"),
31763
+ name: external_exports.string().describe("instance DB name"),
31764
+ instanceOf: external_exports.string().describe("name of the FB to instantiate from"),
31765
+ autoNumber: external_exports.boolean().optional().describe("automatic numbering (default true; omit 'number' for auto)"),
31766
+ number: external_exports.number().int().optional().describe("block number \u22651 (only with autoNumber=false); omitted or 0 \u21D2 automatic numbering"),
31767
+ group: external_exports.string().optional().describe("target block group"),
31768
31768
  ...dryRunField
31769
31769
  }
31770
31770
  },
31771
31771
  async ({ plc, name, instanceOf, autoNumber, number: number4, group, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/instancedbs`, jsonBody2({ name, instanceOf, autoNumber, number: number4, group }), {
31772
31772
  dryRun,
31773
- summary: `criar iDB ${name} de ${instanceOf} em ${plc}`
31773
+ summary: `create iDB ${name} from ${instanceOf} on ${plc}`
31774
31774
  })
31775
31775
  );
31776
31776
  server2.registerTool(
31777
31777
  "tia_block_delete",
31778
31778
  {
31779
- title: "TIA \u2014 excluir bloco",
31780
- description: "Exclui um bloco. Mapeia DELETE /plcs/{plc}/blocks/{block}. M-off.",
31781
- inputSchema: { plc: external_exports.string().describe("nome do CLP"), block: external_exports.string().describe("nome do bloco"), ...dryRunField }
31779
+ title: "TIA \u2014 delete block",
31780
+ description: "Deletes a block. Maps to DELETE /plcs/{plc}/blocks/{block}. M-off.",
31781
+ inputSchema: { plc: external_exports.string().describe("PLC name"), block: external_exports.string().describe("block name"), ...dryRunField }
31782
31782
  },
31783
- async ({ plc, block, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/blocks/${seg2(block)}`, void 0, { dryRun, summary: `excluir bloco ${block}` })
31783
+ async ({ plc, block, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/blocks/${seg2(block)}`, void 0, { dryRun, summary: `delete block ${block}` })
31784
31784
  );
31785
31785
  server2.registerTool(
31786
31786
  "tia_block_set_attribute",
31787
31787
  {
31788
- title: "TIA \u2014 definir atributo de bloco",
31789
- description: "Define um atributo de um bloco (ex.: acesso otimizado). Mapeia POST /plcs/{plc}/blocks/{block}/attributes. M-off.",
31788
+ title: "TIA \u2014 set block attribute",
31789
+ description: "Sets an attribute of a block (e.g., optimized access). Maps to POST /plcs/{plc}/blocks/{block}/attributes. M-off.",
31790
31790
  inputSchema: {
31791
- plc: external_exports.string().describe("nome do CLP"),
31792
- block: external_exports.string().describe("nome do bloco"),
31793
- name: external_exports.string().describe("nome do atributo"),
31794
- value: external_exports.unknown().describe("valor do atributo"),
31791
+ plc: external_exports.string().describe("PLC name"),
31792
+ block: external_exports.string().describe("block name"),
31793
+ name: external_exports.string().describe("attribute name"),
31794
+ value: external_exports.unknown().describe("attribute value"),
31795
31795
  ...dryRunField
31796
31796
  }
31797
31797
  },
31798
31798
  async ({ plc, block, name, value, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/blocks/${seg2(block)}/attributes`, jsonBody2({ name, value }), {
31799
31799
  dryRun,
31800
- summary: `set ${name} em ${block}`
31800
+ summary: `set ${name} on ${block}`
31801
31801
  })
31802
31802
  );
31803
31803
  server2.registerTool(
31804
31804
  "tia_block_group_create",
31805
31805
  {
31806
- title: "TIA \u2014 criar grupo de blocos",
31807
- description: "Cria um grupo de blocos. Mapeia POST /plcs/{plc}/blockgroups. M-off.",
31808
- inputSchema: { plc: external_exports.string().describe("nome do CLP"), name: external_exports.string().describe("nome do grupo"), ...dryRunField }
31806
+ title: "TIA \u2014 create block group",
31807
+ description: "Creates a block group. Maps to POST /plcs/{plc}/blockgroups. M-off.",
31808
+ inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("group name"), ...dryRunField }
31809
31809
  },
31810
- async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/blockgroups`, jsonBody2({ name }), { dryRun, summary: `criar grupo de blocos ${name}` })
31810
+ async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/blockgroups`, jsonBody2({ name }), { dryRun, summary: `create block group ${name}` })
31811
31811
  );
31812
31812
  server2.registerTool(
31813
31813
  "tia_type_group_create",
31814
31814
  {
31815
- title: "TIA \u2014 criar grupo de tipos",
31816
- description: "Cria um grupo de tipos (UDTs). Mapeia POST /plcs/{plc}/typegroups. M-off.",
31817
- inputSchema: { plc: external_exports.string().describe("nome do CLP"), name: external_exports.string().describe("nome do grupo"), ...dryRunField }
31815
+ title: "TIA \u2014 create type group",
31816
+ description: "Creates a type group (UDTs). Maps to POST /plcs/{plc}/typegroups. M-off.",
31817
+ inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("group name"), ...dryRunField }
31818
31818
  },
31819
- async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/typegroups`, jsonBody2({ name }), { dryRun, summary: `criar grupo de tipos ${name}` })
31819
+ async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/typegroups`, jsonBody2({ name }), { dryRun, summary: `create type group ${name}` })
31820
31820
  );
31821
31821
  server2.registerTool(
31822
31822
  "tia_type_delete",
31823
31823
  {
31824
- title: "TIA \u2014 excluir tipo",
31825
- description: "Exclui um tipo (UDT). Mapeia DELETE /plcs/{plc}/types/{type}. M-off.",
31826
- inputSchema: { plc: external_exports.string().describe("nome do CLP"), type: external_exports.string().describe("nome do tipo"), ...dryRunField }
31824
+ title: "TIA \u2014 delete type",
31825
+ description: "Deletes a type (UDT). Maps to DELETE /plcs/{plc}/types/{type}. M-off.",
31826
+ inputSchema: { plc: external_exports.string().describe("PLC name"), type: external_exports.string().describe("type name"), ...dryRunField }
31827
31827
  },
31828
- async ({ plc, type, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/types/${seg2(type)}`, void 0, { dryRun, summary: `excluir tipo ${type}` })
31828
+ async ({ plc, type, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/types/${seg2(type)}`, void 0, { dryRun, summary: `delete type ${type}` })
31829
31829
  );
31830
31830
  server2.registerTool(
31831
31831
  "tia_source_put",
31832
31832
  {
31833
- title: "TIA \u2014 escrever/compilar fonte SCL",
31834
- description: "Escreve um bloco a partir de fonte SCL textual e (opcional) compila. Gd6: use ISTO para linguagem TEXTUAL (SCL/STL); para gr\xE1fica (LAD/FBD/GRAPH) use tia_import_xml. Mapeia POST /plcs/{plc}/source. M-off.",
31833
+ title: "TIA \u2014 write/compile SCL source",
31834
+ description: "Writes a block from textual SCL source and (optionally) compiles it. Gd6: use THIS for TEXTUAL language (SCL/STL); for graphical (LAD/FBD/GRAPH) use tia_import_xml. Maps to POST /plcs/{plc}/source. M-off.",
31835
31835
  inputSchema: {
31836
- plc: external_exports.string().describe("nome do CLP"),
31837
- name: external_exports.string().describe("nome do bloco/fonte"),
31838
- code: external_exports.string().describe("c\xF3digo-fonte SCL"),
31839
- compile: external_exports.boolean().optional().describe("compilar ap\xF3s gerar (default false)"),
31836
+ plc: external_exports.string().describe("PLC name"),
31837
+ name: external_exports.string().describe("block/source name"),
31838
+ code: external_exports.string().describe("SCL source code"),
31839
+ compile: external_exports.boolean().optional().describe("compile after generating (default false)"),
31840
31840
  ...dryRunField
31841
31841
  }
31842
31842
  },
31843
- async ({ plc, name, code, compile, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/source`, jsonBody2({ name, code, compile }), { dryRun, summary: `escrever SCL ${name} em ${plc}` })
31843
+ async ({ plc, name, code, compile, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/source`, jsonBody2({ name, code, compile }), { dryRun, summary: `write SCL ${name} on ${plc}` })
31844
31844
  );
31845
31845
  server2.registerTool(
31846
31846
  "tia_import_xml",
31847
31847
  {
31848
- title: "TIA \u2014 importar bloco (SimaticML XML)",
31849
- description: "Importa um bloco em SimaticML XML (a \xFAnica via para LAD/FBD/GRAPH \u2014 Gd6). Gd7: a vers\xE3o do SimaticML deve casar com o V21. Importe UDTs ANTES (tia_types_import). Aceita `xml` no corpo ou `path` no host. Mapeia POST /plcs/{plc}/import. M-off.",
31848
+ title: "TIA \u2014 import block (SimaticML XML)",
31849
+ description: "Imports a block in SimaticML XML (the only path for LAD/FBD/GRAPH \u2014 Gd6). Gd7: the SimaticML version must match V21. Import UDTs FIRST (tia_types_import). Accepts `xml` in the body or `path` on the host. Maps to POST /plcs/{plc}/import. M-off.",
31850
31850
  inputSchema: {
31851
- plc: external_exports.string().describe("nome do CLP"),
31852
- xml: external_exports.string().optional().describe("conte\xFAdo SimaticML XML (alternativa a path)"),
31853
- path: external_exports.string().optional().describe("caminho do .xml no host do serve (alternativa a xml)"),
31854
- override: external_exports.boolean().optional().describe("sobrescrever se j\xE1 existir (default true)"),
31851
+ plc: external_exports.string().describe("PLC name"),
31852
+ xml: external_exports.string().optional().describe("SimaticML XML content (alternative to path)"),
31853
+ path: external_exports.string().optional().describe("path to the .xml on the serve host (alternative to xml)"),
31854
+ override: external_exports.boolean().optional().describe("overwrite if it already exists (default true)"),
31855
31855
  ...dryRunField
31856
31856
  }
31857
31857
  },
31858
- async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `importar XML em ${plc}` })
31858
+ async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `import XML on ${plc}` })
31859
31859
  );
31860
31860
  server2.registerTool(
31861
31861
  "tia_types_import",
31862
31862
  {
31863
- title: "TIA \u2014 importar tipo/UDT (SimaticML XML)",
31864
- description: "Importa um UDT em SimaticML XML. Importe os UDTs ANTES dos blocos que os usam (Gd6). Mapeia POST /plcs/{plc}/types/import. M-off.",
31863
+ title: "TIA \u2014 import type/UDT (SimaticML XML)",
31864
+ description: "Imports a UDT in SimaticML XML. Import UDTs BEFORE the blocks that use them (Gd6). Maps to POST /plcs/{plc}/types/import. M-off.",
31865
31865
  inputSchema: {
31866
- plc: external_exports.string().describe("nome do CLP"),
31867
- xml: external_exports.string().optional().describe("conte\xFAdo SimaticML XML do UDT (alternativa a path)"),
31868
- path: external_exports.string().optional().describe("caminho do .xml no host (alternativa a xml)"),
31869
- override: external_exports.boolean().optional().describe("sobrescrever se j\xE1 existir (default true)"),
31866
+ plc: external_exports.string().describe("PLC name"),
31867
+ xml: external_exports.string().optional().describe("SimaticML XML content of the UDT (alternative to path)"),
31868
+ path: external_exports.string().optional().describe("path to the .xml on the host (alternative to xml)"),
31869
+ override: external_exports.boolean().optional().describe("overwrite if it already exists (default true)"),
31870
31870
  ...dryRunField
31871
31871
  }
31872
31872
  },
31873
- async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/types/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `importar UDT em ${plc}` })
31873
+ async ({ plc, xml, path, override, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/types/import`, jsonBody2({ xml, path, override }), { dryRun, summary: `import UDT on ${plc}` })
31874
31874
  );
31875
31875
  server2.registerTool(
31876
31876
  "tia_export_xml",
31877
31877
  {
31878
- title: "TIA \u2014 exportar blocos/tipos (SimaticML XML)",
31879
- description: "Exporta blocos e tipos do CLP para arquivos SimaticML XML num diret\xF3rio (projeto-como-c\xF3digo). Mapeia POST /plcs/{plc}/export. M-off.",
31878
+ title: "TIA \u2014 export blocks/types (SimaticML XML)",
31879
+ description: "Exports the PLC's blocks and types to SimaticML XML files in a directory (project-as-code). Maps to POST /plcs/{plc}/export. M-off.",
31880
31880
  inputSchema: {
31881
- plc: external_exports.string().describe("nome do CLP"),
31882
- directory: external_exports.string().describe("diret\xF3rio de destino no host do serve"),
31881
+ plc: external_exports.string().describe("PLC name"),
31882
+ directory: external_exports.string().describe("target directory on the serve host"),
31883
31883
  ...dryRunField
31884
31884
  }
31885
31885
  },
31886
- async ({ plc, directory, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/export`, jsonBody2({ directory }), { dryRun, summary: `exportar XML de ${plc} para ${directory}` })
31886
+ async ({ plc, directory, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/export`, jsonBody2({ directory }), { dryRun, summary: `export XML from ${plc} to ${directory}` })
31887
31887
  );
31888
31888
  server2.registerTool(
31889
31889
  "tia_watchtable_create",
31890
31890
  {
31891
- title: "TIA \u2014 criar watch table",
31892
- description: "Cria uma tabela de observa\xE7\xE3o (watch table). Mapeia POST /plcs/{plc}/watchtables. M-off.",
31893
- inputSchema: { plc: external_exports.string().describe("nome do CLP"), name: external_exports.string().describe("nome da watch table"), ...dryRunField }
31891
+ title: "TIA \u2014 create watch table",
31892
+ description: "Creates a watch table. Maps to POST /plcs/{plc}/watchtables. M-off.",
31893
+ inputSchema: { plc: external_exports.string().describe("PLC name"), name: external_exports.string().describe("watch table name"), ...dryRunField }
31894
31894
  },
31895
- async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/watchtables`, jsonBody2({ name }), { dryRun, summary: `criar watch table ${name}` })
31895
+ async ({ plc, name, dryRun }) => mutate("POST", `/plcs/${seg2(plc)}/watchtables`, jsonBody2({ name }), { dryRun, summary: `create watch table ${name}` })
31896
31896
  );
31897
31897
  server2.registerTool(
31898
31898
  "tia_watchtable_delete",
31899
31899
  {
31900
- title: "TIA \u2014 excluir watch table",
31901
- description: "Exclui uma watch table. Mapeia DELETE /plcs/{plc}/watchtables/{wt}. M-off.",
31902
- inputSchema: { plc: external_exports.string().describe("nome do CLP"), watchtable: external_exports.string().describe("nome da watch table"), ...dryRunField }
31900
+ title: "TIA \u2014 delete watch table",
31901
+ description: "Deletes a watch table. Maps to DELETE /plcs/{plc}/watchtables/{wt}. M-off.",
31902
+ inputSchema: { plc: external_exports.string().describe("PLC name"), watchtable: external_exports.string().describe("watch table name"), ...dryRunField }
31903
31903
  },
31904
- async ({ plc, watchtable, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/watchtables/${seg2(watchtable)}`, void 0, { dryRun, summary: `excluir watch table ${watchtable}` })
31904
+ async ({ plc, watchtable, dryRun }) => mutate("DELETE", `/plcs/${seg2(plc)}/watchtables/${seg2(watchtable)}`, void 0, { dryRun, summary: `delete watch table ${watchtable}` })
31905
31905
  );
31906
31906
  server2.registerTool(
31907
31907
  "tia_obj_service",
31908
31908
  {
31909
- title: "TIA \u2014 adquirir servi\xE7o (GetService\u2192handle)",
31910
- description: "Adquire um servi\xE7o de um objeto por handle (GetService<T> gen\xE9rico) e retorna um HANDLE de servi\xE7o, para ent\xE3o invocar m\xE9todos via tia_obj_invoke. Ex.: PlcMasterSecretConfigurator.Protect \u2014 destrava CPU pelada (senha de dados confidenciais offline; gera o certificado). A aquisi\xE7\xE3o em si N\xC3O muta o projeto. Mapeia POST /obj/{handle}/service {type}. M-off.",
31909
+ title: "TIA \u2014 acquire service (GetService\u2192handle)",
31910
+ description: "Acquires a service from an object by handle (generic GetService<T>) and returns a service HANDLE, to then invoke methods via tia_obj_invoke. E.g.: PlcMasterSecretConfigurator.Protect \u2014 unlocks a bare CPU (offline confidential-data password; generates the certificate). The acquisition itself does NOT mutate the project. Maps to POST /obj/{handle}/service {type}. M-off.",
31911
31911
  inputSchema: {
31912
- handle: external_exports.string().describe("handle do objeto (ex.: o device item da CPU)"),
31913
- type: external_exports.string().describe("nome do tipo do servi\xE7o (ex.: Siemens.Engineering.HW.Features.PlcMasterSecretConfigurator)")
31912
+ handle: external_exports.string().describe("object handle (e.g., the CPU's device item)"),
31913
+ type: external_exports.string().describe("service type name (e.g., Siemens.Engineering.HW.Features.PlcMasterSecretConfigurator)")
31914
31914
  }
31915
31915
  },
31916
- async ({ handle, type }) => mutate("POST", `/obj/${seg2(handle)}/service`, jsonBody2({ type }), { summary: `adquirir servi\xE7o ${type} do obj ${handle}` })
31916
+ async ({ handle, type }) => mutate("POST", `/obj/${seg2(handle)}/service`, jsonBody2({ type }), { summary: `acquire service ${type} from obj ${handle}` })
31917
31917
  );
31918
31918
  server2.registerTool(
31919
31919
  "tia_obj_set_attributes",
31920
31920
  {
31921
- title: "TIA \u2014 set atributos (gen\xE9rico)",
31922
- description: "Define atributos de qualquer objeto do modelo por handle. Mapeia POST /obj/{handle}/attributes. M-off. Use os handles das tools obj read-only (M1).",
31921
+ title: "TIA \u2014 set attributes (generic)",
31922
+ description: "Sets attributes of any model object by handle. Maps to POST /obj/{handle}/attributes. M-off. Use the handles from the read-only obj tools (M1).",
31923
31923
  inputSchema: {
31924
- handle: external_exports.string().describe("handle do objeto (das tools tia_obj_* read-only)"),
31925
- attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("mapa nome\u2192valor de atributos a definir"),
31924
+ handle: external_exports.string().describe("object handle (from the read-only tia_obj_* tools)"),
31925
+ attributes: external_exports.record(external_exports.string(), external_exports.unknown()).describe("name\u2192value map of attributes to set"),
31926
31926
  ...dryRunField
31927
31927
  }
31928
31928
  },
31929
- async ({ handle, attributes, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/attributes`, jsonBody2({ ...attributes }), { dryRun, summary: `set atributos no obj ${handle}` })
31929
+ async ({ handle, attributes, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/attributes`, jsonBody2({ ...attributes }), { dryRun, summary: `set attributes on obj ${handle}` })
31930
31930
  );
31931
31931
  server2.registerTool(
31932
31932
  "tia_obj_invoke",
31933
31933
  {
31934
- title: "TIA \u2014 invocar m\xE9todo (gen\xE9rico)",
31935
- description: 'Invoca um m\xE9todo de um objeto do modelo por handle (args coeridos aos tipos; {"$handle":N} passa outro objeto). Mapeia POST /obj/{handle}/invoke. M-off. Poderoso \u2014 combina com tia_obj_info p/ ver a assinatura.',
31934
+ title: "TIA \u2014 invoke method (generic)",
31935
+ description: 'Invokes a method of a model object by handle (args coerced to the parameter types; {"$handle":N} passes another object). Maps to POST /obj/{handle}/invoke. M-off. Powerful \u2014 combine with tia_obj_info to see the signature.',
31936
31936
  inputSchema: {
31937
- handle: external_exports.string().describe("handle do objeto"),
31938
- name: external_exports.string().describe("nome do m\xE9todo a invocar"),
31939
- args: external_exports.array(external_exports.unknown()).optional().describe("argumentos posicionais (coeridos aos tipos do par\xE2metro)"),
31937
+ handle: external_exports.string().describe("object handle"),
31938
+ name: external_exports.string().describe("name of the method to invoke"),
31939
+ args: external_exports.array(external_exports.unknown()).optional().describe("positional arguments (coerced to the parameter types)"),
31940
31940
  ...dryRunField
31941
31941
  }
31942
31942
  },
31943
- async ({ handle, name, args, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/invoke`, jsonBody2({ name, args }), { dryRun, summary: `invoke ${name}() no obj ${handle}` })
31943
+ async ({ handle, name, args, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/invoke`, jsonBody2({ name, args }), { dryRun, summary: `invoke ${name}() on obj ${handle}` })
31944
31944
  );
31945
31945
  server2.registerTool(
31946
31946
  "tia_obj_create",
31947
31947
  {
31948
- title: "TIA \u2014 criar objeto (gen\xE9rico)",
31949
- description: "Cria um objeto numa composi\xE7\xE3o de um objeto pai por handle. Mapeia POST /obj/{handle}/create. M-off. Veja os tipos cri\xE1veis em tia_obj_creationinfos.",
31948
+ title: "TIA \u2014 create object (generic)",
31949
+ description: "Creates an object in a composition of a parent object by handle. Maps to POST /obj/{handle}/create. M-off. See the creatable types in tia_obj_creationinfos.",
31950
31950
  inputSchema: {
31951
- handle: external_exports.string().describe("handle do objeto pai"),
31952
- composition: external_exports.string().describe("nome da composi\xE7\xE3o (ex.: 'Blocks')"),
31953
- type: external_exports.string().describe("tipo a criar (Siemens type)"),
31954
- parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("par\xE2metros do construtor (nome\u2192valor)"),
31951
+ handle: external_exports.string().describe("parent object handle"),
31952
+ composition: external_exports.string().describe("composition name (e.g., 'Blocks')"),
31953
+ type: external_exports.string().describe("type to create (Siemens type)"),
31954
+ parameters: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("constructor parameters (name\u2192value)"),
31955
31955
  ...dryRunField
31956
31956
  }
31957
31957
  },
31958
31958
  async ({ handle, composition, type, parameters, dryRun }) => mutate("POST", `/obj/${seg2(handle)}/create`, jsonBody2({ composition, type, parameters }), {
31959
31959
  dryRun,
31960
- summary: `criar ${type} em ${composition} do obj ${handle}`
31960
+ summary: `create ${type} in ${composition} of obj ${handle}`
31961
31961
  })
31962
31962
  );
31963
31963
  }
@@ -31995,18 +31995,18 @@ function planHash(plan) {
31995
31995
  return (h >>> 0).toString(16).padStart(8, "0");
31996
31996
  }
31997
31997
  var GATE_INSTRUCTION = {
31998
- download_approval: "Um humano deve APROVAR o download: ele PARA a CPU f\xEDsica (StopAll), SOBRESCREVE dados de sistema e RELIGA a CPU. Revise o 'plan'. ATEN\xC7\xC3O: o serve atual AUTO-CONFIRMA esses di\xE1logos (backlog C# P0.5) \u2014 a aprova\xE7\xE3o aqui \xE9 a salvaguarda na camada do MCP.",
31999
- go_online: "Ir ONLINE conecta ao CLP F\xCDSICO pela rede. Confirme com um humano que \xE9 seguro conectar \xE0 m\xE1quina-alvo.",
32000
- net_scan: "Uma varredura de rede (accessible devices) sonda a rede local pela placa PG/PC. Confirme antes de varrer."
31998
+ download_approval: "A human must APPROVE the download: it STOPS the physical CPU (StopAll), OVERWRITES system data, and RESTARTS the CPU. Review the 'plan'. WARNING: the current serve AUTO-CONFIRMS these dialogs (C# backlog P0.5) \u2014 the approval here is the safeguard at the MCP layer.",
31999
+ go_online: "Going ONLINE connects to the PHYSICAL PLC over the network. Confirm with a human that it is safe to connect to the target machine.",
32000
+ net_scan: "A network scan (accessible devices) probes the local network via the PG/PC adapter. Confirm before scanning."
32001
32001
  };
32002
32002
  function gateHandoff(gate, ctx) {
32003
- const resume = gate === "download_approval" ? ["1. Revise o 'plan' (CPU, interface, op\xE7\xF5es).", "2. Confirme com o respons\xE1vel pela linha.", `3. Re-chame com approved:true e planHash:"${ctx.planHash}".`] : ["1. Confirme com um humano que \xE9 seguro.", "2. Re-chame a mesma tool com confirm:true."];
32003
+ const resume = gate === "download_approval" ? ["1. Review the 'plan' (CPU, interface, options).", "2. Confirm with the line's responsible person.", `3. Re-call with approved:true and planHash:"${ctx.planHash}".`] : ["1. Confirm with a human that it's safe.", "2. Re-call the same tool with confirm:true."];
32004
32004
  return textResult(
32005
32005
  {
32006
32006
  status: "requires_human_action",
32007
32007
  gate,
32008
- canDo: ctx.plc ? `${gate} em ${ctx.plc}` : gate,
32009
- youMustDo: GATE_INSTRUCTION[gate] ?? "Confirma\xE7\xE3o humana necess\xE1ria.",
32008
+ canDo: ctx.plc ? `${gate} on ${ctx.plc}` : gate,
32009
+ youMustDo: GATE_INSTRUCTION[gate] ?? "Human confirmation required.",
32010
32010
  plan: ctx.plan ?? null,
32011
32011
  planHash: ctx.planHash ?? null,
32012
32012
  nextSteps: resume
@@ -32020,7 +32020,7 @@ async function compileFlow(plc) {
32020
32020
  const d = data ?? {};
32021
32021
  const errors = typeof d.errors === "number" ? d.errors : null;
32022
32022
  const clean = errors !== null ? errors === 0 : d.state === "Success";
32023
- const nextHints = clean ? ["Compile LIMPO (Gd8: avisos n\xE3o bloqueiam). Pronto para download gated (tia_download) ou conex\xE3o S7."] : [`Compile com ${errors ?? "?"} ERRO(s) \u2014 corrija ANTES de download/S7 (Gd9 pro\xEDbe deploy n\xE3o-limpo). Veja 'messages' (\xE1rvore).`];
32023
+ const nextHints = clean ? ["Compile CLEAN (Gd8: warnings don't block). Ready for gated download (tia_download) or S7 connection."] : [`Compile with ${errors ?? "?"} ERROR(s) \u2014 fix BEFORE download/S7 (Gd9 forbids a non-clean deploy). See 'messages' (tree).`];
32024
32024
  return textResult({ ...d, verification: { compiled: clean ? "clean" : "error", errors, warnings: d.warnings ?? null }, nextHints });
32025
32025
  } catch (e) {
32026
32026
  return errorResult3(asTiaError(e));
@@ -32045,16 +32045,16 @@ async function downloadFlow(args) {
32045
32045
  gate: "download_approval",
32046
32046
  plan,
32047
32047
  planHash: hash2,
32048
- gd9: "PRECONDI\xC7\xC3O Gd9/Gd10: o projeto DEVE estar compile-limpo e consistente. Rode tia_compile e s\xF3 siga com errors=0.",
32048
+ gd9: "PRECONDITION Gd9/Gd10: the project MUST be compile-clean and consistent. Run tia_compile and only proceed with errors=0.",
32049
32049
  loadPreview: {
32050
32050
  willConfirm: [
32051
- "StopModules = StopAll \u2014 PARA a CPU f\xEDsica",
32052
- "OverwriteSystemData = Overwrite \u2014 sobrescreve dados de sistema",
32053
- "StartModules = StartModule \u2014 RELIGA a CPU ao final"
32051
+ "StopModules = StopAll \u2014 STOPS the physical CPU",
32052
+ "OverwriteSystemData = Overwrite \u2014 overwrites system data",
32053
+ "StartModules = StartModule \u2014 RESTARTS the CPU at the end"
32054
32054
  ],
32055
- note: "O Openness n\xE3o tem preview-sem-baixar; estas s\xE3o as sele\xE7\xF5es padr\xE3o dos delegates do serve. Ap\xF3s um download real, o resultado traz 'configurations' com o que foi de fato confirmado (auditoria \u2014 P0.5)."
32055
+ note: "Openness has no preview-without-downloading; these are the default selections of serve's delegates. After a real download, the result carries 'configurations' with what was actually confirmed (audit trail \u2014 P0.5)."
32056
32056
  },
32057
- note: "Plano validado. NADA foi baixado. Para aplicar: tia_download com approved:true e este planHash (ap\xF3s aprova\xE7\xE3o humana)."
32057
+ note: "Plan validated. NOTHING was downloaded. To apply: tia_download with approved:true and this planHash (after human approval)."
32058
32058
  },
32059
32059
  false
32060
32060
  );
@@ -32086,20 +32086,20 @@ function registerVerificationTools(server2) {
32086
32086
  server2.registerTool(
32087
32087
  "tia_compile",
32088
32088
  {
32089
- title: "TIA \u2014 compilar (verificador)",
32090
- description: "Compila o CLP e retorna a \xE1rvore de mensagens + um resumo de verifica\xE7\xE3o (Gd8: s\xF3 ERRO bloqueia, avisos n\xE3o) e nextHints. \xC9 o VERIFICADOR offline: compile limpo \xE9 precondi\xE7\xE3o (Gd9) para download/S7. Mapeia POST /plcs/{plc}/compile. M-off.",
32091
- inputSchema: { plc: external_exports.string().describe("nome do CLP") }
32089
+ title: "TIA \u2014 compile (verifier)",
32090
+ description: "Compiles the PLC and returns the message tree + a verification summary (Gd8: only ERROR blocks, warnings don't) and nextHints. This is the offline VERIFIER: a clean compile is a precondition (Gd9) for download/S7. Maps to POST /plcs/{plc}/compile. M-off.",
32091
+ inputSchema: { plc: external_exports.string().describe("PLC name") }
32092
32092
  },
32093
32093
  async ({ plc }) => compileFlow(plc)
32094
32094
  );
32095
32095
  server2.registerTool(
32096
32096
  "tia_connection_create",
32097
32097
  {
32098
- title: "TIA \u2014 criar conex\xE3o S7",
32099
- description: "Cria uma conex\xE3o S7 entre dois devices. Guard G2: exige \u22652 CPUs CONSISTENTES (compilam limpo) \u2014 CPU pelada falha. Em caso de erro, o 'details' do envelope traz o diagn\xF3stico (ou use tia_connections_diagnose). Mapeia POST /connections. M-off.",
32098
+ title: "TIA \u2014 create S7 connection",
32099
+ description: "Creates an S7 connection between two devices. Guard G2: requires \u22652 CONSISTENT CPUs (compile clean) \u2014 a bare CPU fails. On error, the envelope's 'details' carries the diagnostic (or use tia_connections_diagnose). Maps to POST /connections. M-off.",
32100
32100
  inputSchema: {
32101
- localDevice: external_exports.string().describe("device local"),
32102
- partnerDevice: external_exports.string().describe("device parceiro")
32101
+ localDevice: external_exports.string().describe("local device"),
32102
+ partnerDevice: external_exports.string().describe("partner device")
32103
32103
  }
32104
32104
  },
32105
32105
  async ({ localDevice, partnerDevice }) => send("POST", "/connections", jsonBody3({ localDevice, partnerDevice }))
@@ -32107,19 +32107,19 @@ function registerVerificationTools(server2) {
32107
32107
  server2.registerTool(
32108
32108
  "tia_download",
32109
32109
  {
32110
- title: "TIA \u2014 baixar para o CLP (GATE G3)",
32111
- description: "Baixa hardware/software para a CPU F\xCDSICA (PARA e RELIGA a CPU). GATE G3: N\xC3O baixa sem aprova\xE7\xE3o humana. Use dryRun:true para obter o plano + planHash (sem baixar); ent\xE3o, ap\xF3s um humano aprovar, chame com approved:true e o MESMO planHash. Precondi\xE7\xE3o Gd9: compile limpo (rode tia_compile). Descubra connectionMode/pcInterfaceName/targetInterfaceName via tia_accessible_devices. Mapeia POST /plcs/{plc}/download.",
32110
+ title: "TIA \u2014 download to the PLC (GATE G3)",
32111
+ description: "Downloads hardware/software to the PHYSICAL CPU (STOPS and RESTARTS the CPU). GATE G3: does NOT download without human approval. Use dryRun:true to get the plan + planHash (without downloading); then, after a human approves, call with approved:true and the SAME planHash. Precondition Gd9: clean compile (run tia_compile). Discover connectionMode/pcInterfaceName/targetInterfaceName via tia_accessible_devices. Maps to POST /plcs/{plc}/download.",
32112
32112
  inputSchema: {
32113
- plc: external_exports.string().describe("nome do CLP"),
32114
- connectionMode: external_exports.string().optional().describe('modo de conex\xE3o (ex.: "PN/IE") \u2014 nome LOCALIZADO do TIA'),
32115
- pcInterfaceName: external_exports.string().optional().describe("placa PG/PC (nome localizado)"),
32116
- pcInterfaceNumber: external_exports.number().int().optional().describe("n\xFAmero da placa (default 1)"),
32117
- targetInterfaceName: external_exports.string().optional().describe('interface alvo da CPU (ex.: "1 X1")'),
32118
- hardware: external_exports.boolean().optional().describe("baixar hardware (default false)"),
32119
- software: external_exports.boolean().optional().describe("baixar software (default true)"),
32120
- dryRun: external_exports.boolean().optional().describe("Gd11: retorna o plano + planHash SEM baixar"),
32121
- approved: external_exports.boolean().optional().describe("G3: s\xF3 true ap\xF3s APROVA\xC7\xC3O HUMANA expl\xEDcita"),
32122
- planHash: external_exports.string().optional().describe("G3: o planHash exato devolvido pelo dryRun (vincula a aprova\xE7\xE3o ao plano)")
32113
+ plc: external_exports.string().describe("PLC name"),
32114
+ connectionMode: external_exports.string().optional().describe(`connection mode (e.g., "PN/IE") \u2014 TIA's LOCALIZED name`),
32115
+ pcInterfaceName: external_exports.string().optional().describe("PG/PC adapter (localized name)"),
32116
+ pcInterfaceNumber: external_exports.number().int().optional().describe("adapter number (default 1)"),
32117
+ targetInterfaceName: external_exports.string().optional().describe('target CPU interface (e.g., "1 X1")'),
32118
+ hardware: external_exports.boolean().optional().describe("download hardware (default false)"),
32119
+ software: external_exports.boolean().optional().describe("download software (default true)"),
32120
+ dryRun: external_exports.boolean().optional().describe("Gd11: returns the plan + planHash WITHOUT downloading"),
32121
+ approved: external_exports.boolean().optional().describe("G3: only true after explicit HUMAN APPROVAL"),
32122
+ planHash: external_exports.string().optional().describe("G3: the exact planHash returned by dryRun (binds the approval to the plan)")
32123
32123
  }
32124
32124
  },
32125
32125
  async (args) => downloadFlow(args)
@@ -32127,15 +32127,15 @@ function registerVerificationTools(server2) {
32127
32127
  server2.registerTool(
32128
32128
  "tia_online",
32129
32129
  {
32130
- title: "TIA \u2014 ir online (GATE G4)",
32131
- description: "Conecta ONLINE ao CLP f\xEDsico. GATE G4: passe confirm:true (ap\xF3s um humano confirmar que \xE9 seguro conectar \xE0 m\xE1quina-alvo); sem isso, devolve um handoff. Mapeia POST /plcs/{plc}/online.",
32130
+ title: "TIA \u2014 go online (GATE G4)",
32131
+ description: "Connects ONLINE to the physical PLC. GATE G4: pass confirm:true (after a human confirms it's safe to connect to the target machine); without it, returns a handoff. Maps to POST /plcs/{plc}/online.",
32132
32132
  inputSchema: {
32133
- plc: external_exports.string().describe("nome do CLP"),
32134
- connectionMode: external_exports.string().optional().describe("modo de conex\xE3o (localizado)"),
32135
- pcInterfaceName: external_exports.string().optional().describe("placa PG/PC (localizada)"),
32136
- pcInterfaceNumber: external_exports.number().int().optional().describe("n\xFAmero da placa (default 1)"),
32137
- targetInterfaceName: external_exports.string().optional().describe("interface alvo da CPU"),
32138
- confirm: external_exports.boolean().optional().describe("G4: true ap\xF3s confirma\xE7\xE3o humana")
32133
+ plc: external_exports.string().describe("PLC name"),
32134
+ connectionMode: external_exports.string().optional().describe("connection mode (localized)"),
32135
+ pcInterfaceName: external_exports.string().optional().describe("PG/PC adapter (localized)"),
32136
+ pcInterfaceNumber: external_exports.number().int().optional().describe("adapter number (default 1)"),
32137
+ targetInterfaceName: external_exports.string().optional().describe("target CPU interface"),
32138
+ confirm: external_exports.boolean().optional().describe("G4: true after human confirmation")
32139
32139
  }
32140
32140
  },
32141
32141
  async ({ plc, connectionMode, pcInterfaceName, pcInterfaceNumber, targetInterfaceName, confirm }) => {
@@ -32146,18 +32146,18 @@ function registerVerificationTools(server2) {
32146
32146
  server2.registerTool(
32147
32147
  "tia_offline",
32148
32148
  {
32149
- title: "TIA \u2014 ir offline",
32150
- description: "Desconecta o CLP do modo online. Mapeia POST /plcs/{plc}/offline.",
32151
- inputSchema: { plc: external_exports.string().describe("nome do CLP") }
32149
+ title: "TIA \u2014 go offline",
32150
+ description: "Disconnects the PLC from online mode. Maps to POST /plcs/{plc}/offline.",
32151
+ inputSchema: { plc: external_exports.string().describe("PLC name") }
32152
32152
  },
32153
32153
  async ({ plc }) => send("POST", `/plcs/${seg3(plc)}/offline`)
32154
32154
  );
32155
32155
  server2.registerTool(
32156
32156
  "tia_online_state",
32157
32157
  {
32158
- title: "TIA \u2014 estado online",
32159
- description: "L\xEA o estado online do CLP (online/offline). Read-only (classe R). Mapeia GET /plcs/{plc}/online/state.",
32160
- inputSchema: { plc: external_exports.string().describe("nome do CLP") }
32158
+ title: "TIA \u2014 online state",
32159
+ description: "Reads the PLC's online state (online/offline). Read-only (class R). Maps to GET /plcs/{plc}/online/state.",
32160
+ inputSchema: { plc: external_exports.string().describe("PLC name") }
32161
32161
  },
32162
32162
  async ({ plc }) => {
32163
32163
  try {
@@ -32170,14 +32170,14 @@ function registerVerificationTools(server2) {
32170
32170
  server2.registerTool(
32171
32171
  "tia_accessible_devices",
32172
32172
  {
32173
- title: "TIA \u2014 dispositivos acess\xEDveis (GATE G7)",
32174
- description: "Varre a rede pela placa PG/PC e lista dispositivos acess\xEDveis \u2014 \xFAtil p/ descobrir os nomes localizados de modo/placa/interface antes do download. GATE G7 (net scan): passe confirm:true. Mapeia POST /plcs/{plc}/online/accessibledevices.",
32173
+ title: "TIA \u2014 accessible devices (GATE G7)",
32174
+ description: "Scans the network via the PG/PC adapter and lists accessible devices \u2014 useful for discovering the localized names of mode/adapter/interface before downloading. GATE G7 (net scan): pass confirm:true. Maps to POST /plcs/{plc}/online/accessibledevices.",
32175
32175
  inputSchema: {
32176
- plc: external_exports.string().describe("nome do CLP"),
32177
- connectionMode: external_exports.string().optional().describe("modo de conex\xE3o (localizado)"),
32178
- pcInterfaceName: external_exports.string().optional().describe("placa PG/PC (localizada)"),
32179
- pcInterfaceNumber: external_exports.number().int().optional().describe("n\xFAmero da placa (default 1)"),
32180
- confirm: external_exports.boolean().optional().describe("G7: true ap\xF3s confirma\xE7\xE3o humana")
32176
+ plc: external_exports.string().describe("PLC name"),
32177
+ connectionMode: external_exports.string().optional().describe("connection mode (localized)"),
32178
+ pcInterfaceName: external_exports.string().optional().describe("PG/PC adapter (localized)"),
32179
+ pcInterfaceNumber: external_exports.number().int().optional().describe("adapter number (default 1)"),
32180
+ confirm: external_exports.boolean().optional().describe("G7: true after human confirmation")
32181
32181
  }
32182
32182
  },
32183
32183
  async ({ plc, connectionMode, pcInterfaceName, pcInterfaceNumber, confirm }) => {
@@ -32188,11 +32188,11 @@ function registerVerificationTools(server2) {
32188
32188
  server2.registerTool(
32189
32189
  "tia_mastersecret_set",
32190
32190
  {
32191
- title: "TIA \u2014 definir master secret (GATE G6)",
32192
- description: "Define o master secret (senha) de uma CPU protegida, antes de online/download. GATE G6: a senha vem de um HUMANO (ou cofre de credenciais) \u2014 a IA NUNCA a inventa. (Obs.: P3.7 questiona enviar o segredo por HTTP em texto; prefira entrada local no host.) Mapeia POST /plcs/{plc}/online/mastersecret.",
32191
+ title: "TIA \u2014 set master secret (GATE G6)",
32192
+ description: "Sets the master secret (password) of a protected CPU, before online/download. GATE G6: the password comes from a HUMAN (or a credential vault) \u2014 the AI NEVER makes it up. (Note: P3.7 questions sending the secret over HTTP in plain text; prefer local entry on the host.) Maps to POST /plcs/{plc}/online/mastersecret.",
32193
32193
  inputSchema: {
32194
- plc: external_exports.string().describe("nome do CLP"),
32195
- password: external_exports.string().describe("master secret fornecido por um humano (NUNCA inventado pela IA)")
32194
+ plc: external_exports.string().describe("PLC name"),
32195
+ password: external_exports.string().describe("master secret provided by a human (NEVER made up by the AI)")
32196
32196
  }
32197
32197
  },
32198
32198
  async ({ plc, password }) => send("POST", `/plcs/${seg3(plc)}/online/mastersecret`, jsonBody3({ password }))
@@ -32200,9 +32200,9 @@ function registerVerificationTools(server2) {
32200
32200
  server2.registerTool(
32201
32201
  "tia_mastersecret_reset",
32202
32202
  {
32203
- title: "TIA \u2014 resetar master secret",
32204
- description: "Remove/reseta o master secret da CPU. Mapeia DELETE /plcs/{plc}/online/mastersecret.",
32205
- inputSchema: { plc: external_exports.string().describe("nome do CLP") }
32203
+ title: "TIA \u2014 reset master secret",
32204
+ description: "Removes/resets the CPU's master secret. Maps to DELETE /plcs/{plc}/online/mastersecret.",
32205
+ inputSchema: { plc: external_exports.string().describe("PLC name") }
32206
32206
  },
32207
32207
  async ({ plc }) => send("DELETE", `/plcs/${seg3(plc)}/online/mastersecret`)
32208
32208
  );
@@ -32236,15 +32236,15 @@ function ipInCidr(ip, cidr) {
32236
32236
  function checkUnique(names, rule, what, out) {
32237
32237
  const seen = /* @__PURE__ */ new Set();
32238
32238
  for (const n of names) {
32239
- if (seen.has(n)) out.push({ rule, severity: "error", detail: `${what} duplicado: "${n}" (R-NAMES: nomes devem ser \xFAnicos).` });
32239
+ if (seen.has(n)) out.push({ rule, severity: "error", detail: `duplicate ${what}: "${n}" (R-NAMES: names must be unique).` });
32240
32240
  seen.add(n);
32241
32241
  }
32242
32242
  }
32243
32243
  function validateSpec(spec) {
32244
32244
  const v = [];
32245
32245
  const devices = Array.isArray(spec?.devices) ? spec.devices : [];
32246
- if (!spec?.project?.name) v.push({ rule: "SCHEMA", severity: "error", detail: "project.name \xE9 obrigat\xF3rio." });
32247
- if (devices.length === 0) v.push({ rule: "SCHEMA", severity: "error", detail: "devices deve ter \u22651 item." });
32246
+ if (!spec?.project?.name) v.push({ rule: "SCHEMA", severity: "error", detail: "project.name is required." });
32247
+ if (devices.length === 0) v.push({ rule: "SCHEMA", severity: "error", detail: "devices must have \u22651 item." });
32248
32248
  checkUnique(devices.map((d) => d?.name).filter(Boolean), "R-NAMES", "device", v);
32249
32249
  const subnetNames = [
32250
32250
  ...spec?.network?.subnet?.name ? [spec.network.subnet.name] : [],
@@ -32252,26 +32252,26 @@ function validateSpec(spec) {
32252
32252
  ];
32253
32253
  checkUnique(subnetNames, "R-NAMES", "subnet", v);
32254
32254
  checkUnique((Array.isArray(spec?.dataTypes) ? spec.dataTypes : []).map((u) => u?.name).filter(Boolean), "R-NAMES", "UDT", v);
32255
- checkUnique((Array.isArray(spec?.blocks) ? spec.blocks : []).map((b) => b?.name).filter(Boolean), "R-NAMES", "bloco", v);
32255
+ checkUnique((Array.isArray(spec?.blocks) ? spec.blocks : []).map((b) => b?.name).filter(Boolean), "R-NAMES", "block", v);
32256
32256
  const byTable = /* @__PURE__ */ new Map();
32257
32257
  for (const t of Array.isArray(spec?.tags) ? spec.tags : []) {
32258
32258
  if (!t?.table || !t?.name) continue;
32259
32259
  if (!byTable.has(t.table)) byTable.set(t.table, []);
32260
32260
  byTable.get(t.table).push(t.name);
32261
32261
  }
32262
- for (const [table, names] of byTable) checkUnique(names, "R-NAMES", `tag (tabela ${table})`, v);
32262
+ for (const [table, names] of byTable) checkUnique(names, "R-NAMES", `tag (table ${table})`, v);
32263
32263
  for (const d of devices) {
32264
32264
  if (d?.typeIdentifier && !TYPEID_RE.test(d.typeIdentifier))
32265
- v.push({ rule: "R-TYPEID", severity: "error", detail: `device "${d.name}": typeIdentifier inv\xE1lido "${d.typeIdentifier}" \u2014 use OrderNumber:<MLFB>/V<fw> (barra, n\xE3o ':V'). Resolva via tia_catalog.` });
32265
+ v.push({ rule: "R-TYPEID", severity: "error", detail: `device "${d.name}": invalid typeIdentifier "${d.typeIdentifier}" \u2014 use OrderNumber:<MLFB>/V<fw> (slash, not ':V'). Resolve via tia_catalog.` });
32266
32266
  for (const m of Array.isArray(d?.modules) ? d.modules : []) {
32267
32267
  if (m?.order && !TYPEID_RE.test(m.order))
32268
- v.push({ rule: "R-TYPEID", severity: "error", detail: `m\xF3dulo em "${d.name}": order inv\xE1lido "${m.order}" \u2014 use OrderNumber:<MLFB>/V<fw>.` });
32268
+ v.push({ rule: "R-TYPEID", severity: "error", detail: `module in "${d.name}": invalid order "${m.order}" \u2014 use OrderNumber:<MLFB>/V<fw>.` });
32269
32269
  }
32270
32270
  }
32271
32271
  for (const d of devices) {
32272
32272
  if (d?.family === "S7-1200") {
32273
32273
  const sm = (Array.isArray(d?.modules) ? d.modules : []).filter((m) => (m?.kind ?? "SM") === "SM").length;
32274
- if (sm > 8) v.push({ rule: "R-MODLIMIT", severity: "error", detail: `device "${d.name}" (S7-1200) tem ${sm} SM \u2014 acima do limite (8). Confirme o limite exato do modelo via tia_catalog.` });
32274
+ if (sm > 8) v.push({ rule: "R-MODLIMIT", severity: "error", detail: `device "${d.name}" (S7-1200) has ${sm} SM \u2014 above the limit (8). Confirm the exact limit for the model via tia_catalog.` });
32275
32275
  }
32276
32276
  }
32277
32277
  const families = new Set(devices.filter((d) => d?.role === "cpu" || /^S7-1[25]00$/.test(d?.family ?? "")).map((d) => d?.family).filter(Boolean));
@@ -32280,8 +32280,8 @@ function validateSpec(spec) {
32280
32280
  const graphLangs = /* @__PURE__ */ new Set(["STL", "GRAPH"]);
32281
32281
  for (const b of Array.isArray(spec?.blocks) ? spec.blocks : []) {
32282
32282
  if (graphLangs.has(b?.language)) {
32283
- if (has1200 && !has1500) v.push({ rule: "R-LANGFAM", severity: "error", detail: `bloco "${b.name}" usa ${b.language}, que \xE9 S7-1500-only, mas o alvo \xE9 S7-1200.` });
32284
- else if (has1200 && has1500) v.push({ rule: "R-LANGFAM", severity: "warning", detail: `bloco "${b.name}" usa ${b.language} (S7-1500-only) num projeto com S7-1200 e S7-1500 \u2014 garanta que vai para a CPU 1500.` });
32283
+ if (has1200 && !has1500) v.push({ rule: "R-LANGFAM", severity: "error", detail: `block "${b.name}" uses ${b.language}, which is S7-1500-only, but the target is S7-1200.` });
32284
+ else if (has1200 && has1500) v.push({ rule: "R-LANGFAM", severity: "warning", detail: `block "${b.name}" uses ${b.language} (S7-1500-only) in a project with S7-1200 and S7-1500 \u2014 make sure it targets the 1500 CPU.` });
32285
32285
  }
32286
32286
  }
32287
32287
  const net = spec?.network;
@@ -32294,31 +32294,31 @@ function validateSpec(spec) {
32294
32294
  let ioSystemSubnet = null;
32295
32295
  let ioSystemCount = 0;
32296
32296
  for (const n of nodes) {
32297
- if (!deviceByName.has(n?.device)) v.push({ rule: "R-SUBNET", severity: "error", detail: `network node referencia device inexistente "${n?.device}".` });
32297
+ if (!deviceByName.has(n?.device)) v.push({ rule: "R-SUBNET", severity: "error", detail: `network node references nonexistent device "${n?.device}".` });
32298
32298
  const sName = n?.subnet ?? net?.subnet?.name;
32299
32299
  const sub = sName ? subnetByName.get(sName) : void 0;
32300
- if (!sub) v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}" referencia subnet inexistente "${sName}".` });
32300
+ if (!sub) v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}" references nonexistent subnet "${sName}".` });
32301
32301
  else if (n?.ip && sub?.cidr && !ipInCidr(n.ip, sub.cidr))
32302
- v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}": IP ${n.ip} fora do CIDR ${sub.cidr} da subnet ${sName}.` });
32302
+ v.push({ rule: "R-SUBNET", severity: "error", detail: `node "${n?.device}": IP ${n.ip} is outside CIDR ${sub.cidr} of subnet ${sName}.` });
32303
32303
  if (n?.createIoSystem) {
32304
32304
  ioSystemCount++;
32305
32305
  ioSystemSubnet = n?.subnet ?? net?.subnet?.name ?? null;
32306
32306
  }
32307
32307
  }
32308
- if (ioSystemCount === 0) v.push({ rule: "R-SUBNET", severity: "warning", detail: "nenhum node com createIoSystem:true \u2014 uma CPU deve hospedar o IO-system (\xA73)." });
32309
- if (ioSystemCount > 1) v.push({ rule: "R-SUBNET", severity: "warning", detail: `${ioSystemCount} nodes com createIoSystem:true \u2014 normalmente \xE9 1 por interface de controlador.` });
32308
+ if (ioSystemCount === 0) v.push({ rule: "R-SUBNET", severity: "warning", detail: "no node with createIoSystem:true \u2014 one CPU must host the IO-system (\xA73)." });
32309
+ if (ioSystemCount > 1) v.push({ rule: "R-SUBNET", severity: "warning", detail: `${ioSystemCount} nodes with createIoSystem:true \u2014 normally 1 per controller interface.` });
32310
32310
  if (ioSystemSubnet) {
32311
32311
  for (const n of nodes) {
32312
32312
  const dev = deviceByName.get(n?.device);
32313
32313
  if (dev?.role === "io-device") {
32314
32314
  const sName = n?.subnet ?? net?.subnet?.name;
32315
- if (sName !== ioSystemSubnet) v.push({ rule: "R-SUBNET", severity: "error", detail: `io-device "${n?.device}" est\xE1 na subnet "${sName}", diferente da subnet do IO-system "${ioSystemSubnet}" (CPU+IO devem compartilhar a subnet).` });
32315
+ if (sName !== ioSystemSubnet) v.push({ rule: "R-SUBNET", severity: "error", detail: `io-device "${n?.device}" is on subnet "${sName}", different from the IO-system's subnet "${ioSystemSubnet}" (CPU+IO must share the subnet).` });
32316
32316
  }
32317
32317
  }
32318
32318
  }
32319
32319
  }
32320
32320
  if (spec?.safety?.required === true && spec?.autonomous === true)
32321
- v.push({ rule: "G5", severity: "error", detail: "safety.required && autonomous \u21D2 REJEITADO. L\xF3gica de seguran\xE7a (F) NUNCA \xE9 autorada/baixada autonomamente (IEC 61511). Selecionar CPU-F \xE9 permitido; a autoria F \xE9 humana e gated." });
32321
+ v.push({ rule: "G5", severity: "error", detail: "safety.required && autonomous \u21D2 REJECTED. Safety logic (F) is NEVER authored/downloaded autonomously (IEC 61511). Selecting an F-CPU is allowed; F authoring is human and gated." });
32322
32322
  const counts = {
32323
32323
  devices: devices.length,
32324
32324
  modules: devices.reduce((a, d) => a + (Array.isArray(d?.modules) ? d.modules.length : 0), 0),
@@ -32338,8 +32338,8 @@ function planSpec(spec) {
32338
32338
  const steps = [];
32339
32339
  const assumptions = [];
32340
32340
  const plc = primaryPlc(spec);
32341
- assumptions.push(`CLP-alvo de tags/blocos = "${plc}" (1\xAA device role:cpu; ajuste se o nome do PlcSoftware diferir).`);
32342
- assumptions.push("Pr\xE9-condi\xE7\xE3o: um projeto j\xE1 deve estar ABERTO (tia_connect/tia_project_create \u2014 gated G1). UDTs e a L\xD3GICA dos blocos n\xE3o s\xE3o auto-gerados a partir do spec (declaram estrutura, n\xE3o c\xF3digo).");
32341
+ assumptions.push(`Target PLC for tags/blocks = "${plc}" (1st device role:cpu; adjust if the PlcSoftware name differs).`);
32342
+ assumptions.push("Precondition: a project must already be OPEN (tia_connect/tia_project_create \u2014 gated G1). UDTs and block LOGIC are not auto-generated from the spec (they declare structure, not code).");
32343
32343
  const subnets = [];
32344
32344
  if (spec?.network?.subnet) subnets.push(spec.network.subnet);
32345
32345
  for (const s of Array.isArray(spec?.subnets) ? spec.subnets : []) subnets.push(s);
@@ -32347,59 +32347,59 @@ function planSpec(spec) {
32347
32347
  for (const s of subnets) {
32348
32348
  if (!s?.name || subnetSeen.has(s.name)) continue;
32349
32349
  subnetSeen.add(s.name);
32350
- steps.push({ op: "subnet.create", method: "POST", path: "/subnets", body: jsonBody4({ typeIdentifier: s.type ?? "System:Subnet.Ethernet", name: s.name }), summary: `criar subnet ${s.name}` });
32350
+ steps.push({ op: "subnet.create", method: "POST", path: "/subnets", body: jsonBody4({ typeIdentifier: s.type ?? "System:Subnet.Ethernet", name: s.name }), summary: `create subnet ${s.name}` });
32351
32351
  }
32352
32352
  for (const d of Array.isArray(spec?.devices) ? spec.devices : []) {
32353
- steps.push({ op: "device.create", method: "POST", path: "/devices", body: jsonBody4({ typeIdentifier: d.typeIdentifier, deviceName: d.name }), summary: `criar device ${d.name}` });
32353
+ steps.push({ op: "device.create", method: "POST", path: "/devices", body: jsonBody4({ typeIdentifier: d.typeIdentifier, deviceName: d.name }), summary: `create device ${d.name}` });
32354
32354
  }
32355
32355
  for (const d of Array.isArray(spec?.devices) ? spec.devices : []) {
32356
32356
  for (const m of Array.isArray(d?.modules) ? d.modules : []) {
32357
- steps.push({ op: "device.plug", method: "POST", path: `/devices/${seg4(d.name)}/plug`, body: jsonBody4({ typeIdentifier: m.order, position: m.slot }), summary: `plugar m\xF3dulo em ${d.name}` });
32357
+ steps.push({ op: "device.plug", method: "POST", path: `/devices/${seg4(d.name)}/plug`, body: jsonBody4({ typeIdentifier: m.order, position: m.slot }), summary: `plug module into ${d.name}` });
32358
32358
  }
32359
32359
  }
32360
32360
  for (const n of Array.isArray(spec?.network?.nodes) ? spec.network.nodes : []) {
32361
32361
  const sName = n?.subnet ?? spec?.network?.subnet?.name;
32362
- steps.push({ op: "network.connect", method: "POST", path: "/network/connect", body: jsonBody4({ device: n.device, subnet: sName, ip: n.ip, createIoSystem: n.createIoSystem }), summary: `conectar ${n.device} @ ${n.ip} \xE0 subnet ${sName}` });
32362
+ steps.push({ op: "network.connect", method: "POST", path: "/network/connect", body: jsonBody4({ device: n.device, subnet: sName, ip: n.ip, createIoSystem: n.createIoSystem }), summary: `connect ${n.device} @ ${n.ip} to subnet ${sName}` });
32363
32363
  }
32364
32364
  if (plc) {
32365
32365
  const tableNames = /* @__PURE__ */ new Set();
32366
32366
  for (const tt of Array.isArray(spec?.tagTables) ? spec.tagTables : []) if (tt?.name) tableNames.add(tt.name);
32367
32367
  for (const t of Array.isArray(spec?.tags) ? spec.tags : []) if (t?.table) tableNames.add(t.table);
32368
- for (const name of tableNames) steps.push({ op: "tagtable.create", method: "POST", path: `/plcs/${seg4(plc)}/tagtables`, body: { name }, summary: `criar tabela de tags ${name}` });
32368
+ for (const name of tableNames) steps.push({ op: "tagtable.create", method: "POST", path: `/plcs/${seg4(plc)}/tagtables`, body: { name }, summary: `create tag table ${name}` });
32369
32369
  for (const t of Array.isArray(spec?.tags) ? spec.tags : []) {
32370
- steps.push({ op: "tag.create", method: "POST", path: `/plcs/${seg4(plc)}/tags`, body: jsonBody4({ table: t.table, name: t.name, dataType: t.dataType, address: t.address }), summary: `criar tag ${t.name}:${t.dataType}` });
32370
+ steps.push({ op: "tag.create", method: "POST", path: `/plcs/${seg4(plc)}/tags`, body: jsonBody4({ table: t.table, name: t.name, dataType: t.dataType, address: t.address }), summary: `create tag ${t.name}:${t.dataType}` });
32371
32371
  }
32372
32372
  for (const b of Array.isArray(spec?.blocks) ? spec.blocks : []) {
32373
- if (b?.kind === "FB") steps.push({ op: "fb.create", method: "POST", path: `/plcs/${seg4(plc)}/fbs`, body: jsonBody4({ name: b.name, language: b.language }), summary: `criar FB ${b.name} (${b.language})` });
32373
+ if (b?.kind === "FB") steps.push({ op: "fb.create", method: "POST", path: `/plcs/${seg4(plc)}/fbs`, body: jsonBody4({ name: b.name, language: b.language }), summary: `create FB ${b.name} (${b.language})` });
32374
32374
  }
32375
32375
  const fcObDb = (Array.isArray(spec?.blocks) ? spec.blocks : []).filter((b) => b?.kind && b.kind !== "FB").map((b) => b.name);
32376
- if (fcObDb.length) assumptions.push(`Blocos OB/FC/DB (${fcObDb.join(", ")}) e a l\xF3gica n\xE3o entram no apply \u2014 autore via tia_source_put (SCL) / tia_import_xml (gr\xE1fico).`);
32376
+ if (fcObDb.length) assumptions.push(`OB/FC/DB blocks (${fcObDb.join(", ")}) and their logic are not included in apply \u2014 author them via tia_source_put (SCL) / tia_import_xml (graphical).`);
32377
32377
  for (const fu of Array.isArray(spec?.functionalUnits) ? spec.functionalUnits : []) {
32378
32378
  for (const em of Array.isArray(fu?.equipmentModules) ? fu.equipmentModules : []) {
32379
32379
  for (const cm of Array.isArray(em?.controlModules) ? em.controlModules : []) {
32380
32380
  if (cm?.instanceDb && cm?.libraryType) {
32381
32381
  const fb = String(cm.libraryType).split("@")[0];
32382
- steps.push({ op: "instancedb.create", method: "POST", path: `/plcs/${seg4(plc)}/instancedbs`, body: jsonBody4({ name: cm.instanceDb, instanceOf: fb }), summary: `criar iDB ${cm.instanceDb} de ${fb}` });
32382
+ steps.push({ op: "instancedb.create", method: "POST", path: `/plcs/${seg4(plc)}/instancedbs`, body: jsonBody4({ name: cm.instanceDb, instanceOf: fb }), summary: `create iDB ${cm.instanceDb} from ${fb}` });
32383
32383
  }
32384
32384
  }
32385
32385
  }
32386
32386
  }
32387
32387
  const ladder = Array.isArray(spec?.verification?.ladder) ? spec.verification.ladder : ["compile"];
32388
- if (ladder.includes("compile")) steps.push({ op: "compile", method: "POST", path: `/plcs/${seg4(plc)}/compile`, body: {}, summary: `compilar ${plc} (verificador)` });
32388
+ if (ladder.includes("compile")) steps.push({ op: "compile", method: "POST", path: `/plcs/${seg4(plc)}/compile`, body: {}, summary: `compile ${plc} (verifier)` });
32389
32389
  }
32390
32390
  return { steps, assumptions };
32391
32391
  }
32392
32392
  async function applySpec(spec, opts = {}) {
32393
32393
  if (spec?.safety?.required === true && spec?.autonomous === true) {
32394
- return textResult({ status: "rejected", gate: "safety_signoff", reason: "G5: safety.required && autonomous \u21D2 REJECT (IEC 61511). Selecionar CPU-F \xE9 OK; autorar/baixar F nunca \xE9 aut\xF4nomo." }, true);
32394
+ return textResult({ status: "rejected", gate: "safety_signoff", reason: "G5: safety.required && autonomous \u21D2 REJECT (IEC 61511). Selecting an F-CPU is OK; authoring/downloading F is never autonomous." }, true);
32395
32395
  }
32396
32396
  const val = validateSpec(spec);
32397
32397
  if (!val.valid) {
32398
- return textResult({ status: "invalid", valid: false, violations: val.violations, counts: val.counts, note: "Spec inv\xE1lido \u2014 corrija as viola\xE7\xF5es 'error' antes de aplicar." }, true);
32398
+ return textResult({ status: "invalid", valid: false, violations: val.violations, counts: val.counts, note: "Invalid spec \u2014 fix the 'error' violations before applying." }, true);
32399
32399
  }
32400
32400
  const { steps, assumptions } = planSpec(spec);
32401
32401
  if (opts.dryRun) {
32402
- return textResult({ dryRun: true, status: "plan_ok", valid: true, stepCount: steps.length, steps, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), note: "Plano validado. NADA foi aplicado. Rode com dryRun:false (projeto aberto) para construir; o download (G3) N\xC3O \xE9 inclu\xEDdo." }, false);
32402
+ return textResult({ dryRun: true, status: "plan_ok", valid: true, stepCount: steps.length, steps, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), note: "Plan validated. NOTHING was applied. Run with dryRun:false (project open) to build; the download (G3) is NOT included." }, false);
32403
32403
  }
32404
32404
  const applied = [];
32405
32405
  let compileResult = null;
@@ -32412,20 +32412,20 @@ async function applySpec(spec, opts = {}) {
32412
32412
  const err = asTiaError(e);
32413
32413
  applied.push({ op: s.op, summary: s.summary, ok: false, error: err.message, kind: err.kind });
32414
32414
  if (!opts.continueOnError) {
32415
- return textResult({ status: "stopped", appliedCount: applied.length, applied, stoppedAt: s.summary, error: err.message, kind: err.kind, assumptions, note: "Parou no 1\xBA erro (Gd2: re-rodar converge por nome; passe continueOnError:true para seguir mesmo com erros)." }, true);
32415
+ return textResult({ status: "stopped", appliedCount: applied.length, applied, stoppedAt: s.summary, error: err.message, kind: err.kind, assumptions, note: "Stopped at the 1st error (Gd2: re-running converges by name; pass continueOnError:true to keep going despite errors)." }, true);
32416
32416
  }
32417
32417
  }
32418
32418
  }
32419
32419
  const okAll = applied.every((a) => a.ok);
32420
- return textResult({ status: okAll ? "applied" : "applied_with_errors", appliedCount: applied.length, applied, compile: compileResult, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), nextHints: ["Build offline conclu\xEDdo. Para deploy: revise o compile, ent\xE3o tia_download (GATE G3, exige aprova\xE7\xE3o humana)."] }, !okAll);
32420
+ return textResult({ status: okAll ? "applied" : "applied_with_errors", appliedCount: applied.length, applied, compile: compileResult, assumptions, warnings: val.violations.filter((x) => x.severity === "warning"), nextHints: ["Offline build complete. To deploy: review the compile, then tia_download (GATE G3, requires human approval)."] }, !okAll);
32421
32421
  }
32422
32422
  function registerSpecTools(server2) {
32423
32423
  server2.registerTool(
32424
32424
  "tia_spec_validate",
32425
32425
  {
32426
- title: "TIA \u2014 validar project-spec (determin\xEDstico, R)",
32427
- description: "Valida um project-spec (docs/TIA-BEST-PRACTICES \xA713.2) deterministicamente, SEM tocar o serve (rung 0): R-NAMES (nomes \xFAnicos), R-TYPEID (OrderNumber:<MLFB>/V<fw>), R-SUBNET (IP\u2208CIDR, mesma subnet, 1 IO-system), R-LANGFAM (STL/GRAPH s\xF3 S7-1500), R-MODLIMIT, e G5 (safety.required && autonomous \u21D2 REJECT). Retorna { valid, violations:[{rule,severity,detail}], counts }.",
32428
- inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("o project-spec (objeto conforme o JSON Schema do plugin)") }
32426
+ title: "TIA \u2014 validate project-spec (deterministic, R)",
32427
+ description: "Validates a project-spec (docs/TIA-BEST-PRACTICES \xA713.2) deterministically, WITHOUT touching serve (rung 0): R-NAMES (unique names), R-TYPEID (OrderNumber:<MLFB>/V<fw>), R-SUBNET (IP\u2208CIDR, same subnet, 1 IO-system), R-LANGFAM (STL/GRAPH S7-1500 only), R-MODLIMIT, and G5 (safety.required && autonomous \u21D2 REJECT). Returns { valid, violations:[{rule,severity,detail}], counts }.",
32428
+ inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("the project-spec (object conforming to the plugin's JSON Schema)") }
32429
32429
  },
32430
32430
  async ({ spec }) => {
32431
32431
  const r = validateSpec(spec);
@@ -32435,9 +32435,9 @@ function registerSpecTools(server2) {
32435
32435
  server2.registerTool(
32436
32436
  "tia_spec_plan",
32437
32437
  {
32438
- title: "TIA \u2014 planejar project-spec (sem aplicar)",
32439
- description: "Valida e transforma um project-spec na SEQU\xCANCIA ORDENADA de opera\xE7\xF5es offline (subnets\u2192devices\u2192m\xF3dulos\u2192rede\u2192tags\u2192blocos\u2192compile), SEM tocar o serve. Opera\xE7\xF5es gated (connect/download) N\xC3O entram. Retorna { steps, assumptions } ou as viola\xE7\xF5es se inv\xE1lido.",
32440
- inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("o project-spec") }
32438
+ title: "TIA \u2014 plan project-spec (without applying)",
32439
+ description: "Validates and transforms a project-spec into the ORDERED SEQUENCE of offline operations (subnets\u2192devices\u2192modules\u2192network\u2192tags\u2192blocks\u2192compile), WITHOUT touching serve. Gated operations (connect/download) are NOT included. Returns { steps, assumptions } or the violations if invalid.",
32440
+ inputSchema: { spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("the project-spec") }
32441
32441
  },
32442
32442
  async ({ spec }) => {
32443
32443
  const val = validateSpec(spec);
@@ -32449,12 +32449,12 @@ function registerSpecTools(server2) {
32449
32449
  server2.registerTool(
32450
32450
  "tia_spec_apply",
32451
32451
  {
32452
- title: "TIA \u2014 aplicar project-spec (orquestrador offline)",
32453
- description: "Orquestra o build OFFLINE de um project-spec num projeto J\xC1 ABERTO: valida \u2192 G5 (rejeita safety+autonomous) \u2192 executa serialmente subnets/devices/m\xF3dulos/rede/tags/blocos \u2192 compila. PARA no 1\xBA erro (continueOnError p/ seguir). NUNCA baixa (download \xE9 o GATE G3, sempre humano). dryRun:true devolve o plano sem aplicar. Requer um projeto aberto (tia_connect/tia_project_create antes).",
32452
+ title: "TIA \u2014 apply project-spec (offline orchestrator)",
32453
+ description: "Orchestrates the OFFLINE build of a project-spec on an ALREADY OPEN project: validates \u2192 G5 (rejects safety+autonomous) \u2192 serially executes subnets/devices/modules/network/tags/blocks \u2192 compiles. STOPS at the 1st error (continueOnError to keep going). NEVER downloads (download is GATE G3, always human). dryRun:true returns the plan without applying. Requires an open project (tia_connect/tia_project_create beforehand).",
32454
32454
  inputSchema: {
32455
- spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("o project-spec"),
32456
- dryRun: external_exports.boolean().optional().describe("true \u2192 devolve o plano sem aplicar"),
32457
- continueOnError: external_exports.boolean().optional().describe("true \u2192 n\xE3o para no 1\xBA erro (Gd2: re-rodar converge por nome)")
32455
+ spec: external_exports.record(external_exports.string(), external_exports.unknown()).describe("the project-spec"),
32456
+ dryRun: external_exports.boolean().optional().describe("true \u2192 returns the plan without applying"),
32457
+ continueOnError: external_exports.boolean().optional().describe("true \u2192 does not stop at the 1st error (Gd2: re-running converges by name)")
32458
32458
  }
32459
32459
  },
32460
32460
  async ({ spec, dryRun, continueOnError }) => applySpec(spec, { dryRun, continueOnError })
@@ -32462,12 +32462,12 @@ function registerSpecTools(server2) {
32462
32462
  }
32463
32463
 
32464
32464
  // src/index.ts
32465
- var server = new McpServer({ name: "tia-openness", version: "1.1.1" });
32465
+ var server = new McpServer({ name: "tia-openness", version: "1.2.0" });
32466
32466
  server.registerTool(
32467
32467
  "tia_ping",
32468
32468
  {
32469
- title: "TIA \u2014 diagn\xF3stico de conex\xE3o",
32470
- description: "Diagnostica a conectividade com a API `serve` do TIA Openness e se o servidor est\xE1 ATIVADO. Testa GET /health (alcan\xE7abilidade) e GET /readiness (ativa\xE7\xE3o por licen\xE7a). Ideal para o cen\xE1rio MCP no Mac apontando para um `serve` numa VM Windows. Read-only. Retorna { base, reachable, activated, latencyMs, hint }.",
32469
+ title: "TIA \u2014 connection diagnostics",
32470
+ description: "Diagnoses connectivity to the TIA Openness `serve` API and whether the server is ACTIVATED. Tests GET /health (reachability) and GET /readiness (license activation). Ideal for the MCP-on-Mac-pointing-at-a-`serve`-on-a-Windows-VM scenario. Read-only. Returns { base, reachable, activated, latencyMs, hint }.",
32471
32471
  inputSchema: {}
32472
32472
  },
32473
32473
  async () => {
@@ -32506,8 +32506,8 @@ server.registerTool(
32506
32506
  server.registerTool(
32507
32507
  "tia_readiness",
32508
32508
  {
32509
- title: "TIA \u2014 prontid\xE3o do ambiente",
32510
- description: "Diagn\xF3stico de prontid\xE3o do ambiente TIA Openness V21 NO HOST DO SERVE (processo x64, grupo Windows 'Siemens TIA Openness', PublicAPI, registro 21.0 e inst\xE2ncias TIA). Chame ANTES de conectar. Mapeia GET /readiness. Read-only (classe R). Retorna { ready, checks:[{ name, status, detail, remediation }] }.",
32509
+ title: "TIA \u2014 environment readiness",
32510
+ description: "Readiness diagnostic for the TIA Openness V21 environment ON THE SERVE HOST (x64 process, Windows 'Siemens TIA Openness' group, PublicAPI, 21.0 registry key, and TIA instances). Call BEFORE connecting. Maps to GET /readiness. Read-only (class R). Returns { ready, checks:[{ name, status, detail, remediation }] }.",
32511
32511
  inputSchema: {}
32512
32512
  },
32513
32513
  async () => {
@@ -32528,9 +32528,9 @@ registerSpecTools(server);
32528
32528
  async function main() {
32529
32529
  const transport = new StdioServerTransport();
32530
32530
  await server.connect(transport);
32531
- console.error(`[tia-openness-mcp] stdio pronto. API base = ${BASE} timeout=${TIMEOUT_MS}ms`);
32531
+ console.error(`[tia-openness-mcp] stdio ready. API base = ${BASE} timeout=${TIMEOUT_MS}ms`);
32532
32532
  }
32533
32533
  main().catch((e) => {
32534
- console.error("[tia-openness-mcp] falha fatal:", e);
32534
+ console.error("[tia-openness-mcp] fatal error:", e);
32535
32535
  process.exit(1);
32536
32536
  });