@fjall/ai-tools 2.18.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 (39) hide show
  1. package/LICENSE +50 -0
  2. package/README.md +19 -0
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.js +3 -0
  5. package/dist/registry.d.ts +12 -0
  6. package/dist/registry.js +47 -0
  7. package/dist/schemas/compareDeployments.d.ts +6 -0
  8. package/dist/schemas/compareDeployments.js +9 -0
  9. package/dist/schemas/explainError.d.ts +8 -0
  10. package/dist/schemas/explainError.js +21 -0
  11. package/dist/schemas/getOrganisationOverview.d.ts +10 -0
  12. package/dist/schemas/getOrganisationOverview.js +15 -0
  13. package/dist/schemas/index.d.ts +14 -0
  14. package/dist/schemas/index.js +14 -0
  15. package/dist/schemas/manageDomain.d.ts +9 -0
  16. package/dist/schemas/manageDomain.js +8 -0
  17. package/dist/schemas/manageSecret.d.ts +15 -0
  18. package/dist/schemas/manageSecret.js +26 -0
  19. package/dist/schemas/provisionRegion.d.ts +6 -0
  20. package/dist/schemas/provisionRegion.js +12 -0
  21. package/dist/schemas/queryCompliance.d.ts +21 -0
  22. package/dist/schemas/queryCompliance.js +23 -0
  23. package/dist/schemas/queryCosts.d.ts +16 -0
  24. package/dist/schemas/queryCosts.js +34 -0
  25. package/dist/schemas/queryInfrastructure.d.ts +14 -0
  26. package/dist/schemas/queryInfrastructure.js +24 -0
  27. package/dist/schemas/queryMetrics.d.ts +13 -0
  28. package/dist/schemas/queryMetrics.js +23 -0
  29. package/dist/schemas/renderChart.d.ts +40 -0
  30. package/dist/schemas/renderChart.js +45 -0
  31. package/dist/schemas/suggestRemediation.d.ts +11 -0
  32. package/dist/schemas/suggestRemediation.js +16 -0
  33. package/dist/schemas/triggerDeployment.d.ts +7 -0
  34. package/dist/schemas/triggerDeployment.js +14 -0
  35. package/dist/schemas/updateConfiguration.d.ts +8 -0
  36. package/dist/schemas/updateConfiguration.js +27 -0
  37. package/dist/types.d.ts +25 -0
  38. package/dist/types.js +23 -0
  39. package/package.json +54 -0
