@maind-dev/cli 0.6.0 → 0.7.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/build/index.js +3957 -107
- package/build/meta.json +1 -0
- package/package.json +11 -6
- package/build/auth.js +0 -76
- package/build/auth.js.map +0 -1
- package/build/ci-report.js +0 -162
- package/build/ci-report.js.map +0 -1
- package/build/ci-result.js +0 -145
- package/build/ci-result.js.map +0 -1
- package/build/context.js +0 -157
- package/build/context.js.map +0 -1
- package/build/git-context.js +0 -214
- package/build/git-context.js.map +0 -1
- package/build/git.js +0 -133
- package/build/git.js.map +0 -1
- package/build/index-cmd.js +0 -245
- package/build/index-cmd.js.map +0 -1
- package/build/index.js.map +0 -1
- package/build/mcp-client.js +0 -225
- package/build/mcp-client.js.map +0 -1
- package/build/render.js +0 -81
- package/build/render.js.map +0 -1
- package/build/review-render.js +0 -231
- package/build/review-render.js.map +0 -1
- package/build/review.js +0 -296
- package/build/review.js.map +0 -1
- package/build/sync-cmd.js +0 -140
- package/build/sync-cmd.js.map +0 -1
package/build/meta.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"inputs":{"src/auth.ts":{"bytes":3441,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:os","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true}],"format":"esm"},"src/mcp-client.ts":{"bytes":8724,"imports":[],"format":"esm"},"src/render.ts":{"bytes":4525,"imports":[],"format":"esm"},"src/context.ts":{"bytes":6805,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"src/auth.ts","kind":"import-statement","original":"./auth.js"},{"path":"src/mcp-client.ts","kind":"import-statement","original":"./mcp-client.js"},{"path":"src/render.ts","kind":"import-statement","original":"./render.js"}],"format":"esm"},"../../packages/project-key/build/index.js":{"bytes":3446,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:crypto","kind":"import-statement","external":true}],"format":"esm"},"src/git.ts":{"bytes":5748,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"../../packages/project-key/build/index.js","kind":"import-statement","original":"@maind/project-key"},{"path":"../../packages/project-key/build/index.js","kind":"import-statement","original":"@maind/project-key"}],"format":"esm"},"src/ci-report.ts":{"bytes":6631,"imports":[{"path":"node:crypto","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"src/auth.ts","kind":"import-statement","original":"./auth.js"},{"path":"src/git.ts","kind":"import-statement","original":"./git.js"}],"format":"esm"},"src/ci-result.ts":{"bytes":5483,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"src/auth.ts","kind":"import-statement","original":"./auth.js"}],"format":"esm"},"src/git-context.ts":{"bytes":9481,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"src/auth.ts","kind":"import-statement","original":"./auth.js"},{"path":"src/mcp-client.ts","kind":"import-statement","original":"./mcp-client.js"},{"path":"src/git.ts","kind":"import-statement","original":"./git.js"}],"format":"esm"},"../../packages/code-index/build/parse/keys.js":{"bytes":448,"imports":[],"format":"esm"},"../../packages/code-index/build/parse/types.js":{"bytes":768,"imports":[],"format":"esm"},"../../packages/code-index/build/parse/lang/shared.js":{"bytes":2278,"imports":[],"format":"esm"},"../../packages/code-index/build/parse/lang/python.js":{"bytes":4535,"imports":[{"path":"../../packages/code-index/build/parse/keys.js","kind":"import-statement","original":"../keys.js"},{"path":"../../packages/code-index/build/parse/lang/shared.js","kind":"import-statement","original":"./shared.js"}],"format":"esm"},"../../packages/code-index/build/parse/lang/typescript.js":{"bytes":5949,"imports":[{"path":"../../packages/code-index/build/parse/keys.js","kind":"import-statement","original":"../keys.js"},{"path":"../../packages/code-index/build/parse/lang/shared.js","kind":"import-statement","original":"./shared.js"}],"format":"esm"},"../../packages/code-index/build/parse/tree-sitter/grammars.js":{"bytes":1941,"imports":[{"path":"node:module","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true}],"format":"esm"},"../../packages/code-index/build/parse/tree-sitter/parser.js":{"bytes":3231,"imports":[{"path":"node:path","kind":"import-statement","external":true},{"path":"web-tree-sitter","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/parse/keys.js","kind":"import-statement","original":"../keys.js"},{"path":"../../packages/code-index/build/parse/types.js","kind":"import-statement","original":"../types.js"},{"path":"../../packages/code-index/build/parse/lang/python.js","kind":"import-statement","original":"../lang/python.js"},{"path":"../../packages/code-index/build/parse/lang/typescript.js","kind":"import-statement","original":"../lang/typescript.js"},{"path":"../../packages/code-index/build/parse/lang/shared.js","kind":"import-statement","original":"../lang/shared.js"},{"path":"../../packages/code-index/build/parse/tree-sitter/grammars.js","kind":"import-statement","original":"./grammars.js"}],"format":"esm"},"../../packages/code-index/build/embed/recipe.js":{"bytes":594,"imports":[],"format":"esm"},"../../packages/code-index/build/embed/types.js":{"bytes":505,"imports":[],"format":"esm"},"../../packages/code-index/build/util/vector.js":{"bytes":707,"imports":[],"format":"esm"},"../../packages/code-index/build/graph/resolve.js":{"bytes":3928,"imports":[{"path":"node:path","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/parse/keys.js","kind":"import-statement","original":"../parse/keys.js"}],"format":"esm"},"../../packages/code-index/build/incremental/discover.js":{"bytes":8578,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:crypto","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/parse/types.js","kind":"import-statement","original":"../parse/types.js"}],"format":"esm"},"../../packages/code-index/build/incremental/hunks.js":{"bytes":6171,"imports":[{"path":"../../packages/code-index/build/incremental/discover.js","kind":"import-statement","original":"./discover.js"}],"format":"esm"},"../../packages/code-index/build/review/risk-rules.js":{"bytes":1958,"imports":[],"format":"esm"},"../../packages/code-index/build/review/risk-scan.js":{"bytes":1451,"imports":[{"path":"../../packages/code-index/build/review/risk-rules.js","kind":"import-statement","original":"./risk-rules.js"}],"format":"esm"},"../../packages/code-index/build/store/schema.js":{"bytes":3047,"imports":[],"format":"esm"},"../../packages/code-index/build/util/identifiers.js":{"bytes":2180,"imports":[],"format":"esm"},"../../packages/code-index/build/query/engine.js":{"bytes":18965,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/embed/recipe.js","kind":"import-statement","original":"../embed/recipe.js"},{"path":"../../packages/code-index/build/embed/types.js","kind":"import-statement","original":"../embed/types.js"},{"path":"../../packages/code-index/build/util/vector.js","kind":"import-statement","original":"../util/vector.js"},{"path":"../../packages/code-index/build/graph/resolve.js","kind":"import-statement","original":"../graph/resolve.js"},{"path":"../../packages/code-index/build/incremental/discover.js","kind":"import-statement","original":"../incremental/discover.js"},{"path":"../../packages/code-index/build/incremental/hunks.js","kind":"import-statement","original":"../incremental/hunks.js"},{"path":"../../packages/code-index/build/review/risk-scan.js","kind":"import-statement","original":"../review/risk-scan.js"},{"path":"../../packages/code-index/build/store/schema.js","kind":"import-statement","original":"../store/schema.js"},{"path":"../../packages/code-index/build/util/identifiers.js","kind":"import-statement","original":"../util/identifiers.js"}],"format":"esm"},"../../packages/code-index/build/store/node-sqlite.js":{"bytes":11850,"imports":[{"path":"better-sqlite3","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/store/schema.js","kind":"import-statement","original":"./schema.js"},{"path":"../../packages/code-index/build/util/identifiers.js","kind":"import-statement","original":"../util/identifiers.js"}],"format":"esm"},"../../packages/code-index/build/sync/types.js":{"bytes":1779,"imports":[{"path":"node:crypto","kind":"import-statement","external":true}],"format":"esm"},"../../packages/code-index/build/sync/client.js":{"bytes":10021,"imports":[{"path":"../../packages/code-index/build/store/schema.js","kind":"import-statement","original":"../store/schema.js"},{"path":"../../packages/code-index/build/sync/types.js","kind":"import-statement","original":"./types.js"}],"format":"esm"},"../../packages/code-index/build/node.js":{"bytes":2578,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"../../packages/project-key/build/index.js","kind":"import-statement","original":"@maind/project-key"},{"path":"../../packages/code-index/build/parse/tree-sitter/parser.js","kind":"import-statement","original":"./parse/tree-sitter/parser.js"},{"path":"../../packages/code-index/build/query/engine.js","kind":"import-statement","original":"./query/engine.js"},{"path":"../../packages/code-index/build/store/node-sqlite.js","kind":"import-statement","original":"./store/node-sqlite.js"},{"path":"../../packages/code-index/build/sync/client.js","kind":"import-statement","original":"./sync/client.js"},{"path":"../../packages/code-index/build/sync/client.js","kind":"import-statement","original":"./sync/client.js"}],"format":"esm"},"../../packages/embedding/build/index.js":{"bytes":6053,"imports":[{"path":"@huggingface/transformers","kind":"dynamic-import","external":true}],"format":"esm"},"../../packages/code-index/build/embed/node.js":{"bytes":661,"imports":[{"path":"../../packages/embedding/build/index.js","kind":"import-statement","original":"@maind/embedding"},{"path":"../../packages/code-index/build/embed/recipe.js","kind":"import-statement","original":"./recipe.js"}],"format":"esm"},"../../packages/code-index/build/node-embed.js":{"bytes":660,"imports":[{"path":"../../packages/code-index/build/embed/node.js","kind":"import-statement","original":"./embed/node.js"}],"format":"esm"},"src/index-cmd.ts":{"bytes":9353,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:os","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:url","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/node.js","kind":"import-statement","original":"@maind/code-index/node"},{"path":"../../packages/code-index/build/node-embed.js","kind":"import-statement","original":"@maind/code-index/node-embed"}],"format":"esm"},"../../packages/code-index/build/model/types.js":{"bytes":471,"imports":[],"format":"esm"},"../../packages/code-index/build/index.js":{"bytes":1204,"imports":[{"path":"../../packages/code-index/build/model/types.js","kind":"import-statement","original":"./model/types.js"},{"path":"../../packages/code-index/build/query/engine.js","kind":"import-statement","original":"./query/engine.js"},{"path":"../../packages/code-index/build/review/risk-rules.js","kind":"import-statement","original":"./review/risk-rules.js"},{"path":"../../packages/code-index/build/parse/types.js","kind":"import-statement","original":"./parse/types.js"},{"path":"../../packages/code-index/build/embed/types.js","kind":"import-statement","original":"./embed/types.js"},{"path":"../../packages/code-index/build/store/schema.js","kind":"import-statement","original":"./store/schema.js"}],"format":"esm"},"src/review-render.ts":{"bytes":14139,"imports":[],"format":"esm"},"src/review.ts":{"bytes":16004,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/node.js","kind":"import-statement","original":"@maind/code-index/node"},{"path":"../../packages/code-index/build/index.js","kind":"import-statement","original":"@maind/code-index"},{"path":"src/auth.ts","kind":"import-statement","original":"./auth.js"},{"path":"src/git.ts","kind":"import-statement","original":"./git.js"},{"path":"src/mcp-client.ts","kind":"import-statement","original":"./mcp-client.js"},{"path":"src/review-render.ts","kind":"import-statement","original":"./review-render.js"}],"format":"esm"},"src/sync-cmd.ts":{"bytes":5243,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"../../packages/code-index/build/node.js","kind":"import-statement","original":"@maind/code-index/node"},{"path":"src/auth.ts","kind":"import-statement","original":"./auth.js"}],"format":"esm"},"src/index.ts":{"bytes":9745,"imports":[{"path":"src/context.ts","kind":"import-statement","original":"./context.js"},{"path":"src/ci-report.ts","kind":"import-statement","original":"./ci-report.js"},{"path":"src/ci-result.ts","kind":"import-statement","original":"./ci-result.js"},{"path":"src/git-context.ts","kind":"import-statement","original":"./git-context.js"},{"path":"src/git.ts","kind":"import-statement","original":"./git.js"},{"path":"src/index-cmd.ts","kind":"import-statement","original":"./index-cmd.js"},{"path":"src/review.ts","kind":"import-statement","original":"./review.js"},{"path":"src/sync-cmd.ts","kind":"import-statement","original":"./sync-cmd.js"}],"format":"esm"}},"outputs":{"build/index.js":{"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:os","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:crypto","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:crypto","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:os","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:url","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"web-tree-sitter","kind":"import-statement","external":true},{"path":"node:module","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:crypto","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"better-sqlite3","kind":"import-statement","external":true},{"path":"node:crypto","kind":"import-statement","external":true},{"path":"@huggingface/transformers","kind":"dynamic-import","external":true},{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"node:child_process","kind":"import-statement","external":true}],"exports":[],"entryPoint":"src/index.ts","inputs":{"src/context.ts":{"bytesInOutput":4644},"src/auth.ts":{"bytesInOutput":1609},"src/mcp-client.ts":{"bytesInOutput":5955},"src/render.ts":{"bytesInOutput":2406},"src/ci-report.ts":{"bytesInOutput":4467},"src/git.ts":{"bytesInOutput":3325},"../../packages/project-key/build/index.js":{"bytesInOutput":1449},"src/ci-result.ts":{"bytesInOutput":3848},"src/git-context.ts":{"bytesInOutput":6854},"src/index-cmd.ts":{"bytesInOutput":6717},"../../packages/code-index/build/node.js":{"bytesInOutput":1159},"../../packages/code-index/build/parse/tree-sitter/parser.js":{"bytesInOutput":2043},"../../packages/code-index/build/parse/keys.js":{"bytesInOutput":169},"../../packages/code-index/build/parse/types.js":{"bytesInOutput":546},"../../packages/code-index/build/parse/lang/shared.js":{"bytesInOutput":1131},"../../packages/code-index/build/parse/lang/python.js":{"bytesInOutput":3747},"../../packages/code-index/build/parse/lang/typescript.js":{"bytesInOutput":4721},"../../packages/code-index/build/parse/tree-sitter/grammars.js":{"bytesInOutput":523},"../../packages/code-index/build/query/engine.js":{"bytesInOutput":13877},"../../packages/code-index/build/embed/recipe.js":{"bytesInOutput":229},"../../packages/code-index/build/embed/types.js":{"bytesInOutput":105},"../../packages/code-index/build/util/vector.js":{"bytesInOutput":339},"../../packages/code-index/build/graph/resolve.js":{"bytesInOutput":2486},"../../packages/code-index/build/incremental/discover.js":{"bytesInOutput":4855},"../../packages/code-index/build/incremental/hunks.js":{"bytesInOutput":3951},"../../packages/code-index/build/review/risk-rules.js":{"bytesInOutput":876},"../../packages/code-index/build/review/risk-scan.js":{"bytesInOutput":798},"../../packages/code-index/build/store/schema.js":{"bytesInOutput":2266},"../../packages/code-index/build/util/identifiers.js":{"bytesInOutput":1094},"../../packages/code-index/build/store/node-sqlite.js":{"bytesInOutput":9751},"../../packages/code-index/build/sync/types.js":{"bytesInOutput":875},"../../packages/code-index/build/sync/client.js":{"bytesInOutput":7568},"../../packages/embedding/build/index.js":{"bytesInOutput":1293},"../../packages/code-index/build/embed/node.js":{"bytesInOutput":288},"../../packages/code-index/build/node-embed.js":{"bytesInOutput":63},"src/review.ts":{"bytesInOutput":10816},"../../packages/code-index/build/index.js":{"bytesInOutput":34},"src/review-render.ts":{"bytesInOutput":7809},"src/sync-cmd.ts":{"bytesInOutput":3860},"src/index.ts":{"bytesInOutput":7760}},"bytes":138276}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maind-dev/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Headless maind CLI — pull stack-relevant lessons into CI runners, report CI outcomes, and brief agents on local git state (branch, PRs, peers). No device flow; authenticates from MAIND_API_KEY.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./build/index.js",
|
|
@@ -12,14 +12,19 @@
|
|
|
12
12
|
"README.md"
|
|
13
13
|
],
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@
|
|
16
|
-
"
|
|
17
|
-
"
|
|
15
|
+
"@huggingface/transformers": "^3.0.0",
|
|
16
|
+
"better-sqlite3": "^12.11.1",
|
|
17
|
+
"tree-sitter-wasms": "^0.1.13",
|
|
18
|
+
"web-tree-sitter": "0.24.7"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"@types/node": "^20.11.0",
|
|
22
|
+
"esbuild": "^0.24.0",
|
|
21
23
|
"tsx": "^4.7.0",
|
|
22
|
-
"typescript": "^5.4.0"
|
|
24
|
+
"typescript": "^5.4.0",
|
|
25
|
+
"@maind/code-index": "0.0.0",
|
|
26
|
+
"@maind/embedding": "0.0.0",
|
|
27
|
+
"@maind/project-key": "0.0.0"
|
|
23
28
|
},
|
|
24
29
|
"engines": {
|
|
25
30
|
"node": ">=20.0.0"
|
|
@@ -36,7 +41,7 @@
|
|
|
36
41
|
"access": "public"
|
|
37
42
|
},
|
|
38
43
|
"scripts": {
|
|
39
|
-
"build": "
|
|
44
|
+
"build": "node scripts/bundle.mjs",
|
|
40
45
|
"start": "node build/index.js",
|
|
41
46
|
"dev": "node --import tsx src/index.ts",
|
|
42
47
|
"test": "node --import tsx --test test/**/*.test.ts",
|
package/build/auth.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// API-key + device-id resolution for the headless CLI.
|
|
2
|
-
//
|
|
3
|
-
// CI-first: the key comes from the MAIND_API_KEY environment variable. For local
|
|
4
|
-
// dev convenience we also fall back to the same on-disk key the mcp-bridge
|
|
5
|
-
// persists (~/Library/Application Support/maind/api-key etc.), so a developer who
|
|
6
|
-
// already paired the bridge can run `maind context` without re-exporting anything.
|
|
7
|
-
//
|
|
8
|
-
// We deliberately do NOT run a device-authorization flow here. A CI runner has no
|
|
9
|
-
// browser and no stable device, so an interactive flow would just hang. The
|
|
10
|
-
// intended key for CI is a device-unbound "ci"-kind key minted in the dashboard
|
|
11
|
-
// (read-scoped). Until that key class ships, a free-tier / pre-cutoff key works
|
|
12
|
-
// because those are not device-bound either.
|
|
13
|
-
//
|
|
14
|
-
// The device-id is sent ONLY when an existing device-id file is found on disk
|
|
15
|
-
// (i.e. this machine already paired the bridge). In CI no such file exists, so the
|
|
16
|
-
// header is omitted and the server treats the request as device-less.
|
|
17
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
18
|
-
import { homedir, platform } from "node:os";
|
|
19
|
-
import { join } from "node:path";
|
|
20
|
-
/** XDG-style config directory for maind — must match apps/mcp-bridge/src/device-id.ts. */
|
|
21
|
-
function configDir() {
|
|
22
|
-
const home = homedir();
|
|
23
|
-
const env = process.env;
|
|
24
|
-
if (platform() === "darwin") {
|
|
25
|
-
return join(home, "Library", "Application Support", "maind");
|
|
26
|
-
}
|
|
27
|
-
if (platform() === "win32") {
|
|
28
|
-
const appdata = env.APPDATA && env.APPDATA.length > 0 ? env.APPDATA : join(home, "AppData", "Roaming");
|
|
29
|
-
return join(appdata, "maind");
|
|
30
|
-
}
|
|
31
|
-
const xdg = env.XDG_CONFIG_HOME && env.XDG_CONFIG_HOME.length > 0
|
|
32
|
-
? env.XDG_CONFIG_HOME
|
|
33
|
-
: join(home, ".config");
|
|
34
|
-
return join(xdg, "maind");
|
|
35
|
-
}
|
|
36
|
-
function readFileTrimmed(path) {
|
|
37
|
-
if (!existsSync(path))
|
|
38
|
-
return null;
|
|
39
|
-
try {
|
|
40
|
-
const raw = readFileSync(path, "utf8").trim();
|
|
41
|
-
return raw.length > 0 ? raw : null;
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export class MissingApiKeyError extends Error {
|
|
48
|
-
constructor() {
|
|
49
|
-
super("No API key found. Set MAIND_API_KEY (a read-scoped CI key from https://maind.dev/keys) " +
|
|
50
|
-
"or pair the maind bridge on this machine first.");
|
|
51
|
-
this.name = "MissingApiKeyError";
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Resolves the API key (env-first, then the bridge's on-disk key) and an optional
|
|
56
|
-
* device-id. Throws MissingApiKeyError when neither source yields a key.
|
|
57
|
-
*/
|
|
58
|
-
export function resolveAuth() {
|
|
59
|
-
const fromEnv = process.env.MAIND_API_KEY?.trim();
|
|
60
|
-
const apiKey = fromEnv && fromEnv.length > 0 ? fromEnv : readFileTrimmed(join(configDir(), "api-key"));
|
|
61
|
-
if (!apiKey)
|
|
62
|
-
throw new MissingApiKeyError();
|
|
63
|
-
const deviceId = readFileTrimmed(join(configDir(), "device-id"));
|
|
64
|
-
return { apiKey, deviceId, keyPrefix: keyPrefixOf(apiKey) };
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Extracts the non-secret identifying prefix from a maind key (`mnd_<8hex>_<secret>`).
|
|
68
|
-
* Returns the `mnd_<8hex>` portion, or a coarse first-12-chars fallback for other shapes.
|
|
69
|
-
*/
|
|
70
|
-
export function keyPrefixOf(apiKey) {
|
|
71
|
-
const m = /^(mnd_[0-9a-f]{8})_/i.exec(apiKey);
|
|
72
|
-
if (m)
|
|
73
|
-
return m[1];
|
|
74
|
-
return apiKey.slice(0, 12);
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=auth.js.map
|
package/build/auth.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/build/ci-report.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// `maind ci-report` — report a CI failure as a draft-lesson candidate (ADR-207
|
|
2
|
-
// Phase 2, INGESTION). An agent running in the CI runner authors a lesson
|
|
3
|
-
// candidate (frontmatter + body) capturing the gotcha + fix; this command reads
|
|
4
|
-
// that file, attaches CI provenance from the runner env, and POSTs it to the
|
|
5
|
-
// maind ingest endpoint with the CI key. maind files it in the maintainer review
|
|
6
|
-
// inbox — never auto-published.
|
|
7
|
-
//
|
|
8
|
-
// Fail-open by contract: a failing report must never further break the build.
|
|
9
|
-
// Any error → stderr warning, exit 0. (This already runs in an on-failure step.)
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
|
-
import { readFileSync } from "node:fs";
|
|
12
|
-
import { MissingApiKeyError, resolveAuth } from "./auth.js";
|
|
13
|
-
import { gatherGitState } from "./git.js";
|
|
14
|
-
const DEFAULT_REPORT_URL = "https://app.maind.dev/api/ci/report";
|
|
15
|
-
const PROJECT_KEY_RE = /^[a-f0-9]{64}$/;
|
|
16
|
-
export function parseCiReportArgs(argv) {
|
|
17
|
-
const get = (name) => {
|
|
18
|
-
const i = argv.indexOf(name);
|
|
19
|
-
if (i === -1 || i + 1 >= argv.length)
|
|
20
|
-
return undefined;
|
|
21
|
-
return argv[i + 1];
|
|
22
|
-
};
|
|
23
|
-
return {
|
|
24
|
-
lessonPath: get("--lesson") ?? null,
|
|
25
|
-
rationale: get("--rationale") ?? null,
|
|
26
|
-
failureType: get("--failure-type") ?? null,
|
|
27
|
-
signature: get("--signature") ?? null,
|
|
28
|
-
summary: get("--summary") ?? null,
|
|
29
|
-
provider: get("--provider") ?? "github-actions",
|
|
30
|
-
logsPath: get("--logs") ?? null,
|
|
31
|
-
remediation: get("--remediation") ?? null,
|
|
32
|
-
reportUrl: get("--report-url") ?? process.env.MAIND_REPORT_URL ?? DEFAULT_REPORT_URL,
|
|
33
|
-
projectKey: get("--project-key") ?? null,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
/** Collects CI run metadata from the runner environment (GitHub Actions today). */
|
|
37
|
-
function ciEnv() {
|
|
38
|
-
const env = process.env;
|
|
39
|
-
const runId = env.GITHUB_RUN_ID;
|
|
40
|
-
const repo = env.GITHUB_REPOSITORY;
|
|
41
|
-
const server = env.GITHUB_SERVER_URL ?? "https://github.com";
|
|
42
|
-
return {
|
|
43
|
-
workflow_name: env.GITHUB_WORKFLOW || undefined,
|
|
44
|
-
run_id: runId || undefined,
|
|
45
|
-
run_url: runId && repo ? `${server}/${repo}/actions/runs/${runId}` : undefined,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function sha256(s) {
|
|
49
|
-
return createHash("sha256").update(s, "utf8").digest("hex");
|
|
50
|
-
}
|
|
51
|
-
/** Runs the report. Always returns 0 (fail-open). */
|
|
52
|
-
export async function runCiReport(opts) {
|
|
53
|
-
try {
|
|
54
|
-
if (!opts.lessonPath) {
|
|
55
|
-
warn("missing --lesson <path-to-authored-lesson.md>; nothing to report.");
|
|
56
|
-
return 0;
|
|
57
|
-
}
|
|
58
|
-
if (!opts.rationale) {
|
|
59
|
-
warn("missing --rationale; the agent should explain why this is a lesson.");
|
|
60
|
-
return 0;
|
|
61
|
-
}
|
|
62
|
-
if (!opts.failureType) {
|
|
63
|
-
warn("missing --failure-type (e.g. tsc-error, test-failure).");
|
|
64
|
-
return 0;
|
|
65
|
-
}
|
|
66
|
-
const lesson = readFileSync(opts.lessonPath, "utf8");
|
|
67
|
-
if (lesson.trim().length < 50) {
|
|
68
|
-
warn("authored lesson is too short — skipping report.");
|
|
69
|
-
return 0;
|
|
70
|
-
}
|
|
71
|
-
const env = ciEnv();
|
|
72
|
-
const runId = env.run_id ?? "local";
|
|
73
|
-
// Stable signature: explicit flag wins; else derive from failure-type + a
|
|
74
|
-
// hash of the lesson so the same recurring failure dedups server-side.
|
|
75
|
-
const signature = opts.signature ?? `${opts.failureType}:${sha256(opts.failureType + lesson).slice(0, 16)}`;
|
|
76
|
-
const provenance = {
|
|
77
|
-
ci_provider: opts.provider,
|
|
78
|
-
run_id: runId,
|
|
79
|
-
failure_type: opts.failureType,
|
|
80
|
-
failure_signature: signature,
|
|
81
|
-
draft_rationale: opts.rationale,
|
|
82
|
-
};
|
|
83
|
-
if (env.workflow_name)
|
|
84
|
-
provenance.workflow_name = env.workflow_name;
|
|
85
|
-
if (env.run_url)
|
|
86
|
-
provenance.run_url = env.run_url;
|
|
87
|
-
if (opts.summary)
|
|
88
|
-
provenance.failure_summary = opts.summary;
|
|
89
|
-
if (opts.remediation)
|
|
90
|
-
provenance.remediation_hint = opts.remediation;
|
|
91
|
-
if (opts.logsPath) {
|
|
92
|
-
try {
|
|
93
|
-
provenance.failure_logs = readFileSync(opts.logsPath, "utf8").slice(0, 8000);
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
// logs are best-effort
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// Repo scope (ADR-212 B4): explicit --project-key wins (validated 64-hex),
|
|
100
|
-
// else auto-detect from the repo's git remote. Fail-soft: null → the server
|
|
101
|
-
// routes the draft public (fallback), exactly as before B4.
|
|
102
|
-
const overrideKey = opts.projectKey?.trim().toLowerCase();
|
|
103
|
-
const projectKey = overrideKey && PROJECT_KEY_RE.test(overrideKey)
|
|
104
|
-
? overrideKey
|
|
105
|
-
: gatherGitState().projectKey;
|
|
106
|
-
const auth = resolveAuth();
|
|
107
|
-
const body = JSON.stringify({
|
|
108
|
-
lesson,
|
|
109
|
-
content_hash: sha256(lesson),
|
|
110
|
-
ci_provenance: provenance,
|
|
111
|
-
...(projectKey ? { project_key: projectKey } : {}),
|
|
112
|
-
});
|
|
113
|
-
let res;
|
|
114
|
-
try {
|
|
115
|
-
res = await fetch(opts.reportUrl, {
|
|
116
|
-
method: "POST",
|
|
117
|
-
headers: {
|
|
118
|
-
"content-type": "application/json",
|
|
119
|
-
authorization: `Bearer ${auth.apiKey}`,
|
|
120
|
-
},
|
|
121
|
-
body,
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
warn(`network error posting to ${opts.reportUrl}: ${msg(err)}`);
|
|
126
|
-
return 0;
|
|
127
|
-
}
|
|
128
|
-
const text = await res.text().catch(() => "");
|
|
129
|
-
if (!res.ok) {
|
|
130
|
-
warn(`ingest rejected (HTTP ${res.status}): ${text.slice(0, 300)}`);
|
|
131
|
-
return 0;
|
|
132
|
-
}
|
|
133
|
-
let parsed = {};
|
|
134
|
-
try {
|
|
135
|
-
parsed = JSON.parse(text);
|
|
136
|
-
}
|
|
137
|
-
catch {
|
|
138
|
-
// non-JSON 200 — treat as success but unparseable
|
|
139
|
-
}
|
|
140
|
-
const scope = parsed.routing_decision === "org_private"
|
|
141
|
-
? parsed.repo_scoped
|
|
142
|
-
? " [org-private, repo-scoped]"
|
|
143
|
-
: " [org-private]"
|
|
144
|
-
: "";
|
|
145
|
-
process.stderr.write(`maind ci-report: ${parsed.deduplicated ? "deduplicated" : "filed"} draft ${parsed.draft_id ?? "?"}${scope}` +
|
|
146
|
-
(parsed.review_url ? ` → ${parsed.review_url}` : "") +
|
|
147
|
-
"\n");
|
|
148
|
-
return 0;
|
|
149
|
-
}
|
|
150
|
-
catch (err) {
|
|
151
|
-
const reason = err instanceof MissingApiKeyError ? err.message : msg(err);
|
|
152
|
-
warn(`report failed, continuing: ${reason}`);
|
|
153
|
-
return 0;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
function msg(err) {
|
|
157
|
-
return err instanceof Error ? err.message : String(err);
|
|
158
|
-
}
|
|
159
|
-
function warn(line) {
|
|
160
|
-
process.stderr.write(`maind ci-report: ${line}\n`);
|
|
161
|
-
}
|
|
162
|
-
//# sourceMappingURL=ci-report.js.map
|
package/build/ci-report.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ci-report.js","sourceRoot":"","sources":["../src/ci-report.ts"],"names":[],"mappings":"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"}
|
package/build/ci-result.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// `maind ci-result` — report a CI build outcome (success|failure) together with
|
|
2
|
-
// the served-lesson manifest (ADR-207 Phase 3, FEEDBACK). For every lesson that
|
|
3
|
-
// was in the agent's context for this run (from `maind context`'s manifest.json),
|
|
4
|
-
// maind records a per-run CI signal. The aggregate "CI-confirmed N×" is shown to
|
|
5
|
-
// maintainers as a human-gated signal — it never changes a lesson's trust
|
|
6
|
-
// automatically. The signal means "this lesson was in context for N green runs"
|
|
7
|
-
// (correlation, not causation).
|
|
8
|
-
//
|
|
9
|
-
// Fail-open by contract: a failing report must never break the build. Any error
|
|
10
|
-
// → stderr warning, exit 0. Runs at the end of a job (success OR failure).
|
|
11
|
-
import { readFileSync } from "node:fs";
|
|
12
|
-
import { MissingApiKeyError, resolveAuth } from "./auth.js";
|
|
13
|
-
const DEFAULT_RESULT_URL = "https://app.maind.dev/api/ci/result";
|
|
14
|
-
export function parseCiResultArgs(argv) {
|
|
15
|
-
const get = (name) => {
|
|
16
|
-
const i = argv.indexOf(name);
|
|
17
|
-
if (i === -1 || i + 1 >= argv.length)
|
|
18
|
-
return undefined;
|
|
19
|
-
return argv[i + 1];
|
|
20
|
-
};
|
|
21
|
-
return {
|
|
22
|
-
outcome: get("--outcome") ?? null,
|
|
23
|
-
manifestPath: get("--manifest") ?? ".maind/manifest.json",
|
|
24
|
-
runRef: get("--run-ref") ?? null,
|
|
25
|
-
runUrl: get("--run-url") ?? null,
|
|
26
|
-
resultUrl: get("--result-url") ?? process.env.MAIND_RESULT_URL ?? DEFAULT_RESULT_URL,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Normalizes common CI outcome spellings (incl. GitHub Actions `${{ job.status }}`
|
|
31
|
-
* → success|failure|cancelled) to the two states the server records.
|
|
32
|
-
*/
|
|
33
|
-
function normalizeOutcome(raw) {
|
|
34
|
-
const s = raw.trim().toLowerCase();
|
|
35
|
-
if (["success", "passed", "pass", "passing", "ok", "green", "0"].includes(s))
|
|
36
|
-
return "success";
|
|
37
|
-
if (["failure", "failed", "fail", "failing", "error", "red", "cancelled", "canceled"].includes(s)) {
|
|
38
|
-
return "failure";
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
/** Collects CI run metadata from the runner environment (GitHub Actions today). */
|
|
43
|
-
function ciEnv() {
|
|
44
|
-
const env = process.env;
|
|
45
|
-
const runId = env.GITHUB_RUN_ID;
|
|
46
|
-
const repo = env.GITHUB_REPOSITORY;
|
|
47
|
-
const server = env.GITHUB_SERVER_URL ?? "https://github.com";
|
|
48
|
-
return {
|
|
49
|
-
run_id: runId || undefined,
|
|
50
|
-
run_url: runId && repo ? `${server}/${repo}/actions/runs/${runId}` : undefined,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
/** Runs the result report. Always returns 0 (fail-open). */
|
|
54
|
-
export async function runCiResult(opts) {
|
|
55
|
-
try {
|
|
56
|
-
if (!opts.outcome) {
|
|
57
|
-
warn("missing --outcome <success|failure> (e.g. --outcome ${{ job.status }}).");
|
|
58
|
-
return 0;
|
|
59
|
-
}
|
|
60
|
-
const outcome = normalizeOutcome(opts.outcome);
|
|
61
|
-
if (!outcome) {
|
|
62
|
-
warn(`unrecognized --outcome '${opts.outcome}'; expected success|failure.`);
|
|
63
|
-
return 0;
|
|
64
|
-
}
|
|
65
|
-
let manifestRaw;
|
|
66
|
-
try {
|
|
67
|
-
manifestRaw = readFileSync(opts.manifestPath, "utf8");
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
warn(`no manifest at ${opts.manifestPath} (did 'maind context' run first?); nothing to attribute.`);
|
|
71
|
-
return 0;
|
|
72
|
-
}
|
|
73
|
-
let manifest;
|
|
74
|
-
try {
|
|
75
|
-
manifest = JSON.parse(manifestRaw);
|
|
76
|
-
}
|
|
77
|
-
catch {
|
|
78
|
-
warn(`manifest at ${opts.manifestPath} is not valid JSON; skipping.`);
|
|
79
|
-
return 0;
|
|
80
|
-
}
|
|
81
|
-
const lessonIds = Array.isArray(manifest.served)
|
|
82
|
-
? manifest.served.map((s) => s.id).filter((id) => typeof id === "string" && id.length > 0)
|
|
83
|
-
: [];
|
|
84
|
-
if (lessonIds.length === 0) {
|
|
85
|
-
warn("manifest lists no served lessons; nothing to report.");
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
88
|
-
const env = ciEnv();
|
|
89
|
-
const runRef = opts.runRef ?? manifest.run_ref ?? env.run_id ?? null;
|
|
90
|
-
if (!runRef) {
|
|
91
|
-
warn("no run ref (--run-ref / manifest.run_ref / $GITHUB_RUN_ID); cannot attribute an outcome.");
|
|
92
|
-
return 0;
|
|
93
|
-
}
|
|
94
|
-
const runUrl = opts.runUrl ?? env.run_url ?? null;
|
|
95
|
-
const auth = resolveAuth();
|
|
96
|
-
const body = JSON.stringify({
|
|
97
|
-
outcome,
|
|
98
|
-
run_ref: runRef,
|
|
99
|
-
run_url: runUrl,
|
|
100
|
-
lesson_ids: lessonIds,
|
|
101
|
-
});
|
|
102
|
-
let res;
|
|
103
|
-
try {
|
|
104
|
-
res = await fetch(opts.resultUrl, {
|
|
105
|
-
method: "POST",
|
|
106
|
-
headers: {
|
|
107
|
-
"content-type": "application/json",
|
|
108
|
-
authorization: `Bearer ${auth.apiKey}`,
|
|
109
|
-
},
|
|
110
|
-
body,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
catch (err) {
|
|
114
|
-
warn(`network error posting to ${opts.resultUrl}: ${msg(err)}`);
|
|
115
|
-
return 0;
|
|
116
|
-
}
|
|
117
|
-
const text = await res.text().catch(() => "");
|
|
118
|
-
if (!res.ok) {
|
|
119
|
-
warn(`ingest rejected (HTTP ${res.status}): ${text.slice(0, 300)}`);
|
|
120
|
-
return 0;
|
|
121
|
-
}
|
|
122
|
-
let parsed = {};
|
|
123
|
-
try {
|
|
124
|
-
parsed = JSON.parse(text);
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
// non-JSON 200 — treat as success but unparseable
|
|
128
|
-
}
|
|
129
|
-
process.stderr.write(`maind ci-result: ${outcome} · recorded ${parsed.recorded ?? "?"} · skipped ${parsed.skipped ?? 0}` +
|
|
130
|
-
` (run ${runRef})\n`);
|
|
131
|
-
return 0;
|
|
132
|
-
}
|
|
133
|
-
catch (err) {
|
|
134
|
-
const reason = err instanceof MissingApiKeyError ? err.message : msg(err);
|
|
135
|
-
warn(`result failed, continuing: ${reason}`);
|
|
136
|
-
return 0;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
function msg(err) {
|
|
140
|
-
return err instanceof Error ? err.message : String(err);
|
|
141
|
-
}
|
|
142
|
-
function warn(line) {
|
|
143
|
-
process.stderr.write(`maind ci-result: ${line}\n`);
|
|
144
|
-
}
|
|
145
|
-
//# sourceMappingURL=ci-result.js.map
|
package/build/ci-result.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ci-result.js","sourceRoot":"","sources":["../src/ci-result.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,gFAAgF;AAChF,kFAAkF;AAClF,iFAAiF;AACjF,0EAA0E;AAC1E,gFAAgF;AAChF,gCAAgC;AAChC,EAAE;AACF,gFAAgF;AAChF,2EAA2E;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG5D,MAAM,kBAAkB,GAAG,qCAAqC,CAAC;AAUjE,MAAM,UAAU,iBAAiB,CAAC,IAAc;IAC9C,MAAM,GAAG,GAAG,CAAC,IAAY,EAAsB,EAAE;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QACvD,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI;QACjC,YAAY,EAAE,GAAG,CAAC,YAAY,CAAC,IAAI,sBAAsB;QACzD,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI;QAChC,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI;QAChC,SAAS,EAAE,GAAG,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,kBAAkB;KACrF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/F,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QAClG,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mFAAmF;AACnF,SAAS,KAAK;IACZ,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC;IAChC,MAAM,IAAI,GAAG,GAAG,CAAC,iBAAiB,CAAC;IACnC,MAAM,MAAM,GAAG,GAAG,CAAC,iBAAiB,IAAI,oBAAoB,CAAC;IAC7D,OAAO;QACL,MAAM,EAAE,KAAK,IAAI,SAAS;QAC1B,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,IAAI,iBAAiB,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS;KAC/E,CAAC;AACJ,CAAC;AAED,4DAA4D;AAC5D,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAqB;IACrD,IAAI,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,yEAAyE,CAAC,CAAC;YAChF,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,2BAA2B,IAAI,CAAC,OAAO,8BAA8B,CAAC,CAAC;YAC5E,OAAO,CAAC,CAAC;QACX,CAAC;QAED,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,kBAAkB,IAAI,CAAC,YAAY,0DAA0D,CAAC,CAAC;YACpG,OAAO,CAAC,CAAC;QACX,CAAC;QAED,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAa,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,eAAe,IAAI,CAAC,YAAY,+BAA+B,CAAC,CAAC;YACtE,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC9C,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;YACxG,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,sDAAsD,CAAC,CAAC;YAC7D,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC;QACrE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,0FAA0F,CAAC,CAAC;YACjG,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC;QAElD,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,OAAO;YACP,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,MAAM;YACf,UAAU,EAAE,SAAS;SACtB,CAAC,CAAC;QAEH,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE;gBAChC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;iBACvC;gBACD,IAAI;aACL,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,4BAA4B,IAAI,CAAC,SAAS,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChE,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,yBAAyB,GAAG,CAAC,MAAM,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,MAAM,GAA4C,EAAE,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;QACpD,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,oBAAoB,OAAO,eAAe,MAAM,CAAC,QAAQ,IAAI,GAAG,cAAc,MAAM,CAAC,OAAO,IAAI,CAAC,EAAE;YACjG,SAAS,MAAM,KAAK,CACvB,CAAC;QACF,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1E,IAAI,CAAC,8BAA8B,MAAM,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,SAAS,GAAG,CAAC,GAAY;IACvB,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,IAAI,CAAC,IAAY;IACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,IAAI,IAAI,CAAC,CAAC;AACrD,CAAC"}
|