fjall 0.95.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 +7569 -4226
  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 +761 -550
  228. package/package.json +38 -35
@@ -0,0 +1,31 @@
1
+ import { type McpStepStatus } from "@fjall/util/mcpProtocol";
2
+ export interface McpProtocolEmitter {
3
+ stepStart(stepId: string, name: string, index: number, total: number): Promise<void>;
4
+ stepComplete(stepId: string, name: string, status: McpStepStatus, index: number, total: number, errorMessage?: string): Promise<void>;
5
+ warning(message: string): Promise<void>;
6
+ result(data: unknown): Promise<void>;
7
+ error(code: string, message: string, details?: Record<string, unknown>): Promise<void>;
8
+ }
9
+ export interface CreateMcpProtocolEmitterOptions {
10
+ readonly write?: (chunk: string) => Promise<void>;
11
+ }
12
+ /**
13
+ * Build a stdout emitter that serialises every frame onto a single
14
+ * promise chain.
15
+ *
16
+ * 1. Frame order matches call order (each write awaits the previous).
17
+ * 2. `await emitter.result(...)` / `.error(...)` drains in-flight
18
+ * writes — callers can fire-and-forget intermediate progress
19
+ * frames.
20
+ * 3. `safeParse` validation precedes every write; a protocol
21
+ * violation rejects the returned promise (and propagates through
22
+ * the chain) rather than throwing synchronously.
23
+ * 4. A failed write (EPIPE / closed pipe) is logged once at warn
24
+ * level and the chain is reset so subsequent frames still attempt
25
+ * emission. Write failures NEVER silently no-op the rest of the
26
+ * stream.
27
+ *
28
+ * Masking happens BEFORE `JSON.stringify` on every user-derived string
29
+ * field (security-standards "Mask Before You Truncate").
30
+ */
31
+ export declare function createMcpProtocolEmitter(options?: CreateMcpProtocolEmitterOptions): McpProtocolEmitter;
@@ -0,0 +1,2 @@
1
+ import{maskSensitiveOutput as i}from"@fjall/util";import{MCP_PROTOCOL_VERSION as f,McpProtocolFrameSchema as l}from"@fjall/util/mcpProtocol";import{logger as g}from"../logger/index.js";const P="McpProtocolEmit";function u(e){if(typeof e=="string")return i(e);if(Array.isArray(e))return e.map(u);if(e!==null&&typeof e=="object"){const a={};for(const[c,t]of Object.entries(e))a[c]=u(t);return a}return e}const w=e=>new Promise((a,c)=>{process.stdout.write(e,t=>{t?c(t):a()})});function S(e={}){const a=e.write??w;let c=Promise.resolve();function t(r){const n=l.safeParse(r);if(!n.success){const s=Promise.reject(new Error(`Invalid MCP frame: ${n.error.message}`));return c=s.catch(()=>{}),s}const o=JSON.stringify(n.data)+`
2
+ `,m=c.then(()=>a(o));return c=m.catch(s=>{g.warn(P,"Frame write failed",{error:i(s instanceof Error?s.message:String(s))})}),m}return{stepStart(r,n,o,m){return t({v:f,kind:"step.start",stepId:r,name:i(n),index:o,total:m})},stepComplete(r,n,o,m,s,p){const d={v:f,kind:"step.complete",stepId:r,name:i(n),status:o,index:m,total:s,...p!==void 0&&{errorMessage:i(p)}};return t(d)},warning(r){return t({v:f,kind:"warning",message:i(r)})},result(r){return t({v:f,kind:"result",data:u(r)})},error(r,n,o){return t({v:f,kind:"error",error:{code:i(r),message:i(n),...o!==void 0&&{details:u(o)}}})}}}export{S as createMcpProtocolEmitter};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Agent output schemas for apps + status commands.
3
+ * Defines field schemas and tabular projections for TOON rendering.
4
+ */
5
+ import type { AgentSchema, TabularSchema } from "./types.js";
6
+ import type { AppSummary, AppDetail, AppListData } from "../../../services/app/AppQueryService.js";
7
+ export declare const APPS_LIST_TABULAR: TabularSchema<AppSummary>;
8
+ export declare function buildAppsListAggregates(data: AppListData): Record<string, number>;
9
+ export declare const APPS_DESCRIBE_SCHEMA: AgentSchema;
10
+ export declare function buildAppDescribeData(detail: AppDetail): Record<string, unknown>;
11
+ export declare const APPS_CREATE_SCHEMA: AgentSchema;
12
+ /**
13
+ * Schema for the dry-run preview emitted by `fjall apps create --dry-run --agent`.
14
+ * Mirrors `DryRunArtefactsSchema` in `cli/src/operations/types.ts` so the CLI
15
+ * and MCP wires stay in lockstep.
16
+ */
17
+ export declare const APPS_CREATE_DRY_RUN_SCHEMA: AgentSchema;
18
+ export declare const STATUS_TABULAR: TabularSchema<AppSummary>;
@@ -0,0 +1 @@
1
+ const t={fields:["name","health"],project:e=>({name:e.name,health:e.health})};function a(e){return{total:e.totalCount,healthy:e.healthy,unhealthy:e.unhealthy,deploying:e.deploying}}const n={entity:"app",defaultFields:["name","health","id"],extraFields:{},aggregates:[]};function l(e){return{name:e.name,health:e.health,id:e.id,...typeof e.application=="object"&&e.application!==null?e.application:{}}}const o={entity:"app",defaultFields:["name"],extraFields:{},aggregates:[]},p={entity:"plan",defaultFields:["name","mode","fileCount","npmPackages","registryActions"],extraFields:{},aggregates:[]},h={fields:["name","health"],project:e=>({name:e.name,health:e.health})};export{p as APPS_CREATE_DRY_RUN_SCHEMA,o as APPS_CREATE_SCHEMA,n as APPS_DESCRIBE_SCHEMA,t as APPS_LIST_TABULAR,h as STATUS_TABULAR,l as buildAppDescribeData,a as buildAppsListAggregates};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Agent output schemas for asset commands.
3
+ * Defines field schemas and tabular projections for TOON rendering.
4
+ */
5
+ import type { AgentSchema, TabularSchema } from "./types.js";
6
+ import type { AssetSummary, ComplianceIssueSummary } from "../../api/FjallApiClient.types.js";
7
+ export declare const ASSETS_LIST_TABULAR: TabularSchema<AssetSummary>;
8
+ export declare function buildAssetsListAggregates(assets: readonly AssetSummary[]): Record<string, number>;
9
+ export declare const ASSETS_DETAIL_SCHEMA: AgentSchema;
10
+ export declare const ASSETS_COMPLIANCE_TABULAR: TabularSchema<ComplianceIssueSummary>;
11
+ export declare function buildComplianceAggregates(issues: readonly ComplianceIssueSummary[]): Record<string, number>;
12
+ export declare const ASSETS_SUMMARY_SCHEMA: AgentSchema;
13
+ export declare function buildAssetsSummary(assets: readonly AssetSummary[]): Record<string, number>;
@@ -0,0 +1 @@
1
+ const r={fields:["name","type","region","status"],project:t=>({name:t.name,type:t.type,region:t.region??"",status:t.status})};function i(t){let a=0,s=0;for(const e of t)e.status==="active"?a++:e.status==="deleted"&&s++;return{total:t.length,active:a,deleted:s}}const o={entity:"asset",defaultFields:["name","type","region","status","assetIdentifier","provider"],extraFields:{id:{path:"id"},accountId:{path:"accountId"},iacStatus:{path:"iacStatus"},estimatedMonthlyCost:{path:"estimatedMonthlyCost",transform:"currency"},lastSeenAt:{path:"lastSeenAt",transform:"relativeTime"},createdAt:{path:"createdAt",transform:"relativeTime"},updatedAt:{path:"updatedAt",transform:"relativeTime"}},aggregates:[]},l={fields:["title","severity","status","ruleId"],project:t=>({title:t.title,severity:t.severity,status:t.status,ruleId:t.ruleId})};function n(t){let a=0,s=0;for(const e of t)e.severity==="critical"?a++:e.severity==="high"&&s++;return{total:t.length,critical:a,high:s}}const u={entity:"asset_summary",defaultFields:["total","active","withIssues"],extraFields:{},aggregates:[]};function c(t){let a=0,s=0;for(const e of t)e.status==="active"&&a++,e._count&&e._count.complianceIssues>0&&s++;return{total:t.length,active:a,withIssues:s}}export{l as ASSETS_COMPLIANCE_TABULAR,o as ASSETS_DETAIL_SCHEMA,r as ASSETS_LIST_TABULAR,u as ASSETS_SUMMARY_SCHEMA,i as buildAssetsListAggregates,c as buildAssetsSummary,n as buildComplianceAggregates};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Agent output schemas for AWS commands: aws exec.
3
+ */
4
+ import type { AgentSchema } from "./types.js";
5
+ export declare const AWS_EXEC_SCHEMA: AgentSchema;
@@ -0,0 +1 @@
1
+ const e={entity:"exec",defaultFields:["exitCode"],extraFields:{command:{path:"command"},target:{path:"target"},region:{path:"region"}},aggregates:[]};export{e as AWS_EXEC_SCHEMA};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Agent output schemas for deploy, destroy, and build commands.
3
+ * These are streaming commands — they emit multiple TOON blocks.
4
+ */
5
+ import type { AgentSchema } from "./types.js";
6
+ export declare const DEPLOY_SCHEMA: AgentSchema;
7
+ export declare const DESTROY_SCHEMA: AgentSchema;
8
+ export declare const BUILD_SCHEMA: AgentSchema;
@@ -0,0 +1 @@
1
+ const t={entity:"deployment",defaultFields:["target","status","duration"],extraFields:{stackName:{path:"stackName"},outputs:{path:"outputs"}},aggregates:[]},a={entity:"destroy",defaultFields:["target","status","duration"],extraFields:{},aggregates:[]},e={entity:"build",defaultFields:["app","imageUrl","status"],extraFields:{tag:{path:"tag"},duration:{path:"duration"}},aggregates:[]};export{e as BUILD_SCHEMA,t as DEPLOY_SCHEMA,a as DESTROY_SCHEMA};
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Barrel for agent output schema types and per-command schemas.
3
+ */
4
+ export type { ActionRequired, Aggregate, AgentError, AgentSchema, FieldSource, StreamEvent, TabularSchema, TransformName } from "./types.js";
5
+ export * from "./appsSchemas.js";
6
+ export * from "./secretsSchemas.js";
7
+ export * from "./userSchemas.js";
8
+ export * from "./deploySchemas.js";
9
+ export * from "./infraSchemas.js";
10
+ export * from "./assetSchemas.js";
@@ -0,0 +1 @@
1
+ export*from"./appsSchemas.js";export*from"./secretsSchemas.js";export*from"./userSchemas.js";export*from"./deploySchemas.js";export*from"./infraSchemas.js";export*from"./assetSchemas.js";
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Agent output schemas for infrastructure commands:
3
+ * connect, login, list, add, tunnel, target, domain, create (account/org),
4
+ * restore, import, sync.
5
+ */
6
+ import type { DerivedTarget } from "@fjall/util";
7
+ import type { AgentSchema, TabularSchema } from "./types.js";
8
+ export declare const CONNECT_SCHEMA: AgentSchema;
9
+ export declare const LOGIN_SCHEMA: AgentSchema;
10
+ export declare const LIST_SCHEMA: AgentSchema;
11
+ export declare const LIST_TABULAR: TabularSchema<{
12
+ type: string;
13
+ name: string;
14
+ filePath: string;
15
+ start: number;
16
+ length: number;
17
+ }>;
18
+ export declare const ADD_SCHEMA: AgentSchema;
19
+ export declare const HISTORY_SCHEMA: AgentSchema;
20
+ export declare const HISTORY_TABULAR: TabularSchema<{
21
+ timestamp: string;
22
+ path: string;
23
+ sizeBytes: number;
24
+ }>;
25
+ export declare const TUNNEL_SCHEMA: AgentSchema;
26
+ export declare const TARGET_LIST_SCHEMA: AgentSchema;
27
+ export declare const TARGET_LIST_TABULAR: TabularSchema<DerivedTarget & {
28
+ active: boolean;
29
+ }>;
30
+ export declare const TARGET_GET_SCHEMA: AgentSchema;
31
+ export declare const TARGET_SET_SCHEMA: AgentSchema;
32
+ export declare const DOMAIN_LIST_SCHEMA: AgentSchema;
33
+ export declare const DOMAIN_LIST_TABULAR: TabularSchema<{
34
+ name: string;
35
+ status: string;
36
+ }>;
37
+ export declare const DOMAIN_VERIFY_SCHEMA: AgentSchema;
38
+ export declare const DOMAIN_EXPORT_SCHEMA: AgentSchema;
39
+ export declare const DOMAIN_IMPORT_SCHEMA: AgentSchema;
40
+ export declare const CREATE_DOMAIN_SCHEMA: AgentSchema;
41
+ export declare const CREATE_ACCOUNT_SCHEMA: AgentSchema;
42
+ export declare const CREATE_ORG_SCHEMA: AgentSchema;
43
+ export declare const RESTORE_SCHEMA: AgentSchema;
44
+ export declare const IMPORT_SCHEMA: AgentSchema;
45
+ export declare const SYNC_SCHEMA: AgentSchema;
@@ -0,0 +1 @@
1
+ const e={entity:"connection",defaultFields:["environment","status"],extraFields:{accountId:{path:"accountId"},region:{path:"region"}},aggregates:[]},a={entity:"login",defaultFields:["status","email"],extraFields:{},aggregates:[]},n={entity:"resources",defaultFields:["type","name","filePath"],extraFields:{start:{path:"start"},length:{path:"length"}},aggregates:[{name:"total",compute:"count"}]},o={fields:["type","name","filePath"],project:t=>({type:t.type,name:t.name,filePath:t.filePath})},s={entity:"resource",defaultFields:["type","name","status"],extraFields:{},aggregates:[]},r={entity:"snapshots",defaultFields:["timestamp","path","sizeBytes"],extraFields:{},aggregates:[{name:"total",compute:"count"}]},i={fields:["timestamp","path","sizeBytes"],project:t=>({timestamp:t.timestamp,path:t.path,sizeBytes:t.sizeBytes})},c={entity:"tunnel",defaultFields:["localPort","target","status"],extraFields:{host:{path:"host"},remotePort:{path:"remotePort"}},aggregates:[]},l={entity:"targets",defaultFields:["name","environment","accountName","region"],extraFields:{accountId:{path:"accountId"},active:{path:"active"}},aggregates:[{name:"totalCount",compute:"count"}]},p={fields:["name","environment","accountName","region","active"],project:t=>({name:t.name,environment:t.environment,accountName:t.accountName,region:t.region,active:t.active})},d={entity:"target",defaultFields:["name","status","environment","accountName","region"],extraFields:{accountId:{path:"accountId"}},aggregates:[]},u={entity:"target",defaultFields:["name","environment","accountName","region"],extraFields:{accountId:{path:"accountId"}},aggregates:[]},g={entity:"domains",defaultFields:["name","status"],extraFields:{path:{path:"path"},hasZoneFile:{path:"hasZoneFile"},hasInfrastructure:{path:"hasInfrastructure"}},aggregates:[{name:"total",compute:"count"}]},m={fields:["name","status"],project:t=>({name:t.name,status:t.status})},h={entity:"domain",defaultFields:["name","delegated"],extraFields:{nameservers:{path:"nameservers"}},aggregates:[]},A={entity:"export",defaultFields:["name","recordCount","zoneFilePath"],extraFields:{content:{path:"content",transform:"truncate"}},aggregates:[]},x={entity:"import",defaultFields:["name","hostedZoneId","recordCount","path"],extraFields:{},aggregates:[]},F={entity:"domain",defaultFields:["name","path"],extraFields:{},aggregates:[]},y={entity:"account",defaultFields:["status","region","outputPath"],extraFields:{warning:{path:"warning"}},aggregates:[]},E={entity:"organisation",defaultFields:["name","status","path"],extraFields:{email:{path:"email"},primaryRegion:{path:"primaryRegion"},security:{path:"security"},warning:{path:"warning"}},aggregates:[]},_={entity:"restore",defaultFields:["resourceType","recoveryPointArn","status"],extraFields:{iamRole:{path:"iamRole",transform:"truncate"},restoreJobArn:{path:"restoreJobArn",transform:"truncate"},consoleUrl:{path:"consoleUrl"}},aggregates:[]},C={entity:"import",defaultFields:["action","target","dryRun"],extraFields:{region:{path:"region"},discoveryMode:{path:"discoveryMode"}},aggregates:[{name:"resourceCount",compute:"count"}]},T={entity:"sync",defaultFields:["app","region","resourceCount"],extraFields:{awsAccountId:{path:"awsAccountId"},auditRole:{path:"hasAuditRole"}},aggregates:[{name:"resourceCount",compute:"count"}]};export{s as ADD_SCHEMA,e as CONNECT_SCHEMA,y as CREATE_ACCOUNT_SCHEMA,F as CREATE_DOMAIN_SCHEMA,E as CREATE_ORG_SCHEMA,A as DOMAIN_EXPORT_SCHEMA,x as DOMAIN_IMPORT_SCHEMA,g as DOMAIN_LIST_SCHEMA,m as DOMAIN_LIST_TABULAR,h as DOMAIN_VERIFY_SCHEMA,r as HISTORY_SCHEMA,i as HISTORY_TABULAR,C as IMPORT_SCHEMA,n as LIST_SCHEMA,o as LIST_TABULAR,a as LOGIN_SCHEMA,_ as RESTORE_SCHEMA,T as SYNC_SCHEMA,d as TARGET_GET_SCHEMA,l as TARGET_LIST_SCHEMA,p as TARGET_LIST_TABULAR,u as TARGET_SET_SCHEMA,c as TUNNEL_SCHEMA};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Agent output schemas for secrets commands.
3
+ */
4
+ import type { AgentSchema, TabularSchema } from "./types.js";
5
+ import type { SecretEntry } from "../../../services/index.js";
6
+ export declare const SECRETS_LIST_SCHEMA: AgentSchema;
7
+ export declare const SECRETS_LIST_TABULAR: TabularSchema<SecretEntry>;
8
+ export declare const SECRETS_GET_SCHEMA: AgentSchema;
9
+ export declare const SECRETS_SET_SCHEMA: AgentSchema;
10
+ export declare const SECRETS_DELETE_SCHEMA: AgentSchema;
11
+ export declare const SECRETS_IMPORT_SCHEMA: AgentSchema;
12
+ export declare const SECRETS_EXPORT_SCHEMA: AgentSchema;
13
+ export declare const SECRETS_EXEC_SCHEMA: AgentSchema;
@@ -0,0 +1 @@
1
+ const t={entity:"secrets",defaultFields:["name","lastModified"],extraFields:{version:{path:"version"},arn:{path:"arn"}},aggregates:[{name:"total",compute:"count"}]},a={fields:["name","lastModified"],project:e=>({name:e.name,lastModified:e.lastModified?.toISOString()??""})},s={entity:"secret",defaultFields:["name","value"],extraFields:{},aggregates:[]},r={entity:"secret",defaultFields:["name"],extraFields:{},aggregates:[]},i={entity:"secret",defaultFields:["name"],extraFields:{},aggregates:[]},o={entity:"import",defaultFields:["count"],extraFields:{},aggregates:[]},n={entity:"export",defaultFields:["format","content"],extraFields:{},aggregates:[]},d={entity:"exec",defaultFields:["exitCode"],extraFields:{},aggregates:[]};export{i as SECRETS_DELETE_SCHEMA,d as SECRETS_EXEC_SCHEMA,n as SECRETS_EXPORT_SCHEMA,s as SECRETS_GET_SCHEMA,o as SECRETS_IMPORT_SCHEMA,t as SECRETS_LIST_SCHEMA,a as SECRETS_LIST_TABULAR,r as SECRETS_SET_SCHEMA};
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Shared types for agent output schemas. These describe the internal
3
+ * wiring between operation callbacks and the TOON output layer — they are
4
+ * author-controlled, not user input, so plain interfaces are used instead
5
+ * of Zod.
6
+ *
7
+ * Per-command schemas that consume these types land in Phase 3.
8
+ */
9
+ import type { AgentErrorCode } from "../errorCodes.js";
10
+ /**
11
+ * Describes how a single command's TOON output is assembled.
12
+ *
13
+ * - `entity` is the top-level TOON key (e.g. "apps", "deployment", "secret")
14
+ * - `defaultFields` are rendered without extra flags
15
+ * - `extraFields` require `--fields <name>` to appear
16
+ * - `aggregates` are pre-computed summaries rendered as sibling keys
17
+ */
18
+ export interface AgentSchema {
19
+ readonly entity: string;
20
+ readonly defaultFields: readonly string[];
21
+ readonly extraFields: Readonly<Record<string, FieldSource>>;
22
+ readonly aggregates: readonly Aggregate[];
23
+ }
24
+ /**
25
+ * Describes where a field's value comes from on a source object.
26
+ *
27
+ * - `path` is a dot-path from the source root; defaults to the field name
28
+ * when omitted
29
+ * - `transform` names a named transform applied after path resolution
30
+ */
31
+ export interface FieldSource {
32
+ readonly path?: string;
33
+ readonly transform?: TransformName;
34
+ }
35
+ /**
36
+ * Closed union of named transforms. New transforms are added by widening
37
+ * this union and registering the implementation in the formatter.
38
+ */
39
+ export type TransformName = "relativeTime" | "truncate" | "currency" | "mask";
40
+ /**
41
+ * A pre-computed aggregate attached to a list's output. Rendered as a
42
+ * sibling TOON key.
43
+ */
44
+ export type Aggregate = {
45
+ readonly name: string;
46
+ readonly compute: "count";
47
+ } | {
48
+ readonly name: string;
49
+ readonly compute: "countWhere";
50
+ readonly field: string;
51
+ readonly value: string;
52
+ } | {
53
+ readonly name: string;
54
+ readonly compute: "sum";
55
+ readonly field: string;
56
+ };
57
+ /**
58
+ * A structured error rendered in the TOON error block. `code` is a stable
59
+ * machine-readable string; `userActionRequired` tells the agent whether a
60
+ * human must intervene.
61
+ */
62
+ export interface AgentError {
63
+ readonly message: string;
64
+ readonly code: AgentErrorCode;
65
+ readonly userActionRequired?: boolean;
66
+ readonly details?: Readonly<Record<string, unknown>>;
67
+ }
68
+ /**
69
+ * An action-required TOON block. Emitted when the agent needs to take a
70
+ * specific action (add a flag, perform SSO, pick an option) before the
71
+ * command can proceed.
72
+ */
73
+ export interface ActionRequired {
74
+ readonly action: string;
75
+ readonly message: string;
76
+ readonly userActionRequired: boolean;
77
+ readonly choices?: readonly string[];
78
+ readonly details?: Readonly<Record<string, unknown>>;
79
+ }
80
+ /**
81
+ * A streaming event produced by long-running commands (deploy, destroy,
82
+ * build). Rendered as a TOON block separated from other blocks by the
83
+ * block separator.
84
+ */
85
+ export interface StreamEvent {
86
+ readonly operation: string;
87
+ readonly field: string;
88
+ readonly value: unknown;
89
+ }
90
+ /**
91
+ * A tabular schema for rendering uniform arrays. The `project` function
92
+ * normalises each item to a flat row of primitives — this guarantees
93
+ * `@toon-format/toon`'s tabular encoding path is hit.
94
+ */
95
+ export interface TabularSchema<T> {
96
+ readonly fields: readonly string[];
97
+ readonly project: (item: T) => Readonly<Record<string, string | number | boolean | null>>;
98
+ }
File without changes
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Agent output schemas for user + token commands.
3
+ */
4
+ import type { AgentSchema, TabularSchema } from "./types.js";
5
+ import type { TokenSummary } from "../../../util/api/FjallApiClient.types.js";
6
+ export declare const USER_LIST_SCHEMA: AgentSchema;
7
+ export declare const USER_LIST_TABULAR: TabularSchema<{
8
+ username: string;
9
+ displayName: string;
10
+ userId: string;
11
+ }>;
12
+ export declare const USER_CREATE_SCHEMA: AgentSchema;
13
+ export declare const USER_DESTROY_SCHEMA: AgentSchema;
14
+ export declare const USER_MEMBERSHIP_SCHEMA: AgentSchema;
15
+ export declare const TOKEN_LIST_SCHEMA: AgentSchema;
16
+ export declare const TOKEN_LIST_TABULAR: TabularSchema<TokenSummary & {
17
+ status: string;
18
+ }>;
19
+ export declare const TOKEN_CREATE_SCHEMA: AgentSchema;
20
+ export declare const TOKEN_SHOW_SCHEMA: AgentSchema;
21
+ export declare const TOKEN_REVOKE_SCHEMA: AgentSchema;
@@ -0,0 +1 @@
1
+ const t={entity:"users",defaultFields:["username","displayName"],extraFields:{userId:{path:"userId"}},aggregates:[{name:"total",compute:"count"}]},s={fields:["username","displayName","userId"],project:e=>({username:e.username,displayName:e.displayName,userId:e.userId})},a={entity:"user",defaultFields:["username","userId"],extraFields:{},aggregates:[]},r={entity:"user",defaultFields:["username"],extraFields:{},aggregates:[]},o={entity:"membership",defaultFields:["username","groupname"],extraFields:{},aggregates:[]},n={entity:"tokens",defaultFields:["name","scopes","status","expiresAt"],extraFields:{id:{path:"id"},tokenPrefix:{path:"tokenPrefix"},lastUsedAt:{path:"lastUsedAt"},usageCount:{path:"usageCount"}},aggregates:[{name:"total",compute:"count"}]},d={fields:["name","scopes","status","expiresAt"],project:e=>({name:e.name,scopes:e.scopes.join(","),status:e.status,expiresAt:e.expiresAt??""})},u={entity:"token",defaultFields:["id","name","tokenPrefix"],extraFields:{},aggregates:[]},i={entity:"token",defaultFields:["id","name","tokenPrefix","scopes","status","expiresAt","createdAt","lastUsedAt","usageCount","deniedCount"],extraFields:{sourceTag:{path:"sourceTag"},revokedAt:{path:"revokedAt"},revokedReason:{path:"revokedReason"}},aggregates:[]},p={entity:"token",defaultFields:["id"],extraFields:{},aggregates:[]};export{u as TOKEN_CREATE_SCHEMA,n as TOKEN_LIST_SCHEMA,d as TOKEN_LIST_TABULAR,p as TOKEN_REVOKE_SCHEMA,i as TOKEN_SHOW_SCHEMA,a as USER_CREATE_SCHEMA,r as USER_DESTROY_SCHEMA,t as USER_LIST_SCHEMA,s as USER_LIST_TABULAR,o as USER_MEMBERSHIP_SCHEMA};
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Session hook installer and uninstaller for AI agent tools.
3
+ *
4
+ * Manages hook entries in agent configuration files:
5
+ * - Claude Code: ~/.claude/settings.json (UserProjectConfig hook)
6
+ * - Codex: ~/.codex/hooks.json (pre-session hook)
7
+ *
8
+ * Respects opt-out sentinel (~/.fjall/hook-opt-out) and
9
+ * FJALL_DISABLE_HOOKS=1 environment variable.
10
+ */
11
+ /**
12
+ * Check whether hook installation is disabled via environment variable
13
+ * or persistent opt-out sentinel.
14
+ */
15
+ export declare function isHookInstallDisabled(): boolean;
16
+ /**
17
+ * Check whether the opt-out sentinel exists.
18
+ */
19
+ export declare function hasOptOutSentinel(): boolean;
20
+ /**
21
+ * Write the persistent opt-out sentinel file.
22
+ */
23
+ export declare function writeOptOutSentinel(): void;
24
+ /**
25
+ * Remove the persistent opt-out sentinel file.
26
+ */
27
+ export declare function removeOptOutSentinel(): void;
28
+ interface InstallResult {
29
+ readonly installed: readonly string[];
30
+ readonly skipped: readonly string[];
31
+ readonly errors: readonly string[];
32
+ }
33
+ /**
34
+ * Install session hooks for all detected agent tools.
35
+ *
36
+ * Skips if opt-out sentinel exists or FJALL_DISABLE_HOOKS=1, unless
37
+ * `forceInstall` is true (which also removes the sentinel).
38
+ */
39
+ export declare function installHooks(options?: {
40
+ forceInstall?: boolean;
41
+ }): InstallResult;
42
+ /**
43
+ * Uninstall session hooks from all detected agent tools and write
44
+ * the opt-out sentinel.
45
+ */
46
+ export declare function uninstallHooks(): InstallResult;
47
+ export {};
@@ -0,0 +1,6 @@
1
+ import{existsSync as l,mkdirSync as h,readFileSync as f,unlinkSync as m,writeFileSync as c}from"node:fs";import{join as i}from"node:path";import{homedir as a}from"node:os";import{logger as k}from"../logger/index.js";const p=i(a(),".fjall"),d=i(p,"hook-opt-out"),g="fjall status --agent --budget minimal",u="fjall-agent-session-hook";function y(){return process.env.FJALL_DISABLE_HOOKS==="1"?!0:l(d)}function E(){return l(d)}function C(){h(p,{recursive:!0}),c(d,`opted-out-at: ${new Date().toISOString()}
2
+ `)}function S(){try{m(d)}catch(s){k.debug("SessionHooks","removeOptOutSentinel failed",{error:s instanceof Error?s.message:String(s)})}}function I(s){const e=[],r=[],o=[];if(!s?.forceInstall&&y())return k.debug("SessionHooks","Hook installation disabled (opt-out or env)"),{installed:e,skipped:["all (opt-out active)"],errors:o};s?.forceInstall&&S();const t=x();t.status==="installed"?e.push("Claude Code (~/.claude/settings.json)"):t.status==="skipped"?r.push(`Claude Code: ${t.reason}`):o.push(`Claude Code: ${t.reason}`);const n=O();return n.status==="installed"?e.push("Codex (~/.codex/hooks.json)"):n.status==="skipped"?r.push(`Codex: ${n.reason}`):o.push(`Codex: ${n.reason}`),{installed:e,skipped:r,errors:o}}function N(){const s=[],e=[],r=[],o=j();o.removed?s.push("Claude Code (~/.claude/settings.json)"):e.push(`Claude Code: ${o.reason}`);const t=v();return t.removed?s.push("Codex (~/.codex/hooks.json)"):e.push(`Codex: ${t.reason}`),C(),{installed:s,skipped:e,errors:r}}function x(){const s=i(a(),".claude","settings.json");try{let e={};if(l(s)){const t=f(s,"utf-8"),n=JSON.parse(t);e=typeof n=="object"&&n!==null&&!Array.isArray(n)?n:{}}else h(i(a(),".claude"),{recursive:!0});e.hooks||(e.hooks={}),Array.isArray(e.hooks.UserProjectConfig)||(e.hooks.UserProjectConfig=[]);const r=e.hooks.UserProjectConfig.findIndex(t=>t.marker===u),o={type:"command",command:g,marker:u};return r>=0?e.hooks.UserProjectConfig[r]=o:e.hooks.UserProjectConfig.push(o),c(s,JSON.stringify(e,null,2)+`
3
+ `),{status:"installed"}}catch(e){return{status:"error",reason:e instanceof Error?e.message:String(e)}}}function j(){const s=i(a(),".claude","settings.json");try{if(!l(s))return{removed:!1,reason:"settings file not found"};const e=f(s,"utf-8"),r=JSON.parse(e),o=typeof r=="object"&&r!==null&&!Array.isArray(r)?r:{};if(!o.hooks?.UserProjectConfig)return{removed:!1,reason:"no hooks configured"};const t=o.hooks.UserProjectConfig.length;return o.hooks.UserProjectConfig=o.hooks.UserProjectConfig.filter(n=>n.marker!==u),o.hooks.UserProjectConfig.length===t?{removed:!1,reason:"hook not found"}:(c(s,JSON.stringify(o,null,2)+`
4
+ `),{removed:!0,reason:"removed"})}catch(e){return{removed:!1,reason:e instanceof Error?e.message:String(e)}}}function O(){const s=i(a(),".codex","hooks.json");try{let e={};if(l(s)){const t=f(s,"utf-8"),n=JSON.parse(t);e=typeof n=="object"&&n!==null&&!Array.isArray(n)?n:{}}else h(i(a(),".codex"),{recursive:!0});Array.isArray(e.hooks)||(e.hooks=[]);const r=e.hooks.findIndex(t=>t.marker===u),o={type:"command",event:"pre-session",command:g,marker:u};return r>=0?e.hooks[r]=o:e.hooks.push(o),c(s,JSON.stringify(e,null,2)+`
5
+ `),{status:"installed"}}catch(e){return{status:"error",reason:e instanceof Error?e.message:String(e)}}}function v(){const s=i(a(),".codex","hooks.json");try{if(!l(s))return{removed:!1,reason:"hooks file not found"};const e=f(s,"utf-8"),r=JSON.parse(e),o=typeof r=="object"&&r!==null&&!Array.isArray(r)?r:{};if(!Array.isArray(o.hooks))return{removed:!1,reason:"no hooks configured"};const t=o.hooks.length;return o.hooks=o.hooks.filter(n=>n.marker!==u),o.hooks.length===t?{removed:!1,reason:"hook not found"}:(c(s,JSON.stringify(o,null,2)+`
6
+ `),{removed:!0,reason:"removed"})}catch(e){return{removed:!1,reason:e instanceof Error?e.message:String(e)}}}export{E as hasOptOutSentinel,I as installHooks,y as isHookInstallDisabled,S as removeOptOutSentinel,N as uninstallHooks,C as writeOptOutSentinel};
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Streaming TOON adapter for long-running AXI operations (deploy, destroy,
3
+ * build). Wraps AgentOutputWriter to emit multi-block streaming output
4
+ * with phase progress, resource updates, and a terminal result block.
5
+ *
6
+ * The callback mapping itself lives in agentCallbacks.ts and is re-exported
7
+ * here for convenience — callers that need both streaming and callbacks
8
+ * import from a single module.
9
+ */
10
+ import { AgentOutputWriter, type AgentOutputWriterOptions } from "./agentOutput.js";
11
+ import type { SuggestionContext } from "./suggestions.js";
12
+ export { createAgentOutput, type AgentCallbacksOutput } from "./agentCallbacks.js";
13
+ export interface ResourceStatus {
14
+ readonly name: string;
15
+ readonly type: string;
16
+ readonly status: string;
17
+ }
18
+ /**
19
+ * High-level streaming writer for deploy/destroy/build operations.
20
+ *
21
+ * Each method emits one or more TOON blocks via the underlying
22
+ * AgentOutputWriter, separated by `---` block separators. The sequence
23
+ * is: zero or more phase/resource blocks, then a single terminal result.
24
+ */
25
+ export declare class StreamingToonWriter {
26
+ private readonly writer;
27
+ private readonly operation;
28
+ private blockEmitted;
29
+ constructor(options: AgentOutputWriterOptions & {
30
+ operation: string;
31
+ });
32
+ /**
33
+ * Emit a phase-progress block. Separates from the previous block if one
34
+ * has already been written.
35
+ */
36
+ writePhase(phase: string, step: string, progress: number): void;
37
+ /**
38
+ * Emit a resource-status block listing one or more resources and their
39
+ * current deployment status.
40
+ */
41
+ writeResources(resources: readonly ResourceStatus[]): void;
42
+ /**
43
+ * Emit the terminal result block. This is the final block in the stream
44
+ * and includes contextual help suggestions. No further blocks should be
45
+ * written after this.
46
+ */
47
+ writeTerminalResult(result: Record<string, unknown>, suggestionContext: SuggestionContext): void;
48
+ /** Expose the underlying writer for callers that need direct access. */
49
+ getWriter(): AgentOutputWriter;
50
+ private emitSeparatorIfNeeded;
51
+ }
@@ -0,0 +1 @@
1
+ import{AgentOutputWriter as i}from"./agentOutput.js";import{createAgentOutput as d}from"./agentCallbacks.js";class a{writer;operation;blockEmitted=!1;constructor(e){const{operation:t,...r}=e;this.writer=new i(r),this.operation=t}writePhase(e,t,r){this.emitSeparatorIfNeeded(),this.writer.renderEvent({operation:this.operation,field:"phase",value:{phase:e,step:t,progress:r}}),this.blockEmitted=!0}writeResources(e){this.emitSeparatorIfNeeded(),this.writer.renderEvent({operation:this.operation,field:"resources",value:e}),this.blockEmitted=!0}writeTerminalResult(e,t){this.emitSeparatorIfNeeded(),this.writer.renderResult(e,{suggestionContext:t})}getWriter(){return this.writer}emitSeparatorIfNeeded(){this.blockEmitted&&this.writer.emitEventSeparator()}}export{a as StreamingToonWriter,d as createAgentOutput};
@@ -0,0 +1,2 @@
1
+ import { type SuggestionEntry } from "./types.js";
2
+ export declare const CORE_ENTRIES: readonly SuggestionEntry[];
@@ -0,0 +1 @@
1
+ import{matchOutcome as a}from"./types.js";const t=[{command:"home",match:a.success,templates:["Run `fjall apps describe <name>` to see app details","Run `fjall deploy <name>` to deploy","Run `fjall status <name>` to check a specific app"]},{command:"home",match:a.empty,templates:['Run `fjall apps create --name "<name>"` to create your first app',"Run `fjall connect` to connect an AWS account"]},{command:"apps list",match:a.success,templates:["Run `fjall apps describe <name>` to see app details","Run `fjall deploy <name>` to deploy",'Run `fjall apps create --name "<name>"` to create a new app']},{command:"apps list",match:a.empty,templates:['Run `fjall apps create --name "<name>"` to create your first app',"Run `fjall connect` to connect an AWS account first"]},{command:"apps describe",match:a.success,templates:["Run `fjall deploy <app>` to deploy","Run `fjall secrets list --app <app>` to list secrets","Run `fjall status <app>` to check health"]},{command:"apps create",match:a.success,templates:["Run `fjall deploy <app>` to deploy your new app","Run `fjall secrets set --app <app> --key DB_URL --value <url>` to configure secrets"]},{command:"status",match:a.success,templates:["Run `fjall deploy <app>` to deploy","Run `fjall apps describe <app>` for details"]},{command:"deploy",match:a.success,templates:["Run `fjall status <app>` to check health","Run `fjall apps describe <app>` for full details"]},{command:"deploy",match:a.error,templates:["Run `fjall deploy <app>` to retry","Run `fjall status <app>` to check current state"]},{command:"destroy",match:a.success,templates:["Run `fjall list` to see remaining resources","Run `fjall apps list` to see remaining apps"]},{command:"destroy",match:a.error,templates:["Run `fjall destroy <app> --skip-confirmation` to force destroy","Run `fjall status <app>` to check current state"]},{command:"build",match:a.success,templates:["Run `fjall deploy <app> --skip-build` to deploy the built image","Run `fjall status <app>` to check health"]},{command:"connect",match:a.success,templates:["Run `fjall deploy account` or `fjall deploy organisation` to deploy infrastructure",'Run `fjall apps create --name "<name>"` to create an app']},{command:"login",match:a.success,templates:["Run `fjall apps list` to see your applications","Run `fjall connect` to connect an AWS account"]},{command:"list",match:a.success,templates:["Run `fjall apps describe <name>` for app details","Run `fjall deploy <name>` to deploy"]},{command:"add",match:a.success,templates:["Run `fjall deploy <app>` to deploy the change","Run `fjall apps describe <app>` to see updated resources"]},{command:"tunnel",match:a.success,templates:["Run `fjall tunnel <app> --background` to run in the background"]}];export{t as CORE_ENTRIES};
@@ -0,0 +1,2 @@
1
+ import { type SuggestionEntry } from "./types.js";
2
+ export declare const IDENTITY_ENTRIES: readonly SuggestionEntry[];
@@ -0,0 +1 @@
1
+ import{matchOutcome as e}from"./types.js";const a=[{command:"user list",match:e.success,templates:["Run `fjall user create --email <email> --first-name <name> --last-name <name>` to add a user","Run `fjall user associate <username> <group>` to assign a group"]},{command:"user list",match:e.empty,templates:["Run `fjall user create --email <email> --first-name <name> --last-name <name>` to create a user"]},{command:"user create",match:e.success,templates:["Run `fjall user associate <username> <group>` to assign a group","Run `fjall user list` to see all users"]},{command:"user destroy",match:e.success,templates:["Run `fjall user list` to see remaining users"]},{command:"user associate",match:e.success,templates:["Run `fjall user list` to verify group membership"]},{command:"user dissociate",match:e.success,templates:["Run `fjall user list` to verify group membership"]},{command:"user token create",match:e.success,templates:["Run `fjall user token list` to see all tokens","Save the token now \u2014 it cannot be retrieved again"]},{command:"user token list",match:e.success,templates:["Run `fjall user token create --name <name> --scope <scope> --expires <duration>` to create a token","Run `fjall user token revoke <id>` to revoke a token"]},{command:"user token show",match:e.success,templates:["Run `fjall user token revoke <id>` to revoke this token","Run `fjall user token list` to see all tokens"]},{command:"user token revoke",match:e.success,templates:["Run `fjall user token list` to see remaining tokens"]},{command:"target list",match:e.success,templates:["Run `fjall target set <name>` to change active target","Run `fjall deploy <app>` to deploy to the active target","Run `fjall apps list` to see applications"]},{command:"target list",match:e.empty,templates:["Run `fjall connect` to connect an AWS account","Run `fjall login` to authenticate if not logged in"]},{command:"target get",match:e.success,templates:["Run `fjall target set <name>` to change active target","Run `fjall target list` to see all targets"]},{command:"target get",match:e.empty,templates:["Run `fjall target set <name>` to set a target","Run `fjall target list` to see available targets"]},{command:"target set",match:e.success,templates:["Run `fjall deploy <app>` to deploy to this target","Run `fjall target get` to verify the active target"]},{command:"target set",match:e.errorWithCode("NOT_FOUND"),templates:["Run `fjall target list` to see available targets","Run `fjall connect` to connect an AWS account if none available"]}];export{a as IDENTITY_ENTRIES};
@@ -0,0 +1,3 @@
1
+ import { type SuggestionEntry } from "./types.js";
2
+ export declare const SUGGESTION_TABLE: readonly SuggestionEntry[];
3
+ export type { SuggestionContext, SuggestionEntry } from "./types.js";
@@ -0,0 +1 @@
1
+ import{matchOutcome as o}from"./types.js";import{CORE_ENTRIES as m}from"./coreEntries.js";import{SECRETS_ENTRIES as r}from"./secretsEntries.js";import{IDENTITY_ENTRIES as E}from"./identityEntries.js";import{INFRA_ENTRIES as t}from"./infraEntries.js";import{OBSERVABILITY_ENTRIES as T}from"./observabilityEntries.js";const I={command:"*",match:o.error,templates:["Run `fjall <command> --help` for usage information"]},i=[...m,...r,...E,...t,...T,I];export{i as SUGGESTION_TABLE};
@@ -0,0 +1,2 @@
1
+ import { type SuggestionEntry } from "./types.js";
2
+ export declare const INFRA_ENTRIES: readonly SuggestionEntry[];
@@ -0,0 +1 @@
1
+ import{matchOutcome as e}from"./types.js";const a=[{command:"domain list",match:e.success,templates:["Run `fjall domain verify <name>` to check DNS delegation","Run `fjall domain export <name>` to export zone file","Run `fjall create domain --name <name>` to create a new domain"]},{command:"domain list",match:e.empty,templates:['Run `fjall create domain --name "<name>"` to create a domain',"Run `fjall domain import <name>` to import from Route53"]},{command:"domain verify",match:e.success,templates:["Run `fjall domain export <name>` to export zone file","Run `fjall deploy <name>` to deploy domain infrastructure"]},{command:"domain verify",match:e.error,templates:["Run `fjall domain verify <name>` to retry","Run `fjall domain list` to see existing domains"]},{command:"domain export",match:e.success,templates:["Run `fjall domain verify <name>` to check delegation","Run `fjall domain import <name>` to re-import from Route53"]},{command:"domain import",match:e.success,templates:["Run `fjall domain verify <name>` to check delegation","Run `fjall domain export <name>` to see the zone file","Run `fjall deploy <name>` to deploy domain infrastructure"]},{command:"domain import",match:e.error,templates:["Run `fjall domain import --hosted-zone-id <id>` to import by zone ID","Run `fjall domain list` to see existing domains"]},{command:"create domain",match:e.success,templates:["Run `fjall domain verify <name>` to check DNS delegation","Run `fjall domain export <name>` to export zone records","Run `fjall deploy <name>` to deploy the domain"]},{command:"create domain",match:e.error,templates:["Run `fjall domain list` to see existing domains",'Run `fjall create domain --name "<name>"` to retry with a different name']},{command:"create account",match:e.success,templates:["Run `fjall connect --environment production` to link your AWS account","Run `fjall deploy account` to deploy account infrastructure (after connecting)"]},{command:"create account",match:e.error,templates:["Run `fjall create account --primary-region <region>` to retry","Run `fjall create account --help` for usage information"]},{command:"create org",match:e.success,templates:["Run `fjall connect --environment production` to link your AWS account","Run `fjall deploy organisation` to deploy all infrastructure (after connecting)"]},{command:"create org",match:e.error,templates:['Run `fjall create org --name "<name>" --email "<email>"` to retry',"Run `fjall create org --help` for all options"]},{command:"restore",match:e.successDryRun,templates:["Run `fjall restore <resourceType> --recovery-point <recoveryPointArn> --yes` to initiate restore","Run `fjall apps list` to see existing applications"]},{command:"restore",match:e.success,templates:["Open the AWS Console URL above to monitor restore progress","Run `fjall import` to import the restored resource after completion"]},{command:"restore",match:e.errorWithCode("NOT_FOUND"),templates:["Verify the recovery point ARN is correct and exists in the current region","Run `fjall restore <resourceType> --recovery-point <arn>` to retry"]},{command:"restore",match:e.errorWithCode("FORBIDDEN"),templates:["Ensure the IAM role has backup:StartRestoreJob and iam:PassRole permissions","Run `fjall restore` interactively to configure with guided setup"]},{command:"import",match:e.successDryRun,templates:["Run `fjall import --app <app> --resource-id <resourceId> --yes` to import a specific resource","Run `fjall import --app <app> --yes` to import all discovered resources"]},{command:"import",match:e.success,templates:["Run `fjall deploy <app>` to deploy with the imported resource","Run `fjall apps describe <app>` to see updated resources"]},{command:"import",match:e.errorWithCode("NOT_FOUND"),templates:['Run `fjall apps create --name "<app>"` to create the application',"Run `fjall apps list` to see existing applications"]},{command:"import",match:e.errorWithCode("VALIDATION_ERROR"),templates:["Run `fjall import --app <app> --resource-id <resourceId>` to import a specific resource","Run `fjall import --app <app> --resource-id <resourceId> --yes` to import immediately"]},{command:"sync",match:e.success,templates:["Run `fjall status <app>` to check health","Run `fjall deploy <app>` to deploy latest changes"]},{command:"sync",match:e.error,templates:["Run `fjall sync <app>` to retry","Run `fjall status <app>` to check current state"]},{command:"aws exec",match:e.success,templates:["Run `fjall aws exec -- <command>` to run another AWS CLI command","Run `fjall status` to check application health"]},{command:"aws exec",match:e.error,templates:["Run `fjall connect` to configure an AWS account","Run `fjall aws exec --help` for usage information"]}];export{a as INFRA_ENTRIES};
@@ -0,0 +1,2 @@
1
+ import { type SuggestionEntry } from "./types.js";
2
+ export declare const OBSERVABILITY_ENTRIES: readonly SuggestionEntry[];
@@ -0,0 +1 @@
1
+ import{matchOutcome as e}from"./types.js";const t=[{command:"costs show",match:e.success,templates:["Run `fjall costs --mode forecast` to see forecasted spend","Run `fjall costs --mode breakdown` to see service-level breakdown"]},{command:"costs show",match:e.error,templates:["Run `fjall costs --app <app>` to filter by application","Run `fjall costs --help` for usage information"]},{command:"metrics show",match:e.success,templates:["Run `fjall metrics --mode latency` to see latency percentiles","Run `fjall metrics --mode errors` to see error trends"]},{command:"metrics show",match:e.error,templates:["Run `fjall metrics --app <app>` to filter by application","Run `fjall metrics --help` for usage information"]},{command:"compliance fix",match:e.success,templates:["Run `fjall compliance --issue-id <id>` to get details for a specific issue","Run `fjall deploy <app>` to apply remediation changes"]},{command:"compliance fix",match:e.error,templates:["Run `fjall compliance --domain <domain>` to specify compliance domain","Run `fjall compliance --help` for usage information"]},{command:"deploy diff",match:e.success,templates:["Run `fjall deploy logs --deployment-id <id>` to analyse deployment logs","Run `fjall status <app>` to check current deployment health"]},{command:"deploy diff",match:e.error,templates:["Run `fjall list deployments` to see recent deployment IDs","Run `fjall deploy diff --help` for usage information"]},{command:"deploy logs",match:e.success,templates:["Run `fjall deploy diff <idA> <idB>` to compare two deployments","Run `fjall status <app>` to check current deployment health"]},{command:"deploy logs",match:e.error,templates:["Run `fjall deploy logs --deployment-id <id>` with a valid deployment ID","Run `fjall list deployments` to find a deployment ID"]}];export{t as OBSERVABILITY_ENTRIES};
@@ -0,0 +1,2 @@
1
+ import { type SuggestionEntry } from "./types.js";
2
+ export declare const SECRETS_ENTRIES: readonly SuggestionEntry[];
@@ -0,0 +1 @@
1
+ import{matchOutcome as e}from"./types.js";const t=[{command:"secrets list",match:e.success,templates:['Run `fjall secrets set --app <app> --key "<key>" --value "<value>"` to set a secret',"Run `fjall deploy <app>` to apply changes"]},{command:"secrets list",match:e.empty,templates:['Run `fjall secrets set --app <app> --key "<key>" --value "<value>"` to add a secret',"Run `fjall secrets import --app <app> <file>` to bulk import"]},{command:"secrets get",match:e.success,templates:['Run `fjall secrets set --app <app> --key "<key>" --value "<value>"` to update',"Run `fjall secrets list --app <app>` to see all secrets"]},{command:"secrets set",match:e.success,templates:["Run `fjall deploy <app>` to apply the change","Run `fjall secrets list --app <app>` to verify"]},{command:"secrets delete",match:e.success,templates:["Run `fjall deploy <app>` to apply the change","Run `fjall secrets list --app <app>` to verify"]},{command:"secrets import",match:e.success,templates:["Run `fjall deploy <app>` to apply changes","Run `fjall secrets list --app <app>` to verify"]},{command:"secrets export",match:e.success,templates:["Run `fjall secrets list --app <app>` to see all secret names","Run `fjall secrets import --app <app> <file>` to restore"]},{command:"secrets exec",match:e.success,templates:["Run `fjall secrets list --app <app>` to see available secrets"]}];export{t as SECRETS_ENTRIES};
@@ -0,0 +1,17 @@
1
+ export interface SuggestionContext {
2
+ readonly command: string;
3
+ readonly outcome?: "success" | "error" | "empty";
4
+ readonly [key: string]: string | undefined;
5
+ }
6
+ export interface SuggestionEntry {
7
+ readonly command: string;
8
+ readonly match: (ctx: SuggestionContext) => boolean;
9
+ readonly templates: readonly string[];
10
+ }
11
+ export declare const matchOutcome: {
12
+ readonly success: (ctx: SuggestionContext) => boolean;
13
+ readonly error: (ctx: SuggestionContext) => boolean;
14
+ readonly empty: (ctx: SuggestionContext) => boolean;
15
+ readonly successDryRun: (ctx: SuggestionContext) => boolean;
16
+ readonly errorWithCode: (code: string) => (ctx: SuggestionContext) => boolean;
17
+ };
@@ -0,0 +1 @@
1
+ const r={success:e=>e.outcome==="success",error:e=>e.outcome==="error",empty:e=>e.outcome==="empty",successDryRun:e=>e.outcome==="success"&&e.dryRun==="true",errorWithCode:e=>o=>o.outcome==="error"&&o.errorCode===e};export{r as matchOutcome};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Contextual suggestion resolver for AXI agent output. Generates `help[]`
3
+ * lines that appear after every command output, guiding agents to their
4
+ * next action.
5
+ *
6
+ * Entry tables are grouped by domain in `./suggestionEntries/`.
7
+ */
8
+ import type { SuggestionContext } from "./suggestionEntries/types.js";
9
+ export type { SuggestionContext } from "./suggestionEntries/types.js";
10
+ /**
11
+ * Shell-escape a value for embedding in suggestion text.
12
+ *
13
+ * Suggestions are intended to be safe for an agent to copy-paste into a
14
+ * POSIX shell. Any value containing shell-active characters is wrapped in
15
+ * single quotes with embedded single quotes safely terminated.
16
+ */
17
+ declare function shellEscape(value: string): string;
18
+ /**
19
+ * Resolves contextual suggestions for agent output. Matches the current
20
+ * command and context against the suggestion table, interpolates
21
+ * placeholders, and preserves flags from the original invocation.
22
+ */
23
+ export declare class SuggestionResolver {
24
+ private readonly command;
25
+ private readonly flags;
26
+ constructor(command: string, flags: Readonly<Record<string, string>>);
27
+ resolve(context: SuggestionContext): string[];
28
+ private interpolate;
29
+ }
30
+ export { shellEscape as _shellEscapeForTesting };
@@ -0,0 +1 @@
1
+ import{SUGGESTION_TABLE as i}from"./suggestionEntries/index.js";const l=["app","environment","region","profile","target"];function a(s){return/[^\w@%+=:,./-]/.test(s)?`'${s.replace(/'/g,"'\\''")}'`:s}class f{command;flags;constructor(t,n){this.command=t,this.flags=n}resolve(t){const n=i.find(e=>(e.command===this.command||e.command==="*")&&e.match(t));return n===void 0?[]:n.templates.map(e=>this.interpolate(e,t))}interpolate(t,n){let e=t.replace(/<(\w+)>/g,(o,r)=>n[r]??`<${r}>`);for(const o of l){const r=this.flags[o];r!==void 0&&!e.includes(`--${o}`)&&(e+=` --${o} ${a(r)}`)}return e}}export{f as SuggestionResolver,a as _shellEscapeForTesting};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Maps each CLI command surface to the scoped-token scope(s) required to
3
+ * execute it. Used by the agent output layer to emit a structured
4
+ * `scope_required` error when a token lacks permissions, rather than a
5
+ * generic 403.
6
+ *
7
+ * `TokenScope` / `SCOPE_VALUES` are imported from `@fjall/util` so the
8
+ * webapp's `/api/tokens` schemas and the CLI's command-scope lookup
9
+ * share a single source of truth (closes 2026-04-28 review H5).
10
+ */
11
+ import { type TokenScope } from "@fjall/util";
12
+ export { type TokenScope };
13
+ /**
14
+ * Command surface → minimum required scope(s). The first scope in the
15
+ * array is the primary; additional entries are alternatives that also
16
+ * grant access (e.g. `secrets:write` implies `secrets:read` at the
17
+ * middleware level, but we list the exact scope the command needs).
18
+ */
19
+ export declare const COMMAND_SCOPES: Readonly<Record<string, readonly TokenScope[]>>;
20
+ /**
21
+ * Look up the required scope(s) for a command. Returns `undefined` for
22
+ * commands not in the map (e.g. future commands not yet wired).
23
+ */
24
+ export declare function getRequiredScopes(command: string): readonly TokenScope[] | undefined;