@lannguyensi/harness 0.5.0 → 0.6.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 +77 -0
- package/README.md +56 -16
- package/dist/cli/add/mutate.d.ts +4 -0
- package/dist/cli/add/mutate.js +30 -1
- package/dist/cli/add/mutate.js.map +1 -1
- package/dist/cli/adopt/derive.d.ts +23 -0
- package/dist/cli/adopt/derive.js +85 -0
- package/dist/cli/adopt/derive.js.map +1 -1
- package/dist/cli/adopt/index.d.ts +9 -1
- package/dist/cli/adopt/index.js +72 -4
- package/dist/cli/adopt/index.js.map +1 -1
- package/dist/cli/apply/apply.d.ts +45 -1
- package/dist/cli/apply/apply.js +237 -25
- package/dist/cli/apply/apply.js.map +1 -1
- package/dist/cli/apply/generate-settings.d.ts +13 -1
- package/dist/cli/apply/generate-settings.js +45 -0
- package/dist/cli/apply/generate-settings.js.map +1 -1
- package/dist/cli/apply/index.d.ts +1 -0
- package/dist/cli/apply/index.js +1 -0
- package/dist/cli/apply/index.js.map +1 -1
- package/dist/cli/apply/next-steps.d.ts +7 -0
- package/dist/cli/apply/next-steps.js +37 -0
- package/dist/cli/apply/next-steps.js.map +1 -0
- package/dist/cli/audit.js +2 -1
- package/dist/cli/audit.js.map +1 -1
- package/dist/cli/diff/since-apply.js +1 -1
- package/dist/cli/diff/since-apply.js.map +1 -1
- package/dist/cli/doctor/format.js +17 -3
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/index.js +9 -2
- package/dist/cli/doctor/index.js.map +1 -1
- package/dist/cli/doctor/types.d.ts +0 -2
- package/dist/cli/index.js +83 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/validate/index.d.ts +8 -0
- package/dist/cli/validate/index.js +37 -1
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/io/harness-lock.d.ts +6 -1
- package/dist/io/harness-lock.js +2 -2
- package/dist/io/harness-lock.js.map +1 -1
- package/dist/io/merge-settings.d.ts +8 -0
- package/dist/io/merge-settings.js +47 -0
- package/dist/io/merge-settings.js.map +1 -0
- package/dist/policies/ledger-client.js +3 -2
- package/dist/policies/ledger-client.js.map +1 -1
- package/dist/policies/requires.js +3 -2
- package/dist/policies/requires.js.map +1 -1
- package/dist/probes/mcp.d.ts +13 -0
- package/dist/probes/mcp.js +26 -3
- package/dist/probes/mcp.js.map +1 -1
- package/dist/runtime/intercept.js +3 -2
- package/dist/runtime/intercept.js.map +1 -1
- package/dist/runtime/ledger-record.d.ts +8 -0
- package/dist/runtime/ledger-record.js +11 -3
- package/dist/runtime/ledger-record.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,83 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.6.0] - 2026-05-03
|
|
11
|
+
|
|
12
|
+
**Headline: the Phase-5 adoption-blocker cycle closes end-to-end.**
|
|
13
|
+
`harness apply` now writes directly into a Claude Code settings
|
|
14
|
+
discovery path (`--target` + `--merge`), translates the manifest's
|
|
15
|
+
`tools.mcp[]` into the settings.json `mcpServers` block (so a real
|
|
16
|
+
`claude -p --settings <apply'd>` session actually loads them), prints
|
|
17
|
+
a Next-steps hint that names the real wire-up commands instead of
|
|
18
|
+
leaving adopters to guess, and `harness adopt` round-trips hand-edits
|
|
19
|
+
to `mcpServers` back into the manifest. The full
|
|
20
|
+
`apply → hand-edit → adopt → apply` cycle is byte-identical on the
|
|
21
|
+
settings.json bytes.
|
|
22
|
+
|
|
23
|
+
Operator note: no schema changes; `harness.lock` gains an optional
|
|
24
|
+
`target` entry kind (additive). Existing `harness.lock` files without
|
|
25
|
+
target entries continue to parse. The new flags on `apply` are all
|
|
26
|
+
opt-in; the default invocation still writes to `harness.generated/`.
|
|
27
|
+
Per-package version bumped from 0.5.0 to 0.6.0; this is the first
|
|
28
|
+
minor release on the `@lannguyensi/harness` npm distribution. No
|
|
29
|
+
operator action required beyond `npm i -g @lannguyensi/harness@0.6.0`
|
|
30
|
+
on machines running the published binary.
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **`harness apply --target / --merge / --force`** (task `d38f6f91`, PR #58):
|
|
35
|
+
write the rendered settings.json directly into a Claude Code settings
|
|
36
|
+
discovery path (e.g. `.claude/settings.local.json` or
|
|
37
|
+
`~/.claude/settings.json`). `--merge` does a 3-way merge that replaces
|
|
38
|
+
harness-owned top-level keys (today: `hooks`, `mcpServers`) and preserves
|
|
39
|
+
everything else. `harness.lock` records the target sha so `validate
|
|
40
|
+
--check-lock` flags out-of-band edits. Closes the adoption blocker that
|
|
41
|
+
forced every adopter into a hand `cp` or per-invocation `--settings`.
|
|
42
|
+
- **`apply` translates `tools.mcp[]` into the settings.json `mcpServers`
|
|
43
|
+
block** (task `62380337`, PR #59). The Phase 5 #1a caveat is closed:
|
|
44
|
+
`init.mcp_servers` in a `claude -p --settings <apply'd>` session now
|
|
45
|
+
contains the manifest's MCP entries. Disabled servers (`enabled: false`)
|
|
46
|
+
are omitted; warnings (not errors) cover entries that survive schema
|
|
47
|
+
but produce no runnable command. String-form commands with embedded
|
|
48
|
+
whitespace in paths must be expressed as the array form to preserve
|
|
49
|
+
token boundaries.
|
|
50
|
+
- **`apply` prints a Next-steps hint after a successful run** (task
|
|
51
|
+
`517aa919`, PR #60). After the summary line, the CLI prints concrete,
|
|
52
|
+
copy-pasteable next actions: one-shot `claude -p --settings ...`,
|
|
53
|
+
project-scope `harness apply --target .claude/settings.local.json`,
|
|
54
|
+
and user-global `harness apply --target ~/.claude/settings.json --merge`.
|
|
55
|
+
When `--target` was actually written, the hint collapses to a single
|
|
56
|
+
verify line with `--settings <targetPath>` included (so non-canonical
|
|
57
|
+
target paths still resolve through `claude -p`). Two new flags pair
|
|
58
|
+
with this: `--quiet` suppresses the hint while keeping the summary,
|
|
59
|
+
and `--json` emits a machine-readable JSON summary instead of prose
|
|
60
|
+
(implies `--quiet`; refusal outcomes still set non-zero exit).
|
|
61
|
+
Motivated by a 2026-05-03 hallucination incident where an agent
|
|
62
|
+
fabricated a non-existent `claude -p --output-dir` flag because
|
|
63
|
+
nothing in the apply output guided the wire-up step; both unit and
|
|
64
|
+
CLI integration tests assert the hint never contains `--output-dir`.
|
|
65
|
+
- **`adopt` reverse-projection for `mcpServers` into `tools.mcp[]`**
|
|
66
|
+
(task `7059d92b`, PR #61). Closes the round-trip gap: hand-edits to
|
|
67
|
+
settings.json's `mcpServers` block can now be captured back into the
|
|
68
|
+
manifest. New entries are appended; same-name entries with different
|
|
69
|
+
command/env are replaced (preserving manifest-only fields like `health`
|
|
70
|
+
and `enabled: false`, so adopting a hand-edit does not silently wipe
|
|
71
|
+
doctor/probe/policy metadata). The full
|
|
72
|
+
`harness apply --target ... --merge → hand-edit → harness adopt → harness apply`
|
|
73
|
+
cycle is byte-identical on the settings.json bytes.
|
|
74
|
+
|
|
75
|
+
### Notes for upgraders
|
|
76
|
+
|
|
77
|
+
- The settings.json output now includes a `mcpServers` key when your
|
|
78
|
+
manifest declares enabled MCP servers. On the first apply after
|
|
79
|
+
upgrade, the file grows by that block. The three-state compare handles
|
|
80
|
+
this safely (no spurious drift-refuse on the generated file), but if
|
|
81
|
+
you have hand-edited a `mcpServers` block into a previously apply'd
|
|
82
|
+
settings.json, the next apply will refuse (`drift-refuse`) until you
|
|
83
|
+
reconcile via `harness adopt` or `--overwrite-drift`.
|
|
84
|
+
|
|
8
85
|
## [0.5.0] - 2026-05-01
|
|
9
86
|
|
|
10
87
|
**Phase 5: dogfood + polish.** Phase 4 shipped policies that fire; Phase 5
|
package/README.md
CHANGED
|
@@ -6,22 +6,39 @@ One zod-validated YAML manifest for grounding, tools, memory, hooks, and policie
|
|
|
6
6
|
|
|
7
7
|
> Most config tools tell you what an agent is configured to use. `harness` tells you what an agent is *allowed to do*, under this exact context, and why.
|
|
8
8
|
|
|
9
|
-
`harness` collapses the six-to-eight surfaces a working agent harness leaks across (`settings.json`, `CLAUDE.md`, memory frontmatter, MCP registrations, per-project overrides, hook scripts) into a single source of truth. Today (`v0.
|
|
9
|
+
`harness` collapses the six-to-eight surfaces a working agent harness leaks across (`settings.json`, `CLAUDE.md`, memory frontmatter, MCP registrations, per-project overrides, hook scripts) into a single source of truth. Today (`v0.5.0`) policies fire end-to-end: a `mcp__agent-tasks__pull_requests_merge` call against a session without a `review:${PR_NUMBER}` ledger entry refuses; `harness explain review-before-merge --trace` shows exactly why. Phase 6 adds an *Understanding Gate* (agents confirm task interpretation before editing); Phase 7 adds a *Risk Gate* that blocks `DROP TABLE` against a prod target, even when the model would happily run it.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i -g @lannguyensi/harness
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The CLI binary is `harness`. Node ≥ 20 required.
|
|
10
18
|
|
|
11
19
|
## Try it in 60 seconds
|
|
12
20
|
|
|
21
|
+
```bash
|
|
22
|
+
# Statically predict which policies fire for a tool call (no ledger, no LLM).
|
|
23
|
+
# Uses the bundled reference manifest from the npm package.
|
|
24
|
+
harness dry-run "merge PR 42" \
|
|
25
|
+
--tool mcp__agent-tasks__pull_requests_merge \
|
|
26
|
+
--tool-args '{"prNumber":42}' \
|
|
27
|
+
--config "$(npm root -g)/@lannguyensi/harness/dist/../docs/examples/full-manifest.yaml"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or from a checkout:
|
|
31
|
+
|
|
13
32
|
```bash
|
|
14
33
|
git clone https://github.com/LanNguyenSi/harness && cd harness
|
|
15
34
|
npm install && npm run build
|
|
16
|
-
|
|
17
|
-
# Statically predict which policies fire for a tool call (no ledger, no LLM)
|
|
18
35
|
node dist/cli/main.js dry-run "merge PR 42" \
|
|
19
36
|
--tool mcp__agent-tasks__pull_requests_merge \
|
|
20
37
|
--tool-args '{"prNumber":42}' \
|
|
21
38
|
--config docs/examples/full-manifest.yaml
|
|
22
39
|
```
|
|
23
40
|
|
|
24
|
-
`dry-run` reads the reference manifest
|
|
41
|
+
`dry-run` reads the reference manifest, runs the trigger matcher, substitutes `${PR_NUMBER}=42` through the JSONPath-restricted extract DSL, and tells you exactly which hooks would fire and which policies would match — before any ledger I/O.
|
|
25
42
|
|
|
26
43
|
## What a run looks like
|
|
27
44
|
|
|
@@ -72,10 +89,12 @@ When the matching policy actually fires (via `harness policy intercept`, wired b
|
|
|
72
89
|
{"decision":"deny","reason":"review-before-merge: no matching ledger entry for tag `review:42`"}
|
|
73
90
|
```
|
|
74
91
|
|
|
92
|
+
With `--verbose` (or `HARNESS_POLICY_VERBOSE=1`), stderr also carries a structured diagnostic block — policy name, ledger_tag, matched count, reason, sorted extract values — so the user sees *why* without a follow-up `explain --trace`.
|
|
93
|
+
|
|
75
94
|
After the entry is recorded, the same call is silently allowed. Every fire writes a `policy_decision` row that `harness audit` and `harness explain --trace` replay:
|
|
76
95
|
|
|
77
96
|
```
|
|
78
|
-
$
|
|
97
|
+
$ harness audit --since 1h --policy review-before-merge
|
|
79
98
|
|
|
80
99
|
timestamp policy outcome reason
|
|
81
100
|
------------------------ ------------------- ------- ---------------------------------------------
|
|
@@ -83,6 +102,27 @@ timestamp policy outcome reason
|
|
|
83
102
|
2026-04-30T18:31:00.000Z review-before-merge allow 1 matching ledger entries for tag `review:42`
|
|
84
103
|
```
|
|
85
104
|
|
|
105
|
+
Inside a Claude Code session, `--session` defaults to `$CLAUDE_SESSION_ID`, so the read path automatically lines up with what the runtime hook wrote.
|
|
106
|
+
|
|
107
|
+
## Wire into Claude Code
|
|
108
|
+
|
|
109
|
+
By default, `harness apply` writes the rendered settings to `harness.generated/settings.json` next to your manifest. To make Claude Code actually use it, point `apply` at a settings discovery path with `--target`:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Project scope: write straight to .claude/settings.local.json (created if missing).
|
|
113
|
+
harness apply --target .claude/settings.local.json
|
|
114
|
+
|
|
115
|
+
# User scope: merge harness-owned keys into your existing ~/.claude/settings.json,
|
|
116
|
+
# preserving env, permissions, enabledPlugins, and any other top-level keys.
|
|
117
|
+
harness apply --target ~/.claude/settings.json --merge
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`--merge` does a 3-way merge: harness-owned top-level keys (today: `hooks`) get replaced wholesale; everything else in the existing target file is preserved verbatim. Re-applying is idempotent: running twice produces the same target, and the second run reports `no changes`.
|
|
121
|
+
|
|
122
|
+
If the target exists and you pass neither `--merge` nor `--force`, apply refuses with a clear hint instead of clobbering. `--force` overwrites with the generated content as-is (no merge).
|
|
123
|
+
|
|
124
|
+
`harness.lock` records the target path + a sha256 of the merged output, so `harness validate --check-lock` flags out-of-band edits.
|
|
125
|
+
|
|
86
126
|
## Next steps
|
|
87
127
|
|
|
88
128
|
| If you want to... | Read |
|
|
@@ -96,14 +136,14 @@ timestamp policy outcome reason
|
|
|
96
136
|
## Common commands
|
|
97
137
|
|
|
98
138
|
```bash
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
139
|
+
harness init --template full --config /tmp/harness-demo/harness.yaml
|
|
140
|
+
harness describe --config /tmp/harness-demo/harness.yaml --pillar tools
|
|
141
|
+
harness doctor --config /tmp/harness-demo/harness.yaml --shallow
|
|
142
|
+
harness validate --config /tmp/harness-demo/harness.yaml
|
|
143
|
+
harness apply --config /tmp/harness-demo/harness.yaml # regenerate settings.json + MEMORY.md, write harness.lock
|
|
144
|
+
harness diff --since-apply --config /tmp/harness-demo/harness.yaml
|
|
145
|
+
harness explain review-before-merge --trace
|
|
146
|
+
harness audit --since 24h
|
|
107
147
|
```
|
|
108
148
|
|
|
109
149
|
## What's next
|
|
@@ -123,12 +163,12 @@ Both build on Phase 4's `policy intercept` runtime backbone; neither replaces it
|
|
|
123
163
|
- [x] Repo bootstrap (LICENSE, .gitignore)
|
|
124
164
|
- [x] README + VISION — repo legible
|
|
125
165
|
- [x] ARCHITECTURE — YAML shape + CLI surface agreed
|
|
126
|
-
- [x] ROADMAP — phases 1–
|
|
166
|
+
- [x] ROADMAP — phases 1–7 with acceptance criteria
|
|
127
167
|
- [x] Phase 1 — read-only inventory (`describe`, `validate`, `doctor`, `list`, `explain`, `diff`) — released as [`v0.1.0`](CHANGELOG.md#010---2026-04-29)
|
|
128
168
|
- [x] Phase 2 — managed edits (`init`, `add`, `remove`, `adopt`, `export`) — released as [`v0.2.0`](CHANGELOG.md#020---2026-04-29)
|
|
129
169
|
- [x] Phase 3 — declarative truth (`apply`, `diff --since-apply`, `harness.lock`) — released as [`v0.3.0`](CHANGELOG.md#030---2026-04-30)
|
|
130
170
|
- [x] Phase 4 — policy layer (`policy intercept`, `explain --trace`, `audit`, `dry-run`, requires-evaluator + extract DSL + grounding-mcp adapter) — released as [`v0.4.0`](CHANGELOG.md#040---2026-04-30)
|
|
131
|
-
- [
|
|
171
|
+
- [x] Phase 5 — polish + dogfood lessons (`--verbose` policy diagnostics, `$CLAUDE_SESSION_ID` env fallback, server-side `audit` filter pushdown, `policy_decision` first-class entry type, audit `--since` UTC parse fix, `explain --trace` ms-precision sort, npm distribution as `@lannguyensi/harness`) — released as [`v0.5.0`](CHANGELOG.md#050---2026-05-01)
|
|
132
172
|
- [ ] Phase 6 — Understanding Gate Policy Pack (agents must expose and confirm task understanding before write-capable tools fire)
|
|
133
173
|
- [ ] Phase 7 — Risk Gate (Action Envelope + Risk Classifier + `allow / warn / require_approval / deny` for destructive-action prevention)
|
|
134
174
|
|
|
@@ -147,7 +187,7 @@ Our entry point into this problem: on 2026-04-23, an `agent-grounding` checkout
|
|
|
147
187
|
- [`agent-tasks`](https://github.com/LanNguyenSi/agent-tasks) — the MCP-registered task platform whose registration + health appear in `harness describe`.
|
|
148
188
|
- [`agent-preflight`](https://github.com/LanNguyenSi/agent-preflight) — local preflight validator; the canonical implementation of preflight-hook content harness wires (see `docs/ARCHITECTURE.md` §5 for the canonical hook-script shape and §6 for the Phase 4 policy that gates further work on a `preflight:${REPO}` ledger entry).
|
|
149
189
|
- [`codebase-oracle`](https://github.com/LanNguyenSi/codebase-oracle) — one of the MCP surfaces being registered.
|
|
150
|
-
- [`
|
|
190
|
+
- [`agent-dx`](https://github.com/LanNguyenSi/agent-dx) — ships `git-batch-cli` (under `packages/git-batch-cli`), a day-to-day tool whose inventory appears in `harness describe`.
|
|
151
191
|
|
|
152
192
|
## License
|
|
153
193
|
|
package/dist/cli/add/mutate.d.ts
CHANGED
package/dist/cli/add/mutate.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { isSeq, parseDocument } from "yaml";
|
|
1
|
+
import { isMap, isSeq, parseDocument } from "yaml";
|
|
2
2
|
export function applyAdd(yamlText, action) {
|
|
3
3
|
const doc = parseDocument(yamlText);
|
|
4
4
|
switch (action.type) {
|
|
5
5
|
case "mcp":
|
|
6
6
|
addToSequence(doc, ["tools", "mcp"], action.entry);
|
|
7
7
|
break;
|
|
8
|
+
case "mcp_replace":
|
|
9
|
+
replaceOrAppendByName(doc, ["tools", "mcp"], action.name, action.entry);
|
|
10
|
+
break;
|
|
8
11
|
case "cli":
|
|
9
12
|
addToSequence(doc, ["tools", "cli"], action.entry);
|
|
10
13
|
break;
|
|
@@ -33,4 +36,30 @@ function addToSequence(doc, pathSegments, entry) {
|
|
|
33
36
|
}
|
|
34
37
|
throw new Error(`expected a YAML sequence at ${pathSegments.join(".")}, got ${typeof node}`);
|
|
35
38
|
}
|
|
39
|
+
// Find the first item in the sequence whose `name:` matches; replace it. If
|
|
40
|
+
// no match is found, append (so the call site doesn't need to branch on
|
|
41
|
+
// "exists vs new"). Comments and other YAML niceties on the original node are
|
|
42
|
+
// dropped on replace; that is acceptable for the adopt round-trip use case
|
|
43
|
+
// (the replacement is the user's hand-edit becoming the new source of truth).
|
|
44
|
+
function replaceOrAppendByName(doc, pathSegments, name, entry) {
|
|
45
|
+
const node = doc.getIn(pathSegments);
|
|
46
|
+
if (node === undefined || node === null) {
|
|
47
|
+
doc.setIn(pathSegments, [entry]);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!isSeq(node)) {
|
|
51
|
+
throw new Error(`expected a YAML sequence at ${pathSegments.join(".")}, got ${typeof node}`);
|
|
52
|
+
}
|
|
53
|
+
for (let i = 0; i < node.items.length; i++) {
|
|
54
|
+
const item = node.items[i];
|
|
55
|
+
if (!isMap(item))
|
|
56
|
+
continue;
|
|
57
|
+
const itemName = item.get("name");
|
|
58
|
+
if (typeof itemName === "string" && itemName === name) {
|
|
59
|
+
node.set(i, entry);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
node.add(entry);
|
|
64
|
+
}
|
|
36
65
|
//# sourceMappingURL=mutate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../../src/cli/add/mutate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,aAAa,EAAiB,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"mutate.js","sourceRoot":"","sources":["../../../src/cli/add/mutate.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,3 +36,26 @@ export declare function computeDrift(settingsHooks: DerivedHook[], manifestHooks
|
|
|
36
36
|
* `adopted-hook` if the command has no recognisable basename.
|
|
37
37
|
*/
|
|
38
38
|
export declare function synthesizeName(d: DerivedHook, taken: Set<string>): string;
|
|
39
|
+
export interface DerivedMcp {
|
|
40
|
+
name: string;
|
|
41
|
+
command: string[];
|
|
42
|
+
env?: Record<string, string>;
|
|
43
|
+
}
|
|
44
|
+
export interface SettingsMcpSpec {
|
|
45
|
+
command?: unknown;
|
|
46
|
+
args?: unknown;
|
|
47
|
+
env?: unknown;
|
|
48
|
+
}
|
|
49
|
+
export interface SettingsRootWithMcp extends SettingsRoot {
|
|
50
|
+
mcpServers?: Record<string, SettingsMcpSpec>;
|
|
51
|
+
}
|
|
52
|
+
export declare function parseSettingsMcpServers(raw: unknown): DerivedMcp[];
|
|
53
|
+
export declare function manifestMcpProjection(manifest: Manifest): DerivedMcp[];
|
|
54
|
+
export type McpDriftReason = "new" | "modified";
|
|
55
|
+
export interface McpDriftEntry {
|
|
56
|
+
entry: DerivedMcp;
|
|
57
|
+
reason: McpDriftReason;
|
|
58
|
+
}
|
|
59
|
+
export declare function computeMcpDrift(settingsMcp: DerivedMcp[], manifestMcp: DerivedMcp[]): McpDriftEntry[];
|
|
60
|
+
export { mcpEqual };
|
|
61
|
+
declare function mcpEqual(a: DerivedMcp, b: DerivedMcp): boolean;
|
package/dist/cli/adopt/derive.js
CHANGED
|
@@ -91,4 +91,89 @@ export function synthesizeName(d, taken) {
|
|
|
91
91
|
function isRecord(x) {
|
|
92
92
|
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
93
93
|
}
|
|
94
|
+
export function parseSettingsMcpServers(raw) {
|
|
95
|
+
if (!isRecord(raw))
|
|
96
|
+
return [];
|
|
97
|
+
const root = raw;
|
|
98
|
+
if (!isRecord(root.mcpServers))
|
|
99
|
+
return [];
|
|
100
|
+
const out = [];
|
|
101
|
+
for (const [name, specRaw] of Object.entries(root.mcpServers)) {
|
|
102
|
+
if (!isRecord(specRaw))
|
|
103
|
+
continue;
|
|
104
|
+
const spec = specRaw;
|
|
105
|
+
if (typeof spec.command !== "string" || spec.command.length === 0)
|
|
106
|
+
continue;
|
|
107
|
+
const args = Array.isArray(spec.args)
|
|
108
|
+
? spec.args.filter((a) => typeof a === "string")
|
|
109
|
+
: [];
|
|
110
|
+
const command = [spec.command, ...args];
|
|
111
|
+
const entry = { name, command };
|
|
112
|
+
if (isRecord(spec.env)) {
|
|
113
|
+
const env = {};
|
|
114
|
+
for (const [k, v] of Object.entries(spec.env)) {
|
|
115
|
+
if (typeof v === "string")
|
|
116
|
+
env[k] = v;
|
|
117
|
+
}
|
|
118
|
+
if (Object.keys(env).length > 0)
|
|
119
|
+
entry.env = env;
|
|
120
|
+
}
|
|
121
|
+
out.push(entry);
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
export function manifestMcpProjection(manifest) {
|
|
126
|
+
return manifest.tools.mcp.map(toDerivedMcp);
|
|
127
|
+
}
|
|
128
|
+
function toDerivedMcp(m) {
|
|
129
|
+
const command = Array.isArray(m.command)
|
|
130
|
+
? [...m.command]
|
|
131
|
+
: m.command
|
|
132
|
+
.trim()
|
|
133
|
+
.split(/\s+/)
|
|
134
|
+
.filter((t) => t.length > 0);
|
|
135
|
+
const out = { name: m.name, command };
|
|
136
|
+
if (m.env && Object.keys(m.env).length > 0)
|
|
137
|
+
out.env = { ...m.env };
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
export function computeMcpDrift(settingsMcp, manifestMcp) {
|
|
141
|
+
const byName = new Map(manifestMcp.map((m) => [m.name, m]));
|
|
142
|
+
const out = [];
|
|
143
|
+
for (const s of settingsMcp) {
|
|
144
|
+
const existing = byName.get(s.name);
|
|
145
|
+
if (!existing) {
|
|
146
|
+
out.push({ entry: s, reason: "new" });
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (mcpEqual(existing, s))
|
|
150
|
+
continue;
|
|
151
|
+
out.push({ entry: s, reason: "modified" });
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
export { mcpEqual };
|
|
156
|
+
function mcpEqual(a, b) {
|
|
157
|
+
if (a.command.length !== b.command.length)
|
|
158
|
+
return false;
|
|
159
|
+
for (let i = 0; i < a.command.length; i++) {
|
|
160
|
+
if (a.command[i] !== b.command[i])
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
const aEnv = a.env ?? {};
|
|
164
|
+
const bEnv = b.env ?? {};
|
|
165
|
+
const ak = Object.keys(aEnv).sort();
|
|
166
|
+
const bk = Object.keys(bEnv).sort();
|
|
167
|
+
if (ak.length !== bk.length)
|
|
168
|
+
return false;
|
|
169
|
+
for (let i = 0; i < ak.length; i++) {
|
|
170
|
+
const ka = ak[i];
|
|
171
|
+
const kb = bk[i];
|
|
172
|
+
if (ka !== kb)
|
|
173
|
+
return false;
|
|
174
|
+
if (aEnv[ka] !== bEnv[kb])
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
94
179
|
//# sourceMappingURL=derive.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../../src/cli/adopt/derive.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../../src/cli/adopt/derive.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,11 +9,19 @@ export interface AdoptResult {
|
|
|
9
9
|
manifestPath: string;
|
|
10
10
|
settingsPath: string;
|
|
11
11
|
driftCount: number;
|
|
12
|
+
/** Hook entries adopted (subset of driftCount). */
|
|
13
|
+
hookDriftCount: number;
|
|
14
|
+
/** MCP entries adopted (subset of driftCount). */
|
|
15
|
+
mcpDriftCount: number;
|
|
12
16
|
/** The unified diff of the proposed change. Empty when nothing to adopt. */
|
|
13
17
|
diff: string;
|
|
14
18
|
applied: boolean;
|
|
15
|
-
/** Names synthesised for the new
|
|
19
|
+
/** Names synthesised for the new hook entries. */
|
|
16
20
|
adoptedNames: string[];
|
|
21
|
+
/** Names of MCP entries adopted (new) or replaced (modified). */
|
|
22
|
+
adoptedMcpNames: string[];
|
|
23
|
+
/** Names of MCP entries replaced (existed in manifest, content differed). */
|
|
24
|
+
replacedMcpNames: string[];
|
|
17
25
|
/** Human-readable status: "no-drift" | "declined" | "applied". */
|
|
18
26
|
outcome: "no-drift" | "declined" | "applied";
|
|
19
27
|
}
|
package/dist/cli/adopt/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { formatValidationErrors, validateBeforeWrite, } from "../../io/validate-
|
|
|
10
10
|
import { parseManifest } from "../../schema/index.js";
|
|
11
11
|
import { applyAdd } from "../add/mutate.js";
|
|
12
12
|
import { EX_FAIL, EX_NOINPUT, HarnessExitError } from "../exit-codes.js";
|
|
13
|
-
import { computeDrift, manifestProjection, parseSettingsHooks, synthesizeName, } from "./derive.js";
|
|
13
|
+
import { computeDrift, computeMcpDrift, manifestMcpProjection, manifestProjection, parseSettingsHooks, parseSettingsMcpServers, synthesizeName, } from "./derive.js";
|
|
14
14
|
const DEFAULT_BASENAME = "harness.yaml";
|
|
15
15
|
const LOCK_BASENAME = ".harness.lock";
|
|
16
16
|
function resolveManifestPath(opts) {
|
|
@@ -47,14 +47,21 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
47
47
|
}
|
|
48
48
|
const settingsHooks = parseSettingsHooks(settingsRaw);
|
|
49
49
|
const drift = computeDrift(settingsHooks, projection);
|
|
50
|
-
|
|
50
|
+
const settingsMcp = parseSettingsMcpServers(settingsRaw);
|
|
51
|
+
const mcpProjection = manifestMcpProjection(manifest);
|
|
52
|
+
const mcpDrift = computeMcpDrift(settingsMcp, mcpProjection);
|
|
53
|
+
if (drift.length === 0 && mcpDrift.length === 0) {
|
|
51
54
|
return {
|
|
52
55
|
manifestPath,
|
|
53
56
|
settingsPath,
|
|
54
57
|
driftCount: 0,
|
|
58
|
+
hookDriftCount: 0,
|
|
59
|
+
mcpDriftCount: 0,
|
|
55
60
|
diff: "",
|
|
56
61
|
applied: false,
|
|
57
62
|
adoptedNames: [],
|
|
63
|
+
adoptedMcpNames: [],
|
|
64
|
+
replacedMcpNames: [],
|
|
58
65
|
outcome: "no-drift",
|
|
59
66
|
};
|
|
60
67
|
}
|
|
@@ -70,6 +77,25 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
70
77
|
entry: buildHookEntry(name, d),
|
|
71
78
|
});
|
|
72
79
|
}
|
|
80
|
+
const adoptedMcpNames = [];
|
|
81
|
+
const replacedMcpNames = [];
|
|
82
|
+
// Preserve manifest-only fields (`health`, `enabled: false`) when
|
|
83
|
+
// replacing an existing entry. The settings.json projection only
|
|
84
|
+
// carries `command` + `env`; without this merge, hand-edits to those
|
|
85
|
+
// fields would silently wipe `health` (load-bearing for the audit /
|
|
86
|
+
// doctor / probe paths) and `enabled: false` (which would re-enable a
|
|
87
|
+
// server the user explicitly turned off).
|
|
88
|
+
const manifestByName = new Map(manifest.tools.mcp.map((m) => [m.name, m]));
|
|
89
|
+
for (const m of mcpDrift) {
|
|
90
|
+
if (m.reason === "modified")
|
|
91
|
+
replacedMcpNames.push(m.entry.name);
|
|
92
|
+
adoptedMcpNames.push(m.entry.name);
|
|
93
|
+
proposedYaml = applyAdd(proposedYaml, {
|
|
94
|
+
type: "mcp_replace",
|
|
95
|
+
name: m.entry.name,
|
|
96
|
+
entry: buildMcpEntry(m.entry, manifestByName.get(m.entry.name)),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
73
99
|
const diff = unifiedDiff({
|
|
74
100
|
fileName: path.basename(manifestPath),
|
|
75
101
|
oldText: originalYaml,
|
|
@@ -93,10 +119,14 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
93
119
|
return {
|
|
94
120
|
manifestPath,
|
|
95
121
|
settingsPath,
|
|
96
|
-
driftCount: drift.length,
|
|
122
|
+
driftCount: drift.length + mcpDrift.length,
|
|
123
|
+
hookDriftCount: drift.length,
|
|
124
|
+
mcpDriftCount: mcpDrift.length,
|
|
97
125
|
diff,
|
|
98
126
|
applied: false,
|
|
99
127
|
adoptedNames,
|
|
128
|
+
adoptedMcpNames,
|
|
129
|
+
replacedMcpNames,
|
|
100
130
|
outcome: "declined",
|
|
101
131
|
};
|
|
102
132
|
}
|
|
@@ -123,6 +153,19 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
123
153
|
next = applyAdd(next, { type: "hook", entry: buildHookEntry(name, d) });
|
|
124
154
|
lockTaken.add(name);
|
|
125
155
|
}
|
|
156
|
+
// MCP entries adopt as replace-or-append (keyed by name), so re-applying
|
|
157
|
+
// the same drift under the lock is naturally idempotent: the same name
|
|
158
|
+
// gets the same replacement. Use the freshly-read manifest's entries
|
|
159
|
+
// for the field-preservation merge, in case a concurrent adopt added
|
|
160
|
+
// health/enabled to the same name in between.
|
|
161
|
+
const lockedMcpByName = new Map(currentManifest.tools.mcp.map((m) => [m.name, m]));
|
|
162
|
+
for (const m of mcpDrift) {
|
|
163
|
+
next = applyAdd(next, {
|
|
164
|
+
type: "mcp_replace",
|
|
165
|
+
name: m.entry.name,
|
|
166
|
+
entry: buildMcpEntry(m.entry, lockedMcpByName.get(m.entry.name)),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
126
169
|
const recheck = validateBeforeWrite(parseYaml(next));
|
|
127
170
|
if (!recheck.ok) {
|
|
128
171
|
throw new HarnessExitError(`proposed manifest fails schema validation after lock acquisition:\n${formatValidationErrors(recheck.errors)}`, EX_FAIL);
|
|
@@ -132,13 +175,38 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
132
175
|
return {
|
|
133
176
|
manifestPath,
|
|
134
177
|
settingsPath,
|
|
135
|
-
driftCount: drift.length,
|
|
178
|
+
driftCount: drift.length + mcpDrift.length,
|
|
179
|
+
hookDriftCount: drift.length,
|
|
180
|
+
mcpDriftCount: mcpDrift.length,
|
|
136
181
|
diff,
|
|
137
182
|
applied: true,
|
|
138
183
|
adoptedNames,
|
|
184
|
+
adoptedMcpNames,
|
|
185
|
+
replacedMcpNames,
|
|
139
186
|
outcome: "applied",
|
|
140
187
|
};
|
|
141
188
|
}
|
|
189
|
+
function buildMcpEntry(d, existing) {
|
|
190
|
+
const entry = {
|
|
191
|
+
name: d.name,
|
|
192
|
+
command: [...d.command],
|
|
193
|
+
};
|
|
194
|
+
if (d.env && Object.keys(d.env).length > 0)
|
|
195
|
+
entry.env = { ...d.env };
|
|
196
|
+
// Carry forward manifest-only fields. settings.json's mcpServers shape
|
|
197
|
+
// has no projection for `health` (used by doctor / probe / policy paths)
|
|
198
|
+
// or `enabled: false` (explicit opt-out the user chose to keep), so a
|
|
199
|
+
// pure replace from the projected drift would silently wipe them.
|
|
200
|
+
// `enabled: true` is the schema default and is omitted to keep the
|
|
201
|
+
// re-emitted YAML clean.
|
|
202
|
+
if (existing) {
|
|
203
|
+
if (existing.health)
|
|
204
|
+
entry.health = { ...existing.health };
|
|
205
|
+
if (existing.enabled === false)
|
|
206
|
+
entry.enabled = false;
|
|
207
|
+
}
|
|
208
|
+
return entry;
|
|
209
|
+
}
|
|
142
210
|
function buildHookEntry(name, d) {
|
|
143
211
|
// Adopted hooks default to non-blocking so the captured entry doesn't
|
|
144
212
|
// unexpectedly start gating tool calls. The user can promote to soft/hard
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/adopt/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/adopt/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAkB,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,cAAc,GAGf,MAAM,aAAa,CAAC;AA+BrB,MAAM,gBAAgB,GAAG,cAAc,CAAC;AACxC,MAAM,aAAa,GAAG,eAAe,CAAC;AAEtC,SAAS,mBAAmB,CAAC,IAAkB;IAC7C,IAAI,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,EAAE,gBAAgB,CAAC,CAAC;AACzF,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,OAAe;IAC1C,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACtF,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,YAAoB,EACpB,OAAqB,EAAE;IAEvB,MAAM,YAAY,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,gBAAgB,CACxB,iCAAiC,YAAY,8BAA8B,EAC3E,UAAU,CACX,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,gBAAgB,CACxB,sCAAsC,YAAY,EAAE,EACpD,UAAU,CACX,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,QAAQ,GAAG,aAAa,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAEhD,IAAI,WAAoB,CAAC;IACzB,IAAI,CAAC;QACH,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,gBAAgB,CACxB,iBAAiB,YAAY,uBAAwB,CAAW,CAAC,OAAO,EAAE,EAC1E,OAAO,CACR,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAEtD,MAAM,WAAW,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACzD,MAAM,aAAa,GAAG,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAE7D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO;YACL,YAAY;YACZ,YAAY;YACZ,UAAU,EAAE,CAAC;YACb,cAAc,EAAE,CAAC;YACjB,aAAa,EAAE,CAAC;YAChB,IAAI,EAAE,EAAE;YACR,OAAO,EAAE,KAAK;YACd,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,EAAE;YACnB,gBAAgB,EAAE,EAAE;YACpB,OAAO,EAAE,UAAU;SACpB,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,YAAY,GAAG,YAAY,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACtC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAChB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,YAAY,GAAG,QAAQ,CAAC,YAAY,EAAE;YACpC,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,kEAAkE;IAClE,iEAAiE;IACjE,qEAAqE;IACrE,oEAAoE;IACpE,sEAAsE;IACtE,0CAA0C;IAC1C,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU;YAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjE,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,YAAY,GAAG,QAAQ,CAAC,YAAY,EAAE;YACpC,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI;YAClB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SAChE,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,WAAW,CAAC;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QACrC,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,YAAY;QACrB,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,UAAU;KACtB,CAAC,CAAC;IAEH,+EAA+E;IAC/E,qEAAqE;IACrE,4EAA4E;IAC5E,4EAA4E;IAC5E,6EAA6E;IAC7E,MAAM,UAAU,GAAG,mBAAmB,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;IAChE,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,gBAAgB,CACxB,+CAA+C,sBAAsB,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,EAC1F,OAAO,CACR,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC;QAC9C,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,GAAG,IAAI,iBAAiB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC/E,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACvC,OAAO;gBACL,YAAY;gBACZ,YAAY;gBACZ,UAAU,EAAE,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;gBAC1C,cAAc,EAAE,KAAK,CAAC,MAAM;gBAC5B,aAAa,EAAE,QAAQ,CAAC,MAAM;gBAC9B,IAAI;gBACJ,OAAO,EAAE,KAAK;gBACd,YAAY;gBACZ,eAAe;gBACf,gBAAgB;gBAChB,OAAO,EAAE,UAAU;aACpB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,CAAC;IACtE,MAAM,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE;QAChC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,IAAI,GAAG,OAAO,CAAC;QACnB,MAAM,eAAe,GAAG,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;YACpB,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC;YAC9B,yEAAyE;YACzE,iEAAiE;YACjE,kEAAkE;YAClE,yEAAyE;YACzE,wEAAwE;YACxE,wEAAwE;YACxE,uEAAuE;YACvE,2EAA2E;YAC3E,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,SAAS;YAClC,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YACxE,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QACD,yEAAyE;QACzE,uEAAuE;QACvE,qEAAqE;QACrE,qEAAqE;QACrE,8CAA8C;QAC9C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACnF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE;gBACpB,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI;gBAClB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aACjE,CAAC,CAAC;QACL,CAAC;QACD,MAAM,OAAO,GAAG,mBAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;YAChB,MAAM,IAAI,gBAAgB,CACxB,sEAAsE,sBAAsB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAC9G,OAAO,CACR,CAAC;QACJ,CAAC;QACD,eAAe,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,YAAY;QACZ,YAAY;QACZ,UAAU,EAAE,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM;QAC1C,cAAc,EAAE,KAAK,CAAC,MAAM;QAC5B,aAAa,EAAE,QAAQ,CAAC,MAAM;QAC9B,IAAI;QACJ,OAAO,EAAE,IAAI;QACb,YAAY;QACZ,eAAe;QACf,gBAAgB;QAChB,OAAO,EAAE,SAAS;KACnB,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CACpB,CAAa,EACb,QAA+B;IAQ/B,MAAM,KAAK,GAMP;QACF,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC;KACxB,CAAC;IACF,IAAI,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;IACrE,uEAAuE;IACvE,yEAAyE;IACzE,sEAAsE;IACtE,kEAAkE;IAClE,mEAAmE;IACnE,yBAAyB;IACzB,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,QAAQ,CAAC,MAAM;YAAE,KAAK,CAAC,MAAM,GAAG,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC3D,IAAI,QAAQ,CAAC,OAAO,KAAK,KAAK;YAAE,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CACrB,IAAY,EACZ,CAAc;IAEd,sEAAsE;IACtE,0EAA0E;IAC1E,uCAAuC;IACvC,MAAM,KAAK,GAAsF;QAC/F,IAAI;QACJ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,QAAQ,EAAE,KAAK;KAChB,CAAC;IACF,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;IACjD,OAAO,KAAK,CAAC;AACf,CAAC"}
|