harnessbrew 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +83 -0
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +242 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/bundle.d.ts +43 -0
- package/dist/core/bundle.d.ts.map +1 -0
- package/dist/core/bundle.js +195 -0
- package/dist/core/bundle.js.map +1 -0
- package/dist/core/errors.d.ts +4 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +7 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/formulas.d.ts +29 -0
- package/dist/core/formulas.d.ts.map +1 -0
- package/dist/core/formulas.js +185 -0
- package/dist/core/formulas.js.map +1 -0
- package/dist/core/git.d.ts +3 -0
- package/dist/core/git.d.ts.map +1 -0
- package/dist/core/git.js +36 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/installations.d.ts +38 -0
- package/dist/core/installations.d.ts.map +1 -0
- package/dist/core/installations.js +250 -0
- package/dist/core/installations.js.map +1 -0
- package/dist/core/paths.d.ts +8 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +39 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/state.d.ts +16 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +43 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/taps.d.ts +16 -0
- package/dist/core/taps.d.ts.map +1 -0
- package/dist/core/taps.js +102 -0
- package/dist/core/taps.js.map +1 -0
- package/dist/core/targets.d.ts +11 -0
- package/dist/core/targets.d.ts.map +1 -0
- package/dist/core/targets.js +150 -0
- package/dist/core/targets.js.map +1 -0
- package/dist/core/upgrades.d.ts +14 -0
- package/dist/core/upgrades.d.ts.map +1 -0
- package/dist/core/upgrades.js +127 -0
- package/dist/core/upgrades.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +63 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## 0.4.0 - 2026-08-12
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Git Tap registration, validation, updates, commit checkout, and removal
|
|
10
|
+
- Formula catalog for skills, agents, workflows, instructions, prompts, MCP configurations, and adapters
|
|
11
|
+
- dependency resolution, conflict detection, immutable Cellar installs, and SHA-256 receipts
|
|
12
|
+
- OpenAI Codex and Claude Code target linking with ownership and tamper checks
|
|
13
|
+
- `update`, `outdated`, and rollback-safe `upgrade` commands
|
|
14
|
+
- Git-reproducible `Harnessfile`, `Harnessfile.lock`, `bundle install`, and `bundle cleanup`
|
|
15
|
+
- TypeScript 7.0 strict builds, comprehensive tests, npm packaging, and GitHub release automation
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- redefined HarnessBrew as a Git-native package manager for AI Agent assets
|
|
20
|
+
- moved version history from per-asset snapshots to Tap commits and tags
|
|
21
|
+
- raised the minimum supported Node.js version to 20
|
|
22
|
+
|
|
23
|
+
### Removed
|
|
24
|
+
|
|
25
|
+
- repository-owned sample assets and the obsolete workspace/export architecture
|
|
26
|
+
|
|
27
|
+
## 0.3.0 - 2026-06-27
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- asset maintenance commands: `set`, `add-dependency`, `remove-dependency`, `clone`, and `archive`
|
|
32
|
+
- dependency graph commands: `deps`, `dependents`, `orphans`, and `impact`
|
|
33
|
+
- bundle `checksums.json` generation plus manifest digest metadata for release artifact verification
|
|
34
|
+
- `verify-bundle` command for validating required bundle files, SHA-256 digests, and asset payload consistency
|
|
35
|
+
- `pack --channel draft|stable`, with `stable` bundles requiring workspace validation before packaging
|
|
36
|
+
- `pack --archive` for producing distributable `.tar.gz` bundle archives
|
|
37
|
+
- `docs/walkthrough-asset-to-bundle.md` covering asset creation through bundle verification
|
|
38
|
+
- `docs/release-0.3.0.md` with version touchpoints, verification commands, manual checks, and release flow
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- repository sample agent now declares dependencies that match the initialized sample workspace
|
|
43
|
+
- asset metadata now includes `status: "active" | "archived"` and `list --status` filtering
|
|
44
|
+
- README command surface now reflects the `0.3.0` asset lifecycle, dependency graph, and bundle verification workflows
|
|
45
|
+
- smoke coverage now exercises lifecycle commands, graph queries, bundle digests, bundle verification, release channels, and archive packaging
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- archive flow now blocks assets that are still depended on, avoiding broken dependency graphs
|
|
50
|
+
- bundle verification now catches missing files, checksum mismatches, and manifest/assets asset set drift
|
|
51
|
+
|
|
52
|
+
## 0.2.0 - 2026-06-17
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- asset dependency modeling with validation for missing, duplicate, cyclic, and target-incompatible dependencies
|
|
57
|
+
- `show --resolved` for inspecting dependency trees and flattened dependency graphs
|
|
58
|
+
- filtered and grouped `list` output with `--kind`, `--tag`, `--owner`, `--target`, and `--group-by`
|
|
59
|
+
- structured `--json` output for `list`, `validate`, `history`, `diff`, `export`, and `pack`
|
|
60
|
+
- entry-scoped exports with `--entry <kind:id>` and optional `--include-dependencies`
|
|
61
|
+
- `pack` command for bundle delivery with `manifest.json`, `assets.json`, and `rendered/<target>.json`
|
|
62
|
+
- workspace-level `schemaVersion` and `bundleDirectory` configuration
|
|
63
|
+
- `0.2.0` roadmap documentation covering milestones, command design, and bundle packaging direction
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- strengthened target compatibility enforcement during export and pack flows
|
|
68
|
+
- expanded smoke coverage for dependency resolution, local adapter compatibility, scoped exports, and bundle generation
|
|
69
|
+
- updated README and architecture docs to reflect the `0.2.0` asset, export, and packaging model
|
|
70
|
+
|
|
71
|
+
## 0.1.1 - 2026-06-17
|
|
72
|
+
|
|
73
|
+
### Added
|
|
74
|
+
|
|
75
|
+
- `harness --version` support for checking the CLI release version directly
|
|
76
|
+
- release-facing documentation for version visibility and pre-release verification
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- stricter workspace validation for timezone presence, history integrity, compatibility target duplication, and snapshot consistency
|
|
81
|
+
- clearer `diff` output with metadata-field change summaries
|
|
82
|
+
- clearer `history` output with current-version markers and snapshot paths
|
|
83
|
+
- more focused `show` output with `--metadata` and `--content` modes
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HarnessBrew contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# HarnessBrew
|
|
2
|
+
|
|
3
|
+
HarnessBrew 是面向 AI Agent 资产的 Git 包管理器。它的定位类似 Homebrew:通过 Git Tap 发现资产,通过 Formula 描述资产,通过 Cellar 与 Receipt 安装、升级和安全卸载资产。
|
|
4
|
+
|
|
5
|
+
HarnessBrew 不托管资产。个人、团队和第三方资产都保存在各自的 Git 仓库中,并使用完全相同的安装机制。
|
|
6
|
+
|
|
7
|
+
## 主要能力
|
|
8
|
+
|
|
9
|
+
- 注册、更新和移除 Git Tap
|
|
10
|
+
- 校验并搜索 skill、agent、workflow、instruction、prompt、MCP 和 adapter Formula
|
|
11
|
+
- 解析依赖、循环、缺失项与冲突
|
|
12
|
+
- 按 Git commit 将不可变内容安装到 Cellar
|
|
13
|
+
- 链接到 OpenAI Codex 和 Claude Code
|
|
14
|
+
- 通过 Receipt 跟踪文件所有权和 SHA-256 摘要
|
|
15
|
+
- 检测可用升级,并在升级后保留 Agent target 链接
|
|
16
|
+
- 使用 `Harnessfile` 和 lockfile 在不同设备上复现环境
|
|
17
|
+
- 从 npm 安装并通过 GitHub Release 发布
|
|
18
|
+
|
|
19
|
+
## 安装
|
|
20
|
+
|
|
21
|
+
要求:Node.js 20 或更高版本,系统中可用 Git。
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install --global harnessbrew
|
|
25
|
+
harnessbrew --version
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
也可以直接使用:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx harnessbrew help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
HarnessBrew 默认将受管状态保存到 `~/.harnessbrew`。测试或隔离环境可以设置 `HARNESSBREW_HOME`。
|
|
35
|
+
|
|
36
|
+
## 快速开始
|
|
37
|
+
|
|
38
|
+
注册自己的资产 Tap:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
harnessbrew tap add xiejinheng/agents git@github.com:xiejinheng/agent-assets.git
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
搜索并查看 Formula:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
harnessbrew search review
|
|
48
|
+
harnessbrew search --kind skill --target openai-codex
|
|
49
|
+
harnessbrew info xiejinheng/agents/code-review
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
安装到 Cellar,并链接到 Codex:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
harnessbrew install xiejinheng/agents/code-review \
|
|
56
|
+
--target openai-codex
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
如果只希望保存到 Cellar,不写入 Agent 配置目录,可以省略 `--target`。
|
|
60
|
+
|
|
61
|
+
更新和升级:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
harnessbrew update
|
|
65
|
+
harnessbrew outdated
|
|
66
|
+
harnessbrew upgrade code-review
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
安全卸载:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
harnessbrew uninstall code-review
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
若受管文件或链接已被修改,HarnessBrew 会停止卸载。确认需要删除时可以显式传入 `--force`。
|
|
76
|
+
|
|
77
|
+
## Homebrew 概念对应
|
|
78
|
+
|
|
79
|
+
| Homebrew | HarnessBrew |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `brew` | `harnessbrew` |
|
|
82
|
+
| Tap | Git 资产源仓库 |
|
|
83
|
+
| Formula / Cask | Agent 资产 Formula |
|
|
84
|
+
| Cellar | 按 Git commit 隔离的本地安装区 |
|
|
85
|
+
| Link | 到 Codex、Claude Code 等 target 的链接 |
|
|
86
|
+
| `Brewfile` | `Harnessfile` |
|
|
87
|
+
| Receipt | 安装来源、文件摘要与所有权记录 |
|
|
88
|
+
|
|
89
|
+
## 创建 Tap
|
|
90
|
+
|
|
91
|
+
Tap 是普通 Git 仓库。推荐按资产集合建立 Tap,不需要为每个 skill 单独建立仓库。
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
my-agent-tap/
|
|
95
|
+
├── tap.json
|
|
96
|
+
├── skills/
|
|
97
|
+
│ └── code-review/
|
|
98
|
+
│ ├── formula.json
|
|
99
|
+
│ └── SKILL.md
|
|
100
|
+
├── workflows/
|
|
101
|
+
├── agents/
|
|
102
|
+
├── instructions/
|
|
103
|
+
├── prompts/
|
|
104
|
+
├── mcp/
|
|
105
|
+
└── adapters/
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
最小 `tap.json`:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"schemaVersion": 1
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Formula 的目录名称必须与 `name` 一致,目录类型必须与 `kind` 一致:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"schemaVersion": 1,
|
|
121
|
+
"name": "code-review",
|
|
122
|
+
"kind": "skill",
|
|
123
|
+
"description": "Review code changes with a consistent rubric.",
|
|
124
|
+
"entry": "SKILL.md",
|
|
125
|
+
"targets": ["openai-codex", "claude-code"],
|
|
126
|
+
"dependencies": [
|
|
127
|
+
"xiejinheng/agents/repository-guardrails"
|
|
128
|
+
],
|
|
129
|
+
"conflicts": [],
|
|
130
|
+
"tags": ["review", "quality"]
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
完整坐标为 `<owner>/<tap>/<formula>`。依赖和冲突必须使用完整坐标,以避免跨 Tap 名称歧义。
|
|
135
|
+
|
|
136
|
+
Git commit 是安装版本的唯一事实来源;Formula 不维护 `.snapshots` 或重复的 `history`。
|
|
137
|
+
|
|
138
|
+
## Target
|
|
139
|
+
|
|
140
|
+
当前内置:
|
|
141
|
+
|
|
142
|
+
- `openai-codex`
|
|
143
|
+
- `claude-code`
|
|
144
|
+
|
|
145
|
+
可以在安装时指定 target:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
harnessbrew install code-review --target openai-codex
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
默认 target 根目录分别是 `~/.codex` 和 `~/.claude`。需要隔离安装时可使用:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
harnessbrew install code-review \
|
|
155
|
+
--target openai-codex \
|
|
156
|
+
--target-root /path/to/sandbox/.codex
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
也可以单独管理链接:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
harnessbrew link code-review --target openai-codex
|
|
163
|
+
harnessbrew unlink code-review --target openai-codex
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Harnessfile
|
|
167
|
+
|
|
168
|
+
`Harnessfile` 适合提交到个人 dotfiles 或项目仓库:
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
schemaVersion: 1
|
|
172
|
+
taps:
|
|
173
|
+
- name: xiejinheng/agents
|
|
174
|
+
git: git@github.com:xiejinheng/agent-assets.git
|
|
175
|
+
ref: main
|
|
176
|
+
|
|
177
|
+
assets:
|
|
178
|
+
- formula: xiejinheng/agents/code-review
|
|
179
|
+
targets: [openai-codex]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
安装并生成 `Harnessfile.lock`:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
harnessbrew bundle install
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
lockfile 会记录每个 Tap 的准确 commit、依赖闭包和 target,应与 `Harnessfile` 一起提交到 Git。
|
|
189
|
+
|
|
190
|
+
在其他设备运行同一命令时,HarnessBrew 会检出 lockfile 固定的 commit,而不是未经确认地使用 Tap 最新版本。
|
|
191
|
+
|
|
192
|
+
清理清单之外的受管资产:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
harnessbrew bundle cleanup
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
使用其他文件路径:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
harnessbrew bundle install --file ./config/Harnessfile
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## CLI
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
harnessbrew tap add <owner/name> <git-url> [--ref <ref>]
|
|
208
|
+
harnessbrew tap list
|
|
209
|
+
harnessbrew tap update [owner/name]
|
|
210
|
+
harnessbrew tap remove <owner/name>
|
|
211
|
+
harnessbrew untap <owner/name>
|
|
212
|
+
harnessbrew search [query] [--kind <kind>] [--target <target>]
|
|
213
|
+
harnessbrew info <formula>
|
|
214
|
+
harnessbrew install <formula> [--target <target>] [--target-root <path>]
|
|
215
|
+
harnessbrew list
|
|
216
|
+
harnessbrew link <formula> --target <target> [--target-root <path>]
|
|
217
|
+
harnessbrew unlink <formula> --target <target> [--force]
|
|
218
|
+
harnessbrew update
|
|
219
|
+
harnessbrew outdated
|
|
220
|
+
harnessbrew upgrade [formula]
|
|
221
|
+
harnessbrew uninstall <formula> [--force]
|
|
222
|
+
harnessbrew bundle install [--file <path>]
|
|
223
|
+
harnessbrew bundle cleanup [--file <path>]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## 本地目录
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
~/.harnessbrew/
|
|
230
|
+
├── taps/ # HarnessBrew 管理的 Git 工作树
|
|
231
|
+
├── cellar/ # 按 Formula 与 commit 隔离的不可变内容
|
|
232
|
+
├── receipts/ # 安装、依赖、target 链接和摘要
|
|
233
|
+
└── state.json # Tap 注册状态
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Tap 工作树和 Cellar 内容都由 HarnessBrew 管理,不应直接编辑。个人资产应在原始 Tap 仓库中修改、提交和推送,再通过 `update`/`upgrade` 安装。
|
|
237
|
+
|
|
238
|
+
## 安全边界
|
|
239
|
+
|
|
240
|
+
- Formula 是声明式 JSON;HarnessBrew 不执行 Tap 中的任意脚本。
|
|
241
|
+
- Formula 入口不能逃逸所属目录。
|
|
242
|
+
- 安装前会检查依赖、冲突和 target 兼容性。
|
|
243
|
+
- HarnessBrew 不覆盖未由 Receipt 管理的目标文件。
|
|
244
|
+
- 卸载前会检查 Cellar 文件摘要和符号链接目标。
|
|
245
|
+
- 私有 Tap 凭据由系统 Git/SSH credential 机制管理。
|
|
246
|
+
|
|
247
|
+
## 开发
|
|
248
|
+
|
|
249
|
+
项目使用 TypeScript 7.0,并启用严格类型检查。
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
npm ci
|
|
253
|
+
npm run build
|
|
254
|
+
npm test
|
|
255
|
+
npm run check
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`npm run check` 会执行 TypeScript 编译、全部 Node.js 测试、安装包冒烟测试和 `npm pack --dry-run`。
|
|
259
|
+
|
|
260
|
+
## 架构
|
|
261
|
+
|
|
262
|
+
完整设计见 [docs/architecture.md](docs/architecture.md)。
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
MIT
|
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
|
package/dist/bin.js
ADDED
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,CAAC,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface CliIO {
|
|
2
|
+
stdout: (message: string) => void;
|
|
3
|
+
stderr: (message: string) => void;
|
|
4
|
+
}
|
|
5
|
+
export interface CliOptions {
|
|
6
|
+
home?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function runCli(args: readonly string[], io?: CliIO, options?: CliOptions): Promise<number>;
|
|
9
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA8OD,wBAAsB,MAAM,CAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,GAAE,KAAiB,EACrB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,MAAM,CAAC,CAUjB"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { HarnessBrewError } from "./core/errors.js";
|
|
3
|
+
import { formulaKinds, getFormula, searchFormulas } from "./core/formulas.js";
|
|
4
|
+
import { installFormula, listInstalled, uninstallFormula } from "./core/installations.js";
|
|
5
|
+
import { builtinTargets, installForTarget, linkFormula, unlinkFormula } from "./core/targets.js";
|
|
6
|
+
import { findOutdated, upgradeFormulas } from "./core/upgrades.js";
|
|
7
|
+
import { bundleCleanup, bundleInstall } from "./core/bundle.js";
|
|
8
|
+
import { resolveHarnessHome } from "./core/paths.js";
|
|
9
|
+
import { addTap, listTaps, removeTap, updateTaps } from "./core/taps.js";
|
|
10
|
+
import { VERSION } from "./version.js";
|
|
11
|
+
const defaultIO = {
|
|
12
|
+
stdout: (message) => console.log(message),
|
|
13
|
+
stderr: (message) => console.error(message)
|
|
14
|
+
};
|
|
15
|
+
const helpText = `HarnessBrew ${VERSION}
|
|
16
|
+
|
|
17
|
+
A Git-native package manager for AI Agent assets.
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
harnessbrew <command> [options]
|
|
21
|
+
|
|
22
|
+
Commands:
|
|
23
|
+
help Show this help
|
|
24
|
+
version Show the installed version
|
|
25
|
+
tap Add, list, update, or remove Git taps
|
|
26
|
+
untap Remove a Git tap
|
|
27
|
+
search Search formulas across registered taps
|
|
28
|
+
info Show formula metadata
|
|
29
|
+
install Install a formula and its dependencies
|
|
30
|
+
list List installed formulas
|
|
31
|
+
uninstall Safely uninstall a formula
|
|
32
|
+
link Link an installed formula to an Agent target
|
|
33
|
+
unlink Remove a managed target link
|
|
34
|
+
update Fetch all registered taps
|
|
35
|
+
outdated List installed formulas with available changes
|
|
36
|
+
upgrade Upgrade formulas while preserving target links
|
|
37
|
+
bundle Rebuild or clean an environment from Harnessfile
|
|
38
|
+
`;
|
|
39
|
+
function optionValue(args, name) {
|
|
40
|
+
const index = args.indexOf(name);
|
|
41
|
+
if (index === -1)
|
|
42
|
+
return undefined;
|
|
43
|
+
const value = args[index + 1];
|
|
44
|
+
if (value === undefined)
|
|
45
|
+
throw new HarnessBrewError(`Missing value for ${name}.`);
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
async function runTapCommand(args, home, io) {
|
|
49
|
+
const [action = "list", ...rest] = args;
|
|
50
|
+
if (action === "list") {
|
|
51
|
+
const taps = await listTaps(home);
|
|
52
|
+
taps.forEach((tap) => io.stdout(`${tap.name}\t${tap.commit.slice(0, 12)}\t${tap.url}`));
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
if (action === "add") {
|
|
56
|
+
const [name, url] = rest;
|
|
57
|
+
if (name === undefined || url === undefined) {
|
|
58
|
+
throw new HarnessBrewError("Usage: harnessbrew tap add <owner/name> <git-url> [--ref <ref>]");
|
|
59
|
+
}
|
|
60
|
+
const ref = optionValue(rest, "--ref");
|
|
61
|
+
const record = await addTap(home, name, url, ref === undefined ? {} : { ref });
|
|
62
|
+
io.stdout(`Tapped ${record.name} at ${record.commit.slice(0, 12)}.`);
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
if (action === "update") {
|
|
66
|
+
const updates = await updateTaps(home, rest[0]);
|
|
67
|
+
updates.forEach((update) => {
|
|
68
|
+
io.stdout(update.changed
|
|
69
|
+
? `Updated ${update.name}: ${update.before.slice(0, 12)} -> ${update.after.slice(0, 12)}.`
|
|
70
|
+
: `${update.name} is already up-to-date.`);
|
|
71
|
+
});
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
if (action === "remove") {
|
|
75
|
+
const [name] = rest;
|
|
76
|
+
if (name === undefined)
|
|
77
|
+
throw new HarnessBrewError("Usage: harnessbrew tap remove <owner/name>");
|
|
78
|
+
await removeTap(home, name);
|
|
79
|
+
io.stdout(`Untapped ${name}.`);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
throw new HarnessBrewError(`Unknown tap action: ${action}`);
|
|
83
|
+
}
|
|
84
|
+
async function execute(args, io, options) {
|
|
85
|
+
const [command] = args;
|
|
86
|
+
if (command === undefined || command === "help" || command === "--help" || command === "-h") {
|
|
87
|
+
io.stdout(helpText.trimEnd());
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if (command === "version" || command === "--version" || command === "-v") {
|
|
91
|
+
io.stdout(VERSION);
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
const home = resolveHarnessHome(options.home);
|
|
95
|
+
if (command === "tap") {
|
|
96
|
+
return runTapCommand(args.slice(1), home, io);
|
|
97
|
+
}
|
|
98
|
+
if (command === "update") {
|
|
99
|
+
const updates = await updateTaps(home);
|
|
100
|
+
updates.forEach((update) => io.stdout(update.changed
|
|
101
|
+
? `Updated ${update.name}: ${update.before.slice(0, 12)} -> ${update.after.slice(0, 12)}.`
|
|
102
|
+
: `${update.name} is already up-to-date.`));
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
if (command === "untap") {
|
|
106
|
+
const name = args[1];
|
|
107
|
+
if (name === undefined)
|
|
108
|
+
throw new HarnessBrewError("Usage: harnessbrew untap <owner/name>");
|
|
109
|
+
await removeTap(home, name);
|
|
110
|
+
io.stdout(`Untapped ${name}.`);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
if (command === "search") {
|
|
114
|
+
const kindValue = optionValue(args, "--kind");
|
|
115
|
+
if (kindValue !== undefined && !formulaKinds.includes(kindValue)) {
|
|
116
|
+
throw new HarnessBrewError(`Unsupported formula kind: ${kindValue}`);
|
|
117
|
+
}
|
|
118
|
+
const target = optionValue(args, "--target");
|
|
119
|
+
const query = args.slice(1).find((value, index, values) => {
|
|
120
|
+
if (value.startsWith("--"))
|
|
121
|
+
return false;
|
|
122
|
+
return index === 0 || !values[index - 1]?.startsWith("--");
|
|
123
|
+
}) ?? "";
|
|
124
|
+
const formulas = await searchFormulas(home, query, {
|
|
125
|
+
...(kindValue === undefined ? {} : { kind: kindValue }),
|
|
126
|
+
...(target === undefined ? {} : { target })
|
|
127
|
+
});
|
|
128
|
+
formulas.forEach((formula) => io.stdout(`${formula.coordinate}\t${formula.kind}\t${formula.description}`));
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
if (command === "info") {
|
|
132
|
+
const name = args[1];
|
|
133
|
+
if (name === undefined)
|
|
134
|
+
throw new HarnessBrewError("Usage: harnessbrew info <formula>");
|
|
135
|
+
const formula = await getFormula(home, name);
|
|
136
|
+
io.stdout(JSON.stringify({
|
|
137
|
+
coordinate: formula.coordinate,
|
|
138
|
+
kind: formula.kind,
|
|
139
|
+
description: formula.description,
|
|
140
|
+
targets: formula.targets,
|
|
141
|
+
dependencies: formula.dependencies,
|
|
142
|
+
commit: formula.commit,
|
|
143
|
+
...(formula.deprecated === undefined ? {} : { deprecated: formula.deprecated })
|
|
144
|
+
}, null, 2));
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
if (command === "install") {
|
|
148
|
+
const name = args[1];
|
|
149
|
+
if (name === undefined)
|
|
150
|
+
throw new HarnessBrewError("Usage: harnessbrew install <formula>");
|
|
151
|
+
const targetValue = optionValue(args, "--target");
|
|
152
|
+
if (targetValue !== undefined && !builtinTargets.includes(targetValue)) {
|
|
153
|
+
throw new HarnessBrewError(`Unsupported built-in target: ${targetValue}`);
|
|
154
|
+
}
|
|
155
|
+
const targetRoot = optionValue(args, "--target-root");
|
|
156
|
+
const receipts = targetValue === undefined
|
|
157
|
+
? await installFormula(home, name)
|
|
158
|
+
: await installForTarget(home, name, targetValue, targetRoot === undefined ? {} : { root: targetRoot });
|
|
159
|
+
receipts.forEach((receipt) => io.stdout(`Installed ${receipt.coordinate} at ${receipt.commit.slice(0, 12)}.`));
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
if (command === "list") {
|
|
163
|
+
const receipts = await listInstalled(home);
|
|
164
|
+
receipts.forEach((receipt) => io.stdout(`${receipt.coordinate}\t${receipt.commit.slice(0, 12)}`));
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
if (command === "uninstall") {
|
|
168
|
+
const name = args[1];
|
|
169
|
+
if (name === undefined)
|
|
170
|
+
throw new HarnessBrewError("Usage: harnessbrew uninstall <formula> [--force]");
|
|
171
|
+
const receipt = await uninstallFormula(home, name, { force: args.includes("--force") });
|
|
172
|
+
io.stdout(`Uninstalled ${receipt.coordinate}.`);
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
if (command === "link" || command === "unlink") {
|
|
176
|
+
const name = args[1];
|
|
177
|
+
const targetValue = optionValue(args, "--target");
|
|
178
|
+
if (name === undefined || targetValue === undefined) {
|
|
179
|
+
throw new HarnessBrewError(`Usage: harnessbrew ${command} <formula> --target <target> [--target-root <path>]`);
|
|
180
|
+
}
|
|
181
|
+
if (!builtinTargets.includes(targetValue)) {
|
|
182
|
+
throw new HarnessBrewError(`Unsupported built-in target: ${targetValue}`);
|
|
183
|
+
}
|
|
184
|
+
if (command === "link") {
|
|
185
|
+
await linkFormula(home, name, targetValue, {
|
|
186
|
+
...(optionValue(args, "--target-root") === undefined ? {} : { root: optionValue(args, "--target-root") })
|
|
187
|
+
});
|
|
188
|
+
io.stdout(`Linked ${name} to ${targetValue}.`);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
await unlinkFormula(home, name, targetValue, args.includes("--force"));
|
|
192
|
+
io.stdout(`Unlinked ${name} from ${targetValue}.`);
|
|
193
|
+
}
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
if (command === "outdated") {
|
|
197
|
+
const outdated = await findOutdated(home);
|
|
198
|
+
outdated.forEach((item) => io.stdout(item.available
|
|
199
|
+
? `${item.coordinate}\t${item.installedCommit.slice(0, 12)} -> ${item.availableCommit?.slice(0, 12)}`
|
|
200
|
+
: `${item.coordinate}\t${item.installedCommit.slice(0, 12)} -> unavailable`));
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
if (command === "upgrade") {
|
|
204
|
+
const name = args[1]?.startsWith("--") === true ? undefined : args[1];
|
|
205
|
+
const results = await upgradeFormulas(home, name);
|
|
206
|
+
if (results.length === 0)
|
|
207
|
+
io.stdout("All installed formulas are up-to-date.");
|
|
208
|
+
results.forEach((result) => io.stdout(`Upgraded ${result.coordinate}: ${result.before.slice(0, 12)} -> ${result.after.slice(0, 12)}.`));
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
if (command === "bundle") {
|
|
212
|
+
const action = args[1];
|
|
213
|
+
const filePath = optionValue(args, "--file") ?? path.resolve("Harnessfile");
|
|
214
|
+
if (action === "install") {
|
|
215
|
+
const lock = await bundleInstall(home, filePath);
|
|
216
|
+
io.stdout(`Bundle installed ${lock.assets.length} formulas from ${lock.taps.length} taps.`);
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
if (action === "cleanup") {
|
|
220
|
+
const result = await bundleCleanup(home, filePath);
|
|
221
|
+
result.removed.forEach((coordinate) => io.stdout(`Removed ${coordinate}.`));
|
|
222
|
+
return 0;
|
|
223
|
+
}
|
|
224
|
+
throw new HarnessBrewError("Usage: harnessbrew bundle <install|cleanup> [--file <Harnessfile>]");
|
|
225
|
+
}
|
|
226
|
+
io.stderr(`Unknown command: ${command}`);
|
|
227
|
+
io.stderr("Run 'harnessbrew help' for usage.");
|
|
228
|
+
return 1;
|
|
229
|
+
}
|
|
230
|
+
export async function runCli(args, io = defaultIO, options = {}) {
|
|
231
|
+
try {
|
|
232
|
+
return await execute(args, io, options);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
if (error instanceof HarnessBrewError) {
|
|
236
|
+
io.stderr(error.message);
|
|
237
|
+
return 1;
|
|
238
|
+
}
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAoB,MAAM,oBAAoB,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAsB,MAAM,mBAAmB,CAAC;AACrH,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAWvC,MAAM,SAAS,GAAU;IACvB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;IACzC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;CAC5C,CAAC;AAEF,MAAM,QAAQ,GAAG,eAAe,OAAO;;;;;;;;;;;;;;;;;;;;;;;CAuBtC,CAAC;AAEF,SAAS,WAAW,CAAC,IAAuB,EAAE,IAAY;IACxD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,gBAAgB,CAAC,qBAAqB,IAAI,GAAG,CAAC,CAAC;IAClF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAuB,EAAE,IAAY,EAAE,EAAS;IAC3E,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAExC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACxF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QACrB,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;QACzB,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,IAAI,gBAAgB,CAAC,iEAAiE,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/E,EAAE,CAAC,MAAM,CAAC,UAAU,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACrE,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YACzB,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO;gBACtB,CAAC,CAAC,WAAW,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG;gBAC1F,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,yBAAyB,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;QACpB,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,gBAAgB,CAAC,4CAA4C,CAAC,CAAC;QACjG,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5B,EAAE,CAAC,MAAM,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC;QAC/B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,IAAI,gBAAgB,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAAuB,EAAE,EAAS,EAAE,OAAmB;IAC5E,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IAEvB,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC5F,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACzE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,IAAI,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO;YAClD,CAAC,CAAC,WAAW,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG;YAC1F,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,yBAAyB,CAAC,CAAC,CAAC;QAC9C,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;QAC5F,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC5B,EAAE,CAAC,MAAM,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC;QAC/B,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC9C,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,SAAwB,CAAC,EAAE,CAAC;YAChF,MAAM,IAAI,gBAAgB,CAAC,6BAA6B,SAAS,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YACxD,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,OAAO,KAAK,CAAC;YACzC,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC,CAAC,IAAI,EAAE,CAAC;QACT,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE;YACjD,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAwB,EAAE,CAAC;YACtE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;SAC5C,CAAC,CAAC;QACH,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC3G,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,gBAAgB,CAAC,mCAAmC,CAAC,CAAC;QACxF,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7C,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;YACvB,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;SAChF,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACb,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,gBAAgB,CAAC,sCAAsC,CAAC,CAAC;QAC3F,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAClD,IAAI,WAAW,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,WAA4B,CAAC,EAAE,CAAC;YACxF,MAAM,IAAI,gBAAgB,CAAC,gCAAgC,WAAW,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACtD,MAAM,QAAQ,GAAG,WAAW,KAAK,SAAS;YACxC,CAAC,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC;YAClC,CAAC,CAAC,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,WAA4B,EAAE,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3H,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,aAAa,OAAO,CAAC,UAAU,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/G,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;QAC3C,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAClG,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,gBAAgB,CAAC,kDAAkD,CAAC,CAAC;QACvG,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACxF,EAAE,CAAC,MAAM,CAAC,eAAe,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC;QAChD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAClD,IAAI,IAAI,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YACpD,MAAM,IAAI,gBAAgB,CAAC,sBAAsB,OAAO,qDAAqD,CAAC,CAAC;QACjH,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,WAA4B,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,gBAAgB,CAAC,gCAAgC,WAAW,EAAE,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACvB,MAAM,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,WAA4B,EAAE;gBAC1D,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,eAAe,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,EAAE,eAAe,CAAW,EAAE,CAAC;aACpH,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,UAAU,IAAI,OAAO,WAAW,GAAG,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,WAA4B,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;YACxF,EAAE,CAAC,MAAM,CAAC,YAAY,IAAI,SAAS,WAAW,GAAG,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;QAC1C,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS;YACjD,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;YACrG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC;QAChF,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtE,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,EAAE,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC;QAC9E,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CACnC,YAAY,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAChG,CAAC,CAAC;QACH,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC5E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACjD,EAAE,CAAC,MAAM,CAAC,oBAAoB,IAAI,CAAC,MAAM,CAAC,MAAM,kBAAkB,IAAI,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,CAAC;YAC5F,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,UAAU,GAAG,CAAC,CAAC,CAAC;YAC5E,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,IAAI,gBAAgB,CAAC,oEAAoE,CAAC,CAAC;IACnG,CAAC;IAED,EAAE,CAAC,MAAM,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IACzC,EAAE,CAAC,MAAM,CAAC,mCAAmC,CAAC,CAAC;IAC/C,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,IAAuB,EACvB,EAAE,GAAU,SAAS,EACrB,OAAO,GAAe,EAAE;IAExB,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;YACtC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACzB,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|