@hawkeyexl/manni 4.4.1 → 4.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/README.md +1 -1
- package/dist/batch-OZOACN4G.js +41 -0
- package/dist/build-Z5VOVADH.js +32 -0
- package/dist/calibrate-TZYT42DR.js +36 -0
- package/dist/capture-SL4MNDDP.js +34 -0
- package/dist/check-5OMA42Y6.js +26 -0
- package/dist/{check-HYNGXYJV.js → check-OAJWC3WD.js} +7 -5
- package/dist/{check-ASPIHA6B.js → check-PKY7KTQE.js} +13 -14
- package/dist/check-WB2QDHJQ.js +880 -0
- package/dist/check-WB2QDHJQ.js.map +1 -0
- package/dist/{chunk-MWJLZMBL.js → chunk-2JFPBZJK.js} +11 -11
- package/dist/{chunk-QQUKGCAJ.js → chunk-2KRB3EG7.js} +2 -2
- package/dist/{chunk-DXNZS72W.js → chunk-2M6DVNI5.js} +10 -6
- package/dist/{chunk-DXNZS72W.js.map → chunk-2M6DVNI5.js.map} +1 -1
- package/dist/{chunk-QZ6LRSNV.js → chunk-3NWX34ZI.js} +19 -19
- package/dist/{chunk-IDV6HJCB.js → chunk-5G53XATW.js} +4 -4
- package/dist/{chunk-M2JCK5F6.js → chunk-6KKZXB2O.js} +19 -6
- package/dist/chunk-6KKZXB2O.js.map +1 -0
- package/dist/{chunk-PNPQTHBT.js → chunk-733Y2STG.js} +2 -2
- package/dist/{chunk-WB3QM6PP.js → chunk-73TC4DYH.js} +332 -2522
- package/dist/chunk-73TC4DYH.js.map +1 -0
- package/dist/{chunk-EPH54CAY.js → chunk-7WRP5FFP.js} +4 -4
- package/dist/{chunk-NXV7WE2D.js → chunk-APKH2T6E.js} +29 -591
- package/dist/chunk-APKH2T6E.js.map +1 -0
- package/dist/{chunk-I2AH3CJJ.js → chunk-B3TS4WRM.js} +17 -15
- package/dist/{chunk-I2AH3CJJ.js.map → chunk-B3TS4WRM.js.map} +1 -1
- package/dist/chunk-BWCWTHYS.js +146 -0
- package/dist/chunk-BWCWTHYS.js.map +1 -0
- package/dist/{chunk-MMTSSTG7.js → chunk-C3B2VJNC.js} +2 -2
- package/dist/{chunk-PU6DFJMY.js → chunk-C73RSUIC.js} +4 -4
- package/dist/chunk-CU57HT2E.js +116 -0
- package/dist/chunk-CU57HT2E.js.map +1 -0
- package/dist/chunk-CWXZ2MRT.js +222 -0
- package/dist/chunk-CWXZ2MRT.js.map +1 -0
- package/dist/{chunk-GCQRPUSB.js → chunk-DC5DDJVE.js} +6 -6
- package/dist/{chunk-6OYEI2VV.js → chunk-ECVQNGTH.js} +3 -3
- package/dist/chunk-FLAO4ZS3.js +502 -0
- package/dist/chunk-FLAO4ZS3.js.map +1 -0
- package/dist/chunk-FQGLRJGX.js +174 -0
- package/dist/chunk-FQGLRJGX.js.map +1 -0
- package/dist/{chunk-7UKO3ASZ.js → chunk-GAJIJKET.js} +3 -3
- package/dist/{chunk-6JSSEWBG.js → chunk-GREQKO6M.js} +202 -54
- package/dist/chunk-GREQKO6M.js.map +1 -0
- package/dist/chunk-HX44GB4Z.js +30 -0
- package/dist/chunk-HX44GB4Z.js.map +1 -0
- package/dist/{chunk-4IUC2MNL.js → chunk-IY7NYNPZ.js} +9 -11
- package/dist/{chunk-4IUC2MNL.js.map → chunk-IY7NYNPZ.js.map} +1 -1
- package/dist/{chunk-57NEQRVO.js → chunk-KCOFEWV5.js} +8 -6
- package/dist/{chunk-57NEQRVO.js.map → chunk-KCOFEWV5.js.map} +1 -1
- package/dist/chunk-M2RLHZ4J.js +849 -0
- package/dist/chunk-M2RLHZ4J.js.map +1 -0
- package/dist/{chunk-NLXTXE5Y.js → chunk-M6GSS72T.js} +185 -33
- package/dist/chunk-M6GSS72T.js.map +1 -0
- package/dist/{chunk-YTURO7SI.js → chunk-MHM4QEBV.js} +4 -4
- package/dist/{chunk-RL5XWQOL.js → chunk-MOWMCEOJ.js} +143 -54
- package/dist/chunk-MOWMCEOJ.js.map +1 -0
- package/dist/{chunk-C4SQM22E.js → chunk-MWBJ3KTF.js} +13 -11
- package/dist/chunk-MWBJ3KTF.js.map +1 -0
- package/dist/chunk-N7JSEDSC.js +233 -0
- package/dist/chunk-N7JSEDSC.js.map +1 -0
- package/dist/{chunk-JCDXE76J.js → chunk-NBMPHD4I.js} +2 -2
- package/dist/{chunk-37LP5HMZ.js → chunk-NHHOPZRA.js} +12 -10
- package/dist/{chunk-37LP5HMZ.js.map → chunk-NHHOPZRA.js.map} +1 -1
- package/dist/{chunk-YB4IBW3M.js → chunk-NTWW7J76.js} +2 -2
- package/dist/{chunk-UJCVAWP7.js → chunk-PCFG7E6B.js} +3 -3
- package/dist/{chunk-UJCVAWP7.js.map → chunk-PCFG7E6B.js.map} +1 -1
- package/dist/{chunk-FBEQCK47.js → chunk-PL4UAF4S.js} +73 -1304
- package/dist/chunk-PL4UAF4S.js.map +1 -0
- package/dist/chunk-QCHVR4ZM.js +286 -0
- package/dist/chunk-QCHVR4ZM.js.map +1 -0
- package/dist/{chunk-PIKOVN6W.js → chunk-QW77LCOU.js} +10 -10
- package/dist/{chunk-2B7ZNTPV.js → chunk-SM6NOMJS.js} +2 -2
- package/dist/chunk-SWSTHZBI.js +2464 -0
- package/dist/chunk-SWSTHZBI.js.map +1 -0
- package/dist/{chunk-JXLTXMJ7.js → chunk-T6SYGLWR.js} +3 -3
- package/dist/{chunk-CK7SKVHR.js → chunk-TBAMBLF3.js} +3 -12
- package/dist/chunk-TBAMBLF3.js.map +1 -0
- package/dist/chunk-TH4JVQPF.js +133 -0
- package/dist/chunk-TH4JVQPF.js.map +1 -0
- package/dist/{chunk-QRWGPQKO.js → chunk-TLXE7LYK.js} +4 -4
- package/dist/{chunk-M3W7J6MU.js → chunk-TUAAR3MM.js} +3280 -283
- package/dist/chunk-TUAAR3MM.js.map +1 -0
- package/dist/{chunk-SKSDRUUK.js → chunk-UAKNZVCD.js} +4 -4
- package/dist/{chunk-YJOGUXGP.js → chunk-UJSGS2Y5.js} +8 -6
- package/dist/{chunk-YJOGUXGP.js.map → chunk-UJSGS2Y5.js.map} +1 -1
- package/dist/{chunk-UQISLDAV.js → chunk-UWQ2UVHE.js} +8 -6
- package/dist/{chunk-UQISLDAV.js.map → chunk-UWQ2UVHE.js.map} +1 -1
- package/dist/chunk-WQWKYAAK.js +86 -0
- package/dist/chunk-WQWKYAAK.js.map +1 -0
- package/dist/{chunk-LJ2RDH3F.js → chunk-XG6PVB5S.js} +1 -23
- package/dist/chunk-XG6PVB5S.js.map +1 -0
- package/dist/{chunk-Q35YIDBV.js → chunk-XKBEHKWO.js} +29 -264
- package/dist/chunk-XKBEHKWO.js.map +1 -0
- package/dist/chunk-XPEWUK7J.js +532 -0
- package/dist/chunk-XPEWUK7J.js.map +1 -0
- package/dist/{chunk-MYMBCTDE.js → chunk-XXDXIIQ4.js} +2 -2
- package/dist/chunk-YGFIQ6Y5.js +17 -0
- package/dist/chunk-YGFIQ6Y5.js.map +1 -0
- package/dist/chunk-YLK2J5YK.js +610 -0
- package/dist/chunk-YLK2J5YK.js.map +1 -0
- package/dist/{chunk-3VK37OR2.js → chunk-Z4IZGEM3.js} +16 -12
- package/dist/{chunk-3VK37OR2.js.map → chunk-Z4IZGEM3.js.map} +1 -1
- package/dist/{cli-6HIDIFVT.js → cli-6EWVMEN6.js} +5 -3
- package/dist/{cli-6HIDIFVT.js.map → cli-6EWVMEN6.js.map} +1 -1
- package/dist/{cli-VI7VHWNZ.js → cli-6H7HVDMQ.js} +113 -20
- package/dist/{cli-VI7VHWNZ.js.map → cli-6H7HVDMQ.js.map} +1 -1
- package/dist/{cli-RPM5PELX.js → cli-EPVZHAZS.js} +24 -20
- package/dist/cli-EPVZHAZS.js.map +1 -0
- package/dist/{cli-MN7PYMBI.js → cli-LUCSGTVI.js} +17 -19
- package/dist/{cli-MN7PYMBI.js.map → cli-LUCSGTVI.js.map} +1 -1
- package/dist/{cli-LFP5ZGYS.js → cli-NIG4N3XM.js} +16 -15
- package/dist/{cli-LFP5ZGYS.js.map → cli-NIG4N3XM.js.map} +1 -1
- package/dist/{cli-PYPX6O6E.js → cli-PSKNB66T.js} +225 -58
- package/dist/cli-PSKNB66T.js.map +1 -0
- package/dist/{cli-3BIBYHFK.js → cli-UO4NHIB3.js} +17 -17
- package/dist/{cli-6UB5N6CU.js → cli-UQ7A3YA2.js} +17 -18
- package/dist/{cli-6UB5N6CU.js.map → cli-UQ7A3YA2.js.map} +1 -1
- package/dist/{cli-673OTRGE.js → cli-YHYDLQAF.js} +10 -10
- package/dist/cli.js +11 -11
- package/dist/config-P4HDNTYD.js +26 -0
- package/dist/conformance-ZFCMKM6M.js +18 -0
- package/dist/docmeta.js +9 -9
- package/dist/github-7ZCH5PSO.js +26 -0
- package/dist/github-POT6724K.js +31 -0
- package/dist/host-6GURH5HE.js +23 -0
- package/dist/index.d.ts +102 -12
- package/dist/index.js +185 -171
- package/dist/index.js.map +1 -1
- package/dist/{json-SY7KLNC7.js → json-KT2K62L5.js} +12 -13
- package/dist/lint-5AQ5C2BV.js +29 -0
- package/dist/list-5JZKX2NK.js +28 -0
- package/dist/list-SWPFXQMU.js +30 -0
- package/dist/{page-KSGV5RD4.js → page-UPSXRP75.js} +11 -12
- package/dist/prepare-6GNEWCNH.js +155 -0
- package/dist/prepare-6GNEWCNH.js.map +1 -0
- package/dist/{pretty-CXSDXNAS.js → pretty-Q6FQAOK4.js} +13 -14
- package/dist/{pretty-A5EGTN35.js → pretty-SQRPFPSQ.js} +12 -13
- package/dist/provider-AMGRDY6V.js +34 -0
- package/dist/release-IECYCLTD.js +36 -0
- package/dist/release-IECYCLTD.js.map +1 -0
- package/dist/{reporters-HUY7UXFS.js → reporters-45MMC2ID.js} +13 -13
- package/dist/{reporters-K2VUKSAK.js → reporters-XUV4MM64.js} +7 -5
- package/dist/reporters-XUV4MM64.js.map +1 -0
- package/dist/run-KMWY2IAN.js +32 -0
- package/dist/run-KMWY2IAN.js.map +1 -0
- package/dist/{term-BIQUPMOR.js → term-PCJUCWNF.js} +16 -17
- package/dist/{term-BIQUPMOR.js.map → term-PCJUCWNF.js.map} +1 -1
- package/dist/validate-IMNCZNWG.js +17 -0
- package/dist/validate-IMNCZNWG.js.map +1 -0
- package/package.json +2 -2
- package/plugin/manni/.claude-plugin/plugin.json +1 -1
- package/plugin/manni/hooks/hooks.json +47 -0
- package/dist/batch-GFNLTGOH.js +0 -36
- package/dist/build-COYIQ25L.js +0 -31
- package/dist/calibrate-MDBLJKEE.js +0 -31
- package/dist/capture-LRML2PKV.js +0 -32
- package/dist/check-EDLBYL5N.js +0 -27
- package/dist/chunk-6JSSEWBG.js.map +0 -1
- package/dist/chunk-A5ULMVHQ.js +0 -164
- package/dist/chunk-A5ULMVHQ.js.map +0 -1
- package/dist/chunk-C4SQM22E.js.map +0 -1
- package/dist/chunk-CK7SKVHR.js.map +0 -1
- package/dist/chunk-FBEQCK47.js.map +0 -1
- package/dist/chunk-LJ2RDH3F.js.map +0 -1
- package/dist/chunk-M2JCK5F6.js.map +0 -1
- package/dist/chunk-M3W7J6MU.js.map +0 -1
- package/dist/chunk-NLXTXE5Y.js.map +0 -1
- package/dist/chunk-NXV7WE2D.js.map +0 -1
- package/dist/chunk-Q35YIDBV.js.map +0 -1
- package/dist/chunk-RL5XWQOL.js.map +0 -1
- package/dist/chunk-TK3FC4RF.js +0 -3090
- package/dist/chunk-TK3FC4RF.js.map +0 -1
- package/dist/chunk-TU2WUBVZ.js +0 -2
- package/dist/chunk-WB3QM6PP.js.map +0 -1
- package/dist/cli-PYPX6O6E.js.map +0 -1
- package/dist/cli-RPM5PELX.js.map +0 -1
- package/dist/github-6QMYOHC3.js +0 -27
- package/dist/github-SXPGP5DB.js +0 -32
- package/dist/lint-ASMJLLPA.js +0 -28
- package/dist/list-KZNVTNVC.js +0 -31
- package/dist/list-Q57YTFUQ.js +0 -29
- package/dist/run-3DYJNRIG.js +0 -33
- package/dist/validate-53RKM2XG.js +0 -16
- /package/dist/{batch-GFNLTGOH.js.map → batch-OZOACN4G.js.map} +0 -0
- /package/dist/{build-COYIQ25L.js.map → build-Z5VOVADH.js.map} +0 -0
- /package/dist/{calibrate-MDBLJKEE.js.map → calibrate-TZYT42DR.js.map} +0 -0
- /package/dist/{capture-LRML2PKV.js.map → capture-SL4MNDDP.js.map} +0 -0
- /package/dist/{check-ASPIHA6B.js.map → check-5OMA42Y6.js.map} +0 -0
- /package/dist/{check-EDLBYL5N.js.map → check-OAJWC3WD.js.map} +0 -0
- /package/dist/{check-HYNGXYJV.js.map → check-PKY7KTQE.js.map} +0 -0
- /package/dist/{chunk-MWJLZMBL.js.map → chunk-2JFPBZJK.js.map} +0 -0
- /package/dist/{chunk-QQUKGCAJ.js.map → chunk-2KRB3EG7.js.map} +0 -0
- /package/dist/{chunk-QZ6LRSNV.js.map → chunk-3NWX34ZI.js.map} +0 -0
- /package/dist/{chunk-IDV6HJCB.js.map → chunk-5G53XATW.js.map} +0 -0
- /package/dist/{chunk-PNPQTHBT.js.map → chunk-733Y2STG.js.map} +0 -0
- /package/dist/{chunk-EPH54CAY.js.map → chunk-7WRP5FFP.js.map} +0 -0
- /package/dist/{chunk-MMTSSTG7.js.map → chunk-C3B2VJNC.js.map} +0 -0
- /package/dist/{chunk-PU6DFJMY.js.map → chunk-C73RSUIC.js.map} +0 -0
- /package/dist/{chunk-GCQRPUSB.js.map → chunk-DC5DDJVE.js.map} +0 -0
- /package/dist/{chunk-6OYEI2VV.js.map → chunk-ECVQNGTH.js.map} +0 -0
- /package/dist/{chunk-7UKO3ASZ.js.map → chunk-GAJIJKET.js.map} +0 -0
- /package/dist/{chunk-YTURO7SI.js.map → chunk-MHM4QEBV.js.map} +0 -0
- /package/dist/{chunk-JCDXE76J.js.map → chunk-NBMPHD4I.js.map} +0 -0
- /package/dist/{chunk-YB4IBW3M.js.map → chunk-NTWW7J76.js.map} +0 -0
- /package/dist/{chunk-PIKOVN6W.js.map → chunk-QW77LCOU.js.map} +0 -0
- /package/dist/{chunk-2B7ZNTPV.js.map → chunk-SM6NOMJS.js.map} +0 -0
- /package/dist/{chunk-JXLTXMJ7.js.map → chunk-T6SYGLWR.js.map} +0 -0
- /package/dist/{chunk-QRWGPQKO.js.map → chunk-TLXE7LYK.js.map} +0 -0
- /package/dist/{chunk-SKSDRUUK.js.map → chunk-UAKNZVCD.js.map} +0 -0
- /package/dist/{chunk-MYMBCTDE.js.map → chunk-XXDXIIQ4.js.map} +0 -0
- /package/dist/{cli-3BIBYHFK.js.map → cli-UO4NHIB3.js.map} +0 -0
- /package/dist/{chunk-TU2WUBVZ.js.map → cli-YHYDLQAF.js.map} +0 -0
- /package/dist/{cli-673OTRGE.js.map → config-P4HDNTYD.js.map} +0 -0
- /package/dist/{github-6QMYOHC3.js.map → conformance-ZFCMKM6M.js.map} +0 -0
- /package/dist/{github-SXPGP5DB.js.map → github-7ZCH5PSO.js.map} +0 -0
- /package/dist/{json-SY7KLNC7.js.map → github-POT6724K.js.map} +0 -0
- /package/dist/{lint-ASMJLLPA.js.map → host-6GURH5HE.js.map} +0 -0
- /package/dist/{list-KZNVTNVC.js.map → json-KT2K62L5.js.map} +0 -0
- /package/dist/{list-Q57YTFUQ.js.map → lint-5AQ5C2BV.js.map} +0 -0
- /package/dist/{page-KSGV5RD4.js.map → list-5JZKX2NK.js.map} +0 -0
- /package/dist/{pretty-A5EGTN35.js.map → list-SWPFXQMU.js.map} +0 -0
- /package/dist/{pretty-CXSDXNAS.js.map → page-UPSXRP75.js.map} +0 -0
- /package/dist/{reporters-HUY7UXFS.js.map → pretty-Q6FQAOK4.js.map} +0 -0
- /package/dist/{reporters-K2VUKSAK.js.map → pretty-SQRPFPSQ.js.map} +0 -0
- /package/dist/{run-3DYJNRIG.js.map → provider-AMGRDY6V.js.map} +0 -0
- /package/dist/{validate-53RKM2XG.js.map → reporters-45MMC2ID.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
NS,
|
|
5
5
|
PREFIXES,
|
|
6
6
|
byCodeUnit
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6KKZXB2O.js";
|
|
8
8
|
import {
|
|
9
9
|
packageRoot
|
|
10
10
|
} from "./chunk-TIUTIOFB.js";
|
|
@@ -384,4 +384,4 @@ export {
|
|
|
384
384
|
bundledShapesPath,
|
|
385
385
|
validateGraph
|
|
386
386
|
};
|
|
387
|
-
//# sourceMappingURL=chunk-
|
|
387
|
+
//# sourceMappingURL=chunk-XXDXIIQ4.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ToolError
|
|
4
|
+
} from "./chunk-G3T47CFV.js";
|
|
5
|
+
|
|
6
|
+
// src/lint/types.ts
|
|
7
|
+
var LintError = class extends ToolError {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "LintError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
LintError
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=chunk-YGFIQ6Y5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lint/types.ts"],"sourcesContent":["/**\n * The contract every other module is written against.\n *\n * Two shapes matter. `DocumentTree` is what a parser owes the rest of the tool:\n * a nested section tree with real source positions, in a vocabulary that has\n * nothing to do with Markdown. `Finding` is what the tool owes its caller.\n * Everything between the two - matching, rules, reporting - touches neither\n * mdast nor Asciidoctor nor parse5, which is what lets a new input format be\n * one file plus a line in the parser registry.\n */\n\nimport { ToolError } from \"../shared/errors.js\";\nimport type { Severity } from \"../shared/severity.js\";\n\n/**\n * Operational/usage failure. Exits 2; never used for lint findings.\n *\n * Extends the umbrella's `ToolError`, which is what the shared bin runner\n * matches on; the subclass stays so this tool's tests and library callers can\n * match on it by name. Named for its domain, as `A11yError`, `CiteError` and\n * `KeyError` are.\n */\nexport class LintError extends ToolError {\n constructor(message: string) {\n super(message);\n this.name = \"LintError\";\n }\n}\n\n/** A point in a source file. Line and column are 1-based, offset 0-based. */\nexport interface Point {\n line: number;\n column: number;\n offset: number;\n}\n\n/** A half-open source span, `start` inclusive and `end` exclusive. */\nexport interface Position {\n start: Point;\n end: Point;\n}\n\n/**\n * Content kinds a section can hold, named generically so a rule written once\n * works on every format. Each parser maps its own AST onto these: mdast\n * `paragraph`/`code`/`list`, Asciidoctor `paragraph`/`listing`/`ulist`|`olist`,\n * HTML `<p>`/`<pre>`/`<ul>` - all three onto `paragraph`/`codeBlock`/`list`.\n *\n * The vocabulary is wider than any one parser emits today. `table`,\n * `admonition`, `image`, `blockquote`, `definitionList`, and `element` are\n * declared here, and in each `DocumentParser.kinds`, only once a parser\n * actually produces them - see `src/lint/parsers/index.ts`.\n */\nexport type ContentKind =\n | \"paragraph\"\n | \"codeBlock\"\n | \"list\"\n | \"listItem\"\n | \"table\"\n | \"tableRow\"\n | \"tableCell\"\n | \"admonition\"\n | \"image\"\n | \"blockquote\"\n | \"definitionList\"\n | \"definitionItem\"\n | \"element\";\n\nexport interface ContentNodeBase {\n kind: ContentKind;\n position: Position;\n /** Plain-text rendering, used by pattern rules. */\n text: string;\n}\n\nexport interface ParagraphNode extends ContentNodeBase {\n kind: \"paragraph\";\n}\n\nexport interface CodeNode extends ContentNodeBase {\n kind: \"codeBlock\";\n /** Language, when the format carries one. */\n language?: string;\n /** The info-string tail after the language, when the format carries one. */\n fenceInfo?: string;\n}\n\nexport interface ListItemNode {\n kind: \"listItem\";\n position: Position;\n text: string;\n /** Nested content, so item-level paragraph/code/list rules can run. */\n children: ContentNode[];\n}\n\nexport interface ListNode extends ContentNodeBase {\n kind: \"list\";\n ordered: boolean;\n items: ListItemNode[];\n}\n\nexport interface TableCellNode extends ContentNodeBase {\n kind: \"tableCell\";\n children: ContentNode[];\n}\n\nexport interface TableRowNode extends ContentNodeBase {\n kind: \"tableRow\";\n header: boolean;\n children: TableCellNode[];\n}\n\nexport interface TableNode extends ContentNodeBase {\n kind: \"table\";\n children: TableRowNode[];\n}\n\n/**\n * A callout, and the flavor the source gave it.\n *\n * `variant` is optional because not every format names one this vocabulary\n * has. reStructuredText has `hint`, `attention`, `error` and a generic\n * `admonition` directive, and a bare HTML `<aside>` says nothing at all. Those\n * produce an admonition with no variant rather than an invented equivalence:\n * mapping `hint` onto `tip` would make `variant: tip` pass on a page that\n * never said tip. A `variant:` rule reports such a node as a mismatch, and a\n * plain count rule still counts it.\n */\nexport interface AdmonitionNode extends ContentNodeBase {\n kind: \"admonition\";\n variant?: \"note\" | \"tip\" | \"important\" | \"caution\" | \"warning\" | \"danger\";\n children: ContentNode[];\n}\n\nexport interface ImageNode extends ContentNodeBase {\n kind: \"image\";\n url: string;\n alt: string;\n title?: string;\n}\n\nexport interface BlockquoteNode extends ContentNodeBase {\n kind: \"blockquote\";\n children: ContentNode[];\n}\n\nexport interface DefinitionItemNode {\n kind: \"definitionItem\";\n position: Position;\n text: string;\n term: string;\n definition: ContentNode[];\n}\n\nexport interface DefinitionListNode extends ContentNodeBase {\n kind: \"definitionList\";\n children: DefinitionItemNode[];\n}\n\n/**\n * A named wrapper - an MDX/JSX component today, and where HTML and DITA may\n * eventually anchor a custom element. Its children are its own content, never\n * the enclosing section's: a rule reading a section's `children` must not see\n * inside an `<Element>` it did not ask about.\n */\nexport interface ElementNode extends ContentNodeBase {\n kind: \"element\";\n name: string;\n attributes?: Record<string, string | true>;\n children: ContentNode[];\n}\n\nexport type ContentNode =\n | ParagraphNode\n | CodeNode\n | ListNode\n | TableNode\n | AdmonitionNode\n | ImageNode\n | BlockquoteNode\n | DefinitionListNode\n | ElementNode;\n\n/**\n * One section of a document, demarcated by a heading.\n *\n * `slug`/`title`/`level`/`order`/`parentSlug` intentionally match manni graph's\n * `Section` (dockg/src/types.ts), so its graph can be built from this tree.\n *\n * `children` is in document order and is the single source of truth: the\n * paragraph/codeBlock/list counts every rule needs are queries over it, not\n * separately maintained arrays.\n */\nexport interface SectionNode {\n /** Slug of the heading, disambiguated across the document (`install-1`). */\n slug: string;\n /** Heading text, with inline markup flattened. */\n title: string;\n /** Heading level, 1-6. 0 for the implicit lead section before any heading. */\n level: number;\n /** 1-based position among siblings under the same parent. */\n order: number;\n /** Slug of the enclosing section, or null at the top level. */\n parentSlug: string | null;\n /** Span of the title itself. Null for the implicit lead section. */\n titlePosition: Position | null;\n /**\n * The anchor the source itself gives this section, verbatim - an HTML `id`,\n * a DITA `@id`, an AsciiDoc `[[id]]`, a reST `.. _label:` - when it gives\n * one. `slug` stays the slugged title either way: a link written against\n * the source's own id resolves through this, and nothing lint matches on\n * reads it.\n */\n id?: string;\n /**\n * Set on the level-1 section `withMetadataTitle` made from a metadata\n * `title`, so a consumer can tell it from a heading the author wrote. Its\n * `titlePosition` is not enough: a reST title read back as docinfo shares\n * its span with the frontmatter, written or not.\n */\n synthetic?: true;\n /** Span of the whole section: its heading through the last node before the next sibling heading. */\n position: Position;\n /** Direct content, in document order, excluding anything owned by a subsection. */\n children: ContentNode[];\n /** Nested sections, in document order. */\n sections: SectionNode[];\n}\n\n/** What a parser returns for one file. */\nexport interface DocumentTree {\n /** Name of the parser that produced this (`markdown`, `asciidoc`, ...). */\n format: string;\n /** Path the content came from, for error messages. */\n filePath: string;\n /** Raw frontmatter/metadata values, or null when the file carries none. */\n frontmatter: Record<string, unknown> | null;\n /** Span of the frontmatter block, for anchoring findings about it. */\n frontmatterPosition: Position | null;\n /** Top-level sections, in document order. */\n sections: SectionNode[];\n /**\n * Link targets exactly as the source wrote them, in document order, for\n * `manni graph`. No lint rule reads them. Each parser decides what counts:\n * an anchor to elsewhere does, and a stylesheet, a heading's own permalink,\n * or a key reference resolved only at build time does not.\n */\n links: { target: string; position: Position }[];\n}\n\n/**\n * A parser for one input format.\n *\n * Shaped after docmeta's `MetadataExtractor` so the two registries read the\n * same way. A format is registered only when its parser reads it, so every\n * registered format is one the tool reads, and an extension no parser claims is\n * skipped by name rather than parsed as Markdown.\n */\nexport interface DocumentParser {\n /** Stable name, also used as `DocumentTree.format`. */\n name: string;\n /** Human-readable label for `manni lint tools`. */\n label: string;\n /**\n * The content kinds this parser actually emits today. A capability\n * declaration, not the full `ContentKind` vocabulary: a kind absent here is\n * one no rule will ever see from this parser's trees, whatever the format\n * could in principle represent.\n */\n kinds: ContentKind[];\n /** Lowercase file extensions this parser handles, incl. dot (e.g. \".md\"). */\n extensions: string[];\n /**\n * Extensions safe to collect from a directory walk. Defaults to\n * `extensions`.\n *\n * The two differ when an extension is a generic container rather than a\n * documentation format. `.xml` is the case: this parser can read a DocBook\n * or DITA document named explicitly, but a docs tree also contains\n * `pom.xml`, `sitemap.xml`, and `.csproj`, and sweeping those in turns a\n * clean run into a failure about files the user never asked to lint.\n */\n walkExtensions?: string[];\n /** Parse raw file content into the generic tree. */\n parse(content: string, filePath: string): DocumentTree;\n}\n\n/**\n * How much a finding weighs, on the one scale every manni tool speaks\n * (`src/shared/severity.ts`): `notice | warning | error`.\n *\n * Almost every structural finding is an `error`, since a template either\n * describes a document or it does not. `unsupported_content_kind` is the\n * exception and is a `warning`: the rule never ran, so the page may still be\n * fine, and a warning never moves the exit code.\n *\n * The scale is the family's and not this tool's private pair, because a flag\n * or config key two domains both have carries the same name *and* the same\n * values. Re-exported so `lint.Severity` names the same type a caller already\n * has.\n */\nexport type { Severity };\n\n/**\n * One structural violation.\n *\n * The field set is pinned by manni docevals' tool adapter, which reads\n * `{ type, heading, message, position }` off the JSON reporter. Additions are\n * safe; renames are not.\n */\nexport interface Finding {\n /** Machine-readable rule id, e.g. `missing_section`. */\n type: string;\n /** Heading of the section the finding is anchored to, if any. */\n heading: string | null;\n message: string;\n position: Position;\n severity: Severity;\n}\n\n/**\n * Why a file was not linted.\n *\n * `unreadable` is the one that is not about the document: the file was found,\n * claimed by a parser, and then could not be opened - a denied permission, a\n * symlink loop, a page a doc build moved between the walk and the read. It is a\n * skip rather than a finding because nothing was checked, and calling it a\n * finding would report the docs as wrong when the filesystem was.\n */\nexport type SkipReason = \"no-template\" | \"unsupported-format\" | \"unreadable\";\n\n/** Result of linting one file. */\nexport interface FileResult {\n file: string;\n /** True when the file was linted and produced no findings. */\n success: boolean;\n findings: Finding[];\n /** Template id/ref applied, or null when skipped. */\n template: string | null;\n /** Set when the file was skipped rather than linted. */\n skipped?: SkipReason;\n}\n"],"mappings":";;;;;;AAsBO,IAAM,YAAN,cAAwB,UAAU;AAAA,EACvC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
|
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
emptyWindow,
|
|
4
|
+
materialize,
|
|
5
|
+
windowOf
|
|
6
|
+
} from "./chunk-CWXZ2MRT.js";
|
|
7
|
+
import {
|
|
8
|
+
extractEvals,
|
|
9
|
+
findGitRoot,
|
|
10
|
+
listInTree,
|
|
11
|
+
resolveArtifacts,
|
|
12
|
+
safeRead
|
|
13
|
+
} from "./chunk-APKH2T6E.js";
|
|
14
|
+
import {
|
|
15
|
+
configDir
|
|
16
|
+
} from "./chunk-4TSWU2SU.js";
|
|
17
|
+
import {
|
|
18
|
+
extractFrontmatter
|
|
19
|
+
} from "./chunk-KCOFEWV5.js";
|
|
20
|
+
|
|
21
|
+
// src/tracevals/rules/turn.ts
|
|
22
|
+
var INJECTED = /<(system-reminder|task-notification|ci-monitor-event|local-command-stdout|local-command-stderr|local-command-caveat)>[\s\S]*?<\/\1>/g;
|
|
23
|
+
var MARKER = /^(?:Stop hook feedback:|SubagentStop hook feedback:|\[Request interrupted by user)/;
|
|
24
|
+
var TYPED_TURN_ORIGINS = /* @__PURE__ */ new Set(["human", "sdk"]);
|
|
25
|
+
var WORK = /* @__PURE__ */ new Set(["assistant", "tool_call", "tool_result"]);
|
|
26
|
+
function isTypedPrompt(event) {
|
|
27
|
+
if (event.kind !== "user" || event.text === void 0) return false;
|
|
28
|
+
const { raw } = event;
|
|
29
|
+
if (raw.isMeta === true || raw.isCompactSummary === true) return false;
|
|
30
|
+
const origin = raw.origin;
|
|
31
|
+
if (typeof origin === "object" && origin !== null && "kind" in origin && typeof origin.kind === "string") {
|
|
32
|
+
if (!TYPED_TURN_ORIGINS.has(origin.kind)) return false;
|
|
33
|
+
} else if (typeof raw.turnOrigin === "string" && !TYPED_TURN_ORIGINS.has(raw.turnOrigin)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const rest = event.text.replace(INJECTED, "").trim();
|
|
37
|
+
return rest !== "" && !MARKER.test(rest);
|
|
38
|
+
}
|
|
39
|
+
function lastTurn(trace) {
|
|
40
|
+
const prompts = trace.events.filter((e) => e.sidechain !== true && isTypedPrompt(e));
|
|
41
|
+
const sessionTurnCount = prompts.length;
|
|
42
|
+
const to = trace.events.length - 1;
|
|
43
|
+
const last = prompts.at(-1);
|
|
44
|
+
if (last === void 0) {
|
|
45
|
+
return {
|
|
46
|
+
window: emptyWindow("turn", "last turn", "the trace holds no prompt the user typed"),
|
|
47
|
+
from: to + 1,
|
|
48
|
+
to,
|
|
49
|
+
sessionTurnCount
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return slice(trace, last.index, [last], /* @__PURE__ */ new Set([void 0]), sessionTurnCount, {
|
|
53
|
+
label: "last turn",
|
|
54
|
+
reason: "nothing happened after the last prompt the user typed"
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function subagentTurn(trace) {
|
|
58
|
+
const prompts = trace.events.filter(isTypedPrompt);
|
|
59
|
+
return slice(
|
|
60
|
+
trace,
|
|
61
|
+
0,
|
|
62
|
+
prompts,
|
|
63
|
+
new Set(trace.events.map((e) => e.branchId)),
|
|
64
|
+
prompts.length,
|
|
65
|
+
{ label: "subagent run", reason: "the subagent recorded no work" }
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
function slice(trace, from, prompts, own, sessionTurnCount, words) {
|
|
69
|
+
const to = trace.events.length - 1;
|
|
70
|
+
const worked = trace.events.some((e) => e.index > from && WORK.has(e.kind));
|
|
71
|
+
if (!worked) {
|
|
72
|
+
return {
|
|
73
|
+
window: emptyWindow("turn", words.label, words.reason),
|
|
74
|
+
from,
|
|
75
|
+
to,
|
|
76
|
+
sessionTurnCount
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const window = materialize(
|
|
80
|
+
trace,
|
|
81
|
+
"turn",
|
|
82
|
+
words.label,
|
|
83
|
+
[{ start: from, end: Number.POSITIVE_INFINITY }],
|
|
84
|
+
void 0,
|
|
85
|
+
own
|
|
86
|
+
);
|
|
87
|
+
window.userMessages = prompts.map((p) => p.text ?? "");
|
|
88
|
+
window.turnCount = sessionTurnCount;
|
|
89
|
+
return { window, from, to, sessionTurnCount };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/tracevals/rules/sources.ts
|
|
93
|
+
import { createHash } from "node:crypto";
|
|
94
|
+
import { homedir } from "node:os";
|
|
95
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
96
|
+
import picomatch from "picomatch";
|
|
97
|
+
var MAX_IMPORT_HOPS = 4;
|
|
98
|
+
var Collector = class {
|
|
99
|
+
constructor(cwd, root, home, exclude) {
|
|
100
|
+
this.cwd = cwd;
|
|
101
|
+
this.root = root;
|
|
102
|
+
this.home = home;
|
|
103
|
+
const match = exclude.length > 0 ? picomatch(exclude, { dot: true }) : null;
|
|
104
|
+
this.excluded = (path) => match !== null && match(this.display(path));
|
|
105
|
+
}
|
|
106
|
+
cwd;
|
|
107
|
+
root;
|
|
108
|
+
home;
|
|
109
|
+
sources = [];
|
|
110
|
+
warnings = [];
|
|
111
|
+
seen = /* @__PURE__ */ new Set();
|
|
112
|
+
parsed = /* @__PURE__ */ new Map();
|
|
113
|
+
excluded;
|
|
114
|
+
display(path) {
|
|
115
|
+
const inRoot = relPosix(this.root, path);
|
|
116
|
+
if (inRoot !== null) return inRoot;
|
|
117
|
+
const inHome = relPosix(this.home, path);
|
|
118
|
+
if (inHome !== null) return `~/${inHome}`;
|
|
119
|
+
return path.split(sep).join("/");
|
|
120
|
+
}
|
|
121
|
+
has(path) {
|
|
122
|
+
return this.seen.has(key(path));
|
|
123
|
+
}
|
|
124
|
+
/** The file's front matter, or null when it has none or it does not parse. */
|
|
125
|
+
front(path, content) {
|
|
126
|
+
const k = key(path);
|
|
127
|
+
if (this.parsed.has(k)) return this.parsed.get(k) ?? null;
|
|
128
|
+
let parsed = null;
|
|
129
|
+
try {
|
|
130
|
+
const fm = extractFrontmatter(content, "markdown");
|
|
131
|
+
parsed = fm.present ? fm : null;
|
|
132
|
+
} catch (err) {
|
|
133
|
+
const loose = isCursorRule(path) ? cursorFront(content) : null;
|
|
134
|
+
if (loose !== null) {
|
|
135
|
+
this.parsed.set(k, loose);
|
|
136
|
+
return loose;
|
|
137
|
+
}
|
|
138
|
+
const first = (err instanceof Error ? err.message : String(err)).split("\n")[0] ?? "";
|
|
139
|
+
this.warnings.push(
|
|
140
|
+
`${this.display(path)}: front matter does not parse (${first}), so it is read as having none`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
this.parsed.set(k, parsed);
|
|
144
|
+
return parsed;
|
|
145
|
+
}
|
|
146
|
+
/** Adds a source once. Returns it, or null when excluded or already listed. */
|
|
147
|
+
add(path, content, format, trigger, skill) {
|
|
148
|
+
if (this.has(path) || this.excluded(path)) return null;
|
|
149
|
+
this.seen.add(key(path));
|
|
150
|
+
const source = {
|
|
151
|
+
path,
|
|
152
|
+
displayPath: this.display(path),
|
|
153
|
+
format,
|
|
154
|
+
trigger,
|
|
155
|
+
content,
|
|
156
|
+
sha256: createHash("sha256").update(content).digest("hex")
|
|
157
|
+
};
|
|
158
|
+
if (skill !== void 0) source.skill = skill;
|
|
159
|
+
const declared = this.declared(path, content);
|
|
160
|
+
if (declared !== void 0) source.declaredRules = declared;
|
|
161
|
+
this.sources.push(source);
|
|
162
|
+
return source;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Adds a source that says what the session was asked. These never declare
|
|
166
|
+
* evals. With no file, its display path is its format, and no glob removes it.
|
|
167
|
+
*/
|
|
168
|
+
addRequest(file, content, format, trigger) {
|
|
169
|
+
if (file !== null) {
|
|
170
|
+
if (this.has(file) || this.excluded(file)) return;
|
|
171
|
+
this.seen.add(key(file));
|
|
172
|
+
}
|
|
173
|
+
this.sources.push({
|
|
174
|
+
path: file ?? "",
|
|
175
|
+
displayPath: file === null ? format : this.display(file),
|
|
176
|
+
format,
|
|
177
|
+
trigger,
|
|
178
|
+
content,
|
|
179
|
+
sha256: createHash("sha256").update(content).digest("hex")
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
declared(path, content) {
|
|
183
|
+
const fm = this.front(path, content);
|
|
184
|
+
if (fm === null) return void 0;
|
|
185
|
+
const extracted = extractEvals(
|
|
186
|
+
{ name: basename(path), type: "project-rules", path, content, origin: "project" },
|
|
187
|
+
fm
|
|
188
|
+
);
|
|
189
|
+
if (extracted.errors.length > 0) {
|
|
190
|
+
this.warnings.push(
|
|
191
|
+
`${this.display(path)}: metadata.evals does not validate (${extracted.errors[0]?.message ?? "invalid"}), so it declares no rules`
|
|
192
|
+
);
|
|
193
|
+
return void 0;
|
|
194
|
+
}
|
|
195
|
+
const rules = [];
|
|
196
|
+
for (const entry of extracted.evals) {
|
|
197
|
+
if (entry.grader !== "ai" || entry.assertion === void 0) continue;
|
|
198
|
+
const rule = { id: entry.id, text: entry.assertion };
|
|
199
|
+
const when = entry.options?.when;
|
|
200
|
+
if (isRecord(when)) rule.when = when;
|
|
201
|
+
rules.push(rule);
|
|
202
|
+
}
|
|
203
|
+
return rules.length > 0 ? rules : void 0;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
async function resolveAlwaysSources(opts) {
|
|
207
|
+
const c = await collector(opts);
|
|
208
|
+
for (const candidate of await catalog(c, opts)) {
|
|
209
|
+
if (candidate.trigger.kind === "always") await addWithImports(c, candidate, "always");
|
|
210
|
+
}
|
|
211
|
+
await addDesignated(c, opts);
|
|
212
|
+
return { sources: c.sources, warnings: c.warnings };
|
|
213
|
+
}
|
|
214
|
+
async function resolveTurnSources(trace, turn, opts) {
|
|
215
|
+
const c = await collector(opts);
|
|
216
|
+
const touches = trace.fileAccesses.filter((a) => a.index <= turn.to).map((a) => {
|
|
217
|
+
const abs = resolve(c.cwd, a.path);
|
|
218
|
+
return { abs, rel: relPosix(c.root, abs), read: a.op === "read" };
|
|
219
|
+
});
|
|
220
|
+
const wasRead = new Set(touches.filter((t) => t.read).map((t) => key(t.abs)));
|
|
221
|
+
for (const candidate of await catalog(c, opts)) {
|
|
222
|
+
const { trigger } = candidate;
|
|
223
|
+
if (trigger.kind === "always") {
|
|
224
|
+
await addWithImports(c, candidate, "always");
|
|
225
|
+
} else if (trigger.kind === "read") {
|
|
226
|
+
if (wasRead.has(key(candidate.path))) await addWithImports(c, candidate, "read");
|
|
227
|
+
} else {
|
|
228
|
+
const match = picomatch(trigger.patterns, { dot: true });
|
|
229
|
+
const hit = touches.find((t) => t.rel !== null && match(t.rel));
|
|
230
|
+
if (hit !== void 0 && hit.rel !== null) {
|
|
231
|
+
await addWithImports(c, candidate, `${trigger.key} matched ${hit.rel}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const nested = /* @__PURE__ */ new Map();
|
|
236
|
+
for (const touch of touches) {
|
|
237
|
+
if (touch.rel === null) continue;
|
|
238
|
+
for (const dir of dirsBelowCwd(c, dirname(touch.abs))) {
|
|
239
|
+
if (!nested.has(dir)) nested.set(dir, touch.rel);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const dirs = [...nested.keys()].sort((a, b) => a.length - b.length);
|
|
243
|
+
for (const dir of dirs) {
|
|
244
|
+
const touched = nested.get(dir) ?? "";
|
|
245
|
+
for (const [name, format] of NESTED_FILES) {
|
|
246
|
+
const path = join(dir, name);
|
|
247
|
+
const content = await safeRead(path);
|
|
248
|
+
if (content !== null) {
|
|
249
|
+
await addWithImports(c, { path, format, trigger: { kind: "always" } }, `touched ${touched}`, content);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
await addWindowed(c, trace, turn, touches, opts);
|
|
254
|
+
await addDesignated(c, opts);
|
|
255
|
+
addPrompts(c, trace, turn);
|
|
256
|
+
await addPlan(c, trace, turn, opts);
|
|
257
|
+
await addSpecs(c, touches, opts.plans ?? []);
|
|
258
|
+
return { sources: c.sources, warnings: c.warnings };
|
|
259
|
+
}
|
|
260
|
+
function addPrompts(c, trace, turn) {
|
|
261
|
+
const typed = trace.events.filter((e) => e.index <= turn.to && isTypedPrompt(e));
|
|
262
|
+
const main = typed.filter((e) => e.sidechain !== true);
|
|
263
|
+
const prompts = main.length > 0 ? main : typed;
|
|
264
|
+
if (prompts.length === 0) return;
|
|
265
|
+
const content = prompts.map((p, i) => `${String(i + 1)}. ${(p.text ?? "").trim()}`).join("\n\n");
|
|
266
|
+
c.addRequest(null, content, "prompt", `typed prompts 1-${String(prompts.length)}`);
|
|
267
|
+
}
|
|
268
|
+
async function addPlan(c, trace, turn, opts) {
|
|
269
|
+
const approved = trace.toolCalls.filter((call) => call.name === "ExitPlanMode" && call.index <= turn.to).filter((call) => isApproved(trace, call.index, turn.to)).at(-1);
|
|
270
|
+
if (approved === void 0) return;
|
|
271
|
+
const trigger = `approved at turn ${String(approved.index)}`;
|
|
272
|
+
const plan = approved.input.plan;
|
|
273
|
+
if (typeof plan === "string" && plan.trim() !== "") {
|
|
274
|
+
c.addRequest(null, plan, "plan", trigger);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const plansDir = join(configDir(opts.env), "plans");
|
|
278
|
+
const file = trace.fileAccesses.filter((a) => a.op !== "read" && a.index < approved.index).map((a) => resolve(c.cwd, a.path)).filter((abs) => relPosix(plansDir, abs) !== null).at(-1);
|
|
279
|
+
if (file === void 0) return;
|
|
280
|
+
const content = await safeRead(file);
|
|
281
|
+
if (content !== null) c.addRequest(file, content, "plan", trigger);
|
|
282
|
+
}
|
|
283
|
+
function isApproved(trace, index, to) {
|
|
284
|
+
const id = trace.events.find((e) => e.index === index)?.raw.id;
|
|
285
|
+
if (typeof id !== "string") return false;
|
|
286
|
+
for (const event of trace.events) {
|
|
287
|
+
if (event.kind !== "tool_result" || event.index <= index || event.index > to) continue;
|
|
288
|
+
const message = event.raw.message;
|
|
289
|
+
const blocks = isRecord(message) ? message.content : void 0;
|
|
290
|
+
if (!Array.isArray(blocks)) continue;
|
|
291
|
+
for (const block of blocks) {
|
|
292
|
+
if (isRecord(block) && block.type === "tool_result" && block.tool_use_id === id) {
|
|
293
|
+
return block.is_error !== true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
var SPEC_FILES = {
|
|
300
|
+
"speckit-spec": ["spec.md", "plan.md", "tasks.md"],
|
|
301
|
+
"kiro-spec": ["requirements.md", "design.md", "tasks.md"]
|
|
302
|
+
};
|
|
303
|
+
function specDirOf(rel) {
|
|
304
|
+
const parts = rel.split("/");
|
|
305
|
+
const [first, second, third] = parts;
|
|
306
|
+
if (first === "specs" && second !== void 0 && parts.length > 2) {
|
|
307
|
+
return { dir: `specs/${second}`, format: "speckit-spec" };
|
|
308
|
+
}
|
|
309
|
+
if (first === ".kiro" && second === "specs" && third !== void 0 && parts.length > 3) {
|
|
310
|
+
return { dir: `.kiro/specs/${third}`, format: "kiro-spec" };
|
|
311
|
+
}
|
|
312
|
+
if (first === "openspec" && second === "changes" && third !== void 0 && third !== "archive" && parts.length > 3) {
|
|
313
|
+
return { dir: `openspec/changes/${third}`, format: "openspec-change" };
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
async function addSpecs(c, touches, plans) {
|
|
318
|
+
const isPlan = plans.length > 0 ? picomatch(plans, { dot: true }) : null;
|
|
319
|
+
const done = /* @__PURE__ */ new Set();
|
|
320
|
+
for (const touch of touches) {
|
|
321
|
+
const { rel } = touch;
|
|
322
|
+
if (rel === null) continue;
|
|
323
|
+
const trigger = `touched ${rel}`;
|
|
324
|
+
const spec = specDirOf(rel);
|
|
325
|
+
if (spec !== null && !done.has(spec.dir)) {
|
|
326
|
+
done.add(spec.dir);
|
|
327
|
+
const dir = join(c.root, ...spec.dir.split("/"));
|
|
328
|
+
const files = spec.format === "openspec-change" ? await listInTree(dir, (p) => p.endsWith(".md")) : SPEC_FILES[spec.format].map((name) => join(dir, name));
|
|
329
|
+
for (const file of files) {
|
|
330
|
+
const content = await safeRead(file);
|
|
331
|
+
if (content !== null) c.addRequest(file, content, spec.format, trigger);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (isPlan?.(rel) === true) {
|
|
335
|
+
const content = await safeRead(touch.abs);
|
|
336
|
+
if (content !== null) c.addRequest(touch.abs, content, "plans", trigger);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function addDesignated(c, opts) {
|
|
341
|
+
const include = opts.include ?? [];
|
|
342
|
+
if (include.length === 0) return;
|
|
343
|
+
const match = picomatch(include, { dot: true });
|
|
344
|
+
const found = await listInTree(c.root, (abs) => {
|
|
345
|
+
const rel = relPosix(c.root, abs);
|
|
346
|
+
return rel !== null && match(rel);
|
|
347
|
+
});
|
|
348
|
+
for (const abs of found) {
|
|
349
|
+
if (c.has(abs)) continue;
|
|
350
|
+
const content = await safeRead(abs);
|
|
351
|
+
if (content === null) {
|
|
352
|
+
c.warnings.push(`${c.display(abs)}: matched conformance.include but could not be read`);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
c.add(abs, content, "designated", "always");
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
async function addWindowed(c, trace, turn, touches, opts) {
|
|
359
|
+
const { artifacts } = await resolveArtifacts(
|
|
360
|
+
{
|
|
361
|
+
...trace,
|
|
362
|
+
agentSpawns: opts.agentType === void 0 ? [] : [{ subagentType: opts.agentType, index: 0 }]
|
|
363
|
+
},
|
|
364
|
+
{ projectDir: c.cwd, projectRoot: c.root, ...opts.env ? { env: opts.env } : {} }
|
|
365
|
+
);
|
|
366
|
+
for (const artifact of artifacts) {
|
|
367
|
+
if (artifact.type === "agent") {
|
|
368
|
+
c.add(artifact.path, artifact.content, "agent", "subagent run");
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (artifact.type !== "skill" && artifact.type !== "slash-command") continue;
|
|
372
|
+
const window = windowOf(trace, artifact);
|
|
373
|
+
if (!window.events.some((e) => e.index <= turn.to)) continue;
|
|
374
|
+
if (artifact.type === "slash-command") {
|
|
375
|
+
c.add(artifact.path, artifact.content, "slash-command", "slash command window");
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
c.add(artifact.path, artifact.content, "skill", "skill window", artifact.name);
|
|
379
|
+
const skillDir = dirname(artifact.path);
|
|
380
|
+
for (const touch of touches) {
|
|
381
|
+
if (!touch.read || relPosix(skillDir, touch.abs) === null || c.has(touch.abs)) continue;
|
|
382
|
+
const content = await safeRead(touch.abs);
|
|
383
|
+
if (content !== null) {
|
|
384
|
+
c.add(touch.abs, content, "skill", `read under skill ${artifact.name}`, artifact.name);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
var ANCESTOR_FILES = [
|
|
390
|
+
["CLAUDE.md", "claude-md"],
|
|
391
|
+
["CLAUDE.local.md", "claude-md"],
|
|
392
|
+
[join(".claude", "CLAUDE.md"), "claude-md"],
|
|
393
|
+
["AGENTS.md", "agents-md"],
|
|
394
|
+
[join(".claude", "AGENTS.md"), "agents-md"],
|
|
395
|
+
["GEMINI.md", "gemini-md"]
|
|
396
|
+
];
|
|
397
|
+
var NESTED_FILES = [
|
|
398
|
+
["CLAUDE.md", "claude-md"],
|
|
399
|
+
["AGENTS.md", "agents-md"],
|
|
400
|
+
["GEMINI.md", "gemini-md"]
|
|
401
|
+
];
|
|
402
|
+
async function catalog(c, opts) {
|
|
403
|
+
const out = [];
|
|
404
|
+
const userClaude = configDir(opts.env);
|
|
405
|
+
const always = { kind: "always" };
|
|
406
|
+
out.push({ path: join(userClaude, "CLAUDE.md"), format: "claude-md", trigger: always });
|
|
407
|
+
out.push({ path: join(c.home, ".gemini", "GEMINI.md"), format: "gemini-md", trigger: always });
|
|
408
|
+
for (const dir of ancestors(c.cwd, c.root).reverse()) {
|
|
409
|
+
for (const [name, format] of ANCESTOR_FILES) {
|
|
410
|
+
out.push({ path: join(dir, name), format, trigger: always });
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const bases = c.cwd === c.root ? [c.root] : [c.root, c.cwd];
|
|
414
|
+
for (const dir of [join(userClaude, "rules"), ...bases.map((b) => join(b, ".claude", "rules"))]) {
|
|
415
|
+
for (const path of await listInTree(dir, (p) => p.endsWith(".md"))) {
|
|
416
|
+
out.push({ path, format: "claude-rule", trigger: await claudeRuleTrigger(c, path) });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
for (const base of bases) {
|
|
420
|
+
const dir = join(base, ".cursor", "rules");
|
|
421
|
+
for (const path of await listInTree(dir, (p) => p.endsWith(".mdc") || p.endsWith(".md"))) {
|
|
422
|
+
const trigger = await cursorTrigger(c, path);
|
|
423
|
+
if (trigger !== null) out.push({ path, format: "cursor-rule", trigger });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
for (const dir of [join(c.home, ".kiro", "steering"), ...bases.map((b) => join(b, ".kiro", "steering"))]) {
|
|
427
|
+
for (const path of await listInTree(dir, (p) => p.endsWith(".md"), { maxDepth: 0 })) {
|
|
428
|
+
out.push({ path, format: "kiro-steering", trigger: await kiroTrigger(c, path) });
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
for (const base of bases) {
|
|
432
|
+
out.push({
|
|
433
|
+
path: join(base, ".specify", "memory", "constitution.md"),
|
|
434
|
+
format: "speckit-constitution",
|
|
435
|
+
trigger: always
|
|
436
|
+
});
|
|
437
|
+
out.push({ path: join(base, "openspec", "project.md"), format: "openspec-project", trigger: { kind: "read" } });
|
|
438
|
+
}
|
|
439
|
+
return out;
|
|
440
|
+
}
|
|
441
|
+
async function frontOf(c, path) {
|
|
442
|
+
const content = await safeRead(path);
|
|
443
|
+
if (content === null) return null;
|
|
444
|
+
return c.front(path, content)?.data ?? null;
|
|
445
|
+
}
|
|
446
|
+
async function claudeRuleTrigger(c, path) {
|
|
447
|
+
const patterns = globList((await frontOf(c, path))?.paths);
|
|
448
|
+
return patterns.length > 0 ? { kind: "globs", key: "paths", patterns } : { kind: "always" };
|
|
449
|
+
}
|
|
450
|
+
async function cursorTrigger(c, path) {
|
|
451
|
+
const fm = await frontOf(c, path);
|
|
452
|
+
if (fm === null && !path.endsWith(".mdc")) return null;
|
|
453
|
+
if (fm?.alwaysApply === true) return { kind: "always" };
|
|
454
|
+
const patterns = globList(fm?.globs);
|
|
455
|
+
return patterns.length > 0 ? { kind: "globs", key: "globs", patterns } : { kind: "read" };
|
|
456
|
+
}
|
|
457
|
+
async function kiroTrigger(c, path) {
|
|
458
|
+
const fm = await frontOf(c, path);
|
|
459
|
+
const inclusion = fm?.inclusion;
|
|
460
|
+
if (inclusion === void 0 || inclusion === "always") return { kind: "always" };
|
|
461
|
+
if (inclusion === "fileMatch") {
|
|
462
|
+
const patterns = globList(fm?.fileMatchPattern);
|
|
463
|
+
if (patterns.length > 0) return { kind: "globs", key: "fileMatchPattern", patterns };
|
|
464
|
+
}
|
|
465
|
+
return { kind: "read" };
|
|
466
|
+
}
|
|
467
|
+
async function addWithImports(c, candidate, trigger, known) {
|
|
468
|
+
if (c.has(candidate.path)) return;
|
|
469
|
+
const content = known ?? await safeRead(candidate.path);
|
|
470
|
+
if (content === null) return;
|
|
471
|
+
const added = c.add(candidate.path, content, candidate.format, trigger);
|
|
472
|
+
if (added === null || candidate.format !== "claude-md" && candidate.format !== "gemini-md") {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
let frontier = [added];
|
|
476
|
+
for (let hop = 1; hop <= MAX_IMPORT_HOPS && frontier.length > 0; hop += 1) {
|
|
477
|
+
const next = [];
|
|
478
|
+
for (const importer of frontier) {
|
|
479
|
+
for (const ref of importsOf(importer.content)) {
|
|
480
|
+
const path = ref.startsWith("~/") ? join(c.home, ref.slice(2)) : resolve(dirname(importer.path), ref);
|
|
481
|
+
if (c.has(path)) continue;
|
|
482
|
+
const body = await safeRead(path);
|
|
483
|
+
if (body === null) continue;
|
|
484
|
+
const source = c.add(path, body, "import", `imported by ${importer.displayPath}`);
|
|
485
|
+
if (source !== null) next.push(source);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
frontier = next;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function importsOf(content) {
|
|
492
|
+
const refs = [];
|
|
493
|
+
let fence = null;
|
|
494
|
+
for (const line of content.split(/\r?\n/)) {
|
|
495
|
+
const marker = /^\s*(`{3,}|~{3,})/.exec(line)?.[1];
|
|
496
|
+
if (marker !== void 0) {
|
|
497
|
+
const char = marker.charAt(0);
|
|
498
|
+
if (fence === null) {
|
|
499
|
+
fence = { char, length: marker.length };
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
if (char === fence.char && marker.length >= fence.length && line.trim() === marker) {
|
|
503
|
+
fence = null;
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (fence !== null) continue;
|
|
508
|
+
const prose = line.replace(/`[^`]*`/g, "");
|
|
509
|
+
for (const m of prose.matchAll(/(?:^|\s)@([^\s`]+)/g)) {
|
|
510
|
+
const ref = m[1]?.replace(/[.,;:!?)\]]+$/, "");
|
|
511
|
+
if (ref) refs.push(ref);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return refs;
|
|
515
|
+
}
|
|
516
|
+
async function collector(opts) {
|
|
517
|
+
const cwd = resolve(opts.projectDir);
|
|
518
|
+
const root = resolve(opts.projectRoot ?? await findGitRoot(cwd) ?? cwd);
|
|
519
|
+
return new Collector(cwd, root, homeDir(opts.env), opts.exclude ?? []);
|
|
520
|
+
}
|
|
521
|
+
function homeDir(env = process.env) {
|
|
522
|
+
const set = process.platform === "win32" ? env.USERPROFILE ?? env.HOME : env.HOME;
|
|
523
|
+
return resolve(set ?? homedir());
|
|
524
|
+
}
|
|
525
|
+
function ancestors(cwd, root) {
|
|
526
|
+
const dirs = [];
|
|
527
|
+
let current = cwd;
|
|
528
|
+
for (let depth = 0; depth < 32; depth += 1) {
|
|
529
|
+
dirs.push(current);
|
|
530
|
+
if (current === root) break;
|
|
531
|
+
const parent = dirname(current);
|
|
532
|
+
if (parent === current) break;
|
|
533
|
+
current = parent;
|
|
534
|
+
}
|
|
535
|
+
return dirs;
|
|
536
|
+
}
|
|
537
|
+
function dirsBelowCwd(c, dir) {
|
|
538
|
+
const dirs = [];
|
|
539
|
+
let current = dir;
|
|
540
|
+
for (let depth = 0; depth < 64; depth += 1) {
|
|
541
|
+
if (relPosix(c.root, current) === null || relPosix(current, c.cwd) !== null) break;
|
|
542
|
+
dirs.push(current);
|
|
543
|
+
const parent = dirname(current);
|
|
544
|
+
if (parent === current) break;
|
|
545
|
+
current = parent;
|
|
546
|
+
}
|
|
547
|
+
return dirs;
|
|
548
|
+
}
|
|
549
|
+
function isCursorRule(path) {
|
|
550
|
+
return path.split(sep).join("/").includes("/.cursor/rules/");
|
|
551
|
+
}
|
|
552
|
+
function cursorFront(content) {
|
|
553
|
+
const block = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(content)?.[1];
|
|
554
|
+
if (block === void 0) return null;
|
|
555
|
+
const data = {};
|
|
556
|
+
for (const line of block.split(/\r?\n/)) {
|
|
557
|
+
const m = /^(description|globs|alwaysApply):\s*(.*)$/.exec(line);
|
|
558
|
+
const name = m?.[1];
|
|
559
|
+
const value = m?.[2]?.trim();
|
|
560
|
+
if (name === void 0 || value === void 0) continue;
|
|
561
|
+
data[name] = name === "alwaysApply" ? value === "true" : value;
|
|
562
|
+
}
|
|
563
|
+
if (Object.keys(data).length === 0) return null;
|
|
564
|
+
return { data, present: true, format: "markdown", lineFor: () => void 0 };
|
|
565
|
+
}
|
|
566
|
+
function globList(value) {
|
|
567
|
+
if (Array.isArray(value)) {
|
|
568
|
+
return value.filter((v) => typeof v === "string" && v.trim() !== "").map((v) => v.trim());
|
|
569
|
+
}
|
|
570
|
+
if (typeof value !== "string") return [];
|
|
571
|
+
const out = [];
|
|
572
|
+
let depth = 0;
|
|
573
|
+
let current = "";
|
|
574
|
+
for (const ch of value) {
|
|
575
|
+
if (ch === "{") depth += 1;
|
|
576
|
+
if (ch === "}") depth = Math.max(0, depth - 1);
|
|
577
|
+
if (ch === "," && depth === 0) {
|
|
578
|
+
out.push(current);
|
|
579
|
+
current = "";
|
|
580
|
+
} else {
|
|
581
|
+
current += ch;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
out.push(current);
|
|
585
|
+
return out.map((p) => p.trim()).filter((p) => p !== "");
|
|
586
|
+
}
|
|
587
|
+
function relPosix(base, path) {
|
|
588
|
+
const rel = relative(base, path);
|
|
589
|
+
if (rel === "") return "";
|
|
590
|
+
if (rel.startsWith("..") || isAbsolute(rel)) return null;
|
|
591
|
+
return rel.split(sep).join("/");
|
|
592
|
+
}
|
|
593
|
+
function key(path) {
|
|
594
|
+
const abs = resolve(path);
|
|
595
|
+
return process.platform === "win32" ? abs.toLowerCase() : abs;
|
|
596
|
+
}
|
|
597
|
+
var pathKey = key;
|
|
598
|
+
function isRecord(value) {
|
|
599
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export {
|
|
603
|
+
isTypedPrompt,
|
|
604
|
+
lastTurn,
|
|
605
|
+
subagentTurn,
|
|
606
|
+
resolveAlwaysSources,
|
|
607
|
+
resolveTurnSources,
|
|
608
|
+
pathKey
|
|
609
|
+
};
|
|
610
|
+
//# sourceMappingURL=chunk-YLK2J5YK.js.map
|