fjall 0.96.0 → 0.99.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.
- package/bin/.bundled +3 -3
- package/bin/.metafile.json +4742 -3402
- package/bin/assets/generators/application/generator.js +1 -1
- package/bin/assets/generators/compute/generator.js +1 -1
- package/bin/assets/generators/compute/service/generator.js +1 -1
- package/bin/assets/generators/database/generator.js +1 -1
- package/bin/assets/generators/domain/generator.js +2 -2
- package/bin/assets/generators/organisation/files/organisation/infrastructure.ts +8 -2
- package/bin/assets/generators/shared/files/cdk.json +1 -1
- package/bin/assets/generators/shared/files/package.json +8 -7
- package/bin/assets/generators/shared/files/tsconfig.json +5 -4
- package/bin/assets/generators/utils/integrationTestUtils.d.ts +9 -0
- package/bin/assets/generators/utils/integrationTestUtils.js +4 -2
- package/bin/assets/generators/utils/planning/generatorHelpers.js +2 -2
- package/bin/assets/src/util/__tests__/fjallApiClientTestHelpers.d.ts +9 -0
- package/bin/assets/src/util/__tests__/fjallApiClientTestHelpers.js +1 -0
- package/bin/assets/src/util/__tests__/outputTestHelpers.d.ts +9 -0
- package/bin/assets/src/util/__tests__/outputTestHelpers.js +1 -0
- package/bin/assets/src/util/agent/__tests__/toonTestHelpers.d.ts +91 -0
- package/bin/assets/src/util/agent/__tests__/toonTestHelpers.js +1 -0
- package/bin/assets/src/util/agent/actionRequired.d.ts +60 -0
- package/bin/assets/src/util/agent/actionRequired.js +1 -0
- package/bin/assets/src/util/agent/agentCallbacks.d.ts +21 -0
- package/bin/assets/src/util/agent/agentCallbacks.js +1 -0
- package/bin/assets/src/util/agent/agentInit.d.ts +17 -0
- package/bin/assets/src/util/agent/agentInit.js +288 -0
- package/bin/assets/src/util/agent/agentOutput.d.ts +61 -0
- package/bin/assets/src/util/agent/agentOutput.js +8 -0
- package/bin/assets/src/util/agent/budget.d.ts +19 -0
- package/bin/assets/src/util/agent/budget.js +4 -0
- package/bin/assets/src/util/agent/detectAgent.d.ts +51 -0
- package/bin/assets/src/util/agent/detectAgent.js +1 -0
- package/bin/assets/src/util/agent/errorCodeMap.d.ts +16 -0
- package/bin/assets/src/util/agent/errorCodeMap.js +1 -0
- package/bin/assets/src/util/agent/errorCodes.d.ts +48 -0
- package/bin/assets/src/util/agent/errorCodes.js +1 -0
- package/bin/assets/src/util/agent/fieldSelection.d.ts +22 -0
- package/bin/assets/src/util/agent/fieldSelection.js +1 -0
- package/bin/assets/src/util/agent/getSurface.d.ts +27 -0
- package/bin/assets/src/util/agent/getSurface.js +1 -0
- package/bin/assets/src/util/agent/index.d.ts +27 -0
- package/bin/assets/src/util/agent/index.js +1 -0
- package/bin/assets/src/util/agent/mcpProtocolEmit.d.ts +31 -0
- package/bin/assets/src/util/agent/mcpProtocolEmit.js +2 -0
- package/bin/assets/src/util/agent/schemas/appsSchemas.d.ts +18 -0
- package/bin/assets/src/util/agent/schemas/appsSchemas.js +1 -0
- package/bin/assets/src/util/agent/schemas/assetSchemas.d.ts +13 -0
- package/bin/assets/src/util/agent/schemas/assetSchemas.js +1 -0
- package/bin/assets/src/util/agent/schemas/awsSchemas.d.ts +5 -0
- package/bin/assets/src/util/agent/schemas/awsSchemas.js +1 -0
- package/bin/assets/src/util/agent/schemas/deploySchemas.d.ts +8 -0
- package/bin/assets/src/util/agent/schemas/deploySchemas.js +1 -0
- package/bin/assets/src/util/agent/schemas/index.d.ts +10 -0
- package/bin/assets/src/util/agent/schemas/index.js +1 -0
- package/bin/assets/src/util/agent/schemas/infraSchemas.d.ts +45 -0
- package/bin/assets/src/util/agent/schemas/infraSchemas.js +1 -0
- package/bin/assets/src/util/agent/schemas/secretsSchemas.d.ts +13 -0
- package/bin/assets/src/util/agent/schemas/secretsSchemas.js +1 -0
- package/bin/assets/src/util/agent/schemas/types.d.ts +98 -0
- package/bin/assets/src/util/agent/schemas/types.js +0 -0
- package/bin/assets/src/util/agent/schemas/userSchemas.d.ts +21 -0
- package/bin/assets/src/util/agent/schemas/userSchemas.js +1 -0
- package/bin/assets/src/util/agent/sessionHooks.d.ts +47 -0
- package/bin/assets/src/util/agent/sessionHooks.js +6 -0
- package/bin/assets/src/util/agent/streaming.d.ts +51 -0
- package/bin/assets/src/util/agent/streaming.js +1 -0
- package/bin/assets/src/util/agent/suggestionEntries/coreEntries.d.ts +2 -0
- package/bin/assets/src/util/agent/suggestionEntries/coreEntries.js +1 -0
- package/bin/assets/src/util/agent/suggestionEntries/identityEntries.d.ts +2 -0
- package/bin/assets/src/util/agent/suggestionEntries/identityEntries.js +1 -0
- package/bin/assets/src/util/agent/suggestionEntries/index.d.ts +3 -0
- package/bin/assets/src/util/agent/suggestionEntries/index.js +1 -0
- package/bin/assets/src/util/agent/suggestionEntries/infraEntries.d.ts +2 -0
- package/bin/assets/src/util/agent/suggestionEntries/infraEntries.js +1 -0
- package/bin/assets/src/util/agent/suggestionEntries/observabilityEntries.d.ts +2 -0
- package/bin/assets/src/util/agent/suggestionEntries/observabilityEntries.js +1 -0
- package/bin/assets/src/util/agent/suggestionEntries/secretsEntries.d.ts +2 -0
- package/bin/assets/src/util/agent/suggestionEntries/secretsEntries.js +1 -0
- package/bin/assets/src/util/agent/suggestionEntries/types.d.ts +17 -0
- package/bin/assets/src/util/agent/suggestionEntries/types.js +1 -0
- package/bin/assets/src/util/agent/suggestions.d.ts +30 -0
- package/bin/assets/src/util/agent/suggestions.js +1 -0
- package/bin/assets/src/util/agent/tokenScopes.d.ts +24 -0
- package/bin/assets/src/util/agent/tokenScopes.js +1 -0
- package/bin/assets/src/util/agent/toonFormatter.d.ts +55 -0
- package/bin/assets/src/util/agent/toonFormatter.js +14 -0
- package/bin/assets/src/util/api/Credentials.d.ts +13 -0
- package/bin/assets/src/util/api/Credentials.js +1 -0
- package/bin/assets/src/util/api/FjallApiClient.d.ts +33 -0
- package/bin/assets/src/util/api/FjallApiClient.js +1 -0
- package/bin/assets/src/util/api/FjallApiClient.types.d.ts +375 -0
- package/bin/assets/src/util/api/FjallApiClient.types.js +1 -0
- package/bin/assets/src/util/api/FjallApiClientBase.d.ts +13 -0
- package/bin/assets/src/util/api/FjallApiClientBase.js +1 -0
- package/bin/assets/src/util/api/FjallApiClientDeviceCode.d.ts +13 -0
- package/bin/assets/src/util/api/FjallApiClientDeviceCode.js +1 -0
- package/bin/assets/src/util/api/FjallApiClientErrors.d.ts +5 -0
- package/bin/assets/src/util/api/FjallApiClientErrors.js +1 -0
- package/bin/assets/src/util/api/FjallApiClientResources.d.ts +45 -0
- package/bin/assets/src/util/api/FjallApiClientResources.js +1 -0
- package/bin/assets/src/util/api/index.d.ts +7 -0
- package/bin/assets/src/util/api/index.js +1 -0
- package/bin/assets/src/util/api/resolveApiKey.d.ts +1 -0
- package/bin/assets/src/util/api/resolveApiKey.js +1 -0
- package/bin/assets/src/util/api/scaffoldNotification.d.ts +2 -0
- package/bin/assets/src/util/api/scaffoldNotification.js +1 -0
- package/bin/assets/src/util/awsCleanup.d.ts +9 -0
- package/bin/assets/src/util/awsCleanup.js +1 -0
- package/bin/assets/src/util/awsTags.d.ts +19 -0
- package/bin/assets/src/util/awsTags.js +1 -0
- package/bin/assets/src/util/buildxEventAdapter.d.ts +20 -0
- package/bin/assets/src/util/buildxEventAdapter.js +1 -0
- package/bin/assets/src/util/caseConversion.d.ts +1 -0
- package/bin/assets/src/util/caseConversion.js +1 -0
- package/bin/assets/src/util/codemod/emitCliTelemetry.d.ts +32 -0
- package/bin/assets/src/util/codemod/emitCliTelemetry.js +1 -0
- package/bin/assets/src/util/codemod/exitCodes.d.ts +11 -0
- package/bin/assets/src/util/codemod/exitCodes.js +1 -0
- package/bin/assets/src/util/codemod/index.d.ts +3 -0
- package/bin/assets/src/util/codemod/index.js +1 -0
- package/bin/assets/src/util/codemod/renderCodemod.d.ts +5 -0
- package/bin/assets/src/util/codemod/renderCodemod.js +1 -0
- package/bin/assets/src/util/codemod/stepLabels.d.ts +11 -0
- package/bin/assets/src/util/codemod/stepLabels.js +1 -0
- package/bin/assets/src/util/colourUtils.d.ts +21 -0
- package/bin/assets/src/util/colourUtils.js +1 -0
- package/bin/assets/src/util/commandErrorHandler.d.ts +16 -0
- package/bin/assets/src/util/commandErrorHandler.js +1 -0
- package/bin/assets/src/util/commandResult.d.ts +63 -0
- package/bin/assets/src/util/commandResult.js +1 -0
- package/bin/assets/src/util/concurrency.d.ts +35 -0
- package/bin/assets/src/util/concurrency.js +1 -0
- package/bin/assets/src/util/deploymentEvents.d.ts +155 -0
- package/bin/assets/src/util/deploymentEvents.js +1 -0
- package/bin/assets/src/util/errorDisplay.d.ts +4 -0
- package/bin/assets/src/util/errorDisplay.js +2 -0
- package/bin/assets/src/util/errorUtils.d.ts +1 -0
- package/bin/assets/src/util/errorUtils.js +1 -0
- package/bin/assets/src/util/executionMode.d.ts +18 -0
- package/bin/assets/src/util/executionMode.js +1 -0
- package/bin/assets/src/util/formatDeltaValue.d.ts +1 -0
- package/bin/assets/src/util/formatDeltaValue.js +1 -0
- package/bin/assets/src/util/formatDuration.d.ts +1 -0
- package/bin/assets/src/util/formatDuration.js +1 -0
- package/bin/assets/src/util/formatRelativeTime.d.ts +1 -0
- package/bin/assets/src/util/formatRelativeTime.js +1 -0
- package/bin/assets/src/util/fuzzyMatch.d.ts +38 -0
- package/bin/assets/src/util/fuzzyMatch.js +1 -0
- package/bin/assets/src/util/gitDetection.d.ts +8 -0
- package/bin/assets/src/util/gitDetection.js +1 -0
- package/bin/assets/src/util/index.d.ts +50 -0
- package/bin/assets/src/util/index.js +1 -0
- package/bin/assets/src/util/log.d.ts +29 -0
- package/bin/assets/src/util/log.js +4 -0
- package/bin/assets/src/util/logger/CorrelatedLogger.d.ts +15 -0
- package/bin/assets/src/util/logger/CorrelatedLogger.js +1 -0
- package/bin/assets/src/util/logger/DeploymentLogger.d.ts +33 -0
- package/bin/assets/src/util/logger/DeploymentLogger.js +2 -0
- package/bin/assets/src/util/logger/FileRotator.d.ts +17 -0
- package/bin/assets/src/util/logger/FileRotator.js +1 -0
- package/bin/assets/src/util/logger/LogFileWriter.d.ts +54 -0
- package/bin/assets/src/util/logger/LogFileWriter.js +4 -0
- package/bin/assets/src/util/logger/Logger.d.ts +43 -0
- package/bin/assets/src/util/logger/Logger.js +1 -0
- package/bin/assets/src/util/logger/index.d.ts +15 -0
- package/bin/assets/src/util/logger/index.js +2 -0
- package/bin/assets/src/util/logger/logDir.d.ts +5 -0
- package/bin/assets/src/util/logger/logDir.js +1 -0
- package/bin/assets/src/util/logger/types.d.ts +48 -0
- package/bin/assets/src/util/logger/types.js +1 -0
- package/bin/assets/src/util/nonInteractive/index.d.ts +3 -0
- package/bin/assets/src/util/nonInteractive/index.js +1 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveCallbacks.d.ts +18 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveCallbacks.js +1 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveCascadeOutput.d.ts +51 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveCascadeOutput.js +1 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveLabels.d.ts +23 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveLabels.js +1 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveOutput.d.ts +128 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveOutput.js +4 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveSummaryOutput.d.ts +29 -0
- package/bin/assets/src/util/nonInteractive/nonInteractiveSummaryOutput.js +3 -0
- package/bin/assets/src/util/organisationStructure.d.ts +9 -0
- package/bin/assets/src/util/organisationStructure.js +1 -0
- package/bin/assets/src/util/parseTakeOption.d.ts +1 -0
- package/bin/assets/src/util/parseTakeOption.js +1 -0
- package/bin/assets/src/util/passwordValidation.d.ts +22 -0
- package/bin/assets/src/util/passwordValidation.js +1 -0
- package/bin/assets/src/util/pathHelpers.d.ts +19 -0
- package/bin/assets/src/util/pathHelpers.js +1 -0
- package/bin/assets/src/util/patternDetection.d.ts +7 -0
- package/bin/assets/src/util/patternDetection.js +1 -0
- package/bin/assets/src/util/promptYesNo.d.ts +5 -0
- package/bin/assets/src/util/promptYesNo.js +1 -0
- package/bin/assets/src/util/readStdin.d.ts +9 -0
- package/bin/assets/src/util/readStdin.js +1 -0
- package/bin/assets/src/util/secretsUtils.d.ts +155 -0
- package/bin/assets/src/util/secretsUtils.js +3 -0
- package/bin/assets/src/util/signalCleanup.d.ts +13 -0
- package/bin/assets/src/util/signalCleanup.js +4 -0
- package/bin/assets/src/util/stripAnsi.d.ts +2 -0
- package/bin/assets/src/util/stripAnsi.js +1 -0
- package/bin/assets/src/util/synchronizedOutput.d.ts +26 -0
- package/bin/assets/src/util/synchronizedOutput.js +1 -0
- package/bin/assets/src/util/targetDetection.d.ts +27 -0
- package/bin/assets/src/util/targetDetection.js +1 -0
- package/bin/assets/src/util/targetHelpers.d.ts +20 -0
- package/bin/assets/src/util/targetHelpers.js +1 -0
- package/bin/assets/src/util/terminalCapabilities.d.ts +21 -0
- package/bin/assets/src/util/terminalCapabilities.js +1 -0
- package/bin/assets/src/util/terminalEscapes.d.ts +29 -0
- package/bin/assets/src/util/terminalEscapes.js +1 -0
- package/bin/assets/src/util/terminalFocus.d.ts +33 -0
- package/bin/assets/src/util/terminalFocus.js +1 -0
- package/bin/assets/src/util/theme.d.ts +80 -0
- package/bin/assets/src/util/theme.js +1 -0
- package/bin/assets/src/util/truncateMiddle.d.ts +9 -0
- package/bin/assets/src/util/truncateMiddle.js +1 -0
- package/bin/assets/src/util/typeGuards.d.ts +5 -0
- package/bin/assets/src/util/typeGuards.js +1 -0
- package/bin/assets/src/util/uiRouter.d.ts +13 -0
- package/bin/assets/src/util/uiRouter.js +1 -0
- package/bin/assets/src/util/urlHelpers.d.ts +4 -0
- package/bin/assets/src/util/urlHelpers.js +1 -0
- package/bin/assets/src/util/versionDisplay.d.ts +5 -0
- package/bin/assets/src/util/versionDisplay.js +1 -0
- package/bin/fjall.bundle.js +736 -564
- package/package.json +38 -35
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{join as m}from"path";import{copySharedCdkFiles as u}from"../utils/copySharedFiles.js";import{getInfrastructurePath as d,getAppPath as l}from"../../src/util/pathHelpers.js";import{planApplicationResources as f,planOpenNextResources as g,generateInfrastructureFromPlan as b,ApplicationGeneratorSchema as w,getZodErrorMessage as h}from"@fjall/generator";import{z as y}from"zod";async function C(n,r){let e;try{e=w.parse(r)}catch(t){throw t instanceof y.ZodError?new Error(`Invalid application generator options:
|
|
2
|
-
${h(t)}
|
|
2
|
+
${h(t)}`,{cause:t}):t}let o;if(e.pattern){const t=e.includeDatabase??!0,a=e.patternTier||"standard",c=t?a==="custom"&&e.customDatabase?{type:e.customDatabase.type,instanceType:e.customDatabase.instanceType,databaseName:e.databaseName,backupRetention:e.customDatabase.backupRetention,deletionProtection:e.customDatabase.deletionProtection,encryption:e.customDatabase.encryption}:{databaseName:e.databaseName}:void 0,p=a==="custom"&&e.customCompute?{memorySize:e.customCompute.memorySize,timeout:e.customCompute.timeout}:void 0,i=g(e.name,e.pattern,{tier:a,domain:e.patternDomain,database:c,compute:p});if(!i.success)throw new Error(i.error.message);o=i.data}else if(e.type==="custom")o=await k(e);else{const t=e.services?.map(a=>({name:a.name,...a.docker!==void 0&&{docker:a.docker},containerPort:a.containerPort,needsDatabaseConnection:a.needsDatabaseConnection,routing:a.routing}));o=f(e.name,e.type,e.includeDatabase??!0,t,{snapshotIdentifier:e.snapshotIdentifier,snapshotUsername:e.snapshotUsername})}e.owner&&(o.owner=e.owner),e.vpcId&&(o.vpcId=e.vpcId),e.network!==void 0&&(o.network=e.network===!1?void 0:e.network);const s=b(o);if(!s.success)throw new Error(s.error.message);if(n.write(d(e.name),s.data),e.pattern==="payload"||e.pattern==="nextjs"){const t=m(l(e.name),"open-next.config.ts");n.write(t,D())}u(n,e.name,{name:e.name,type:e.type,packageName:e.name})}async function k(n){const r=n.network||void 0;return{appName:n.name,type:"custom",owner:n.owner,network:r,database:[],s3:[],compute:[]}}function D(){return`// OpenNext configuration - Generated by Fjall CLI
|
|
3
3
|
const sharpInstallConfig = {
|
|
4
4
|
packages: ["sharp@0.34.2", "typescript@5.7.3"],
|
|
5
5
|
arch: "arm64" as const,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertResourceNameUnique as o}from"../utils/resources/resourceDetection.js";import{withInfrastructurePlan as s}from"../utils/planning/generatorHelpers.js";import{ComputeGeneratorSchema as i}from"@fjall/generator";import{ensureUniqueResourceName as f}from"../utils/resources/resourceNaming.js";import{promptForConnection as y,selectResources as h}from"../utils/prompts.js";function p(r,e,n){const t=n.length>0;switch(e.type){case"ecs":return{name:r,type:"ecs",needsConnection:t,connectedDatabase:n,cluster:e.cluster,services:e.services
|
|
1
|
+
import{assertResourceNameUnique as o}from"../utils/resources/resourceDetection.js";import{withInfrastructurePlan as s}from"../utils/planning/generatorHelpers.js";import{ComputeGeneratorSchema as i}from"@fjall/generator";import{ensureUniqueResourceName as f}from"../utils/resources/resourceNaming.js";import{promptForConnection as y,selectResources as h}from"../utils/prompts.js";function p(r,e,n){const t=n.length>0;switch(e.type){case"ecs":return{name:r,type:"ecs",needsConnection:t,connectedDatabase:n,cluster:e.cluster,services:e.services,...e.docker!==void 0&&{docker:e.docker}};case"lambda":return{name:r,type:"lambda",needsConnection:t,connectedDatabase:n,timeout:e.timeout,memory:e.memory,handler:e.handler,runtime:e.runtime,environment:e.environment,secrets:e.secrets};case"ec2":return{name:r,type:"ec2",needsConnection:t,connectedDatabase:n,instanceType:e.instanceType,enableSSH:e.enableSSH,keyName:e.keyName,userData:e.userData,securityGroups:e.securityGroups};default:return e}}async function C(r,e){await s(r,i,e,"compute",async({tree:n,validated:t,plan:a})=>{t.nameProvidedByFlag||o(n,t.appName,t.computeName);const c=t.nameProvidedByFlag?f(n,t.appName,t.computeName):t.computeName,m=await b(t,a),u=p(c,t,m);return{...a,compute:[...a.compute,u]}})}async function b(r,e){return r.connectionConfig?r.connectionConfig.connectToDatabase??[]:e.database.length>0&&!r.nameProvidedByFlag&&await y(e.database.length,"database","Connect to existing database?","Found {count} databases. Configure connections?")?h(e.database,"Select databases to connect:",t=>`${t.type} - ${t.databaseName}`):[]}var w=C;export{C as computeGenerator,w as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AddServiceGeneratorSchema as
|
|
1
|
+
import{AddServiceGeneratorSchema as p}from"@fjall/generator";import{withInfrastructurePlan as h}from"../../utils/planning/generatorHelpers.js";async function a(m,g){await h(m,p,g,"service",({validated:e,plan:i})=>{const t=i.compute.find(n=>n.name===e.clusterName&&n.type==="ecs");if(!t)throw new Error(`ECS cluster '${e.clusterName}' not found. Available clusters: ${i.compute.filter(n=>n.type==="ecs").map(n=>n.name).join(", ")||"none"}`);const c=t.services||[];if(c.some(n=>n.name===e.serviceName))throw new Error(`Service '${e.serviceName}' already exists in cluster '${e.clusterName}'`);const o={name:e.serviceName,capacityProvider:e.capacityProvider};if(e.cpu!==void 0&&(o.cpu=e.cpu),e.memoryLimitMiB!==void 0&&(o.memoryLimitMiB=e.memoryLimitMiB),e.desiredCount!==void 0&&(o.desiredCount=e.desiredCount),e.ec2Config!==void 0&&(o.ec2Config=e.ec2Config),e.routing!==void 0&&(o.routing=e.routing),e.docker?.path!==void 0){const n=e.docker.context,r=e.docker.target;o.docker={path:e.docker.path,...n!==void 0&&{context:n},...r!==void 0&&{target:r}}}if(e.containerPort&&(o.containers=[{port:e.containerPort}]),e.connectionConfig?.connectToDatabase?.length){o.needsDatabaseConnection=!0;const n=t.connectedDatabase||[],r=e.connectionConfig.connectToDatabase.filter(u=>!n.includes(u));r.length>0&&(t.connectedDatabase=[...n,...r],t.needsConnection=!0)}t.services=[...c,o];const s=t.services.filter(n=>n.containers?.some(r=>r.port));if(s.length>1){const n=s.filter(r=>!(Array.isArray(r.routing)?r.routing:r.routing?[r.routing]:[]).some(f=>f.path||f.host));if(n.length>0)throw new Error(`Multiple services have container ports \u2014 all must have routing configuration. Services missing routing: ${n.map(r=>r.name).join(", ")}`)}return i})}var w=a;export{w as default,a as serviceGenerator};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{assertResourceNameUnique as
|
|
1
|
+
import{assertResourceNameUnique as b,databaseExists as p}from"../utils/resources/resourceDetection.js";import{pickDefined as t,withInfrastructurePlan as d}from"../utils/planning/generatorHelpers.js";import{DatabaseGeneratorSchema as l}from"@fjall/generator";import{handleResourceConnections as f}from"../utils/resources/connectionHelpers.js";function h(s,e){const r={name:s,type:e.databaseType,databaseName:e.databaseName,...t(e,"databaseInsights","port","proxy","credentials","encryption","deletionProtection")};switch(e.databaseType){case"Instance":return{...r,...t(e,"instanceType","multiAz","readReplica","publiclyAccessible","backupRetention","snapshotIdentifier","snapshotUsername")};case"Aurora":return{...r,...t(e,"writer","readers","backupRetention","preferredMaintenanceWindow","snapshotIdentifier","snapshotUsername")};case"GlobalAurora":return{...r,primaryRegion:e.primaryRegion,...e.secondaryRegions&&e.secondaryRegions.length>0&&{secondaryRegions:e.secondaryRegions},...t(e,"globalClusterIdentifier","enableGlobalWriteForwarding","writer","readers","backupRetention","preferredMaintenanceWindow","snapshotIdentifier","snapshotUsername")};default:return e}}function y(s,e){return{name:s,type:"ClickHouse",databaseName:e.databaseName,...t(e,"instanceType","coldTier","optimiseSchedule","backupSchedule","backupRetentionDays")}}async function R(s,e){await d(s,l,e,"database",async({tree:r,validated:a,plan:n})=>{const u=a.databaseType==="ClickHouse",m=u?`${a.appName}Analytics`:`${a.appName}Database`,c=a.resourceName||m;if(b(r,a.appName,c),p(r,a.appName,a.databaseName))throw new Error(`Database name '${a.databaseName}' already exists in ${a.appName}. Please choose a different database name.`);let o;if(u){const i=y(c,a);o={...n,clickhouse:[...n.clickhouse??[],i]}}else{const i=h(c,a);o={...n,database:[...n.database,i]}}return await f(o,a,c,"database",{singularPrompt:"Found an existing compute resource. Configure database access for it?",pluralPrompt:"Found {count} compute resources. Configure database access for them?"}),o})}var C=R;export{R as databaseGenerator,C as default};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{join as i}from"path";import{renderEjsTemplates as d}from"../utils/renderEjs.js";import{copySharedCdkFiles as p}from"../utils/copySharedFiles.js";import{getDomainComponentPath as c}from"../../src/util/pathHelpers.js";import{z as e}from"zod";import{VALIDATION_PATTERNS as f,VALIDATION_MESSAGES as l,getZodErrorMessage as u}from"@fjall/generator";import{toPascalCase as N}from"../../src/util/caseConversion.js";const
|
|
2
|
-
${u(r.error)}`);const o=r.data,m=N(o.domainName.split(".").join("")),a=c(o.domainName),n={domainName:o.domainName,safeZoneName:m,hostedZoneId:o.hostedZoneId??""};d(t,i(
|
|
1
|
+
import{join as i}from"path";import{renderEjsTemplates as d}from"../utils/renderEjs.js";import{copySharedCdkFiles as p}from"../utils/copySharedFiles.js";import{getDomainComponentPath as c}from"../../src/util/pathHelpers.js";import{z as e}from"zod";import{VALIDATION_PATTERNS as f,VALIDATION_MESSAGES as l,getZodErrorMessage as u}from"@fjall/generator";import{toPascalCase as N}from"../../src/util/caseConversion.js";const I=import.meta.dirname,g=e.object({domainName:e.string().regex(f.DOMAIN,l.DOMAIN),hostedZoneId:e.string().min(1,"hostedZoneId cannot be empty").optional(),infrastructureTs:e.string().optional()}).strict();async function h(t,s){const r=g.safeParse(s);if(!r.success)throw new Error(`Invalid domain generator options:
|
|
2
|
+
${u(r.error)}`);const o=r.data,m=N(o.domainName.split(".").join("")),a=c(o.domainName),n={domainName:o.domainName,safeZoneName:m,hostedZoneId:o.hostedZoneId??""};d(t,i(I,"files"),a,n),o.infrastructureTs!==void 0&&t.write(i(a,"infrastructure.ts"),o.infrastructureTs),p(t,a,{...n,packageName:`domain-${o.domainName}`})}var P=h;export{g as DomainGeneratorSchema,P as default,h as domainGenerator};
|
|
@@ -27,11 +27,17 @@ if (config.environment === "root") {
|
|
|
27
27
|
organisationName: "<%= name %>",
|
|
28
28
|
orgEmail: "<%= email %>"
|
|
29
29
|
});
|
|
30
|
+
<% if (security === "compliance" || security === "hardened") { -%>
|
|
31
|
+
|
|
32
|
+
const rootIdCtx = organisation.node.tryGetContext("rootId");
|
|
33
|
+
const rootId =
|
|
34
|
+
typeof rootIdCtx === "string" && rootIdCtx !== "" ? rootIdCtx : undefined;
|
|
35
|
+
<% } -%>
|
|
30
36
|
<% if (security === "compliance") { -%>
|
|
31
37
|
|
|
32
38
|
organisation.enableScps({
|
|
33
39
|
preset: "standard",
|
|
34
|
-
rootId
|
|
40
|
+
rootId,
|
|
35
41
|
allowedRegions: ALLOWED_REGIONS
|
|
36
42
|
});
|
|
37
43
|
<% } -%>
|
|
@@ -39,7 +45,7 @@ if (config.environment === "root") {
|
|
|
39
45
|
|
|
40
46
|
organisation.enableScps({
|
|
41
47
|
preset: "hardened",
|
|
42
|
-
rootId
|
|
48
|
+
rootId,
|
|
43
49
|
allowedRegions: ALLOWED_REGIONS
|
|
44
50
|
});
|
|
45
51
|
<% } -%>
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "<%= packageName %>",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.99.1",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"scripts": {},
|
|
5
6
|
"devDependencies": {
|
|
6
|
-
"@types/node": "
|
|
7
|
-
"
|
|
8
|
-
"typescript": "~
|
|
7
|
+
"@types/node": "25.6.0",
|
|
8
|
+
"tsx": "^4.21.0",
|
|
9
|
+
"typescript": "~6.0.3"
|
|
9
10
|
},
|
|
10
11
|
"dependencies": {
|
|
11
|
-
"@fjall/components-infrastructure": "^0.
|
|
12
|
-
"aws-cdk-lib": "^2.
|
|
13
|
-
"constructs": "^10.
|
|
12
|
+
"@fjall/components-infrastructure": "^0.99.1",
|
|
13
|
+
"aws-cdk-lib": "^2.251.0",
|
|
14
|
+
"constructs": "^10.6.0"
|
|
14
15
|
}
|
|
15
16
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
4
|
-
"module": "
|
|
5
|
-
"
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["es2022"],
|
|
6
7
|
"declaration": true,
|
|
7
8
|
"strict": true,
|
|
8
9
|
"noImplicitAny": true,
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
"inlineSources": true,
|
|
18
19
|
"experimentalDecorators": true,
|
|
19
20
|
"strictPropertyInitialization": false,
|
|
20
|
-
"
|
|
21
|
+
"skipLibCheck": true
|
|
21
22
|
},
|
|
22
23
|
"exclude": ["node_modules", "cdk.out"]
|
|
23
24
|
}
|
|
@@ -97,6 +97,12 @@ export interface CdkSynthResult {
|
|
|
97
97
|
export declare function runCdkSynth(appName: string, options?: {
|
|
98
98
|
context?: Record<string, unknown>;
|
|
99
99
|
}): CdkSynthResult;
|
|
100
|
+
/**
|
|
101
|
+
* Patch package.json + ensure node_modules for a test app, without running
|
|
102
|
+
* `cdk synth`. Use this when a test only needs `tsc --noEmit` (or another
|
|
103
|
+
* non-synth probe) against the generated `infrastructure.ts`.
|
|
104
|
+
*/
|
|
105
|
+
export declare function prepareTestApp(appName: string): boolean;
|
|
100
106
|
/**
|
|
101
107
|
* Clean up a test app directory.
|
|
102
108
|
* Handles symlinked node_modules properly.
|
|
@@ -104,6 +110,9 @@ export declare function runCdkSynth(appName: string, options?: {
|
|
|
104
110
|
export declare function cleanupTestApp(appName: string): void;
|
|
105
111
|
/**
|
|
106
112
|
* Read a CloudFormation template from cdk.out.
|
|
113
|
+
*
|
|
114
|
+
* Stack names use `toPascalCase(appName)` as prefix to match the transformation
|
|
115
|
+
* in `App.getApp()` (see `components/infrastructure/lib/app.ts`).
|
|
107
116
|
*/
|
|
108
117
|
export declare function readCfnTemplate(appName: string, stackSuffix: string): CfnTemplate;
|
|
109
118
|
/**
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
import r from"fs";import o from"path";import{execFileSync as p}from"child_process";import{normaliseError as
|
|
2
|
-
`)
|
|
1
|
+
import r from"fs";import o from"path";import{execFileSync as p}from"child_process";import{toPascalCase as y}from"@fjall/util";import{normaliseError as b}from"../../src/util/errorUtils.js";const a=o.resolve(import.meta.dirname,"../.."),u=o.join(a,"fjall"),d=o.resolve(a,"../components/infrastructure"),x=o.join(a,"test-fixtures"),f=o.join(x,"node_modules"),l="123456789012",s="ap-southeast-2";function v(n,e){const t=o.join(u,n);return S(t),_(t,e?.context),m(t)?g(t):{success:!1,output:"Failed to set up node_modules"}}function O(n){const e=o.join(u,n);return S(e),m(e)}function m(n){const e=o.join(n,"node_modules");if(r.existsSync(f))try{return r.existsSync(e)&&(r.lstatSync(e).isSymbolicLink()?r.unlinkSync(e):r.rmSync(e,{recursive:!0,force:!0})),r.symlinkSync(f,e,"junction"),!0}catch(t){process.stderr.write(`integrationTestUtils: symlink to shared node_modules failed, falling back to npm install: ${t instanceof Error?t.message:String(t)}
|
|
2
|
+
`)}if(!r.existsSync(e))try{p("npm",["install"],{cwd:n,encoding:"utf-8",timeout:12e4})}catch(t){return process.stderr.write(`integrationTestUtils: npm install in ${n} failed: ${t instanceof Error?t.message:String(t)}
|
|
3
|
+
`),!1}return!0}function g(n){try{const e=o.join(n,"node_modules",".bin","cdk");return{success:!0,output:p(e,["synth"],{cwd:n,encoding:"utf-8",timeout:12e4,stdio:["pipe","pipe","pipe"],env:{...process.env,AWS_REGION:s,AWS_DEFAULT_REGION:s,CDK_DEFAULT_ACCOUNT:l,CDK_DEFAULT_REGION:s}})}}catch(e){const t=b(e),i="stdout"in t&&typeof t.stdout=="string"?t.stdout:void 0,c="stderr"in t&&typeof t.stderr=="string"?t.stderr:void 0;return{success:!1,output:i||c||t.message||"Unknown error"}}}function S(n){const e=o.join(n,"package.json"),t=JSON.parse(r.readFileSync(e,"utf-8"));t.dependencies["@fjall/components-infrastructure"]=`file:${d}`,r.writeFileSync(e,JSON.stringify(t,null,2))}function _(n,e){const t={app:"./node_modules/.bin/tsx infrastructure.ts",context:{"aws:cdk:bundling-stacks":[],[`availability-zones:account=${l}:region=${s}`]:[`${s}a`,`${s}b`,`${s}c`],[`vpc-provider:account=${l}:filter.isDefault=true:region=${s}:returnAsymmetricSubnets=true`]:{vpcId:"vpc-12345678",vpcCidrBlock:"10.0.0.0/16",availabilityZones:[`${s}a`,`${s}b`],publicSubnetIds:["subnet-pub1","subnet-pub2"],publicSubnetRouteTableIds:["rtb-pub1","rtb-pub2"],privateSubnetIds:["subnet-priv1","subnet-priv2"],privateSubnetRouteTableIds:["rtb-priv1","rtb-priv2"]},...e}};r.writeFileSync(o.join(n,"cdk.json"),JSON.stringify(t,null,2))}function h(n){const e=o.join(u,n);if(!r.existsSync(e))return;const t=o.join(e,"node_modules");r.existsSync(t)&&r.lstatSync(t).isSymbolicLink()&&r.unlinkSync(t),r.rmSync(e,{recursive:!0,force:!0})}function $(n,e){const t=o.join(u,n,"cdk.out",`${y(n)}${e}.template.json`);if(!r.existsSync(t))throw new Error(`Template not found: ${t}`);return JSON.parse(r.readFileSync(t,"utf-8"))}function I(n){const e=o.join(u,n,"infrastructure.ts");if(!r.existsSync(e))throw new Error(`Infrastructure file not found: ${e}`);return r.readFileSync(e,"utf-8")}function w(n,e){return Object.entries(n.Resources).filter(([,t])=>t.Type===e).map(([t,i])=>({logicalId:t,properties:i.Properties}))}function D(n,e){return n.find(t=>t.properties.GroupDescription?.includes(e))}function N(n,e){const t=e==="path-pattern"?"PathPatternConfig":"HostHeaderConfig";return n.flatMap(i=>i.properties.Conditions?.filter(c=>c.Field===e).flatMap(c=>c[t]?.Values??c.Values??[])).filter(i=>i!==void 0)}function R(){r.existsSync(o.join(d,"dist"))||(process.stdout.write(`Building components-infrastructure...
|
|
4
|
+
`),p("npm",["run","build"],{cwd:d,stdio:"inherit"}))}export{a as CLI_ROOT,d as COMPONENTS_DIR,l as MOCK_ACCOUNT,s as MOCK_REGION,f as SHARED_NODE_MODULES,u as TEST_APPS_DIR,x as TEST_FIXTURES_DIR,h as cleanupTestApp,R as ensureComponentsBuilt,N as extractConditionValues,w as findResourcesByType,D as findSecurityGroupByDescription,I as getInfrastructureContent,O as prepareTestApp,$ as readCfnTemplate,v as runCdkSynth};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import*as
|
|
2
|
-
${
|
|
1
|
+
import*as i from"fs";import*as w from"path";import{maskSensitiveOutput as h}from"@fjall/util";import{logger as g}from"../../../src/util/logger/index.js";import{normaliseError as d}from"../../../src/util/errorUtils.js";import{success as p,failure as a}from"../../../src/types/Result.js";import{parseInfrastructure as k,convertToResourcePlan as x,getZodErrorMessage as P,generateInfrastructureFromPlan as $}from"@fjall/generator";import{getInfrastructurePath as E}from"../../../src/util/pathHelpers.js";function I(t,o,r){const e=t.root?w.join(t.root,o):o;try{if(i.existsSync(e)){const s=`${e}.bak`,n=`${s}.tmp`;i.writeFileSync(n,r),i.renameSync(n,s)}return p(void 0)}catch(s){const n=d(s);return g.warn("Generator",`Failed to create backup of ${o}`,{error:h(n.message)}),a(n)}}function G(t,...o){const r={};for(const e of o)t[e]!==void 0&&(r[e]=t[e]);return r}function y(t,o){try{const r=k(t,{extractCustomCode:!0}),e=x(r,o,{skipValidation:!0});return r.customCodeBlocks?.length&&(e.customCodeBlocks=r.customCodeBlocks),p({parsed:r,plan:e})}catch(r){return a(d(r))}}function b(t,o){const r=y(t,o);if(!r.success)throw new Error(`Failed to parse infrastructure: ${r.error.message}`,{cause:r.error});return r.data}function B(t,o,r){const e=t.safeParse(o);if(!e.success)throw new Error(`Invalid ${r} generator options:
|
|
2
|
+
${P(e.error)}`);return e.data}function v(t,o){const r=E(o),e=t.read(r)?.toString();if(!e)throw new Error(`App '${o}' not found. Expected infrastructure.ts at: ${r}`);return{path:r,content:e}}async function j(t,o,r,e,s){const n=B(o,r,e),{path:f,content:c}=v(t,n.appName),{plan:l}=b(c,n.appName),m=await s({tree:t,validated:n,plan:l,infrastructurePath:f,content:c}),u=C(t,f,c,m);if(!u.success)throw new Error(u.error.message,{cause:u.error})}function C(t,o,r,e){const s=$(e);if(!s.success)return a(s.error);const n=I(t,o,r);return n.success?(t.write(o,s.data),p(void 0)):a(new Error(`Failed to create backup: ${n.error.message}`))}export{I as createInfrastructureBackup,C as generateAndWriteInfrastructure,y as parseAndBuildPlan,b as parseAndBuildPlanOrThrow,G as pickDefined,v as readInfrastructureOrThrow,B as validateGeneratorOptions,j as withInfrastructurePlan};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test constants and helpers for FjallApiClient test files.
|
|
3
|
+
*
|
|
4
|
+
* vi.mock() calls must remain in each test file (Vitest hoisting),
|
|
5
|
+
* but these constants and factory functions can be shared.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TEST_API_KEY = "fj_test_key_abc123";
|
|
8
|
+
export declare const TEST_BASE_URL = "https://test.fjall.io";
|
|
9
|
+
export declare function createClient(FjallApiClientClass: new (apiKey: string, baseUrl: string) => unknown, apiKey?: string, baseUrl?: string): unknown;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o="fj_test_key_abc123",_="https://test.fjall.io";function r(t,e=o,n=_){return new t(e,n)}export{o as TEST_API_KEY,_ as TEST_BASE_URL,r as createClient};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
export declare function rawLines(): string[];
|
|
3
|
+
export declare function plainLines(): string[];
|
|
4
|
+
export declare function getWriteSpy(): ReturnType<typeof vi.spyOn>;
|
|
5
|
+
/**
|
|
6
|
+
* Registers beforeEach/afterEach hooks that spy on process.stdout.write.
|
|
7
|
+
* Call once at the top of your describe block or test file.
|
|
8
|
+
*/
|
|
9
|
+
export declare function installStdoutSpy(): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{vi as e,beforeEach as n,afterEach as o}from"vitest";import i from"strip-ansi";let t;function p(){return t.mock.calls.map(r=>String(r[0]).replace(/\n$/,""))}function m(){return p().map(r=>i(r))}function s(){return t}function u(){n(()=>{t=e.spyOn(process.stdout,"write").mockImplementation(()=>!0)}),o(()=>{t.mockRestore()})}export{s as getWriteSpy,u as installStdoutSpy,m as plainLines,p as rawLines};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TOON capture spy for AXI agent-mode tests.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `installStdoutSpy` from `outputTestHelpers.ts` but accumulates
|
|
5
|
+
* writes into a buffer, splits on the `---` block separator, and parses
|
|
6
|
+
* each block as TOON via `@toon-format/toon`.
|
|
7
|
+
*
|
|
8
|
+
* The helper handles:
|
|
9
|
+
*
|
|
10
|
+
* 1. Multiple blocks flushed in a single `write()` call
|
|
11
|
+
* 2. A single block spanning multiple `write()` calls
|
|
12
|
+
* 3. Malformed TOON blocks (recorded as `malformed` events, never thrown)
|
|
13
|
+
*
|
|
14
|
+
* Tests that assert on the final block without a trailing `---` separator
|
|
15
|
+
* must call `capture.flush()` before querying, otherwise the lazy parser
|
|
16
|
+
* will still include the tail — parsing happens across the entire buffer
|
|
17
|
+
* regardless, but `flush()` is retained as an explicit no-op sync point
|
|
18
|
+
* for readability and future-proofing.
|
|
19
|
+
*/
|
|
20
|
+
import { vi } from "vitest";
|
|
21
|
+
export type CapturedEventType = "data" | "error" | "action_required" | "step" | "progress" | "malformed";
|
|
22
|
+
export interface CapturedToonEvent {
|
|
23
|
+
readonly type: CapturedEventType;
|
|
24
|
+
readonly block: string;
|
|
25
|
+
readonly parsed: unknown;
|
|
26
|
+
readonly timestamp: number;
|
|
27
|
+
readonly error?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ToonCapture {
|
|
30
|
+
events: () => readonly CapturedToonEvent[];
|
|
31
|
+
rawBuffer: () => string;
|
|
32
|
+
parsed: () => readonly CapturedToonEvent[];
|
|
33
|
+
malformed: () => readonly CapturedToonEvent[];
|
|
34
|
+
ofType: (type: CapturedEventType) => readonly CapturedToonEvent[];
|
|
35
|
+
last: () => CapturedToonEvent | undefined;
|
|
36
|
+
flush: () => void;
|
|
37
|
+
clear: () => void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Matches a line containing only the block separator with optional
|
|
41
|
+
* surrounding whitespace. Multiline mode so `^` and `$` match line boundaries.
|
|
42
|
+
*/
|
|
43
|
+
declare const BLOCK_SEPARATOR_RE: RegExp;
|
|
44
|
+
/**
|
|
45
|
+
* Matches a trailing `help[N]:` section at the end of a TOON block.
|
|
46
|
+
*
|
|
47
|
+
* `renderHelp()` produces `help[N]:\n line1\n line2` which is NOT valid
|
|
48
|
+
* TOON — the decoder interprets `help[N]:` as a typed array header and fails
|
|
49
|
+
* to parse the indented text lines. We strip this section before decoding
|
|
50
|
+
* and preserve it as metadata on the event.
|
|
51
|
+
*/
|
|
52
|
+
declare const HELP_BLOCK_RE: RegExp;
|
|
53
|
+
/**
|
|
54
|
+
* Installs beforeEach/afterEach hooks that spy on `process.stdout.write`,
|
|
55
|
+
* accumulating every chunk into an in-memory buffer. Returns a handle
|
|
56
|
+
* whose query methods parse the buffer lazily (only when called).
|
|
57
|
+
*
|
|
58
|
+
* Call once at the top of a describe block or test file, exactly like
|
|
59
|
+
* `installStdoutSpy()`.
|
|
60
|
+
*/
|
|
61
|
+
export declare function installToonCapture(): ToonCapture;
|
|
62
|
+
/**
|
|
63
|
+
* Asserts the capture contains at least one valid TOON block and zero
|
|
64
|
+
* malformed blocks.
|
|
65
|
+
*/
|
|
66
|
+
export declare function assertValidToon(capture: ToonCapture): void;
|
|
67
|
+
/**
|
|
68
|
+
* Asserts the last captured block exists and has the expected type.
|
|
69
|
+
* Consolidates the common guard pattern across TOON snapshot tests.
|
|
70
|
+
*/
|
|
71
|
+
export declare function assertLastBlockType(capture: ToonCapture, expectedType: CapturedEventType): void;
|
|
72
|
+
/**
|
|
73
|
+
* Creates a mock OutputWriter with vi.fn() methods. Use in tests that
|
|
74
|
+
* pass a writer directly to handler functions (e.g. secrets set/delete).
|
|
75
|
+
*/
|
|
76
|
+
export declare function createMockWriter(): Record<string, ReturnType<typeof vi.fn>>;
|
|
77
|
+
/**
|
|
78
|
+
* Returns a mock configuration for `nonInteractiveOutput.js`. Use inside
|
|
79
|
+
* `vi.mock()` factory calls to avoid duplicating the OutputWriter stub.
|
|
80
|
+
*/
|
|
81
|
+
export declare function createOutputWriterMock(): Record<string, unknown>;
|
|
82
|
+
/**
|
|
83
|
+
* Returns a mock configuration for `logger/index.js`. Use inside
|
|
84
|
+
* `vi.mock()` factory calls to avoid duplicating the logger stub.
|
|
85
|
+
*/
|
|
86
|
+
export declare function createLoggerMock(): Record<string, unknown>;
|
|
87
|
+
/**
|
|
88
|
+
* Returns a standard mock theme with consistent colour values.
|
|
89
|
+
*/
|
|
90
|
+
export declare function createThemeMock(): Record<string, unknown>;
|
|
91
|
+
export { BLOCK_SEPARATOR_RE, HELP_BLOCK_RE };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{afterEach as y,beforeEach as g,expect as c,vi as r}from"vitest";import{decode as h}from"@toon-format/toon";import{BLOCK_SEPARATOR as E}from"../toonFormatter.js";let p,s="",n=[],i=!1;const m=new RegExp(`^\\s*${E.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\s*$`,"m"),d=/\nhelp\[\d+\]:(?:\n {2}[^\n]*)*\s*$/;function k(e){if(typeof e!="object"||e===null||Array.isArray(e))return"data";const t=e;if("error"in t&&"code"in t)return"error";if("action"in t&&"userActionRequired"in t)return"action_required";for(const o of Object.keys(t))if(o.includes(".step"))return"step";for(const o of Object.keys(t))if(o.endsWith(".progress"))return"progress";return"data"}function a(){if(!i)return;n=[];const e=s.split(m);for(const t of e){const o=t.trim();if(o.length===0)continue;const u=o.replace(d,"").trim();if(u.length===0)continue;const l=Date.now();try{const f=h(u);n.push({type:k(f),block:o,parsed:f,timestamp:l})}catch(f){n.push({type:"malformed",block:o,parsed:void 0,timestamp:l,error:f instanceof Error?f.message:String(f)})}}i=!1}function B(){return g(()=>{s="",n=[],i=!1,p=r.spyOn(process.stdout,"write").mockImplementation((e=>{const t=typeof e=="string"?e:Buffer.from(e).toString("utf8");return s+=t,i=!0,!0}))}),y(()=>{p?.mockRestore(),p=void 0,s="",n=[],i=!1}),{events:()=>(a(),n),rawBuffer:()=>s,parsed:()=>(a(),n.filter(e=>e.type!=="malformed")),malformed:()=>(a(),n.filter(e=>e.type==="malformed")),ofType:e=>(a(),n.filter(t=>t.type===e)),last:()=>(a(),n.length===0?void 0:n[n.length-1]),flush:()=>{a()},clear:()=>{s="",n=[],i=!1}}}function T(e){c(e.malformed()).toHaveLength(0);const t=e.parsed();c(t.length).toBeGreaterThan(0)}function S(e,t){T(e);const o=e.last();c(o).toBeDefined(),c(o?.type).toBe(t)}function b(){return{line:r.fn(),indent:r.fn(),stepStart:r.fn(),stepComplete:r.fn(),summary:r.fn(),dockerProgress:r.fn()}}function A(){return{OutputWriter:class{stepStart=r.fn();stepComplete=r.fn();indent=r.fn();line=r.fn();summary=r.fn();dockerProgress=r.fn()},STEP_STATUS:{COMPLETED:"completed",ERROR:"error"}}}function L(){return{logger:{debug:r.fn(),info:r.fn(),warn:r.fn(),error:r.fn()}}}function w(){return{theme:{colours:{primary:"#6366f1",completed:"#00ff00",error:"#ff0000",warning:"#ffaa00",dim:"#888888"}}}}export{m as BLOCK_SEPARATOR_RE,d as HELP_BLOCK_RE,S as assertLastBlockType,T as assertValidToon,L as createLoggerMock,b as createMockWriter,A as createOutputWriterMock,w as createThemeMock,B as installToonCapture};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action-required payload factories for common CLI gates. Each factory
|
|
3
|
+
* returns a structured ActionRequired object that the agent can parse
|
|
4
|
+
* to determine whether it can resolve the gate itself (add a flag,
|
|
5
|
+
* run a command) or must escalate to a human.
|
|
6
|
+
*/
|
|
7
|
+
import type { ActionRequired } from "./schemas/types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Emitted when a command would destroy infrastructure and the user has
|
|
10
|
+
* not passed `--skip-confirmation` or `--yes`.
|
|
11
|
+
*
|
|
12
|
+
* The agent can resolve this autonomously by re-running with the flag.
|
|
13
|
+
*/
|
|
14
|
+
export declare function destructiveGate(command: string, target: string): ActionRequired;
|
|
15
|
+
/**
|
|
16
|
+
* Emitted when a required flag is missing from the invocation.
|
|
17
|
+
*
|
|
18
|
+
* The agent can resolve this by adding the missing flag.
|
|
19
|
+
*/
|
|
20
|
+
export declare function missingFlagGate(command: string, flag: string, description: string): ActionRequired;
|
|
21
|
+
/**
|
|
22
|
+
* Emitted when the user is not authenticated.
|
|
23
|
+
*
|
|
24
|
+
* If an API key is available the agent can resolve this by setting
|
|
25
|
+
* FJALL_API_KEY; otherwise a human must complete interactive login.
|
|
26
|
+
*/
|
|
27
|
+
export declare function authRequiredGate(command: string, options?: {
|
|
28
|
+
apiKeyAvailable?: boolean;
|
|
29
|
+
}): ActionRequired;
|
|
30
|
+
/**
|
|
31
|
+
* Emitted when SSO login is required. Always requires human
|
|
32
|
+
* intervention to complete the browser-based flow.
|
|
33
|
+
*/
|
|
34
|
+
export declare function ssoGate(url: string): ActionRequired;
|
|
35
|
+
/**
|
|
36
|
+
* Emitted when no AWS account is connected to the organisation.
|
|
37
|
+
*
|
|
38
|
+
* The agent can resolve this by running `fjall connect`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function awsAccountGate(command: string): ActionRequired;
|
|
41
|
+
export interface DriftConflictDelta {
|
|
42
|
+
readonly property: string;
|
|
43
|
+
readonly theirs: unknown;
|
|
44
|
+
readonly ours: unknown;
|
|
45
|
+
readonly verdict: "clean" | "no-op" | "compatible" | "conflict";
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Emitted when a codemod operation encounters a drift conflict — the
|
|
49
|
+
* user's infrastructure file has manual edits that conflict with the
|
|
50
|
+
* requested operation.
|
|
51
|
+
*
|
|
52
|
+
* The agent can resolve this by re-running with `--force` (overwrite)
|
|
53
|
+
* or by skipping the operation. Merge requires LLM fallback eligibility.
|
|
54
|
+
*/
|
|
55
|
+
export declare function driftConflictGate(params: {
|
|
56
|
+
resourceType: string;
|
|
57
|
+
resourceName: string;
|
|
58
|
+
deltas: readonly DriftConflictDelta[];
|
|
59
|
+
allowMerge: boolean;
|
|
60
|
+
}): ActionRequired;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{formatDeltaValue as o}from"../formatDeltaValue.js";function s(e,t){return{action:"destructive_confirmation_required",message:`Command "${e}" will destroy infrastructure for "${t}". Explicit confirmation required.`,userActionRequired:!1,choices:[`Re-run with --yes to confirm: fjall ${e} --yes`,`Re-run with --skip-confirmation: fjall ${e} --skip-confirmation`],details:{command:e,target:t}}}function u(e,t,r){return{action:"missing_flag",message:`Command "${e}" requires the --${t} flag: ${r}`,userActionRequired:!1,choices:[`Re-run with --${t} <value>: fjall ${e} --${t} <value>`],details:{command:e,flag:t,description:r}}}function c(e,t){return t?.apiKeyAvailable??!1?{action:"auth_required",message:`Command "${e}" requires authentication. An API key is available.`,userActionRequired:!1,choices:["Set FJALL_API_KEY environment variable and retry","Run: fjall login"],details:{command:e,apiKeyAvailable:!0}}:{action:"auth_required",message:`Command "${e}" requires authentication. Interactive login needed.`,userActionRequired:!0,choices:["Run: fjall login --device --agent (browser-based device-code flow)","Run: fjall login (requires interactive session)"],details:{command:e,apiKeyAvailable:!1}}}function l(e){return{action:"sso_login_required",message:"SSO login required. Open the URL in a browser to authenticate.",userActionRequired:!0,choices:["Open the SSO URL in a browser to complete authentication"],details:{url:e}}}function f(e){return{action:"aws_account_required",message:`Command "${e}" requires a connected AWS account.`,userActionRequired:!1,choices:["Run: fjall connect","Connect an AWS account via the webapp"],details:{command:e}}}function d(e){const t=e.deltas.filter(i=>i.verdict==="conflict").map(i=>i.property),r=["Re-run with --force to overwrite manual edits","Skip this operation to keep manual edits"];e.allowMerge&&r.push("Re-run with --merge to attempt AI-assisted merge");const n=e.deltas.map(i=>({property:i.property,theirs:o(i.theirs),ours:o(i.ours),verdict:i.verdict}));return{action:"drift_conflict_resolution_required",message:`Drift conflict on ${e.resourceType} "${e.resourceName}": conflicting properties [${t.join(", ")}].`,userActionRequired:!0,choices:r,details:{resourceType:e.resourceType,resourceName:e.resourceName,conflictCount:t.length,deltas:n}}}export{c as authRequiredGate,f as awsAccountGate,s as destructiveGate,d as driftConflictGate,u as missingFlagGate,l as ssoGate};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent callback factory — builds the full OperationCallbacks interface
|
|
3
|
+
* wired to an AgentOutputWriter. Sibling of `nonInteractiveCallbacks.ts`,
|
|
4
|
+
* not a replacement. Commands opt into this path in Phase 3.
|
|
5
|
+
*
|
|
6
|
+
* Masking is NOT this factory's responsibility (synthesis S1.11).
|
|
7
|
+
* AgentOutputWriter is the single masking boundary. This factory is a
|
|
8
|
+
* thin pass-through that translates callback arguments into writer
|
|
9
|
+
* method calls.
|
|
10
|
+
*/
|
|
11
|
+
import type { ApplicationCallbacks, OrganisationCallbacks } from "../../types/callbacks.js";
|
|
12
|
+
import { AgentOutputWriter } from "./agentOutput.js";
|
|
13
|
+
export interface AgentCallbacksOutput {
|
|
14
|
+
readonly callbacks: ApplicationCallbacks & OrganisationCallbacks;
|
|
15
|
+
readonly writer: AgentOutputWriter;
|
|
16
|
+
}
|
|
17
|
+
export declare function createAgentOutput(options: {
|
|
18
|
+
command: string;
|
|
19
|
+
flags: Readonly<Record<string, string>>;
|
|
20
|
+
verbose?: boolean;
|
|
21
|
+
}): AgentCallbacksOutput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{AgentOutputWriter as g}from"./agentOutput.js";function d(o){return o===void 0?"debug":o}function p(o){const t=new g({command:o.command,flags:o.flags,verbose:o.verbose});return{callbacks:u(t,o),writer:t}}function u(o,t){const c=t.command;return{verbose:t.verbose,onProgress:e=>{e.type==="error"||e.type==="warning"?(o.renderEvent({operation:c,field:e.type,value:{...e.metadata??{},message:e.message}}),o.emitEventSeparator()):o.logDiagnostic("progress",e.message)},onStepStart:(e,n,a,s)=>{o.renderEvent({operation:c,field:"step.start",value:{id:e,name:n,index:a,total:s}}),o.emitEventSeparator()},onStepComplete:(e,n,a,s,i,l)=>{o.renderEvent({operation:c,field:"step.complete",value:{id:e,name:n,status:a,index:s,total:i,...l!==void 0?{error:l}:{}}}),o.emitEventSeparator()},onResourceProgress:e=>{o.renderEvent({operation:c,field:"resource",value:e}),o.emitEventSeparator()},onSSOUrl:e=>{if(e===null){o.logDiagnostic("sso","SSO URL cleared");return}o.renderActionRequired({action:"sso_login_required",message:"Open URL to complete SSO",userActionRequired:!0,details:{url:e}})},onAuthComplete:()=>{o.logDiagnostic("auth","Authentication complete")},onConfirmRequired:async e=>(o.renderActionRequired({action:"confirmation_required",message:e,userActionRequired:!0,choices:["Re-run with --skip-confirmation to proceed","Cancel the operation"]}),!1),onSecretsConfirmRequired:async e=>(o.renderActionRequired({action:"secrets_confirmation_required",message:`Secrets validation requires confirmation (${e.found.length}/${e.totalRequired} found)`,userActionRequired:!0,details:{valid:e.valid,totalRequired:e.totalRequired,foundCount:e.found.length,missingCount:e.missing.length},choices:["Re-run with --skip-confirmation to proceed","Provide missing secrets and retry"]}),!1),onOutput:e=>{o.logDiagnostic("output",e)},onLog:(e,n)=>{o.logDiagnostic("log",e,void 0,d(n))},onCDKBootstrap:()=>{o.logDiagnostic("cdk","CDK bootstrap started")},onCdkOutput:e=>{o.logDiagnostic("cdk",e)},onAccountDetected:e=>{o.logDiagnostic("account","Account detected",{isManagedAccount:e})},onConfigurationDetected:e=>{o.logDiagnostic("config","Configuration detected",{isManagedAccount:e.isManagedAccount,hasDockerfile:e.hasDockerfile,hasDifferences:e.hasDifferences,pattern:e.pattern??"unknown"})},onPreDeploymentProgress:e=>{o.logDiagnostic("pre-deploy",e.message??e.type,{type:e.type,phase:e.phase})},onDockerProgress:(e,n)=>{o.logDiagnostic("docker",e,n!==void 0?{percentage:n}:void 0)},onECSUpdate:e=>{o.logDiagnostic("ecs",e)},onECSProgress:(e,n)=>{o.logDiagnostic("ecs",e,n!==void 0?{percentage:n}:void 0)},onOpenNextBuildStart:()=>{o.logDiagnostic("opennext","Build starting")},onOpenNextProgress:(e,n,a)=>{o.logDiagnostic("opennext",e,{type:n,status:a})},onOpenNextBuildComplete:()=>{o.logDiagnostic("opennext","Build completed")},onOpenNextBuildError:e=>{o.logDiagnostic("opennext",`Build failed: ${e}`,void 0,"error")},onStackCleanupProgress:(e,n)=>{o.logDiagnostic("cleanup",`${e}: ${n}`)},onParallelDeployStart:e=>{o.logDiagnostic("parallel","Parallel deploy starting",{stackCount:e.length})},onParallelStackStart:e=>{o.logDiagnostic("parallel",`Stack starting: ${e}`)},onParallelStackComplete:(e,n,a)=>{o.logDiagnostic("parallel",`Stack complete: ${e}`,{status:n,...a!==void 0?{error:a}:{}})},onParallelStackProgress:(e,n)=>{o.logDiagnostic("parallel","Stack resource progress",{logicalId:n.logicalId})},onParallelDeployComplete:(e,n)=>{o.logDiagnostic("parallel","Parallel deploy complete",{allSuccessful:n})},onOrgSetupProgress:e=>{o.logDiagnostic("org-setup",e.message??e.type,{type:e.type,phase:e.phase})},onChangeDetectionComplete:e=>{o.logDiagnostic("changes","Change detection complete",e)},onCascadeStart:()=>{o.logDiagnostic("cascade","Cascade starting")},onCascadePhaseStart:e=>{o.logDiagnostic("cascade",`Phase starting: ${e}`)},onCascadeAccountStart:(e,n,a)=>{o.logDiagnostic("cascade",`Account starting: ${e}`,{accountId:n,region:a})},onCascadeAccountPhaseChange:(e,n,a)=>{o.logDiagnostic("cascade",`Account phase change: ${e}`,{phase:n,...a!==void 0?{region:a}:{}})},onCascadeAccountResourceProgress:(e,n,a)=>{o.logDiagnostic("cascade",`Account resource progress: ${e}`,{logicalId:n.logicalId,...a!==void 0?{region:a}:{}})},onCascadeAccountComplete:(e,n,a)=>{o.logDiagnostic("cascade",`Account complete: ${e}`,{succeeded:n,...a!==void 0?{error:a}:{}})},onCascadeComplete:e=>{o.logDiagnostic("cascade","Cascade complete",{totalDuration:e.totalDuration})}}}export{p as createAgentOutput};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent file generator for `fjall agent install-skill`.
|
|
3
|
+
*
|
|
4
|
+
* Generates SKILL.md with YAML frontmatter as a global Claude Code skill
|
|
5
|
+
* at ~/.claude/skills/fjall/. Managed sections allow idempotent updates;
|
|
6
|
+
* user content outside managed sections is preserved on re-runs.
|
|
7
|
+
*/
|
|
8
|
+
interface GenerateResult {
|
|
9
|
+
readonly created: readonly string[];
|
|
10
|
+
readonly updated: readonly string[];
|
|
11
|
+
readonly skipped: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate or update SKILL.md in the given output directory.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateAgentFiles(outputDir: string): GenerateResult;
|
|
17
|
+
export {};
|