@deftai/directive-core 0.98.1 → 0.99.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/dist/authz/classify.js +265 -73
- package/dist/consumer-check-contract/evaluate.d.ts +40 -0
- package/dist/consumer-check-contract/evaluate.js +188 -3
- package/dist/consumer-check-contract/index.d.ts +1 -1
- package/dist/consumer-check-contract/index.js +1 -1
- package/dist/content-contracts/skills/greptile-detector.d.ts +42 -0
- package/dist/content-contracts/skills/greptile-detector.js +202 -4
- package/dist/decision/index.d.ts +17 -0
- package/dist/decision/index.js +35 -0
- package/dist/decision/list.d.ts +47 -0
- package/dist/decision/list.js +250 -0
- package/dist/decision/schema.d.ts +88 -0
- package/dist/decision/schema.js +293 -0
- package/dist/decision/write.d.ts +82 -0
- package/dist/decision/write.js +427 -0
- package/dist/eval/report.d.ts +29 -0
- package/dist/eval/report.js +69 -0
- package/dist/eval/run.d.ts +9 -0
- package/dist/eval/run.js +40 -4
- package/dist/eval/version-pin.d.ts +99 -0
- package/dist/eval/version-pin.js +181 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/platform/host-content-surface.d.ts +74 -0
- package/dist/platform/host-content-surface.js +214 -0
- package/dist/platform/index.d.ts +1 -0
- package/dist/platform/index.js +1 -0
- package/dist/policy/ceremony-dial.d.ts +233 -0
- package/dist/policy/ceremony-dial.js +829 -0
- package/dist/policy/deft-directive-disable.js +12 -2
- package/dist/policy/index.d.ts +1 -0
- package/dist/policy/index.js +15 -1
- package/dist/pr-merge-readiness/evaluate.js +10 -0
- package/dist/pr-merge-readiness/mergeability.js +5 -0
- package/dist/pr-merge-readiness/output.js +2 -0
- package/dist/pr-merge-readiness/parse.js +4 -0
- package/dist/pr-merge-readiness/types.d.ts +6 -0
- package/dist/scope/effort-activate-gate.d.ts +28 -0
- package/dist/scope/effort-activate-gate.js +64 -0
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/transition.js +8 -0
- package/dist/session/session-start.d.ts +24 -1
- package/dist/session/session-start.js +183 -26
- package/dist/swarm/index.d.ts +2 -0
- package/dist/swarm/index.js +2 -0
- package/dist/swarm/pre-dispatch-cli.d.ts +19 -0
- package/dist/swarm/pre-dispatch-cli.js +143 -0
- package/dist/swarm/pre-dispatch.d.ts +87 -0
- package/dist/swarm/pre-dispatch.js +373 -0
- package/dist/vbrief-activate/activate.js +6 -0
- package/dist/vbrief-validate/constants.d.ts +2 -0
- package/dist/vbrief-validate/constants.js +2 -0
- package/dist/vbrief-validate/schema.js +4 -1
- package/package.json +15 -3
|
@@ -17,6 +17,157 @@ export const REQUIRED_CONSUMER_ENFORCEMENT_GATES = [
|
|
|
17
17
|
"verify:scope-provenance",
|
|
18
18
|
"verify:consumer-check-contract",
|
|
19
19
|
];
|
|
20
|
+
/**
|
|
21
|
+
* Relative path forms accepted for the deft-install canonical Taskfile include
|
|
22
|
+
* (init-deposit `MINIMAL_TASKFILE` / `CANONICAL_TASKFILE_INCLUDE`).
|
|
23
|
+
* Use only as a path-value matcher — never as a whole-file text search (Greptile P1 #3218).
|
|
24
|
+
*/
|
|
25
|
+
export const CANONICAL_DEFT_TASKFILE_PATH_RE = /^(?:\.\.?\/)?\.deft\/core\/Taskfile\.yml$/i;
|
|
26
|
+
/** `taskfile: ./.deft/core/Taskfile.yml` under an includes: child (object form). */
|
|
27
|
+
const INCLUDE_TASKFILE_KEY_RE = /^taskfile:\s*['"]?((?:\.\.?\/)?\.deft\/core\/Taskfile\.yml)['"]?\s*(?:#.*)?$/i;
|
|
28
|
+
/**
|
|
29
|
+
* Short form under includes: — **must** be namespace `deft` so `task deft:check`
|
|
30
|
+
* remains the documented greenfield entrypoint (Greptile conf residual #3218).
|
|
31
|
+
*/
|
|
32
|
+
const INCLUDE_DEFT_SHORT_FORM_RE = /^deft:\s*['"]?((?:\.\.?\/)?\.deft\/core\/Taskfile\.yml)['"]?\s*(?:#.*)?$/i;
|
|
33
|
+
/** Object-form entry start for the `deft` namespace only. */
|
|
34
|
+
const INCLUDE_DEFT_ENTRY_START_RE = /^deft\s*:\s*(?:#.*)?$/i;
|
|
35
|
+
/** @deprecated Prefer path/line parsers; kept for export stability. */
|
|
36
|
+
export const CANONICAL_DEFT_TASKFILE_INCLUDE_RE = INCLUDE_TASKFILE_KEY_RE;
|
|
37
|
+
/**
|
|
38
|
+
* Return the relative path of the canonical `.deft/core/Taskfile.yml` include when
|
|
39
|
+
* present as an **active, direct** go-task `includes:` entry; otherwise null.
|
|
40
|
+
*
|
|
41
|
+
* Greenfield `directive init` deposits an include-only Taskfile (#3218); composition
|
|
42
|
+
* lives in the included framework graph, not in root `check` deps.
|
|
43
|
+
*
|
|
44
|
+
* Greptile P1 (#3218):
|
|
45
|
+
* - Path text in comments / cmds / vars / non-include keys must not match.
|
|
46
|
+
* - Only **direct** include entries count: short form `deft: path` or object form
|
|
47
|
+
* `deft: { taskfile: path }` (immediate property). Nested
|
|
48
|
+
* `includes.some.nested.taskfile` is not an executable go-task include.
|
|
49
|
+
* - Namespace must be `deft` so the documented `task deft:check` entrypoint exists.
|
|
50
|
+
*/
|
|
51
|
+
export function resolveCanonicalDeftTaskfileInclude(rootTaskfileText) {
|
|
52
|
+
const lines = rootTaskfileText.replace(/\r\n/g, "\n").split("\n");
|
|
53
|
+
let inIncludes = false;
|
|
54
|
+
let includesIndent = 0;
|
|
55
|
+
/** Indent of direct children under `includes:` (include entry keys). */
|
|
56
|
+
let directChildIndent = null;
|
|
57
|
+
/** Indent of immediate properties under the current object-form include entry. */
|
|
58
|
+
let entryBodyIndent = null;
|
|
59
|
+
/** True while inside the body of the `deft:` include entry. */
|
|
60
|
+
let inDeftEntryBody = false;
|
|
61
|
+
for (const raw of lines) {
|
|
62
|
+
const stripped = raw.trim();
|
|
63
|
+
if (!stripped || stripped.startsWith("#"))
|
|
64
|
+
continue;
|
|
65
|
+
// Full-line list comment: - # ...
|
|
66
|
+
if (/^-\s+#/.test(stripped))
|
|
67
|
+
continue;
|
|
68
|
+
const indent = raw.length - raw.trimStart().length;
|
|
69
|
+
if (!inIncludes) {
|
|
70
|
+
// Top-level includes: only (indent 0 or document-level).
|
|
71
|
+
if (/^includes\s*:/.test(stripped) && indent <= 1) {
|
|
72
|
+
inIncludes = true;
|
|
73
|
+
includesIndent = indent;
|
|
74
|
+
directChildIndent = null;
|
|
75
|
+
entryBodyIndent = null;
|
|
76
|
+
inDeftEntryBody = false;
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Left the includes block: another key at the same or shallower indent.
|
|
81
|
+
if (indent <= includesIndent && /^[\w.-]+\s*:/.test(stripped)) {
|
|
82
|
+
if (/^includes\s*:/.test(stripped)) {
|
|
83
|
+
includesIndent = indent;
|
|
84
|
+
directChildIndent = null;
|
|
85
|
+
entryBodyIndent = null;
|
|
86
|
+
inDeftEntryBody = false;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
inIncludes = false;
|
|
90
|
+
directChildIndent = null;
|
|
91
|
+
entryBodyIndent = null;
|
|
92
|
+
inDeftEntryBody = false;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (indent <= includesIndent)
|
|
96
|
+
continue;
|
|
97
|
+
if (directChildIndent === null) {
|
|
98
|
+
directChildIndent = indent;
|
|
99
|
+
}
|
|
100
|
+
// Direct include entry line (namespace key under includes:).
|
|
101
|
+
if (indent === directChildIndent) {
|
|
102
|
+
entryBodyIndent = null;
|
|
103
|
+
inDeftEntryBody = false;
|
|
104
|
+
const short = INCLUDE_DEFT_SHORT_FORM_RE.exec(stripped);
|
|
105
|
+
if (short?.[1] !== undefined && CANONICAL_DEFT_TASKFILE_PATH_RE.test(short[1])) {
|
|
106
|
+
return short[1].replace(/\\/g, "/");
|
|
107
|
+
}
|
|
108
|
+
// Object-form `deft:` entry — only this namespace exposes task deft:check.
|
|
109
|
+
if (INCLUDE_DEFT_ENTRY_START_RE.test(stripped)) {
|
|
110
|
+
inDeftEntryBody = true;
|
|
111
|
+
}
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// Nested under a direct include entry: only immediate props of `deft:` count.
|
|
115
|
+
if (indent > directChildIndent && inDeftEntryBody) {
|
|
116
|
+
if (entryBodyIndent === null) {
|
|
117
|
+
entryBodyIndent = indent;
|
|
118
|
+
}
|
|
119
|
+
// Deeper than one property level → not an executable include taskfile key.
|
|
120
|
+
if (indent !== entryBodyIndent)
|
|
121
|
+
continue;
|
|
122
|
+
const m = INCLUDE_TASKFILE_KEY_RE.exec(stripped);
|
|
123
|
+
if (m?.[1] !== undefined && CANONICAL_DEFT_TASKFILE_PATH_RE.test(m[1])) {
|
|
124
|
+
return m[1].replace(/\\/g, "/");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* True when a framework (included) Taskfile composes every required gate via
|
|
132
|
+
* `check` / `check:consumer` / `check:framework-source` deps or an orchestrator body,
|
|
133
|
+
* and `tasks/verify.yml` defines the local task keys.
|
|
134
|
+
*/
|
|
135
|
+
export function frameworkTaskfileComposesRequiredGates(frameworkTaskfileText, verifyTaskfileText, required = REQUIRED_CONSUMER_ENFORCEMENT_GATES) {
|
|
136
|
+
if (verifyTaskfileText === null || frameworkTaskfileText.trim().length === 0) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
for (const gateId of required) {
|
|
140
|
+
if (!gateId.startsWith("verify:"))
|
|
141
|
+
continue;
|
|
142
|
+
if (!taskDefinedInTaskfileYaml(verifyTaskfileText, gateId.slice("verify:".length))) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const checkTargets = ["check", "check:consumer", "check:framework-source"];
|
|
147
|
+
for (const target of checkTargets) {
|
|
148
|
+
const deps = extractCheckDeps(frameworkTaskfileText, target);
|
|
149
|
+
const body = extractTaskBody(frameworkTaskfileText, target);
|
|
150
|
+
const defined = deps.length > 0 || body.trim().length > 0;
|
|
151
|
+
if (!defined)
|
|
152
|
+
continue;
|
|
153
|
+
if (taskBodyInvokesCheckOrchestrator(body)) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
const allListed = required.every((gateId) => {
|
|
157
|
+
for (const d of deps) {
|
|
158
|
+
const name = d.trim();
|
|
159
|
+
if (name === gateId)
|
|
160
|
+
return true;
|
|
161
|
+
if (name === `task ${gateId}` || name === `task:${gateId}`)
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
});
|
|
166
|
+
if (allListed)
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
20
171
|
function readText(path) {
|
|
21
172
|
try {
|
|
22
173
|
if (!existsSync(path))
|
|
@@ -583,12 +734,46 @@ export function evaluateConsumerCheckContract(projectRoot, options = {}) {
|
|
|
583
734
|
}
|
|
584
735
|
}
|
|
585
736
|
}
|
|
737
|
+
// Include-only greenfield (#3218): root Taskfile from `directive init` only wires
|
|
738
|
+
// `includes.deft → ./.deft/core/Taskfile.yml`. Composition lives in the included
|
|
739
|
+
// framework Taskfile + tasks/verify.yml. Trust that graph when no local check
|
|
740
|
+
// aggregates are defined. A partial local check aggregate still fails closed —
|
|
741
|
+
// the include must not conceal incomplete root deps.
|
|
742
|
+
let includeComposes = false;
|
|
743
|
+
const includeRel = resolveCanonicalDeftTaskfileInclude(rootTaskfile);
|
|
744
|
+
if (includeRel !== null) {
|
|
745
|
+
let includedTf;
|
|
746
|
+
if (options.includedFrameworkTaskfileText !== undefined) {
|
|
747
|
+
includedTf = options.includedFrameworkTaskfileText;
|
|
748
|
+
}
|
|
749
|
+
else {
|
|
750
|
+
const absInclude = join(root, includeRel.replace(/^\.\//, ""));
|
|
751
|
+
includedTf = readText(absInclude);
|
|
752
|
+
}
|
|
753
|
+
let includedVerify;
|
|
754
|
+
if (options.includedVerifyTaskfileText !== undefined) {
|
|
755
|
+
includedVerify = options.includedVerifyTaskfileText;
|
|
756
|
+
}
|
|
757
|
+
else if (includedTf !== null) {
|
|
758
|
+
const includeDir = join(root, includeRel.replace(/^\.\//, "").replace(/[/\\]Taskfile\.yml$/i, ""));
|
|
759
|
+
includedVerify = readText(join(includeDir, "tasks", "verify.yml"));
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
includedVerify = null;
|
|
763
|
+
}
|
|
764
|
+
if (includedTf !== null) {
|
|
765
|
+
includeComposes = frameworkTaskfileComposesRequiredGates(includedTf, includedVerify, required);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
586
768
|
// No check aggregates defined at all — still a composition gap when enforce
|
|
587
|
-
// (unless trust via whole-file orchestrator
|
|
769
|
+
// (unless trust via whole-file orchestrator, or canonical deft include composition).
|
|
588
770
|
if (!anyAggregateDefined) {
|
|
589
|
-
// Preserve prior behavior for empty/missing check tasks: fail each required gate.
|
|
590
771
|
const invokesAny = taskfileInvokesCheckOrchestrator(rootTaskfile);
|
|
591
|
-
if (
|
|
772
|
+
if (includeComposes || (invokesAny && verifyDefinesRequired)) {
|
|
773
|
+
// Include-only greenfield or root orchestrator body — clean for check-task.
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
// Preserve prior behavior for empty/missing check tasks: fail each required gate.
|
|
592
777
|
for (const gateId of required) {
|
|
593
778
|
findings.push({
|
|
594
779
|
gateId,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* consumer-check-contract package surface (#3145).
|
|
3
3
|
*/
|
|
4
|
-
export { type ConsumerCheckContractFinding, type ConsumerCheckContractOptions, type ConsumerCheckContractResult, evaluateConsumerCheckContract, extractCheckDeps, REQUIRED_CONSUMER_ENFORCEMENT_GATES, requiredGatesFromConsumerList, taskfileInvokesCheckOrchestrator, textReferencesGate, workflowExecutesCheck, } from "./evaluate.js";
|
|
4
|
+
export { CANONICAL_DEFT_TASKFILE_INCLUDE_RE, CANONICAL_DEFT_TASKFILE_PATH_RE, type ConsumerCheckContractFinding, type ConsumerCheckContractOptions, type ConsumerCheckContractResult, evaluateConsumerCheckContract, extractCheckDeps, frameworkTaskfileComposesRequiredGates, REQUIRED_CONSUMER_ENFORCEMENT_GATES, requiredGatesFromConsumerList, resolveCanonicalDeftTaskfileInclude, taskfileInvokesCheckOrchestrator, textReferencesGate, workflowExecutesCheck, } from "./evaluate.js";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* consumer-check-contract package surface (#3145).
|
|
3
3
|
*/
|
|
4
|
-
export { evaluateConsumerCheckContract, extractCheckDeps, REQUIRED_CONSUMER_ENFORCEMENT_GATES, requiredGatesFromConsumerList, taskfileInvokesCheckOrchestrator, textReferencesGate, workflowExecutesCheck, } from "./evaluate.js";
|
|
4
|
+
export { CANONICAL_DEFT_TASKFILE_INCLUDE_RE, CANONICAL_DEFT_TASKFILE_PATH_RE, evaluateConsumerCheckContract, extractCheckDeps, frameworkTaskfileComposesRequiredGates, REQUIRED_CONSUMER_ENFORCEMENT_GATES, requiredGatesFromConsumerList, resolveCanonicalDeftTaskfileInclude, taskfileInvokesCheckOrchestrator, textReferencesGate, workflowExecutesCheck, } from "./evaluate.js";
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
@@ -12,11 +12,53 @@ interface DetectResult {
|
|
|
12
12
|
has_blocking: boolean;
|
|
13
13
|
}
|
|
14
14
|
export declare function parseConfidence(body: string): number | null;
|
|
15
|
+
/**
|
|
16
|
+
* Extract verdict-bearing text windows from a bot rolling-summary body (#3225).
|
|
17
|
+
* Prefers Confidence Score sections and Summary:/Decision: lines over whole-body
|
|
18
|
+
* Overview tables that may *describe* advisory phrases without issuing them.
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractAdvisoryVerdictRegions(body: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* True when comment body prose records an advisory should-not-merge / not-safe
|
|
23
|
+
* verdict (#3225). Code-fence regions are stripped first so detector docs do
|
|
24
|
+
* not self-trigger (#1004).
|
|
25
|
+
*
|
|
26
|
+
* Line-anchored hybrid scan (PR #3227 residuals):
|
|
27
|
+
* 1. Soft + high-signal **line-anchored** phrases in Confidence / Summary /
|
|
28
|
+
* Decision regions (and whole body)
|
|
29
|
+
* 2. Same line-anchored high-signal set on whole body (standalone warnings)
|
|
30
|
+
* Mid-sentence residual discussion does not hard-block; conf floor still does (#3095).
|
|
31
|
+
*/
|
|
32
|
+
export declare function hasShouldNotMergeProse(body: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Structured advisory verdict from bot comment body (#3225 / #1282 style).
|
|
35
|
+
* Confidence is independent of formal GitHub review state; compose with
|
|
36
|
+
* `minGreptileConfidence` (#3095) at the clean gate.
|
|
37
|
+
*/
|
|
38
|
+
export interface AdvisoryReviewerVerdict {
|
|
39
|
+
readonly confidence: number | null;
|
|
40
|
+
readonly shouldNotMerge: boolean;
|
|
41
|
+
readonly hasBlocking: boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare function parseAdvisoryReviewerVerdict(body: string): AdvisoryReviewerVerdict;
|
|
15
44
|
export declare function detect(body: string): DetectResult;
|
|
16
45
|
export declare function parseLastReviewedShaMarkdownLink(body: string): string | null;
|
|
17
46
|
export declare function parseLastReviewedShaNaiveInline(body: string): string | null;
|
|
18
47
|
export declare const BODY_TIER2_P1_ONLY = "Greptile review of head 1234567\n\nConfidence Score: 4/5\n\nLast reviewed commit: [fix: foo bar](https://github.com/deftai/directive/commit/abcdef1234567)\n\nComments:\n\n- **P1 -- wrong exception type for state/limit validation in populate()**\n The current code raises ValueError but the contract calls for InvalidRepoError.\n- **P2 -- minor wording in error message**\n Consider `--repo` instead of `the repo flag`.\n";
|
|
19
48
|
export declare const BODY_TIER3_NOT_SAFE_ONLY = "Greptile review of head 7654321\n\nConfidence Score: 3/5\n\nLast reviewed commit: [refactor: thing](https://github.com/deftai/directive/commit/0011223344556)\n\nSummary: Not safe to merge until the mocked-import test defect and the two\npreviously filed P1s are resolved.\n";
|
|
49
|
+
/** #3225 live-case shape: conf 3/5 + should-not-merge prose, zero badges. */
|
|
50
|
+
export declare const BODY_ADVISORY_SHOULD_NOT_MERGE_CONF3 = "Greptile review of head advisory01\n\n## Confidence Score: 3/5\n\nSummary: should-not-merge \u2014 residual risk on the auth path is too high for\nthis change set. Formal review state is still Comment (not Changes Requested).\n\nLast reviewed commit: [feat: advisory](https://github.com/deftai/directive/commit/advisory01abcdef12)\n";
|
|
51
|
+
/** Green mechanical path trap: high conf but explicit do-not-merge prose. */
|
|
52
|
+
export declare const BODY_ADVISORY_DO_NOT_MERGE_HIGH_CONF = "Greptile review of head advisory02\n\nConfidence Score: 5/5\n\nNo P0 or P1 issues found via badges.\n\nSummary: Do not merge until the operator documents residual risk.\n\nLast reviewed commit: [docs: note](https://github.com/deftai/directive/commit/advisory02abcdef12)\n";
|
|
53
|
+
/**
|
|
54
|
+
* Overview prose names the detector phrase without issuing a verdict (#3225 residual).
|
|
55
|
+
* Confidence section is clean — must NOT set shouldNotMerge.
|
|
56
|
+
*/
|
|
57
|
+
export declare const BODY_ADVISORY_DESCRIPTIVE_ONLY = "Greptile review of head advisory03\n\n<details><summary><h3>Greptile Summary</h3></summary>\n\nThis PR adds should-not-merge prose detection and Not safe to merge matching to\nmerge-ready. Descriptive overview only \u2014 no blocking residual on the product path.\n\n</details>\n\n<details open><summary><h3>Confidence Score: 5/5</h3></summary>\n\nNo P0 or P1 issues found. The change looks clean and well-tested.\n\n</details>\n\nLast reviewed commit: [feat: detector](https://github.com/deftai/directive/commit/advisory03abcdef12)\n";
|
|
58
|
+
/** Standalone high-signal warning outside Confidence section must still block. */
|
|
59
|
+
export declare const BODY_ADVISORY_STANDALONE_NOT_SAFE = "Greptile review of head advisory04\n\n<details open><summary><h3>Confidence Score: 5/5</h3></summary>\n\nLooks solid from a findings perspective.\n\n</details>\n\nNot safe to merge until the operator confirms residual risk handling.\n\nLast reviewed commit: [feat: residual](https://github.com/deftai/directive/commit/advisory04abcdef12)\n";
|
|
60
|
+
/** Subject-prefixed verdict Greptile commonly emits (#3225 residual). */
|
|
61
|
+
export declare const BODY_ADVISORY_SUBJECT_PREFIXED = "Greptile review of head advisory05\n\n## Confidence Score: 4/5\n\nThe PR is not safe to merge until residual risk is documented on the auth path.\n\nLast reviewed commit: [feat: subject](https://github.com/deftai/directive/commit/advisory05abcdef12)\n";
|
|
20
62
|
export declare const BODY_TIER3_COUNT_PROSE_ONLY = "Greptile review of head deadbeef\n\nConfidence Score: 4/5\n\nLast reviewed commit: [chore: bump](https://github.com/deftai/directive/commit/deadbeefcafe123)\n\nThree P1 findings (two from prior review, one new): wrong exception type for\nstate/limit validation in populate(), misleading skip message, and an\nunguarded import that will fail on Windows.\n";
|
|
21
63
|
export declare const BODY_NEGATION_GUARDED = "Greptile review of head ffffffff\n\nConfidence Score: 5/5\n\nLast reviewed commit: [feat: clean](https://github.com/deftai/directive/commit/ffffffffabc1234)\n\nSummary: No P0 findings. Zero P1 findings. The PR is ready for merge.\n";
|
|
22
64
|
export declare const BODY_CLEAN = "Greptile review of head 1111111\n\nConfidence Score: 5/5\n\nLast reviewed commit: [docs: tweak](https://github.com/deftai/directive/commit/1111111aaa2222b)\n\nNo P0 or P1 issues found. The change looks clean and well-tested.\n";
|
|
@@ -13,6 +13,38 @@ const TIER3_LINE_RE = /^\s*P[01]\s+--\s/gm;
|
|
|
13
13
|
const TIER3_NEGATIONS = ["No ", "Zero ", "no ", "NO "];
|
|
14
14
|
const CONFIDENCE_INLINE_RE = /Confidence Score:\s*(\d+)\s*\/\s*5/;
|
|
15
15
|
const CONFIDENCE_HEADING_RE = /^#{1,6}\s*Confidence Score:\s*(\d+)\s*\/\s*5\s*$/m;
|
|
16
|
+
/**
|
|
17
|
+
* Advisory should-not-merge prose (#3225) — reviewer bots often record a block
|
|
18
|
+
* only in comment body text without formal Changes-Requested. Patterns are
|
|
19
|
+
* applied after code-fence strip; case-insensitive. Composes with
|
|
20
|
+
* minGreptileConfidence (#3095): either signal alone is blocking.
|
|
21
|
+
*
|
|
22
|
+
* Matching is scoped to **verdict-bearing regions** (Confidence Score detail /
|
|
23
|
+
* heading sections, Summary:/Decision: lines) so descriptive overview prose
|
|
24
|
+
* that names the detector phrases ("adds should-not-merge parsing") does not
|
|
25
|
+
* false-block a clean review (Greptile residual on PR #3227 / #1004 class).
|
|
26
|
+
*/
|
|
27
|
+
const ADVISORY_SHOULD_NOT_MERGE_RES = [
|
|
28
|
+
// "not safe to merge" | "not yet safe to merge"
|
|
29
|
+
/\bnot\s+(?:yet\s+)?safe\s+to\s+merge\b/i,
|
|
30
|
+
// should-not-merge | should not merge | should–not–merge (hyphen optional each side)
|
|
31
|
+
/\bshould\s*[-–—]?\s*not\s*[-–—]?\s*merge\b/i,
|
|
32
|
+
/\bsafe\s+to\s+merge\s+once\s+corrected\b/i,
|
|
33
|
+
/\bdo\s+not\s+merge\b/i,
|
|
34
|
+
/\bnot\s+ready\s+to\s+merge\b/i,
|
|
35
|
+
/\bnot\s+ready\s+for\s+merge\b/i,
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* High-signal phrases scanned outside Overview tables after fence strip.
|
|
39
|
+
* Soft phrases (do not merge / should not merge with spaces) stay region-only
|
|
40
|
+
* so explanatory Confidence residual prose naming the detector does not thrash
|
|
41
|
+
* indefinitely (#2881 / PR #3227 conf 4 residual).
|
|
42
|
+
*/
|
|
43
|
+
const ADVISORY_HIGH_SIGNAL_RES = [
|
|
44
|
+
/\bnot\s+(?:yet\s+)?safe\s+to\s+merge\b/i,
|
|
45
|
+
/\bshould-not-merge\b/i,
|
|
46
|
+
/\bsafe\s+to\s+merge\s+once\s+corrected\b/i,
|
|
47
|
+
];
|
|
16
48
|
const NAIVE_INLINE_SHA_RE = /Last reviewed commit:\s*([0-9a-f]{7,40})/;
|
|
17
49
|
const MARKDOWN_LINK_SHA_RE = /Last reviewed commit:\s*\[.*?\]\(https?:\/\/github\.com\/[^/]+\/[^/]+\/commit\/(?<sha>[0-9a-f]{7,40})/;
|
|
18
50
|
function lineFor(body, pos) {
|
|
@@ -27,6 +59,109 @@ export function parseConfidence(body) {
|
|
|
27
59
|
}
|
|
28
60
|
return m ? Number.parseInt(m[1] ?? "0", 10) : null;
|
|
29
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Extract verdict-bearing text windows from a bot rolling-summary body (#3225).
|
|
64
|
+
* Prefers Confidence Score sections and Summary:/Decision: lines over whole-body
|
|
65
|
+
* Overview tables that may *describe* advisory phrases without issuing them.
|
|
66
|
+
*/
|
|
67
|
+
export function extractAdvisoryVerdictRegions(body) {
|
|
68
|
+
const text = stripCodeFences(body);
|
|
69
|
+
const regions = [];
|
|
70
|
+
// Per-details blocks only — do not span from Overview into Confidence Score.
|
|
71
|
+
for (const m of text.matchAll(/<details\b[^>]*>[\s\S]*?<\/details>/gi)) {
|
|
72
|
+
const block = m[0] ?? "";
|
|
73
|
+
if (/Confidence\s+Score/i.test(block)) {
|
|
74
|
+
regions.push(block);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const m of text.matchAll(/(?:^|\n)#{1,6}\s*Confidence\s+Score\s*:[^\n]*\n([\s\S]*?)(?=\n#{1,6}\s|\n<details\b|\n---\s*$|\n\*?\*?Last reviewed|\z)/gi)) {
|
|
78
|
+
regions.push(m[0] ?? "");
|
|
79
|
+
}
|
|
80
|
+
for (const m of text.matchAll(/(?:^|\n)(?:\*\*)?Confidence\s+Score(?:\*\*)?\s*:\s*\d+\s*\/\s*5[^\n]*\n([\s\S]{0,800})/gi)) {
|
|
81
|
+
regions.push(m[0] ?? "");
|
|
82
|
+
}
|
|
83
|
+
for (const m of text.matchAll(/(?:^|\n)(?:Summary|Decision|Verdict)\s*:\s*([^\n]+(?:\n(?![A-Z][^\n]{0,40}:)[^\n]+)*)/gi)) {
|
|
84
|
+
regions.push(m[0] ?? "");
|
|
85
|
+
}
|
|
86
|
+
return regions.filter((r) => r.trim().length > 0).join("\n\n");
|
|
87
|
+
}
|
|
88
|
+
function anyPatternMatches(text, patterns) {
|
|
89
|
+
return patterns.some((re) => {
|
|
90
|
+
re.lastIndex = 0;
|
|
91
|
+
return re.test(text);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* True when a line is a **verdict-shaped** advisory phrase (#3225 residual).
|
|
96
|
+
* Requires the match near the start of the line (after optional Summary:/Decision:
|
|
97
|
+
* label, bullet, or bold). Mid-sentence descriptive mentions
|
|
98
|
+
* ("adds should-not-merge parsing", "The PR is not yet safe to merge because…")
|
|
99
|
+
* do not count — those are residual discussion, not the bot's verdict line.
|
|
100
|
+
*/
|
|
101
|
+
function lineHasAnchoredAdvisory(line, patterns) {
|
|
102
|
+
let bare = line.trim();
|
|
103
|
+
// Blockquote / common markdown wrappers Greptile residual (PR #3227 conf 4).
|
|
104
|
+
bare = bare.replace(/^>\s*/, "");
|
|
105
|
+
bare = bare.replace(/^(?:Summary|Decision|Verdict)\s*[:\-–—]\s*/i, "");
|
|
106
|
+
bare = bare.replace(/^(?:[-*•]\s+)+/, "");
|
|
107
|
+
bare = bare.replace(/^\*\*/, "").replace(/\*\*$/, "");
|
|
108
|
+
bare = bare.replace(/^_/, "").replace(/_$/, "");
|
|
109
|
+
// Explicit subject-prefixed verdicts Greptile uses: "The PR is not safe to merge…"
|
|
110
|
+
bare = bare.replace(/^(?:the\s+pr|this\s+pr|this\s+change|the\s+change|this\s+diff)\s+is\s+/i, "");
|
|
111
|
+
bare = bare.trim();
|
|
112
|
+
if (bare.length === 0) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
for (const re of patterns) {
|
|
116
|
+
re.lastIndex = 0;
|
|
117
|
+
const m = re.exec(bare);
|
|
118
|
+
// Allow small lead-in after wrappers (em-dash residual, thin markdown).
|
|
119
|
+
if (m !== null && (m.index ?? 0) <= 4) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
function textHasAnchoredAdvisory(text, patterns) {
|
|
126
|
+
for (const line of text.split(/\r?\n/)) {
|
|
127
|
+
if (lineHasAnchoredAdvisory(line, patterns)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* True when comment body prose records an advisory should-not-merge / not-safe
|
|
135
|
+
* verdict (#3225). Code-fence regions are stripped first so detector docs do
|
|
136
|
+
* not self-trigger (#1004).
|
|
137
|
+
*
|
|
138
|
+
* Line-anchored hybrid scan (PR #3227 residuals):
|
|
139
|
+
* 1. Soft + high-signal **line-anchored** phrases in Confidence / Summary /
|
|
140
|
+
* Decision regions (and whole body)
|
|
141
|
+
* 2. Same line-anchored high-signal set on whole body (standalone warnings)
|
|
142
|
+
* Mid-sentence residual discussion does not hard-block; conf floor still does (#3095).
|
|
143
|
+
*/
|
|
144
|
+
export function hasShouldNotMergeProse(body) {
|
|
145
|
+
const text = stripCodeFences(body);
|
|
146
|
+
const regions = extractAdvisoryVerdictRegions(body);
|
|
147
|
+
if (regions.length > 0 && textHasAnchoredAdvisory(regions, ADVISORY_SHOULD_NOT_MERGE_RES)) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
// Soft + high line-anchored anywhere (covers standalone spaced Do not merge /
|
|
151
|
+
// should not merge outside Confidence regions without Overview mid-sentence hits).
|
|
152
|
+
if (textHasAnchoredAdvisory(text, ADVISORY_SHOULD_NOT_MERGE_RES)) {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
export function parseAdvisoryReviewerVerdict(body) {
|
|
158
|
+
const findings = detect(body);
|
|
159
|
+
return {
|
|
160
|
+
confidence: parseConfidence(body),
|
|
161
|
+
shouldNotMerge: hasShouldNotMergeProse(body),
|
|
162
|
+
hasBlocking: findings.has_blocking,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
30
165
|
export function detect(body) {
|
|
31
166
|
body = stripCodeFences(body);
|
|
32
167
|
const tier1_p0 = (body.match(/<img alt="P0"/g) ?? []).length;
|
|
@@ -59,10 +194,9 @@ export function detect(body) {
|
|
|
59
194
|
tier25_p1 += 1;
|
|
60
195
|
}
|
|
61
196
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
197
|
+
// Tier 3: advisory should-not-merge prose (#3225 extends "Not safe to merge")
|
|
198
|
+
// plus count-prose and line-anchored P0/P1 sentinels (#910).
|
|
199
|
+
let tier3_sentinel = hasShouldNotMergeProse(body);
|
|
66
200
|
if (!tier3_sentinel) {
|
|
67
201
|
for (const m of body.matchAll(TIER3_COUNT_RE)) {
|
|
68
202
|
const line = lineFor(body, m.index ?? 0);
|
|
@@ -133,6 +267,70 @@ Last reviewed commit: [refactor: thing](https://github.com/deftai/directive/comm
|
|
|
133
267
|
Summary: Not safe to merge until the mocked-import test defect and the two
|
|
134
268
|
previously filed P1s are resolved.
|
|
135
269
|
`;
|
|
270
|
+
/** #3225 live-case shape: conf 3/5 + should-not-merge prose, zero badges. */
|
|
271
|
+
export const BODY_ADVISORY_SHOULD_NOT_MERGE_CONF3 = `Greptile review of head advisory01
|
|
272
|
+
|
|
273
|
+
## Confidence Score: 3/5
|
|
274
|
+
|
|
275
|
+
Summary: should-not-merge — residual risk on the auth path is too high for
|
|
276
|
+
this change set. Formal review state is still Comment (not Changes Requested).
|
|
277
|
+
|
|
278
|
+
Last reviewed commit: [feat: advisory](https://github.com/deftai/directive/commit/advisory01abcdef12)
|
|
279
|
+
`;
|
|
280
|
+
/** Green mechanical path trap: high conf but explicit do-not-merge prose. */
|
|
281
|
+
export const BODY_ADVISORY_DO_NOT_MERGE_HIGH_CONF = `Greptile review of head advisory02
|
|
282
|
+
|
|
283
|
+
Confidence Score: 5/5
|
|
284
|
+
|
|
285
|
+
No P0 or P1 issues found via badges.
|
|
286
|
+
|
|
287
|
+
Summary: Do not merge until the operator documents residual risk.
|
|
288
|
+
|
|
289
|
+
Last reviewed commit: [docs: note](https://github.com/deftai/directive/commit/advisory02abcdef12)
|
|
290
|
+
`;
|
|
291
|
+
/**
|
|
292
|
+
* Overview prose names the detector phrase without issuing a verdict (#3225 residual).
|
|
293
|
+
* Confidence section is clean — must NOT set shouldNotMerge.
|
|
294
|
+
*/
|
|
295
|
+
export const BODY_ADVISORY_DESCRIPTIVE_ONLY = `Greptile review of head advisory03
|
|
296
|
+
|
|
297
|
+
<details><summary><h3>Greptile Summary</h3></summary>
|
|
298
|
+
|
|
299
|
+
This PR adds should-not-merge prose detection and Not safe to merge matching to
|
|
300
|
+
merge-ready. Descriptive overview only — no blocking residual on the product path.
|
|
301
|
+
|
|
302
|
+
</details>
|
|
303
|
+
|
|
304
|
+
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
|
|
305
|
+
|
|
306
|
+
No P0 or P1 issues found. The change looks clean and well-tested.
|
|
307
|
+
|
|
308
|
+
</details>
|
|
309
|
+
|
|
310
|
+
Last reviewed commit: [feat: detector](https://github.com/deftai/directive/commit/advisory03abcdef12)
|
|
311
|
+
`;
|
|
312
|
+
/** Standalone high-signal warning outside Confidence section must still block. */
|
|
313
|
+
export const BODY_ADVISORY_STANDALONE_NOT_SAFE = `Greptile review of head advisory04
|
|
314
|
+
|
|
315
|
+
<details open><summary><h3>Confidence Score: 5/5</h3></summary>
|
|
316
|
+
|
|
317
|
+
Looks solid from a findings perspective.
|
|
318
|
+
|
|
319
|
+
</details>
|
|
320
|
+
|
|
321
|
+
Not safe to merge until the operator confirms residual risk handling.
|
|
322
|
+
|
|
323
|
+
Last reviewed commit: [feat: residual](https://github.com/deftai/directive/commit/advisory04abcdef12)
|
|
324
|
+
`;
|
|
325
|
+
/** Subject-prefixed verdict Greptile commonly emits (#3225 residual). */
|
|
326
|
+
export const BODY_ADVISORY_SUBJECT_PREFIXED = `Greptile review of head advisory05
|
|
327
|
+
|
|
328
|
+
## Confidence Score: 4/5
|
|
329
|
+
|
|
330
|
+
The PR is not safe to merge until residual risk is documented on the auth path.
|
|
331
|
+
|
|
332
|
+
Last reviewed commit: [feat: subject](https://github.com/deftai/directive/commit/advisory05abcdef12)
|
|
333
|
+
`;
|
|
136
334
|
export const BODY_TIER3_COUNT_PROSE_ONLY = `Greptile review of head deadbeef
|
|
137
335
|
|
|
138
336
|
Confidence Score: 4/5
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured agent decision log (#1396).
|
|
3
|
+
*
|
|
4
|
+
* CLI surface: task decision:write / task decision:list
|
|
5
|
+
*/
|
|
6
|
+
export { type DecisionListCliArgs, type DecisionListEntry, type DecisionListOptions, type DecisionListResult, decisionListMain, parseDecisionListArgs, runDecisionList, } from "./list.js";
|
|
7
|
+
export { DECISION_FILE_SUFFIX, DECISION_SCHEMA_VERSION, DECISIONS_DIR_REL, type DecisionAlternative, type DecisionConfidence, type DecisionGoverningRule, type DecisionRecord, type DecisionValidationError, type DecisionValidationResult, datePrefixFromTimestamp, decisionFilename, formatDecisionValidationErrors, normalizeTimestamp, sanitizeForTerminal, slugifyDecision, validateDecisionRecord, } from "./schema.js";
|
|
8
|
+
export { appendScopeDecisionPointer, type DecisionWriteCliArgs, type DecisionWriteInput, type DecisionWriteOutcome, type DecisionWriteResult, decisionWriteMain, parseDecisionWriteArgs, runDecisionWrite, } from "./write.js";
|
|
9
|
+
/**
|
|
10
|
+
* Unified CLI entry for dispatch when verb is decision-write / decision-list.
|
|
11
|
+
* Expects first argv token to be the subcommand (write|list) when routed via
|
|
12
|
+
* a single decision stem; dispatch registers separate stems per verb.
|
|
13
|
+
*/
|
|
14
|
+
export declare function mainEntry(argv?: string[]): number;
|
|
15
|
+
export declare function writeMainEntry(argv?: string[]): number;
|
|
16
|
+
export declare function listMainEntry(argv?: string[]): number;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured agent decision log (#1396).
|
|
3
|
+
*
|
|
4
|
+
* CLI surface: task decision:write / task decision:list
|
|
5
|
+
*/
|
|
6
|
+
import { decisionListMain } from "./list.js";
|
|
7
|
+
import { decisionWriteMain } from "./write.js";
|
|
8
|
+
export { decisionListMain, parseDecisionListArgs, runDecisionList, } from "./list.js";
|
|
9
|
+
export { DECISION_FILE_SUFFIX, DECISION_SCHEMA_VERSION, DECISIONS_DIR_REL, datePrefixFromTimestamp, decisionFilename, formatDecisionValidationErrors, normalizeTimestamp, sanitizeForTerminal, slugifyDecision, validateDecisionRecord, } from "./schema.js";
|
|
10
|
+
export { appendScopeDecisionPointer, decisionWriteMain, parseDecisionWriteArgs, runDecisionWrite, } from "./write.js";
|
|
11
|
+
/**
|
|
12
|
+
* Unified CLI entry for dispatch when verb is decision-write / decision-list.
|
|
13
|
+
* Expects first argv token to be the subcommand (write|list) when routed via
|
|
14
|
+
* a single decision stem; dispatch registers separate stems per verb.
|
|
15
|
+
*/
|
|
16
|
+
export function mainEntry(argv = process.argv.slice(2)) {
|
|
17
|
+
const [head, ...rest] = argv;
|
|
18
|
+
if (head === "write" || head === "decision:write") {
|
|
19
|
+
return decisionWriteMain(rest);
|
|
20
|
+
}
|
|
21
|
+
if (head === "list" || head === "decision:list") {
|
|
22
|
+
return decisionListMain(rest);
|
|
23
|
+
}
|
|
24
|
+
// When dispatch loads decision-write / decision-list stems, argv has no head.
|
|
25
|
+
// Callers use decisionWriteMain / decisionListMain directly from loadCoreModuleHandler.
|
|
26
|
+
process.stderr.write("decision: unknown subcommand. Use decision:write or decision:list.\n");
|
|
27
|
+
return 2;
|
|
28
|
+
}
|
|
29
|
+
export function writeMainEntry(argv = process.argv.slice(2)) {
|
|
30
|
+
return decisionWriteMain(argv);
|
|
31
|
+
}
|
|
32
|
+
export function listMainEntry(argv = process.argv.slice(2)) {
|
|
33
|
+
return decisionListMain(argv);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* decision:list — find structured decision records (#1396).
|
|
3
|
+
*/
|
|
4
|
+
export interface DecisionListOptions {
|
|
5
|
+
readonly projectRoot?: string | null;
|
|
6
|
+
/** Filter by substring match on id, decision text, or tags. */
|
|
7
|
+
readonly query?: string | null;
|
|
8
|
+
/** Filter by scope path substring. */
|
|
9
|
+
readonly scope?: string | null;
|
|
10
|
+
/** Filter by related issue number. */
|
|
11
|
+
readonly issue?: number | null;
|
|
12
|
+
/** Max rows (default unlimited). */
|
|
13
|
+
readonly limit?: number | null;
|
|
14
|
+
readonly json?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface DecisionListEntry {
|
|
17
|
+
readonly path: string;
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly decision: string;
|
|
20
|
+
readonly confidence: string;
|
|
21
|
+
readonly timestamp: string;
|
|
22
|
+
readonly revisitTrigger: string;
|
|
23
|
+
readonly activeScopeRefs: readonly string[];
|
|
24
|
+
readonly tags: readonly string[];
|
|
25
|
+
readonly relatedIssues: readonly number[];
|
|
26
|
+
}
|
|
27
|
+
export interface DecisionListResult {
|
|
28
|
+
readonly exitCode: 0 | 1 | 2;
|
|
29
|
+
readonly entries: readonly DecisionListEntry[];
|
|
30
|
+
readonly message: string;
|
|
31
|
+
}
|
|
32
|
+
/** List decision records under xbrief/decisions/. */
|
|
33
|
+
export declare function runDecisionList(options?: DecisionListOptions): DecisionListResult;
|
|
34
|
+
export interface DecisionListCliArgs {
|
|
35
|
+
query?: string;
|
|
36
|
+
scope?: string;
|
|
37
|
+
issue?: number;
|
|
38
|
+
limit?: number;
|
|
39
|
+
json?: boolean;
|
|
40
|
+
projectRoot?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Parse argv for decision:list. */
|
|
44
|
+
export declare function parseDecisionListArgs(argv: readonly string[]): DecisionListCliArgs;
|
|
45
|
+
/** CLI entry for decision:list. */
|
|
46
|
+
export declare function decisionListMain(argv: readonly string[]): number;
|
|
47
|
+
//# sourceMappingURL=list.d.ts.map
|