@latysh-development/monolith 0.0.0-stage → 0.1.0-alpha.0

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 (291) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -2
  3. package/dist/brief/cli.d.ts +30 -0
  4. package/dist/brief/cli.d.ts.map +1 -0
  5. package/dist/brief/cli.js +85 -0
  6. package/dist/brief/collect.d.ts +17 -0
  7. package/dist/brief/collect.d.ts.map +1 -0
  8. package/dist/brief/collect.js +302 -0
  9. package/dist/brief/config.d.ts +40 -0
  10. package/dist/brief/config.d.ts.map +1 -0
  11. package/dist/brief/config.js +85 -0
  12. package/dist/brief/constants.d.ts +10 -0
  13. package/dist/brief/constants.d.ts.map +1 -0
  14. package/dist/brief/constants.js +9 -0
  15. package/dist/brief/docs.d.ts +53 -0
  16. package/dist/brief/docs.d.ts.map +1 -0
  17. package/dist/brief/docs.js +229 -0
  18. package/dist/brief/freshness.d.ts +104 -0
  19. package/dist/brief/freshness.d.ts.map +1 -0
  20. package/dist/brief/freshness.js +263 -0
  21. package/dist/brief/git-signals.d.ts +17 -0
  22. package/dist/brief/git-signals.d.ts.map +1 -0
  23. package/dist/brief/git-signals.js +101 -0
  24. package/dist/brief/index.d.ts +11 -0
  25. package/dist/brief/index.d.ts.map +1 -0
  26. package/dist/brief/index.js +5 -0
  27. package/dist/brief/reconcile.d.ts +75 -0
  28. package/dist/brief/reconcile.d.ts.map +1 -0
  29. package/dist/brief/reconcile.js +259 -0
  30. package/dist/brief/render.d.ts +60 -0
  31. package/dist/brief/render.d.ts.map +1 -0
  32. package/dist/brief/render.js +407 -0
  33. package/dist/brief/sanitize.d.ts +38 -0
  34. package/dist/brief/sanitize.d.ts.map +1 -0
  35. package/dist/brief/sanitize.js +48 -0
  36. package/dist/brief/selectors.d.ts +36 -0
  37. package/dist/brief/selectors.d.ts.map +1 -0
  38. package/dist/brief/selectors.js +75 -0
  39. package/dist/brief/story.d.ts +18 -0
  40. package/dist/brief/story.d.ts.map +1 -0
  41. package/dist/brief/story.js +59 -0
  42. package/dist/brief/types.d.ts +110 -0
  43. package/dist/brief/types.d.ts.map +1 -0
  44. package/dist/brief/types.js +11 -0
  45. package/dist/cli/index.d.ts +3 -0
  46. package/dist/cli/index.d.ts.map +1 -0
  47. package/dist/cli/index.js +166 -0
  48. package/dist/cli/init-args.d.ts +16 -0
  49. package/dist/cli/init-args.d.ts.map +1 -0
  50. package/dist/cli/init-args.js +24 -0
  51. package/dist/cli/ui-args.d.ts +23 -0
  52. package/dist/cli/ui-args.d.ts.map +1 -0
  53. package/dist/cli/ui-args.js +66 -0
  54. package/dist/cli/ui.d.ts +40 -0
  55. package/dist/cli/ui.d.ts.map +1 -0
  56. package/dist/cli/ui.js +180 -0
  57. package/dist/coordinatorium/checkpoint.d.ts +44 -0
  58. package/dist/coordinatorium/checkpoint.d.ts.map +1 -0
  59. package/dist/coordinatorium/checkpoint.js +124 -0
  60. package/dist/coordinatorium/cli.d.ts +39 -0
  61. package/dist/coordinatorium/cli.d.ts.map +1 -0
  62. package/dist/coordinatorium/cli.js +203 -0
  63. package/dist/coordinatorium/errors.d.ts +112 -0
  64. package/dist/coordinatorium/errors.d.ts.map +1 -0
  65. package/dist/coordinatorium/errors.js +145 -0
  66. package/dist/coordinatorium/index.d.ts +11 -0
  67. package/dist/coordinatorium/index.d.ts.map +1 -0
  68. package/dist/coordinatorium/index.js +5 -0
  69. package/dist/coordinatorium/lock.d.ts +187 -0
  70. package/dist/coordinatorium/lock.d.ts.map +1 -0
  71. package/dist/coordinatorium/lock.js +659 -0
  72. package/dist/coordinatorium/mission.d.ts +32 -0
  73. package/dist/coordinatorium/mission.d.ts.map +1 -0
  74. package/dist/coordinatorium/mission.js +87 -0
  75. package/dist/coordinatorium/state-keeper.d.ts +115 -0
  76. package/dist/coordinatorium/state-keeper.d.ts.map +1 -0
  77. package/dist/coordinatorium/state-keeper.js +396 -0
  78. package/dist/coordinatorium/types.d.ts +69 -0
  79. package/dist/coordinatorium/types.d.ts.map +1 -0
  80. package/dist/coordinatorium/types.js +27 -0
  81. package/dist/durable/assess.d.ts +105 -0
  82. package/dist/durable/assess.d.ts.map +1 -0
  83. package/dist/durable/assess.js +239 -0
  84. package/dist/durable/canonical.d.ts +25 -0
  85. package/dist/durable/canonical.d.ts.map +1 -0
  86. package/dist/durable/canonical.js +78 -0
  87. package/dist/durable/cli.d.ts +37 -0
  88. package/dist/durable/cli.d.ts.map +1 -0
  89. package/dist/durable/cli.js +141 -0
  90. package/dist/durable/errors.d.ts +188 -0
  91. package/dist/durable/errors.d.ts.map +1 -0
  92. package/dist/durable/errors.js +317 -0
  93. package/dist/durable/fs-store.d.ts +233 -0
  94. package/dist/durable/fs-store.d.ts.map +1 -0
  95. package/dist/durable/fs-store.js +1393 -0
  96. package/dist/durable/index.d.ts +20 -0
  97. package/dist/durable/index.d.ts.map +1 -0
  98. package/dist/durable/index.js +13 -0
  99. package/dist/durable/log.d.ts +33 -0
  100. package/dist/durable/log.d.ts.map +1 -0
  101. package/dist/durable/log.js +157 -0
  102. package/dist/durable/memory-store.d.ts +51 -0
  103. package/dist/durable/memory-store.d.ts.map +1 -0
  104. package/dist/durable/memory-store.js +302 -0
  105. package/dist/durable/projection.d.ts +35 -0
  106. package/dist/durable/projection.d.ts.map +1 -0
  107. package/dist/durable/projection.js +328 -0
  108. package/dist/durable/prune-check.d.ts +17 -0
  109. package/dist/durable/prune-check.d.ts.map +1 -0
  110. package/dist/durable/prune-check.js +45 -0
  111. package/dist/durable/register.d.ts +100 -0
  112. package/dist/durable/register.d.ts.map +1 -0
  113. package/dist/durable/register.js +532 -0
  114. package/dist/durable/retention.d.ts +49 -0
  115. package/dist/durable/retention.d.ts.map +1 -0
  116. package/dist/durable/retention.js +59 -0
  117. package/dist/durable/runtime.d.ts +497 -0
  118. package/dist/durable/runtime.d.ts.map +1 -0
  119. package/dist/durable/runtime.js +1271 -0
  120. package/dist/durable/seams.d.ts +40 -0
  121. package/dist/durable/seams.d.ts.map +1 -0
  122. package/dist/durable/seams.js +21 -0
  123. package/dist/durable/testing.d.ts +11 -0
  124. package/dist/durable/testing.d.ts.map +1 -0
  125. package/dist/durable/testing.js +25 -0
  126. package/dist/durable/types.d.ts +442 -0
  127. package/dist/durable/types.d.ts.map +1 -0
  128. package/dist/durable/types.js +75 -0
  129. package/dist/graph/builder.d.ts +11 -0
  130. package/dist/graph/builder.d.ts.map +1 -0
  131. package/dist/graph/builder.js +153 -0
  132. package/dist/graph/identity.d.ts +37 -0
  133. package/dist/graph/identity.d.ts.map +1 -0
  134. package/dist/graph/identity.js +46 -0
  135. package/dist/graph/index.d.ts +7 -0
  136. package/dist/graph/index.d.ts.map +1 -0
  137. package/dist/graph/index.js +3 -0
  138. package/dist/graph/resolver.d.ts +41 -0
  139. package/dist/graph/resolver.d.ts.map +1 -0
  140. package/dist/graph/resolver.js +36 -0
  141. package/dist/graph/types.d.ts +42 -0
  142. package/dist/graph/types.d.ts.map +1 -0
  143. package/dist/graph/types.js +1 -0
  144. package/dist/http/index.d.ts +5 -0
  145. package/dist/http/index.d.ts.map +1 -0
  146. package/dist/http/index.js +2 -0
  147. package/dist/http/server.d.ts +76 -0
  148. package/dist/http/server.d.ts.map +1 -0
  149. package/dist/http/server.js +195 -0
  150. package/dist/http/ui-assets.d.ts +22 -0
  151. package/dist/http/ui-assets.d.ts.map +1 -0
  152. package/dist/http/ui-assets.js +100 -0
  153. package/dist/index.d.ts +31 -0
  154. package/dist/index.d.ts.map +1 -0
  155. package/dist/index.js +26 -0
  156. package/dist/init/index.d.ts +12 -0
  157. package/dist/init/index.d.ts.map +1 -0
  158. package/dist/init/index.js +90 -0
  159. package/dist/init/prompts.d.ts +3 -0
  160. package/dist/init/prompts.d.ts.map +1 -0
  161. package/dist/init/prompts.js +47 -0
  162. package/dist/init/scaffold.d.ts +25 -0
  163. package/dist/init/scaffold.d.ts.map +1 -0
  164. package/dist/init/scaffold.js +204 -0
  165. package/dist/init/types.d.ts +14 -0
  166. package/dist/init/types.d.ts.map +1 -0
  167. package/dist/init/types.js +1 -0
  168. package/dist/readmodel/dashboard.d.ts +40 -0
  169. package/dist/readmodel/dashboard.d.ts.map +1 -0
  170. package/dist/readmodel/dashboard.js +236 -0
  171. package/dist/readmodel/index.d.ts +3 -0
  172. package/dist/readmodel/index.d.ts.map +1 -0
  173. package/dist/readmodel/index.js +1 -0
  174. package/dist/readmodel/types.d.ts +104 -0
  175. package/dist/readmodel/types.d.ts.map +1 -0
  176. package/dist/readmodel/types.js +15 -0
  177. package/dist/root/index.d.ts +179 -0
  178. package/dist/root/index.d.ts.map +1 -0
  179. package/dist/root/index.js +418 -0
  180. package/dist/root/safe-write.d.ts +268 -0
  181. package/dist/root/safe-write.d.ts.map +1 -0
  182. package/dist/root/safe-write.js +966 -0
  183. package/dist/root/write-artifacts.d.ts +20 -0
  184. package/dist/root/write-artifacts.d.ts.map +1 -0
  185. package/dist/root/write-artifacts.js +42 -0
  186. package/dist/scriptorium/compile.d.ts +4 -0
  187. package/dist/scriptorium/compile.d.ts.map +1 -0
  188. package/dist/scriptorium/compile.js +185 -0
  189. package/dist/scriptorium/frontmatter.d.ts +13 -0
  190. package/dist/scriptorium/frontmatter.d.ts.map +1 -0
  191. package/dist/scriptorium/frontmatter.js +90 -0
  192. package/dist/scriptorium/index.d.ts +3 -0
  193. package/dist/scriptorium/index.d.ts.map +1 -0
  194. package/dist/scriptorium/index.js +1 -0
  195. package/dist/scriptorium/markdown.d.ts +31 -0
  196. package/dist/scriptorium/markdown.d.ts.map +1 -0
  197. package/dist/scriptorium/markdown.js +88 -0
  198. package/dist/scriptorium/types.d.ts +78 -0
  199. package/dist/scriptorium/types.d.ts.map +1 -0
  200. package/dist/scriptorium/types.js +1 -0
  201. package/dist/types/enforcement.d.ts +11 -0
  202. package/dist/types/enforcement.d.ts.map +1 -0
  203. package/dist/types/enforcement.js +1 -0
  204. package/dist/types/integrity.d.ts +33 -0
  205. package/dist/types/integrity.d.ts.map +1 -0
  206. package/dist/types/integrity.js +1 -0
  207. package/dist/types/project-definition.d.ts +30 -0
  208. package/dist/types/project-definition.d.ts.map +1 -0
  209. package/dist/types/project-definition.js +1 -0
  210. package/dist/ui/assets/cosmic-glass-bg-Dwx47zPu.webp +0 -0
  211. package/dist/ui/assets/index-C4NhMaq7.js +28 -0
  212. package/dist/ui/assets/index-DMZ7ZvZY.css +1 -0
  213. package/dist/ui/index.html +13 -0
  214. package/dist/validate/index.d.ts +6 -0
  215. package/dist/validate/index.d.ts.map +1 -0
  216. package/dist/validate/index.js +214 -0
  217. package/dist/version.d.ts +2 -0
  218. package/dist/version.d.ts.map +1 -0
  219. package/dist/version.js +1 -0
  220. package/package.json +67 -4
  221. package/templates/.gitkeep +0 -0
  222. package/templates/default-instance/instruction/.cursorrules +53 -0
  223. package/templates/default-instance/instruction/.windsurfrules +53 -0
  224. package/templates/default-instance/instruction/CLAUDE.md +53 -0
  225. package/templates/default-instance/monolith/context/boot/HANDOFF.md +49 -0
  226. package/templates/default-instance/monolith/context/boot/WORK_SESSION.md +30 -0
  227. package/templates/default-instance/monolith/context/execution/current-state.md +30 -0
  228. package/templates/default-instance/monolith/context/maps/dependency-map.md +38 -0
  229. package/templates/default-instance/monolith/context/maps/project-map.md +85 -0
  230. package/templates/default-instance/monolith/context/maps/roadmap-index.md +41 -0
  231. package/templates/default-instance/monolith/context/maps/routing-map.md +147 -0
  232. package/templates/default-instance/monolith/context/maps/semantic-map.md +73 -0
  233. package/templates/default-instance/monolith/context/models/model-registry.md +37 -0
  234. package/templates/default-instance/monolith/context/models/privacy-classification.md +35 -0
  235. package/templates/default-instance/monolith/context/templates/plan-template.md +56 -0
  236. package/templates/default-instance/monolith/governance/README.md +29 -0
  237. package/templates/default-instance/monolith/governance/RULE_SCHEMA.md +58 -0
  238. package/templates/default-instance/monolith/learning/INDEX.md +48 -0
  239. package/templates/default-instance/monolith/learning/injection-map.md +49 -0
  240. package/templates/default-instance/monolith/learning/taxonomy.md +30 -0
  241. package/templates/default-instance/monolith/memory/errors/README.md +26 -0
  242. package/templates/default-instance/monolith/memory/errors/SCHEMA.md +47 -0
  243. package/templates/default-instance/monolith/memory/errors/TAXONOMY.md +27 -0
  244. package/templates/default-instance/monolith/memory/long-term/architecture-principles.md +31 -0
  245. package/templates/default-instance/monolith/memory/long-term/decisions.md +36 -0
  246. package/templates/default-instance/monolith/memory/long-term/execution-history.md +20 -0
  247. package/templates/default-instance/monolith/memory/long-term/tech-debt.md +25 -0
  248. package/templates/default-instance/monolith/memory/working/active.md +41 -0
  249. package/templates/default-instance/monolith/memory/working/governance-result.md +0 -0
  250. package/templates/default-instance/monolith/memory/working/integrity-result.md +0 -0
  251. package/templates/default-instance/monolith/memory/working/story-index.md +28 -0
  252. package/templates/default-instance/monolith/protocols/boot/boot-sequence.md +59 -0
  253. package/templates/default-instance/monolith/protocols/cognition/cognitive-modes.md +90 -0
  254. package/templates/default-instance/monolith/protocols/cognition/dry-run.md +56 -0
  255. package/templates/default-instance/monolith/protocols/cognition/execution-trace-format.md +52 -0
  256. package/templates/default-instance/monolith/protocols/cognition/semantic-planning.md +51 -0
  257. package/templates/default-instance/monolith/protocols/execution/hybrid-execution.md +37 -0
  258. package/templates/default-instance/monolith/protocols/execution/local-llm-governance.md +42 -0
  259. package/templates/default-instance/monolith/protocols/governance/command-policy.md +51 -0
  260. package/templates/default-instance/monolith/protocols/governance/core-invariants.md +40 -0
  261. package/templates/default-instance/monolith/protocols/governance/memory-governance.md +54 -0
  262. package/templates/default-instance/monolith/protocols/governance/metadata-schema.md +62 -0
  263. package/templates/default-instance/monolith/protocols/governance/skills.md +53 -0
  264. package/templates/default-instance/monolith/protocols/governance/work-session.md +46 -0
  265. package/templates/default-instance/monolith/skills/INDEX.md +28 -0
  266. package/templates/default-instance/monolith/skills/current-status/SKILL.md +47 -0
  267. package/templates/default-instance/monolith/skills/finalize-story/SKILL.md +86 -0
  268. package/templates/default-instance/monolith/skills/global-status/SKILL.md +56 -0
  269. package/templates/default-instance/monolith/skills/self-improvement/SKILL.md +77 -0
  270. package/templates/default-instance/monolith/state.json +11 -0
  271. package/templates/default-instance/monolith/tests/INDEX.md +57 -0
  272. package/templates/default-instance/monolith/tests/scenarios/architecture-review.md +32 -0
  273. package/templates/default-instance/monolith/tests/scenarios/debug-failure.md +32 -0
  274. package/templates/default-instance/monolith/tests/scenarios/dry-run-activation.md +33 -0
  275. package/templates/default-instance/monolith/tests/scenarios/execution-trace-verification.md +31 -0
  276. package/templates/default-instance/monolith/tests/scenarios/finalize-story.md +35 -0
  277. package/templates/default-instance/monolith/tests/scenarios/implement-feature.md +36 -0
  278. package/templates/default-instance/monolith/tests/scenarios/local-llm-delegation.md +31 -0
  279. package/templates/default-instance/monolith/tests/scenarios/planning-request.md +32 -0
  280. package/templates/default-instance/monolith/tests/scenarios/sensitive-context-task.md +30 -0
  281. package/templates/default-instance/monolith/tests/scenarios/validator-verification.md +33 -0
  282. package/templates/default-instance/monolith/tests/validation/expected-behavior.md +70 -0
  283. package/templates/default-instance/monolith/tests/validators/INDEX.md +17 -0
  284. package/templates/default-instance/monolith/tests/validators/delegation-semantics.md +22 -0
  285. package/templates/default-instance/monolith/tests/validators/mode-consistency.md +25 -0
  286. package/templates/default-instance/monolith/tests/validators/privacy-routing.md +23 -0
  287. package/templates/default-instance/monolith/tests/validators/protocol-references.md +27 -0
  288. package/templates/default-instance/monolith/tests/validators/routing-integrity.md +30 -0
  289. package/templates/default-instance/projectroot/AGENTS.md +107 -0
  290. package/templates/default-instance/projectroot/monolith.config.json +32 -0
  291. package/templates/default-instance/projectroot/project.definition.mjs.template +41 -0
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Project State Freshness (SELF-AWARENESS-001).
3
+ *
4
+ * `Completeness` says whether the brief lost data while being rendered.
5
+ * `Freshness` says whether the recorded project state can still be trusted.
6
+ * They are independent: `Completeness: COMPLETE` + `Freshness: STALE` is a
7
+ * valid combination, and nothing here ever changes `Completeness`.
8
+ *
9
+ * `evaluateFreshness()` is pure: it takes already-gathered evidence and
10
+ * returns a verdict. Git is a signal, never the only source of truth:
11
+ *
12
+ * STALE only on a concrete, named discrepancy — either the state
13
+ * documents contradict each other, or git history references
14
+ * work items that no state document mentions.
15
+ * FRESH only on positive evidence — git is readable, the last state
16
+ * update is located, and every commit after it either touches
17
+ * only the state documents or belongs to a recorded work item.
18
+ * UNKNOWN everything else. Git activity alone, an old date alone, or the
19
+ * absence of an active story alone never produce STALE, and the
20
+ * absence of an active story never means "project complete".
21
+ */
22
+ // ---------------------------------------------------------------------------
23
+ // Work-item ids
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Work-item id: an upper-case, dash-separated prefix, a number, then optional
27
+ * sub-story qualifiers — UI-002D, SEC-001B.1-R, LOCK-RELEASE-001, CONTEXT-001A.
28
+ * Deliberately narrow: an id that is not matched is simply not evidence.
29
+ */
30
+ const WORK_ITEM_SOURCE = String.raw `(?:[A-Z]{2,}-)+\d{3}[A-Z]?(?:\.\d+)*(?:-[A-Z])?`;
31
+ /** Decision / lesson records are not work items. */
32
+ const NON_WORK_PREFIXES = ['ADR-', 'DEC-', 'LESSON-'];
33
+ function isWorkItem(id) {
34
+ return !NON_WORK_PREFIXES.some((p) => id.startsWith(p));
35
+ }
36
+ export function extractWorkItemIds(text) {
37
+ const re = new RegExp(`(?<![A-Za-z0-9-])${WORK_ITEM_SOURCE}(?![A-Za-z0-9]|\\.\\d|-[A-Z0-9])`, 'g');
38
+ const seen = new Set();
39
+ for (const m of text.matchAll(re)) {
40
+ if (isWorkItem(m[0]))
41
+ seen.add(m[0]);
42
+ }
43
+ return [...seen];
44
+ }
45
+ export function mentionsId(text, id) {
46
+ const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
47
+ return new RegExp(`(?<![A-Za-z0-9-])${escaped}(?![A-Za-z0-9]|\\.\\d|-[A-Z0-9])`).test(text);
48
+ }
49
+ // ---------------------------------------------------------------------------
50
+ // Parsers for the state documents (confirmed structure only)
51
+ // ---------------------------------------------------------------------------
52
+ const NONE_RE = /^\W*(?:no active story|none|unknown)\b|^\s*[—-]\s*$/i;
53
+ /** Interprets the `## Current Story` excerpt of active.md. */
54
+ export function parseActiveStoryClaim(excerpt) {
55
+ if (excerpt === null)
56
+ return { kind: 'unknown' };
57
+ const firstLine = excerpt.split('\n').find((l) => l.trim() !== '') ?? '';
58
+ if (/^\W*no active story\b/i.test(firstLine))
59
+ return { kind: 'none' };
60
+ const ids = extractWorkItemIds(excerpt);
61
+ return ids.length > 0 ? { kind: 'ids', ids } : { kind: 'unknown' };
62
+ }
63
+ /** `Active Story: <text>` line of roadmap-index.md. */
64
+ export function parseRoadmapActiveStory(content) {
65
+ const m = /^Active Story:\s*(.+?)\s*$/m.exec(content);
66
+ return m ? m[1] : null;
67
+ }
68
+ /** Table rows `| id | title | STATUS | date |` of roadmap-index.md. */
69
+ export function parseRoadmapStatuses(content) {
70
+ const out = new Map();
71
+ for (const line of content.split('\n')) {
72
+ const cells = line.split('|').map((c) => c.trim());
73
+ // leading and trailing '|' produce empty first/last cells
74
+ if (cells.length < 5 || cells[0] !== '' || cells[cells.length - 1] !== '')
75
+ continue;
76
+ const id = cells[1];
77
+ const status = cells[3];
78
+ if (!/^[A-Za-z0-9][A-Za-z0-9.\-]*$/.test(id) || !/^[A-Z][A-Z _]+$/.test(status))
79
+ continue;
80
+ if (!out.has(id))
81
+ out.set(id, status);
82
+ }
83
+ return out;
84
+ }
85
+ /** `### [STORY ]<id> — title` followed by `**Status:** X` in story-index.md. */
86
+ export function parseStoryIndexStatuses(content) {
87
+ const out = new Map();
88
+ const lines = content.split('\n');
89
+ for (let i = 0; i < lines.length; i++) {
90
+ const h = /^###\s+(?:STORY\s+)?([A-Za-z0-9][A-Za-z0-9.\-]*)\s+—/.exec(lines[i]);
91
+ if (!h)
92
+ continue;
93
+ for (let j = i + 1; j < Math.min(lines.length, i + 6); j++) {
94
+ if (/^#{1,3}\s/.test(lines[j]))
95
+ break;
96
+ const s = /^\*\*Status:\*\*\s*([A-Z][A-Z _]*)/.exec(lines[j]);
97
+ if (s) {
98
+ if (!out.has(h[1]))
99
+ out.set(h[1], s[1].trim());
100
+ break;
101
+ }
102
+ }
103
+ }
104
+ return out;
105
+ }
106
+ // ---------------------------------------------------------------------------
107
+ // Evaluation
108
+ // ---------------------------------------------------------------------------
109
+ const MAX_LISTED = 5;
110
+ function listIds(ids) {
111
+ if (ids.length <= MAX_LISTED)
112
+ return ids.join(', ');
113
+ return `${ids.slice(0, MAX_LISTED).join(', ')} and ${ids.length - MAX_LISTED} more`;
114
+ }
115
+ function isDone(status) {
116
+ return status === 'COMPLETED' || status === 'DONE';
117
+ }
118
+ function findContradictions(ev) {
119
+ const out = [];
120
+ if (ev.activeStory.kind === 'none' && ev.roadmapActiveStory !== null && !NONE_RE.test(ev.roadmapActiveStory)) {
121
+ out.push({
122
+ message: `active.md records no active story, but roadmap-index.md names "${ev.roadmapActiveStory}".`,
123
+ documents: ['active.md', 'roadmap-index.md'],
124
+ });
125
+ }
126
+ if (ev.activeStory.kind === 'ids') {
127
+ for (const id of ev.activeStory.ids) {
128
+ if (isDone(ev.roadmapStatuses.get(id))) {
129
+ out.push({
130
+ message: `active.md treats ${id} as current, but roadmap-index.md marks it ${ev.roadmapStatuses.get(id)}.`,
131
+ documents: ['active.md', 'roadmap-index.md'],
132
+ });
133
+ }
134
+ else if (isDone(ev.storyIndexStatuses.get(id))) {
135
+ out.push({
136
+ message: `active.md treats ${id} as current, but story-index.md marks it ${ev.storyIndexStatuses.get(id)}.`,
137
+ documents: ['active.md', 'story-index.md'],
138
+ });
139
+ }
140
+ }
141
+ }
142
+ for (const [id, roadmapStatus] of ev.roadmapStatuses) {
143
+ const indexStatus = ev.storyIndexStatuses.get(id);
144
+ if (indexStatus !== undefined && indexStatus !== roadmapStatus) {
145
+ out.push({
146
+ message: `${id} is ${roadmapStatus} in roadmap-index.md but ${indexStatus} in story-index.md.`,
147
+ documents: ['roadmap-index.md', 'story-index.md'],
148
+ });
149
+ }
150
+ }
151
+ return out;
152
+ }
153
+ const REVIEW_RECOMMENDATION = 'Review project state before relying on this brief.';
154
+ export function evaluateFreshness(ev) {
155
+ const reasons = [];
156
+ const warnings = [];
157
+ const base = {
158
+ activeStory: ev.activeStory.kind === 'none' ? 'none-recorded' : ev.activeStory.kind === 'ids' ? 'recorded' : 'unknown',
159
+ lastStateUpdate: ev.git.status === 'ok' ? ev.git.lastStateUpdate : null,
160
+ activityCount: null,
161
+ unrecordedWork: [],
162
+ };
163
+ // 1. Internal contradictions need no git at all.
164
+ const contradictions = findContradictions(ev);
165
+ for (const c of contradictions)
166
+ reasons.push({ code: 'STATE_CONTRADICTION', message: c.message, documents: c.documents });
167
+ // 2. Git-derived signals.
168
+ let gitVerdict = null;
169
+ if (ev.git.status === 'unavailable') {
170
+ const why = {
171
+ GIT_NOT_INSTALLED: 'git is not installed or not runnable',
172
+ NOT_A_GIT_REPOSITORY: 'the project is not inside a git repository',
173
+ GIT_FAILED: 'git could not be queried',
174
+ };
175
+ reasons.push({ code: 'GIT_UNAVAILABLE', message: `Cannot compare state with history: ${why[ev.git.reason]}.` });
176
+ gitVerdict = 'unknown';
177
+ }
178
+ else if (ev.git.lastStateUpdate === null) {
179
+ reasons.push({
180
+ code: 'STATE_NOT_IN_GIT',
181
+ message: 'No commit touches the state documents, so the last state update cannot be located.',
182
+ });
183
+ gitVerdict = 'unknown';
184
+ }
185
+ else {
186
+ const activity = ev.git.commitsSince.filter((c) => c.files.some((f) => !ev.stateFiles.has(f)));
187
+ base.activityCount = activity.length;
188
+ const referenced = new Set();
189
+ let unattributed = 0;
190
+ for (const c of activity) {
191
+ const ids = extractWorkItemIds(c.subject);
192
+ if (ids.length === 0)
193
+ unattributed++;
194
+ for (const id of ids)
195
+ referenced.add(id);
196
+ }
197
+ const unrecorded = [...referenced].filter((id) => !mentionsId(ev.recordedText, id)).sort();
198
+ base.unrecordedWork = unrecorded;
199
+ if (unrecorded.length > 0) {
200
+ reasons.push({
201
+ code: 'UNRECORDED_WORK',
202
+ message: `${activity.length} commit(s) after the last state update (${ev.git.lastStateUpdate.sha.slice(0, 7)}, ${ev.git.lastStateUpdate.date.slice(0, 10)}) ` +
203
+ `reference ${unrecorded.length} work item(s) that no state document mentions: ${listIds(unrecorded)}.`,
204
+ });
205
+ gitVerdict = 'stale';
206
+ }
207
+ else if (ev.git.truncated) {
208
+ reasons.push({
209
+ code: 'GIT_HISTORY_TRUNCATED',
210
+ message: 'Git history after the last state update was cut at the read limit; the check is partial.',
211
+ });
212
+ gitVerdict = 'unknown';
213
+ }
214
+ else if (unattributed > 0) {
215
+ reasons.push({
216
+ code: 'UNATTRIBUTED_ACTIVITY',
217
+ message: `${unattributed} commit(s) after the last state update touch project files without naming a work item; ` +
218
+ `whether the recorded state still describes them cannot be determined.`,
219
+ });
220
+ gitVerdict = 'unknown';
221
+ }
222
+ else if (activity.length === 0) {
223
+ reasons.push({
224
+ code: 'NO_ACTIVITY_SINCE_STATE_UPDATE',
225
+ message: 'No commit after the last state update changed anything beyond the state documents.',
226
+ });
227
+ gitVerdict = 'fresh';
228
+ }
229
+ else {
230
+ reasons.push({
231
+ code: 'ACTIVITY_RECORDED',
232
+ message: `All ${activity.length} commit(s) after the last state update reference work items that the state documents mention.`,
233
+ });
234
+ gitVerdict = 'fresh';
235
+ }
236
+ if (activity.length > 0 && ev.activeStory.kind === 'none') {
237
+ warnings.push('Git activity exists after the last recorded state update, but no active story is recorded.');
238
+ }
239
+ }
240
+ // 3. Combine. A contradiction or unrecorded work is concrete evidence of staleness;
241
+ // FRESH needs positive evidence and no contradiction.
242
+ let status;
243
+ if (contradictions.length > 0 || gitVerdict === 'stale')
244
+ status = 'STALE';
245
+ else if (gitVerdict === 'fresh')
246
+ status = 'FRESH';
247
+ else
248
+ status = 'UNKNOWN';
249
+ if (status !== 'FRESH') {
250
+ if (status === 'STALE')
251
+ warnings.unshift('Project state may be outdated.');
252
+ else
253
+ warnings.unshift('Freshness could not be established from the available evidence.');
254
+ if (ev.activeStory.kind === 'none') {
255
+ warnings.push('No active story is recorded; this does not mean the project is complete.');
256
+ }
257
+ else if (ev.activeStory.kind === 'unknown') {
258
+ warnings.push('The active story could not be determined from active.md.');
259
+ }
260
+ }
261
+ const recommendation = status === 'FRESH' ? 'No action needed.' : status === 'STALE' ? REVIEW_RECOMMENDATION : `${REVIEW_RECOMMENDATION} Freshness is unverified, not confirmed outdated.`;
262
+ return { status, reasons, warnings, recommendation, ...base };
263
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Read-only git signals for the freshness check (SELF-AWARENESS-001).
3
+ *
4
+ * Runs only `git log` and `git rev-parse`, never a command that writes, never
5
+ * through a shell, with config that could launch helper programs switched off.
6
+ * Any failure degrades to `{ status: 'unavailable' }` — git being absent,
7
+ * broken or refusing the directory must never fail the brief.
8
+ */
9
+ import type { GitSignals } from './freshness.js';
10
+ /** Upper bound on commits read after the last state update. Hitting it marks the result truncated. */
11
+ export declare const MAX_COMMITS_SINCE = 500;
12
+ /**
13
+ * @param targetDir project directory (git is run from here; paths are relative to it)
14
+ * @param stateFiles state documents, relative to `targetDir`. Only existing ones need be passed.
15
+ */
16
+ export declare function readGitSignals(targetDir: string, stateFiles: string[]): GitSignals;
17
+ //# sourceMappingURL=git-signals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-signals.d.ts","sourceRoot":"","sources":["../../src/brief/git-signals.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAmB,MAAM,gBAAgB,CAAC;AAElE,sGAAsG;AACtG,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAgCrC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,UAAU,CAqDlF"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Read-only git signals for the freshness check (SELF-AWARENESS-001).
3
+ *
4
+ * Runs only `git log` and `git rev-parse`, never a command that writes, never
5
+ * through a shell, with config that could launch helper programs switched off.
6
+ * Any failure degrades to `{ status: 'unavailable' }` — git being absent,
7
+ * broken or refusing the directory must never fail the brief.
8
+ */
9
+ import { execFileSync } from 'child_process';
10
+ /** Upper bound on commits read after the last state update. Hitting it marks the result truncated. */
11
+ export const MAX_COMMITS_SINCE = 500;
12
+ const GIT_TIMEOUT_MS = 10_000;
13
+ const GIT_MAX_BUFFER = 8 * 1024 * 1024;
14
+ const SAFE_CONFIG = [
15
+ '-c', 'core.fsmonitor=false',
16
+ '-c', 'core.pager=cat',
17
+ '-c', 'log.showSignature=false',
18
+ '-c', 'diff.external=',
19
+ ];
20
+ class GitMissingError extends Error {
21
+ }
22
+ function git(cwd, args) {
23
+ try {
24
+ return execFileSync('git', [...SAFE_CONFIG, ...args], {
25
+ cwd,
26
+ encoding: 'utf8',
27
+ timeout: GIT_TIMEOUT_MS,
28
+ maxBuffer: GIT_MAX_BUFFER,
29
+ stdio: ['ignore', 'pipe', 'pipe'],
30
+ env: { ...process.env, GIT_OPTIONAL_LOCKS: '0', GIT_TERMINAL_PROMPT: '0', GIT_EXTERNAL_DIFF: '' },
31
+ });
32
+ }
33
+ catch (err) {
34
+ if (err.code === 'ENOENT')
35
+ throw new GitMissingError('git not installed');
36
+ throw err;
37
+ }
38
+ }
39
+ const RS = '\x1e'; // record separator, starts each commit
40
+ const US = '\x1f'; // unit separator, between header fields
41
+ /**
42
+ * @param targetDir project directory (git is run from here; paths are relative to it)
43
+ * @param stateFiles state documents, relative to `targetDir`. Only existing ones need be passed.
44
+ */
45
+ export function readGitSignals(targetDir, stateFiles) {
46
+ try {
47
+ const inside = git(targetDir, ['rev-parse', '--is-inside-work-tree']).trim();
48
+ if (inside !== 'true')
49
+ return { status: 'unavailable', reason: 'NOT_A_GIT_REPOSITORY' };
50
+ }
51
+ catch (err) {
52
+ if (err instanceof GitMissingError)
53
+ return { status: 'unavailable', reason: 'GIT_NOT_INSTALLED' };
54
+ const stderr = String(err.stderr ?? '');
55
+ return { status: 'unavailable', reason: /not a git repository/i.test(stderr) ? 'NOT_A_GIT_REPOSITORY' : 'GIT_FAILED' };
56
+ }
57
+ try {
58
+ // A repository without commits has no HEAD: nothing to compare with.
59
+ try {
60
+ git(targetDir, ['rev-parse', '--verify', '--quiet', 'HEAD']);
61
+ }
62
+ catch {
63
+ return { status: 'ok', lastStateUpdate: null, commitsSince: [], truncated: false };
64
+ }
65
+ let lastStateUpdate = null;
66
+ if (stateFiles.length > 0) {
67
+ const out = git(targetDir, ['log', '-1', `--format=%H${US}%cI`, '--', ...stateFiles]).trim();
68
+ if (out) {
69
+ const [sha, date] = out.split(US);
70
+ lastStateUpdate = { sha, date };
71
+ }
72
+ }
73
+ if (!lastStateUpdate)
74
+ return { status: 'ok', lastStateUpdate: null, commitsSince: [], truncated: false };
75
+ const raw = git(targetDir, [
76
+ 'log',
77
+ `-n${MAX_COMMITS_SINCE + 1}`,
78
+ '--no-ext-diff',
79
+ '--no-textconv',
80
+ '--relative',
81
+ '--name-only',
82
+ `--format=${RS}%H${US}%cI${US}%s`,
83
+ `${lastStateUpdate.sha}..HEAD`,
84
+ ]);
85
+ const commits = [];
86
+ for (const rec of raw.split(RS)) {
87
+ if (!rec.trim())
88
+ continue;
89
+ const nl = rec.indexOf('\n');
90
+ const header = nl === -1 ? rec : rec.slice(0, nl);
91
+ const [sha, date, subject] = header.split(US);
92
+ const files = (nl === -1 ? '' : rec.slice(nl + 1)).split('\n').filter((l) => l.trim() !== '');
93
+ commits.push({ sha, date, subject: subject ?? '', files });
94
+ }
95
+ const truncated = commits.length > MAX_COMMITS_SINCE;
96
+ return { status: 'ok', lastStateUpdate, commitsSince: commits.slice(0, MAX_COMMITS_SINCE), truncated };
97
+ }
98
+ catch {
99
+ return { status: 'unavailable', reason: 'GIT_FAILED' };
100
+ }
101
+ }
@@ -0,0 +1,11 @@
1
+ export type { BriefModel, BriefDiagnostic, BriefDiagnosticCode, DiagnosticSeverity, Provenance, ProjectIdentity, StateKeeperStatus, StateKeeperSummary, MissionsSummary, CheckpointSummary, StorySummary, DocRef, AdrRef, AdrIndex, ProtocolIndex, } from './types.js';
2
+ export { collect } from './collect.js';
3
+ export { render, DEFAULT_MAX_CHARS } from './render.js';
4
+ export type { RenderResult, Completeness } from './render.js';
5
+ export { runBrief, parseBriefArgs } from './cli.js';
6
+ export type { BriefArgsResult, BriefArgsOk, BriefArgsErr } from './cli.js';
7
+ export { evaluateFreshness } from './freshness.js';
8
+ export type { FreshnessStatus, FreshnessResult, FreshnessEvidence, FreshnessReason, GitSignals } from './freshness.js';
9
+ export { reconcile, renderReconciliation } from './reconcile.js';
10
+ export type { ReconciliationReport, ReconciliationFinding, FindingKind, UntrackedWorkItem, ReviewDocument } from './reconcile.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/brief/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,MAAM,EACN,MAAM,EACN,QAAQ,EACR,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvH,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACjE,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { collect } from './collect.js';
2
+ export { render, DEFAULT_MAX_CHARS } from './render.js';
3
+ export { runBrief, parseBriefArgs } from './cli.js';
4
+ export { evaluateFreshness } from './freshness.js';
5
+ export { reconcile, renderReconciliation } from './reconcile.js';
@@ -0,0 +1,75 @@
1
+ /**
2
+ * State Reconciliation Report (SELF-AWARENESS-002).
3
+ *
4
+ * SELF-AWARENESS-001 says *whether* the recorded state looks outdated. This
5
+ * module says *what* the evidence is and *what a human should check*. It is
6
+ * pure: it takes the same `FreshnessEvidence` / `FreshnessResult` that
7
+ * `brief` already computed, reads nothing and writes nothing.
8
+ *
9
+ * Two rules shape every line of the report:
10
+ * - A git commit is not evidence that a work item is complete, and a work-item
11
+ * id in a commit subject is not evidence that its recorded status is right.
12
+ * The report therefore only ever says "referenced" and "not mentioned",
13
+ * never "done" or "missing from the roadmap because it was finished".
14
+ * - Recommendations are things for a person to verify or decide. Nothing here
15
+ * edits a document or concludes anything on the person's behalf.
16
+ *
17
+ * Findings are graded:
18
+ * confirmed a concrete, checkable discrepancy (documents contradict each other,
19
+ * or git names a work item that no state document mentions)
20
+ * suspected something that may be a discrepancy but cannot be shown from the data
21
+ * unknown the evidence needed to decide is missing (no git, truncated history, ...)
22
+ */
23
+ import { type FreshnessEvidence, type FreshnessResult, type FreshnessStatus } from './freshness.js';
24
+ export type FindingKind = 'confirmed' | 'suspected' | 'unknown';
25
+ export type FindingCode = 'STATE_CONTRADICTION' | 'UNRECORDED_WORK' | 'UNATTRIBUTED_ACTIVITY' | 'ACTIVITY_WITHOUT_ACTIVE_STORY' | 'GIT_UNAVAILABLE' | 'STATE_NOT_IN_GIT' | 'GIT_HISTORY_TRUNCATED' | 'ACTIVE_STORY_UNKNOWN';
26
+ export interface ReconciliationFinding {
27
+ kind: FindingKind;
28
+ code: FindingCode;
29
+ summary: string;
30
+ /** Short, checkable pointers: document names or `<sha7> <subject>`. */
31
+ evidence: string[];
32
+ }
33
+ export interface UntrackedWorkItem {
34
+ id: string;
35
+ /** Newest first, at most `MAX_COMMITS_PER_ITEM`. */
36
+ commits: {
37
+ sha: string;
38
+ subject: string;
39
+ }[];
40
+ totalCommits: number;
41
+ }
42
+ export interface ReviewDocument {
43
+ path: string;
44
+ reasons: string[];
45
+ }
46
+ export interface ReconciliationReport {
47
+ freshness: FreshnessStatus;
48
+ lastStateUpdate: {
49
+ sha: string;
50
+ date: string;
51
+ } | null;
52
+ findings: ReconciliationFinding[];
53
+ /** Work-item ids git references after the last state update that no state document mentions. Sorted. */
54
+ untrackedWork: UntrackedWorkItem[];
55
+ /** Ids git references that some state document mentions. Mentioned is not correct. Sorted. */
56
+ mentionedWork: string[];
57
+ documents: ReviewDocument[];
58
+ limitations: string[];
59
+ actions: string[];
60
+ }
61
+ export declare const MAX_COMMITS_PER_ITEM = 3;
62
+ export declare function reconcile(ev: FreshnessEvidence, result: FreshnessResult): ReconciliationReport;
63
+ export interface RenderedReconciliation {
64
+ text: string;
65
+ /** True when a section was dropped to fit the budget. */
66
+ truncated: boolean;
67
+ }
68
+ /**
69
+ * Deterministic, bounded text. The header (freshness) and the closing
70
+ * "No files were modified." are mandatory and never dropped; the sections in
71
+ * between are added in priority order while they fit, and an omission is
72
+ * always announced.
73
+ */
74
+ export declare function renderReconciliation(report: ReconciliationReport, maxChars: number): RenderedReconciliation;
75
+ //# sourceMappingURL=reconcile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.d.ts","sourceRoot":"","sources":["../../src/brief/reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,eAAe,EAErB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,CAAC;AAEhE,MAAM,MAAM,WAAW,GACnB,qBAAqB,GACrB,iBAAiB,GACjB,uBAAuB,GACvB,+BAA+B,GAC/B,iBAAiB,GACjB,kBAAkB,GAClB,uBAAuB,GACvB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,oDAAoD;IACpD,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,eAAe,CAAC;IAC3B,eAAe,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACtD,QAAQ,EAAE,qBAAqB,EAAE,CAAC;IAClC,wGAAwG;IACxG,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,8FAA8F;IAC9F,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAiBtC,wBAAgB,SAAS,CAAC,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,eAAe,GAAG,oBAAoB,CAmI9F;AAiBD,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,GAAG,sBAAsB,CAoF3G"}