wingfoil 0.2.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 (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +334 -0
  3. package/dist/cli/error.d.ts +11 -0
  4. package/dist/cli/error.d.ts.map +1 -0
  5. package/dist/cli/error.js +27 -0
  6. package/dist/cli/error.js.map +1 -0
  7. package/dist/cli/exit.d.ts +19 -0
  8. package/dist/cli/exit.d.ts.map +1 -0
  9. package/dist/cli/exit.js +14 -0
  10. package/dist/cli/exit.js.map +1 -0
  11. package/dist/cli/index.d.ts +28 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +36 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/init-command.d.ts +34 -0
  16. package/dist/cli/init-command.d.ts.map +1 -0
  17. package/dist/cli/init-command.js +100 -0
  18. package/dist/cli/init-command.js.map +1 -0
  19. package/dist/cli/mcp-command.d.ts +24 -0
  20. package/dist/cli/mcp-command.d.ts.map +1 -0
  21. package/dist/cli/mcp-command.js +42 -0
  22. package/dist/cli/mcp-command.js.map +1 -0
  23. package/dist/cli/output.d.ts +13 -0
  24. package/dist/cli/output.d.ts.map +1 -0
  25. package/dist/cli/output.js +28 -0
  26. package/dist/cli/output.js.map +1 -0
  27. package/dist/cli/program.d.ts +12 -0
  28. package/dist/cli/program.d.ts.map +1 -0
  29. package/dist/cli/program.js +279 -0
  30. package/dist/cli/program.js.map +1 -0
  31. package/dist/cli/registrar.d.ts +69 -0
  32. package/dist/cli/registrar.d.ts.map +1 -0
  33. package/dist/cli/registrar.js +82 -0
  34. package/dist/cli/registrar.js.map +1 -0
  35. package/dist/cli.d.ts +3 -0
  36. package/dist/cli.d.ts.map +1 -0
  37. package/dist/cli.js +45 -0
  38. package/dist/cli.js.map +1 -0
  39. package/dist/core/approval-authority.d.ts +83 -0
  40. package/dist/core/approval-authority.d.ts.map +1 -0
  41. package/dist/core/approval-authority.js +112 -0
  42. package/dist/core/approval-authority.js.map +1 -0
  43. package/dist/core/builtin-asset.d.ts +71 -0
  44. package/dist/core/builtin-asset.d.ts.map +1 -0
  45. package/dist/core/builtin-asset.js +137 -0
  46. package/dist/core/builtin-asset.js.map +1 -0
  47. package/dist/core/builtin-integrity.d.ts +32 -0
  48. package/dist/core/builtin-integrity.d.ts.map +1 -0
  49. package/dist/core/builtin-integrity.js +148 -0
  50. package/dist/core/builtin-integrity.js.map +1 -0
  51. package/dist/core/confinement.d.ts +57 -0
  52. package/dist/core/confinement.d.ts.map +1 -0
  53. package/dist/core/confinement.js +108 -0
  54. package/dist/core/confinement.js.map +1 -0
  55. package/dist/core/context.d.ts +187 -0
  56. package/dist/core/context.d.ts.map +1 -0
  57. package/dist/core/context.js +192 -0
  58. package/dist/core/context.js.map +1 -0
  59. package/dist/core/directive-assign.d.ts +131 -0
  60. package/dist/core/directive-assign.d.ts.map +1 -0
  61. package/dist/core/directive-assign.js +352 -0
  62. package/dist/core/directive-assign.js.map +1 -0
  63. package/dist/core/directives-list.d.ts +80 -0
  64. package/dist/core/directives-list.d.ts.map +1 -0
  65. package/dist/core/directives-list.js +148 -0
  66. package/dist/core/directives-list.js.map +1 -0
  67. package/dist/core/exit-code.d.ts +85 -0
  68. package/dist/core/exit-code.d.ts.map +1 -0
  69. package/dist/core/exit-code.js +163 -0
  70. package/dist/core/exit-code.js.map +1 -0
  71. package/dist/core/git-identity.d.ts +32 -0
  72. package/dist/core/git-identity.d.ts.map +1 -0
  73. package/dist/core/git-identity.js +72 -0
  74. package/dist/core/git-identity.js.map +1 -0
  75. package/dist/core/index.d.ts +388 -0
  76. package/dist/core/index.d.ts.map +1 -0
  77. package/dist/core/index.js +1331 -0
  78. package/dist/core/index.js.map +1 -0
  79. package/dist/core/init.d.ts +78 -0
  80. package/dist/core/init.d.ts.map +1 -0
  81. package/dist/core/init.js +167 -0
  82. package/dist/core/init.js.map +1 -0
  83. package/dist/core/loaders.d.ts +174 -0
  84. package/dist/core/loaders.d.ts.map +1 -0
  85. package/dist/core/loaders.js +364 -0
  86. package/dist/core/loaders.js.map +1 -0
  87. package/dist/core/memory-add-type.d.ts +43 -0
  88. package/dist/core/memory-add-type.d.ts.map +1 -0
  89. package/dist/core/memory-add-type.js +151 -0
  90. package/dist/core/memory-add-type.js.map +1 -0
  91. package/dist/core/memory-transition.d.ts +111 -0
  92. package/dist/core/memory-transition.d.ts.map +1 -0
  93. package/dist/core/memory-transition.js +269 -0
  94. package/dist/core/memory-transition.js.map +1 -0
  95. package/dist/core/registry.d.ts +189 -0
  96. package/dist/core/registry.d.ts.map +1 -0
  97. package/dist/core/registry.js +66 -0
  98. package/dist/core/registry.js.map +1 -0
  99. package/dist/core/relevance.d.ts +86 -0
  100. package/dist/core/relevance.d.ts.map +1 -0
  101. package/dist/core/relevance.js +258 -0
  102. package/dist/core/relevance.js.map +1 -0
  103. package/dist/core/require-reason.d.ts +27 -0
  104. package/dist/core/require-reason.d.ts.map +1 -0
  105. package/dist/core/require-reason.js +95 -0
  106. package/dist/core/require-reason.js.map +1 -0
  107. package/dist/core/types.d.ts +45 -0
  108. package/dist/core/types.d.ts.map +1 -0
  109. package/dist/core/types.js +22 -0
  110. package/dist/core/types.js.map +1 -0
  111. package/dist/core/usage-error.d.ts +20 -0
  112. package/dist/core/usage-error.d.ts.map +1 -0
  113. package/dist/core/usage-error.js +29 -0
  114. package/dist/core/usage-error.js.map +1 -0
  115. package/dist/core/write-guard.d.ts +99 -0
  116. package/dist/core/write-guard.d.ts.map +1 -0
  117. package/dist/core/write-guard.js +247 -0
  118. package/dist/core/write-guard.js.map +1 -0
  119. package/dist/directives/create.d.ts +47 -0
  120. package/dist/directives/create.d.ts.map +1 -0
  121. package/dist/directives/create.js +82 -0
  122. package/dist/directives/create.js.map +1 -0
  123. package/dist/directives/index.d.ts +20 -0
  124. package/dist/directives/index.d.ts.map +1 -0
  125. package/dist/directives/index.js +32 -0
  126. package/dist/directives/index.js.map +1 -0
  127. package/dist/directives/roles-edit.d.ts +53 -0
  128. package/dist/directives/roles-edit.d.ts.map +1 -0
  129. package/dist/directives/roles-edit.js +286 -0
  130. package/dist/directives/roles-edit.js.map +1 -0
  131. package/dist/directives/schema.d.ts +65 -0
  132. package/dist/directives/schema.d.ts.map +1 -0
  133. package/dist/directives/schema.js +68 -0
  134. package/dist/directives/schema.js.map +1 -0
  135. package/dist/dna/edit.d.ts +61 -0
  136. package/dist/dna/edit.d.ts.map +1 -0
  137. package/dist/dna/edit.js +429 -0
  138. package/dist/dna/edit.js.map +1 -0
  139. package/dist/dna/index.d.ts +24 -0
  140. package/dist/dna/index.d.ts.map +1 -0
  141. package/dist/dna/index.js +59 -0
  142. package/dist/dna/index.js.map +1 -0
  143. package/dist/dna/mutate.d.ts +74 -0
  144. package/dist/dna/mutate.d.ts.map +1 -0
  145. package/dist/dna/mutate.js +318 -0
  146. package/dist/dna/mutate.js.map +1 -0
  147. package/dist/dna/path.d.ts +175 -0
  148. package/dist/dna/path.d.ts.map +1 -0
  149. package/dist/dna/path.js +289 -0
  150. package/dist/dna/path.js.map +1 -0
  151. package/dist/dna/roles.d.ts +57 -0
  152. package/dist/dna/roles.d.ts.map +1 -0
  153. package/dist/dna/roles.js +50 -0
  154. package/dist/dna/roles.js.map +1 -0
  155. package/dist/dna/schema.d.ts +172 -0
  156. package/dist/dna/schema.d.ts.map +1 -0
  157. package/dist/dna/schema.js +182 -0
  158. package/dist/dna/schema.js.map +1 -0
  159. package/dist/dna/set.d.ts +145 -0
  160. package/dist/dna/set.d.ts.map +1 -0
  161. package/dist/dna/set.js +428 -0
  162. package/dist/dna/set.js.map +1 -0
  163. package/dist/mcp/dna-resource.d.ts +16 -0
  164. package/dist/mcp/dna-resource.d.ts.map +1 -0
  165. package/dist/mcp/dna-resource.js +56 -0
  166. package/dist/mcp/dna-resource.js.map +1 -0
  167. package/dist/mcp/index.d.ts +49 -0
  168. package/dist/mcp/index.d.ts.map +1 -0
  169. package/dist/mcp/index.js +60 -0
  170. package/dist/mcp/index.js.map +1 -0
  171. package/dist/mcp/memory-resource.d.ts +17 -0
  172. package/dist/mcp/memory-resource.d.ts.map +1 -0
  173. package/dist/mcp/memory-resource.js +133 -0
  174. package/dist/mcp/memory-resource.js.map +1 -0
  175. package/dist/mcp/prompt.d.ts +48 -0
  176. package/dist/mcp/prompt.d.ts.map +1 -0
  177. package/dist/mcp/prompt.js +176 -0
  178. package/dist/mcp/prompt.js.map +1 -0
  179. package/dist/mcp/read-only.d.ts +42 -0
  180. package/dist/mcp/read-only.d.ts.map +1 -0
  181. package/dist/mcp/read-only.js +93 -0
  182. package/dist/mcp/read-only.js.map +1 -0
  183. package/dist/mcp/registrar.d.ts +54 -0
  184. package/dist/mcp/registrar.d.ts.map +1 -0
  185. package/dist/mcp/registrar.js +72 -0
  186. package/dist/mcp/registrar.js.map +1 -0
  187. package/dist/mcp/server.d.ts +58 -0
  188. package/dist/mcp/server.d.ts.map +1 -0
  189. package/dist/mcp/server.js +64 -0
  190. package/dist/mcp/server.js.map +1 -0
  191. package/dist/mcp/workflow-resource.d.ts +17 -0
  192. package/dist/mcp/workflow-resource.d.ts.map +1 -0
  193. package/dist/mcp/workflow-resource.js +63 -0
  194. package/dist/mcp/workflow-resource.js.map +1 -0
  195. package/dist/memory/add.d.ts +50 -0
  196. package/dist/memory/add.d.ts.map +1 -0
  197. package/dist/memory/add.js +131 -0
  198. package/dist/memory/add.js.map +1 -0
  199. package/dist/memory/audit.d.ts +177 -0
  200. package/dist/memory/audit.d.ts.map +1 -0
  201. package/dist/memory/audit.js +287 -0
  202. package/dist/memory/audit.js.map +1 -0
  203. package/dist/memory/commit-message.d.ts +146 -0
  204. package/dist/memory/commit-message.d.ts.map +1 -0
  205. package/dist/memory/commit-message.js +203 -0
  206. package/dist/memory/commit-message.js.map +1 -0
  207. package/dist/memory/entry.d.ts +56 -0
  208. package/dist/memory/entry.d.ts.map +1 -0
  209. package/dist/memory/entry.js +28 -0
  210. package/dist/memory/entry.js.map +1 -0
  211. package/dist/memory/frontmatter-edit.d.ts +68 -0
  212. package/dist/memory/frontmatter-edit.d.ts.map +1 -0
  213. package/dist/memory/frontmatter-edit.js +333 -0
  214. package/dist/memory/frontmatter-edit.js.map +1 -0
  215. package/dist/memory/git-log.d.ts +32 -0
  216. package/dist/memory/git-log.d.ts.map +1 -0
  217. package/dist/memory/git-log.js +100 -0
  218. package/dist/memory/git-log.js.map +1 -0
  219. package/dist/memory/history.d.ts +142 -0
  220. package/dist/memory/history.d.ts.map +1 -0
  221. package/dist/memory/history.js +250 -0
  222. package/dist/memory/history.js.map +1 -0
  223. package/dist/memory/index.d.ts +58 -0
  224. package/dist/memory/index.d.ts.map +1 -0
  225. package/dist/memory/index.js +107 -0
  226. package/dist/memory/index.js.map +1 -0
  227. package/dist/memory/query.d.ts +150 -0
  228. package/dist/memory/query.d.ts.map +1 -0
  229. package/dist/memory/query.js +307 -0
  230. package/dist/memory/query.js.map +1 -0
  231. package/dist/memory/reject.d.ts +11 -0
  232. package/dist/memory/reject.d.ts.map +1 -0
  233. package/dist/memory/reject.js +32 -0
  234. package/dist/memory/reject.js.map +1 -0
  235. package/dist/memory/schema.d.ts +104 -0
  236. package/dist/memory/schema.d.ts.map +1 -0
  237. package/dist/memory/schema.js +161 -0
  238. package/dist/memory/schema.js.map +1 -0
  239. package/dist/memory/state-machine.d.ts +166 -0
  240. package/dist/memory/state-machine.d.ts.map +1 -0
  241. package/dist/memory/state-machine.js +431 -0
  242. package/dist/memory/state-machine.js.map +1 -0
  243. package/dist/memory/submit.d.ts +11 -0
  244. package/dist/memory/submit.d.ts.map +1 -0
  245. package/dist/memory/submit.js +44 -0
  246. package/dist/memory/submit.js.map +1 -0
  247. package/dist/storage/builtin-directives.d.ts +54 -0
  248. package/dist/storage/builtin-directives.d.ts.map +1 -0
  249. package/dist/storage/builtin-directives.js +152 -0
  250. package/dist/storage/builtin-directives.js.map +1 -0
  251. package/dist/storage/commit.d.ts +92 -0
  252. package/dist/storage/commit.d.ts.map +1 -0
  253. package/dist/storage/commit.js +201 -0
  254. package/dist/storage/commit.js.map +1 -0
  255. package/dist/storage/confinement.d.ts +93 -0
  256. package/dist/storage/confinement.d.ts.map +1 -0
  257. package/dist/storage/confinement.js +164 -0
  258. package/dist/storage/confinement.js.map +1 -0
  259. package/dist/storage/document.d.ts +27 -0
  260. package/dist/storage/document.d.ts.map +1 -0
  261. package/dist/storage/document.js +52 -0
  262. package/dist/storage/document.js.map +1 -0
  263. package/dist/storage/errors.d.ts +36 -0
  264. package/dist/storage/errors.d.ts.map +1 -0
  265. package/dist/storage/errors.js +46 -0
  266. package/dist/storage/errors.js.map +1 -0
  267. package/dist/storage/frontmatter.d.ts +27 -0
  268. package/dist/storage/frontmatter.d.ts.map +1 -0
  269. package/dist/storage/frontmatter.js +37 -0
  270. package/dist/storage/frontmatter.js.map +1 -0
  271. package/dist/storage/git-root.d.ts +17 -0
  272. package/dist/storage/git-root.d.ts.map +1 -0
  273. package/dist/storage/git-root.js +49 -0
  274. package/dist/storage/git-root.js.map +1 -0
  275. package/dist/storage/index.d.ts +29 -0
  276. package/dist/storage/index.d.ts.map +1 -0
  277. package/dist/storage/index.js +66 -0
  278. package/dist/storage/index.js.map +1 -0
  279. package/dist/storage/init-state.d.ts +9 -0
  280. package/dist/storage/init-state.d.ts.map +1 -0
  281. package/dist/storage/init-state.js +24 -0
  282. package/dist/storage/init-state.js.map +1 -0
  283. package/dist/storage/layout.d.ts +51 -0
  284. package/dist/storage/layout.d.ts.map +1 -0
  285. package/dist/storage/layout.js +88 -0
  286. package/dist/storage/layout.js.map +1 -0
  287. package/dist/storage/memory-path.d.ts +72 -0
  288. package/dist/storage/memory-path.d.ts.map +1 -0
  289. package/dist/storage/memory-path.js +127 -0
  290. package/dist/storage/memory-path.js.map +1 -0
  291. package/dist/storage/snapshot.d.ts +16 -0
  292. package/dist/storage/snapshot.d.ts.map +1 -0
  293. package/dist/storage/snapshot.js +72 -0
  294. package/dist/storage/snapshot.js.map +1 -0
  295. package/dist/storage/templates.d.ts +88 -0
  296. package/dist/storage/templates.d.ts.map +1 -0
  297. package/dist/storage/templates.js +422 -0
  298. package/dist/storage/templates.js.map +1 -0
  299. package/dist/validation/error-mapper.d.ts +16 -0
  300. package/dist/validation/error-mapper.d.ts.map +1 -0
  301. package/dist/validation/error-mapper.js +18 -0
  302. package/dist/validation/error-mapper.js.map +1 -0
  303. package/dist/validation/errors.d.ts +69 -0
  304. package/dist/validation/errors.d.ts.map +1 -0
  305. package/dist/validation/errors.js +69 -0
  306. package/dist/validation/errors.js.map +1 -0
  307. package/dist/validation/id.d.ts +16 -0
  308. package/dist/validation/id.d.ts.map +1 -0
  309. package/dist/validation/id.js +177 -0
  310. package/dist/validation/id.js.map +1 -0
  311. package/dist/validation/index.d.ts +18 -0
  312. package/dist/validation/index.d.ts.map +1 -0
  313. package/dist/validation/index.js +37 -0
  314. package/dist/validation/index.js.map +1 -0
  315. package/dist/validation/secret-scan.d.ts +129 -0
  316. package/dist/validation/secret-scan.d.ts.map +1 -0
  317. package/dist/validation/secret-scan.js +367 -0
  318. package/dist/validation/secret-scan.js.map +1 -0
  319. package/dist/validation/two-pass.d.ts +24 -0
  320. package/dist/validation/two-pass.d.ts.map +1 -0
  321. package/dist/validation/two-pass.js +24 -0
  322. package/dist/validation/two-pass.js.map +1 -0
  323. package/dist/validation/warning.d.ts +31 -0
  324. package/dist/validation/warning.d.ts.map +1 -0
  325. package/dist/validation/warning.js +81 -0
  326. package/dist/validation/warning.js.map +1 -0
  327. package/dist/validation/yaml.d.ts +9 -0
  328. package/dist/validation/yaml.d.ts.map +1 -0
  329. package/dist/validation/yaml.js +30 -0
  330. package/dist/validation/yaml.js.map +1 -0
  331. package/dist/workflow/index.d.ts +10 -0
  332. package/dist/workflow/index.d.ts.map +1 -0
  333. package/dist/workflow/index.js +16 -0
  334. package/dist/workflow/index.js.map +1 -0
  335. package/dist/workflow/schema.d.ts +89 -0
  336. package/dist/workflow/schema.d.ts.map +1 -0
  337. package/dist/workflow/schema.js +73 -0
  338. package/dist/workflow/schema.js.map +1 -0
  339. package/package.json +78 -0
@@ -0,0 +1,85 @@
1
+ import type { CoreError, CoreResult } from './types';
2
+ /** The three-code exit contract (spec-005 §1). Canonical home for the type; `src/cli` re-exports it. */
3
+ export type ExitCode = 0 | 1 | 2;
4
+ /** The exit code a {@link CoreError} maps to (spec-005 §1). */
5
+ export declare function exitCodeForError(error: CoreError): ExitCode;
6
+ /** The exit code for a whole {@link CoreResult}: `0` on success, else the error's mapped code. */
7
+ export declare function exitCodeForResult(result: CoreResult<unknown>): ExitCode;
8
+ /**
9
+ * How a CLI argument parser terminated, reduced to the two fields the exit-code decision needs — the
10
+ * parser's own outcome identifier and the exit code it *suggests*. Commander's `CommanderError` is
11
+ * structurally this (`.code` / `.exitCode`), so `src/cli` hands one straight in; the interface is
12
+ * declared structurally rather than importing `commander` so `core` keeps no dependency on the CLI's
13
+ * parser (REQ-SYS-05 — the same mapping has to be applicable from the MCP surface).
14
+ */
15
+ export interface ParseOutcome {
16
+ /** The parser's outcome identifier, e.g. Commander's `'commander.unknownCommand'`. */
17
+ readonly code: string;
18
+ /** The exit code the parser suggests for this outcome — advisory, not the contract's answer. */
19
+ readonly exitCode: number;
20
+ }
21
+ /**
22
+ * How a parse outcome resolves against spec-005 §1: the exit code, and whether the **surface** still
23
+ * owes the `error:` line the section requires of every non-zero exit.
24
+ */
25
+ export interface ParseTermination {
26
+ /** The contract's answer, overriding the parser's suggestion. */
27
+ readonly exitCode: ExitCode;
28
+ /**
29
+ * `true` when the parser terminated non-zero having written no error message of its own, so the
30
+ * surface must emit one to satisfy spec-005 §1's "a non-zero exit code is **always** accompanied by
31
+ * an error message on stderr". `false` when the parser already wrote its own `error: …` line (every
32
+ * code in {@link USAGE_ERROR_PARSE_CODES}) or when the exit is `0`. The message *text* is the
33
+ * surface's to compose — only the obligation is decided here.
34
+ */
35
+ readonly needsErrorLine: boolean;
36
+ }
37
+ /**
38
+ * Resolve a CLI argument parser's own termination against spec-005 §1 (REQ-INT-04 — task-101 /
39
+ * `bug-098`, extended by task-103 / `bug-103`). The parser reaches this both when it *refuses* an
40
+ * invocation and when it *completes* one without running a command (`--help`, `--version`), so the
41
+ * rule has three branches:
42
+ *
43
+ * - an outcome in {@link USAGE_ERROR_PARSE_CODES} is a malformed invocation → exit **2**, overriding
44
+ * the parser's suggestion (Commander suggests `1` for every one of them). It wrote its own message,
45
+ * so the surface owes nothing;
46
+ * - {@link INCOMPLETE_INVOCATION_PARSE_CODE} with a **non-zero** suggestion is an invocation the
47
+ * parser found incomplete — a noun with no verb, `wingfoil` with no arguments, `help <unknown>`.
48
+ * §1 lists a "missing required argument" among the malformed invocations, so it is exit **2** as
49
+ * well; unlike the codes above it printed only help text, so `needsErrorLine` is `true`;
50
+ * - anything else is a *successful* termination or an outcome this contract does not classify, and
51
+ * keeps the parser's own suggested code, narrowed to the three-code contract: `0` stays `0` (so
52
+ * `--help`, `--version` and an explicit `help` still exit `0`, as spec-005 §1 requires), any
53
+ * non-zero suggestion becomes `1`. That default is deliberately the status quo rather than `2`: an
54
+ * unrecognised outcome must not silently acquire a usage-error meaning it was never shown to have —
55
+ * and, for the same reason, must not acquire a manufactured error message either. The only code
56
+ * that reaches it non-zero today is `commander.executeSubCommandAsync`, and WingFoil registers no
57
+ * executable subcommand.
58
+ */
59
+ export declare function classifyParseOutcome(outcome: ParseOutcome): ParseTermination;
60
+ /**
61
+ * The exit code alone for a parse outcome — {@link classifyParseOutcome}'s `exitCode`, kept as a named
62
+ * function for callers (and tests) that care only about the code. It *delegates* rather than repeating
63
+ * the rule, so the code and the error-line obligation can never be decided from two different tables.
64
+ */
65
+ export declare function exitCodeForParseOutcome(outcome: ParseOutcome): ExitCode;
66
+ /** A thrown error's surface rendering: the human `reason` (spec-005 §3) and the process exit code. */
67
+ export interface ThrownOutcome {
68
+ readonly reason: string;
69
+ readonly exitCode: ExitCode;
70
+ }
71
+ /**
72
+ * Select the exit code and reason for a core operation that *threw* (the throw-path companion to
73
+ * {@link exitCodeForResult}, which handles the return path). Keeping this in `src/core` is what lets a
74
+ * thrown usage/integrity error stay "core owns exit-code selection" (spec-008-cli-grammar
75
+ * Consequences), so both surfaces apply it identically rather than each re-deciding:
76
+ *
77
+ * - a {@link UsageError} (a malformed argument, e.g. `dna set`'s invalid key path) → exit **2**, with
78
+ * its already-clean `.message` as the reason (task-025-implement-dna-set);
79
+ * - a {@link ValidationError} carries its own `exitCode` (integrity/cross-field → 2, field-level → 1,
80
+ * per spec-009-validation-strategy §3), with the reason joined from its issue messages (never the
81
+ * composite `${code} ${path} (${file}): …` form its `.message` builds);
82
+ * - anything else is a logic error → exit **1**, with the error's message (or its string form).
83
+ */
84
+ export declare function exitCodeForThrow(error: unknown): ThrownOutcome;
85
+ //# sourceMappingURL=exit-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-code.d.ts","sourceRoot":"","sources":["../../src/core/exit-code.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,SAAS,EAAiB,UAAU,EAAE,MAAM,SAAS,CAAC;AAGpE,wGAAwG;AACxG,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAgBjC,+DAA+D;AAC/D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAE3D;AAED,kGAAkG;AAClG,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAEvE;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAoDD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,gBAAgB,CAM5E;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,GAAG,QAAQ,CAEvE;AAED,sGAAsG;AACtG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,CAS9D"}
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exitCodeForError = exitCodeForError;
4
+ exports.exitCodeForResult = exitCodeForResult;
5
+ exports.classifyParseOutcome = classifyParseOutcome;
6
+ exports.exitCodeForParseOutcome = exitCodeForParseOutcome;
7
+ exports.exitCodeForThrow = exitCodeForThrow;
8
+ /**
9
+ * Exit-code selection (spec-005-cli-command-contract §1, REQ-INT-04 — task-012-cli-exit-code-contract).
10
+ *
11
+ * The `0`/`1`/`2` contract has a single source of truth here in `core`, not duplicated across the CLI
12
+ * and MCP surfaces: both derive severity from the same `CoreError` model (REQ-SYS-05), so this module
13
+ * owns the mapping from a domain outcome to its exit code and each surface only *applies* it
14
+ * (`src/cli/exit.ts`'s `exitWith`).
15
+ *
16
+ * Parse-level usage errors (`2`) are *detected* by a surface before any core call — an unknown
17
+ * command, an unknown option, a missing required argument — but since
18
+ * task-101-route-commander-parse-errors-through-the-exit-code-contract (`bug-098`) their **code** is
19
+ * decided here too, by {@link classifyParseOutcome}. Before that task the CLI's argument parser
20
+ * terminated through its own `process.exit(1)` and those classes never reached this module at all, so
21
+ * an unknown command reported `1` — the code spec-005 §1 reserves for a *well-formed* invocation that
22
+ * failed. Keeping the parse mapping here is what that task's AC6 protects: one place decides an exit
23
+ * code, not one place per error origin.
24
+ *
25
+ * task-103-a-missing-verb-exits-2-with-an-error-line (`bug-103`) added the second half of the same
26
+ * §1 rule to that one place: the section also states that a non-zero exit is **always** accompanied by
27
+ * an error message on stderr, and one parse outcome — an invocation the parser found incomplete —
28
+ * carries no message of its own. So {@link classifyParseOutcome} answers two questions rather than
29
+ * one, from a single rule: which exit code, and whether the surface still owes the `error:` line.
30
+ */
31
+ const validation_1 = require("../validation");
32
+ const usage_error_1 = require("./usage-error");
33
+ /**
34
+ * Every `CoreError.code` is a **logic** error — a well-formed invocation that failed on business logic
35
+ * — so all map to exit `1`. Declared as an exhaustive `Record<CoreErrorCode, ExitCode>` on purpose: a
36
+ * future `CoreErrorCode` will not compile until its exit code is chosen here, rather than silently
37
+ * defaulting.
38
+ */
39
+ const EXIT_CODE_BY_ERROR = {
40
+ NOT_FOUND: 1,
41
+ INVALID_TRANSITION: 1,
42
+ VALIDATION: 1,
43
+ CONFLICT: 1,
44
+ IO: 1,
45
+ };
46
+ /** The exit code a {@link CoreError} maps to (spec-005 §1). */
47
+ function exitCodeForError(error) {
48
+ return EXIT_CODE_BY_ERROR[error.code];
49
+ }
50
+ /** The exit code for a whole {@link CoreResult}: `0` on success, else the error's mapped code. */
51
+ function exitCodeForResult(result) {
52
+ return result.ok ? 0 : exitCodeForError(result.error);
53
+ }
54
+ /**
55
+ * The argument-parser outcomes that are **usage errors** under spec-005 §1 ("the invocation itself is
56
+ * malformed: unknown command/pillar/verb, unknown flag, missing required argument, invalid flag
57
+ * value") and therefore exit `2`, whatever the parser itself suggests.
58
+ *
59
+ * The identifiers are Commander's, confirmed against the **installed** version (`commander@15.0.0`,
60
+ * `node_modules/commander/lib/command.js` — `unknownOption()`, `excessArguments()`,
61
+ * `unknownCommand()`, `missingArgument()`, `optionMissingArgument()`, `missingMandatoryOptionValue()`,
62
+ * `conflictingOption()`, each calling `this.error(message, { code })`, plus `commander.error` as
63
+ * `error()`'s own default and `commander.invalidArgument` from `InvalidArgumentError`). They are
64
+ * version surface: a Commander upgrade that renames or adds one must revisit this set, which is why
65
+ * the codes are listed explicitly here rather than inferred from the suggested exit code.
66
+ *
67
+ * One of them, `commander.excessArguments`, is mapped but **unreachable in production today**: every
68
+ * derived command registers a variadic `[positionals...]` (`src/cli/program.ts`), so Commander never
69
+ * has an excess argument to refuse — `wingfoil dna show project extra` is accepted and an extra
70
+ * positional on a write verb is refused by WingFoil's own check instead, already at exit `2`. It is
71
+ * listed because the mapping must stay correct for the code rather than for today's registration
72
+ * shape; a reader finding it never fires is not looking at a mistake.
73
+ */
74
+ const USAGE_ERROR_PARSE_CODES = new Set([
75
+ 'commander.unknownCommand',
76
+ 'commander.unknownOption',
77
+ 'commander.excessArguments',
78
+ 'commander.missingArgument',
79
+ 'commander.optionMissingArgument',
80
+ 'commander.missingMandatoryOptionValue',
81
+ 'commander.conflictingOption',
82
+ 'commander.invalidArgument',
83
+ 'commander.error',
84
+ ]);
85
+ /**
86
+ * The parser outcome that reports an **incomplete invocation**: the parser had nothing to run and
87
+ * printed the command's help to stderr instead of an error (task-103, `bug-103`).
88
+ *
89
+ * This is *not* an error code — it is the same identifier Commander uses when the user asks for help
90
+ * with the built-in `help` command, which must keep exiting `0`. The two are separated by the
91
+ * **suggested exit code** carried alongside it: `Command#help(contextOptions)`
92
+ * (`node_modules/commander/lib/command.js`, commander@15.0.0) suggests `1` exactly when it was called
93
+ * as `help({ error: true })`, which is what its three "there is nothing here to run" call sites do —
94
+ * the missing-subcommand branch, the nothing-hooked-up branch, and `_dispatchSubcommand`'s
95
+ * `if (!subCommand)`, where `wingfoil help <unknown>` lands. A user-requested help suggests `0`.
96
+ *
97
+ * That one bit is the whole discriminator, and it is read from the parser's own two fields rather
98
+ * than by re-reading argv — so this module still decides alone, and the surface never re-parses an
99
+ * invocation the parser has already parsed.
100
+ */
101
+ const INCOMPLETE_INVOCATION_PARSE_CODE = 'commander.help';
102
+ /**
103
+ * Resolve a CLI argument parser's own termination against spec-005 §1 (REQ-INT-04 — task-101 /
104
+ * `bug-098`, extended by task-103 / `bug-103`). The parser reaches this both when it *refuses* an
105
+ * invocation and when it *completes* one without running a command (`--help`, `--version`), so the
106
+ * rule has three branches:
107
+ *
108
+ * - an outcome in {@link USAGE_ERROR_PARSE_CODES} is a malformed invocation → exit **2**, overriding
109
+ * the parser's suggestion (Commander suggests `1` for every one of them). It wrote its own message,
110
+ * so the surface owes nothing;
111
+ * - {@link INCOMPLETE_INVOCATION_PARSE_CODE} with a **non-zero** suggestion is an invocation the
112
+ * parser found incomplete — a noun with no verb, `wingfoil` with no arguments, `help <unknown>`.
113
+ * §1 lists a "missing required argument" among the malformed invocations, so it is exit **2** as
114
+ * well; unlike the codes above it printed only help text, so `needsErrorLine` is `true`;
115
+ * - anything else is a *successful* termination or an outcome this contract does not classify, and
116
+ * keeps the parser's own suggested code, narrowed to the three-code contract: `0` stays `0` (so
117
+ * `--help`, `--version` and an explicit `help` still exit `0`, as spec-005 §1 requires), any
118
+ * non-zero suggestion becomes `1`. That default is deliberately the status quo rather than `2`: an
119
+ * unrecognised outcome must not silently acquire a usage-error meaning it was never shown to have —
120
+ * and, for the same reason, must not acquire a manufactured error message either. The only code
121
+ * that reaches it non-zero today is `commander.executeSubCommandAsync`, and WingFoil registers no
122
+ * executable subcommand.
123
+ */
124
+ function classifyParseOutcome(outcome) {
125
+ if (USAGE_ERROR_PARSE_CODES.has(outcome.code))
126
+ return { exitCode: 2, needsErrorLine: false };
127
+ if (outcome.code === INCOMPLETE_INVOCATION_PARSE_CODE && outcome.exitCode !== 0) {
128
+ return { exitCode: 2, needsErrorLine: true };
129
+ }
130
+ return { exitCode: outcome.exitCode === 0 ? 0 : 1, needsErrorLine: false };
131
+ }
132
+ /**
133
+ * The exit code alone for a parse outcome — {@link classifyParseOutcome}'s `exitCode`, kept as a named
134
+ * function for callers (and tests) that care only about the code. It *delegates* rather than repeating
135
+ * the rule, so the code and the error-line obligation can never be decided from two different tables.
136
+ */
137
+ function exitCodeForParseOutcome(outcome) {
138
+ return classifyParseOutcome(outcome).exitCode;
139
+ }
140
+ /**
141
+ * Select the exit code and reason for a core operation that *threw* (the throw-path companion to
142
+ * {@link exitCodeForResult}, which handles the return path). Keeping this in `src/core` is what lets a
143
+ * thrown usage/integrity error stay "core owns exit-code selection" (spec-008-cli-grammar
144
+ * Consequences), so both surfaces apply it identically rather than each re-deciding:
145
+ *
146
+ * - a {@link UsageError} (a malformed argument, e.g. `dna set`'s invalid key path) → exit **2**, with
147
+ * its already-clean `.message` as the reason (task-025-implement-dna-set);
148
+ * - a {@link ValidationError} carries its own `exitCode` (integrity/cross-field → 2, field-level → 1,
149
+ * per spec-009-validation-strategy §3), with the reason joined from its issue messages (never the
150
+ * composite `${code} ${path} (${file}): …` form its `.message` builds);
151
+ * - anything else is a logic error → exit **1**, with the error's message (or its string form).
152
+ */
153
+ function exitCodeForThrow(error) {
154
+ if (error instanceof usage_error_1.UsageError) {
155
+ return { reason: error.message, exitCode: 2 };
156
+ }
157
+ if (error instanceof validation_1.ValidationError) {
158
+ const reason = error.issues.length > 0 ? error.issues.map((issue) => issue.message).join('; ') : error.message;
159
+ return { reason, exitCode: error.exitCode === 2 ? 2 : 1 };
160
+ }
161
+ return { reason: error instanceof Error ? error.message : String(error), exitCode: 1 };
162
+ }
163
+ //# sourceMappingURL=exit-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-code.js","sourceRoot":"","sources":["../../src/core/exit-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { type CoreResult } from './types';
2
+ /**
3
+ * The single source of truth for "a configured/attributable identity": non-empty `name` AND
4
+ * non-empty `email`. Both the write-time precondition below (`requireGitIdentity`, REQ-SEC-01,
5
+ * task-014-git-identity-required) and the read-time historical audit (`isValidAttribution` in
6
+ * `src/memory/audit.ts`, REQ-SEC-02, task-015-complete-audit-trail) build on this exact predicate for
7
+ * their shared base check — see `isValidAttribution`'s doc-comment for the audit-only augmentations
8
+ * it layers on top for historical commits (a concern this write-time check has no need for, since it
9
+ * only ever looks at the *current* live git config). Pure predicate — no git/filesystem access.
10
+ */
11
+ export declare function isConfiguredIdentity(name: string, email: string): boolean;
12
+ /** The `user.name`/`user.email` pair `readGitIdentity` resolves at a given root — either may be `''` (unset). */
13
+ export interface GitIdentity {
14
+ readonly name: string;
15
+ readonly email: string;
16
+ }
17
+ /**
18
+ * Read the live `user.name`/`user.email` git identity configured at `root`, with no "is it valid"
19
+ * judgement of its own (that is {@link isConfiguredIdentity}'s job) — the single read primitive both
20
+ * {@link requireGitIdentity} (REQ-SEC-01) and `src/core/approval-authority.ts`'s
21
+ * `requireApprovalAuthority` (REQ-SEC-03, task-040-role-based-approval-authority) build on, so the two
22
+ * checks never each re-implement their own `git config` read.
23
+ */
24
+ export declare function readGitIdentity(root: string): GitIdentity;
25
+ /**
26
+ * Verify a git identity is configured at `root` before a state mutation. Returns a
27
+ * `CoreResult.error` (code `VALIDATION` — a failed precondition, mapped to exit `1` by
28
+ * `exitCodeForError`) carrying the exact REQ-SEC-01 message when either `user.name` or `user.email`
29
+ * is unset; otherwise `ok`.
30
+ */
31
+ export declare function requireGitIdentity(root: string): CoreResult<void>;
32
+ //# sourceMappingURL=git-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-identity.d.ts","sourceRoot":"","sources":["../../src/core/git-identity.ts"],"names":[],"mappings":"AAaA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAqB3D;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzE;AAED,iHAAiH;AACjH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAMjE"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isConfiguredIdentity = isConfiguredIdentity;
4
+ exports.readGitIdentity = readGitIdentity;
5
+ exports.requireGitIdentity = requireGitIdentity;
6
+ /**
7
+ * Git-identity pre-flight check (REQ-SEC-01, adr-006-git-identity-role-based-authz —
8
+ * task-014-git-identity-required).
9
+ *
10
+ * Git identity is WingFoil's sole attribution mechanism: the commit author *is* the "who" of the
11
+ * audit trail (adr-001 / adr-006 — no separate auth/session/IAM layer). So every state-mutating
12
+ * operation must refuse to run when `user.name`/`user.email` are unset, rather than produce a commit
13
+ * with an unattributable author. This check lives in `src/core` so the CLI and every MCP Tool enforce
14
+ * it identically by construction (REQ-SYS-05) — a mutation calls it first and returns its
15
+ * `CoreResult.error` unchanged, so the surface renders the exact message and writes nothing.
16
+ */
17
+ const node_child_process_1 = require("node:child_process");
18
+ const types_1 = require("./types");
19
+ /** Exact refusal message required by REQ-SEC-01's fit criterion — do not reword. */
20
+ const IDENTITY_ERROR = 'git identity not configured (user.name/user.email)';
21
+ /**
22
+ * The effective value of a git config `key` at `root`, or `''` when it is unset — git exits non-zero
23
+ * for an unset key, which we treat as absent (the same "empty means unconfigured" contract the check
24
+ * relies on). Resolves local → global → system exactly as any git command would.
25
+ */
26
+ function readGitConfig(root, key) {
27
+ try {
28
+ // `env: process.env` is passed explicitly (identical to the default in production): it makes git's
29
+ // config resolution follow the current environment by design, so a caller/test can scope it via
30
+ // `GIT_CONFIG_GLOBAL`/`GIT_CONFIG_SYSTEM`/`GIT_CONFIG_NOSYSTEM` deterministically.
31
+ return (0, node_child_process_1.execFileSync)('git', ['-C', root, 'config', key], { encoding: 'utf-8', env: process.env }).trim();
32
+ }
33
+ catch {
34
+ return '';
35
+ }
36
+ }
37
+ /**
38
+ * The single source of truth for "a configured/attributable identity": non-empty `name` AND
39
+ * non-empty `email`. Both the write-time precondition below (`requireGitIdentity`, REQ-SEC-01,
40
+ * task-014-git-identity-required) and the read-time historical audit (`isValidAttribution` in
41
+ * `src/memory/audit.ts`, REQ-SEC-02, task-015-complete-audit-trail) build on this exact predicate for
42
+ * their shared base check — see `isValidAttribution`'s doc-comment for the audit-only augmentations
43
+ * it layers on top for historical commits (a concern this write-time check has no need for, since it
44
+ * only ever looks at the *current* live git config). Pure predicate — no git/filesystem access.
45
+ */
46
+ function isConfiguredIdentity(name, email) {
47
+ return name.length > 0 && email.length > 0;
48
+ }
49
+ /**
50
+ * Read the live `user.name`/`user.email` git identity configured at `root`, with no "is it valid"
51
+ * judgement of its own (that is {@link isConfiguredIdentity}'s job) — the single read primitive both
52
+ * {@link requireGitIdentity} (REQ-SEC-01) and `src/core/approval-authority.ts`'s
53
+ * `requireApprovalAuthority` (REQ-SEC-03, task-040-role-based-approval-authority) build on, so the two
54
+ * checks never each re-implement their own `git config` read.
55
+ */
56
+ function readGitIdentity(root) {
57
+ return { name: readGitConfig(root, 'user.name'), email: readGitConfig(root, 'user.email') };
58
+ }
59
+ /**
60
+ * Verify a git identity is configured at `root` before a state mutation. Returns a
61
+ * `CoreResult.error` (code `VALIDATION` — a failed precondition, mapped to exit `1` by
62
+ * `exitCodeForError`) carrying the exact REQ-SEC-01 message when either `user.name` or `user.email`
63
+ * is unset; otherwise `ok`.
64
+ */
65
+ function requireGitIdentity(root) {
66
+ const { name, email } = readGitIdentity(root);
67
+ if (!isConfiguredIdentity(name, email)) {
68
+ return (0, types_1.coreErr)({ code: 'VALIDATION', message: IDENTITY_ERROR });
69
+ }
70
+ return (0, types_1.coreOk)(undefined);
71
+ }
72
+ //# sourceMappingURL=git-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-identity.js","sourceRoot":"","sources":["../../src/core/git-identity.ts"],"names":[],"mappings":";;AA2CA,oDAEC;AAeD,0CAEC;AAQD,gDAMC;AA5ED;;;;;;;;;;GAUG;AACH,2DAAkD;AAElD,mCAA2D;AAE3D,oFAAoF;AACpF,MAAM,cAAc,GAAG,oDAAoD,CAAC;AAE5E;;;;GAIG;AACH,SAAS,aAAa,CAAC,IAAY,EAAE,GAAW;IAC9C,IAAI,CAAC;QACH,mGAAmG;QACnG,gGAAgG;QAChG,mFAAmF;QACnF,OAAO,IAAA,iCAAY,EAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1G,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,oBAAoB,CAAC,IAAY,EAAE,KAAa;IAC9D,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AAC7C,CAAC;AAQD;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,IAAY;IAC7C,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO,IAAA,eAAO,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,IAAA,cAAM,EAAO,SAAS,CAAC,CAAC;AACjC,CAAC"}