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
@@ -0,0 +1,288 @@
1
+ import{existsSync as h,mkdirSync as m,readFileSync as g}from"node:fs";import{join as y,relative as w}from"node:path";import{maskSensitiveOutput as j}from"@fjall/util";import{atomicWrite as f}from"@fjall/util/fsHelpers";import{DEFAULT_BASE_URL as k}from"../api/FjallApiClient.types.js";import{logger as d}from"../logger/index.js";const u=e=>{d.debug("AgentInit","tmp cleanup failed",{error:e instanceof Error?e.message:String(e)})},l="<!-- fjall:managed:start -->",p="<!-- fjall:managed:end -->",v=`---
2
+ name: fjall
3
+ description: Deploy applications to AWS via Fjall CLI. Use when the user asks to deploy, connect AWS, manage secrets, or provision infrastructure.
4
+ ---
5
+
6
+ `;function E(e){const c=[],o=[],t=[],n=y(e,"SKILL.md"),a=w(process.cwd(),n)||"SKILL.md",i=S();try{if(m(e,{recursive:!0}),h(n)){const r=g(n,"utf-8");if(r.includes(l)){const s=A(r,i);s.kind==="corrupt"?(d.warn("AgentInit","MANAGED markers are corrupt \u2014 leaving file untouched",{relPath:a}),t.push(`${a} (corrupt managed markers \u2014 repair manually)`)):s.kind==="unchanged"?t.push(`${a} (no changes)`):(f(n,s.content,{onCleanupError:u}),o.push(a))}else t.push(`${a} (exists, no managed section \u2014 add manually)`)}else f(n,v+b(i),{onCleanupError:u}),c.push(a)}catch(r){const s=j(r instanceof Error?r.message:String(r));d.debug("AgentInit","Skill file write failed",{relPath:a,error:s}),t.push(`${a} (error: ${s})`)}return{created:c,updated:o,skipped:t}}function b(e){return`${l}
7
+ ${e}
8
+ ${p}
9
+ `}function A(e,c){const o=e.indexOf(l),t=e.indexOf(p);if(o===-1||t===-1||t<o)return{kind:"corrupt"};if(e.lastIndexOf(l)!==o||e.lastIndexOf(p)!==t)return{kind:"corrupt"};const n=e.slice(0,o),a=e.slice(t+p.length),i=`${n}${l}
10
+ ${c}
11
+ ${p}${a}`;return i===e?{kind:"unchanged"}:{kind:"replaced",content:i}}function S(){return`# Fjall \u2014 Skill for AI Agents
12
+
13
+ You have the Fjall CLI available. Fjall deploys applications to AWS via
14
+ infrastructure-as-code. Always pass \`--agent\` for structured TOON output.
15
+
16
+ ## Before You Start
17
+ - Confirm \`FJALL_API_KEY\` is set. If not, tell the user to sign up at
18
+ ${k} and run \`fjall login --api-key <key>\`.
19
+ Alternatively, run \`fjall login --device --agent\` to initiate a
20
+ browser-based device-code flow.
21
+ - All Fjall terminology is British English: "organisation", "authorise", "colour".
22
+ - Each \`--agent\` output is **authoritative** \u2014 its \`status\`, \`error\`, and
23
+ \`help[]\` fields tell you what happened and what to do next. You do not
24
+ need to poll a separate state command between steps.
25
+ - **Always run \`fjall\` from the project root.** Scaffolding commands
26
+ (e.g. \`create account\`, \`create org\`) create subdirectories like
27
+ \`fjall/account/\` \u2014 do not \`cd\` into them. All subsequent commands
28
+ (\`connect\`, \`deploy\`, \`target list\`, etc.) expect the project root.
29
+ - Do **not** hand-roll AWS CLI, CDK, or Terraform \u2014 Fjall owns the
30
+ infrastructure graph and will diverge from manual edits.
31
+
32
+ ## What Fjall Owns
33
+
34
+ Fjall manages two layers per application:
35
+ 1. **Infrastructure** \u2014 CDK-generated AWS resources (ECS, RDS, ALB, S3, Lambda).
36
+ 2. **Code** \u2014 container images and Lambda bundles from the source tree.
37
+
38
+ Both deploy via \`fjall deploy\`. Use \`--infra-only\` or \`--deploy-only\` to split.
39
+
40
+ \`fjall deploy <org>\` cascades: organisation \u2192 platform \u2192 accounts \u2192 applications.
41
+ Use \`--no-cascade\` to deploy a single level.
42
+
43
+ ## Recipe: Onboard a New User
44
+
45
+ **First, ask the user which path they want:**
46
+ - **Single account** \u2014 one AWS account, no shared governance.
47
+ - **Organisation** \u2014 multi-account with governance and shared infrastructure.
48
+
49
+ ### Path A: Single Account
50
+ 1. \`fjall login --device --agent\` (skip if authenticated)
51
+ 2. Ask which region. Default to **us-east-2** if no preference.
52
+ Common regions: us-east-2, us-west-2, eu-west-1, ap-southeast-2.
53
+ 3. \`fjall create account --primary-region <region> --agent\`
54
+ -> Scaffolds \`fjall/account/\` infrastructure-as-code.
55
+ -> Confirm the user is in the correct project directory first.
56
+ 4. \`fjall connect --environment production --region <region> --agent\`
57
+ -> Opens the CloudFormation URL in the user's browser and polls for
58
+ completion. **This command blocks** until the stack finishes (~3 min).
59
+ If the browser doesn't open, the URL is printed \u2014 show it to the user.
60
+ -> Run with a **10-minute timeout** (the stack takes ~3 minutes).
61
+ -> On success, the connection is fully registered and targets are available.
62
+ 5. \`fjall deploy account --agent\`
63
+ -> Deploys the scaffolded account infrastructure to AWS.
64
+ 6. Now the base infrastructure is live. Ask if they want to create an app
65
+ (see **Recipe: Create and Deploy an Application** below).
66
+
67
+ ### Path B: Organisation
68
+ 1. \`fjall login --device --agent\` (skip if authenticated)
69
+ 2. Ask for: organisation name, admin email, and primary region.
70
+ 3. \`fjall create org --name "<name>" --email "<email>" --primary-region <region> --agent\`
71
+ -> Scaffolds \`fjall/organisation/\`, \`fjall/platform/\`, \`fjall/account/\`.
72
+ -> Confirm the user is in the correct project directory first.
73
+ 4. \`fjall connect --environment production --region <region> --agent\`
74
+ -> Same blocking CloudFormation flow as Path A (see step 4 above).
75
+ 5. \`fjall deploy organisation --agent\`
76
+ -> Cascades: organisation \u2192 platform \u2192 accounts. This is a single
77
+ command \u2014 do NOT deploy each level separately.
78
+ 6. Now the base infrastructure is live. Ask if they want to create an app
79
+ (see **Recipe: Create and Deploy an Application** below).
80
+
81
+ ### Recipe: Create and Deploy an Application
82
+
83
+ Walk the decision tree below. **Do not skip steps** \u2014 each resolves
84
+ information the next step needs. Skipping detect or dry-run is the #1
85
+ cause of scaffold failures.
86
+
87
+ **Common mistakes to avoid:**
88
+
89
+ - \`--pattern\` is the **framework** (\`nextjs\`, \`payload\`), NOT the compute
90
+ model. There is no \`--pattern ecs\`. ECS vs Lambda is determined by the
91
+ pattern + tier combination.
92
+ - \`--tier\` sets the **infrastructure tier** (\`tinkerer\`,
93
+ \`lightweight\`, \`standard\`, \`resilient\`, \`enterprise\`). Do NOT pass
94
+ these values via \`--type\` \u2014 that flag is for legacy template mode only.
95
+ - \`--into <path>\` sets the repo root the scaffold writes into. The output
96
+ lands at \`<into>/fjall/<app-name>/\`. **You must also \`cd\` to the
97
+ \`--into\` path** (or its parent) before running the command \u2014 the CLI
98
+ resolves the config root from cwd, and a cwd mismatch causes files to
99
+ land in the wrong project.
100
+ - \`--dockerfile <path>\` is resolved relative to the \`--into\` directory
101
+ (or cwd if no \`--into\`), NOT relative to the agent's working directory.
102
+ Use a path relative to the target repo root, e.g. \`apps/website/Dockerfile\`.
103
+
104
+ **Step 1 \u2014 Detect the repo (MANDATORY for existing repos).** Run:
105
+ \`fjall apps detect <path> --output json --agent\`
106
+
107
+ This returns the framework, monorepo tool, Dockerfile presence, inferred
108
+ port, and \`suggestedConfigPath\` for each app. Use these values to seed
109
+ \`--pattern\` and \`--name\` in the create command. Do NOT guess the pattern
110
+ from the user's description \u2014 always use what detect reports.
111
+
112
+ **Step 2 \u2014 Pick the tier.** Tier governs blast radius and cost.
113
+ - \`tinkerer\` \u2014 smallest viable; single-AZ, no LB.
114
+ - \`lightweight\` \u2014 LB-only validation env. **Default for "is this app
115
+ deployable?" smoke tests.**
116
+ - \`standard\` \u2014 typical production profile.
117
+ - \`resilient\` / \`enterprise\` \u2014 multi-AZ, multi-region.
118
+
119
+ Pass via \`--tier <tier>\`. Use \`--pattern-domain <domain>\` for a
120
+ custom domain or omit for none.
121
+
122
+ **Step 3 \u2014 Pick the target account.** If more than one provider account
123
+ is connected, the scaffold needs to know which one will deploy this app.
124
+ - \`fjall accounts list --output json --agent\` \u2014 see candidates.
125
+ - Pass \`--target <account-name>\` to \`apps create\`.
126
+ - If only one candidate exists, the CLI auto-resolves it.
127
+
128
+ **Step 4 \u2014 Optional: pick a network preset.**
129
+ \`--network <lightweight|standard|resilient|enterprise|none>\`. Most apps
130
+ inherit from the tier; only set this when an app needs different network
131
+ topology from its tier default.
132
+
133
+ **Step 5 \u2014 Preview the scaffold (MANDATORY).** Before writing anything,
134
+ run with \`--dry-run\` to get a TOON preview of the planned files, npm
135
+ packages, and registry actions. Nothing is written, no API call is made,
136
+ no dependencies are installed. **Never skip this step.**
137
+
138
+ When using \`--into\`, \`cd\` to the target repo root first:
139
+
140
+ \`\`\`bash
141
+ cd <repo-path>
142
+ fjall apps create \\
143
+ --name <app> \\
144
+ --pattern <nextjs|payload|...> \\
145
+ --tier <tier> \\
146
+ [--pattern-domain <domain>] \\
147
+ [--network <preset>] \\
148
+ [--database] \\
149
+ [--dockerfile <relative-path-from-repo-root>] \\
150
+ [--container-port <port>] \\
151
+ [--container <monorepo-subdir>] \\
152
+ --into <repo-path> \\
153
+ [--target <account>] \\
154
+ --dry-run --agent
155
+ \`\`\`
156
+
157
+ Scaffold paths follow the \`fjall/\` marker convention \u2014 \`fjall/<name>/infrastructure.ts\`
158
+ at the repo root by default, or \`<container>/fjall/<name>/infrastructure.ts\` when the
159
+ optional \`--container\` flag is supplied (useful in monorepos where infrastructure
160
+ lives under a workspace directory like \`services/\` or \`apps/\`).
161
+
162
+ The TOON output includes \`fileCount\`, a \`files[]\` list with paths and
163
+ sizes, \`npmPackages[]\`, and \`registryActions[]\`. **Verify that \`path\`
164
+ in the output points inside the target repo**, not somewhere else. If
165
+ it doesn't, the cwd is wrong. Review files against the user's intent.
166
+ If anything looks wrong (file would clobber an existing path, wrong
167
+ tier, missing service), refine the flags and re-run \`--dry-run\` until
168
+ the preview matches.
169
+
170
+ If the output contains \`patternUnsupportedForDryRun: true\`, the
171
+ scaffold relies on a registry clone whose file list is only available
172
+ after apply \u2014 confirm the high-level shape (\`mode\`, \`pattern\`,
173
+ \`registryActions\`) and proceed.
174
+
175
+ **Step 6 \u2014 Apply.** Drop \`--dry-run\` and run again with the same flags
176
+ (same cwd) to write the scaffold, register the application, and install
177
+ dependencies.
178
+
179
+ For a fresh-start single-template app the older form still works:
180
+ \`fjall apps create --name <app> --template <template> --agent\`.
181
+
182
+ **Step 7 \u2014 Deploy:** \`fjall deploy <app> --agent\`.
183
+
184
+ **Worked example \u2014 "point at ansa, scaffold a lightweight LB-only env":**
185
+ 1. \`fjall apps detect /Users/paul/Code/fjall/ansa --output json --agent\`
186
+ \u2192 reports \`monorepo: npm-workspaces\`, \`apps/website\` is
187
+ \`nextjs+payload\` with Dockerfile at \`apps/website/Dockerfile\`,
188
+ port 3000.
189
+ 2. \`fjall accounts list --output json --agent\` \u2192 one candidate,
190
+ auto-resolved.
191
+ 3. \`cd /Users/paul/Code/fjall/ansa\` \u2190 **must cd to the --into target**
192
+ 4. \`fjall apps create --name ansa-web --pattern payload --tier lightweight --database --dockerfile apps/website/Dockerfile --container-port 3000 --into /Users/paul/Code/fjall/ansa --dry-run --agent\`
193
+ \u2192 review TOON: verify \`path\` is inside ansa repo, check \`fileCount\`,
194
+ \`registryActions[]\`. Confirm with the user.
195
+ 5. Same command without \`--dry-run\` \u2192 scaffold writes to
196
+ \`ansa/fjall/ansa-web/\` (or pass \`--container apps\` to land
197
+ under \`ansa/apps/fjall/ansa-web/\` to match the existing
198
+ monorepo layout).
199
+ 6. \`fjall deploy ansa-web --agent\`
200
+
201
+ After each step, summarise the TOON \`status\` and any \`help[]\` hints for the
202
+ user. On a non-zero exit, quote the \`error\` field and offer the suggested fix.
203
+
204
+ If you lose context mid-recipe, run:
205
+ - \`fjall list --agent\` (what resources exist?)
206
+ - \`fjall target list --agent\` (what AWS accounts are connected?)
207
+
208
+ ## Recipe: Deploy Changes
209
+ 1. \`fjall status <app> --agent\`
210
+ 2. \`fjall deploy <app> --agent\`
211
+
212
+ ## Recipe: Manage Secrets
213
+ 1. \`fjall secrets list --app <app> --agent\`
214
+ 2. \`fjall secrets set KEY=value --app <app> --agent\`
215
+ 3. \`fjall deploy <app> --agent\` (secrets injected on next deploy)
216
+
217
+ ## Recipe: Add a Database
218
+ 1. \`fjall add database --app <app> --agent\`
219
+ 2. \`fjall deploy <app> --agent\`
220
+
221
+ ## Recipe: Recover from a Failed Deploy
222
+ 1. \`fjall status <app> --agent\` (which step failed?)
223
+ 2. \`fjall deploy logs --deployment-id <id> --agent\` (recent events \u2014 id from \`fjall status\`)
224
+ 3. Ask the user: retry, rollback (\`fjall destroy\` + redeploy), or investigate.
225
+
226
+ ## Global Flags
227
+ - \`--agent\` \u2014 TOON output (always use for parsing).
228
+ - \`--budget compact|minimal|<tokens>\` \u2014 cap output size.
229
+ - \`--fields <csv>\` \u2014 select specific fields.
230
+ - \`--verbose\` \u2014 diagnostic output (masks credentials).
231
+
232
+ ## Flags Appendix (for composition beyond recipes)
233
+ When the user asks for something outside these recipes, compose from these
234
+ primitives. Always pass \`--agent\`.
235
+
236
+ | Command | Key flags |
237
+ |---------|-----------|
238
+ | \`fjall create org\` | \`--name\`, \`--email\`, \`--primary-region\`, \`--secondary-regions\`, \`--disaster-recovery-region\`, \`--security <foundation\\|compliance\\|hardened>\` |
239
+ | \`fjall create account\` | \`--primary-region\` |
240
+ | \`fjall connect\` | \`--region\`, \`--environment <production\\|staging\\|development\\|platform\\|compliance>\`, \`--name\` |
241
+ | \`fjall apps create\` | \`--name\`, \`--type\`, \`--template <nextjs\\|payload\\|dockerfile\\|api>\`, \`--pattern\`, \`--tier <tinkerer\\|lightweight\\|standard\\|resilient\\|enterprise>\`, \`--pattern-domain\`, \`--network <lightweight\\|standard\\|resilient\\|enterprise\\|none>\`, \`--into <repo-path>\`, \`--target <account-name>\`, \`--file-override <path>=<base64>\`, \`--dry-run\`, \`--database\`, \`--git\`, \`--github\`, \`--repo-visibility\` |
242
+ | \`fjall apps detect\` | (positional path), \`--output json\` |
243
+ | \`fjall accounts list\` | \`--output json\` |
244
+ | \`fjall deploy\` | \`--infra-only\`, \`--deploy-only\`, \`--skip-build\`, \`--environment\`, \`--target\`, \`--region\`, \`--all-regions\`, \`--no-cascade\` |
245
+ | \`fjall secrets set\` | \`--app\`, \`--cluster\`, \`--service\`, \`--lambda\`, \`--from-file\` |
246
+ | \`fjall add <type>\` | \`--app\`, \`--name\`, variadic \`--<property> <value>\` |
247
+ | \`fjall target set\` | (positional name) |
248
+
249
+ ## Environment Detection
250
+ Fjall auto-detects these agent environments:
251
+
252
+ | Agent | Env Var |
253
+ |-------|---------|
254
+ | Claude Code | \`CLAUDECODE\` |
255
+ | Codex | \`CODEX_SANDBOX\` |
256
+ | Cursor | \`CURSOR_AGENT\` |
257
+ | GitHub Copilot | \`COPILOT_MODEL\` |
258
+ | Generic | \`AI_AGENT\` |
259
+
260
+ The \`--agent\` flag is still recommended for explicitness and portability.
261
+
262
+ ## Session Hooks
263
+
264
+ \`\`\`bash
265
+ fjall agent install-hooks # Install ambient-context hooks
266
+ fjall agent uninstall-hooks # Remove hooks
267
+ \`\`\`
268
+
269
+ ## If your host doesn't load SKILL files
270
+
271
+ This SKILL is the primary, validated agent surface. If your host (Claude
272
+ Desktop, Cursor, Cline, Continue, Zed, etc.) cannot load skill files,
273
+ Fjall ships a beta MCP server (\`@fjall/mcp\`, \`fjall-mcp\` binary,
274
+ \`0.1.0-beta.1\`) that exposes 9 production tools that map to the same
275
+ CLI commands: \`create_organisation\`, \`add_resource\`, \`deploy\`,
276
+ \`destroy\`, \`list_resources\`, \`manage_profile\`, \`detect_app_framework\`,
277
+ \`plan_app_scaffold\`, \`apply_app_scaffold\`. The MCP shells out to the
278
+ same \`fjall\` CLI, so authentication, masking, and exit-code semantics
279
+ are identical.
280
+
281
+ The scaffold trio (\`detect_app_framework\` \u2192 \`plan_app_scaffold\` \u2192
282
+ \`apply_app_scaffold\`) supports the same plan\u2192review\u2192apply loop the
283
+ SKILL recipe teaches above, with \`fjall://plans/{planId}\` resources,
284
+ elicitation for ambiguous target accounts, and \`notifications/progress\`
285
+ streaming during apply. Use the SKILL+CLI path above when available;
286
+ fall back to the MCP only when the host lacks SKILL support.
287
+ See \`mcp/README.md\` for the beta surface and known gaps.
288
+ `}export{E as generateAgentFiles};
@@ -0,0 +1,61 @@
1
+ /**
2
+ * AgentOutputWriter — the sole stdout-facing adapter for AXI agent mode.
3
+ *
4
+ * This class owns ALL TOON writes to stdout. It is the SINGLE masking
5
+ * boundary (synthesis §1.11): every public method masks string data via
6
+ * `maskSensitiveOutput` before passing it to the formatter. Neither the
7
+ * formatter nor the callback layer performs masking.
8
+ *
9
+ * Diagnostics go to stderr via `logDiagnostic`, never stdout.
10
+ */
11
+ import type { AgentError, AgentSchema, ActionRequired, StreamEvent, TabularSchema } from "./schemas/types.js";
12
+ import { type SuggestionContext } from "./suggestions.js";
13
+ export interface AgentOutputWriterOptions {
14
+ readonly command: string;
15
+ readonly flags: Readonly<Record<string, string>>;
16
+ readonly verbose?: boolean;
17
+ readonly full?: boolean;
18
+ readonly writeFn?: (chunk: string) => void;
19
+ }
20
+ /**
21
+ * Severity levels understood by `logDiagnostic`. Mirrors the logger's
22
+ * leveled methods; unspecified level defaults to `debug` to preserve the
23
+ * existing noise floor.
24
+ */
25
+ export type DiagnosticLevel = "debug" | "info" | "warn" | "error";
26
+ export declare class AgentOutputWriter {
27
+ private readonly write;
28
+ private readonly resolver;
29
+ private readonly verbose;
30
+ private readonly full;
31
+ constructor(options: AgentOutputWriterOptions);
32
+ /** Whether `--full` was set, disabling content truncation. */
33
+ get isFullOutput(): boolean;
34
+ renderResult<T>(data: T, options?: {
35
+ schema?: AgentSchema;
36
+ suggestionContext?: SuggestionContext;
37
+ }): void;
38
+ renderListResult<T>(items: readonly T[], tabular: TabularSchema<T>, meta: {
39
+ entity: string;
40
+ aggregates?: Record<string, number | string>;
41
+ suggestionContext?: SuggestionContext;
42
+ fields?: readonly string[];
43
+ }): void;
44
+ renderEvent(event: StreamEvent): void;
45
+ emitEventSeparator(): void;
46
+ renderError(error: AgentError, suggestionContext?: SuggestionContext): void;
47
+ renderActionRequired(action: ActionRequired, suggestionContext?: SuggestionContext): void;
48
+ /**
49
+ * Write a diagnostic message to stderr. Never writes to stdout.
50
+ *
51
+ * When verbose is true, output is unmasked (debug mode per
52
+ * security-standards). When verbose is false, strings are masked.
53
+ *
54
+ * Severity defaults to `debug` to match the Phase 0 noise floor. Callers
55
+ * with explicit severity (e.g. build errors, warn-level callbacks) pass
56
+ * `level` so the message routes to the correct logger method.
57
+ */
58
+ logDiagnostic(component: string, message: string, data?: Record<string, unknown>, level?: DiagnosticLevel): void;
59
+ renderHelpLines(lines: readonly string[]): void;
60
+ private resolveHelp;
61
+ }
@@ -0,0 +1,8 @@
1
+ import{maskSensitiveOutput as f}from"@fjall/util";import{logger as l}from"../logger/index.js";import{BLOCK_SEPARATOR as w,renderActionRequired as b,renderError as v,renderEvent as k,renderHelp as h,renderList as E,renderObject as R}from"./toonFormatter.js";import{SuggestionResolver as A}from"./suggestions.js";function d(n){if(typeof n=="string")return f(n);if(n==null||typeof n!="object")return n;if(Array.isArray(n))return n.map(t=>d(t));if(n instanceof Date||n instanceof RegExp)return n;const e={};for(const[t,r]of Object.entries(n))e[t]=d(r);return e}class q{write;resolver;verbose;full;constructor(e){this.write=e.writeFn??(t=>{process.stdout.write(t)}),this.resolver=new A(e.command,e.flags),this.verbose=e.verbose??!1,this.full=e.full??!1}get isFullOutput(){return this.full}renderResult(e,t){const r=d(e),i=R(r),s=this.resolveHelp(t?.suggestionContext);this.write(i+s+`
2
+ `)}renderListResult(e,t,r){const i=e.map(c=>d(c)),s=r.fields,o=s!==void 0&&s.length>0?{fields:s,project:c=>{const a=t.project(c),g={};for(const u of s)u in a&&(g[u]=a[u]);return g}}:t,m=E(i,o,{entity:r.entity,aggregates:r.aggregates}),p=this.resolveHelp(r.suggestionContext);this.write(m+p+`
3
+ `)}renderEvent(e){const t=d(e),r=k(t);this.write(r)}emitEventSeparator(){this.write(w+`
4
+ `)}renderError(e,t){const r={...e,message:f(e.message),...e.details!==void 0?{details:d(e.details)}:{}},i=v(r),s=this.resolveHelp(t);this.write(i+s+`
5
+ `)}renderActionRequired(e,t){const r={...e,message:f(e.message),action:f(e.action),...e.details!==void 0?{details:d(e.details)}:{},...e.choices!==void 0?{choices:e.choices.map(o=>f(o))}:{}},i=b(r),s=this.resolveHelp(t);this.write(i+s+`
6
+ `)}logDiagnostic(e,t,r,i="debug"){const s=this.verbose?t:f(t),o=this.verbose||r===void 0?r:d(r);switch(i){case"error":l.error(e,s,o);return;case"warn":l.warn(e,s,o);return;case"info":l.info(e,s,o);return;default:l.debug(e,s,o);return}}renderHelpLines(e){if(e.length===0)return;const t=e.map(r=>f(r));this.write(h(t)+`
7
+ `)}resolveHelp(e){if(e===void 0)return"";const t=this.resolver.resolve(e);return t.length===0?"":`
8
+ `+h(t)}}export{q as AgentOutputWriter};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Progressive budget reducer for AXI agent output.
3
+ *
4
+ * Works on the already-rendered TOON string, stripping content until
5
+ * the output fits within the requested budget.
6
+ *
7
+ * Budget modes:
8
+ * - `minimal` — entity count + status summary only (no list items)
9
+ * - `compact` — list items with first 2 fields per row + aggregates
10
+ * - `<number>` — approximate token target via progressive reduction
11
+ */
12
+ /**
13
+ * Apply a budget constraint to a rendered TOON string.
14
+ *
15
+ * @param output - The fully rendered TOON string
16
+ * @param budget - One of `"minimal"`, `"compact"`, or a numeric string
17
+ * @returns The reduced output string
18
+ */
19
+ export declare function applyBudget(output: string, budget: string | undefined): string;
@@ -0,0 +1,4 @@
1
+ function a(n){return Math.ceil(n.length/4)}const i=/^ {2,}\S.*$/gm,s=/^help\[\d+\]:.*(?:\n {2,}.*$)*/gm,o=/^[a-zA-Z][a-zA-Z0-9_]*: \S.*$/gm,m=/^[a-zA-Z][a-zA-Z0-9_]*\[\d+\]:.*$/gm;function E(n){let r=n.replace(s,"");return r=r.replace(i,""),c(r)}function d(n){let r=n.replace(s,"");return r=r.replace(i,e=>p(e,2)),c(r)}function p(n,r){const e=n.match(/^(\s*)/)?.[1]??"",t=n.trimStart().split(",").map(u=>u.trim());if(t.length<=r)return n;const f=t.slice(0,r).join(", ");return`${e}${f}`}function h(n,r){if(a(n)<=r)return n;let e=n.replace(s,"");if(e=c(e),a(e)<=r)return e;const l=new Set;for(const t of e.matchAll(m))l.add(t[0]);return e=e.replace(o,t=>l.has(t)?t:""),e=c(e),a(e)<=r||(e=e.replace(i,t=>p(t,2)),e=c(e),a(e)<=r)?e:(e=e.replace(i,""),c(e))}function c(n){return n.replace(/\n{3,}/g,`
2
+
3
+ `).replace(/^\n+/,"").replace(/\n+$/,`
4
+ `)}function _(n,r){if(r===void 0)return n;if(r==="minimal")return E(n);if(r==="compact")return d(n);const e=parseInt(r,10);return Number.isNaN(e)||e<=0?n:h(n,e)}export{_ as applyBudget};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Agent environment detection.
3
+ *
4
+ * Detects known AI agent environments (Claude Code, Cursor, Codex, Copilot,
5
+ * etc.) via environment variables and filesystem markers. Pure, side-effect
6
+ * free except for a cached filesystem check and a result cache.
7
+ *
8
+ * Priority ordering is load-bearing: `generic` (AI_AGENT env var) must be
9
+ * checked LAST so that specific agent signals take precedence. Tests assert
10
+ * the ordering with an explicit case for CLAUDECODE + AI_AGENT both set.
11
+ *
12
+ * TTY gate: when auto-detecting, requires `!process.stdout.isTTY`. This is
13
+ * deliberate and matches `isNonInteractiveMode` which gates on stdout too.
14
+ * Reviewer feedback flagged stdin-based gating as inconsistent. Explicit
15
+ * `--agent` / `--no-agent` flags bypass the TTY check.
16
+ */
17
+ export interface DetectedAgent {
18
+ readonly name: string;
19
+ readonly detected: true;
20
+ }
21
+ /**
22
+ * Returns the first matching agent signal, or `undefined` if none matches.
23
+ * Memoised — call `resetDetectAgentCache()` in test `beforeEach` to clear.
24
+ */
25
+ export declare function detectAgent(): DetectedAgent | undefined;
26
+ /**
27
+ * Resets the memoisation cache. Call this in `beforeEach` in tests that
28
+ * manipulate `process.env` via `vi.stubEnv`. Production code should never
29
+ * call this.
30
+ */
31
+ export declare function resetDetectAgentCache(): void;
32
+ /**
33
+ * Options that influence agent-mode activation. Explicit `options.agent`
34
+ * (true or false) is a hard override — detection is not consulted.
35
+ */
36
+ export interface AgentModeOptions {
37
+ readonly agent?: boolean;
38
+ }
39
+ /**
40
+ * Returns true when the CLI should activate agent output mode.
41
+ *
42
+ * Priority (reviewer-confirmed):
43
+ * 1. Explicit `options.agent === true` → always on, regardless of TTY
44
+ * 2. Explicit `options.agent === false` → always off, hard override
45
+ * 3. Auto-detection: an agent signal is present AND `stdout` is not a TTY
46
+ *
47
+ * Stdout-based (not stdin-based) TTY gate matches `isNonInteractiveMode`
48
+ * for consistency. A developer running with `CLAUDECODE=1` in a real
49
+ * terminal does NOT auto-enter agent mode — `stdout.isTTY` is true.
50
+ */
51
+ export declare function isAgentMode(options?: AgentModeOptions): boolean;
@@ -0,0 +1 @@
1
+ import{existsSync as r}from"node:fs";import{logger as s}from"../logger/index.js";function c(e){try{return r(e)}catch(t){return s.debug("Agent","safeExistsSync swallowed error",{path:e,error:t instanceof Error?t.message:String(t)}),!1}}const o=[{name:"claude-code",detect:()=>!!process.env.CLAUDECODE||!!process.env.CLAUDE_CODE},{name:"cowork",detect:()=>!!process.env.CLAUDE_CODE_IS_COWORK},{name:"codex",detect:()=>!!process.env.CODEX_SANDBOX||!!process.env.CODEX_CI||!!process.env.CODEX_THREAD_ID},{name:"cursor",detect:()=>!!process.env.CURSOR_TRACE_ID||!!process.env.CURSOR_AGENT||process.env.CURSOR_EXTENSION_HOST_ROLE==="agent-exec"},{name:"gemini",detect:()=>!!process.env.GEMINI_CLI},{name:"copilot",detect:()=>!!process.env.COPILOT_MODEL||!!process.env.COPILOT_ALLOW_ALL||!!process.env.COPILOT_GITHUB_TOKEN},{name:"devin",detect:()=>c("/opt/.devin")},{name:"replit",detect:()=>!!process.env.REPL_ID},{name:"augment",detect:()=>!!process.env.AUGMENT_AGENT},{name:"opencode",detect:()=>!!process.env.OPENCODE_CLIENT},{name:"generic",detect:()=>!!process.env.AI_AGENT}];let n=null;function d(){if(n!==null)return n;for(const e of o)if(e.detect())return n={name:e.name,detected:!0},n;n=void 0}function i(){n=null}function u(e){return e?.agent===!0?!0:e?.agent===!1||d()===void 0?!1:!process.stdout.isTTY}export{d as detectAgent,u as isAgentMode,i as resetDetectAgentCache};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Maps known service error classes to agent error codes. This provides
3
+ * deterministic error classification for typed service errors, bypassing
4
+ * the regex fallback in `errorCodes.ts`.
5
+ *
6
+ * The regex fallback still runs for unrecognised error classes and for
7
+ * raw string errors. This map simply short-circuits the lookup for known
8
+ * types, improving accuracy and avoiding false matches.
9
+ */
10
+ import type { AgentErrorCode } from "./errorCodes.js";
11
+ /**
12
+ * Attempt to map an error to an agent error code via its class name.
13
+ * Returns `undefined` if the error class is not in the map, signalling
14
+ * the caller should fall through to the regex path.
15
+ */
16
+ export declare function mapErrorClassToCode(error: unknown): AgentErrorCode | undefined;
@@ -0,0 +1 @@
1
+ const E={AppQueryError:"NOT_FOUND",SecretsError:"VALIDATION_ERROR",UserError:"VALIDATION_ERROR",ApiError:"UNKNOWN",AuthenticationError:"AUTH_REQUIRED",CloudFormationError:"AWS_ERROR",CredentialError:"AUTH_REQUIRED",DeploymentError:"DEPLOY_FAILED",ValidationError:"VALIDATION_ERROR",ZodError:"VALIDATION_ERROR",DomainError:"NOT_FOUND",CreateError:"VALIDATION_ERROR",RestoreError:"AWS_ERROR",ImportError:"NOT_FOUND",MonitoringMetadataError:"UNKNOWN"},O={AppQueryError:{not_found:"NOT_FOUND",api_error:"NETWORK_ERROR",credential_error:"AUTH_REQUIRED",general:"UNKNOWN"},SecretsError:{not_found:"NOT_FOUND",invalid_namespace:"VALIDATION_ERROR",general:"UNKNOWN"},UserError:{not_found:"NOT_FOUND",already_exists:"CONFLICT",general:"UNKNOWN"},DomainError:{not_found:"NOT_FOUND",already_exists:"CONFLICT",parse_error:"VALIDATION_ERROR",deploy_error:"DEPLOY_FAILED",verification_error:"TIMEOUT",validation_error:"VALIDATION_ERROR",import_error:"AWS_ERROR",export_error:"AWS_ERROR"},CreateError:{already_exists:"CONFLICT",not_found:"NOT_FOUND",generation_error:"UNKNOWN",dependency_error:"UNKNOWN",validation_error:"VALIDATION_ERROR",authentication_error:"AUTH_REQUIRED"},RestoreError:{not_found:"NOT_FOUND",permission_denied:"FORBIDDEN",validation_error:"VALIDATION_ERROR",aws_error:"AWS_ERROR",no_recovery_points:"NOT_FOUND"},ImportError:{APP_NOT_FOUND:"NOT_FOUND",MISSING_INFRASTRUCTURE_FILE:"NOT_FOUND",NO_RESOURCES:"NOT_FOUND",NO_RESOURCES_SELECTED:"VALIDATION_ERROR",MULTIPLE_RESOURCES:"VALIDATION_ERROR",DISCOVERY_FAILED:"AWS_ERROR",GENERATION_FAILED:"AWS_ERROR",SYNTHESIS_FAILED:"AWS_ERROR",MAPPING_FAILED:"AWS_ERROR",CDK_IMPORT_FAILED:"AWS_ERROR",IMPORT_FAILED:"AWS_ERROR"},MonitoringMetadataError:{captureMonitoringMetadata:"AWS_ERROR",sendMonitoringMetadata:"NETWORK_ERROR"}};function _(r){if(r==null||typeof r!="object")return;const e=("name"in r&&typeof r.name=="string"?r.name:void 0)??r.constructor?.name;if(e===void 0||e==="Error")return;const o=E[e];if(o===void 0)return;const R=O[e];if(R!==void 0){const n="errorType"in r&&typeof r.errorType=="string"?r.errorType:"code"in r&&typeof r.code=="string"?r.code:"operation"in r&&typeof r.operation=="string"?r.operation:void 0;if(n!==void 0&&R[n]!==void 0)return R[n]}return o}export{_ as mapErrorClassToCode};
@@ -0,0 +1,48 @@
1
+ /**
2
+ * AXI agent error codes — stable machine-readable strings returned to agents
3
+ * in TOON error blocks. Never leaks internal error class names.
4
+ *
5
+ * Pattern ordering is load-bearing: most-specific patterns FIRST, so that
6
+ * messages like "CloudFormation update failed: Parameter validation failed"
7
+ * resolve to AWS_ERROR rather than VALIDATION_ERROR. Run
8
+ * `errorCodes.test.ts` after any change to confirm the golden fixtures still
9
+ * resolve to their expected codes.
10
+ *
11
+ * Rationale for single closed enum: agents branch on these codes, so they
12
+ * must be stable across releases. New codes are additive only. Removing or
13
+ * renaming a code is a breaking change.
14
+ */
15
+ export declare const AGENT_ERROR_CODES: {
16
+ readonly AUTH_REQUIRED: "AUTH_REQUIRED";
17
+ readonly AUTH_EXPIRED: "AUTH_EXPIRED";
18
+ readonly NO_AWS_ACCOUNT: "NO_AWS_ACCOUNT";
19
+ readonly NOT_FOUND: "NOT_FOUND";
20
+ readonly VALIDATION_ERROR: "VALIDATION_ERROR";
21
+ readonly DEPLOY_FAILED: "DEPLOY_FAILED";
22
+ readonly NETWORK_ERROR: "NETWORK_ERROR";
23
+ readonly AWS_ERROR: "AWS_ERROR";
24
+ readonly TIMEOUT: "TIMEOUT";
25
+ readonly CONFLICT: "CONFLICT";
26
+ readonly RATE_LIMITED: "RATE_LIMITED";
27
+ readonly FORBIDDEN: "FORBIDDEN";
28
+ readonly BUILDX_UNAVAILABLE: "BUILDX_UNAVAILABLE";
29
+ readonly UNKNOWN: "UNKNOWN";
30
+ };
31
+ export type AgentErrorCode = (typeof AGENT_ERROR_CODES)[keyof typeof AGENT_ERROR_CODES];
32
+ /**
33
+ * Maps an arbitrary error-shaped value to a stable agent error code.
34
+ * Accepts `unknown` because callback-surfaced errors are sometimes strings
35
+ * or shaped objects, not `Error` instances.
36
+ *
37
+ * Pattern matching order: explicit class-name checks first (via
38
+ * `errorCodeMap.ts`), then message regex fallback. Never throws; returns
39
+ * `UNKNOWN` on non-matching input.
40
+ */
41
+ export declare function mapErrorToCode(error: unknown): AgentErrorCode;
42
+ /**
43
+ * Indicates whether an agent error represents a state the agent cannot
44
+ * resolve without human intervention. Used by the TOON `action_required`
45
+ * block to set `userActionRequired`.
46
+ */
47
+ export declare function isUserActionRequired(code: AgentErrorCode): boolean;
48
+ export declare function extractMessage(error: unknown): string;
@@ -0,0 +1 @@
1
+ import{mapErrorClassToCode as E}from"./errorCodeMap.js";const r={AUTH_REQUIRED:"AUTH_REQUIRED",AUTH_EXPIRED:"AUTH_EXPIRED",NO_AWS_ACCOUNT:"NO_AWS_ACCOUNT",NOT_FOUND:"NOT_FOUND",VALIDATION_ERROR:"VALIDATION_ERROR",DEPLOY_FAILED:"DEPLOY_FAILED",NETWORK_ERROR:"NETWORK_ERROR",AWS_ERROR:"AWS_ERROR",TIMEOUT:"TIMEOUT",CONFLICT:"CONFLICT",RATE_LIMITED:"RATE_LIMITED",FORBIDDEN:"FORBIDDEN",BUILDX_UNAVAILABLE:"BUILDX_UNAVAILABLE",UNKNOWN:"UNKNOWN"},R=[{pattern:/throttl|rate.?limit/i,code:"RATE_LIMITED"},{pattern:/buildx (?:unavailable|not (?:installed|found))|docker buildx version/i,code:"BUILDX_UNAVAILABLE"},{pattern:/token.+(expired|invalid)|session.+expired/i,code:"AUTH_EXPIRED"},{pattern:/already authenticated/i,code:"CONFLICT"},{pattern:/not.?logged.?in|no.+credentials|authenticat/i,code:"AUTH_REQUIRED"},{pattern:/access.?denied|not authorized to|forbidden/i,code:"FORBIDDEN"},{pattern:/no.+aws.+account/i,code:"NO_AWS_ACCOUNT"},{pattern:/network|econnrefused|etimedout|enotfound/i,code:"NETWORK_ERROR"},{pattern:/timed.?out|timeout/i,code:"TIMEOUT"},{pattern:/already exists/i,code:"CONFLICT"},{pattern:/not.?found|does not exist/i,code:"NOT_FOUND"},{pattern:/cloudformation|cfn|^aws\.|aws::|resourcenotready/i,code:"AWS_ERROR"},{pattern:/validation failed|invalid parameter|is required/i,code:"VALIDATION_ERROR"}],a=new Set(["AUTH_REQUIRED","AUTH_EXPIRED","FORBIDDEN","BUILDX_UNAVAILABLE"]);function s(e){const t=E(e);if(t!==void 0)return t;const n=d(e);if(n==="")return"UNKNOWN";for(const{pattern:o,code:i}of R)if(o.test(n))return i;return"UNKNOWN"}function N(e){return a.has(e)}function d(e){if(e==null)return"";if(typeof e=="string")return e;if(e instanceof Error)return e.message;if(typeof e=="object"&&"message"in e){const t=e.message;return typeof t=="string"?t:String(t)}return String(e)}export{r as AGENT_ERROR_CODES,d as extractMessage,N as isUserActionRequired,s as mapErrorToCode};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Field selection parser for AXI `--fields` flag.
3
+ *
4
+ * Parses a comma-separated field list, validates each field against the
5
+ * command's AgentSchema, and merges with the schema's defaultFields.
6
+ */
7
+ import type { AgentSchema } from "./schemas/types.js";
8
+ /**
9
+ * Parse and resolve a `--fields` argument against an AgentSchema.
10
+ *
11
+ * When `fieldsArg` is undefined, returns the schema's `defaultFields`.
12
+ * When provided, validates each requested field exists in either
13
+ * `defaultFields` or `extraFields`, then returns the union of
14
+ * `defaultFields` and the valid requested fields. Invalid fields are
15
+ * silently dropped — the agent can inspect the returned list to see
16
+ * what was resolved.
17
+ *
18
+ * @param fieldsArg - Comma-separated field list from `--fields`, or undefined
19
+ * @param schema - The command's AgentSchema describing available fields
20
+ * @returns Resolved field list (defaults + validated extras), deduplicated
21
+ */
22
+ export declare function parseFieldSelection(fieldsArg: string | undefined, schema: AgentSchema): string[];
@@ -0,0 +1 @@
1
+ function o(n,t){const l=[...t.defaultFields];if(n===void 0)return l;const i=n.split(",").map(e=>e.trim()).filter(e=>e.length>0),s=new Set([...t.defaultFields,...Object.keys(t.extraFields)]),d=new Set(l);for(const e of i)s.has(e)&&d.add(e);return[...d]}export{o as parseFieldSelection};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Surface classifier for prerequisite-gate routing.
3
+ *
4
+ * Different CLI surfaces consume the same prerequisite failure (e.g. buildx
5
+ * not installed) in different shapes:
6
+ * - interactive → render an Ink screen with [Retry] [Cancel]
7
+ * - non-interactive → write a human-readable error to stderr, exit 64
8
+ * - ci → same as non-interactive (no TTY → no Ink screen)
9
+ * - agent → emit a TOON error block via AgentOutputWriter
10
+ *
11
+ * Precedence (most-specific-first; deliberately does not match
12
+ * `isNonInteractiveMode` which collapses agent into non-interactive):
13
+ * 1. agent — `isAgentMode()` true
14
+ * 2. non-interactive — explicit `--non-interactive` flag
15
+ * 3. ci — `process.env.CI` non-empty OR `!process.stdout.isTTY`
16
+ * 4. interactive — default
17
+ *
18
+ * Empty-string `CI` env is rejected per `robustness-standards.md` § "Environment
19
+ * Variable Truthy Checks" — Kubernetes ConfigMaps and compose env-files can
20
+ * legitimately export `CI=""` for an inherited-and-cleared variable.
21
+ */
22
+ export type Surface = "interactive" | "non-interactive" | "ci" | "agent";
23
+ export interface GetSurfaceOptions {
24
+ readonly nonInteractive?: boolean;
25
+ readonly agent?: boolean;
26
+ }
27
+ export declare function getSurface(opts?: GetSurfaceOptions): Surface;
@@ -0,0 +1 @@
1
+ import{isAgentMode as t}from"./detectAgent.js";function c(e){if(t({agent:e?.agent}))return"agent";if(e?.nonInteractive===!0)return"non-interactive";const n=process.env.CI;return n!==void 0&&n!==""||!process.stdout.isTTY?"ci":"interactive"}export{c as getSurface};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Public API barrel for the AXI agent output layer.
3
+ *
4
+ * This module is CLI-internal. It MUST NOT be imported by the webapp
5
+ * package — `detectAgent.ts` uses `node:fs` directly, and several future
6
+ * submodules will use other Node-only APIs. The webapp consumes agent
7
+ * output contracts via the operations layer and TOON-formatted API
8
+ * responses, not by importing this barrel.
9
+ *
10
+ * Phase 0: detection + error codes + schema types.
11
+ * Phase 1: TOON formatter, suggestion resolver, AgentOutputWriter.
12
+ * Phase 1 (remaining): agent callback factory, CLI wiring.
13
+ */
14
+ export { AGENT_ERROR_CODES, type AgentErrorCode, extractMessage, isUserActionRequired, mapErrorToCode } from "./errorCodes.js";
15
+ export { type AgentModeOptions, type DetectedAgent, detectAgent, isAgentMode, resetDetectAgentCache } from "./detectAgent.js";
16
+ export { SuggestionResolver, type SuggestionContext } from "./suggestions.js";
17
+ export { AgentOutputWriter, type AgentOutputWriterOptions, type DiagnosticLevel } from "./agentOutput.js";
18
+ export { createAgentOutput, type AgentCallbacksOutput } from "./agentCallbacks.js";
19
+ export type { ActionRequired, Aggregate, AgentError, AgentSchema, FieldSource, StreamEvent, TabularSchema, TransformName } from "./schemas/index.js";
20
+ export { mapErrorClassToCode } from "./errorCodeMap.js";
21
+ export { getRequiredScopes, type TokenScope } from "./tokenScopes.js";
22
+ export { applyBudget } from "./budget.js";
23
+ export { parseFieldSelection } from "./fieldSelection.js";
24
+ export { StreamingToonWriter } from "./streaming.js";
25
+ export { destructiveGate, missingFlagGate, authRequiredGate, ssoGate, awsAccountGate, driftConflictGate, type DriftConflictDelta } from "./actionRequired.js";
26
+ export { installHooks, uninstallHooks, isHookInstallDisabled, hasOptOutSentinel } from "./sessionHooks.js";
27
+ export { generateAgentFiles } from "./agentInit.js";
@@ -0,0 +1 @@
1
+ import{AGENT_ERROR_CODES as o,extractMessage as r,isUserActionRequired as s,mapErrorToCode as a}from"./errorCodes.js";import{detectAgent as p,isAgentMode as n,resetDetectAgentCache as m}from"./detectAgent.js";import{SuggestionResolver as f}from"./suggestions.js";import{AgentOutputWriter as u}from"./agentOutput.js";import{createAgentOutput as c}from"./agentCallbacks.js";import{mapErrorClassToCode as A}from"./errorCodeMap.js";import{getRequiredScopes as R}from"./tokenScopes.js";import{applyBudget as O}from"./budget.js";import{parseFieldSelection as E}from"./fieldSelection.js";import{StreamingToonWriter as h}from"./streaming.js";import{destructiveGate as q,missingFlagGate as D,authRequiredGate as F,ssoGate as H,awsAccountGate as v,driftConflictGate as M}from"./actionRequired.js";import{installHooks as _,uninstallHooks as b,isHookInstallDisabled as w,hasOptOutSentinel as y}from"./sessionHooks.js";import{generateAgentFiles as I}from"./agentInit.js";export{o as AGENT_ERROR_CODES,u as AgentOutputWriter,h as StreamingToonWriter,f as SuggestionResolver,O as applyBudget,F as authRequiredGate,v as awsAccountGate,c as createAgentOutput,q as destructiveGate,p as detectAgent,M as driftConflictGate,r as extractMessage,I as generateAgentFiles,R as getRequiredScopes,y as hasOptOutSentinel,_ as installHooks,n as isAgentMode,w as isHookInstallDisabled,s as isUserActionRequired,A as mapErrorClassToCode,a as mapErrorToCode,D as missingFlagGate,E as parseFieldSelection,m as resetDetectAgentCache,H as ssoGate,b as uninstallHooks};