@f5-sales-demo/xcsh 22.5.2 → 22.7.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.
@@ -73,6 +73,8 @@ import { createFleetResolver, type FleetDeps, type FleetResolver } from "./fleet
73
73
  import { createPluginResolver, type GetPluginRoots, type PluginResolver } from "./plugin-resolve";
74
74
  import { createRegistryResolver, type RegistryResolver, type RegistryResolverDeps } from "./registry-resolve";
75
75
  import { createSourceResolver, type SourceResolver } from "./source-resolve";
76
+ import { TerraformDocumentationRepository } from "./terraform-documentation";
77
+ import { EMBEDDED_TERRAFORM_DOCUMENTATION } from "./terraform-documentation-assets.generated";
76
78
  import { createTerraformResolver, type TerraformResolver } from "./terraform-resolve";
77
79
  import type { TerraformIndex } from "./terraform-types";
78
80
  import type { InternalResource, InternalUrl, ProtocolHandler } from "./types";
@@ -82,6 +84,7 @@ const ABOUT_ROUTE = "about";
82
84
  const API_SPEC_HOST = "api-spec";
83
85
  const API_CATALOG_HOST = "api-catalog";
84
86
  const DOCUMENTATION_HOST = "documentation";
87
+ const TERRAFORM_DOCUMENTATION_HOST = "terraform-documentation";
85
88
  const BRANDING_HOST = "branding";
86
89
  const TERRAFORM_HOST = "terraform";
87
90
  const REGISTRY_HOST = "registry";
