@open-agent-toolkit/cli 0.1.41 → 0.1.43
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.
- package/assets/agents/oat-phase-implementer.md +13 -9
- package/assets/agents/oat-reviewer.md +16 -12
- package/assets/docs/cli-utilities/configuration.md +51 -35
- package/assets/docs/cli-utilities/workflow-gates.md +55 -0
- package/assets/docs/reference/cli-reference.md +1 -1
- package/assets/docs/reference/oat-directory-structure.md +26 -24
- package/assets/docs/workflows/projects/artifacts.md +22 -0
- package/assets/docs/workflows/projects/dispatch-ceiling.md +128 -85
- package/assets/docs/workflows/projects/hill-checkpoints.md +2 -0
- package/assets/docs/workflows/projects/implementation-execution.md +70 -46
- package/assets/docs/workflows/projects/index.md +2 -2
- package/assets/docs/workflows/projects/lifecycle.md +17 -2
- package/assets/docs/workflows/projects/reviews.md +17 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-project-implement/SKILL.md +256 -95
- package/assets/skills/oat-project-plan/SKILL.md +60 -29
- package/assets/skills/oat-project-plan-writing/SKILL.md +10 -10
- package/assets/skills/oat-project-quick-start/SKILL.md +60 -29
- package/assets/skills/oat-project-review-provide/SKILL.md +25 -13
- package/assets/skills/oat-project-review-receive/SKILL.md +20 -10
- package/assets/skills/oat-review-provide/SKILL.md +14 -12
- package/assets/skills/oat-review-provide/references/review-artifact-template.md +1 -1
- package/assets/templates/plan.md +4 -4
- package/assets/templates/state.md +7 -3
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +66 -3
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +15 -3
- package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch-ceiling/index.js +296 -49
- package/dist/commands/review/latest.d.ts.map +1 -1
- package/dist/commands/review/latest.js +5 -2
- package/dist/commands/shared/frontmatter.d.ts +11 -0
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +15 -0
- package/dist/config/dispatch-ceiling-preset.d.ts +37 -1
- package/dist/config/dispatch-ceiling-preset.d.ts.map +1 -1
- package/dist/config/dispatch-ceiling-preset.js +20 -0
- package/dist/config/oat-config.d.ts +10 -1
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +20 -1
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +4 -0
- package/dist/providers/ceiling/registry.d.ts.map +1 -1
- package/dist/providers/ceiling/registry.js +6 -1
- package/dist/providers/codex/codec/sync-extension.js +1 -1
- package/package.json +2 -2
|
@@ -43,6 +43,8 @@ const KEY_ORDER = [
|
|
|
43
43
|
'workflow.autoArtifactReview.plan',
|
|
44
44
|
'workflow.autoArtifactReview.analysis',
|
|
45
45
|
'workflow.designMode',
|
|
46
|
+
'workflow.dispatchPolicy.mode',
|
|
47
|
+
'workflow.dispatchPolicy.policy',
|
|
46
48
|
'workflow.dispatchCeiling.preset',
|
|
47
49
|
'workflow.dispatchCeiling.providers.codex',
|
|
48
50
|
'workflow.dispatchCeiling.providers.claude',
|
|
@@ -454,7 +456,29 @@ const CONFIG_CATALOG = [
|
|
|
454
456
|
defaultValue: 'unset',
|
|
455
457
|
mutability: 'read/write',
|
|
456
458
|
owningCommand: 'oat config set workflow.dispatchCeiling.preset <value>',
|
|
457
|
-
description: 'Provider-neutral ceiling preset that compiles to concrete per-provider values at write time. balanced → Codex: high, Claude: sonnet; maximum → Codex: xhigh, Claude: opus; cost-conscious → Codex: medium, Claude: sonnet. Preset provenance only; runtime dispatch reads concrete providers values. Resolution: local > shared > user > default.',
|
|
459
|
+
description: 'Legacy compatibility alias for capped managed dispatch policies. Provider-neutral ceiling preset that compiles to concrete per-provider values at write time. balanced → Codex: high, Claude: sonnet; maximum → Codex: xhigh, Claude: opus; cost-conscious → Codex: medium, Claude: sonnet. Preset provenance only; runtime dispatch reads concrete providers values. Resolution: local > shared > user > default.',
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
key: 'workflow.dispatchPolicy.mode',
|
|
463
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
464
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
465
|
+
scope: 'workflow',
|
|
466
|
+
type: 'managed | inherit',
|
|
467
|
+
defaultValue: 'unset',
|
|
468
|
+
mutability: 'read/write',
|
|
469
|
+
owningCommand: 'oat config set workflow.dispatchPolicy.mode <value>',
|
|
470
|
+
description: 'Dispatch policy mode. "managed" means OAT selects model/effort from workflow.dispatchPolicy.policy; "inherit" means OAT leaves dispatch controls to the host/provider defaults. Set workflow.dispatchPolicy.policy to choose a managed policy. Resolution: local > shared > user > default.',
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
key: 'workflow.dispatchPolicy.policy',
|
|
474
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
475
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
476
|
+
scope: 'workflow',
|
|
477
|
+
type: 'economy | balanced | high | frontier | uncapped',
|
|
478
|
+
defaultValue: 'unset',
|
|
479
|
+
mutability: 'read/write',
|
|
480
|
+
owningCommand: 'oat config set workflow.dispatchPolicy.policy <value>',
|
|
481
|
+
description: 'Managed dispatch policy. economy, balanced, high, and frontier are capped managed policies; uncapped keeps OAT-managed preferred selection without provider caps. Setting this key writes workflow.dispatchPolicy.mode=managed. Resolution: local > shared > user > default.',
|
|
458
482
|
},
|
|
459
483
|
{
|
|
460
484
|
key: 'workflow.dispatchCeiling.providers.codex',
|
|
@@ -472,7 +496,7 @@ const CONFIG_CATALOG = [
|
|
|
472
496
|
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
473
497
|
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
474
498
|
scope: 'workflow',
|
|
475
|
-
type: 'haiku | sonnet | opus',
|
|
499
|
+
type: 'haiku | sonnet | opus | fable',
|
|
476
500
|
defaultValue: 'unset',
|
|
477
501
|
mutability: 'read/write',
|
|
478
502
|
owningCommand: 'oat config set workflow.dispatchCeiling.providers.claude <value>',
|
|
@@ -540,6 +564,14 @@ const WORKFLOW_ENUM_VALUES = {
|
|
|
540
564
|
'workflow.postImplementSequence': ['wait', 'summary', 'pr', 'docs-pr'],
|
|
541
565
|
'workflow.reviewExecutionModel': ['subagent', 'inline', 'fresh-session'],
|
|
542
566
|
'workflow.designMode': ['collaborative', 'selective', 'draft'],
|
|
567
|
+
'workflow.dispatchPolicy.mode': ['managed', 'inherit'],
|
|
568
|
+
'workflow.dispatchPolicy.policy': [
|
|
569
|
+
'economy',
|
|
570
|
+
'balanced',
|
|
571
|
+
'high',
|
|
572
|
+
'frontier',
|
|
573
|
+
'uncapped',
|
|
574
|
+
],
|
|
543
575
|
'workflow.dispatchCeiling.preset': ['balanced', 'maximum', 'cost-conscious'],
|
|
544
576
|
'workflow.dispatchCeiling.providers.codex': [
|
|
545
577
|
'low',
|
|
@@ -547,7 +579,12 @@ const WORKFLOW_ENUM_VALUES = {
|
|
|
547
579
|
'high',
|
|
548
580
|
'xhigh',
|
|
549
581
|
],
|
|
550
|
-
'workflow.dispatchCeiling.providers.claude': [
|
|
582
|
+
'workflow.dispatchCeiling.providers.claude': [
|
|
583
|
+
'haiku',
|
|
584
|
+
'sonnet',
|
|
585
|
+
'opus',
|
|
586
|
+
'fable',
|
|
587
|
+
],
|
|
551
588
|
};
|
|
552
589
|
const WORKFLOW_BOOLEAN_KEYS = new Set([
|
|
553
590
|
'workflow.archiveOnComplete',
|
|
@@ -633,6 +670,32 @@ function parseWorkflowValue(key, rawValue) {
|
|
|
633
670
|
}
|
|
634
671
|
function applyWorkflowValue(workflow, key, value) {
|
|
635
672
|
const subKey = key.slice('workflow.'.length);
|
|
673
|
+
if (subKey === 'dispatchPolicy.mode') {
|
|
674
|
+
const mode = value;
|
|
675
|
+
if (mode === 'inherit') {
|
|
676
|
+
return {
|
|
677
|
+
...workflow,
|
|
678
|
+
dispatchPolicy: { mode },
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
const policy = workflow.dispatchPolicy?.policy;
|
|
682
|
+
if (!policy) {
|
|
683
|
+
throw new Error('Cannot set workflow.dispatchPolicy.mode to managed without an existing workflow.dispatchPolicy.policy. Set workflow.dispatchPolicy.policy <economy|balanced|high|frontier|uncapped> instead.');
|
|
684
|
+
}
|
|
685
|
+
return {
|
|
686
|
+
...workflow,
|
|
687
|
+
dispatchPolicy: { mode, policy },
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
if (subKey === 'dispatchPolicy.policy') {
|
|
691
|
+
return {
|
|
692
|
+
...workflow,
|
|
693
|
+
dispatchPolicy: {
|
|
694
|
+
mode: 'managed',
|
|
695
|
+
policy: value,
|
|
696
|
+
},
|
|
697
|
+
};
|
|
698
|
+
}
|
|
636
699
|
if (subKey === 'dispatchCeiling.preset') {
|
|
637
700
|
// Presets compile to concrete per-provider values at write time so the
|
|
638
701
|
// resolver (which reads only providers.*) gets a usable ceiling. The preset
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAQL,KAAK,UAAU,EAIf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,UAAU,uBAAuB;IAC/B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,UAAU,EAAE,CACV,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AA0CD,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS,CAAC;IACvD,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,kBAAkB,GAAG,cAAc,GAAG,MAAM,CAAC;AAMlD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACpB;AAyZD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAC9C,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,kBAAkB,GACxB,kBAAkB,GAAG,IAAI,CAE3B;AAu7BD,wBAAgB,iBAAiB,CAC/B,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAwKT"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { readdir, readFile } from 'node:fs/promises';
|
|
4
4
|
import { basename, isAbsolute, join, relative } from 'node:path';
|
|
5
5
|
import { buildCommandContext, } from '../../app/command-context.js';
|
|
6
|
-
import { getFrontmatterBlock, getFrontmatterField, } from '../shared/frontmatter.js';
|
|
6
|
+
import { getFrontmatterBlock, getFrontmatterField, parseGeneratedTime, } from '../shared/frontmatter.js';
|
|
7
7
|
import { readGlobalOptions } from '../shared/shared.utils.js';
|
|
8
8
|
import { BUILTIN_EXEC_TARGETS, readOatConfig, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
|
|
9
9
|
import { resolveEffectiveConfig, resolveExecTargets, resolveGate, } from '../../config/resolve.js';
|
|
@@ -502,7 +502,7 @@ async function readReviewGateArtifactCandidate(repoRoot, relativePath) {
|
|
|
502
502
|
if (!generatedAt) {
|
|
503
503
|
return null;
|
|
504
504
|
}
|
|
505
|
-
const generatedTime =
|
|
505
|
+
const generatedTime = parseGeneratedTime(generatedAt);
|
|
506
506
|
if (Number.isNaN(generatedTime)) {
|
|
507
507
|
return null;
|
|
508
508
|
}
|
|
@@ -616,6 +616,7 @@ function writeReviewGateResult(context, payload) {
|
|
|
616
616
|
else {
|
|
617
617
|
context.logger.info('Review completed and gate passed.');
|
|
618
618
|
}
|
|
619
|
+
context.logger.info(`Run: ${payload.runId} (generated ${payload.generatedAt})`);
|
|
619
620
|
context.logger.info(`Review artifact: ${payload.artifactPath}`);
|
|
620
621
|
if (payload.normalization) {
|
|
621
622
|
context.logger.info(`Artifact normalized: inserted ${payload.normalization.insertedSeverities.map((severity) => severityDisplayName(severity)).join(', ')} empty Findings section(s).`);
|
|
@@ -629,6 +630,7 @@ function writeReviewGateExecutionFailure(context, payload) {
|
|
|
629
630
|
context.logger.json({
|
|
630
631
|
status: 'review_failed',
|
|
631
632
|
outcome: 'review_did_not_complete',
|
|
633
|
+
runId: payload.runId,
|
|
632
634
|
target: payload.target,
|
|
633
635
|
project: payload.project,
|
|
634
636
|
exitCode: payload.exitCode,
|
|
@@ -643,9 +645,11 @@ function writeReviewGateArtifactValidationFailure(context, payload) {
|
|
|
643
645
|
context.logger.json({
|
|
644
646
|
status: 'artifact_validation_failed',
|
|
645
647
|
outcome: 'review_completed_artifact_validation_failed',
|
|
648
|
+
runId: payload.runId,
|
|
646
649
|
target: payload.target,
|
|
647
650
|
project: payload.project,
|
|
648
651
|
artifactPath: payload.artifactPath,
|
|
652
|
+
generatedAt: payload.generatedAt,
|
|
649
653
|
message: payload.message,
|
|
650
654
|
recovery: payload.recovery,
|
|
651
655
|
});
|
|
@@ -755,6 +759,7 @@ async function runCrossProviderExec(prompt, options, context, dependencies) {
|
|
|
755
759
|
}
|
|
756
760
|
}
|
|
757
761
|
async function runReviewGate(prompt, options, context, dependencies) {
|
|
762
|
+
const runId = randomUUID();
|
|
758
763
|
try {
|
|
759
764
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
760
765
|
const userConfigDir = join(context.home, '.oat');
|
|
@@ -785,6 +790,7 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
785
790
|
const childExitCode = await executeTarget(selected, [reviewPrompt], context, dependencies);
|
|
786
791
|
if (childExitCode !== 0) {
|
|
787
792
|
writeReviewGateExecutionFailure(context, {
|
|
793
|
+
runId,
|
|
788
794
|
target: selected.id,
|
|
789
795
|
project: projectPath,
|
|
790
796
|
exitCode: childExitCode,
|
|
@@ -799,9 +805,11 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
799
805
|
const producedArtifact = findProducedReviewArtifact(before, after);
|
|
800
806
|
if (!producedArtifact) {
|
|
801
807
|
writeReviewGateArtifactValidationFailure(context, {
|
|
808
|
+
runId,
|
|
802
809
|
target: selected.id,
|
|
803
810
|
project: projectPath,
|
|
804
811
|
artifactPath: null,
|
|
812
|
+
generatedAt: null,
|
|
805
813
|
message: `No new review artifact was detected for project ${projectPath}.`,
|
|
806
814
|
recovery: 'Ensure the review provider wrote a project review artifact. If it did, fix or attach that artifact and run oat-project-review-receive before treating the review as consumed.',
|
|
807
815
|
});
|
|
@@ -817,9 +825,11 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
817
825
|
catch (error) {
|
|
818
826
|
const detail = error instanceof Error ? error.message : String(error);
|
|
819
827
|
writeReviewGateArtifactValidationFailure(context, {
|
|
828
|
+
runId,
|
|
820
829
|
target: selected.id,
|
|
821
830
|
project: projectPath,
|
|
822
831
|
artifactPath: producedArtifact.path,
|
|
832
|
+
generatedAt: producedArtifact.generatedAt,
|
|
823
833
|
message: detail,
|
|
824
834
|
recovery: `The review artifact was created at ${producedArtifact.path} but could not be consumed. Fix the artifact format, then run oat-project-review-receive for ${producedArtifact.path}; if the only issue is a missing zero-count severity heading, rerun the gate to normalize the same artifact instead of creating a new review version.`,
|
|
825
835
|
});
|
|
@@ -835,9 +845,11 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
835
845
|
});
|
|
836
846
|
writeReviewGateResult(context, {
|
|
837
847
|
status: blocking ? 'blocked' : 'ok',
|
|
848
|
+
runId,
|
|
838
849
|
target: selected.id,
|
|
839
850
|
project: projectPath,
|
|
840
851
|
artifactPath: producedArtifact.path,
|
|
852
|
+
generatedAt: producedArtifact.generatedAt,
|
|
841
853
|
threshold,
|
|
842
854
|
blocking,
|
|
843
855
|
counts: verdict.counts,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch-ceiling/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch-ceiling/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAO9B,OAAO,EAKL,KAAK,uBAAuB,EAK7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAEL,KAAK,cAAc,EAEpB,MAAM,iBAAiB,CAAC;AASzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BpC,UAAU,2BAA2B;IACnC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AA2+BD,wBAAgB,mCAAmC,CACjD,SAAS,GAAE,OAAO,CAAC,2BAA2B,CAAM,GACnD,OAAO,CAqDT"}
|