@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,24 @@
|
|
|
1
|
+
import { TelemetryQuerySchema } from "./schemas.js";
|
|
2
|
+
import { requirePermission } from "../middleware/permissions.js";
|
|
3
|
+
export function registerTelemetryRoutes(app, telemetryStore) {
|
|
4
|
+
app.get("/api/telemetry", { preHandler: [requirePermission("settings.manage")] }, async (request) => {
|
|
5
|
+
const parsed = TelemetryQuerySchema.safeParse(request.query);
|
|
6
|
+
const filters = parsed.success ? parsed.data : {};
|
|
7
|
+
const events = telemetryStore.query({
|
|
8
|
+
actor: filters.actor,
|
|
9
|
+
action: filters.action,
|
|
10
|
+
from: filters.from ? new Date(filters.from) : undefined,
|
|
11
|
+
to: filters.to ? new Date(filters.to) : undefined,
|
|
12
|
+
limit: filters.limit ?? 50,
|
|
13
|
+
offset: filters.offset ?? 0,
|
|
14
|
+
});
|
|
15
|
+
const total = telemetryStore.count({
|
|
16
|
+
actor: filters.actor,
|
|
17
|
+
action: filters.action,
|
|
18
|
+
from: filters.from ? new Date(filters.from) : undefined,
|
|
19
|
+
to: filters.to ? new Date(filters.to) : undefined,
|
|
20
|
+
});
|
|
21
|
+
return { events, total };
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/api/telemetry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjE,MAAM,UAAU,uBAAuB,CACrC,GAAoB,EACpB,cAA+B;IAE/B,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,EAAE,UAAU,EAAE,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAClG,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAElD,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAqC;YACrD,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;YACvD,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;YACjD,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE;YAC1B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC;SAC5B,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC;YACjC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAqC;YACrD,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;YACvD,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;SAClD,CAAC,CAAC;QAEH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
import type { IUserStore, IRoleStore, IUserRoleStore } from "@synth-deploy/core";
|
|
3
|
+
export declare function registerUserRoutes(app: FastifyInstance, userStore: IUserStore, roleStore: IRoleStore, userRoleStore: IUserRoleStore): void;
|
|
4
|
+
//# sourceMappingURL=users.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/api/users.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAA0C,MAAM,oBAAoB,CAAC;AAqBzH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,SAAS,EAAE,UAAU,EACrB,SAAS,EAAE,UAAU,EACrB,aAAa,EAAE,cAAc,GAC5B,IAAI,CAoLN"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import bcrypt from "bcryptjs";
|
|
3
|
+
import { requirePermission } from "../middleware/permissions.js";
|
|
4
|
+
import { CreateUserSchema, UpdateUserSchema, AssignRolesSchema, CreateRoleSchema, UpdateRoleSchema, } from "./schemas.js";
|
|
5
|
+
function toPublicUser(user) {
|
|
6
|
+
return {
|
|
7
|
+
id: user.id,
|
|
8
|
+
email: user.email,
|
|
9
|
+
name: user.name,
|
|
10
|
+
authSource: user.authSource ?? "local",
|
|
11
|
+
createdAt: user.createdAt,
|
|
12
|
+
updatedAt: user.updatedAt,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function registerUserRoutes(app, userStore, roleStore, userRoleStore) {
|
|
16
|
+
// --- GET /api/users ---
|
|
17
|
+
app.get("/api/users", { preHandler: [requirePermission("users.manage")] }, async () => {
|
|
18
|
+
const users = userStore.list();
|
|
19
|
+
return { users: users.map(toPublicUser) };
|
|
20
|
+
});
|
|
21
|
+
// --- POST /api/users ---
|
|
22
|
+
app.post("/api/users", { preHandler: [requirePermission("users.manage")] }, async (request, reply) => {
|
|
23
|
+
const parsed = CreateUserSchema.safeParse(request.body);
|
|
24
|
+
if (!parsed.success) {
|
|
25
|
+
return reply.status(400).send({ error: "Validation failed", details: parsed.error.flatten() });
|
|
26
|
+
}
|
|
27
|
+
const { email, name, password } = parsed.data;
|
|
28
|
+
const existing = userStore.getByEmail(email);
|
|
29
|
+
if (existing) {
|
|
30
|
+
return reply.status(409).send({ error: "Email already in use" });
|
|
31
|
+
}
|
|
32
|
+
const passwordHash = await bcrypt.hash(password, 10);
|
|
33
|
+
const userId = crypto.randomUUID();
|
|
34
|
+
const now = new Date();
|
|
35
|
+
const user = userStore.create({
|
|
36
|
+
id: userId,
|
|
37
|
+
email,
|
|
38
|
+
name,
|
|
39
|
+
passwordHash,
|
|
40
|
+
createdAt: now,
|
|
41
|
+
updatedAt: now,
|
|
42
|
+
});
|
|
43
|
+
return reply.status(201).send({ user: toPublicUser(user) });
|
|
44
|
+
});
|
|
45
|
+
// --- PUT /api/users/:id ---
|
|
46
|
+
app.put("/api/users/:id", { preHandler: [requirePermission("users.manage")] }, async (request, reply) => {
|
|
47
|
+
const parsed = UpdateUserSchema.safeParse(request.body);
|
|
48
|
+
if (!parsed.success) {
|
|
49
|
+
return reply.status(400).send({ error: "Validation failed", details: parsed.error.flatten() });
|
|
50
|
+
}
|
|
51
|
+
const userId = request.params.id;
|
|
52
|
+
const existing = userStore.getById(userId);
|
|
53
|
+
if (!existing) {
|
|
54
|
+
return reply.status(404).send({ error: "User not found" });
|
|
55
|
+
}
|
|
56
|
+
const updates = { updatedAt: new Date() };
|
|
57
|
+
if (parsed.data.email !== undefined)
|
|
58
|
+
updates.email = parsed.data.email;
|
|
59
|
+
if (parsed.data.name !== undefined)
|
|
60
|
+
updates.name = parsed.data.name;
|
|
61
|
+
if (parsed.data.password !== undefined) {
|
|
62
|
+
updates.passwordHash = await bcrypt.hash(parsed.data.password, 10);
|
|
63
|
+
}
|
|
64
|
+
const user = userStore.update(userId, updates);
|
|
65
|
+
return { user: toPublicUser(user) };
|
|
66
|
+
});
|
|
67
|
+
// --- DELETE /api/users/:id ---
|
|
68
|
+
app.delete("/api/users/:id", { preHandler: [requirePermission("users.manage")] }, async (request, reply) => {
|
|
69
|
+
const userId = request.params.id;
|
|
70
|
+
const existing = userStore.getById(userId);
|
|
71
|
+
if (!existing) {
|
|
72
|
+
return reply.status(404).send({ error: "User not found" });
|
|
73
|
+
}
|
|
74
|
+
userStore.delete(userId);
|
|
75
|
+
return reply.status(204).send();
|
|
76
|
+
});
|
|
77
|
+
// --- GET /api/users/:id/roles ---
|
|
78
|
+
app.get("/api/users/:id/roles", { preHandler: [requirePermission("users.manage")] }, async (request, reply) => {
|
|
79
|
+
const userId = request.params.id;
|
|
80
|
+
const existing = userStore.getById(userId);
|
|
81
|
+
if (!existing) {
|
|
82
|
+
return reply.status(404).send({ error: "User not found" });
|
|
83
|
+
}
|
|
84
|
+
const roles = userRoleStore.getUserRoles(userId);
|
|
85
|
+
return { roles };
|
|
86
|
+
});
|
|
87
|
+
// --- PUT /api/users/:id/roles ---
|
|
88
|
+
app.put("/api/users/:id/roles", { preHandler: [requirePermission("roles.manage")] }, async (request, reply) => {
|
|
89
|
+
const parsed = AssignRolesSchema.safeParse(request.body);
|
|
90
|
+
if (!parsed.success) {
|
|
91
|
+
return reply.status(400).send({ error: "Validation failed", details: parsed.error.flatten() });
|
|
92
|
+
}
|
|
93
|
+
const userId = request.params.id;
|
|
94
|
+
const existing = userStore.getById(userId);
|
|
95
|
+
if (!existing) {
|
|
96
|
+
return reply.status(404).send({ error: "User not found" });
|
|
97
|
+
}
|
|
98
|
+
const assignedBy = request.user.id;
|
|
99
|
+
const roleIds = parsed.data.roleIds;
|
|
100
|
+
// Validate all role IDs exist
|
|
101
|
+
for (const roleId of roleIds) {
|
|
102
|
+
const role = roleStore.getById(roleId);
|
|
103
|
+
if (!role) {
|
|
104
|
+
return reply.status(400).send({ error: `Role not found: ${roleId}` });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
userRoleStore.setRoles(userId, roleIds, assignedBy);
|
|
108
|
+
const roles = userRoleStore.getUserRoles(userId);
|
|
109
|
+
return { roles };
|
|
110
|
+
});
|
|
111
|
+
// --- GET /api/roles ---
|
|
112
|
+
app.get("/api/roles", { preHandler: [requirePermission("users.manage")] }, async () => {
|
|
113
|
+
const roles = roleStore.list();
|
|
114
|
+
return { roles };
|
|
115
|
+
});
|
|
116
|
+
// --- POST /api/roles ---
|
|
117
|
+
app.post("/api/roles", { preHandler: [requirePermission("roles.manage")] }, async (request, reply) => {
|
|
118
|
+
const parsed = CreateRoleSchema.safeParse(request.body);
|
|
119
|
+
if (!parsed.success) {
|
|
120
|
+
return reply.status(400).send({ error: "Validation failed", details: parsed.error.flatten() });
|
|
121
|
+
}
|
|
122
|
+
const { name, permissions } = parsed.data;
|
|
123
|
+
const existing = roleStore.getByName(name);
|
|
124
|
+
if (existing) {
|
|
125
|
+
return reply.status(409).send({ error: "Role name already in use" });
|
|
126
|
+
}
|
|
127
|
+
const roleId = crypto.randomUUID();
|
|
128
|
+
const role = roleStore.create({
|
|
129
|
+
id: roleId,
|
|
130
|
+
name,
|
|
131
|
+
permissions: permissions,
|
|
132
|
+
isBuiltIn: false,
|
|
133
|
+
createdAt: new Date(),
|
|
134
|
+
});
|
|
135
|
+
return reply.status(201).send({ role });
|
|
136
|
+
});
|
|
137
|
+
// --- PUT /api/roles/:id ---
|
|
138
|
+
app.put("/api/roles/:id", { preHandler: [requirePermission("roles.manage")] }, async (request, reply) => {
|
|
139
|
+
const parsed = UpdateRoleSchema.safeParse(request.body);
|
|
140
|
+
if (!parsed.success) {
|
|
141
|
+
return reply.status(400).send({ error: "Validation failed", details: parsed.error.flatten() });
|
|
142
|
+
}
|
|
143
|
+
const roleId = request.params.id;
|
|
144
|
+
const existing = roleStore.getById(roleId);
|
|
145
|
+
if (!existing) {
|
|
146
|
+
return reply.status(404).send({ error: "Role not found" });
|
|
147
|
+
}
|
|
148
|
+
if (existing.isBuiltIn) {
|
|
149
|
+
return reply.status(403).send({ error: "Cannot modify built-in roles" });
|
|
150
|
+
}
|
|
151
|
+
const updates = {};
|
|
152
|
+
if (parsed.data.name !== undefined)
|
|
153
|
+
updates.name = parsed.data.name;
|
|
154
|
+
if (parsed.data.permissions !== undefined)
|
|
155
|
+
updates.permissions = parsed.data.permissions;
|
|
156
|
+
const role = roleStore.update(roleId, updates);
|
|
157
|
+
return { role };
|
|
158
|
+
});
|
|
159
|
+
// --- DELETE /api/roles/:id ---
|
|
160
|
+
app.delete("/api/roles/:id", { preHandler: [requirePermission("roles.manage")] }, async (request, reply) => {
|
|
161
|
+
const roleId = request.params.id;
|
|
162
|
+
const existing = roleStore.getById(roleId);
|
|
163
|
+
if (!existing) {
|
|
164
|
+
return reply.status(404).send({ error: "Role not found" });
|
|
165
|
+
}
|
|
166
|
+
if (existing.isBuiltIn) {
|
|
167
|
+
return reply.status(403).send({ error: "Cannot delete built-in roles" });
|
|
168
|
+
}
|
|
169
|
+
roleStore.delete(roleId);
|
|
170
|
+
return reply.status(204).send();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=users.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/api/users.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ExtractedFile {
|
|
2
|
+
path: string;
|
|
3
|
+
content: string;
|
|
4
|
+
}
|
|
5
|
+
export interface UnpackResult {
|
|
6
|
+
files: ExtractedFile[];
|
|
7
|
+
skipped: number;
|
|
8
|
+
}
|
|
9
|
+
export type ArchiveFormat = "zip" | "tar" | "tar-gz";
|
|
10
|
+
/**
|
|
11
|
+
* Map artifact type string to archive format, if applicable.
|
|
12
|
+
* Returns null for non-archive types.
|
|
13
|
+
*/
|
|
14
|
+
export declare function archiveFormat(artifactType: string, artifactName: string): ArchiveFormat | null;
|
|
15
|
+
/**
|
|
16
|
+
* Unpack an archive buffer and extract readable text files.
|
|
17
|
+
* Returns an empty result for unrecognized or corrupt archives.
|
|
18
|
+
*/
|
|
19
|
+
export declare function unpackArchive(buffer: Buffer, format: ArchiveFormat): Promise<UnpackResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Format extracted files as a text block suitable for inclusion in an LLM prompt.
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatExtractedFiles(result: UnpackResult): string;
|
|
24
|
+
//# sourceMappingURL=archive-unpacker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive-unpacker.d.ts","sourceRoot":"","sources":["../src/archive-unpacker.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAmMD,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;AAErD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAe9F;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,YAAY,CAAC,CASvB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAcjE"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import AdmZip from "adm-zip";
|
|
2
|
+
import tarStream from "tar-stream";
|
|
3
|
+
import zlib from "node:zlib";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Text file detection
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const TEXT_EXTENSIONS = new Set([
|
|
9
|
+
// Docs / context
|
|
10
|
+
".md", ".txt", ".rst", ".adoc",
|
|
11
|
+
// Config / manifests
|
|
12
|
+
".yaml", ".yml", ".json", ".toml", ".ini", ".conf", ".config",
|
|
13
|
+
".properties", ".env", ".envrc",
|
|
14
|
+
// Infrastructure / IaC
|
|
15
|
+
".tf", ".tfvars", ".hcl", ".bicep",
|
|
16
|
+
// Build / packaging
|
|
17
|
+
".xml", ".gradle", ".gradle.kts", ".nuspec", ".pom",
|
|
18
|
+
".csproj", ".fsproj", ".vbproj", ".sln",
|
|
19
|
+
".gemspec", ".podspec", ".lock",
|
|
20
|
+
// Scripts
|
|
21
|
+
".sh", ".bash", ".zsh", ".fish",
|
|
22
|
+
".ps1", ".psm1", ".psd1", ".cmd", ".bat",
|
|
23
|
+
// Source (for deploy scripts, Lambdas, etc.)
|
|
24
|
+
".py", ".rb", ".js", ".ts", ".go", ".rs", ".java", ".cs",
|
|
25
|
+
// Web / templates
|
|
26
|
+
".html", ".htm", ".jinja", ".j2", ".tpl",
|
|
27
|
+
]);
|
|
28
|
+
const TEXT_FILENAMES = new Set([
|
|
29
|
+
"dockerfile", "makefile", "procfile", "brewfile", "gemfile",
|
|
30
|
+
"rakefile", "vagrantfile", "jenkinsfile", "capfile", "guardfile",
|
|
31
|
+
"podfile", "appfile", "fastfile",
|
|
32
|
+
"readme", "license", "changelog", "authors", "contributors", "notice",
|
|
33
|
+
]);
|
|
34
|
+
const SKIP_PATH_SEGMENTS = new Set([
|
|
35
|
+
"node_modules", ".git", "__pycache__", ".idea", ".vscode",
|
|
36
|
+
"vendor", "dist", "build", "target", "bin", "obj",
|
|
37
|
+
]);
|
|
38
|
+
const SKIP_EXTENSIONS = new Set([
|
|
39
|
+
".pyc", ".class", ".o", ".a", ".so", ".dll", ".exe",
|
|
40
|
+
".png", ".jpg", ".jpeg", ".gif", ".ico", ".svg", ".webp",
|
|
41
|
+
".woff", ".woff2", ".ttf", ".eot",
|
|
42
|
+
".zip", ".tar", ".gz", ".bz2", ".xz", ".7z", ".rar",
|
|
43
|
+
".jar", ".war", ".ear", ".whl", ".nupkg",
|
|
44
|
+
".pdf", ".doc", ".docx", ".xls", ".xlsx",
|
|
45
|
+
]);
|
|
46
|
+
const MAX_FILE_BYTES = 50 * 1024; // 50KB per file
|
|
47
|
+
const MAX_TOTAL_BYTES = 300 * 1024; // 300KB total
|
|
48
|
+
const MAX_FILES = 50;
|
|
49
|
+
function shouldExtract(filePath) {
|
|
50
|
+
const lower = filePath.toLowerCase();
|
|
51
|
+
const segments = lower.split("/");
|
|
52
|
+
const filename = segments[segments.length - 1];
|
|
53
|
+
// Skip directories and hidden files at root
|
|
54
|
+
if (!filename || filename.startsWith("."))
|
|
55
|
+
return false;
|
|
56
|
+
// Skip paths with unwanted segments
|
|
57
|
+
for (const seg of segments.slice(0, -1)) {
|
|
58
|
+
if (SKIP_PATH_SEGMENTS.has(seg))
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const dotIdx = filename.lastIndexOf(".");
|
|
62
|
+
const ext = dotIdx !== -1 ? filename.slice(dotIdx) : "";
|
|
63
|
+
if (SKIP_EXTENSIONS.has(ext))
|
|
64
|
+
return false;
|
|
65
|
+
if (TEXT_EXTENSIONS.has(ext))
|
|
66
|
+
return true;
|
|
67
|
+
if (TEXT_FILENAMES.has(filename))
|
|
68
|
+
return true;
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// ZIP unpacker (zip, nupkg, jar, war, ear, whl, vsix, apk)
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
function unpackZip(buffer) {
|
|
75
|
+
const files = [];
|
|
76
|
+
let skipped = 0;
|
|
77
|
+
let totalBytes = 0;
|
|
78
|
+
let zip;
|
|
79
|
+
try {
|
|
80
|
+
zip = new AdmZip(buffer);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return { files: [], skipped: 0 };
|
|
84
|
+
}
|
|
85
|
+
for (const entry of zip.getEntries()) {
|
|
86
|
+
if (entry.isDirectory)
|
|
87
|
+
continue;
|
|
88
|
+
if (files.length >= MAX_FILES) {
|
|
89
|
+
skipped++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!shouldExtract(entry.entryName)) {
|
|
93
|
+
skipped++;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (entry.header.size > MAX_FILE_BYTES) {
|
|
97
|
+
skipped++;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (totalBytes + entry.header.size > MAX_TOTAL_BYTES) {
|
|
101
|
+
skipped++;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const content = entry.getData().toString("utf-8");
|
|
106
|
+
// Reject if it looks binary (high proportion of null bytes / non-printable)
|
|
107
|
+
if (looksLikeBinary(content)) {
|
|
108
|
+
skipped++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
files.push({ path: entry.entryName, content });
|
|
112
|
+
totalBytes += entry.header.size;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
skipped++;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { files, skipped };
|
|
119
|
+
}
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
// TAR unpacker (tar, tar.gz / tgz)
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
function unpackTar(buffer, gunzip) {
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
const files = [];
|
|
126
|
+
let skipped = 0;
|
|
127
|
+
let totalBytes = 0;
|
|
128
|
+
const extract = tarStream.extract();
|
|
129
|
+
extract.on("entry", (header, stream, next) => {
|
|
130
|
+
if (header.type !== "file" ||
|
|
131
|
+
files.length >= MAX_FILES ||
|
|
132
|
+
!shouldExtract(header.name) ||
|
|
133
|
+
(header.size ?? 0) > MAX_FILE_BYTES ||
|
|
134
|
+
totalBytes + (header.size ?? 0) > MAX_TOTAL_BYTES) {
|
|
135
|
+
if (header.type === "file")
|
|
136
|
+
skipped++;
|
|
137
|
+
stream.resume();
|
|
138
|
+
next();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const chunks = [];
|
|
142
|
+
let bytes = 0;
|
|
143
|
+
stream.on("data", (chunk) => {
|
|
144
|
+
bytes += chunk.length;
|
|
145
|
+
if (bytes <= MAX_FILE_BYTES)
|
|
146
|
+
chunks.push(chunk);
|
|
147
|
+
});
|
|
148
|
+
stream.on("end", () => {
|
|
149
|
+
try {
|
|
150
|
+
const content = Buffer.concat(chunks).toString("utf-8");
|
|
151
|
+
if (!looksLikeBinary(content)) {
|
|
152
|
+
files.push({ path: header.name, content });
|
|
153
|
+
totalBytes += bytes;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
skipped++;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
skipped++;
|
|
161
|
+
}
|
|
162
|
+
next();
|
|
163
|
+
});
|
|
164
|
+
stream.on("error", () => { skipped++; next(); });
|
|
165
|
+
});
|
|
166
|
+
extract.on("finish", () => resolve({ files, skipped }));
|
|
167
|
+
extract.on("error", () => resolve({ files, skipped }));
|
|
168
|
+
const readable = Readable.from(buffer);
|
|
169
|
+
if (gunzip) {
|
|
170
|
+
readable.pipe(zlib.createGunzip()).pipe(extract);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
readable.pipe(extract);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// Binary detection heuristic
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
function looksLikeBinary(text) {
|
|
181
|
+
// Sample the first 1KB — if >10% non-printable chars, treat as binary
|
|
182
|
+
const sample = text.slice(0, 1024);
|
|
183
|
+
let nonPrintable = 0;
|
|
184
|
+
for (let i = 0; i < sample.length; i++) {
|
|
185
|
+
const code = sample.charCodeAt(i);
|
|
186
|
+
if (code < 9 || (code > 13 && code < 32) || code === 127)
|
|
187
|
+
nonPrintable++;
|
|
188
|
+
}
|
|
189
|
+
return nonPrintable / sample.length > 0.1;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Map artifact type string to archive format, if applicable.
|
|
193
|
+
* Returns null for non-archive types.
|
|
194
|
+
*/
|
|
195
|
+
export function archiveFormat(artifactType, artifactName) {
|
|
196
|
+
switch (artifactType) {
|
|
197
|
+
case "zip":
|
|
198
|
+
case "nupkg":
|
|
199
|
+
case "java-archive":
|
|
200
|
+
case "python-package":
|
|
201
|
+
return "zip";
|
|
202
|
+
case "tarball": {
|
|
203
|
+
const name = artifactName.toLowerCase();
|
|
204
|
+
if (name.endsWith(".tar.gz") || name.endsWith(".tgz"))
|
|
205
|
+
return "tar-gz";
|
|
206
|
+
return "tar";
|
|
207
|
+
}
|
|
208
|
+
default:
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Unpack an archive buffer and extract readable text files.
|
|
214
|
+
* Returns an empty result for unrecognized or corrupt archives.
|
|
215
|
+
*/
|
|
216
|
+
export async function unpackArchive(buffer, format) {
|
|
217
|
+
switch (format) {
|
|
218
|
+
case "zip":
|
|
219
|
+
return unpackZip(buffer);
|
|
220
|
+
case "tar":
|
|
221
|
+
return unpackTar(buffer, false);
|
|
222
|
+
case "tar-gz":
|
|
223
|
+
return unpackTar(buffer, true);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Format extracted files as a text block suitable for inclusion in an LLM prompt.
|
|
228
|
+
*/
|
|
229
|
+
export function formatExtractedFiles(result) {
|
|
230
|
+
if (result.files.length === 0) {
|
|
231
|
+
return "(no readable text files found in archive)";
|
|
232
|
+
}
|
|
233
|
+
const sections = result.files.map((f) => `=== ${f.path} ===\n${f.content.trimEnd()}`);
|
|
234
|
+
const footer = result.skipped > 0
|
|
235
|
+
? `\n(${result.skipped} binary or oversized file${result.skipped === 1 ? "" : "s"} skipped)`
|
|
236
|
+
: "";
|
|
237
|
+
return sections.join("\n\n") + footer;
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=archive-unpacker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archive-unpacker.js","sourceRoot":"","sources":["../src/archive-unpacker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ArtifactAnalysis, Artifact } from "@synth-deploy/core";
|
|
2
|
+
import type { LlmClient } from "@synth-deploy/core";
|
|
3
|
+
import type { DebriefWriter } from "@synth-deploy/core";
|
|
4
|
+
import type { PatternStore, PatternMatch } from "./pattern-store.js";
|
|
5
|
+
export interface ArtifactInput {
|
|
6
|
+
name: string;
|
|
7
|
+
type?: string;
|
|
8
|
+
source: string;
|
|
9
|
+
content?: Buffer;
|
|
10
|
+
metadata?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
export interface AnalysisResult {
|
|
13
|
+
analysis: ArtifactAnalysis;
|
|
14
|
+
/** How the analysis was produced */
|
|
15
|
+
method: "llm" | "pattern-auto" | "pattern-suggest" | "unavailable";
|
|
16
|
+
/** Patterns that were matched, if any */
|
|
17
|
+
matchedPatterns?: PatternMatch[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Detect artifact type from name and metadata.
|
|
21
|
+
* Used as a hint for the LLM and for intake routing — not for analysis.
|
|
22
|
+
*/
|
|
23
|
+
export declare function detectArtifactType(artifact: ArtifactInput): string;
|
|
24
|
+
export interface ArtifactAnalyzerDeps {
|
|
25
|
+
llm: LlmClient;
|
|
26
|
+
debrief: DebriefWriter;
|
|
27
|
+
patternStore?: PatternStore;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Artifact analysis engine.
|
|
31
|
+
*
|
|
32
|
+
* Analysis pipeline:
|
|
33
|
+
* 1. Check pattern store for matching corrections (if available)
|
|
34
|
+
* - Auto-apply if >= 2 corrections and confidence >= 0.7 (no LLM call)
|
|
35
|
+
* - Suggest if 1 correction or confidence < 0.7 (apply as overlay after LLM)
|
|
36
|
+
* 2. If LLM is unavailable, return an "unavailable" result — no silent fallback
|
|
37
|
+
* 3. Run LLM analysis on the raw artifact content
|
|
38
|
+
* 4. Apply pattern-suggest overlay if applicable
|
|
39
|
+
* 5. Record debrief entry with decision trail
|
|
40
|
+
*/
|
|
41
|
+
export declare class ArtifactAnalyzer {
|
|
42
|
+
private readonly _llm;
|
|
43
|
+
private readonly _debrief;
|
|
44
|
+
private readonly _patternStore?;
|
|
45
|
+
constructor(deps: ArtifactAnalyzerDeps);
|
|
46
|
+
/**
|
|
47
|
+
* Analyze a deployment artifact. Returns structured analysis with
|
|
48
|
+
* confidence score and method used.
|
|
49
|
+
*/
|
|
50
|
+
analyze(artifact: ArtifactInput): Promise<AnalysisResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Re-analyze an artifact using its stored annotations as correction context.
|
|
53
|
+
* Returns null if LLM is unavailable.
|
|
54
|
+
*/
|
|
55
|
+
reanalyzeWithAnnotations(artifact: Artifact): Promise<ArtifactAnalysis | null>;
|
|
56
|
+
private _recordDebrief;
|
|
57
|
+
}
|
|
58
|
+
export declare function createArtifactAnalyzer(deps: ArtifactAnalyzerDeps): ArtifactAnalyzer;
|
|
59
|
+
//# sourceMappingURL=artifact-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-analyzer.d.ts","sourceRoot":"","sources":["../src/artifact-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AAOtF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,oCAAoC;IACpC,MAAM,EAAE,KAAK,GAAG,cAAc,GAAG,iBAAiB,GAAG,aAAa,CAAC;IACnE,yCAAyC;IACzC,eAAe,CAAC,EAAE,YAAY,EAAE,CAAC;CAClC;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,CA0BlE;AAoGD,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,SAAS,CAAC;IACf,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAe;gBAElC,IAAI,EAAE,oBAAoB;IAMtC;;;OAGG;IACG,OAAO,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAmH/D;;;OAGG;IACG,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IA+EpF,OAAO,CAAC,cAAc;CAqCvB;AAMD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAEnF"}
|