@synth-deploy/server 0.1.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.
- package/dist/agent/debrief-retention.d.ts +12 -0
- package/dist/agent/debrief-retention.d.ts.map +1 -0
- package/dist/agent/debrief-retention.js +27 -0
- package/dist/agent/debrief-retention.js.map +1 -0
- package/dist/agent/envoy-client.d.ts +216 -0
- package/dist/agent/envoy-client.d.ts.map +1 -0
- package/dist/agent/envoy-client.js +266 -0
- package/dist/agent/envoy-client.js.map +1 -0
- package/dist/agent/envoy-registry.d.ts +102 -0
- package/dist/agent/envoy-registry.d.ts.map +1 -0
- package/dist/agent/envoy-registry.js +319 -0
- package/dist/agent/envoy-registry.js.map +1 -0
- package/dist/agent/health-checker.d.ts +39 -0
- package/dist/agent/health-checker.d.ts.map +1 -0
- package/dist/agent/health-checker.js +49 -0
- package/dist/agent/health-checker.js.map +1 -0
- package/dist/agent/mcp-client-manager.d.ts +36 -0
- package/dist/agent/mcp-client-manager.d.ts.map +1 -0
- package/dist/agent/mcp-client-manager.js +106 -0
- package/dist/agent/mcp-client-manager.js.map +1 -0
- package/dist/agent/stale-deployment-detector.d.ts +15 -0
- package/dist/agent/stale-deployment-detector.d.ts.map +1 -0
- package/dist/agent/stale-deployment-detector.js +50 -0
- package/dist/agent/stale-deployment-detector.js.map +1 -0
- package/dist/agent/step-runner.d.ts +31 -0
- package/dist/agent/step-runner.d.ts.map +1 -0
- package/dist/agent/step-runner.js +80 -0
- package/dist/agent/step-runner.js.map +1 -0
- package/dist/agent/synth-agent.d.ts +168 -0
- package/dist/agent/synth-agent.d.ts.map +1 -0
- package/dist/agent/synth-agent.js +1195 -0
- package/dist/agent/synth-agent.js.map +1 -0
- package/dist/api/agent.d.ts +36 -0
- package/dist/api/agent.d.ts.map +1 -0
- package/dist/api/agent.js +867 -0
- package/dist/api/agent.js.map +1 -0
- package/dist/api/api-keys.d.ts +4 -0
- package/dist/api/api-keys.d.ts.map +1 -0
- package/dist/api/api-keys.js +118 -0
- package/dist/api/api-keys.js.map +1 -0
- package/dist/api/artifacts.d.ts +5 -0
- package/dist/api/artifacts.d.ts.map +1 -0
- package/dist/api/artifacts.js +142 -0
- package/dist/api/artifacts.js.map +1 -0
- package/dist/api/auth.d.ts +4 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +280 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/deployments.d.ts +11 -0
- package/dist/api/deployments.d.ts.map +1 -0
- package/dist/api/deployments.js +1098 -0
- package/dist/api/deployments.js.map +1 -0
- package/dist/api/environments.d.ts +5 -0
- package/dist/api/environments.d.ts.map +1 -0
- package/dist/api/environments.js +69 -0
- package/dist/api/environments.js.map +1 -0
- package/dist/api/envoy-reports.d.ts +17 -0
- package/dist/api/envoy-reports.d.ts.map +1 -0
- package/dist/api/envoy-reports.js +138 -0
- package/dist/api/envoy-reports.js.map +1 -0
- package/dist/api/envoys.d.ts +5 -0
- package/dist/api/envoys.d.ts.map +1 -0
- package/dist/api/envoys.js +192 -0
- package/dist/api/envoys.js.map +1 -0
- package/dist/api/fleet.d.ts +11 -0
- package/dist/api/fleet.d.ts.map +1 -0
- package/dist/api/fleet.js +394 -0
- package/dist/api/fleet.js.map +1 -0
- package/dist/api/graph.d.ts +8 -0
- package/dist/api/graph.d.ts.map +1 -0
- package/dist/api/graph.js +355 -0
- package/dist/api/graph.js.map +1 -0
- package/dist/api/health.d.ts +20 -0
- package/dist/api/health.d.ts.map +1 -0
- package/dist/api/health.js +248 -0
- package/dist/api/health.js.map +1 -0
- package/dist/api/idp-schemas.d.ts +41 -0
- package/dist/api/idp-schemas.d.ts.map +1 -0
- package/dist/api/idp-schemas.js +17 -0
- package/dist/api/idp-schemas.js.map +1 -0
- package/dist/api/idp.d.ts +6 -0
- package/dist/api/idp.d.ts.map +1 -0
- package/dist/api/idp.js +620 -0
- package/dist/api/idp.js.map +1 -0
- package/dist/api/intake.d.ts +10 -0
- package/dist/api/intake.d.ts.map +1 -0
- package/dist/api/intake.js +418 -0
- package/dist/api/intake.js.map +1 -0
- package/dist/api/partitions.d.ts +5 -0
- package/dist/api/partitions.d.ts.map +1 -0
- package/dist/api/partitions.js +113 -0
- package/dist/api/partitions.js.map +1 -0
- package/dist/api/progress-event-store.d.ts +62 -0
- package/dist/api/progress-event-store.d.ts.map +1 -0
- package/dist/api/progress-event-store.js +118 -0
- package/dist/api/progress-event-store.js.map +1 -0
- package/dist/api/schemas.d.ts +1000 -0
- package/dist/api/schemas.d.ts.map +1 -0
- package/dist/api/schemas.js +328 -0
- package/dist/api/schemas.js.map +1 -0
- package/dist/api/security-boundaries.d.ts +4 -0
- package/dist/api/security-boundaries.d.ts.map +1 -0
- package/dist/api/security-boundaries.js +32 -0
- package/dist/api/security-boundaries.js.map +1 -0
- package/dist/api/settings.d.ts +4 -0
- package/dist/api/settings.d.ts.map +1 -0
- package/dist/api/settings.js +99 -0
- package/dist/api/settings.js.map +1 -0
- package/dist/api/system.d.ts +75 -0
- package/dist/api/system.d.ts.map +1 -0
- package/dist/api/system.js +558 -0
- package/dist/api/system.js.map +1 -0
- package/dist/api/telemetry.d.ts +4 -0
- package/dist/api/telemetry.d.ts.map +1 -0
- package/dist/api/telemetry.js +24 -0
- package/dist/api/telemetry.js.map +1 -0
- package/dist/api/users.d.ts +4 -0
- package/dist/api/users.d.ts.map +1 -0
- package/dist/api/users.js +173 -0
- package/dist/api/users.js.map +1 -0
- package/dist/archive-unpacker.d.ts +24 -0
- package/dist/archive-unpacker.d.ts.map +1 -0
- package/dist/archive-unpacker.js +239 -0
- package/dist/archive-unpacker.js.map +1 -0
- package/dist/artifact-analyzer.d.ts +59 -0
- package/dist/artifact-analyzer.d.ts.map +1 -0
- package/dist/artifact-analyzer.js +334 -0
- package/dist/artifact-analyzer.js.map +1 -0
- package/dist/auth/idp/index.d.ts +9 -0
- package/dist/auth/idp/index.d.ts.map +1 -0
- package/dist/auth/idp/index.js +5 -0
- package/dist/auth/idp/index.js.map +1 -0
- package/dist/auth/idp/ldap.d.ts +56 -0
- package/dist/auth/idp/ldap.d.ts.map +1 -0
- package/dist/auth/idp/ldap.js +276 -0
- package/dist/auth/idp/ldap.js.map +1 -0
- package/dist/auth/idp/oidc.d.ts +27 -0
- package/dist/auth/idp/oidc.d.ts.map +1 -0
- package/dist/auth/idp/oidc.js +97 -0
- package/dist/auth/idp/oidc.js.map +1 -0
- package/dist/auth/idp/role-mapping.d.ts +9 -0
- package/dist/auth/idp/role-mapping.d.ts.map +1 -0
- package/dist/auth/idp/role-mapping.js +16 -0
- package/dist/auth/idp/role-mapping.js.map +1 -0
- package/dist/auth/idp/saml.d.ts +40 -0
- package/dist/auth/idp/saml.d.ts.map +1 -0
- package/dist/auth/idp/saml.js +117 -0
- package/dist/auth/idp/saml.js.map +1 -0
- package/dist/auth/idp/types.d.ts +23 -0
- package/dist/auth/idp/types.d.ts.map +1 -0
- package/dist/auth/idp/types.js +2 -0
- package/dist/auth/idp/types.js.map +1 -0
- package/dist/fleet/fleet-executor.d.ts +35 -0
- package/dist/fleet/fleet-executor.d.ts.map +1 -0
- package/dist/fleet/fleet-executor.js +228 -0
- package/dist/fleet/fleet-executor.js.map +1 -0
- package/dist/fleet/fleet-store.d.ts +13 -0
- package/dist/fleet/fleet-store.d.ts.map +1 -0
- package/dist/fleet/fleet-store.js +13 -0
- package/dist/fleet/fleet-store.js.map +1 -0
- package/dist/fleet/index.d.ts +5 -0
- package/dist/fleet/index.d.ts.map +1 -0
- package/dist/fleet/index.js +4 -0
- package/dist/fleet/index.js.map +1 -0
- package/dist/fleet/representative-selector.d.ts +15 -0
- package/dist/fleet/representative-selector.d.ts.map +1 -0
- package/dist/fleet/representative-selector.js +71 -0
- package/dist/fleet/representative-selector.js.map +1 -0
- package/dist/graph/graph-executor.d.ts +36 -0
- package/dist/graph/graph-executor.d.ts.map +1 -0
- package/dist/graph/graph-executor.js +348 -0
- package/dist/graph/graph-executor.js.map +1 -0
- package/dist/graph/graph-inference.d.ts +22 -0
- package/dist/graph/graph-inference.d.ts.map +1 -0
- package/dist/graph/graph-inference.js +149 -0
- package/dist/graph/graph-inference.js.map +1 -0
- package/dist/graph/graph-store.d.ts +12 -0
- package/dist/graph/graph-store.d.ts.map +1 -0
- package/dist/graph/graph-store.js +61 -0
- package/dist/graph/graph-store.js.map +1 -0
- package/dist/graph/index.d.ts +5 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +4 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +837 -0
- package/dist/index.js.map +1 -0
- package/dist/intake/index.d.ts +6 -0
- package/dist/intake/index.d.ts.map +1 -0
- package/dist/intake/index.js +5 -0
- package/dist/intake/index.js.map +1 -0
- package/dist/intake/intake-processor.d.ts +17 -0
- package/dist/intake/intake-processor.d.ts.map +1 -0
- package/dist/intake/intake-processor.js +99 -0
- package/dist/intake/intake-processor.js.map +1 -0
- package/dist/intake/intake-store.d.ts +7 -0
- package/dist/intake/intake-store.d.ts.map +1 -0
- package/dist/intake/intake-store.js +7 -0
- package/dist/intake/intake-store.js.map +1 -0
- package/dist/intake/registry-poller.d.ts +41 -0
- package/dist/intake/registry-poller.d.ts.map +1 -0
- package/dist/intake/registry-poller.js +202 -0
- package/dist/intake/registry-poller.js.map +1 -0
- package/dist/intake/webhook-handlers.d.ts +37 -0
- package/dist/intake/webhook-handlers.d.ts.map +1 -0
- package/dist/intake/webhook-handlers.js +268 -0
- package/dist/intake/webhook-handlers.js.map +1 -0
- package/dist/logger.d.ts +5 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +15 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp/resources.d.ts +9 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +72 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts +15 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +20 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +9 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +88 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/middleware/auth.d.ts +29 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +76 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/permissions.d.ts +13 -0
- package/dist/middleware/permissions.d.ts.map +1 -0
- package/dist/middleware/permissions.js +32 -0
- package/dist/middleware/permissions.js.map +1 -0
- package/dist/pattern-store.d.ts +104 -0
- package/dist/pattern-store.d.ts.map +1 -0
- package/dist/pattern-store.js +299 -0
- package/dist/pattern-store.js.map +1 -0
- package/package.json +54 -0
- package/src/agent/debrief-retention.ts +44 -0
- package/src/agent/envoy-client.ts +474 -0
- package/src/agent/envoy-registry.ts +384 -0
- package/src/agent/health-checker.ts +70 -0
- package/src/agent/mcp-client-manager.ts +131 -0
- package/src/agent/stale-deployment-detector.ts +79 -0
- package/src/agent/step-runner.ts +124 -0
- package/src/agent/synth-agent.ts +1567 -0
- package/src/api/agent.ts +1075 -0
- package/src/api/api-keys.ts +129 -0
- package/src/api/artifacts.ts +194 -0
- package/src/api/auth.ts +320 -0
- package/src/api/deployments.ts +1347 -0
- package/src/api/environments.ts +97 -0
- package/src/api/envoy-reports.ts +159 -0
- package/src/api/envoys.ts +237 -0
- package/src/api/fleet.ts +510 -0
- package/src/api/graph.ts +516 -0
- package/src/api/health.ts +311 -0
- package/src/api/idp-schemas.ts +19 -0
- package/src/api/idp.ts +735 -0
- package/src/api/intake.ts +537 -0
- package/src/api/partitions.ts +147 -0
- package/src/api/progress-event-store.ts +153 -0
- package/src/api/schemas.ts +376 -0
- package/src/api/security-boundaries.ts +54 -0
- package/src/api/settings.ts +118 -0
- package/src/api/system.ts +704 -0
- package/src/api/telemetry.ts +32 -0
- package/src/api/users.ts +210 -0
- package/src/archive-unpacker.ts +271 -0
- package/src/artifact-analyzer.ts +438 -0
- package/src/auth/idp/index.ts +8 -0
- package/src/auth/idp/ldap.ts +340 -0
- package/src/auth/idp/oidc.ts +117 -0
- package/src/auth/idp/role-mapping.ts +22 -0
- package/src/auth/idp/saml.ts +148 -0
- package/src/auth/idp/types.ts +22 -0
- package/src/fleet/fleet-executor.ts +309 -0
- package/src/fleet/fleet-store.ts +13 -0
- package/src/fleet/index.ts +4 -0
- package/src/fleet/representative-selector.ts +83 -0
- package/src/graph/graph-executor.ts +446 -0
- package/src/graph/graph-inference.ts +184 -0
- package/src/graph/graph-store.ts +75 -0
- package/src/graph/index.ts +4 -0
- package/src/index.ts +916 -0
- package/src/intake/index.ts +5 -0
- package/src/intake/intake-processor.ts +111 -0
- package/src/intake/intake-store.ts +7 -0
- package/src/intake/registry-poller.ts +230 -0
- package/src/intake/webhook-handlers.ts +328 -0
- package/src/logger.ts +19 -0
- package/src/mcp/resources.ts +98 -0
- package/src/mcp/server.ts +34 -0
- package/src/mcp/tools.ts +117 -0
- package/src/middleware/auth.ts +103 -0
- package/src/middleware/permissions.ts +35 -0
- package/src/pattern-store.ts +409 -0
- package/tests/agent-mode.test.ts +536 -0
- package/tests/api-handlers.test.ts +1245 -0
- package/tests/archive-unpacker.test.ts +179 -0
- package/tests/artifact-analyzer.test.ts +240 -0
- package/tests/auth-middleware.test.ts +189 -0
- package/tests/decision-diary.test.ts +957 -0
- package/tests/diary-reader.test.ts +782 -0
- package/tests/envoy-client.test.ts +342 -0
- package/tests/envoy-reports.test.ts +156 -0
- package/tests/mcp-tools.test.ts +213 -0
- package/tests/orchestration.test.ts +536 -0
- package/tests/partition-deletion.test.ts +143 -0
- package/tests/partition-isolation.test.ts +830 -0
- package/tests/pattern-store.test.ts +371 -0
- package/tests/rbac-enforcement.test.ts +409 -0
- package/tests/ssrf-validation.test.ts +56 -0
- package/tests/stale-deployment.test.ts +85 -0
- package/tests/step-runner.test.ts +308 -0
- package/tests/ui-journey.test.ts +330 -0
- package/tsconfig.json +11 -0
- package/vitest.config.ts +27 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import type { ArtifactAnalysis, Artifact } from "@synth-deploy/core";
|
|
2
|
+
import type { LlmClient, LlmResult } from "@synth-deploy/core";
|
|
3
|
+
import type { DebriefWriter } from "@synth-deploy/core";
|
|
4
|
+
import { sanitizeForPrompt } from "@synth-deploy/core";
|
|
5
|
+
import type { PatternStore, PatternMatch, DerivedAnalysis } from "./pattern-store.js";
|
|
6
|
+
import { archiveFormat, unpackArchive, formatExtractedFiles } from "./archive-unpacker.js";
|
|
7
|
+
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Public types
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
export interface ArtifactInput {
|
|
13
|
+
name: string;
|
|
14
|
+
type?: string;
|
|
15
|
+
source: string;
|
|
16
|
+
content?: Buffer;
|
|
17
|
+
metadata?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AnalysisResult {
|
|
21
|
+
analysis: ArtifactAnalysis;
|
|
22
|
+
/** How the analysis was produced */
|
|
23
|
+
method: "llm" | "pattern-auto" | "pattern-suggest" | "unavailable";
|
|
24
|
+
/** Patterns that were matched, if any */
|
|
25
|
+
matchedPatterns?: PatternMatch[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Type detection
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Detect artifact type from name and metadata.
|
|
34
|
+
* Used as a hint for the LLM and for intake routing — not for analysis.
|
|
35
|
+
*/
|
|
36
|
+
export function detectArtifactType(artifact: ArtifactInput): string {
|
|
37
|
+
if (artifact.type) return artifact.type;
|
|
38
|
+
|
|
39
|
+
const name = artifact.name.toLowerCase();
|
|
40
|
+
const meta = artifact.metadata || {};
|
|
41
|
+
|
|
42
|
+
if (name === "dockerfile" || name.endsWith("/dockerfile") || meta["content-type"]?.includes("dockerfile")) {
|
|
43
|
+
return "dockerfile";
|
|
44
|
+
}
|
|
45
|
+
if (name === "chart.yaml" || name === "chart.yml") return "helm-chart";
|
|
46
|
+
if (name === "values.yaml" || name === "values.yml") return "helm-values";
|
|
47
|
+
if (name === "package.json") return "node-package";
|
|
48
|
+
if (name === "makefile" || name.endsWith("/makefile")) return "makefile";
|
|
49
|
+
if (name.endsWith(".tar.gz") || name.endsWith(".tgz")) return "tarball";
|
|
50
|
+
if (name.endsWith(".tar")) return "tarball";
|
|
51
|
+
if (name.endsWith(".zip")) return "zip";
|
|
52
|
+
if (name.endsWith(".nupkg")) return "nupkg";
|
|
53
|
+
if (name.endsWith(".jar") || name.endsWith(".war") || name.endsWith(".ear")) return "java-archive";
|
|
54
|
+
if (name.endsWith(".whl")) return "python-package";
|
|
55
|
+
if (name.endsWith(".deb")) return "debian-package";
|
|
56
|
+
if (name.endsWith(".rpm")) return "rpm-package";
|
|
57
|
+
if (name.endsWith(".yaml") || name.endsWith(".yml")) return "yaml";
|
|
58
|
+
if (name.endsWith(".json")) return "json";
|
|
59
|
+
if (name.endsWith(".sh") || name.endsWith(".bash")) return "shell-script";
|
|
60
|
+
|
|
61
|
+
return "unknown";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// LLM reasoning
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
const ANALYSIS_SYSTEM_PROMPT = `You are a deployment artifact analyzer. Given information about a deployment artifact, produce a structured analysis.
|
|
69
|
+
|
|
70
|
+
Your response must be valid JSON with these fields:
|
|
71
|
+
- "summary": A plain-language description (1-3 sentences) of what this artifact is and how it should be deployed.
|
|
72
|
+
- "dependencies": An array of strings listing runtime dependencies, system requirements, or external services needed.
|
|
73
|
+
- "configurationExpectations": An object mapping configuration key names to descriptions of expected values.
|
|
74
|
+
- "deploymentIntent": A short phrase describing the deployment method (e.g., "Container deployment via Docker Compose", "Kubernetes Helm release").
|
|
75
|
+
- "confidence": A number 0-1 indicating how confident you are in this analysis.
|
|
76
|
+
|
|
77
|
+
Focus on actionable deployment intelligence. Be specific about ports, environment variables, and deployment prerequisites.`;
|
|
78
|
+
|
|
79
|
+
async function analyzeWithLlm(
|
|
80
|
+
llm: LlmClient,
|
|
81
|
+
artifact: ArtifactInput,
|
|
82
|
+
artifactType: string,
|
|
83
|
+
extractedArchiveContent?: string,
|
|
84
|
+
): Promise<ArtifactAnalysis | null> {
|
|
85
|
+
const contentSection = extractedArchiveContent
|
|
86
|
+
? `Archive contents:\n\n${sanitizeForPrompt(extractedArchiveContent)}`
|
|
87
|
+
: artifact.content
|
|
88
|
+
? `Content:\n'''\n${sanitizeForPrompt(artifact.content.toString("utf-8").slice(0, 4000))}\n'''`
|
|
89
|
+
: "(no content available)";
|
|
90
|
+
|
|
91
|
+
const prompt = `Analyze this deployment artifact.
|
|
92
|
+
|
|
93
|
+
Name: ${sanitizeForPrompt(artifact.name)}
|
|
94
|
+
Type: ${sanitizeForPrompt(artifactType)}
|
|
95
|
+
Source: ${sanitizeForPrompt(artifact.source)}
|
|
96
|
+
Metadata: ${sanitizeForPrompt(JSON.stringify(artifact.metadata || {}))}
|
|
97
|
+
|
|
98
|
+
${contentSection}
|
|
99
|
+
|
|
100
|
+
Produce a JSON analysis of this artifact for deployment planning purposes.`;
|
|
101
|
+
|
|
102
|
+
const result: LlmResult = await llm.reason({
|
|
103
|
+
prompt,
|
|
104
|
+
systemPrompt: ANALYSIS_SYSTEM_PROMPT,
|
|
105
|
+
promptSummary: `Artifact analysis for "${artifact.name}" (${artifactType})`,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!result.ok) {
|
|
109
|
+
console.warn(`[artifact-analyzer] LLM analysis failed for "${artifact.name}": ${result.reason}`);
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const jsonMatch = result.text.match(/\{[\s\S]*\}/);
|
|
115
|
+
if (!jsonMatch) return null;
|
|
116
|
+
|
|
117
|
+
const parsed = JSON.parse(jsonMatch[0]) as {
|
|
118
|
+
summary?: string;
|
|
119
|
+
dependencies?: string[];
|
|
120
|
+
configurationExpectations?: Record<string, string>;
|
|
121
|
+
deploymentIntent?: string;
|
|
122
|
+
confidence?: number;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
summary: parsed.summary ?? `Analysis of "${artifact.name}"`,
|
|
127
|
+
dependencies: parsed.dependencies ?? [],
|
|
128
|
+
configurationExpectations: parsed.configurationExpectations ?? {},
|
|
129
|
+
deploymentIntent: parsed.deploymentIntent,
|
|
130
|
+
confidence: typeof parsed.confidence === "number" ? parsed.confidence : 0.5,
|
|
131
|
+
};
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Pattern overlay
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
function applyPatternOverrides(
|
|
142
|
+
analysis: ArtifactAnalysis,
|
|
143
|
+
derived: DerivedAnalysis,
|
|
144
|
+
): ArtifactAnalysis {
|
|
145
|
+
return {
|
|
146
|
+
summary: derived.summary || analysis.summary,
|
|
147
|
+
dependencies: derived.dependencies && derived.dependencies.length > 0
|
|
148
|
+
? derived.dependencies
|
|
149
|
+
: analysis.dependencies,
|
|
150
|
+
configurationExpectations: derived.configurationExpectations
|
|
151
|
+
? { ...analysis.configurationExpectations, ...derived.configurationExpectations }
|
|
152
|
+
: analysis.configurationExpectations,
|
|
153
|
+
deploymentIntent: derived.deploymentIntent || analysis.deploymentIntent,
|
|
154
|
+
confidence: analysis.confidence,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
// ArtifactAnalyzer
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
export interface ArtifactAnalyzerDeps {
|
|
163
|
+
llm: LlmClient;
|
|
164
|
+
debrief: DebriefWriter;
|
|
165
|
+
patternStore?: PatternStore;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Artifact analysis engine.
|
|
170
|
+
*
|
|
171
|
+
* Analysis pipeline:
|
|
172
|
+
* 1. Check pattern store for matching corrections (if available)
|
|
173
|
+
* - Auto-apply if >= 2 corrections and confidence >= 0.7 (no LLM call)
|
|
174
|
+
* - Suggest if 1 correction or confidence < 0.7 (apply as overlay after LLM)
|
|
175
|
+
* 2. If LLM is unavailable, return an "unavailable" result — no silent fallback
|
|
176
|
+
* 3. Run LLM analysis on the raw artifact content
|
|
177
|
+
* 4. Apply pattern-suggest overlay if applicable
|
|
178
|
+
* 5. Record debrief entry with decision trail
|
|
179
|
+
*/
|
|
180
|
+
export class ArtifactAnalyzer {
|
|
181
|
+
private readonly _llm: LlmClient;
|
|
182
|
+
private readonly _debrief: DebriefWriter;
|
|
183
|
+
private readonly _patternStore?: PatternStore;
|
|
184
|
+
|
|
185
|
+
constructor(deps: ArtifactAnalyzerDeps) {
|
|
186
|
+
this._llm = deps.llm;
|
|
187
|
+
this._debrief = deps.debrief;
|
|
188
|
+
this._patternStore = deps.patternStore;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Analyze a deployment artifact. Returns structured analysis with
|
|
193
|
+
* confidence score and method used.
|
|
194
|
+
*/
|
|
195
|
+
async analyze(artifact: ArtifactInput): Promise<AnalysisResult> {
|
|
196
|
+
const artifactType = detectArtifactType(artifact);
|
|
197
|
+
const reasoningTrail: string[] = [];
|
|
198
|
+
|
|
199
|
+
reasoningTrail.push(`Artifact: "${artifact.name}", detected type: ${artifactType}, source: ${artifact.source}`);
|
|
200
|
+
|
|
201
|
+
// --- Step 1: Check pattern store ---
|
|
202
|
+
let matchedPatterns: PatternMatch[] = [];
|
|
203
|
+
if (this._patternStore) {
|
|
204
|
+
matchedPatterns = this._patternStore.findMatches(
|
|
205
|
+
artifact.source,
|
|
206
|
+
artifactType,
|
|
207
|
+
artifact.name,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
if (matchedPatterns.length > 0) {
|
|
211
|
+
const autoMatch = matchedPatterns.find((m) => m.mode === "auto");
|
|
212
|
+
if (autoMatch) {
|
|
213
|
+
reasoningTrail.push(
|
|
214
|
+
`Pattern match: "${autoMatch.pattern.namePattern}" (${autoMatch.pattern.corrections.length} corrections, confidence ${autoMatch.pattern.confidence}). Auto-applying without LLM call.`,
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const analysis: ArtifactAnalysis = {
|
|
218
|
+
summary: autoMatch.pattern.derivedAnalysis.summary ?? `Pattern-matched artifact "${artifact.name}"`,
|
|
219
|
+
dependencies: autoMatch.pattern.derivedAnalysis.dependencies ?? [],
|
|
220
|
+
configurationExpectations: autoMatch.pattern.derivedAnalysis.configurationExpectations ?? {},
|
|
221
|
+
deploymentIntent: autoMatch.pattern.derivedAnalysis.deploymentIntent,
|
|
222
|
+
confidence: autoMatch.pattern.confidence,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
this._patternStore.recordApplication(autoMatch.pattern.id);
|
|
226
|
+
reasoningTrail.push("Pattern derived analysis applied directly.");
|
|
227
|
+
|
|
228
|
+
this._recordDebrief(artifact, artifactType, analysis, "pattern-auto", reasoningTrail);
|
|
229
|
+
|
|
230
|
+
return { analysis, method: "pattern-auto", matchedPatterns };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
reasoningTrail.push(
|
|
234
|
+
`Pattern suggestion available: "${matchedPatterns[0].pattern.namePattern}" ` +
|
|
235
|
+
`(${matchedPatterns[0].pattern.corrections.length} corrections, ` +
|
|
236
|
+
`confidence ${matchedPatterns[0].pattern.confidence}). ` +
|
|
237
|
+
`Not auto-applying — threshold not met.`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// --- Step 2: Unpack archive if applicable ---
|
|
243
|
+
let extractedArchiveContent: string | undefined;
|
|
244
|
+
if (artifact.content) {
|
|
245
|
+
const format = archiveFormat(artifactType, artifact.name);
|
|
246
|
+
if (format) {
|
|
247
|
+
const unpacked = await unpackArchive(artifact.content, format);
|
|
248
|
+
extractedArchiveContent = formatExtractedFiles(unpacked);
|
|
249
|
+
reasoningTrail.push(
|
|
250
|
+
`Archive unpacked (${format}): ${unpacked.files.length} text files extracted, ${unpacked.skipped} skipped.`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// --- Step 3: Require LLM ---
|
|
256
|
+
|
|
257
|
+
if (!this._llm.isAvailable()) {
|
|
258
|
+
const analysis: ArtifactAnalysis = {
|
|
259
|
+
summary: `Cannot analyze "${artifact.name}" — LLM is required for artifact analysis.`,
|
|
260
|
+
dependencies: [],
|
|
261
|
+
configurationExpectations: {},
|
|
262
|
+
confidence: 0,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
reasoningTrail.push("LLM not available — analysis cannot proceed.");
|
|
266
|
+
this._recordDebrief(artifact, artifactType, analysis, "unavailable", reasoningTrail);
|
|
267
|
+
|
|
268
|
+
return { analysis, method: "unavailable" };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// --- Step 4: LLM analysis ---
|
|
272
|
+
reasoningTrail.push("LLM available — analyzing artifact.");
|
|
273
|
+
const llmAnalysis = await analyzeWithLlm(this._llm, artifact, artifactType, extractedArchiveContent);
|
|
274
|
+
|
|
275
|
+
if (!llmAnalysis) {
|
|
276
|
+
const analysis: ArtifactAnalysis = {
|
|
277
|
+
summary: `Analysis of "${artifact.name}" failed — LLM returned no usable result.`,
|
|
278
|
+
dependencies: [],
|
|
279
|
+
configurationExpectations: {},
|
|
280
|
+
confidence: 0,
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
reasoningTrail.push("LLM returned no usable result.");
|
|
284
|
+
this._recordDebrief(artifact, artifactType, analysis, "unavailable", reasoningTrail);
|
|
285
|
+
|
|
286
|
+
return { analysis, method: "unavailable" };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
reasoningTrail.push(`LLM analysis complete. Confidence: ${llmAnalysis.confidence}.`);
|
|
290
|
+
|
|
291
|
+
let analysis = llmAnalysis;
|
|
292
|
+
let method: AnalysisResult["method"] = "llm";
|
|
293
|
+
|
|
294
|
+
// --- Step 4: Apply pattern-suggest overlay ---
|
|
295
|
+
if (matchedPatterns.length > 0) {
|
|
296
|
+
analysis = applyPatternOverrides(analysis, matchedPatterns[0].pattern.derivedAnalysis);
|
|
297
|
+
method = "pattern-suggest";
|
|
298
|
+
reasoningTrail.push("Pattern suggestion applied as overlay on LLM analysis.");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
this._recordDebrief(artifact, artifactType, analysis, method, reasoningTrail);
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
analysis,
|
|
305
|
+
method,
|
|
306
|
+
matchedPatterns: matchedPatterns.length > 0 ? matchedPatterns : undefined,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Re-analyze an artifact using its stored annotations as correction context.
|
|
312
|
+
* Returns null if LLM is unavailable.
|
|
313
|
+
*/
|
|
314
|
+
async reanalyzeWithAnnotations(artifact: Artifact): Promise<ArtifactAnalysis | null> {
|
|
315
|
+
if (!this._llm.isAvailable() || artifact.annotations.length === 0) return null;
|
|
316
|
+
|
|
317
|
+
const correctionsText = artifact.annotations
|
|
318
|
+
.map((a) => `- ${a.field}: ${a.correction}`)
|
|
319
|
+
.join("\n");
|
|
320
|
+
|
|
321
|
+
const prompt = `An artifact's analysis has user corrections. Revise the analysis to incorporate them.
|
|
322
|
+
|
|
323
|
+
Artifact Name: ${sanitizeForPrompt(artifact.name)}
|
|
324
|
+
Type: ${sanitizeForPrompt(artifact.type)}
|
|
325
|
+
|
|
326
|
+
Current Analysis:
|
|
327
|
+
Summary: ${sanitizeForPrompt(artifact.analysis.summary)}
|
|
328
|
+
Dependencies: ${sanitizeForPrompt(JSON.stringify(artifact.analysis.dependencies))}
|
|
329
|
+
Configuration Expectations: ${sanitizeForPrompt(JSON.stringify(artifact.analysis.configurationExpectations))}
|
|
330
|
+
Deployment Intent: ${sanitizeForPrompt(artifact.analysis.deploymentIntent ?? "unknown")}
|
|
331
|
+
Confidence: ${artifact.analysis.confidence}
|
|
332
|
+
|
|
333
|
+
User Corrections:
|
|
334
|
+
${sanitizeForPrompt(correctionsText)}
|
|
335
|
+
|
|
336
|
+
Produce a JSON analysis that incorporates all user corrections. Raise confidence proportional to how much the corrections clarify the artifact's purpose.`;
|
|
337
|
+
|
|
338
|
+
const result: LlmResult = await this._llm.reason({
|
|
339
|
+
prompt,
|
|
340
|
+
systemPrompt: ANALYSIS_SYSTEM_PROMPT,
|
|
341
|
+
promptSummary: `Re-analysis of "${artifact.name}" with ${artifact.annotations.length} user correction(s)`,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
if (!result.ok) return null;
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
const jsonMatch = result.text.match(/\{[\s\S]*\}/);
|
|
348
|
+
if (!jsonMatch) return null;
|
|
349
|
+
|
|
350
|
+
const parsed = JSON.parse(jsonMatch[0]) as {
|
|
351
|
+
summary?: string;
|
|
352
|
+
dependencies?: string[];
|
|
353
|
+
configurationExpectations?: Record<string, string>;
|
|
354
|
+
deploymentIntent?: string;
|
|
355
|
+
confidence?: number;
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const revised: ArtifactAnalysis = {
|
|
359
|
+
summary: parsed.summary ?? artifact.analysis.summary,
|
|
360
|
+
dependencies: parsed.dependencies ?? artifact.analysis.dependencies,
|
|
361
|
+
configurationExpectations: parsed.configurationExpectations ?? artifact.analysis.configurationExpectations,
|
|
362
|
+
deploymentIntent: parsed.deploymentIntent ?? artifact.analysis.deploymentIntent,
|
|
363
|
+
confidence: typeof parsed.confidence === "number"
|
|
364
|
+
? Math.max(parsed.confidence, artifact.analysis.confidence)
|
|
365
|
+
: artifact.analysis.confidence,
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
this._debrief.record({
|
|
369
|
+
partitionId: null,
|
|
370
|
+
deploymentId: null,
|
|
371
|
+
agent: "server",
|
|
372
|
+
decisionType: "artifact-analysis",
|
|
373
|
+
decision: `Re-analyzed "${artifact.name}" with ${artifact.annotations.length} user correction(s). Confidence: ${revised.confidence}.`,
|
|
374
|
+
reasoning: result.text,
|
|
375
|
+
context: {
|
|
376
|
+
artifactName: artifact.name,
|
|
377
|
+
corrections: correctionsText,
|
|
378
|
+
confidence: revised.confidence,
|
|
379
|
+
prompt,
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
return revised;
|
|
384
|
+
} catch {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// -------------------------------------------------------------------------
|
|
390
|
+
// Debrief integration
|
|
391
|
+
// -------------------------------------------------------------------------
|
|
392
|
+
|
|
393
|
+
private _recordDebrief(
|
|
394
|
+
artifact: ArtifactInput,
|
|
395
|
+
artifactType: string,
|
|
396
|
+
analysis: ArtifactAnalysis,
|
|
397
|
+
method: AnalysisResult["method"],
|
|
398
|
+
reasoningTrail: string[],
|
|
399
|
+
): void {
|
|
400
|
+
const confidenceLabel =
|
|
401
|
+
analysis.confidence >= 0.8
|
|
402
|
+
? "high"
|
|
403
|
+
: analysis.confidence >= 0.5
|
|
404
|
+
? "medium"
|
|
405
|
+
: "low";
|
|
406
|
+
|
|
407
|
+
this._debrief.record({
|
|
408
|
+
partitionId: null,
|
|
409
|
+
deploymentId: null,
|
|
410
|
+
agent: "server",
|
|
411
|
+
decisionType: "artifact-analysis",
|
|
412
|
+
decision: `Analyzed artifact "${artifact.name}" (${artifactType}) via ${method}. ` +
|
|
413
|
+
`Confidence: ${analysis.confidence} (${confidenceLabel}). ` +
|
|
414
|
+
`Found ${analysis.dependencies.length} dependencies, ` +
|
|
415
|
+
`${Object.keys(analysis.configurationExpectations).length} configuration expectations.`,
|
|
416
|
+
reasoning: reasoningTrail.join(" "),
|
|
417
|
+
context: {
|
|
418
|
+
artifactName: artifact.name,
|
|
419
|
+
artifactType,
|
|
420
|
+
source: artifact.source,
|
|
421
|
+
method,
|
|
422
|
+
confidence: analysis.confidence,
|
|
423
|
+
confidenceLabel,
|
|
424
|
+
dependencyCount: analysis.dependencies.length,
|
|
425
|
+
configExpectationCount: Object.keys(analysis.configurationExpectations).length,
|
|
426
|
+
deploymentIntent: analysis.deploymentIntent,
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// ---------------------------------------------------------------------------
|
|
433
|
+
// Factory
|
|
434
|
+
// ---------------------------------------------------------------------------
|
|
435
|
+
|
|
436
|
+
export function createArtifactAnalyzer(deps: ArtifactAnalyzerDeps): ArtifactAnalyzer {
|
|
437
|
+
return new ArtifactAnalyzer(deps);
|
|
438
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type { IdpAdapter } from "./types.js";
|
|
2
|
+
export { OidcAdapter } from "./oidc.js";
|
|
3
|
+
export type { OidcAuthenticateParams } from "./oidc.js";
|
|
4
|
+
export { SamlAdapter } from "./saml.js";
|
|
5
|
+
export type { SamlConfig, SamlAuthenticateParams } from "./saml.js";
|
|
6
|
+
export { LdapAdapter } from "./ldap.js";
|
|
7
|
+
export type { LdapConfig, LdapAuthenticateParams } from "./ldap.js";
|
|
8
|
+
export { applyRoleMappings } from "./role-mapping.js";
|