agentplane 0.2.25 → 0.3.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 (221) hide show
  1. package/README.md +3 -1
  2. package/assets/AGENTS.md +123 -526
  3. package/assets/agents/UPGRADER.json +10 -9
  4. package/assets/framework.manifest.json +112 -7
  5. package/assets/policy/check-routing.mjs +180 -0
  6. package/assets/policy/dod.code.md +25 -0
  7. package/assets/policy/dod.core.md +32 -0
  8. package/assets/policy/dod.docs.md +32 -0
  9. package/assets/policy/examples/migration-note.md +6 -0
  10. package/assets/policy/examples/pr-note.md +16 -0
  11. package/assets/policy/examples/unit-test-pattern.md +19 -0
  12. package/assets/policy/governance.md +37 -0
  13. package/assets/policy/incidents.md +36 -0
  14. package/assets/policy/security.must.md +7 -0
  15. package/assets/policy/workflow.branch_pr.md +34 -0
  16. package/assets/policy/workflow.direct.md +46 -0
  17. package/assets/policy/workflow.md +9 -0
  18. package/assets/policy/workflow.release.md +31 -0
  19. package/assets/policy/workflow.upgrade.md +20 -0
  20. package/bin/agentplane.js +47 -57
  21. package/bin/dist-guard.js +124 -0
  22. package/dist/.build-manifest.json +11 -0
  23. package/dist/agents/agents-template.d.ts +7 -0
  24. package/dist/agents/agents-template.d.ts.map +1 -1
  25. package/dist/agents/agents-template.js +41 -2
  26. package/dist/backends/task-backend/local-backend.d.ts +2 -0
  27. package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
  28. package/dist/backends/task-backend/local-backend.js +12 -1
  29. package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
  30. package/dist/backends/task-backend/redmine/mapping.js +26 -1
  31. package/dist/backends/task-backend/redmine-backend.d.ts +4 -0
  32. package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
  33. package/dist/backends/task-backend/redmine-backend.js +92 -9
  34. package/dist/backends/task-backend/shared/types.d.ts +1 -0
  35. package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
  36. package/dist/backends/task-index.d.ts.map +1 -1
  37. package/dist/backends/task-index.js +8 -1
  38. package/dist/cli/command-guide.d.ts.map +1 -1
  39. package/dist/cli/command-guide.js +39 -17
  40. package/dist/cli/command-snippets.d.ts +24 -0
  41. package/dist/cli/command-snippets.d.ts.map +1 -0
  42. package/dist/cli/command-snippets.js +23 -0
  43. package/dist/cli/reason-codes.d.ts +9 -0
  44. package/dist/cli/reason-codes.d.ts.map +1 -0
  45. package/dist/cli/reason-codes.js +79 -0
  46. package/dist/cli/recipes-bundled.d.ts +1 -0
  47. package/dist/cli/recipes-bundled.d.ts.map +1 -1
  48. package/dist/cli/recipes-bundled.js +4 -1
  49. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  50. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  51. package/dist/cli/run-cli/command-catalog.js +40 -1
  52. package/dist/cli/run-cli/commands/config.d.ts +5 -0
  53. package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
  54. package/dist/cli/run-cli/commands/config.js +86 -1
  55. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  56. package/dist/cli/run-cli/commands/core.js +57 -2
  57. package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
  58. package/dist/cli/run-cli/commands/ide.js +8 -3
  59. package/dist/cli/run-cli/commands/init/recipes.d.ts +5 -1
  60. package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
  61. package/dist/cli/run-cli/commands/init/recipes.js +24 -4
  62. package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
  63. package/dist/cli/run-cli/commands/init/ui.js +1 -2
  64. package/dist/cli/run-cli/commands/init/write-agents.d.ts +2 -0
  65. package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
  66. package/dist/cli/run-cli/commands/init/write-agents.js +24 -5
  67. package/dist/cli/run-cli/commands/init/write-workflow.d.ts +12 -0
  68. package/dist/cli/run-cli/commands/init/write-workflow.d.ts.map +1 -0
  69. package/dist/cli/run-cli/commands/init/write-workflow.js +58 -0
  70. package/dist/cli/run-cli/commands/init.d.ts +4 -1
  71. package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
  72. package/dist/cli/run-cli/commands/init.js +126 -48
  73. package/dist/cli/run-cli.d.ts.map +1 -1
  74. package/dist/cli/run-cli.js +195 -8
  75. package/dist/commands/backend/sync.command.d.ts.map +1 -1
  76. package/dist/commands/backend/sync.command.js +7 -6
  77. package/dist/commands/backend.d.ts.map +1 -1
  78. package/dist/commands/backend.js +2 -0
  79. package/dist/commands/doctor.run.d.ts.map +1 -1
  80. package/dist/commands/doctor.run.js +107 -16
  81. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  82. package/dist/commands/guard/impl/commands.js +12 -6
  83. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
  84. package/dist/commands/recipes/impl/commands/install.js +36 -13
  85. package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
  86. package/dist/commands/recipes/impl/scenario.js +25 -0
  87. package/dist/commands/recipes/impl/types.d.ts +4 -0
  88. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  89. package/dist/commands/release/apply.command.d.ts.map +1 -1
  90. package/dist/commands/release/apply.command.js +9 -4
  91. package/dist/commands/release/plan.command.d.ts.map +1 -1
  92. package/dist/commands/release/plan.command.js +9 -3
  93. package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
  94. package/dist/commands/scenario/impl/commands.js +74 -3
  95. package/dist/commands/scenario/impl/report.d.ts +8 -0
  96. package/dist/commands/scenario/impl/report.d.ts.map +1 -1
  97. package/dist/commands/scenario/impl/report.js +1 -0
  98. package/dist/commands/shared/reconcile-check.d.ts +7 -0
  99. package/dist/commands/shared/reconcile-check.d.ts.map +1 -0
  100. package/dist/commands/shared/reconcile-check.js +60 -0
  101. package/dist/commands/sync.command.d.ts.map +1 -1
  102. package/dist/commands/sync.command.js +9 -2
  103. package/dist/commands/task/add.d.ts.map +1 -1
  104. package/dist/commands/task/add.js +32 -0
  105. package/dist/commands/task/doc.command.d.ts.map +1 -1
  106. package/dist/commands/task/doc.command.js +1 -0
  107. package/dist/commands/task/finish.d.ts.map +1 -1
  108. package/dist/commands/task/finish.js +11 -1
  109. package/dist/commands/task/list.d.ts.map +1 -1
  110. package/dist/commands/task/list.js +2 -1
  111. package/dist/commands/task/list.spec.d.ts.map +1 -1
  112. package/dist/commands/task/list.spec.js +7 -0
  113. package/dist/commands/task/new.d.ts.map +1 -1
  114. package/dist/commands/task/new.js +41 -4
  115. package/dist/commands/task/next.d.ts.map +1 -1
  116. package/dist/commands/task/next.js +2 -1
  117. package/dist/commands/task/next.spec.d.ts.map +1 -1
  118. package/dist/commands/task/next.spec.js +7 -0
  119. package/dist/commands/task/plan.d.ts.map +1 -1
  120. package/dist/commands/task/plan.js +7 -1
  121. package/dist/commands/task/search.d.ts.map +1 -1
  122. package/dist/commands/task/search.js +2 -1
  123. package/dist/commands/task/search.spec.d.ts.map +1 -1
  124. package/dist/commands/task/search.spec.js +7 -0
  125. package/dist/commands/task/shared.d.ts +14 -0
  126. package/dist/commands/task/shared.d.ts.map +1 -1
  127. package/dist/commands/task/shared.js +58 -1
  128. package/dist/commands/task/start-ready.js +1 -1
  129. package/dist/commands/task/verify-record.d.ts.map +1 -1
  130. package/dist/commands/task/verify-record.js +2 -0
  131. package/dist/commands/upgrade.command.d.ts.map +1 -1
  132. package/dist/commands/upgrade.command.js +2 -2
  133. package/dist/commands/upgrade.d.ts.map +1 -1
  134. package/dist/commands/upgrade.js +263 -294
  135. package/dist/commands/workflow-build.command.d.ts +8 -0
  136. package/dist/commands/workflow-build.command.d.ts.map +1 -0
  137. package/dist/commands/workflow-build.command.js +103 -0
  138. package/dist/commands/workflow-playbook.command.d.ts +10 -0
  139. package/dist/commands/workflow-playbook.command.d.ts.map +1 -0
  140. package/dist/commands/workflow-playbook.command.js +173 -0
  141. package/dist/commands/workflow-restore.command.d.ts +5 -0
  142. package/dist/commands/workflow-restore.command.d.ts.map +1 -0
  143. package/dist/commands/workflow-restore.command.js +30 -0
  144. package/dist/commands/workflow.command.d.ts +6 -0
  145. package/dist/commands/workflow.command.d.ts.map +1 -0
  146. package/dist/commands/workflow.command.js +36 -0
  147. package/dist/harness/dynamic-tool-contract.d.ts +29 -0
  148. package/dist/harness/dynamic-tool-contract.d.ts.map +1 -0
  149. package/dist/harness/dynamic-tool-contract.js +86 -0
  150. package/dist/harness/hooks-lifecycle.d.ts +27 -0
  151. package/dist/harness/hooks-lifecycle.d.ts.map +1 -0
  152. package/dist/harness/hooks-lifecycle.js +67 -0
  153. package/dist/harness/index.d.ts +9 -0
  154. package/dist/harness/index.d.ts.map +1 -0
  155. package/dist/harness/index.js +8 -0
  156. package/dist/harness/reconcile.d.ts +37 -0
  157. package/dist/harness/reconcile.d.ts.map +1 -0
  158. package/dist/harness/reconcile.js +42 -0
  159. package/dist/harness/retry-policy.d.ts +31 -0
  160. package/dist/harness/retry-policy.d.ts.map +1 -0
  161. package/dist/harness/retry-policy.js +33 -0
  162. package/dist/harness/scheduler.d.ts +18 -0
  163. package/dist/harness/scheduler.d.ts.map +1 -0
  164. package/dist/harness/scheduler.js +55 -0
  165. package/dist/harness/state-machine.d.ts +17 -0
  166. package/dist/harness/state-machine.d.ts.map +1 -0
  167. package/dist/harness/state-machine.js +70 -0
  168. package/dist/harness/token-accounting.d.ts +19 -0
  169. package/dist/harness/token-accounting.d.ts.map +1 -0
  170. package/dist/harness/token-accounting.js +77 -0
  171. package/dist/harness/workspace-safety.d.ts +14 -0
  172. package/dist/harness/workspace-safety.d.ts.map +1 -0
  173. package/dist/harness/workspace-safety.js +62 -0
  174. package/dist/recipes/bundled-recipes.d.ts +4 -0
  175. package/dist/recipes/bundled-recipes.d.ts.map +1 -1
  176. package/dist/recipes/bundled-recipes.js +11 -0
  177. package/dist/shared/errors.d.ts +6 -0
  178. package/dist/shared/errors.d.ts.map +1 -1
  179. package/dist/shared/errors.js +1 -0
  180. package/dist/shared/policy-gateway.d.ts +15 -0
  181. package/dist/shared/policy-gateway.d.ts.map +1 -0
  182. package/dist/shared/policy-gateway.js +49 -0
  183. package/dist/shared/protected-paths.d.ts.map +1 -1
  184. package/dist/shared/protected-paths.js +1 -0
  185. package/dist/shared/runtime-artifacts.d.ts +2 -2
  186. package/dist/shared/runtime-artifacts.d.ts.map +1 -1
  187. package/dist/shared/runtime-artifacts.js +4 -0
  188. package/dist/workflow-runtime/build.d.ts +4 -0
  189. package/dist/workflow-runtime/build.d.ts.map +1 -0
  190. package/dist/workflow-runtime/build.js +126 -0
  191. package/dist/workflow-runtime/enforcement.d.ts +3 -0
  192. package/dist/workflow-runtime/enforcement.d.ts.map +1 -0
  193. package/dist/workflow-runtime/enforcement.js +10 -0
  194. package/dist/workflow-runtime/file-ops.d.ts +11 -0
  195. package/dist/workflow-runtime/file-ops.d.ts.map +1 -0
  196. package/dist/workflow-runtime/file-ops.js +248 -0
  197. package/dist/workflow-runtime/fix.d.ts +9 -0
  198. package/dist/workflow-runtime/fix.d.ts.map +1 -0
  199. package/dist/workflow-runtime/fix.js +107 -0
  200. package/dist/workflow-runtime/index.d.ts +11 -0
  201. package/dist/workflow-runtime/index.d.ts.map +1 -0
  202. package/dist/workflow-runtime/index.js +10 -0
  203. package/dist/workflow-runtime/markdown.d.ts +10 -0
  204. package/dist/workflow-runtime/markdown.d.ts.map +1 -0
  205. package/dist/workflow-runtime/markdown.js +147 -0
  206. package/dist/workflow-runtime/observability.d.ts +12 -0
  207. package/dist/workflow-runtime/observability.d.ts.map +1 -0
  208. package/dist/workflow-runtime/observability.js +14 -0
  209. package/dist/workflow-runtime/paths.d.ts +3 -0
  210. package/dist/workflow-runtime/paths.d.ts.map +1 -0
  211. package/dist/workflow-runtime/paths.js +11 -0
  212. package/dist/workflow-runtime/template.d.ts +7 -0
  213. package/dist/workflow-runtime/template.d.ts.map +1 -0
  214. package/dist/workflow-runtime/template.js +94 -0
  215. package/dist/workflow-runtime/types.d.ts +68 -0
  216. package/dist/workflow-runtime/types.d.ts.map +1 -0
  217. package/dist/workflow-runtime/types.js +1 -0
  218. package/dist/workflow-runtime/validate.d.ts +8 -0
  219. package/dist/workflow-runtime/validate.d.ts.map +1 -0
  220. package/dist/workflow-runtime/validate.js +331 -0
  221. package/package.json +3 -3
