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.
Files changed (228) hide show
  1. package/bin/.bundled +3 -3
  2. package/bin/.metafile.json +4742 -3402
  3. package/bin/assets/generators/application/generator.js +1 -1
  4. package/bin/assets/generators/compute/generator.js +1 -1
  5. package/bin/assets/generators/compute/service/generator.js +1 -1
  6. package/bin/assets/generators/database/generator.js +1 -1
  7. package/bin/assets/generators/domain/generator.js +2 -2
  8. package/bin/assets/generators/organisation/files/organisation/infrastructure.ts +8 -2
  9. package/bin/assets/generators/shared/files/cdk.json +1 -1
  10. package/bin/assets/generators/shared/files/package.json +8 -7
  11. package/bin/assets/generators/shared/files/tsconfig.json +5 -4
  12. package/bin/assets/generators/utils/integrationTestUtils.d.ts +9 -0
  13. package/bin/assets/generators/utils/integrationTestUtils.js +4 -2
  14. package/bin/assets/generators/utils/planning/generatorHelpers.js +2 -2
  15. package/bin/assets/src/util/__tests__/fjallApiClientTestHelpers.d.ts +9 -0
  16. package/bin/assets/src/util/__tests__/fjallApiClientTestHelpers.js +1 -0
  17. package/bin/assets/src/util/__tests__/outputTestHelpers.d.ts +9 -0
  18. package/bin/assets/src/util/__tests__/outputTestHelpers.js +1 -0
  19. package/bin/assets/src/util/agent/__tests__/toonTestHelpers.d.ts +91 -0
  20. package/bin/assets/src/util/agent/__tests__/toonTestHelpers.js +1 -0
  21. package/bin/assets/src/util/agent/actionRequired.d.ts +60 -0
  22. package/bin/assets/src/util/agent/actionRequired.js +1 -0
  23. package/bin/assets/src/util/agent/agentCallbacks.d.ts +21 -0
  24. package/bin/assets/src/util/agent/agentCallbacks.js +1 -0
  25. package/bin/assets/src/util/agent/agentInit.d.ts +17 -0
  26. package/bin/assets/src/util/agent/agentInit.js +288 -0
  27. package/bin/assets/src/util/agent/agentOutput.d.ts +61 -0
  28. package/bin/assets/src/util/agent/agentOutput.js +8 -0
  29. package/bin/assets/src/util/agent/budget.d.ts +19 -0
  30. package/bin/assets/src/util/agent/budget.js +4 -0
  31. package/bin/assets/src/util/agent/detectAgent.d.ts +51 -0
  32. package/bin/assets/src/util/agent/detectAgent.js +1 -0
  33. package/bin/assets/src/util/agent/errorCodeMap.d.ts +16 -0
  34. package/bin/assets/src/util/agent/errorCodeMap.js +1 -0
  35. package/bin/assets/src/util/agent/errorCodes.d.ts +48 -0
  36. package/bin/assets/src/util/agent/errorCodes.js +1 -0
  37. package/bin/assets/src/util/agent/fieldSelection.d.ts +22 -0
  38. package/bin/assets/src/util/agent/fieldSelection.js +1 -0
  39. package/bin/assets/src/util/agent/getSurface.d.ts +27 -0
  40. package/bin/assets/src/util/agent/getSurface.js +1 -0
  41. package/bin/assets/src/util/agent/index.d.ts +27 -0
  42. package/bin/assets/src/util/agent/index.js +1 -0
  43. package/bin/assets/src/util/agent/mcpProtocolEmit.d.ts +31 -0
  44. package/bin/assets/src/util/agent/mcpProtocolEmit.js +2 -0
  45. package/bin/assets/src/util/agent/schemas/appsSchemas.d.ts +18 -0
  46. package/bin/assets/src/util/agent/schemas/appsSchemas.js +1 -0
  47. package/bin/assets/src/util/agent/schemas/assetSchemas.d.ts +13 -0
  48. package/bin/assets/src/util/agent/schemas/assetSchemas.js +1 -0
  49. package/bin/assets/src/util/agent/schemas/awsSchemas.d.ts +5 -0
  50. package/bin/assets/src/util/agent/schemas/awsSchemas.js +1 -0
  51. package/bin/assets/src/util/agent/schemas/deploySchemas.d.ts +8 -0
  52. package/bin/assets/src/util/agent/schemas/deploySchemas.js +1 -0
  53. package/bin/assets/src/util/agent/schemas/index.d.ts +10 -0
  54. package/bin/assets/src/util/agent/schemas/index.js +1 -0
  55. package/bin/assets/src/util/agent/schemas/infraSchemas.d.ts +45 -0
  56. package/bin/assets/src/util/agent/schemas/infraSchemas.js +1 -0
  57. package/bin/assets/src/util/agent/schemas/secretsSchemas.d.ts +13 -0
  58. package/bin/assets/src/util/agent/schemas/secretsSchemas.js +1 -0
  59. package/bin/assets/src/util/agent/schemas/types.d.ts +98 -0
  60. package/bin/assets/src/util/agent/schemas/types.js +0 -0
  61. package/bin/assets/src/util/agent/schemas/userSchemas.d.ts +21 -0
  62. package/bin/assets/src/util/agent/schemas/userSchemas.js +1 -0
  63. package/bin/assets/src/util/agent/sessionHooks.d.ts +47 -0
  64. package/bin/assets/src/util/agent/sessionHooks.js +6 -0
  65. package/bin/assets/src/util/agent/streaming.d.ts +51 -0
  66. package/bin/assets/src/util/agent/streaming.js +1 -0
  67. package/bin/assets/src/util/agent/suggestionEntries/coreEntries.d.ts +2 -0
  68. package/bin/assets/src/util/agent/suggestionEntries/coreEntries.js +1 -0
  69. package/bin/assets/src/util/agent/suggestionEntries/identityEntries.d.ts +2 -0
  70. package/bin/assets/src/util/agent/suggestionEntries/identityEntries.js +1 -0
  71. package/bin/assets/src/util/agent/suggestionEntries/index.d.ts +3 -0
  72. package/bin/assets/src/util/agent/suggestionEntries/index.js +1 -0
  73. package/bin/assets/src/util/agent/suggestionEntries/infraEntries.d.ts +2 -0
  74. package/bin/assets/src/util/agent/suggestionEntries/infraEntries.js +1 -0
  75. package/bin/assets/src/util/agent/suggestionEntries/observabilityEntries.d.ts +2 -0
  76. package/bin/assets/src/util/agent/suggestionEntries/observabilityEntries.js +1 -0
  77. package/bin/assets/src/util/agent/suggestionEntries/secretsEntries.d.ts +2 -0
  78. package/bin/assets/src/util/agent/suggestionEntries/secretsEntries.js +1 -0
  79. package/bin/assets/src/util/agent/suggestionEntries/types.d.ts +17 -0
  80. package/bin/assets/src/util/agent/suggestionEntries/types.js +1 -0
  81. package/bin/assets/src/util/agent/suggestions.d.ts +30 -0
  82. package/bin/assets/src/util/agent/suggestions.js +1 -0
  83. package/bin/assets/src/util/agent/tokenScopes.d.ts +24 -0
  84. package/bin/assets/src/util/agent/tokenScopes.js +1 -0
  85. package/bin/assets/src/util/agent/toonFormatter.d.ts +55 -0
  86. package/bin/assets/src/util/agent/toonFormatter.js +14 -0
  87. package/bin/assets/src/util/api/Credentials.d.ts +13 -0
  88. package/bin/assets/src/util/api/Credentials.js +1 -0
  89. package/bin/assets/src/util/api/FjallApiClient.d.ts +33 -0
  90. package/bin/assets/src/util/api/FjallApiClient.js +1 -0
  91. package/bin/assets/src/util/api/FjallApiClient.types.d.ts +375 -0
  92. package/bin/assets/src/util/api/FjallApiClient.types.js +1 -0
  93. package/bin/assets/src/util/api/FjallApiClientBase.d.ts +13 -0
  94. package/bin/assets/src/util/api/FjallApiClientBase.js +1 -0
  95. package/bin/assets/src/util/api/FjallApiClientDeviceCode.d.ts +13 -0
  96. package/bin/assets/src/util/api/FjallApiClientDeviceCode.js +1 -0
  97. package/bin/assets/src/util/api/FjallApiClientErrors.d.ts +5 -0
  98. package/bin/assets/src/util/api/FjallApiClientErrors.js +1 -0
  99. package/bin/assets/src/util/api/FjallApiClientResources.d.ts +45 -0
  100. package/bin/assets/src/util/api/FjallApiClientResources.js +1 -0
  101. package/bin/assets/src/util/api/index.d.ts +7 -0
  102. package/bin/assets/src/util/api/index.js +1 -0
  103. package/bin/assets/src/util/api/resolveApiKey.d.ts +1 -0
  104. package/bin/assets/src/util/api/resolveApiKey.js +1 -0
  105. package/bin/assets/src/util/api/scaffoldNotification.d.ts +2 -0
  106. package/bin/assets/src/util/api/scaffoldNotification.js +1 -0
  107. package/bin/assets/src/util/awsCleanup.d.ts +9 -0
  108. package/bin/assets/src/util/awsCleanup.js +1 -0
  109. package/bin/assets/src/util/awsTags.d.ts +19 -0
  110. package/bin/assets/src/util/awsTags.js +1 -0
  111. package/bin/assets/src/util/buildxEventAdapter.d.ts +20 -0
  112. package/bin/assets/src/util/buildxEventAdapter.js +1 -0
  113. package/bin/assets/src/util/caseConversion.d.ts +1 -0
  114. package/bin/assets/src/util/caseConversion.js +1 -0
  115. package/bin/assets/src/util/codemod/emitCliTelemetry.d.ts +32 -0
  116. package/bin/assets/src/util/codemod/emitCliTelemetry.js +1 -0
  117. package/bin/assets/src/util/codemod/exitCodes.d.ts +11 -0
  118. package/bin/assets/src/util/codemod/exitCodes.js +1 -0
  119. package/bin/assets/src/util/codemod/index.d.ts +3 -0
  120. package/bin/assets/src/util/codemod/index.js +1 -0
  121. package/bin/assets/src/util/codemod/renderCodemod.d.ts +5 -0
  122. package/bin/assets/src/util/codemod/renderCodemod.js +1 -0
  123. package/bin/assets/src/util/codemod/stepLabels.d.ts +11 -0
  124. package/bin/assets/src/util/codemod/stepLabels.js +1 -0
  125. package/bin/assets/src/util/colourUtils.d.ts +21 -0
  126. package/bin/assets/src/util/colourUtils.js +1 -0
  127. package/bin/assets/src/util/commandErrorHandler.d.ts +16 -0
  128. package/bin/assets/src/util/commandErrorHandler.js +1 -0
  129. package/bin/assets/src/util/commandResult.d.ts +63 -0
  130. package/bin/assets/src/util/commandResult.js +1 -0
  131. package/bin/assets/src/util/concurrency.d.ts +35 -0
  132. package/bin/assets/src/util/concurrency.js +1 -0
  133. package/bin/assets/src/util/deploymentEvents.d.ts +155 -0
  134. package/bin/assets/src/util/deploymentEvents.js +1 -0
  135. package/bin/assets/src/util/errorDisplay.d.ts +4 -0
  136. package/bin/assets/src/util/errorDisplay.js +2 -0
  137. package/bin/assets/src/util/errorUtils.d.ts +1 -0
  138. package/bin/assets/src/util/errorUtils.js +1 -0
  139. package/bin/assets/src/util/executionMode.d.ts +18 -0
  140. package/bin/assets/src/util/executionMode.js +1 -0
  141. package/bin/assets/src/util/formatDeltaValue.d.ts +1 -0
  142. package/bin/assets/src/util/formatDeltaValue.js +1 -0
  143. package/bin/assets/src/util/formatDuration.d.ts +1 -0
  144. package/bin/assets/src/util/formatDuration.js +1 -0
  145. package/bin/assets/src/util/formatRelativeTime.d.ts +1 -0
  146. package/bin/assets/src/util/formatRelativeTime.js +1 -0
  147. package/bin/assets/src/util/fuzzyMatch.d.ts +38 -0
  148. package/bin/assets/src/util/fuzzyMatch.js +1 -0
  149. package/bin/assets/src/util/gitDetection.d.ts +8 -0
  150. package/bin/assets/src/util/gitDetection.js +1 -0
  151. package/bin/assets/src/util/index.d.ts +50 -0
  152. package/bin/assets/src/util/index.js +1 -0
  153. package/bin/assets/src/util/log.d.ts +29 -0
  154. package/bin/assets/src/util/log.js +4 -0
  155. package/bin/assets/src/util/logger/CorrelatedLogger.d.ts +15 -0
  156. package/bin/assets/src/util/logger/CorrelatedLogger.js +1 -0
  157. package/bin/assets/src/util/logger/DeploymentLogger.d.ts +33 -0
  158. package/bin/assets/src/util/logger/DeploymentLogger.js +2 -0
  159. package/bin/assets/src/util/logger/FileRotator.d.ts +17 -0
  160. package/bin/assets/src/util/logger/FileRotator.js +1 -0
  161. package/bin/assets/src/util/logger/LogFileWriter.d.ts +54 -0
  162. package/bin/assets/src/util/logger/LogFileWriter.js +4 -0
  163. package/bin/assets/src/util/logger/Logger.d.ts +43 -0
  164. package/bin/assets/src/util/logger/Logger.js +1 -0
  165. package/bin/assets/src/util/logger/index.d.ts +15 -0
  166. package/bin/assets/src/util/logger/index.js +2 -0
  167. package/bin/assets/src/util/logger/logDir.d.ts +5 -0
  168. package/bin/assets/src/util/logger/logDir.js +1 -0
  169. package/bin/assets/src/util/logger/types.d.ts +48 -0
  170. package/bin/assets/src/util/logger/types.js +1 -0
  171. package/bin/assets/src/util/nonInteractive/index.d.ts +3 -0
  172. package/bin/assets/src/util/nonInteractive/index.js +1 -0
  173. package/bin/assets/src/util/nonInteractive/nonInteractiveCallbacks.d.ts +18 -0
  174. package/bin/assets/src/util/nonInteractive/nonInteractiveCallbacks.js +1 -0
  175. package/bin/assets/src/util/nonInteractive/nonInteractiveCascadeOutput.d.ts +51 -0
  176. package/bin/assets/src/util/nonInteractive/nonInteractiveCascadeOutput.js +1 -0
  177. package/bin/assets/src/util/nonInteractive/nonInteractiveLabels.d.ts +23 -0
  178. package/bin/assets/src/util/nonInteractive/nonInteractiveLabels.js +1 -0
  179. package/bin/assets/src/util/nonInteractive/nonInteractiveOutput.d.ts +128 -0
  180. package/bin/assets/src/util/nonInteractive/nonInteractiveOutput.js +4 -0
  181. package/bin/assets/src/util/nonInteractive/nonInteractiveSummaryOutput.d.ts +29 -0
  182. package/bin/assets/src/util/nonInteractive/nonInteractiveSummaryOutput.js +3 -0
  183. package/bin/assets/src/util/organisationStructure.d.ts +9 -0
  184. package/bin/assets/src/util/organisationStructure.js +1 -0
  185. package/bin/assets/src/util/parseTakeOption.d.ts +1 -0
  186. package/bin/assets/src/util/parseTakeOption.js +1 -0
  187. package/bin/assets/src/util/passwordValidation.d.ts +22 -0
  188. package/bin/assets/src/util/passwordValidation.js +1 -0
  189. package/bin/assets/src/util/pathHelpers.d.ts +19 -0
  190. package/bin/assets/src/util/pathHelpers.js +1 -0
  191. package/bin/assets/src/util/patternDetection.d.ts +7 -0
  192. package/bin/assets/src/util/patternDetection.js +1 -0
  193. package/bin/assets/src/util/promptYesNo.d.ts +5 -0
  194. package/bin/assets/src/util/promptYesNo.js +1 -0
  195. package/bin/assets/src/util/readStdin.d.ts +9 -0
  196. package/bin/assets/src/util/readStdin.js +1 -0
  197. package/bin/assets/src/util/secretsUtils.d.ts +155 -0
  198. package/bin/assets/src/util/secretsUtils.js +3 -0
  199. package/bin/assets/src/util/signalCleanup.d.ts +13 -0
  200. package/bin/assets/src/util/signalCleanup.js +4 -0
  201. package/bin/assets/src/util/stripAnsi.d.ts +2 -0
  202. package/bin/assets/src/util/stripAnsi.js +1 -0
  203. package/bin/assets/src/util/synchronizedOutput.d.ts +26 -0
  204. package/bin/assets/src/util/synchronizedOutput.js +1 -0
  205. package/bin/assets/src/util/targetDetection.d.ts +27 -0
  206. package/bin/assets/src/util/targetDetection.js +1 -0
  207. package/bin/assets/src/util/targetHelpers.d.ts +20 -0
  208. package/bin/assets/src/util/targetHelpers.js +1 -0
  209. package/bin/assets/src/util/terminalCapabilities.d.ts +21 -0
  210. package/bin/assets/src/util/terminalCapabilities.js +1 -0
  211. package/bin/assets/src/util/terminalEscapes.d.ts +29 -0
  212. package/bin/assets/src/util/terminalEscapes.js +1 -0
  213. package/bin/assets/src/util/terminalFocus.d.ts +33 -0
  214. package/bin/assets/src/util/terminalFocus.js +1 -0
  215. package/bin/assets/src/util/theme.d.ts +80 -0
  216. package/bin/assets/src/util/theme.js +1 -0
  217. package/bin/assets/src/util/truncateMiddle.d.ts +9 -0
  218. package/bin/assets/src/util/truncateMiddle.js +1 -0
  219. package/bin/assets/src/util/typeGuards.d.ts +5 -0
  220. package/bin/assets/src/util/typeGuards.js +1 -0
  221. package/bin/assets/src/util/uiRouter.d.ts +13 -0
  222. package/bin/assets/src/util/uiRouter.js +1 -0
  223. package/bin/assets/src/util/urlHelpers.d.ts +4 -0
  224. package/bin/assets/src/util/urlHelpers.js +1 -0
  225. package/bin/assets/src/util/versionDisplay.d.ts +5 -0
  226. package/bin/assets/src/util/versionDisplay.js +1 -0
  227. package/bin/fjall.bundle.js +736 -564
  228. 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)}`):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,dockerfilePath:a.dockerfilePath,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
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,dockerfilePath:e.dockerfilePath};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
+ 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 g}from"@fjall/generator";import{withInfrastructurePlan as p,pickDefined as h}from"../../utils/planning/generatorHelpers.js";async function l(m,f){await p(m,g,f,"service",({validated:n,plan:o})=>{const t=o.compute.find(e=>e.name===n.clusterName&&e.type==="ecs");if(!t)throw new Error(`ECS cluster '${n.clusterName}' not found. Available clusters: ${o.compute.filter(e=>e.type==="ecs").map(e=>e.name).join(", ")||"none"}`);const c=t.services||[];if(c.some(e=>e.name===n.serviceName))throw new Error(`Service '${n.serviceName}' already exists in cluster '${n.clusterName}'`);const i={name:n.serviceName,capacityProvider:n.capacityProvider,...h(n,"dockerfilePath","dockerTarget","cpu","memoryLimitMiB","desiredCount","ec2Config","routing")};if(n.containerPort&&(i.containers=[{port:n.containerPort}]),n.connectionConfig?.connectToDatabase?.length){i.needsDatabaseConnection=!0;const e=t.connectedDatabase||[],r=n.connectionConfig.connectToDatabase.filter(a=>!e.includes(a));r.length>0&&(t.connectedDatabase=[...e,...r],t.needsConnection=!0)}t.services=[...c,i];const s=t.services.filter(e=>e.containers?.some(r=>r.port));if(s.length>1){const e=s.filter(r=>!(Array.isArray(r.routing)?r.routing:r.routing?[r.routing]:[]).some(u=>u.path||u.host));if(e.length>0)throw new Error(`Multiple services have container ports \u2014 all must have routing configuration. Services missing routing: ${e.map(r=>r.name).join(", ")}`)}return o})}var y=l;export{y as default,l as serviceGenerator};
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 u,databaseExists as m}from"../utils/resources/resourceDetection.js";import{pickDefined as s,withInfrastructurePlan as b}from"../utils/planning/generatorHelpers.js";import{DatabaseGeneratorSchema as p}from"@fjall/generator";import{handleResourceConnections as d}from"../utils/resources/connectionHelpers.js";function f(t,e){const r={name:t,type:e.databaseType,databaseName:e.databaseName,...s(e,"databaseInsights","port","proxy","credentials","encryption","deletionProtection")};switch(e.databaseType){case"Instance":return{...r,...s(e,"instanceType","multiAz","readReplica","publiclyAccessible","backupRetention","snapshotIdentifier","snapshotUsername")};case"Aurora":return{...r,...s(e,"writer","readers","backupRetention","preferredMaintenanceWindow","snapshotIdentifier","snapshotUsername")};case"GlobalAurora":return{...r,primaryRegion:e.primaryRegion,...e.secondaryRegions&&e.secondaryRegions.length>0&&{secondaryRegions:e.secondaryRegions},...s(e,"globalClusterIdentifier","enableGlobalWriteForwarding","writer","readers","backupRetention","preferredMaintenanceWindow","snapshotIdentifier","snapshotUsername")};default:return e}}async function l(t,e){await b(t,p,e,"database",async({tree:r,validated:a,plan:o})=>{const n=a.resourceName||`${a.appName}Database`;if(u(r,a.appName,n),m(r,a.appName,a.databaseName))throw new Error(`Database name '${a.databaseName}' already exists in ${a.appName}. Please choose a different database name.`);const i=f(n,a),c={...o,database:[...o.database,i]};return await d(c,a,n,"database",{singularPrompt:"Found an existing compute resource. Configure database access for it?",pluralPrompt:"Found {count} compute resources. Configure database access for them?"}),c})}var w=l;export{l as databaseGenerator,w as default};
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 g=import.meta.dirname,I=e.object({domainName:e.string().regex(f.DOMAIN,l.DOMAIN),hostedZoneId:e.string().optional(),infrastructureTs:e.string().optional()}).strict();async function h(t,s){const r=I.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(g,"files"),a,n),o.infrastructureTs!==void 0&&t.write(i(a,"infrastructure.ts"),o.infrastructureTs),p(t,a,{...n,packageName:`domain-${o.domainName}`})}var Z=h;export{I as DomainGeneratorSchema,Z as default,h as domainGenerator};
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: organisation.node.tryGetContext("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: organisation.node.tryGetContext("rootId"),
48
+ rootId,
43
49
  allowedRegions: ALLOWED_REGIONS
44
50
  });
45
51
  <% } -%>
@@ -1,5 +1,5 @@
1
1
  {
2
- "app": "npx ts-node --prefer-ts-exts --transpile-only infrastructure.ts",
2
+ "app": "npx tsx infrastructure.ts",
3
3
  "assetMetadata": false,
4
4
  "pathMetadata": false,
5
5
  "versionReporting": false,
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "<%= packageName %>",
3
- "version": "0.96.0",
3
+ "version": "0.99.1",
4
+ "type": "module",
4
5
  "scripts": {},
5
6
  "devDependencies": {
6
- "@types/node": "20.4.9",
7
- "ts-node": "^10.9.1",
8
- "typescript": "~5.1.6"
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.96.0",
12
- "aws-cdk-lib": "^2.239.0",
13
- "constructs": "^10.0.0"
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": "ES2020",
4
- "module": "commonjs",
5
- "lib": ["es2020", "dom"],
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
- "typeRoots": ["./node_modules/@types"]
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 S}from"../../src/util/errorUtils.js";const a=o.resolve(import.meta.dirname,"../.."),c=o.join(a,"fjall"),d=o.resolve(a,"../components/infrastructure"),y=o.join(a,"test-fixtures"),l=o.join(y,"node_modules"),f="123456789012",s="ap-southeast-2";function O(n,e){const t=o.join(c,n);return x(t),_(t,e?.context),m(t)?b(t):{success:!1,output:"Failed to set up node_modules"}}function m(n){const e=o.join(n,"node_modules");if(r.existsSync(l))try{return r.existsSync(e)&&(r.lstatSync(e).isSymbolicLink()?r.unlinkSync(e):r.rmSync(e,{recursive:!0,force:!0})),r.symlinkSync(l,e,"junction"),!0}catch{}if(!r.existsSync(e))try{p("npm",["install"],{cwd:n,encoding:"utf-8",timeout:12e4})}catch{return!1}return!0}function b(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:f,CDK_DEFAULT_REGION:s}})}}catch(e){const t=S(e),i="stdout"in t&&typeof t.stdout=="string"?t.stdout:void 0,u="stderr"in t&&typeof t.stderr=="string"?t.stderr:void 0;return{success:!1,output:i||u||t.message||"Unknown error"}}}function x(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/ts-node infrastructure.ts",context:{"aws:cdk:bundling-stacks":[],[`availability-zones:account=${f}:region=${s}`]:[`${s}a`,`${s}b`,`${s}c`],[`vpc-provider:account=${f}: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 E(n){const e=o.join(c,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 C(n){return n.replace(/[-_](.)/g,(e,t)=>t.toUpperCase()).replace(/^./,e=>e.toUpperCase())}function T(n,e){const t=o.join(c,n,"cdk.out",`${C(n)}${e}.template.json`);if(!r.existsSync(t))throw new Error(`Template not found: ${t}`);return JSON.parse(r.readFileSync(t,"utf-8"))}function h(n){const e=o.join(c,n,"infrastructure.ts");if(!r.existsSync(e))throw new Error(`Infrastructure file not found: ${e}`);return r.readFileSync(e,"utf-8")}function I(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(u=>u.Field===e).flatMap(u=>u[t]?.Values??u.Values??[])).filter(i=>i!==void 0)}function R(){r.existsSync(o.join(d,"dist"))||(process.stdout.write(`Building components-infrastructure...
2
- `),p("npm",["run","build"],{cwd:d,stdio:"inherit"}))}export{a as CLI_ROOT,d as COMPONENTS_DIR,f as MOCK_ACCOUNT,s as MOCK_REGION,l as SHARED_NODE_MODULES,c as TEST_APPS_DIR,y as TEST_FIXTURES_DIR,E as cleanupTestApp,R as ensureComponentsBuilt,N as extractConditionValues,I as findResourcesByType,D as findSecurityGroupByDescription,h as getInfrastructureContent,T as readCfnTemplate,O as runCdkSynth};
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 p from"fs";import*as w from"path";import{logger as g}from"../../../src/util/logger/index.js";import{normaliseError as d}from"../../../src/util/errorUtils.js";import{success as u,failure as a}from"../../../src/types/Result.js";import{parseInfrastructure as h,convertToResourcePlan as k,getZodErrorMessage as x,generateInfrastructureFromPlan as E}from"@fjall/generator";import{getInfrastructurePath as I}from"../../../src/util/pathHelpers.js";function P(t,o,r){const e=t.root?w.join(t.root,o):o;try{return p.existsSync(e)&&p.writeFileSync(`${e}.bak`,r),u(void 0)}catch(s){const n=d(s);return g.warn("Generator",`Failed to create backup of ${o}`,{error:n.message}),a(n)}}function S(t,...o){const r={};for(const e of o)t[e]!==void 0&&(r[e]=t[e]);return r}function $(t,o){try{const r=h(t,{extractCustomCode:!0}),e=k(r,o,{skipValidation:!0});return r.customCodeBlocks?.length&&(e.customCodeBlocks=r.customCodeBlocks),u({parsed:r,plan:e})}catch(r){return a(d(r))}}function y(t,o){const r=$(t,o);if(!r.success)throw new Error(`Failed to parse infrastructure: ${r.error.message}`);return r.data}function B(t,o,r){const e=t.safeParse(o);if(!e.success)throw new Error(`Invalid ${r} generator options:
2
- ${x(e.error)}`);return e.data}function b(t,o){const r=I(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 T(t,o,r,e,s){const n=B(o,r,e),{path:i,content:c}=b(t,n.appName),{plan:l}=y(c,n.appName),m=await s({tree:t,validated:n,plan:l,infrastructurePath:i,content:c}),f=C(t,i,c,m);if(!f.success)throw new Error(f.error.message)}function C(t,o,r,e){const s=E(e);if(!s.success)return a(s.error);const n=P(t,o,r);return n.success?(t.write(o,s.data),u(void 0)):a(new Error(`Failed to create backup: ${n.error.message}`))}export{P as createInfrastructureBackup,C as generateAndWriteInfrastructure,$ as parseAndBuildPlan,y as parseAndBuildPlanOrThrow,S as pickDefined,b as readInfrastructureOrThrow,B as validateGeneratorOptions,T as withInfrastructurePlan};
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 {};