@nuvlore/extension-bds 0.1.1

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 (109) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +3 -0
  3. package/agents/bds-airflow-job-status-readonly.yaml +123 -0
  4. package/agents/bds-disk-investigator.yaml +112 -0
  5. package/agents/bds-inventory-readonly.yaml +60 -0
  6. package/agents/bds-oncall-reporter.yaml +113 -0
  7. package/agents/bds-prism-service-proxy-timeout-readonly.yaml +105 -0
  8. package/agents/bds-scylla-tenant-bucket-readonly.yaml +104 -0
  9. package/agents/bds-tenant-data-operation-log-readonly.yaml +98 -0
  10. package/agents/bds-yarn-app-health-readonly.yaml +114 -0
  11. package/agents/pharos-alert-investigator.yaml +81 -0
  12. package/package.json +60 -0
  13. package/skills/bds-airflow-job-status-investigation/SKILL.md +104 -0
  14. package/skills/bds-airflow-job-status-investigation/references/airflow-access-runbook.md +35 -0
  15. package/skills/bds-airflow-job-status-investigation/references/airflow-bas-dr-runbook.md +42 -0
  16. package/skills/bds-airflow-job-status-investigation/references/airflow-copy-and-migration-runbook.md +63 -0
  17. package/skills/bds-airflow-job-status-investigation/references/airflow-job-status-runbook.md +15 -0
  18. package/skills/bds-airflow-job-status-investigation/references/airflow-output-runbook.md +28 -0
  19. package/skills/bds-airflow-job-status-investigation/references/airflow-snapshot-runbook.md +38 -0
  20. package/skills/bds-disk-io-alert-investigation/SKILL.md +116 -0
  21. package/skills/bds-hadoop-review/SKILL.md +66 -0
  22. package/skills/bds-machine-inventory/SKILL.md +48 -0
  23. package/skills/bds-oncall-followup/SKILL.md +71 -0
  24. package/skills/bds-oncall-followup/references/oncall-followup-runbook.md +58 -0
  25. package/skills/bds-prism-service-proxy-timeout-investigation/SKILL.md +73 -0
  26. package/skills/bds-prism-service-proxy-timeout-investigation/references/service-proxy-timeout-runbook.md +48 -0
  27. package/skills/bds-scylla-tenant-bucket-investigation/SKILL.md +73 -0
  28. package/skills/bds-scylla-tenant-bucket-investigation/references/tenant-bucket-runbook.md +91 -0
  29. package/skills/bds-tenant-data-operation-log-investigation/SKILL.md +89 -0
  30. package/skills/bds-yarn-app-health-investigation/SKILL.md +77 -0
  31. package/skills/bds-yarn-app-health-investigation/references/yarn-app-health-runbook.md +53 -0
  32. package/skills/pharos-alert-investigation/SKILL.md +80 -0
  33. package/src/bds-atomic-log-tools.mjs +300 -0
  34. package/src/bds-team-membership-claude-output.mjs +36 -0
  35. package/src/bds-team-membership-quality.mjs +90 -0
  36. package/tools/bds_airflow_dag_log_read.mjs +24 -0
  37. package/tools/bds_airflow_job_status_command_pack.mjs +587 -0
  38. package/tools/bds_bas_log_read.mjs +23 -0
  39. package/tools/bds_bdm_httpd_log_read.mjs +24 -0
  40. package/tools/bds_chef_client_log_read.mjs +23 -0
  41. package/tools/bds_dashboard_links.mjs +178 -0
  42. package/tools/bds_dashboard_query_knowledge.mjs +258 -0
  43. package/tools/bds_dashboard_query_read.mjs +120 -0
  44. package/tools/bds_disk_io_alert_command_pack.mjs +287 -0
  45. package/tools/bds_environment_host_lookup.mjs +741 -0
  46. package/tools/bds_hdfs_datanode_log_read.mjs +23 -0
  47. package/tools/bds_hdfs_journalnode_log_read.mjs +23 -0
  48. package/tools/bds_hdfs_namenode_log_read.mjs +23 -0
  49. package/tools/bds_hdfs_path_knowledge.mjs +324 -0
  50. package/tools/bds_information_source_knowledge.mjs +356 -0
  51. package/tools/bds_kms_log_read.mjs +23 -0
  52. package/tools/bds_log_path_knowledge.mjs +267 -0
  53. package/tools/bds_machine_inventory.mjs +434 -0
  54. package/tools/bds_mapreduce_historyserver_log_read.mjs +23 -0
  55. package/tools/bds_migration_service_operation_command_pack.mjs +233 -0
  56. package/tools/bds_oncall_followup_payload_draft.mjs +285 -0
  57. package/tools/bds_pharos_query_pack.mjs +218 -0
  58. package/tools/bds_portal_operation_knowledge.mjs +212 -0
  59. package/tools/bds_prism_clone_status_links.mjs +129 -0
  60. package/tools/bds_prism_service_proxy_timeout_query_pack.mjs +224 -0
  61. package/tools/bds_public_cloud_pod_log_read.mjs +18 -0
  62. package/tools/bds_scylla_tenant_bucket_command_pack.mjs +323 -0
  63. package/tools/bds_service_proxy_log_read.mjs +23 -0
  64. package/tools/bds_spark_historyserver_log_read.mjs +32 -0
  65. package/tools/bds_spas_mt_log_read.mjs +23 -0
  66. package/tools/bds_tenant_data_operation_log_command_pack.mjs +321 -0
  67. package/tools/bds_yarn_app_health_command_pack.mjs +529 -0
  68. package/tools/bds_yarn_nodemanager_log_read.mjs +23 -0
  69. package/tools/bds_yarn_resourcemanager_log_read.mjs +23 -0
  70. package/tools/bds_zookeeper_log_read.mjs +23 -0
  71. package/tools/confluence_handoff_page_draft.mjs +173 -0
  72. package/vendor/dashboard/src/grafana-dashboard-query.mjs +61 -0
  73. package/vendor/extension-read-only-toolkit/LICENSE +202 -0
  74. package/vendor/extension-read-only-toolkit/README.md +29 -0
  75. package/vendor/extension-read-only-toolkit/package.json +46 -0
  76. package/vendor/extension-read-only-toolkit/src/devops-data-paths.mjs +222 -0
  77. package/vendor/extension-read-only-toolkit/src/devops-diagnostics.mjs +440 -0
  78. package/vendor/extension-read-only-toolkit/src/enterprise-api-read.mjs +180 -0
  79. package/vendor/extension-read-only-toolkit/src/read-only-command-pack.mjs +1 -0
  80. package/vendor/extension-read-only-toolkit/src/read-only-plan.mjs +45 -0
  81. package/vendor/extension-read-only-toolkit/src/read-only-shell-policy.d.mts +26 -0
  82. package/vendor/extension-read-only-toolkit/src/read-only-shell-policy.mjs +170 -0
  83. package/vendor/extension-workday-infra-access/LICENSE +202 -0
  84. package/vendor/extension-workday-infra-access/README.md +3 -0
  85. package/vendor/extension-workday-infra-access/agents/workday-infra-access-readonly.yaml +183 -0
  86. package/vendor/extension-workday-infra-access/package.json +49 -0
  87. package/vendor/extension-workday-infra-access/skills/workday-infra-access/SKILL.md +102 -0
  88. package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-boundary-runbook.md +43 -0
  89. package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-runbook.md +15 -0
  90. package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-scylla-cloud-runbook.md +39 -0
  91. package/vendor/extension-workday-infra-access/skills/workday-infra-access/references/access-spc-argo-runbook.md +99 -0
  92. package/vendor/extension-workday-infra-access/src/workday-access-profiles.mjs +194 -0
  93. package/vendor/extension-workday-infra-access/tools/aws_cust_federated_readonly_command_pack.mjs +234 -0
  94. package/vendor/extension-workday-infra-access/tools/gcp_readonly_command_pack.mjs +167 -0
  95. package/vendor/extension-workday-infra-access/tools/public_cloud_access_status.mjs +48 -0
  96. package/vendor/extension-workday-infra-access/tools/workday_boundary_login.mjs +460 -0
  97. package/vendor/extension-workday-infra-access/tools/workday_private_cloud_sudo_readonly_command.mjs +386 -0
  98. package/vendor/extension-workday-infra-access/tools/workday_public_cloud_environment_map.mjs +189 -0
  99. package/vendor/extension-workday-infra-access/tools/workday_public_cloud_kubernetes_read.mjs +297 -0
  100. package/vendor/extension-workday-infra-access/tools/workday_public_cloud_spc_login.mjs +505 -0
  101. package/vendor/extension-workday-infra-access/tools/workday_spc_argo_readonly_command_pack.mjs +215 -0
  102. package/vendor/extension-workday-infra-access/workflows/public-cloud-readonly-investigation.js +99 -0
  103. package/workflows/bds-airflow-job-status-investigation.js +168 -0
  104. package/workflows/bds-disk-io-alert-investigation.js +173 -0
  105. package/workflows/bds-oncall-followup.js +112 -0
  106. package/workflows/bds-prism-service-proxy-timeout-investigation.js +69 -0
  107. package/workflows/bds-scylla-tenant-bucket-investigation.js +139 -0
  108. package/workflows/bds-tenant-data-operation-log-investigation.js +189 -0
  109. package/workflows/bds-yarn-app-health-investigation.js +217 -0