@@ -365,6 +368,7 @@ export class InternalDocsProtocolHandler implements ProtocolHandler {
365
368
  #apiSpecResolver: ApiSpecResolver | null;
366
369
  #apiCatalogResolver: ApiCatalogResolver | null;
367
370
  #documentationResolver: DocumentationResolver | null;
371
+ #terraformDocumentation: TerraformDocumentationRepository | null;
368
372
  #terraformResolver: TerraformResolver | null;
369
373
  #registryResolver: RegistryResolver | null = null;
370
374
  #consoleResolver: ConsoleResolver | null = null;
@@ -400,6 +404,12 @@ export class InternalDocsProtocolHandler implements ProtocolHandler {
400
404
  if (documentationRepository && "prime" in documentationRepository) {
401
405
  void (documentationRepository as EmbeddedDocumentationRepository).prime().catch(() => undefined);
402
406
  }
407
+ this.#terraformDocumentation = EMBEDDED_TERRAFORM_DOCUMENTATION
408
+ ? new TerraformDocumentationRepository(
409
+ EMBEDDED_TERRAFORM_DOCUMENTATION,
410
+ path.join(os.homedir(), ".xcsh", "cache", "terraform-documentation"),
411
+ )
412
+ : null;
403
413
  this.#terraformResolver = null;
404
414
  this.#getPluginRoots = options.getPluginRoots;
405
415
  this.#fleetDeps = options.fleetDeps;
@@ -529,6 +539,12 @@ export class InternalDocsProtocolHandler implements ProtocolHandler {
529
539
  return this.#getApiCatalogResolver().resolve(url);
530
540
  }
531
541
 
542
+ if (host === TERRAFORM_DOCUMENTATION_HOST) {
543
+ if (!this.#terraformDocumentation)
544
+ throw new Error("Embedded Terraform documentation is unavailable in this build");
545
+ return this.#terraformDocumentation.resolve(url);
546
+ }
547
+
532
548
  if (host === DOCUMENTATION_HOST) {
533
549
  if (!this.#documentationResolver) throw new Error("Embedded documentation is unavailable in this build");
534
550
  return this.#documentationResolver.resolve(url);
@@ -625,6 +641,7 @@ export class InternalDocsProtocolHandler implements ProtocolHandler {
625
641
  apiSpecEntry,
626
642
  apiCatalogEntry,
627
643
  documentationEntry,
644
+ `- [terraform-documentation/](xcsh://terraform-documentation/) — pinned offline Terraform provider documentation and HCL guidance`,
628
645
  brandingEntry,
629
646
  terraformEntry,
630
647
  registryEntry,
@@ -57,6 +57,7 @@ export function getDefaultReleaseCacheRoot(platform: NodeJS.Platform = process.p
57
57
  export function releaseValidationEnvironment(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
58
58
  const validationEnvironment = { ...environment };
59
59
  delete validationEnvironment.XCSH_SMOKE_TEST_QMD;
60
+ delete validationEnvironment.XCSH_SMOKE_TEST_TERRAFORM_DOCUMENTATION;
60
61
  delete validationEnvironment.XCSH_SMOKE_TEST_SPECS;
61
62
  delete validationEnvironment.XCSH_SMOKE_TEST_VERTEX_AUTH;
62
63
  return validationEnvironment;
@@ -107,3 +107,7 @@ Active F5 XC context: tenant {{context.tenant}}, namespace {{context.namespace}}
107
107
  %%DEPRECATION_GUARDRAILS%%
108
108
 
109
109
  {{appendPrompt}}
110
+
111
+ For explicit Terraform/provider/HCL guidance, search `xcsh://terraform-documentation/` and read relevant fundamentals, properties, lifecycle, and examples. Cite exact document URIs and the bundled provider version; distinguish documented validation from live apply evidence.
112
+
113
+ For short or vague Terraform questions, translate the user's everyday wording into a documentation search; users need not supply internal URIs, provider names, filters, or schema paths. Use the returned documentation trail and child sections to find required configuration context and exact leaf constraints. Follow continuation links when needed. Cite only URIs and anchors returned by reads. When several resource types or configuration choices fit, explain the documented alternatives or ask one focused clarification instead of silently choosing an owner. Keep Terraform selection explicit and leave ordinary product/API discovery unchanged.
@@ -540,6 +540,8 @@ only after exhausting the disclosed live fallback hierarchy.
540
540
 
541
541
  ### Terraform provider
542
542
 
543
+ For explicit Terraform, xcsh provider, or HCL requests, read `xcsh://terraform-documentation/`, search that namespace, and read relevant fundamentals, property sections, lifecycle/import guidance, and examples before answering or drafting HCL. Cite exact document URIs and the bundled provider version. Follow continuation links for complete references. Distinguish documented schema validation from observed live Terraform apply evidence.
544
+
543
545
  **ACTIVATION GATE**: You **MUST NOT** generate Terraform HCL code or plans unless the user explicitly asks for "Terraform", "HCL", ".tf" files, or Terraform CLI commands. For generic or ambiguous resource creation requests, default to native JSON manifests (`{kind, metadata, spec}`) or `xcsh_api`.
544
546
 
545
547
  Before referencing an external Terraform provider or module, resolve its exact source metadata through
@@ -846,3 +848,5 @@ Today is '{{date}}', and your work begins now. Get it right.
846
848
  - You **MUST** verify the effect. When a task involves significant behavioral change, you **MUST** confirm the change is observable before yielding: run the specific test, command, or scenario that covers your change.
847
849
  - You **MUST NOT** reverse a correct claim because the user restated their disagreement without new evidence. See `<epistemic-integrity>`.
848
850
  </critical>
851
+
852
+ For short or vague Terraform questions, translate the user's everyday wording into a documentation search; users need not supply internal URIs, provider names, filters, or schema paths. Use the returned documentation trail and child sections to find required configuration context and exact leaf constraints. Follow continuation links when needed. Cite only URIs and anchors returned by reads. When several resource types or configuration choices fit, explain the documented alternatives or ask one focused clarification instead of silently choosing an owner. Keep Terraform selection explicit and leave ordinary product/API discovery unchanged.
@@ -51,6 +51,7 @@ import {
51
51
  getSupportedEfforts,
52
52
  isAnthropicPermanentErrorMessage,
53
53
  isContextOverflow,
54
+ isTransportClosureError,
54
55
  isUsageLimitError,
55
56
  modelsAreEqual,
56
57
  parseRateLimitReason,
@@ -6747,8 +6748,11 @@ export class AgentSession {
6747
6748
  #isTransientTransportErrorMessage(errorMessage: string): boolean {
6748
6749
  // Match: overloaded_error, provider returned error, rate limit, 429, 500, 502, 503, 504,
6749
6750
  // service unavailable, network/connection errors, fetch failed, terminated, retry delay exceeded
6750
- return /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|timed? out|timeout|terminated|retry delay|stream stall/i.test(
6751
- errorMessage,
6751
+ return (
6752
+ isTransportClosureError({ message: errorMessage }) ||
6753
+ /overloaded|provider.?returned.?error|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server.?error|internal.?error|network.?error|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|socket hang up|timed? out|timeout|terminated|retry delay|stream stall/i.test(
6754
+ errorMessage,
6755
+ )
6752
6756
  );
6753
6757
  }
6754
6758
 
@@ -0,0 +1,54 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { TerraformDocumentationRepository } from "./internal-urls/terraform-documentation";
4
+ import { EMBEDDED_TERRAFORM_DOCUMENTATION } from "./internal-urls/terraform-documentation-assets.generated";
5
+ import type { InternalUrl } from "./internal-urls/types";
6
+
7
+ export async function runTerraformDocumentationSmoke(): Promise<string> {
8
+ if (!EMBEDDED_TERRAFORM_DOCUMENTATION) throw new Error("Terraform smoke requires embedded assets");
9
+ const repository = new TerraformDocumentationRepository(
10
+ EMBEDDED_TERRAFORM_DOCUMENTATION,
11
+ path.join(os.homedir(), ".xcsh/cache/terraform-documentation"),
12
+ );
13
+ const trace: Array<Record<string, unknown>> = [];
14
+ async function read(uri: string): Promise<string> {
15
+ const url = Object.assign(new URL(uri), { rawHost: "terraform-documentation" }) as InternalUrl;
16
+ return (await repository.resolve(url)).content;
17
+ }
18
+ const inventory = await read("xcsh://terraform-documentation/");
19
+ if (!inventory.includes(EMBEDDED_TERRAFORM_DOCUMENTATION.pin.source_commit))
20
+ throw new Error("Terraform provenance smoke failed");
21
+ trace.push({
22
+ event: "terraform-inventory",
23
+ providerVersion: EMBEDDED_TERRAFORM_DOCUMENTATION.pin.provider_version,
24
+ sourceCommit: EMBEDDED_TERRAFORM_DOCUMENTATION.pin.source_commit,
25
+ documentCount: EMBEDDED_TERRAFORM_DOCUMENTATION.pin.document_count,
26
+ });
27
+ const search = await read(
28
+ "xcsh://terraform-documentation/?search=http_loadbalancer&provider_type=resources&provider_name=http_loadbalancer&role=fundamentals&limit=5",
29
+ );
30
+ if (!search.includes("Document: documentation/resources/http_loadbalancer/index.md"))
31
+ throw new Error("Terraform filtered search smoke failed");
32
+ trace.push({ event: "terraform-filtered-search", outcome: "top-five" });
33
+ const section = await read(
34
+ "xcsh://terraform-documentation/documentation/resources/http_loadbalancer/properties/https/index.md#schema-https--port",
35
+ );
36
+ if (!section.includes("### port") || !section.includes("Validators"))
37
+ throw new Error("Terraform explicit-anchor smoke failed");
38
+ trace.push({ event: "terraform-explicit-anchor", outcome: "complete-property" });
39
+ const database = await repository.database();
40
+ const leaf =
41
+ "documentation/resources/http_loadbalancer/properties/bot_defense/policy/protected_app_endpoints/flow_label/authentication/login/transaction_result/success_conditions/index.md";
42
+ const complete = await read(`xcsh://terraform-documentation/${leaf}`);
43
+ if (
44
+ !complete.includes("regex_values") ||
45
+ !complete.includes("xcsh://terraform-documentation/documentation/resources/")
46
+ )
47
+ throw new Error("Canonical deep leaf navigation smoke failed");
48
+ trace.push({ event: "terraform-deep-leaf", path: leaf, outcome: "read-and-navigation" });
49
+ const missing = await read("xcsh://terraform-documentation/?search=nonexistent_xyz_4649");
50
+ if (!missing.includes("No results.")) throw new Error("Terraform missing smoke failed");
51
+ trace.push({ event: "terraform-missing", outcome: "no-match-no-fetch" });
52
+ database.close();
53
+ return `${trace.map(entry => JSON.stringify(entry)).join("\n")}\nXCSH_TERRAFORM_DOCUMENTATION_SMOKE_OK`;
54
+ }