@open-agent-toolkit/cli 0.2.59 → 0.2.63

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 (120) hide show
  1. package/assets/agents/oat-phase-implementer.md +27 -4
  2. package/assets/agents/oat-reviewer.md +25 -14
  3. package/assets/bundle-metadata.json +1 -1
  4. package/assets/docs/cli-utilities/config-and-local-state.md +1 -0
  5. package/assets/docs/cli-utilities/configuration.md +10 -8
  6. package/assets/docs/cli-utilities/project-log.md +16 -0
  7. package/assets/docs/cli-utilities/workflow-gates.md +127 -19
  8. package/assets/docs/provider-sync/commands.md +3 -0
  9. package/assets/docs/provider-sync/instruction-sync.md +107 -0
  10. package/assets/docs/reference/cli-reference.md +26 -9
  11. package/assets/docs/reference/oat-directory-structure.md +33 -31
  12. package/assets/docs/workflows/ideas/index.md +1 -1
  13. package/assets/docs/workflows/index.md +1 -0
  14. package/assets/docs/workflows/projects/artifacts.md +24 -3
  15. package/assets/docs/workflows/projects/hill-checkpoints.md +21 -0
  16. package/assets/docs/workflows/projects/implementation-execution.md +5 -0
  17. package/assets/docs/workflows/projects/lifecycle.md +169 -7
  18. package/assets/docs/workflows/projects/picking-up-projects.md +14 -0
  19. package/assets/docs/workflows/projects/pr-flow.md +2 -0
  20. package/assets/docs/workflows/projects/reviews.md +1 -1
  21. package/assets/docs/workflows/projects/state-machine.md +20 -0
  22. package/assets/docs/workflows/skills/explainer-kit.md +10 -4
  23. package/assets/docs/workflows/skills/index.md +2 -1
  24. package/assets/docs/workflows/skills/repo-improve.md +15 -1
  25. package/assets/public-package-versions.json +4 -4
  26. package/assets/skills/oat-brainstorm/SKILL.md +61 -12
  27. package/assets/skills/oat-docs/SKILL.md +13 -8
  28. package/assets/skills/oat-doctor/SKILL.md +3 -3
  29. package/assets/skills/oat-explainer-kit/SKILL.md +14 -1
  30. package/assets/skills/oat-explainer-kit/references/config-contract.md +12 -0
  31. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +57 -10
  32. package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +28 -5
  33. package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +371 -0
  34. package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +123 -1
  35. package/assets/skills/oat-pjm-review-backlog/SKILL.md +2 -2
  36. package/assets/skills/oat-project-autonomous/SKILL.md +23 -9
  37. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +164 -150
  38. package/assets/skills/oat-project-capture/SKILL.md +2 -2
  39. package/assets/skills/oat-project-complete/SKILL.md +134 -4
  40. package/assets/skills/oat-project-discover/SKILL.md +6 -5
  41. package/assets/skills/oat-project-document/SKILL.md +11 -1
  42. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +164 -150
  43. package/assets/skills/oat-project-implement/SKILL.md +3 -3
  44. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +144 -21
  45. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +164 -150
  46. package/assets/skills/oat-project-implement/references/phase-execution.md +16 -1
  47. package/assets/skills/oat-project-implement/references/plan-and-resume.md +19 -1
  48. package/assets/skills/oat-project-import-plan/SKILL.md +47 -3
  49. package/assets/skills/oat-project-lite/SKILL.md +467 -0
  50. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +331 -0
  51. package/assets/skills/oat-project-next/SKILL.md +75 -16
  52. package/assets/skills/oat-project-plan/SKILL.md +44 -6
  53. package/assets/skills/oat-project-plan-writing/SKILL.md +6 -3
  54. package/assets/skills/oat-project-pr-final/SKILL.md +33 -7
  55. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +164 -150
  56. package/assets/skills/oat-project-pr-progress/SKILL.md +3 -3
  57. package/assets/skills/oat-project-progress/SKILL.md +27 -5
  58. package/assets/skills/oat-project-promote-spec-driven/SKILL.md +3 -1
  59. package/assets/skills/oat-project-quick-start/SKILL.md +264 -4
  60. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +164 -150
  61. package/assets/skills/oat-project-review-provide/SKILL.md +25 -6
  62. package/assets/skills/oat-project-summary/SKILL.md +61 -26
  63. package/assets/skills/oat-repo-improve/SKILL.md +40 -5
  64. package/assets/skills/oat-repo-improve/references/plan-template.md +84 -7
  65. package/assets/templates/plan-lite.md +165 -0
  66. package/assets/templates/plan.md +1 -1
  67. package/assets/templates/state.md +1 -1
  68. package/dist/commands/config/index.d.ts +1 -0
  69. package/dist/commands/config/index.d.ts.map +1 -1
  70. package/dist/commands/config/index.js +401 -18
  71. package/dist/commands/gate/index.d.ts +3 -1
  72. package/dist/commands/gate/index.d.ts.map +1 -1
  73. package/dist/commands/gate/index.js +699 -211
  74. package/dist/commands/init/tools/shared/skill-script-references.d.ts +126 -0
  75. package/dist/commands/init/tools/shared/skill-script-references.d.ts.map +1 -0
  76. package/dist/commands/init/tools/shared/skill-script-references.js +311 -0
  77. package/dist/commands/instructions/instructions.types.d.ts +63 -0
  78. package/dist/commands/instructions/instructions.types.d.ts.map +1 -1
  79. package/dist/commands/instructions/instructions.utils.d.ts +51 -2
  80. package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
  81. package/dist/commands/instructions/instructions.utils.js +201 -4
  82. package/dist/commands/instructions/sync/sync.d.ts.map +1 -1
  83. package/dist/commands/instructions/sync/sync.js +12 -1
  84. package/dist/commands/instructions/validate/validate.d.ts.map +1 -1
  85. package/dist/commands/instructions/validate/validate.js +12 -1
  86. package/dist/commands/project/index.d.ts.map +1 -1
  87. package/dist/commands/project/index.js +2 -0
  88. package/dist/commands/project/log/append.d.ts +195 -0
  89. package/dist/commands/project/log/append.d.ts.map +1 -1
  90. package/dist/commands/project/log/append.js +1034 -11
  91. package/dist/commands/project/new/index.d.ts +3 -2
  92. package/dist/commands/project/new/index.d.ts.map +1 -1
  93. package/dist/commands/project/new/index.js +2 -1
  94. package/dist/commands/project/new/scaffold.d.ts +5 -3
  95. package/dist/commands/project/new/scaffold.d.ts.map +1 -1
  96. package/dist/commands/project/new/scaffold.js +38 -10
  97. package/dist/commands/project/promote/index.d.ts +2 -0
  98. package/dist/commands/project/promote/index.d.ts.map +1 -0
  99. package/dist/commands/project/promote/index.js +1 -0
  100. package/dist/commands/project/promote/promote.d.ts +47 -0
  101. package/dist/commands/project/promote/promote.d.ts.map +1 -0
  102. package/dist/commands/project/promote/promote.js +322 -0
  103. package/dist/commands/project/split/run.d.ts.map +1 -1
  104. package/dist/commands/project/split/run.js +8 -1
  105. package/dist/commands/project/validate-plan/index.d.ts.map +1 -1
  106. package/dist/commands/project/validate-plan/index.js +25 -1
  107. package/dist/commands/project/validate-plan/validate-plan.d.ts +8 -0
  108. package/dist/commands/project/validate-plan/validate-plan.d.ts.map +1 -1
  109. package/dist/commands/project/validate-plan/validate-plan.js +49 -0
  110. package/dist/commands/shared/frontmatter.d.ts +1 -1
  111. package/dist/commands/shared/frontmatter.d.ts.map +1 -1
  112. package/dist/commands/shared/frontmatter.js +1 -0
  113. package/dist/commands/state/generate.d.ts.map +1 -1
  114. package/dist/commands/state/generate.js +23 -0
  115. package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
  116. package/dist/commands/tools/shared/pack-manifest.js +2 -0
  117. package/dist/config/oat-config.d.ts +41 -0
  118. package/dist/config/oat-config.d.ts.map +1 -1
  119. package/dist/config/oat-config.js +111 -0
  120. package/package.json +2 -2
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Skill-to-script reference integrity.
3
+ *
4
+ * A shipped skill may name a helper script through its installed destination,
5
+ * `.oat/scripts/<name>`. Nothing in the install path proves the pack that ships
6
+ * the skill also ships that script, so a rename or a pack move can leave a
7
+ * skill pointing at a file its own installation never materializes.
8
+ *
9
+ * This module supplies the join: a syntax-aware extractor for the reference
10
+ * spellings authored Markdown actually uses, a manifest-derived view of the
11
+ * shipped skill surface, and an owning-pack resolver. Callers compare the two
12
+ * and fail when a shipped skill references a script its owning pack does not
13
+ * ship.
14
+ *
15
+ * The shipped surface is derived from the pack manifest, never from the
16
+ * canonical `.agents/skills` directory listing: that listing is a superset that
17
+ * also holds repository-local authoring and utility skills no pack ships. Those
18
+ * directories are classified and reported, never resolved to a pack and never a
19
+ * failure by themselves.
20
+ *
21
+ * Scan boundary: `extractScriptReferences` takes any text, but the shipping
22
+ * caller feeds it authored Markdown only — every `**\/*.md` under a skill
23
+ * directory except the vendored `references/docs/` copies. That covers every
24
+ * reference in the tree today, since each of the six skill files naming
25
+ * `.oat/scripts` is a `SKILL.md`. A skill that ships a non-Markdown asset
26
+ * carrying a script reference would fall outside this scan, so widen the caller
27
+ * deliberately rather than assuming this module already sees it.
28
+ */
29
+ import type { PackDefinition, PackName } from '../../../tools/shared/types.js';
30
+ /** Installed destination prefix produced by the manifest's `script()` helper. */
31
+ export declare const SCRIPT_DESTINATION_PREFIX = ".oat/scripts/";
32
+ /** One extracted reference, kept line-addressed so failures cite a location. */
33
+ export interface ScriptReference {
34
+ /** Manifest-comparable destination, e.g. `.oat/scripts/resolve-tracking.sh`. */
35
+ reference: string;
36
+ /** 1-based line number of the occurrence within the scanned text. */
37
+ line: number;
38
+ }
39
+ /** Authored text belonging to one skill, ready to be scanned. */
40
+ export interface SkillScriptSource {
41
+ /** Canonical skill name, as shipped by a pack. */
42
+ skill: string;
43
+ /** Display path used in failure messages. */
44
+ file: string;
45
+ /** File contents. */
46
+ text: string;
47
+ }
48
+ /** A shipped skill naming a script its owning pack does not ship. */
49
+ export interface ScriptReferenceViolation {
50
+ skill: string;
51
+ file: string;
52
+ line: number;
53
+ reference: string;
54
+ /** Every pack that ships the skill; membership in any one satisfies the check. */
55
+ packs: PackName[];
56
+ /** Script destinations those packs do ship, for an actionable message. */
57
+ shipped: string[];
58
+ }
59
+ /** How a canonical `.agents/skills` directory relates to the pack manifest. */
60
+ export type CanonicalSkillDirClass = 'shipped' | 'canonical-unshipped';
61
+ /** Split of canonical skill directories by manifest membership. */
62
+ export interface CanonicalSkillDirClassification {
63
+ shipped: string[];
64
+ canonicalUnshipped: string[];
65
+ }
66
+ /**
67
+ * Extract every `.oat/scripts/<name>` reference from authored text.
68
+ *
69
+ * Scanning is line-by-line so each occurrence carries its own line number, and
70
+ * so a reference can never be assembled across a line break.
71
+ *
72
+ * A reference is returned essentially as authored. Nothing is truncated to a
73
+ * shipped-looking prefix, and the only edits are dropping the Markdown
74
+ * decoration around it — a closing emphasis run and at most one prose mark — so
75
+ * a malformed name reaches the manifest comparison intact and fails there
76
+ * rather than being normalized into a name that happens to exist.
77
+ */
78
+ export declare function extractScriptReferences(text: string): ScriptReference[];
79
+ /**
80
+ * The union of every pack's skill assets: the surface the manifest claims to
81
+ * ship, which is what the contract checks.
82
+ */
83
+ export declare function listShippedSkills(manifest?: readonly PackDefinition[]): string[];
84
+ /** Script destinations shipped by one pack. */
85
+ export declare function listPackScriptDestinations(pack: PackName, manifest?: readonly PackDefinition[]): string[];
86
+ /**
87
+ * Classify a canonical skill directory against the manifest.
88
+ *
89
+ * `canonical-unshipped` is an ordinary, expected state: repository-local
90
+ * authoring and utility skills live under `.agents/skills` without belonging to
91
+ * any pack. It is reported, never failed.
92
+ */
93
+ export declare function classifyCanonicalSkillDir(name: string, manifest?: readonly PackDefinition[]): CanonicalSkillDirClass;
94
+ /** Classify a whole directory listing in one pass. */
95
+ export declare function classifyCanonicalSkillDirs(names: readonly string[], manifest?: readonly PackDefinition[]): CanonicalSkillDirClassification;
96
+ /**
97
+ * Shipped skills the manifest names but whose canonical directory is absent.
98
+ *
99
+ * The inverse of `classifyCanonicalSkillDirs`, and unlike an unshipped
100
+ * directory this *is* a failure: the manifest promises to install something the
101
+ * repository does not contain.
102
+ */
103
+ export declare function findMissingShippedSkillDirs(existingDirs: readonly string[], manifest?: readonly PackDefinition[]): string[];
104
+ /**
105
+ * Every pack that ships `skillName`.
106
+ *
107
+ * Throws for a name no pack ships. That is a caller bug rather than a repository
108
+ * defect: callers drive from `listShippedSkills`, so an unshipped canonical
109
+ * directory never reaches here.
110
+ *
111
+ * A skill carried by more than one pack resolves to all of them, and membership
112
+ * in any one satisfies the reference check — the same shared-ownership rule the
113
+ * manifest applies to a script shipped by two packs under one `sharedOwner`.
114
+ */
115
+ export declare function resolveOwningPack(skillName: string, manifest?: readonly PackDefinition[]): PackName[];
116
+ /**
117
+ * The contract itself: every script reference authored by a shipped skill must
118
+ * name a `kind: 'script'` destination of a pack that ships that skill.
119
+ *
120
+ * Sources for skills no pack ships must not be passed; drive callers from
121
+ * `listShippedSkills` so `resolveOwningPack` stays a caller-bug signal.
122
+ */
123
+ export declare function findUnshippedScriptReferences(sources: readonly SkillScriptSource[], manifest?: readonly PackDefinition[]): ScriptReferenceViolation[];
124
+ /** Render one violation so the failure names the skill, reference, and pack. */
125
+ export declare function formatScriptReferenceViolation({ skill, file, line, reference, packs, shipped, }: ScriptReferenceViolation): string;
126
+ //# sourceMappingURL=skill-script-references.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-script-references.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/shared/skill-script-references.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,KAAK,EAEV,cAAc,EACd,QAAQ,EACT,MAAM,8BAA8B,CAAC;AAEtC,iFAAiF;AACjF,eAAO,MAAM,yBAAyB,kBAAkB,CAAC;AAiKzD,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,qEAAqE;AACrE,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,+EAA+E;AAC/E,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,qBAAqB,CAAC;AAEvE,mEAAmE;AACnE,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CA4BvE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,MAAM,EAAE,CAUV;AAED,+CAA+C;AAC/C,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,QAAQ,EACd,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,MAAM,EAAE,CAQV;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,sBAAsB,CAIxB;AAED,sDAAsD;AACtD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,+BAA+B,CAOjC;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,YAAY,EAAE,SAAS,MAAM,EAAE,EAC/B,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,MAAM,EAAE,CAGV;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,QAAQ,EAAE,CAgBZ;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,wBAAwB,EAAE,CAkB5B;AAED,gFAAgF;AAChF,wBAAgB,8BAA8B,CAAC,EAC7C,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,KAAK,EACL,OAAO,GACR,EAAE,wBAAwB,GAAG,MAAM,CAInC"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Skill-to-script reference integrity.
3
+ *
4
+ * A shipped skill may name a helper script through its installed destination,
5
+ * `.oat/scripts/<name>`. Nothing in the install path proves the pack that ships
6
+ * the skill also ships that script, so a rename or a pack move can leave a
7
+ * skill pointing at a file its own installation never materializes.
8
+ *
9
+ * This module supplies the join: a syntax-aware extractor for the reference
10
+ * spellings authored Markdown actually uses, a manifest-derived view of the
11
+ * shipped skill surface, and an owning-pack resolver. Callers compare the two
12
+ * and fail when a shipped skill references a script its owning pack does not
13
+ * ship.
14
+ *
15
+ * The shipped surface is derived from the pack manifest, never from the
16
+ * canonical `.agents/skills` directory listing: that listing is a superset that
17
+ * also holds repository-local authoring and utility skills no pack ships. Those
18
+ * directories are classified and reported, never resolved to a pack and never a
19
+ * failure by themselves.
20
+ *
21
+ * Scan boundary: `extractScriptReferences` takes any text, but the shipping
22
+ * caller feeds it authored Markdown only — every `**\/*.md` under a skill
23
+ * directory except the vendored `references/docs/` copies. That covers every
24
+ * reference in the tree today, since each of the six skill files naming
25
+ * `.oat/scripts` is a `SKILL.md`. A skill that ships a non-Markdown asset
26
+ * carrying a script reference would fall outside this scan, so widen the caller
27
+ * deliberately rather than assuming this module already sees it.
28
+ */
29
+ import { PACK_MANIFEST } from '../../../tools/shared/pack-manifest.js';
30
+ /** Installed destination prefix produced by the manifest's `script()` helper. */
31
+ export const SCRIPT_DESTINATION_PREFIX = '.oat/scripts/';
32
+ // Extraction runs in two stages, and the split is the whole point.
33
+ //
34
+ // Stage one finds where a reference starts. The lookbehind rejects a candidate
35
+ // glued to an identifier, so `myrepo.oat/scripts/…` never matches, while every
36
+ // rooted spelling authored today still does: a leading `/` is explicitly
37
+ // allowed, which covers `$SCOPE_ROOT/.oat/scripts/…`, `${HOME}/.oat/scripts/…`,
38
+ // `~/.oat/scripts/…`, and the plain relative form. The trailing slash is
39
+ // required, so a mention of the directory itself — `${HOME}/.oat/scripts` — is
40
+ // not a reference start at all.
41
+ //
42
+ // `_` is absent from the lookbehind on purpose, so an italic `_.oat/scripts/…_`
43
+ // still starts a match. The glued-identifier case it used to cover —
44
+ // `myrepo_.oat/scripts/…` — is rejected instead by `readOpeningEmphasis`, which
45
+ // can tell an emphasis delimiter at a word boundary from an underscore inside a
46
+ // name. A lookbehind cannot make that distinction, and a wrongly rejected start
47
+ // is a silent miss.
48
+ const SCRIPT_REFERENCE_START = /(?<![A-Za-z0-9.-])\.oat\/scripts\//g;
49
+ // Characters that may not sit next to an emphasis delimiter for it to read as
50
+ // emphasis rather than as part of an identifier.
51
+ const IDENTIFIER_CHARACTER = /[\p{L}\p{N}._-]/u;
52
+ // Stage two reads the name that follows, losslessly, up to the first character
53
+ // that closes the surrounding Markdown construct: whitespace, the backtick or
54
+ // quote closing an inline span, the `)` or `>` closing a link target, or a
55
+ // list/table separator.
56
+ //
57
+ // Reading the whole token rather than matching a "valid-looking" name is what
58
+ // makes the check fail closed. A name class that stopped at the first
59
+ // unexpected character would quietly truncate `…/resolve-tracking.sh/<file>`
60
+ // down to the shipped `resolve-tracking.sh` and report success, and a class
61
+ // that required a leading alphanumeric would drop `_missing.sh` on the floor
62
+ // instead of flagging it. Both are fail-open, and a fail-open integrity check
63
+ // is worse than none.
64
+ //
65
+ // Only true closers belong here, never ordinary punctuation. Every character in
66
+ // this set truncates the token, so admitting one that can appear mid-path would
67
+ // reintroduce exactly the truncation this design removes.
68
+ const REFERENCE_TOKEN_TERMINATOR = /[\s`"'),;\]|>]/;
69
+ // Prose puts a mark after a path without making it part of the path, and each
70
+ // of these is a real authored spelling: `run .oat/scripts/x.sh.`,
71
+ // `did you run .oat/scripts/x.sh?`, `run .oat/scripts/x.sh: it resolves…`.
72
+ //
73
+ // Exactly one such character is dropped, and only in the final position. That
74
+ // is deliberately weaker than trimming a run: a doubled `x.sh..` keeps a period
75
+ // and still fails, so a malformed spelling cannot be normalized into a shipped
76
+ // name. Position-anchored trimming also cannot truncate a path the way a
77
+ // terminator does.
78
+ const TRAILING_PROSE_MARK = /[.:!?]$/;
79
+ // A token carrying shell, glob, or documentation-placeholder syntax names no
80
+ // concrete file: `~/.oat/scripts/<file>` and `.oat/scripts/${NAME}` are prose
81
+ // about the directory, not references into it. These negatives are as
82
+ // load-bearing as the matches, since a false positive here blocks CI on
83
+ // documentation that is entirely correct.
84
+ //
85
+ // This test runs after every trailing decoration is dropped, so a `?` that
86
+ // merely ended a question, or a `*` that merely closed an emphasis span, is
87
+ // gone before it can be mistaken for a glob.
88
+ const PLACEHOLDER_SYNTAX = /[<{}$*?]/;
89
+ function readReferenceToken(line, from) {
90
+ let end = from;
91
+ while (end < line.length && !REFERENCE_TOKEN_TERMINATOR.test(line[end])) {
92
+ end += 1;
93
+ }
94
+ return line.slice(from, end);
95
+ }
96
+ /**
97
+ * The emphasis run opening this reference, or `null` when the run is glued to a
98
+ * name and therefore opened nothing.
99
+ *
100
+ * The opening run is the only reliable evidence that a trailing delimiter is
101
+ * emphasis rather than content, and both delimiters need that evidence:
102
+ *
103
+ * - `_` is a legal filename character, so `.oat/scripts/x.sh_` with no opening
104
+ * run keeps its underscore. That is what makes a typo such as
105
+ * `resolve-tracking.sh_` still fail instead of being normalized into the
106
+ * shipped name.
107
+ * - `*` is not a legal filename character, but it *is* glob syntax, which this
108
+ * module treats as prose about the directory. An unpaired
109
+ * `.oat/scripts/resolve-tracking.sh*` is a glob, and stripping its star would
110
+ * normalize it into a shipped name — the exact fail-open this design exists to
111
+ * prevent. Leaving it attached keeps it a glob, which is skipped.
112
+ *
113
+ * `null` rejects the match outright for `myrepo_.oat/scripts/x.sh`, where the
114
+ * underscore is glued to an identifier. The identifier test is Unicode-aware so
115
+ * `café_.oat/scripts/x.sh` is rejected too.
116
+ */
117
+ function readOpeningEmphasis(line, at) {
118
+ let start = at;
119
+ while (start > 0 && (line[start - 1] === '_' || line[start - 1] === '*')) {
120
+ start -= 1;
121
+ }
122
+ const run = line.slice(start, at);
123
+ if (run.length === 0)
124
+ return { asterisks: 0, underscores: 0 };
125
+ const preceding = start > 0 ? line[start - 1] : '';
126
+ if (IDENTIFIER_CHARACTER.test(preceding))
127
+ return null;
128
+ return {
129
+ asterisks: run.split('').filter((char) => char === '*').length,
130
+ underscores: run.split('').filter((char) => char === '_').length,
131
+ };
132
+ }
133
+ /**
134
+ * Drop the decoration Markdown and prose leave on the end of a reference.
135
+ *
136
+ * Each delimiter comes off only up to the length of its opening run, so an
137
+ * unpaired trailing `*` or `_` survives as part of the name and is judged on its
138
+ * merits downstream. At most one prose mark is dropped in total, so a doubled
139
+ * `x.sh..` keeps a period and still fails the manifest comparison.
140
+ *
141
+ * A single ordered pass is not enough, because the layers interleave:
142
+ * `**x.sh**.` closes its emphasis outside the sentence period, and `_*x.sh*_`
143
+ * nests two delimiters. The loop peels whichever layer is currently outermost
144
+ * until no budget is left.
145
+ */
146
+ function stripTrailingDecoration(token, opening) {
147
+ let name = token;
148
+ let asterisks = opening.asterisks;
149
+ let underscores = opening.underscores;
150
+ let proseMarkDropped = false;
151
+ for (;;) {
152
+ if (asterisks > 0 && name.endsWith('*')) {
153
+ name = name.slice(0, -1);
154
+ asterisks -= 1;
155
+ continue;
156
+ }
157
+ if (underscores > 0 && name.endsWith('_')) {
158
+ name = name.slice(0, -1);
159
+ underscores -= 1;
160
+ continue;
161
+ }
162
+ if (!proseMarkDropped && TRAILING_PROSE_MARK.test(name)) {
163
+ name = name.replace(TRAILING_PROSE_MARK, '');
164
+ proseMarkDropped = true;
165
+ continue;
166
+ }
167
+ break;
168
+ }
169
+ return name;
170
+ }
171
+ function skillNameOf(asset) {
172
+ return asset.id.slice('skill:'.length);
173
+ }
174
+ /**
175
+ * Extract every `.oat/scripts/<name>` reference from authored text.
176
+ *
177
+ * Scanning is line-by-line so each occurrence carries its own line number, and
178
+ * so a reference can never be assembled across a line break.
179
+ *
180
+ * A reference is returned essentially as authored. Nothing is truncated to a
181
+ * shipped-looking prefix, and the only edits are dropping the Markdown
182
+ * decoration around it — a closing emphasis run and at most one prose mark — so
183
+ * a malformed name reaches the manifest comparison intact and fails there
184
+ * rather than being normalized into a name that happens to exist.
185
+ */
186
+ export function extractScriptReferences(text) {
187
+ const references = [];
188
+ for (const [index, line] of text.split(/\r?\n/).entries()) {
189
+ for (const match of line.matchAll(SCRIPT_REFERENCE_START)) {
190
+ const opening = readOpeningEmphasis(line, match.index);
191
+ // A delimiter glued to a name, so it never opened emphasis.
192
+ if (opening === null)
193
+ continue;
194
+ const name = stripTrailingDecoration(readReferenceToken(line, match.index + match[0].length), opening);
195
+ // Prose about the directory, not a reference into it.
196
+ if (PLACEHOLDER_SYNTAX.test(name))
197
+ continue;
198
+ // A bare `.oat/scripts/` mention names no script.
199
+ if (name.length === 0)
200
+ continue;
201
+ references.push({
202
+ reference: `${SCRIPT_DESTINATION_PREFIX}${name}`,
203
+ line: index + 1,
204
+ });
205
+ }
206
+ }
207
+ return references;
208
+ }
209
+ /**
210
+ * The union of every pack's skill assets: the surface the manifest claims to
211
+ * ship, which is what the contract checks.
212
+ */
213
+ export function listShippedSkills(manifest = PACK_MANIFEST) {
214
+ const names = new Set();
215
+ for (const pack of manifest) {
216
+ for (const asset of pack.assets) {
217
+ if (asset.kind === 'skill')
218
+ names.add(skillNameOf(asset));
219
+ }
220
+ }
221
+ return [...names].sort();
222
+ }
223
+ /** Script destinations shipped by one pack. */
224
+ export function listPackScriptDestinations(pack, manifest = PACK_MANIFEST) {
225
+ const definition = manifest.find(({ name }) => name === pack);
226
+ if (!definition)
227
+ throw new Error(`Unknown pack: ${pack}`);
228
+ return definition.assets
229
+ .filter((asset) => asset.kind === 'script')
230
+ .map(({ destination }) => destination)
231
+ .sort();
232
+ }
233
+ /**
234
+ * Classify a canonical skill directory against the manifest.
235
+ *
236
+ * `canonical-unshipped` is an ordinary, expected state: repository-local
237
+ * authoring and utility skills live under `.agents/skills` without belonging to
238
+ * any pack. It is reported, never failed.
239
+ */
240
+ export function classifyCanonicalSkillDir(name, manifest = PACK_MANIFEST) {
241
+ return listShippedSkills(manifest).includes(name)
242
+ ? 'shipped'
243
+ : 'canonical-unshipped';
244
+ }
245
+ /** Classify a whole directory listing in one pass. */
246
+ export function classifyCanonicalSkillDirs(names, manifest = PACK_MANIFEST) {
247
+ const shipped = new Set(listShippedSkills(manifest));
248
+ return {
249
+ shipped: names.filter((name) => shipped.has(name)).sort(),
250
+ canonicalUnshipped: names.filter((name) => !shipped.has(name)).sort(),
251
+ };
252
+ }
253
+ /**
254
+ * Shipped skills the manifest names but whose canonical directory is absent.
255
+ *
256
+ * The inverse of `classifyCanonicalSkillDirs`, and unlike an unshipped
257
+ * directory this *is* a failure: the manifest promises to install something the
258
+ * repository does not contain.
259
+ */
260
+ export function findMissingShippedSkillDirs(existingDirs, manifest = PACK_MANIFEST) {
261
+ const existing = new Set(existingDirs);
262
+ return listShippedSkills(manifest).filter((name) => !existing.has(name));
263
+ }
264
+ /**
265
+ * Every pack that ships `skillName`.
266
+ *
267
+ * Throws for a name no pack ships. That is a caller bug rather than a repository
268
+ * defect: callers drive from `listShippedSkills`, so an unshipped canonical
269
+ * directory never reaches here.
270
+ *
271
+ * A skill carried by more than one pack resolves to all of them, and membership
272
+ * in any one satisfies the reference check — the same shared-ownership rule the
273
+ * manifest applies to a script shipped by two packs under one `sharedOwner`.
274
+ */
275
+ export function resolveOwningPack(skillName, manifest = PACK_MANIFEST) {
276
+ const packs = manifest
277
+ .filter((pack) => pack.assets.some((asset) => asset.kind === 'skill' && skillNameOf(asset) === skillName))
278
+ .map(({ name }) => name);
279
+ if (packs.length === 0) {
280
+ throw new Error(`resolveOwningPack: skill "${skillName}" is shipped by no pack; pass a name from listShippedSkills()`);
281
+ }
282
+ return packs;
283
+ }
284
+ /**
285
+ * The contract itself: every script reference authored by a shipped skill must
286
+ * name a `kind: 'script'` destination of a pack that ships that skill.
287
+ *
288
+ * Sources for skills no pack ships must not be passed; drive callers from
289
+ * `listShippedSkills` so `resolveOwningPack` stays a caller-bug signal.
290
+ */
291
+ export function findUnshippedScriptReferences(sources, manifest = PACK_MANIFEST) {
292
+ const violations = [];
293
+ for (const { skill, file, text } of sources) {
294
+ const packs = resolveOwningPack(skill, manifest);
295
+ const shipped = [
296
+ ...new Set(packs.flatMap((pack) => listPackScriptDestinations(pack, manifest))),
297
+ ].sort();
298
+ for (const { reference, line } of extractScriptReferences(text)) {
299
+ if (shipped.includes(reference))
300
+ continue;
301
+ violations.push({ skill, file, line, reference, packs, shipped });
302
+ }
303
+ }
304
+ return violations;
305
+ }
306
+ /** Render one violation so the failure names the skill, reference, and pack. */
307
+ export function formatScriptReferenceViolation({ skill, file, line, reference, packs, shipped, }) {
308
+ const owner = `pack${packs.length > 1 ? 's' : ''} ${packs.join(', ')}`;
309
+ const available = shipped.length > 0 ? shipped.join(', ') : 'no scripts';
310
+ return `${skill} (${owner}) references ${reference} at ${file}:${line}, but ${owner} ${packs.length > 1 ? 'ship' : 'ships'} ${available}`;
311
+ }
@@ -35,10 +35,67 @@ export interface InstructionsJsonPayload {
35
35
  summary: InstructionsSummary;
36
36
  entries: InstructionEntry[];
37
37
  actions: InstructionActionRecord[];
38
+ /**
39
+ * The normalized repo-relative exclusions this scan was *configured* with, in
40
+ * resolution order. An entry here is a statement of intent, not a guarantee:
41
+ * it may name a directory that does not exist, differ in case from the real
42
+ * path on a case-insensitive filesystem, or be shadowed by the `.oat/repo`
43
+ * carve-in.
44
+ *
45
+ * Read `effectiveExcludedPaths` to learn what was actually protected.
46
+ *
47
+ * Additive and omitted entirely when nothing was configured, so payloads from
48
+ * repositories without a documentation root are byte-identical to the
49
+ * pre-exclusion shape.
50
+ */
51
+ excludedPaths?: string[];
52
+ /**
53
+ * The subset of `excludedPaths` that names a real, case-exact directory the
54
+ * scan can actually prune. This is the field a consumer should trust when
55
+ * deciding whether a tree is protected; every configured entry missing from
56
+ * it was also reported as a warning on stderr.
57
+ *
58
+ * Present whenever `excludedPaths` is, including as an empty array when every
59
+ * configured entry turned out to be inert; omitted only when nothing was
60
+ * configured at all.
61
+ */
62
+ effectiveExcludedPaths?: string[];
63
+ /**
64
+ * One message per configured exclusion that will not protect anything, the
65
+ * same text written to stderr in human mode.
66
+ *
67
+ * This field is why the JSON surface is complete. `logger.warn` is suppressed
68
+ * under `--json`, and an entry rejected during normalization (an absolute
69
+ * path, or one escaping the repository) never reaches `excludedPaths` either
70
+ * — so without this a `--json` consumer would see no trace at all of an
71
+ * exclusion that silently does nothing. Omitted when empty.
72
+ */
73
+ exclusionWarnings?: string[];
74
+ }
75
+ /**
76
+ * The resolved exclusion set, split so that intent and effect cannot be
77
+ * confused. A configured entry that protects nothing is the failure mode this
78
+ * split exists to surface: silently reporting it as applied would let an
79
+ * operator believe a documentation tree is safe while pointers are written
80
+ * into it.
81
+ */
82
+ export interface InstructionPointerExclusions {
83
+ /** Normalized entries exactly as configured, in resolution order. */
84
+ configured: string[];
85
+ /** The subset that names a real, case-exact, prunable directory. */
86
+ effective: string[];
87
+ /** One human-readable warning per configured entry that will do nothing. */
88
+ warnings: string[];
38
89
  }
39
90
  export interface InstructionsScanOptions {
40
91
  strategy?: InstructionSyncStrategy;
41
92
  debug?: (message: string) => void;
93
+ /**
94
+ * Repo-root-relative directories whose subtrees are left out of the scan.
95
+ * Applied after the excluded-root carve-in, so excluding a directory can
96
+ * never strand a subtree the carve-in re-entered (`.oat/repo/**`).
97
+ */
98
+ excludedPaths?: string[];
42
99
  }