@@ -0,0 +1,321 @@
1
+ export const description = "Generate a atomic-helper, read-only BDS tenant data operation-log HDFS/source command pack that separates TSS tenant state from PRISM/BDS data evidence; does not SSH or inspect HDFS.";
2
+
3
+ import { z } from "zod";
4
+ import { defineReadOnlyTool, fail, ok } from "@nuvlore/extension-read-only-toolkit/devops-diagnostics";
5
+ import { ReadOnlyStep, remoteCommandInput, shellQuote } from "@nuvlore/extension-read-only-toolkit/read-only-command-pack";
6
+
7
+ const DEFAULT_CLUSTER = "BDS_DUB_NPRD1_AZ1";
8
+ const DEFAULT_DATANODE_HOST = "s-cz22240ms4.sys.az1.cust.dub.wd";
9
+ const DEFAULT_HDFS_AUTHORITY = "bdsdubnprd1az1";
10
+ const DEFAULT_TSS_BASE_URL = "http://balance-impl.env.az1.cust.dub.wd:17020";
11
+ const DEFAULT_SIRIUS_REPO_URL = "https://bitbucket.workday.com/projects/BDS/repos/sirius/browse";
12
+
13
+ const SAFETY_RULES = [
14
+ "read-only only: tenant status GET, hdfs crypto -listZones, and hdfs dfs list/read/test/du operations",
15
+ "do not equate TSS state RELEASED/OK with BDS or PRISM data readiness; verify the tenant data path directly",
16
+ "operation log path is data/tenants/<ENV_NAME>.<tenantName>/operationsLog.csv",
17
+ "expected BDS tenant data shape is operationsLog.csv, ted, and tmp; missing operationsLog.csv or tmp is strong evidence that PRISM/BDS data was not enable/clone-created",
18
+ "compare against related tenants such as preview, gold, or numbered tenants only as evidence, not as an automatic remediation",
19
+ "never print LDAP passwords, Keychain JSON, tokens, or sudo stdin",
20
+ "Keychain item may be JSON; extract only the top-level token field locally and pass it through stdin",
21
+ "never run hdfs dfs -rm, -put, -get, -cp, -mv, -mkdir, -touchz, -chmod, -chown, or any tenant state mutation"
22
+ ];
23
+
24
+ const BDS_OPERATION_LOG_SOURCE_NOTES = [
25
+ "Sirius BDM exposes operationLog routes such as /v2/bds/log/:envTenant and /api/v3/bds/log/:envTenant.",
26
+ "TenantDataManager builds the operation log path from the tenant base path plus operationsLog.csv.",
27
+ "If BDM HTTP routes return 403 from a jump host, inspect the same HDFS path from an authorized datanode or BDM pod."
28
+ ];
29
+
30
+ const clusterSchema = z
31
+ .string()
32
+ .min(1)
33
+ .max(128)
34
+ .regex(/^[A-Za-z0-9_.:-]+$/);
35
+
36
+ const hostSchema = z
37
+ .string()
38
+ .min(1)
39
+ .max(255)
40
+ .regex(/^(?!-)[a-zA-Z0-9._:@%-]+$/);
41
+
42
+ const pathNameSchema = z
43
+ .string()
44
+ .min(1)
45
+ .max(160)
46
+ .regex(/^[A-Za-z0-9_.-]+$/);
47
+
48
+ const hdfsAuthoritySchema = z
49
+ .string()
50
+ .min(1)
51
+ .max(128)
52
+ .regex(/^[A-Za-z0-9_.-]+$/);
53
+
54
+ const urlSchema = z
55
+ .string()
56
+ .trim()
57
+ .url()
58
+ .max(2048);
59
+
60
+ const relatedTenantSchema = z.array(pathNameSchema).max(12).default([]);
61
+
62
+ class BdsTenantDataOperationLogCommandPack {
63
+ constructor(input) {
64
+ this.cluster = input.cluster ?? DEFAULT_CLUSTER;
65
+ this.datanodeHost = input.datanodeHost ?? DEFAULT_DATANODE_HOST;
66
+ this.hdfsAuthority = input.hdfsAuthority ?? DEFAULT_HDFS_AUTHORITY;
67
+ this.environmentName = input.environmentName;
68
+ this.tenantName = input.tenantName;
69
+ this.relatedTenants = input.relatedTenants ?? [];
70
+ this.tssBaseUrl = input.tssBaseUrl ?? DEFAULT_TSS_BASE_URL;
71
+ this.siriusRepoUrl = input.siriusRepoUrl ?? DEFAULT_SIRIUS_REPO_URL;
72
+ }
73
+
74
+ envTenant() {
75
+ return `${this.environmentName}.${this.tenantName}`;
76
+ }
77
+
78
+ tenantHdfsPath(envTenant = this.envTenant()) {
79
+ return `hdfs://${this.hdfsAuthority}/data/tenants/${envTenant}`;
80
+ }
81
+
82
+ operationLogPath(envTenant = this.envTenant()) {
83
+ return `${this.tenantHdfsPath(envTenant)}/operationsLog.csv`;
84
+ }
85
+
86
+ allEnvTenants() {
87
+ return Array.from(new Set([this.envTenant(), ...this.relatedTenants]));
88
+ }
89
+
90
+ keychainSudoSnippet(command) {
91
+ return `mcp__devops-tool__workday_private_cloud_sudo_readonly_command ${JSON.stringify({
92
+ action: "run",
93
+ host: this.datanodeHost,
94
+ command,
95
+ humanApprovedSudoRead: true
96
+ })}`;
97
+ }
98
+
99
+ statusUrl() {
100
+ return `${this.tssBaseUrl}/tenant/${this.tenantName}?detail=true`;
101
+ }
102
+
103
+ sourceSearchCommand() {
104
+ return [
105
+ "Use bitbucket_api_read on /rest/api/latest/projects/BDS/repos/sirius, or perform an optional HITL local cache clone:",
106
+ "git clone --filter=blob:none https://bitbucket.workday.com/scm/BDS/sirius.git <local-cache>/bds-sirius",
107
+ "Then search read-only for: operationLog, operationLogPath, getOperationLogRaw, /api/v3/bds/log, /v2/bds/log, TenantDataManager"
108
+ ].join("\n");
109
+ }
110
+
111
+ operationLogCheckScript() {
112
+ const body = [
113
+ "set +e",
114
+ "echo HDFS_AUTHORITY " + shellQuote(this.hdfsAuthority),
115
+ "echo TARGET " + shellQuote(this.envTenant()),
116
+ "echo KLIST",
117
+ "klist 2>/dev/null | sed -n '1,3p'",
118
+ "echo CRYPTO_ZONES_MATCHING_TENANT",
119
+ `hdfs crypto -listZones 2>&1 | grep -E ${shellQuote(`/data/tenants/${this.environmentName}\\.${this.tenantName}($|/|[0-9]|_|-)`)} || true`,
120
+ "echo TENANT_PATH_SHAPE",
121
+ `hdfs dfs -ls ${shellQuote(this.tenantHdfsPath())} 2>&1 | sed -n '1,40p'`,
122
+ "echo TENANT_DU",
123
+ `hdfs dfs -du -h ${shellQuote(this.tenantHdfsPath())} 2>&1 | sed -n '1,40p'`,
124
+ "echo OPERATION_LOG",
125
+ `if hdfs dfs -test -e ${shellQuote(this.operationLogPath())}; then`,
126
+ ` hdfs dfs -du -h ${shellQuote(this.operationLogPath())};`,
127
+ ` hdfs dfs -tail ${shellQuote(this.operationLogPath())} | tail -80;`,
128
+ "else",
129
+ " echo operationsLog.csv MISSING;",
130
+ "fi"
131
+ ];
132
+ return body.join("\n");
133
+ }
134
+
135
+ comparisonCommands() {
136
+ return this.allEnvTenants().map((envTenant) => [
137
+ `echo ### ${envTenant}`,
138
+ `hdfs dfs -ls ${shellQuote(this.tenantHdfsPath(envTenant))} 2>&1 | sed -n '1,30p'`,
139
+ `if hdfs dfs -test -e ${shellQuote(this.operationLogPath(envTenant))}; then hdfs dfs -tail ${shellQuote(this.operationLogPath(envTenant))} | tail -20; else echo operationsLog.csv MISSING; fi`
140
+ ].join("\n")).join("\n\n");
141
+ }
142
+
143
+ mcpSafeRemoteCommands() {
144
+ return [
145
+ { label: "datanode-hostname", input: remoteCommandInput({ host: this.datanodeHost, command: "hostname -f" }) },
146
+ { label: "datanode-user", input: remoteCommandInput({ host: this.datanodeHost, command: "id" }) },
147
+ { label: "check-hdfs", input: remoteCommandInput({ host: this.datanodeHost, command: "command -v hdfs" }) },
148
+ { label: "kerberos-cache", input: remoteCommandInput({ host: this.datanodeHost, command: "klist" }) },
149
+ { label: "crypto-zones", input: remoteCommandInput({ host: this.datanodeHost, command: "hdfs crypto -listZones", timeoutMs: 120_000 }) },
150
+ { label: "tenant-list", input: remoteCommandInput({ host: this.datanodeHost, command: `hdfs dfs -ls ${shellQuote(this.tenantHdfsPath())}` }) },
151
+ { label: "tenant-du", input: remoteCommandInput({ host: this.datanodeHost, command: `hdfs dfs -du -h ${shellQuote(this.tenantHdfsPath())}` }) },
152
+ { label: "operation-log-exists", input: remoteCommandInput({ host: this.datanodeHost, command: `hdfs dfs -test -e ${shellQuote(this.operationLogPath())}` }) },
153
+ { label: "operation-log-tail", input: remoteCommandInput({ host: this.datanodeHost, command: `hdfs dfs -tail ${shellQuote(this.operationLogPath())}` }) }
154
+ ];
155
+ }
156
+
157
+ commands() {
158
+ return [
159
+ new ReadOnlyStep({
160
+ id: "00-source-route-map",
161
+ purpose: "Confirm where BDM expects tenant operation logs before interpreting HDFS path shape.",
162
+ command: this.sourceSearchCommand(),
163
+ expectedEvidence: "Sirius route and TenantDataManager code proving operationsLog.csv is under data/tenants/<ENV>.<tenant>/"
164
+ }),
165
+ new ReadOnlyStep({
166
+ id: "01-tss-status-is-not-bds-proof",
167
+ purpose: "Read tenant state from TSS/OMS while explicitly separating it from BDS/PRISM data readiness.",
168
+ command: `curl -s ${shellQuote(this.statusUrl())} | python3 -m json.tool`,
169
+ expectedEvidence: "state, health, releaseTime, and message; use only as TSS evidence, not BDS data evidence"
170
+ }),
171
+ new ReadOnlyStep({
172
+ id: "02-credential-handling",
173
+ purpose: "Use the approved Keychain LDAP item without printing secrets when sudo/root HDFS access is needed.",
174
+ command: this.keychainSudoSnippet("klist 2>/dev/null | sed -n '1,3p'"),
175
+ expectedEvidence: "root Kerberos principal only; no password, token, raw JSON, or sudo stdin"
176
+ }),
177
+ new ReadOnlyStep({
178
+ id: "03-target-operation-log",
179
+ purpose: "Check the exact target tenant data path, crypto zones, and operation log from a datanode.",
180
+ command: this.keychainSudoSnippet(this.operationLogCheckScript()),
181
+ expectedEvidence: "crypto-zone presence or absence, children under tenant path, du output, and operationsLog.csv tail or missing marker"
182
+ }),
183
+ new ReadOnlyStep({
184
+ id: "04-related-tenant-comparison",
185
+ purpose: "Compare the target path shape with preview/gold/numbered tenants to distinguish missing data creation from a general HDFS read issue.",
186
+ command: this.keychainSudoSnippet(this.comparisonCommands()),
187
+ expectedEvidence: "related tenant path shape and operation log entries such as prism Enable or Clone"
188
+ })
189
+ ];
190
+ }
191
+
192
+ antiPatterns() {
193
+ return [
194
+ {
195
+ command: "Assume RELEASED/OK means PRISM/BDS data is present.",
196
+ reason: "TSS/OMS release state and BDS HDFS tenant data are separate evidence domains."
197
+ },
198
+ {
199
+ command: `hdfs dfs -get ${this.tenantHdfsPath()}`,
200
+ reason: "Downloads tenant data to local disk; not needed for operation log inspection."
201
+ },
202
+ {
203
+ command: `hdfs dfs -rm ${this.tenantHdfsPath()}`,
204
+ reason: "Mutates tenant data and is outside read-only investigation scope."
205
+ },
206
+ {
207
+ command: "direct Keychain LDAP PROD password read",
208
+ reason: "Only the dedicated Workday login/sudo tools may read PROD password; do not call Keychain from command packs or agents."
209
+ }
210
+ ];
211
+ }
212
+
213
+ toMarkdown() {
214
+ return [
215
+ "# BDS Tenant Data Operation Log Read-Only Command Pack",
216
+ "",
217
+ `Cluster: ${this.cluster}`,
218
+ `Datanode host: ${this.datanodeHost}`,
219
+ `HDFS authority: ${this.hdfsAuthority}`,
220
+ `Environment: ${this.environmentName}`,
221
+ `Tenant: ${this.tenantName}`,
222
+ `Env tenant: ${this.envTenant()}`,
223
+ `Tenant data path: \`${this.tenantHdfsPath()}\``,
224
+ `Operation log: \`${this.operationLogPath()}\``,
225
+ `TSS URL: ${this.statusUrl()}`,
226
+ `Sirius repo: ${this.siriusRepoUrl}`,
227
+ "",
228
+ "## Source Notes",
229
+ "",
230
+ ...BDS_OPERATION_LOG_SOURCE_NOTES.map((note) => `- ${note}`),
231
+ "",
232
+ "## Safety Boundary",
233
+ "",
234
+ ...SAFETY_RULES.map((rule) => `- ${rule}`),
235
+ "",
236
+ "## Read-Only Commands",
237
+ "",
238
+ ...this.commands().map((command) => command.toMarkdown()),
239
+ "",
240
+ "## MCP-Safe Remote Reads",
241
+ "",
242
+ "These are single-command read-only probes for `remote_readonly_command`. Run credential setup separately when needed.",
243
+ "",
244
+ ...this.mcpSafeRemoteCommands().map((item) => `- ${item.label}: \`${item.input.command}\``),
245
+ "",
246
+ "## Do Not Use",
247
+ "",
248
+ ...this.antiPatterns().map((entry) => `- \`${entry.command}\`: ${entry.reason}`),
249
+ "",
250
+ "Procedure, interpretation, and output shape live in the `bds-tenant-data-operation-log-investigation` skill."
251
+ ].join("\n");
252
+ }
253
+
254
+ toJson() {
255
+ return {
256
+ cluster: this.cluster,
257
+ datanodeHost: this.datanodeHost,
258
+ hdfsAuthority: this.hdfsAuthority,
259
+ environmentName: this.environmentName,
260
+ tenantName: this.tenantName,
261
+ envTenant: this.envTenant(),
262
+ tenantDataPath: this.tenantHdfsPath(),
263
+ operationLogPath: this.operationLogPath(),
264
+ relatedTenants: this.relatedTenants,
265
+ tssUrl: this.statusUrl(),
266
+ siriusRepoUrl: this.siriusRepoUrl,
267
+ expectedTenantChildren: ["operationsLog.csv", "ted", "tmp"],
268
+ sourceNotes: BDS_OPERATION_LOG_SOURCE_NOTES,
269
+ safetyBoundary: SAFETY_RULES,
270
+ commands: this.commands().map((command) => command.toJson()),
271
+ mcpSafeRemoteCommands: this.mcpSafeRemoteCommands(),
272
+ antiPatterns: this.antiPatterns()
273
+ };
274
+ }
275
+ }
276
+
277
+ function buildResponse(input) {
278
+ const commandPack = new BdsTenantDataOperationLogCommandPack(input);
279
+ if (input.format === "json") {
280
+ return JSON.stringify(commandPack.toJson(), null, 2);
281
+ }
282
+ return commandPack.toMarkdown();
283
+ }
284
+
285
+ const sharedTool = defineReadOnlyTool({
286
+ name: "bds_tenant_data_operation_log_command_pack",
287
+ description: "Generate a atomic-helper, read-only BDS tenant data operation-log HDFS/source command pack that separates TSS tenant state from PRISM/BDS data evidence; does not SSH or inspect HDFS.",
288
+ meta: {
289
+ permissions: { rule: "ask" },
290
+ secret_provider: "keychain"
291
+ },
292
+ inputSchema: {
293
+ cluster: clusterSchema.default(DEFAULT_CLUSTER),
294
+ datanodeHost: hostSchema.default(DEFAULT_DATANODE_HOST),
295
+ hdfsAuthority: hdfsAuthoritySchema.default(DEFAULT_HDFS_AUTHORITY),
296
+ environmentName: pathNameSchema.describe("Tenant environment name, for example WD3-IMPL."),
297
+ tenantName: pathNameSchema.describe("Tenant name without environment prefix, for example chloe."),
298
+ relatedTenants: relatedTenantSchema.describe("Optional envTenant names for comparison, for example WD3-IMPL.chloe_preview."),
299
+ tssBaseUrl: urlSchema.default(DEFAULT_TSS_BASE_URL),
300
+ siriusRepoUrl: urlSchema.default(DEFAULT_SIRIUS_REPO_URL),
301
+ format: z.enum(["markdown", "json"]).default("markdown")
302
+ },
303
+ annotations: { openWorldHint: true },
304
+ async handler(input) {
305
+ try {
306
+ return ok(buildResponse(input));
307
+ } catch (error) {
308
+ return fail(error);
309
+ }
310
+ }
311
+ });
312
+
313
+ export default {
314
+ name: sharedTool.name,
315
+ description,
316
+ inputSchema: sharedTool.inputSchema,
317
+ meta: sharedTool.meta,
318
+ annotations: sharedTool.annotations,
319
+ invoke: sharedTool.invoke,
320
+ handler: sharedTool.handler
321
+ };