package/LICENSE ADDED
@@ -0,0 +1,50 @@
1
+ Fjall Proprietary Software Licence
2
+
3
+ Copyright (c) 2026 Fjall. All rights reserved.
4
+
5
+ This software, including all source, object, bundled, and minified forms
6
+ ("the Software"), is the proprietary and confidential property of Fjall.
7
+
8
+ 1. Permitted Use. Subject to the terms of this Licence, Fjall grants you
9
+ a non-exclusive, non-transferable, revocable licence to install the
10
+ Software via the npm registry and to execute it solely for the purpose
11
+ of deploying, operating, and managing your own applications and
12
+ infrastructure on cloud providers.
13
+
14
+ 2. Restrictions. You may NOT, and may not permit any third party to:
15
+ (a) copy, redistribute, sublicense, sell, rent, lease, or otherwise
16
+ transfer the Software;
17
+ (b) modify, adapt, translate, or create derivative works of the Software;
18
+ (c) reverse engineer, decompile, disassemble, deminify, or otherwise
19
+ attempt to derive the source code, structure, or organisation of
20
+ the Software, except to the minimum extent expressly permitted by
21
+ applicable mandatory law;
22
+ (d) use the Software, or any portion of it, to develop, train, or
23
+ improve any product or service that competes with Fjall;
24
+ (e) remove, alter, or obscure any proprietary notices contained in
25
+ the Software;
26
+ (f) publish, share, or otherwise disclose the Software or its contents
27
+ to any third party.
28
+
29
+ 3. Ownership. All right, title, and interest in and to the Software,
30
+ including all intellectual property rights, remain with Fjall. No
31
+ rights are granted except as expressly set out in this Licence.
32
+
33
+ 4. Termination. This Licence terminates automatically if you breach any
34
+ of its terms. Upon termination you must cease all use of the Software
35
+ and destroy all copies in your possession.
36
+
37
+ 5. Disclaimer of Warranty. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT
38
+ WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
39
+ THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
40
+ AND NON-INFRINGEMENT.
41
+
42
+ 6. Limitation of Liability. IN NO EVENT SHALL FJALL BE LIABLE FOR ANY
43
+ INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES
44
+ ARISING OUT OF OR RELATED TO THE SOFTWARE, EVEN IF ADVISED OF THE
45
+ POSSIBILITY OF SUCH DAMAGES.
46
+
47
+ 7. Governing Law. This Licence is governed by the laws of England and
48
+ Wales, without regard to conflict of laws principles.
49
+
50
+ For commercial licensing enquiries, contact: contact@fjall.io
package/README.md ADDED
@@ -0,0 +1,19 @@
1
+ # @fjall/ai-tools
2
+
3
+ Shared AI tool schemas and registry used by the Fjall webapp AI assistant and `@fjall/cli`. Defines the Zod schemas, tool definitions, and routing primitives that keep model-facing tool contracts identical across both surfaces.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @fjall/ai-tools
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { toolRegistry } from "@fjall/ai-tools";
15
+ ```
16
+
17
+ ## Licence
18
+
19
+ Proprietary — see [LICENSE](./LICENSE).
@@ -0,0 +1,4 @@
1
+ export type { ToolTier, ToolSpec, AiToolName } from "./types.js";
2
+ export { AI_TOOL_NAMES } from "./types.js";
3
+ export { AI_TOOL_REGISTRY, getToolSpec } from "./registry.js";
4
+ export * from "./schemas/index.js";
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { AI_TOOL_NAMES } from "./types.js";
2
+ export { AI_TOOL_REGISTRY, getToolSpec } from "./registry.js";
3
+ export * from "./schemas/index.js";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Tool registry — metadata and schemas for all AI tools.
3
+ *
4
+ * This is the single source of truth for tool names, descriptions, tiers,
5
+ * and input schemas. The webapp imports these to build the Anthropic API
6
+ * tool array; the CLI imports them for AXI input validation.
7
+ */
8
+ import type { ToolSpec } from "./types.js";
9
+ /** All AI tool specifications, ordered: read tools first, then write tools. */
10
+ export declare const AI_TOOL_REGISTRY: readonly ToolSpec[];
11
+ /** Look up a tool spec by name. */
12
+ export declare function getToolSpec(name: string): ToolSpec | undefined;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Tool registry — metadata and schemas for all AI tools.
3
+ *
4
+ * This is the single source of truth for tool names, descriptions, tiers,
5
+ * and input schemas. The webapp imports these to build the Anthropic API
6
+ * tool array; the CLI imports them for AXI input validation.
7
+ */
8
+ import { queryInfrastructureSchema } from "./schemas/queryInfrastructure.js";
9
+ import { queryComplianceSchema } from "./schemas/queryCompliance.js";
10
+ import { queryCostsSchema } from "./schemas/queryCosts.js";
11
+ import { queryMetricsSchema } from "./schemas/queryMetrics.js";
12
+ import { getOrganisationOverviewSchema } from "./schemas/getOrganisationOverview.js";
13
+ import { explainErrorSchema } from "./schemas/explainError.js";
14
+ import { compareDeploymentsSchema } from "./schemas/compareDeployments.js";
15
+ import { suggestRemediationSchema } from "./schemas/suggestRemediation.js";
16
+ import { renderChartSchema } from "./schemas/renderChart.js";
17
+ import { triggerDeploymentSchema } from "./schemas/triggerDeployment.js";
18
+ import { manageSecretSchema } from "./schemas/manageSecret.js";
19
+ import { updateConfigurationSchema } from "./schemas/updateConfiguration.js";
20
+ import { manageDomainSchema } from "./schemas/manageDomain.js";
21
+ import { provisionRegionSchema } from "./schemas/provisionRegion.js";
22
+ function spec(name, description, inputSchema, tier, requiredRole) {
23
+ return { name, description, inputSchema, tier, requiredRole };
24
+ }
25
+ /** All AI tool specifications, ordered: read tools first, then write tools. */
26
+ export const AI_TOOL_REGISTRY = [
27
+ // ── Read tools ──────────────────────────────────────────────────
28
+ spec("query_infrastructure", "Query infrastructure entities: applications, deployments, assets, or connected AWS accounts. Set `entity` to choose what to query. Optionally pass `id` to fetch a single record, or use filters like `applicationId` and `status` for deployments. Accounts exclude sensitive credential fields.", queryInfrastructureSchema, "read"),
29
+ spec("query_compliance", "Query compliance data. Use `mode: issues` to list findings with optional severity/status filters, `mode: counts` for a breakdown of open issues by severity, or `mode: summary` for the compliance score, total open issues, and last scan time.", queryComplianceSchema, "read"),
30
+ spec("query_costs", "Query AWS cost data for the organisation. Supports summary, trend, forecast, attribution, per-request, per-deployment, and month-to-date modes.", queryCostsSchema, "read"),
31
+ spec("query_metrics", "Query application metrics from ClickHouse. Supports time-series, latest snapshot, hourly sparklines, and org-wide summary modes.", queryMetricsSchema, "read"),
32
+ spec("get_organisation_overview", "Get a comprehensive organisation overview combining stats, compliance, cost summary, and deployment velocity. Supports selecting specific sections for faster responses.", getOrganisationOverviewSchema, "read"),
33
+ spec("explain_error", "Cross-reference logs, error fingerprints, and deployments to explain an error. Returns error fingerprints with AI summaries, optionally correlated with a deployment and matching log entries.", explainErrorSchema, "read"),
34
+ spec("compare_deployments", "Compare two deployments side-by-side including status, duration, branch, commit, and metric deltas (CPU, memory, error rate, response time) from 1-hour windows around each deployment.", compareDeploymentsSchema, "read"),
35
+ spec("suggest_remediation", "Gather context from a specific domain (compliance, cost, or performance) so the LLM can generate targeted remediation advice. Returns structured data about the most pressing issues in the chosen domain.", suggestRemediationSchema, "read"),
36
+ spec("render_chart", "Render a chart in the chat. Use this after gathering data from other tools to visualise trends, comparisons, or distributions. Supported kinds: timeseries (line chart with time x-axis), bar (vertical/horizontal bars), categoryBar (single-axis categorical bar). Pass the chart configuration with data points.", renderChartSchema, "read"),
37
+ // ── Write tools (require confirmation gate) ─────────────────────
38
+ spec("trigger_deployment", "Trigger a new deployment for an application. Verifies the application exists, has a connected AWS account and repository, and no active deployment is running. Creates a deployment record and enqueues it for processing.", triggerDeploymentSchema, "write", "admin"),
39
+ spec("manage_secret", "Manage application secrets stored in AWS SSM Parameter Store. Supports: list (show secret names without values), set (create or update), and delete. Never exposes secret values — the get operation is intentionally excluded.", manageSecretSchema, "write", "admin"),
40
+ spec("update_configuration", "Update an application's configuration — name, description, or config path. Only safe, non-security-sensitive fields can be changed. At least one field must be provided.", updateConfigurationSchema, "write", "admin"),
41
+ spec("manage_domain", "Manage custom domains for your applications. Currently supports listing connected environments/accounts. Add and remove operations direct users to the settings page for manual configuration.", manageDomainSchema, "read"),
42
+ spec("provision_region", "Add an AWS region to the organisation and deploy infrastructure to it. Shows a consequence preview (affected accounts, deployment shape) before asking the user to confirm. Requires admin role.", provisionRegionSchema, "write", "admin"),
43
+ ];
44
+ /** Look up a tool spec by name. */
45
+ export function getToolSpec(name) {
46
+ return AI_TOOL_REGISTRY.find((t) => t.name === name);
47
+ }
@@ -0,0 +1,6 @@
1
+ import { z } from "zod";
2
+ export declare const compareDeploymentsSchema: z.ZodObject<{
3
+ deploymentIdA: z.ZodString;
4
+ deploymentIdB: z.ZodString;
5
+ }, z.core.$strict>;
6
+ export type CompareDeploymentsInput = z.infer<typeof compareDeploymentsSchema>;
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export const compareDeploymentsSchema = z
3
+ .object({
4
+ deploymentIdA: z.string().describe("First deployment ID (typically older)"),
5
+ deploymentIdB: z
6
+ .string()
7
+ .describe("Second deployment ID (typically newer)"),
8
+ })
9
+ .strict();
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ export declare const explainErrorSchema: z.ZodObject<{
3
+ applicationId: z.ZodString;
4
+ errorPattern: z.ZodOptional<z.ZodString>;
5
+ deploymentId: z.ZodOptional<z.ZodString>;
6
+ hours: z.ZodOptional<z.ZodNumber>;
7
+ }, z.core.$strict>;
8
+ export type ExplainErrorInput = z.infer<typeof explainErrorSchema>;
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ export const explainErrorSchema = z
3
+ .object({
4
+ applicationId: z.string().describe("Application experiencing the error"),
5
+ errorPattern: z
6
+ .string()
7
+ .optional()
8
+ .describe("Error message or pattern to search for"),
9
+ deploymentId: z
10
+ .string()
11
+ .optional()
12
+ .describe("Deployment that may have introduced the error"),
13
+ hours: z
14
+ .number()
15
+ .int()
16
+ .min(1)
17
+ .max(168)
18
+ .optional()
19
+ .describe("Lookback window in hours (default 24)"),
20
+ })
21
+ .strict();
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+ export declare const getOrganisationOverviewSchema: z.ZodObject<{
3
+ sections: z.ZodOptional<z.ZodArray<z.ZodEnum<{
4
+ stats: "stats";
5
+ compliance: "compliance";
6
+ costs: "costs";
7
+ deployments: "deployments";
8
+ }>>>;
9
+ }, z.core.$strict>;
10
+ export type GetOrganisationOverviewInput = z.infer<typeof getOrganisationOverviewSchema>;
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ const OVERVIEW_SECTIONS = [
3
+ "stats",
4
+ "compliance",
5
+ "costs",
6
+ "deployments",
7
+ ];
8
+ export const getOrganisationOverviewSchema = z
9
+ .object({
10
+ sections: z
11
+ .array(z.enum(OVERVIEW_SECTIONS))
12
+ .optional()
13
+ .describe("Which sections to include (default: all). Omit sections for faster response."),
14
+ })
15
+ .strict();
@@ -0,0 +1,14 @@
1
+ export { queryInfrastructureSchema, type QueryInfrastructureInput, } from "./queryInfrastructure.js";
2
+ export { queryComplianceSchema, type QueryComplianceInput, } from "./queryCompliance.js";
3
+ export { queryCostsSchema, type QueryCostsInput } from "./queryCosts.js";
4
+ export { queryMetricsSchema, type QueryMetricsInput } from "./queryMetrics.js";
5
+ export { getOrganisationOverviewSchema, type GetOrganisationOverviewInput, } from "./getOrganisationOverview.js";
6
+ export { explainErrorSchema, type ExplainErrorInput } from "./explainError.js";
7
+ export { compareDeploymentsSchema, type CompareDeploymentsInput, } from "./compareDeployments.js";
8
+ export { suggestRemediationSchema, type SuggestRemediationInput, } from "./suggestRemediation.js";
9
+ export { renderChartSchema, type RenderChartInput } from "./renderChart.js";
10
+ export { triggerDeploymentSchema, type TriggerDeploymentInput, } from "./triggerDeployment.js";
11
+ export { manageSecretSchema, type ManageSecretInput } from "./manageSecret.js";
12
+ export { updateConfigurationSchema, type UpdateConfigurationInput, } from "./updateConfiguration.js";
13
+ export { manageDomainSchema, type ManageDomainInput } from "./manageDomain.js";
14
+ export { provisionRegionSchema, type ProvisionRegionInput, } from "./provisionRegion.js";
@@ -0,0 +1,14 @@
1
+ export { queryInfrastructureSchema, } from "./queryInfrastructure.js";
2
+ export { queryComplianceSchema, } from "./queryCompliance.js";
3
+ export { queryCostsSchema } from "./queryCosts.js";
4
+ export { queryMetricsSchema } from "./queryMetrics.js";
5
+ export { getOrganisationOverviewSchema, } from "./getOrganisationOverview.js";
6
+ export { explainErrorSchema } from "./explainError.js";
7
+ export { compareDeploymentsSchema, } from "./compareDeployments.js";
8
+ export { suggestRemediationSchema, } from "./suggestRemediation.js";
9
+ export { renderChartSchema } from "./renderChart.js";
10
+ export { triggerDeploymentSchema, } from "./triggerDeployment.js";
11
+ export { manageSecretSchema } from "./manageSecret.js";
12
+ export { updateConfigurationSchema, } from "./updateConfiguration.js";
13
+ export { manageDomainSchema } from "./manageDomain.js";
14
+ export { provisionRegionSchema, } from "./provisionRegion.js";
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export declare const manageDomainSchema: z.ZodObject<{
3
+ operation: z.ZodEnum<{
4
+ list: "list";
5
+ add: "add";
6
+ remove: "remove";
7
+ }>;
8
+ }, z.core.$strict>;
9
+ export type ManageDomainInput = z.infer<typeof manageDomainSchema>;
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ export const manageDomainSchema = z
3
+ .object({
4
+ operation: z
5
+ .enum(["list", "add", "remove"])
6
+ .describe("list: show configured environments/accounts; add/remove: redirects to settings page"),
7
+ })
8
+ .strict();
@@ -0,0 +1,15 @@
1
+ import { z } from "zod";
2
+ export declare const manageSecretSchema: z.ZodObject<{
3
+ operation: z.ZodEnum<{
4
+ set: "set";
5
+ delete: "delete";
6
+ list: "list";
7
+ }>;
8
+ applicationId: z.ZodString;
9
+ app: z.ZodString;
10
+ cluster: z.ZodOptional<z.ZodString>;
11
+ service: z.ZodOptional<z.ZodString>;
12
+ name: z.ZodOptional<z.ZodString>;
13
+ value: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$strict>;
15
+ export type ManageSecretInput = z.infer<typeof manageSecretSchema>;
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ export const manageSecretSchema = z
3
+ .object({
4
+ operation: z
5
+ .enum(["set", "delete", "list"])
6
+ .describe("Operation to perform. Note: get is intentionally omitted — secret values are never exposed."),
7
+ applicationId: z
8
+ .string()
9
+ .describe("The application whose AWS account holds the secrets"),
10
+ app: z
11
+ .string()
12
+ .min(1)
13
+ .describe("SSM namespace app component (e.g. application name)"),
14
+ cluster: z.string().optional().describe("SSM namespace cluster component"),
15
+ service: z.string().optional().describe("SSM namespace service component"),
16
+ name: z
17
+ .string()
18
+ .optional()
19
+ .describe("Secret name (required for set and delete operations)"),
20
+ value: z
21
+ .string()
22
+ .max(4096)
23
+ .optional()
24
+ .describe("Secret value (required for set operation)"),
25
+ })
26
+ .strict();
@@ -0,0 +1,6 @@
1
+ import { z } from "zod";
2
+ export declare const provisionRegionSchema: z.ZodObject<{
3
+ region: z.ZodString;
4
+ connectedAwsAccountId: z.ZodOptional<z.ZodString>;
5
+ }, z.core.$strict>;
6
+ export type ProvisionRegionInput = z.infer<typeof provisionRegionSchema>;
@@ -0,0 +1,12 @@
1
+ import { z } from "zod";
2
+ export const provisionRegionSchema = z
3
+ .object({
4
+ region: z
5
+ .string()
6
+ .describe("AWS region code to add, e.g. 'ap-southeast-2'"),
7
+ connectedAwsAccountId: z
8
+ .string()
9
+ .optional()
10
+ .describe("Target connected-account id; only needed when the organisation has no organisation-tier account and multiple accounts are connected"),
11
+ })
12
+ .strict();
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ export declare const queryComplianceSchema: z.ZodObject<{
3
+ mode: z.ZodEnum<{
4
+ issues: "issues";
5
+ counts: "counts";
6
+ summary: "summary";
7
+ }>;
8
+ severity: z.ZodOptional<z.ZodEnum<{
9
+ critical: "critical";
10
+ high: "high";
11
+ medium: "medium";
12
+ low: "low";
13
+ }>>;
14
+ status: z.ZodOptional<z.ZodEnum<{
15
+ open: "open";
16
+ resolved: "resolved";
17
+ suppressed: "suppressed";
18
+ }>>;
19
+ limit: z.ZodOptional<z.ZodNumber>;
20
+ }, z.core.$strict>;
21
+ export type QueryComplianceInput = z.infer<typeof queryComplianceSchema>;
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export const queryComplianceSchema = z
3
+ .object({
4
+ mode: z
5
+ .enum(["issues", "counts", "summary"])
6
+ .describe("issues: list findings; counts: breakdown by severity; summary: compliance score and overview"),
7
+ severity: z
8
+ .enum(["critical", "high", "medium", "low"])
9
+ .optional()
10
+ .describe("Filter by severity (issues mode)"),
11
+ status: z
12
+ .enum(["open", "resolved", "suppressed"])
13
+ .optional()
14
+ .describe("Filter by status (issues mode)"),
15
+ limit: z
16
+ .number()
17
+ .int()
18
+ .min(1)
19
+ .max(50)
20
+ .optional()
21
+ .describe("Max results for issues mode (default 20)"),
22
+ })
23
+ .strict();
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ export declare const queryCostsSchema: z.ZodObject<{
3
+ mode: z.ZodEnum<{
4
+ summary: "summary";
5
+ trend: "trend";
6
+ forecast: "forecast";
7
+ attribution: "attribution";
8
+ per_request: "per_request";
9
+ per_deployment: "per_deployment";
10
+ month_to_date: "month_to_date";
11
+ }>;
12
+ applicationId: z.ZodOptional<z.ZodString>;
13
+ days: z.ZodOptional<z.ZodNumber>;
14
+ forecastDays: z.ZodOptional<z.ZodNumber>;
15
+ }, z.core.$strict>;
16
+ export type QueryCostsInput = z.infer<typeof queryCostsSchema>;
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ export const queryCostsSchema = z
3
+ .object({
4
+ mode: z
5
+ .enum([
6
+ "summary",
7
+ "trend",
8
+ "forecast",
9
+ "attribution",
10
+ "per_request",
11
+ "per_deployment",
12
+ "month_to_date",
13
+ ])
14
+ .describe("summary: total + by-service; trend: daily with period comparison; forecast: linear regression projection; attribution: service breakdown; per_request/per_deployment: cost ratios for an app; month_to_date: MTD total"),
15
+ applicationId: z
16
+ .string()
17
+ .optional()
18
+ .describe("Required for per_request, per_deployment, and app-specific month_to_date"),
19
+ days: z
20
+ .number()
21
+ .int()
22
+ .min(1)
23
+ .max(90)
24
+ .optional()
25
+ .describe("Lookback period (default 30)"),
26
+ forecastDays: z
27
+ .number()
28
+ .int()
29
+ .min(1)
30
+ .max(30)
31
+ .optional()
32
+ .describe("Forecast horizon, only for forecast mode (default 7)"),
33
+ })
34
+ .strict();
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ export declare const queryInfrastructureSchema: z.ZodObject<{
3
+ entity: z.ZodEnum<{
4
+ application: "application";
5
+ deployment: "deployment";
6
+ asset: "asset";
7
+ account: "account";
8
+ }>;
9
+ id: z.ZodOptional<z.ZodString>;
10
+ applicationId: z.ZodOptional<z.ZodString>;
11
+ status: z.ZodOptional<z.ZodString>;
12
+ limit: z.ZodOptional<z.ZodNumber>;
13
+ }, z.core.$strict>;
14
+ export type QueryInfrastructureInput = z.infer<typeof queryInfrastructureSchema>;
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ export const queryInfrastructureSchema = z
3
+ .object({
4
+ entity: z
5
+ .enum(["application", "deployment", "asset", "account"])
6
+ .describe("What to query"),
7
+ id: z.string().optional().describe("Specific entity ID for detail fetch"),
8
+ applicationId: z
9
+ .string()
10
+ .optional()
11
+ .describe("Filter by application (deployments only)"),
12
+ status: z
13
+ .string()
14
+ .optional()
15
+ .describe("Status filter (deployments: queued/pending/running/succeeded/failed)"),
16
+ limit: z
17
+ .number()
18
+ .int()
19
+ .min(1)
20
+ .max(100)
21
+ .optional()
22
+ .describe("Max results (default varies by entity)"),
23
+ })
24
+ .strict();
@@ -0,0 +1,13 @@
1
+ import { z } from "zod";
2
+ export declare const queryMetricsSchema: z.ZodObject<{
3
+ mode: z.ZodEnum<{
4
+ time_series: "time_series";
5
+ latest: "latest";
6
+ sparklines: "sparklines";
7
+ org_summary: "org_summary";
8
+ }>;
9
+ applicationId: z.ZodOptional<z.ZodString>;
10
+ hours: z.ZodOptional<z.ZodNumber>;
11
+ limit: z.ZodOptional<z.ZodNumber>;
12
+ }, z.core.$strict>;
13
+ export type QueryMetricsInput = z.infer<typeof queryMetricsSchema>;
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export const queryMetricsSchema = z
3
+ .object({
4
+ mode: z
5
+ .enum(["time_series", "latest", "sparklines", "org_summary"])
6
+ .describe("time_series: metric values over time for an app; latest: current metrics; sparklines: hourly mini-trends; org_summary: org-wide aggregates"),
7
+ applicationId: z.string().optional().describe("Required for time_series"),
8
+ hours: z
9
+ .number()
10
+ .int()
11
+ .min(1)
12
+ .max(168)
13
+ .optional()
14
+ .describe("Lookback hours (default 24)"),
15
+ limit: z
16
+ .number()
17
+ .int()
18
+ .min(1)
19
+ .max(500)
20
+ .optional()
21
+ .describe("Max data points for time_series (default 100)"),
22
+ })
23
+ .strict();
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ export declare const renderChartSchema: z.ZodObject<{
3
+ kind: z.ZodEnum<{
4
+ timeseries: "timeseries";
5
+ bar: "bar";
6
+ categoryBar: "categoryBar";
7
+ }>;
8
+ title: z.ZodOptional<z.ZodString>;
9
+ series: z.ZodOptional<z.ZodArray<z.ZodObject<{
10
+ id: z.ZodString;
11
+ label: z.ZodString;
12
+ kind: z.ZodEnum<{
13
+ count: "count";
14
+ rate: "rate";
15
+ duration_ms: "duration_ms";
16
+ bytes: "bytes";
17
+ currency: "currency";
18
+ percent: "percent";
19
+ }>;
20
+ data: z.ZodArray<z.ZodObject<{
21
+ x: z.ZodNumber;
22
+ y: z.ZodNullable<z.ZodNumber>;
23
+ }, z.core.$strict>>;
24
+ }, z.core.$strict>>>;
25
+ data: z.ZodOptional<z.ZodArray<z.ZodObject<{
26
+ label: z.ZodString;
27
+ value: z.ZodNumber;
28
+ }, z.core.$strict>>>;
29
+ unit: z.ZodOptional<z.ZodEnum<{
30
+ count: "count";
31
+ rate: "rate";
32
+ duration_ms: "duration_ms";
33
+ bytes: "bytes";
34
+ currency: "currency";
35
+ percent: "percent";
36
+ }>>;
37
+ stacked: z.ZodOptional<z.ZodBoolean>;
38
+ areaFill: z.ZodOptional<z.ZodBoolean>;
39
+ }, z.core.$strict>;
40
+ export type RenderChartInput = z.infer<typeof renderChartSchema>;
@@ -0,0 +1,45 @@
1
+ import { z } from "zod";
2
+ const seriesKindEnum = z.enum([
3
+ "count",
4
+ "rate",
5
+ "duration_ms",
6
+ "bytes",
7
+ "currency",
8
+ "percent",
9
+ ]);
10
+ export const renderChartSchema = z
11
+ .object({
12
+ kind: z.enum(["timeseries", "bar", "categoryBar"]),
13
+ title: z.string().optional(),
14
+ series: z
15
+ .array(z
16
+ .object({
17
+ id: z.string(),
18
+ label: z.string(),
19
+ kind: seriesKindEnum,
20
+ data: z.array(z
21
+ .object({
22
+ x: z
23
+ .number()
24
+ .describe("Unix timestamp in milliseconds, or numeric value"),
25
+ y: z.number().nullable(),
26
+ })
27
+ .strict()),
28
+ })
29
+ .strict())
30
+ .optional()
31
+ .describe("Series data for timeseries and bar charts"),
32
+ data: z
33
+ .array(z
34
+ .object({
35
+ label: z.string(),
36
+ value: z.number(),
37
+ })
38
+ .strict())
39
+ .optional()
40
+ .describe("Category data for categoryBar charts"),
41
+ unit: seriesKindEnum.optional(),
42
+ stacked: z.boolean().optional(),
43
+ areaFill: z.boolean().optional(),
44
+ })
45
+ .strict();
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export declare const suggestRemediationSchema: z.ZodObject<{
3
+ domain: z.ZodEnum<{
4
+ compliance: "compliance";
5
+ cost: "cost";
6
+ performance: "performance";
7
+ }>;
8
+ applicationId: z.ZodOptional<z.ZodString>;
9
+ issueId: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strict>;
11
+ export type SuggestRemediationInput = z.infer<typeof suggestRemediationSchema>;
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ export const suggestRemediationSchema = z
3
+ .object({
4
+ domain: z
5
+ .enum(["compliance", "cost", "performance"])
6
+ .describe("What type of issue to remediate"),
7
+ applicationId: z
8
+ .string()
9
+ .optional()
10
+ .describe("Specific application context"),
11
+ issueId: z
12
+ .string()
13
+ .optional()
14
+ .describe("Specific compliance issue ID for targeted advice"),
15
+ })
16
+ .strict();
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ export declare const triggerDeploymentSchema: z.ZodObject<{
3
+ applicationId: z.ZodString;
4
+ environment: z.ZodOptional<z.ZodString>;
5
+ branch: z.ZodOptional<z.ZodString>;
6
+ }, z.core.$strict>;
7
+ export type TriggerDeploymentInput = z.infer<typeof triggerDeploymentSchema>;
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ export const triggerDeploymentSchema = z
3
+ .object({
4
+ applicationId: z.string().describe("The application ID to deploy"),
5
+ environment: z
6
+ .string()
7
+ .optional()
8
+ .describe("Target environment (e.g. production, staging)"),
9
+ branch: z
10
+ .string()
11
+ .optional()
12
+ .describe("Git branch to deploy from (defaults to repository default)"),
13
+ })
14
+ .strict();
@@ -0,0 +1,8 @@
1
+ import { z } from "zod";
2
+ export declare const updateConfigurationSchema: z.ZodObject<{
3
+ applicationId: z.ZodString;
4
+ name: z.ZodOptional<z.ZodString>;
5
+ description: z.ZodOptional<z.ZodString>;
6
+ configPath: z.ZodOptional<z.ZodString>;
7
+ }, z.core.$strict>;
8
+ export type UpdateConfigurationInput = z.infer<typeof updateConfigurationSchema>;
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ export const updateConfigurationSchema = z
3
+ .object({
4
+ applicationId: z.string().describe("Application to update"),
5
+ name: z
6
+ .string()
7
+ .min(1)
8
+ .max(100)
9
+ .optional()
10
+ .describe("New application name"),
11
+ description: z
12
+ .string()
13
+ .max(500)
14
+ .optional()
15
+ .describe("New application description"),
16
+ configPath: z
17
+ .string()
18
+ .max(500)
19
+ .optional()
20
+ .describe("New IaC configuration path"),
21
+ })
22
+ .strict()
23
+ .refine((input) => input.name !== undefined ||
24
+ input.description !== undefined ||
25
+ input.configPath !== undefined, {
26
+ message: "At least one of 'name', 'description', or 'configPath' must be provided",
27
+ });
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared type definitions for the AI tool system.
3
+ *
4
+ * These types are used by both the webapp (tool execution) and
5
+ * CLI (AXI command validation) to ensure parity.
6
+ */
7
+ import type { z } from "zod";
8
+ /** Tool access tier — read tools auto-execute, write tools require confirmation. */
9
+ export type ToolTier = "read" | "write";
10
+ /** A tool definition without execution logic — schemas and metadata only. */
11
+ export interface ToolSpec {
12
+ /** Machine name, e.g. "query_infrastructure" */
13
+ name: string;
14
+ /** Human-readable description for the AI model */
15
+ description: string;
16
+ /** Zod input schema — validated at both webapp and CLI boundaries */
17
+ inputSchema: z.ZodType;
18
+ /** Access tier */
19
+ tier: ToolTier;
20
+ /** Minimum role required (only meaningful for write tools) */
21
+ requiredRole?: string;
22
+ }
23
+ /** Canonical tool names — single source of truth across webapp and CLI. */
24
+ export declare const AI_TOOL_NAMES: readonly ["query_infrastructure", "query_compliance", "query_costs", "query_metrics", "get_organisation_overview", "explain_error", "compare_deployments", "suggest_remediation", "render_chart", "trigger_deployment", "manage_secret", "update_configuration", "manage_domain", "provision_region"];
25
+ export type AiToolName = (typeof AI_TOOL_NAMES)[number];
package/dist/types.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shared type definitions for the AI tool system.
3
+ *
4
+ * These types are used by both the webapp (tool execution) and
5
+ * CLI (AXI command validation) to ensure parity.
6
+ */
7
+ /** Canonical tool names — single source of truth across webapp and CLI. */
8
+ export const AI_TOOL_NAMES = [
9
+ "query_infrastructure",
10
+ "query_compliance",
11
+ "query_costs",
12
+ "query_metrics",
13
+ "get_organisation_overview",
14
+ "explain_error",
15
+ "compare_deployments",
16
+ "suggest_remediation",
17
+ "render_chart",
18
+ "trigger_deployment",
19
+ "manage_secret",
20
+ "update_configuration",
21
+ "manage_domain",
22
+ "provision_region",
23
+ ];
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@fjall/ai-tools",
3
+ "version": "2.18.1",
4
+ "description": "Shared AI tool schemas and registry for Fjall webapp and CLI",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ },
13
+ "./schemas": {
14
+ "types": "./dist/schemas/index.d.ts",
15
+ "default": "./dist/schemas/index.js"
16
+ },
17
+ "./registry": {
18
+ "types": "./dist/registry.d.ts",
19
+ "default": "./dist/registry.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist/"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "scripts": {
29
+ "clean": "rm -rf ./dist",
30
+ "clean:node": "rm -rf ./node_modules",
31
+ "build": "npm run clean && npx tsc",
32
+ "watch": "npm run build && npx tsc-watch",
33
+ "watch:only": "npx tsc-watch",
34
+ "format": "prettier --write \"src/**/*.{ts,json}\"",
35
+ "format:check": "prettier --check \"src/**/*.{ts,json}\"",
36
+ "test": "vitest run",
37
+ "typecheck": "npx tsc --noEmit"
38
+ },
39
+ "license": "SEE LICENSE IN LICENSE",
40
+ "devDependencies": {
41
+ "@types/node": "^25.6.0",
42
+ "prettier": "^3.8.3",
43
+ "tsc-watch": "^7.2.0",
44
+ "typescript": "^6.0.3",
45
+ "vitest": "^4.1.5"
46
+ },
47
+ "dependencies": {
48
+ "zod": "^4.4.3"
49
+ },
50
+ "engines": {
51
+ "node": ">=22.0.0"
52
+ },
53
+ "gitHead": "abea3c09d4831635e41a91cbd526beeb9ab58443"
54
+ }