43
100
  export interface InstructionsScanDependencies {
44
101
  readdir: (path: string, options: {
@@ -53,6 +110,12 @@ export interface InstructionsScanDependencies {
53
110
  export interface InstructionsValidateCommandDependencies {
54
111
  buildCommandContext: (options: GlobalOptions) => CommandContext;
55
112
  resolveProjectRoot: (cwd: string) => Promise<string>;
113
+ /**
114
+ * The single exclusion path both commands resolve through. Sync inherits it
115
+ * from this interface rather than resolving its own, so validate can never
116
+ * report drift that sync would refuse to fix.
117
+ */
118
+ resolveInstructionPointerExcludes: (repoRoot: string) => Promise<InstructionPointerExclusions>;
56
119
  scanInstructionFiles: (repoRoot: string, options?: InstructionsScanOptions, overrides?: Partial<InstructionsScanDependencies>) => Promise<InstructionEntry[]>;
57
120
  }
58
121
  export interface InstructionsSyncCommandDependencies extends InstructionsValidateCommandDependencies {
@@ -1 +1 @@
1
- {"version":3,"file":"instructions.types.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instructions.types.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.types.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,64 @@
1
- import type { InstructionSyncStrategy, InstructionActionRecord, InstructionEntry, InstructionsJsonPayload, InstructionsMode, InstructionsScanOptions, InstructionsScanDependencies, InstructionsSummary } from './instructions.types.js';
1
+ import type { InstructionSyncStrategy, InstructionActionRecord, InstructionEntry, InstructionsJsonPayload, InstructionsMode, InstructionPointerExclusions, InstructionsScanOptions, InstructionsScanDependencies, InstructionsSummary } from './instructions.types.js';
2
2
  export declare const EXPECTED_CLAUDE_CONTENT = "@AGENTS.md\n";
3
3
  export declare const DEFAULT_INSTRUCTION_SYNC_STRATEGY: InstructionSyncStrategy;
4
4
  interface BuildInstructionsPayloadArgs {
5
5
  mode: InstructionsMode;
6
6
  entries: InstructionEntry[];
7
7
  actions: InstructionActionRecord[];
8
+ excludedPaths?: string[];
9
+ effectiveExcludedPaths?: string[];
10
+ exclusionWarnings?: string[];
8
11
  }
9
12
  export declare function resolveInstructionSyncStrategy(strategy?: InstructionSyncStrategy): InstructionSyncStrategy;
13
+ /**
14
+ * Canonicalize repo-relative exclusion entries into the exact form the scan
15
+ * compares against: POSIX separators, collapsed `.` and `..` segments and
16
+ * duplicate slashes, no trailing slash, de-duplicated, order-preserving.
17
+ *
18
+ * Full normalization is what makes the comparison trustworthy. The scan tests
19
+ * an exclusion against `relative(repoRoot, entryPath)`, which is always
20
+ * already-normalized, so an un-normalized entry like `apps/./docs` or
21
+ * `apps//docs` would silently never match and quietly fail open.
22
+ *
23
+ * Two classes of entry are dropped rather than normalized:
24
+ *
25
+ * - anything resolving to the repository root (`.`, `` , `./`), because
26
+ * excluding the root would silence the entire scan — including the
27
+ * `.oat/repo` carve-in — from one stray config value; and
28
+ * - absolute paths and entries escaping the repository (`..`, `../x`), which
29
+ * can never name a directory inside the tree being scanned. Dropping them
30
+ * keeps a malformed value from masquerading as a matchable exclusion.
31
+ */
32
+ export declare function normalizeExcludedPaths(excludedPaths?: readonly string[]): string[];
33
+ /**
34
+ * The directories `oat instructions sync` and `oat instructions validate` skip:
35
+ * the derived documentation content root first, then the explicit
36
+ * `documentation.instructionPointerExcludes` opt-outs.
37
+ *
38
+ * Both commands resolve exclusions through this one function. That is the
39
+ * property that matters: if they computed exclusions separately, validate
40
+ * could report drift in a directory sync refuses to touch, and the repository
41
+ * would have no clean state to reach.
42
+ *
43
+ * Every configured entry is classified rather than trusted. An entry that is
44
+ * dropped during normalization, names an unexcludable carve-in root, or does
45
+ * not resolve to a real case-exact directory is reported as a warning and kept
46
+ * out of `effective`, so no caller can mistake a typo for protection.
47
+ *
48
+ * `effective` answers "is this tree protected from pointer writes?", not "did
49
+ * the exclusion predicate fire for it". An entry that names an already-skipped
50
+ * built-in root (`.git`, `node_modules`) or sits beneath another exclusion is
51
+ * still effective, because the operator's intent holds; warning about those
52
+ * would be a false alarm about exclusions that do work.
53
+ *
54
+ * Nothing here deletes or rewrites an existing pointer. Excluding a directory
55
+ * only stops it being reported and written; a `CLAUDE.md` already inside an
56
+ * excluded tree is left exactly as it is.
57
+ */
58
+ export declare function resolveInstructionPointerExcludes(repoRoot: string, overrides?: Partial<InstructionsScanDependencies>): Promise<InstructionPointerExclusions>;
10
59
  export declare function scanInstructionFiles(repoRoot: string, options?: InstructionsScanOptions, overrides?: Partial<InstructionsScanDependencies>): Promise<InstructionEntry[]>;
11
60
  export declare function buildInstructionsSummary(entries: InstructionEntry[], actions: InstructionActionRecord[]): InstructionsSummary;
12
- export declare function buildInstructionsPayload({ mode, entries, actions, }: BuildInstructionsPayloadArgs): InstructionsJsonPayload;
61
+ export declare function buildInstructionsPayload({ mode, entries, actions, excludedPaths, effectiveExcludedPaths, exclusionWarnings, }: BuildInstructionsPayloadArgs): InstructionsJsonPayload;
13
62
  export declare function formatInstructionsReport(payload: InstructionsJsonPayload, repoRoot?: string): string;
14
63
  export {};
15
64
  //# sourceMappingURL=instructions.utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"instructions.utils.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.utils.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,uBAAuB,EACvB,4BAA4B,EAE5B,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AACtD,eAAO,MAAM,iCAAiC,EAAE,uBACrC,CAAC;AAcZ,UAAU,4BAA4B;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,uBAAuB,EAAE,CAAC;CACpC;AAiCD,wBAAgB,8BAA8B,CAC5C,QAAQ,CAAC,EAAE,uBAAuB,GACjC,uBAAuB,CAEzB;AA2LD,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B,EACrC,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAiO7B;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,OAAO,EAAE,uBAAuB,EAAE,GACjC,mBAAmB,CAoBrB;AAgBD,wBAAgB,wBAAwB,CAAC,EACvC,IAAI,EACJ,OAAO,EACP,OAAO,GACR,EAAE,4BAA4B,GAAG,uBAAuB,CAWxD;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAmCR"}
1
+ {"version":3,"file":"instructions.utils.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.utils.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,4BAA4B,EAC5B,uBAAuB,EACvB,4BAA4B,EAE5B,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AACtD,eAAO,MAAM,iCAAiC,EAAE,uBACrC,CAAC;AAcZ,UAAU,4BAA4B;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAiCD,wBAAgB,8BAA8B,CAC5C,QAAQ,CAAC,EAAE,uBAAuB,GACjC,uBAAuB,CAEzB;AA2ED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,GAAE,SAAS,MAAM,EAAO,GACpC,MAAM,EAAE,CAyBV;AAsDD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,iCAAiC,CACrD,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CAAC,4BAA4B,CAAC,CAuEvC;AAgID,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B,EACrC,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAkO7B;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,OAAO,EAAE,uBAAuB,EAAE,GACjC,mBAAmB,CAoBrB;AAgBD,wBAAgB,wBAAwB,CAAC,EACvC,IAAI,EACJ,OAAO,EACP,OAAO,EACP,aAAa,EACb,sBAAsB,EACtB,iBAAiB,GAClB,EAAE,4BAA4B,GAAG,uBAAuB,CAgCxD;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAmCR"}