@@ -32,6 +32,7 @@ export function protectedPathKindForFile(opts) {
32
32
  return "tasks";
33
33
  // "Rules of the game": authoring/agent policies and registry.
34
34
  if (p === "AGENTS.md" ||
35
+ p === "CLAUDE.md" ||
35
36
  p === "packages/agentplane/assets/AGENTS.md" ||
36
37
  pathIsUnder(p, ".agentplane/agents")) {
37
38
  return "policy";
@@ -1,3 +1,3 @@
1
- export declare const RUNTIME_GITIGNORE_LINES: readonly ["# agentplane: ignore runtime/transient workspace artifacts", ".env", ".agentplane/worktrees", ".agentplane/cache", ".agentplane/recipes-cache", ".agentplane/.upgrade", ".agentplane/.release", ".agentplane/upgrade", ".agentplane/tasks.json", "AGENTS.md.bak-*", ".agentplane/agents/*.bak-*"];
2
- export declare const AGENT_PROMPT_GITIGNORE_LINES: readonly ["# agentplane: ignore local agent prompts/templates", "AGENTS.md", ".agentplane/agents/"];
1
+ export declare const RUNTIME_GITIGNORE_LINES: readonly ["# agentplane: ignore runtime/transient workspace artifacts", ".env", ".agentplane/worktrees", ".agentplane/cache", ".agentplane/recipes-cache", ".agentplane/.upgrade", ".agentplane/.release", ".agentplane/upgrade", ".agentplane/tasks.json", "AGENTS.md.bak-*", "CLAUDE.md.bak-*", ".agentplane/agents/*.bak-*", ".agentplane/policy/**/*.bak-*"];
2
+ export declare const AGENT_PROMPT_GITIGNORE_LINES: readonly ["# agentplane: ignore local agent prompts/templates", "AGENTS.md", "CLAUDE.md", ".agentplane/agents/", ".agentplane/policy/"];
3
3
  //# sourceMappingURL=runtime-artifacts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-artifacts.d.ts","sourceRoot":"","sources":["../../src/shared/runtime-artifacts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,8SAY1B,CAAC;AAEX,eAAO,MAAM,4BAA4B,qGAI/B,CAAC"}
1
+ {"version":3,"file":"runtime-artifacts.d.ts","sourceRoot":"","sources":["../../src/shared/runtime-artifacts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB,kWAc1B,CAAC;AAEX,eAAO,MAAM,4BAA4B,yIAM/B,CAAC"}
@@ -9,10 +9,14 @@ export const RUNTIME_GITIGNORE_LINES = [
9
9
  ".agentplane/upgrade",
10
10
  ".agentplane/tasks.json",
11
11
  "AGENTS.md.bak-*",
12
+ "CLAUDE.md.bak-*",
12
13
  ".agentplane/agents/*.bak-*",
14
+ ".agentplane/policy/**/*.bak-*",
13
15
  ];
14
16
  export const AGENT_PROMPT_GITIGNORE_LINES = [
15
17
  "# agentplane: ignore local agent prompts/templates",
16
18
  "AGENTS.md",
19
+ "CLAUDE.md",
17
20
  ".agentplane/agents/",
21
+ ".agentplane/policy/",
18
22
  ];
@@ -0,0 +1,4 @@
1
+ import type { WorkflowBuildInput, WorkflowBuildOutput } from "./types.js";
2
+ export declare function buildWorkflowFromTemplates(input: WorkflowBuildInput): WorkflowBuildOutput;
3
+ export declare const DEFAULT_WORKFLOW_TEMPLATE = "---\nversion: 1\nmode: direct\nowners:\n orchestrator: ORCHESTRATOR\napprovals:\n require_plan: true\n require_verify: true\n require_network: true\nretry_policy:\n normal_exit_continuation: true\n abnormal_backoff: exponential\n max_attempts: 5\ntimeouts:\n stall_seconds: 900\nin_scope_paths:\n - packages/**\n---\n\n## Prompt Template\nRepository: {{ runtime.repo_name }}\nWorkflow mode: {{ workflow.mode }}\n\n## Checks\n- preflight\n- verify\n- finish\n\n## Fallback\nlast_known_good: .agentplane/workflows/last-known-good.md\n";
4
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/build.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAsB,MAAM,YAAY,CAAC;AAqC9F,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,CA4EzF;AAED,eAAO,MAAM,yBAAyB,kiBA8BrC,CAAC"}
@@ -0,0 +1,126 @@
1
+ import { parseWorkflowMarkdown, serializeWorkflowMarkdown } from "./markdown.js";
2
+ import { emitWorkflowEvent } from "./observability.js";
3
+ import { renderTemplateStrict, validateTemplateStrict } from "./template.js";
4
+ import { validateWorkflowDocument } from "./validate.js";
5
+ function mergeRecord(baseValue, overrideValue) {
6
+ const out = { ...baseValue };
7
+ for (const [key, value] of Object.entries(overrideValue)) {
8
+ if (value &&
9
+ typeof value === "object" &&
10
+ !Array.isArray(value) &&
11
+ out[key] &&
12
+ typeof out[key] === "object" &&
13
+ !Array.isArray(out[key])) {
14
+ out[key] = mergeRecord(out[key], value);
15
+ continue;
16
+ }
17
+ out[key] = value;
18
+ }
19
+ return out;
20
+ }
21
+ function mergeSections(baseSections, overrideSections) {
22
+ const out = { ...baseSections };
23
+ for (const [key, value] of Object.entries(overrideSections)) {
24
+ if (value.trim().length === 0)
25
+ continue;
26
+ out[key] = value;
27
+ }
28
+ return out;
29
+ }
30
+ export function buildWorkflowFromTemplates(input) {
31
+ emitWorkflowEvent({ event: "workflow_build_started" });
32
+ const diagnostics = [];
33
+ const base = parseWorkflowMarkdown(input.baseTemplate);
34
+ diagnostics.push(...base.diagnostics);
35
+ const override = input.projectOverrideTemplate
36
+ ? parseWorkflowMarkdown(input.projectOverrideTemplate)
37
+ : null;
38
+ if (override)
39
+ diagnostics.push(...override.diagnostics);
40
+ const mergedFrontMatter = mergeRecord(base.document.frontMatterRaw, override?.document.frontMatterRaw ?? {});
41
+ const runtimeWorkflow = input.runtimeContext.workflow;
42
+ if (runtimeWorkflow && typeof runtimeWorkflow === "object" && !Array.isArray(runtimeWorkflow)) {
43
+ const runtimeWorkflowRecord = runtimeWorkflow;
44
+ const runtimeMode = runtimeWorkflowRecord.mode;
45
+ if (runtimeMode === "direct" || runtimeMode === "branch_pr") {
46
+ mergedFrontMatter.mode = runtimeMode;
47
+ }
48
+ const runtimeApprovals = runtimeWorkflowRecord.approvals;
49
+ if (runtimeApprovals &&
50
+ typeof runtimeApprovals === "object" &&
51
+ !Array.isArray(runtimeApprovals)) {
52
+ const approvalsRecord = runtimeApprovals;
53
+ mergedFrontMatter.approvals = {
54
+ require_plan: approvalsRecord.require_plan === true,
55
+ require_verify: approvalsRecord.require_verify === true,
56
+ require_network: approvalsRecord.require_network === true,
57
+ };
58
+ }
59
+ }
60
+ const mergedSections = mergeSections(base.document.sections, override?.document.sections ?? {});
61
+ const promptTemplate = mergedSections["Prompt Template"] ?? "";
62
+ const strict = validateTemplateStrict(promptTemplate, input.runtimeContext, {
63
+ strictVariables: true,
64
+ strictFilters: true,
65
+ });
66
+ diagnostics.push(...strict.diagnostics);
67
+ const renderedPrompt = renderTemplateStrict(promptTemplate, input.runtimeContext, {
68
+ strictVariables: true,
69
+ strictFilters: true,
70
+ });
71
+ diagnostics.push(...renderedPrompt.diagnostics);
72
+ mergedSections["Prompt Template"] = renderedPrompt.text;
73
+ const renderedText = serializeWorkflowMarkdown(mergedFrontMatter, mergedSections);
74
+ const parsedRendered = parseWorkflowMarkdown(renderedText);
75
+ diagnostics.push(...parsedRendered.diagnostics);
76
+ const schema = validateWorkflowDocument(parsedRendered.document);
77
+ diagnostics.push(...schema.diagnostics);
78
+ const hasError = diagnostics.some((d) => d.severity === "ERROR");
79
+ if (hasError) {
80
+ emitWorkflowEvent({
81
+ event: "workflow_build_failed",
82
+ details: { diagnostics: diagnostics.length },
83
+ });
84
+ }
85
+ else {
86
+ emitWorkflowEvent({
87
+ event: "workflow_build_completed",
88
+ details: { diagnostics: diagnostics.length },
89
+ });
90
+ }
91
+ return {
92
+ text: renderedText,
93
+ diagnostics,
94
+ };
95
+ }
96
+ export const DEFAULT_WORKFLOW_TEMPLATE = `---
97
+ version: 1
98
+ mode: direct
99
+ owners:
100
+ orchestrator: ORCHESTRATOR
101
+ approvals:
102
+ require_plan: true
103
+ require_verify: true
104
+ require_network: true
105
+ retry_policy:
106
+ normal_exit_continuation: true
107
+ abnormal_backoff: exponential
108
+ max_attempts: 5
109
+ timeouts:
110
+ stall_seconds: 900
111
+ in_scope_paths:
112
+ - packages/**
113
+ ---
114
+
115
+ ## Prompt Template
116
+ Repository: {{ runtime.repo_name }}
117
+ Workflow mode: {{ workflow.mode }}
118
+
119
+ ## Checks
120
+ - preflight
121
+ - verify
122
+ - finish
123
+
124
+ ## Fallback
125
+ last_known_good: .agentplane/workflows/last-known-good.md
126
+ `;
@@ -0,0 +1,3 @@
1
+ export declare function isWorkflowEnforcementDisabled(env?: NodeJS.ProcessEnv): boolean;
2
+ export declare function workflowEnforcementEnvHint(): string;
3
+ //# sourceMappingURL=enforcement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcement.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/enforcement.ts"],"names":[],"mappings":"AAEA,wBAAgB,6BAA6B,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAI3F;AAED,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD"}
@@ -0,0 +1,10 @@
1
+ const DISABLED_VALUES = new Set(["0", "false", "off", "disabled"]);
2
+ export function isWorkflowEnforcementDisabled(env = process.env) {
3
+ const raw = env.AGENTPLANE_WORKFLOW_ENFORCEMENT ?? env.AGENTPLANE_WORKFLOW_CONTRACT;
4
+ if (typeof raw !== "string")
5
+ return false;
6
+ return DISABLED_VALUES.has(raw.trim().toLowerCase());
7
+ }
8
+ export function workflowEnforcementEnvHint() {
9
+ return "AGENTPLANE_WORKFLOW_ENFORCEMENT";
10
+ }
@@ -0,0 +1,11 @@
1
+ import type { WorkflowDiagnostic, WorkflowDocument, WorkflowValidationResult } from "./types.js";
2
+ export declare function readWorkflowDocument(repoRoot: string, absPath?: string): Promise<{
3
+ document: WorkflowDocument | null;
4
+ diagnostics: WorkflowDiagnostic[];
5
+ path: string;
6
+ }>;
7
+ export declare function validateWorkflowAtPath(repoRoot: string, absPath?: string): Promise<WorkflowValidationResult>;
8
+ export declare function validateWorkflowText(repoRoot: string, workflowText: string): Promise<WorkflowValidationResult>;
9
+ export declare function publishWorkflowCandidate(repoRoot: string, candidateText: string): Promise<WorkflowValidationResult>;
10
+ export declare function restoreWorkflowFromLastKnownGood(repoRoot: string): Promise<WorkflowValidationResult>;
11
+ //# sourceMappingURL=file-ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-ops.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/file-ops.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAiDjG,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAAC,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BjG;AAED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,CAAC,CAuBnC;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,wBAAwB,CAAC,CAanC;AAED,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,wBAAwB,CAAC,CA0DnC;AAED,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,CAAC,CA6EnC"}
@@ -0,0 +1,248 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { loadConfig } from "@agentplaneorg/core";
4
+ import { parseWorkflowMarkdown } from "./markdown.js";
5
+ import { emitWorkflowEvent } from "./observability.js";
6
+ import { resolveWorkflowPaths } from "./paths.js";
7
+ import { validateWorkflowDocument } from "./validate.js";
8
+ async function pathExists(absPath) {
9
+ try {
10
+ await fs.access(absPath);
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ async function resolveWorkflowReadPath(paths) {
18
+ if (await pathExists(paths.workflowPath))
19
+ return paths.workflowPath;
20
+ if (await pathExists(paths.legacyWorkflowPath))
21
+ return paths.legacyWorkflowPath;
22
+ return paths.workflowPath;
23
+ }
24
+ async function removeLegacyWorkflowIfPresent(paths) {
25
+ if (paths.workflowPath === paths.legacyWorkflowPath)
26
+ return;
27
+ try {
28
+ await fs.rm(paths.legacyWorkflowPath, { force: true });
29
+ }
30
+ catch {
31
+ // best effort cleanup
32
+ }
33
+ }
34
+ async function listAgentIds(agentplaneDir) {
35
+ const ids = new Set();
36
+ const dir = path.join(agentplaneDir, "agents");
37
+ try {
38
+ const entries = await fs.readdir(dir, { withFileTypes: true });
39
+ for (const ent of entries) {
40
+ if (ent.isFile() && ent.name.endsWith(".json")) {
41
+ ids.add(ent.name.replace(/\.json$/i, ""));
42
+ }
43
+ }
44
+ }
45
+ catch {
46
+ // best effort
47
+ }
48
+ return ids;
49
+ }
50
+ export async function readWorkflowDocument(repoRoot, absPath) {
51
+ const paths = resolveWorkflowPaths(repoRoot);
52
+ const targetPath = absPath ?? (await resolveWorkflowReadPath(paths));
53
+ try {
54
+ const content = await fs.readFile(targetPath, "utf8");
55
+ const parsed = parseWorkflowMarkdown(content, targetPath);
56
+ return {
57
+ document: parsed.document,
58
+ diagnostics: parsed.diagnostics,
59
+ path: targetPath,
60
+ };
61
+ }
62
+ catch (error) {
63
+ return {
64
+ document: null,
65
+ diagnostics: [
66
+ {
67
+ code: (await pathExists(targetPath)) ? "WF_READ_FAILED" : "WF_MISSING_FILE",
68
+ severity: "ERROR",
69
+ path: "file",
70
+ message: `Cannot read workflow file ${targetPath}: ${error instanceof Error ? error.message : String(error)}`,
71
+ },
72
+ ],
73
+ path: targetPath,
74
+ };
75
+ }
76
+ }
77
+ export async function validateWorkflowAtPath(repoRoot, absPath) {
78
+ const read = await readWorkflowDocument(repoRoot, absPath);
79
+ const diagnostics = [...read.diagnostics];
80
+ if (!read.document) {
81
+ return {
82
+ ok: false,
83
+ diagnostics,
84
+ };
85
+ }
86
+ const loaded = await loadConfig(path.join(repoRoot, ".agentplane"));
87
+ const knownAgentIds = await listAgentIds(path.join(repoRoot, ".agentplane"));
88
+ const validated = validateWorkflowDocument(read.document, {
89
+ repoRoot,
90
+ knownAgentIds,
91
+ config: loaded.config,
92
+ });
93
+ diagnostics.push(...validated.diagnostics);
94
+ return {
95
+ ok: diagnostics.every((d) => d.severity !== "ERROR"),
96
+ diagnostics,
97
+ };
98
+ }
99
+ export async function validateWorkflowText(repoRoot, workflowText) {
100
+ const parsed = parseWorkflowMarkdown(workflowText);
101
+ const loaded = await loadConfig(path.join(repoRoot, ".agentplane"));
102
+ const knownAgentIds = await listAgentIds(path.join(repoRoot, ".agentplane"));
103
+ const validated = validateWorkflowDocument(parsed.document, {
104
+ repoRoot,
105
+ knownAgentIds,
106
+ config: loaded.config,
107
+ });
108
+ return {
109
+ ok: [...parsed.diagnostics, ...validated.diagnostics].every((d) => d.severity !== "ERROR"),
110
+ diagnostics: [...parsed.diagnostics, ...validated.diagnostics],
111
+ };
112
+ }
113
+ export async function publishWorkflowCandidate(repoRoot, candidateText) {
114
+ const paths = resolveWorkflowPaths(repoRoot);
115
+ const tempPath = `${paths.workflowPath}.tmp.${Date.now()}`;
116
+ const parsed = parseWorkflowMarkdown(candidateText, paths.workflowPath);
117
+ const configLoaded = await loadConfig(path.join(repoRoot, ".agentplane"));
118
+ const validation = validateWorkflowDocument(parsed.document, {
119
+ repoRoot,
120
+ knownAgentIds: await listAgentIds(path.join(repoRoot, ".agentplane")),
121
+ config: configLoaded.config,
122
+ });
123
+ const diagnostics = [...parsed.diagnostics, ...validation.diagnostics];
124
+ if (diagnostics.some((d) => d.severity === "ERROR")) {
125
+ emitWorkflowEvent({
126
+ event: "workflow_publish_failed",
127
+ code: "WF_PARSE_ERROR",
128
+ details: { reason: "validation failed before publish", diagnostics: diagnostics.length },
129
+ });
130
+ return { ok: false, diagnostics };
131
+ }
132
+ try {
133
+ await fs.mkdir(path.dirname(paths.workflowPath), { recursive: true });
134
+ await fs.mkdir(paths.workflowDir, { recursive: true });
135
+ await fs.writeFile(tempPath, candidateText, "utf8");
136
+ await fs.rename(tempPath, paths.workflowPath);
137
+ await removeLegacyWorkflowIfPresent(paths);
138
+ await fs.copyFile(paths.workflowPath, paths.lastKnownGoodPath);
139
+ emitWorkflowEvent({
140
+ event: "workflow_publish_completed",
141
+ details: { workflowPath: paths.workflowPath, lastKnownGoodPath: paths.lastKnownGoodPath },
142
+ });
143
+ return { ok: true, diagnostics };
144
+ }
145
+ catch (error) {
146
+ try {
147
+ await fs.rm(tempPath, { force: true });
148
+ }
149
+ catch {
150
+ // best effort cleanup
151
+ }
152
+ emitWorkflowEvent({
153
+ event: "workflow_publish_failed",
154
+ code: "WF_READ_FAILED",
155
+ details: { reason: error instanceof Error ? error.message : String(error) },
156
+ });
157
+ return {
158
+ ok: false,
159
+ diagnostics: [
160
+ ...diagnostics,
161
+ {
162
+ code: "WF_READ_FAILED",
163
+ severity: "ERROR",
164
+ path: "file",
165
+ message: `Failed to atomically publish workflow: ${error instanceof Error ? error.message : String(error)}`,
166
+ },
167
+ ],
168
+ };
169
+ }
170
+ }
171
+ export async function restoreWorkflowFromLastKnownGood(repoRoot) {
172
+ const paths = resolveWorkflowPaths(repoRoot);
173
+ const tempPath = `${paths.workflowPath}.restore.tmp.${Date.now()}`;
174
+ let lkgText = "";
175
+ try {
176
+ lkgText = await fs.readFile(paths.lastKnownGoodPath, "utf8");
177
+ }
178
+ catch (error) {
179
+ emitWorkflowEvent({
180
+ event: "workflow_restore_failed",
181
+ code: "WF_MISSING_FILE",
182
+ details: { reason: error instanceof Error ? error.message : String(error) },
183
+ });
184
+ return {
185
+ ok: false,
186
+ diagnostics: [
187
+ {
188
+ code: "WF_MISSING_FILE",
189
+ severity: "ERROR",
190
+ path: "file",
191
+ message: `Missing last-known-good workflow snapshot at ${paths.lastKnownGoodPath}`,
192
+ },
193
+ ],
194
+ };
195
+ }
196
+ const parsed = parseWorkflowMarkdown(lkgText, paths.lastKnownGoodPath);
197
+ const configLoaded = await loadConfig(path.join(repoRoot, ".agentplane"));
198
+ const validated = validateWorkflowDocument(parsed.document, {
199
+ repoRoot,
200
+ knownAgentIds: await listAgentIds(path.join(repoRoot, ".agentplane")),
201
+ config: configLoaded.config,
202
+ });
203
+ const diagnostics = [...parsed.diagnostics, ...validated.diagnostics];
204
+ if (diagnostics.some((d) => d.severity === "ERROR")) {
205
+ emitWorkflowEvent({
206
+ event: "workflow_restore_failed",
207
+ code: "WF_PARSE_ERROR",
208
+ details: { reason: "last-known-good validation failed" },
209
+ });
210
+ return { ok: false, diagnostics };
211
+ }
212
+ try {
213
+ await fs.mkdir(path.dirname(paths.workflowPath), { recursive: true });
214
+ await fs.writeFile(tempPath, lkgText, "utf8");
215
+ await fs.rename(tempPath, paths.workflowPath);
216
+ await removeLegacyWorkflowIfPresent(paths);
217
+ emitWorkflowEvent({
218
+ event: "workflow_restore_completed",
219
+ details: { workflowPath: paths.workflowPath, from: paths.lastKnownGoodPath },
220
+ });
221
+ return { ok: true, diagnostics };
222
+ }
223
+ catch (error) {
224
+ try {
225
+ await fs.rm(tempPath, { force: true });
226
+ }
227
+ catch {
228
+ // best effort cleanup
229
+ }
230
+ emitWorkflowEvent({
231
+ event: "workflow_restore_failed",
232
+ code: "WF_READ_FAILED",
233
+ details: { reason: error instanceof Error ? error.message : String(error) },
234
+ });
235
+ return {
236
+ ok: false,
237
+ diagnostics: [
238
+ ...diagnostics,
239
+ {
240
+ code: "WF_READ_FAILED",
241
+ severity: "ERROR",
242
+ path: "file",
243
+ message: `Failed to restore workflow from snapshot: ${error instanceof Error ? error.message : String(error)}`,
244
+ },
245
+ ],
246
+ };
247
+ }
248
+ }
@@ -0,0 +1,9 @@
1
+ import type { WorkflowDiagnostic } from "./types.js";
2
+ type WorkflowFixResult = {
3
+ changed: boolean;
4
+ text: string;
5
+ diagnostics: WorkflowDiagnostic[];
6
+ };
7
+ export declare function safeAutofixWorkflowText(text: string): WorkflowFixResult;
8
+ export {};
9
+ //# sourceMappingURL=fix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/fix.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,YAAY,CAAC;AAE1E,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC,CAAC;AAoFF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA6CvE"}
@@ -0,0 +1,107 @@
1
+ import { parseWorkflowMarkdown, serializeWorkflowMarkdown } from "./markdown.js";
2
+ const DEFAULT_FRONT_MATTER = {
3
+ version: 1,
4
+ mode: "direct",
5
+ owners: { orchestrator: "ORCHESTRATOR" },
6
+ approvals: {
7
+ require_plan: true,
8
+ require_verify: true,
9
+ require_network: true,
10
+ },
11
+ retry_policy: {
12
+ normal_exit_continuation: true,
13
+ abnormal_backoff: "exponential",
14
+ max_attempts: 5,
15
+ },
16
+ timeouts: {
17
+ stall_seconds: 900,
18
+ },
19
+ in_scope_paths: ["packages/**"],
20
+ };
21
+ function isRecord(value) {
22
+ return !!value && typeof value === "object" && !Array.isArray(value);
23
+ }
24
+ function withDefaults(raw) {
25
+ const out = { ...raw };
26
+ if (typeof out.version !== "number" || !Number.isInteger(out.version) || out.version < 1) {
27
+ out.version = 1;
28
+ }
29
+ if (out.mode !== "direct" && out.mode !== "branch_pr") {
30
+ out.mode = DEFAULT_FRONT_MATTER.mode;
31
+ }
32
+ const owners = isRecord(out.owners) ? { ...out.owners } : {};
33
+ if (typeof owners.orchestrator !== "string" || owners.orchestrator.trim().length === 0) {
34
+ owners.orchestrator = DEFAULT_FRONT_MATTER.owners.orchestrator;
35
+ }
36
+ out.owners = owners;
37
+ const approvals = isRecord(out.approvals) ? { ...out.approvals } : {};
38
+ for (const key of ["require_plan", "require_verify", "require_network"]) {
39
+ if (typeof approvals[key] !== "boolean")
40
+ approvals[key] = DEFAULT_FRONT_MATTER.approvals[key];
41
+ }
42
+ out.approvals = approvals;
43
+ const retryPolicy = isRecord(out.retry_policy) ? { ...out.retry_policy } : {};
44
+ if (typeof retryPolicy.normal_exit_continuation !== "boolean") {
45
+ retryPolicy.normal_exit_continuation =
46
+ DEFAULT_FRONT_MATTER.retry_policy.normal_exit_continuation;
47
+ }
48
+ if (retryPolicy.abnormal_backoff !== "exponential") {
49
+ retryPolicy.abnormal_backoff = DEFAULT_FRONT_MATTER.retry_policy.abnormal_backoff;
50
+ }
51
+ if (typeof retryPolicy.max_attempts !== "number" ||
52
+ !Number.isInteger(retryPolicy.max_attempts) ||
53
+ retryPolicy.max_attempts < 1) {
54
+ retryPolicy.max_attempts = DEFAULT_FRONT_MATTER.retry_policy.max_attempts;
55
+ }
56
+ out.retry_policy = retryPolicy;
57
+ const timeouts = isRecord(out.timeouts) ? { ...out.timeouts } : {};
58
+ if (typeof timeouts.stall_seconds !== "number" ||
59
+ !Number.isInteger(timeouts.stall_seconds) ||
60
+ timeouts.stall_seconds < 1) {
61
+ timeouts.stall_seconds = DEFAULT_FRONT_MATTER.timeouts.stall_seconds;
62
+ }
63
+ out.timeouts = timeouts;
64
+ const inScope = Array.isArray(out.in_scope_paths)
65
+ ? out.in_scope_paths.filter((v) => typeof v === "string" && v.trim().length > 0)
66
+ : [];
67
+ out.in_scope_paths = inScope.length > 0 ? inScope : DEFAULT_FRONT_MATTER.in_scope_paths;
68
+ return out;
69
+ }
70
+ export function safeAutofixWorkflowText(text) {
71
+ const parsed = parseWorkflowMarkdown(text);
72
+ const diagnostics = [];
73
+ const unknownKeyDiagnostics = Object.keys(parsed.document.frontMatterRaw)
74
+ .filter((key) => ![
75
+ "version",
76
+ "mode",
77
+ "owners",
78
+ "approvals",
79
+ "retry_policy",
80
+ "timeouts",
81
+ "in_scope_paths",
82
+ ].includes(key))
83
+ .map((key) => ({
84
+ code: "WF_FIX_SKIPPED_UNSAFE",
85
+ severity: "WARN",
86
+ path: `front_matter.${key}`,
87
+ message: `Unsafe autofix skipped for unknown key: ${key}`,
88
+ }));
89
+ diagnostics.push(...unknownKeyDiagnostics);
90
+ if (unknownKeyDiagnostics.length > 0) {
91
+ return { changed: false, text, diagnostics };
92
+ }
93
+ const nextFrontMatter = withDefaults(parsed.document.frontMatterRaw);
94
+ const sections = {
95
+ ...parsed.document.sections,
96
+ "Prompt Template": parsed.document.sections["Prompt Template"] ?? "",
97
+ Checks: parsed.document.sections.Checks ?? "- preflight\n- verify\n- finish",
98
+ Fallback: parsed.document.sections.Fallback ??
99
+ "last_known_good: .agentplane/workflows/last-known-good.md",
100
+ };
101
+ const nextText = serializeWorkflowMarkdown(nextFrontMatter, sections);
102
+ return {
103
+ changed: nextText !== text,
104
+ text: nextText,
105
+ diagnostics,
106
+ };
107
+ }
@@ -0,0 +1,11 @@
1
+ export * from "./types.js";
2
+ export * from "./paths.js";
3
+ export * from "./observability.js";
4
+ export * from "./enforcement.js";
5
+ export * from "./markdown.js";
6
+ export * from "./validate.js";
7
+ export * from "./template.js";
8
+ export * from "./build.js";
9
+ export * from "./file-ops.js";
10
+ export * from "./fix.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
@@ -0,0 +1,10 @@
1
+ export * from "./types.js";
2
+ export * from "./paths.js";
3
+ export * from "./observability.js";
4
+ export * from "./enforcement.js";
5
+ export * from "./markdown.js";
6
+ export * from "./validate.js";
7
+ export * from "./template.js";
8
+ export * from "./build.js";
9
+ export * from "./file-ops.js";
10
+ export * from "./fix.js";
@@ -0,0 +1,10 @@
1
+ import type { WorkflowDiagnostic, WorkflowDocument, WorkflowFrontMatter, WorkflowSections, WorkflowValidationResult } from "./types.js";
2
+ export declare function parseWorkflowMarkdown(text: string, sourcePath?: string): {
3
+ document: Omit<WorkflowDocument, "frontMatter"> & {
4
+ frontMatter: WorkflowFrontMatter;
5
+ };
6
+ diagnostics: WorkflowDiagnostic[];
7
+ };
8
+ export declare function serializeWorkflowMarkdown(frontMatter: Record<string, unknown>, sections: WorkflowSections): string;
9
+ export declare function diagnosticsToValidationResult(diagnostics: WorkflowDiagnostic[]): WorkflowValidationResult;
10
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/workflow-runtime/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAmHpB,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB;IACD,QAAQ,EAAE,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,GAAG;QAAE,WAAW,EAAE,mBAAmB,CAAA;KAAE,CAAC;IACvF,WAAW,EAAE,kBAAkB,EAAE,CAAC;CACnC,CAmBA;AAOD,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,QAAQ,EAAE,gBAAgB,GACzB,MAAM,CAkBR;AAED,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,kBAAkB,EAAE,GAChC,wBAAwB,CAM1B"}