@sentropic/harness 0.4.0 → 0.5.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 +84 -3
- package/dist/branch-md/parse.d.ts +2 -1
- package/dist/branch-md/parse.d.ts.map +1 -1
- package/dist/branch-md/parse.js +12 -6
- package/dist/branch-md/parse.js.map +1 -1
- package/dist/checks/scope-check.d.ts +2 -0
- package/dist/checks/scope-check.d.ts.map +1 -1
- package/dist/checks/scope-check.js +11 -0
- package/dist/checks/scope-check.js.map +1 -1
- package/dist/cli/mechanical-verbs.d.ts.map +1 -1
- package/dist/cli/mechanical-verbs.js +6 -18
- package/dist/cli/mechanical-verbs.js.map +1 -1
- package/dist/cli/run.d.ts +0 -8
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +20 -9
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/scope.d.ts.map +1 -1
- package/dist/cli/scope.js +8 -4
- package/dist/cli/scope.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/profile/document.d.ts +16 -0
- package/dist/profile/document.d.ts.map +1 -0
- package/dist/profile/document.js +71 -0
- package/dist/profile/document.js.map +1 -0
- package/dist/profile/profile.d.ts +16 -0
- package/dist/profile/profile.d.ts.map +1 -1
- package/dist/profile/resolve.d.ts +7 -0
- package/dist/profile/resolve.d.ts.map +1 -0
- package/dist/profile/resolve.js +63 -0
- package/dist/profile/resolve.js.map +1 -0
- package/dist/scope/scope-boundary.d.ts +2 -1
- package/dist/scope/scope-boundary.d.ts.map +1 -1
- package/dist/scope/scope-boundary.js +6 -1
- package/dist/scope/scope-boundary.js.map +1 -1
- package/package.json +1 -1
- package/schema/harness-profile.schema.json +49 -0
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ behind a pluggable **profile** SPI. The NATIVE sentropic replacement for superpo
|
|
|
11
11
|
- **Policy as data**: the Sentropic rules (scope paths, exception grammar, thresholds) live
|
|
12
12
|
in a `sentropic` profile module behind the `HarnessProfile` interface. The check **kernel**
|
|
13
13
|
is profile-driven (a second `stub` profile exercises it with divergent policy); full
|
|
14
|
-
plugin-surface genericity (plan-adapter SPI
|
|
14
|
+
plugin-surface genericity (plan-adapter SPI and additional checks) is
|
|
15
15
|
the G1–G4 follow-on tracked in `SPEC_STUDY_HARNESS_GENERICITY_AUDIT.md`.
|
|
16
16
|
|
|
17
17
|
> Status: **BR-42h** — published to npm (D7 lifted 2026-06-08). Installs like every other
|
|
@@ -32,8 +32,89 @@ harness check branch --current-branch "$(git branch --show-current)" --expected-
|
|
|
32
32
|
harness check scope --branch-md BRANCH.md --staged-files "$(git diff --cached --name-only | paste -sd,)" [--json]
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
`--json` emits a neutral artifact.
|
|
36
|
-
|
|
35
|
+
`--json` emits a neutral artifact. Policy selection for `check`, `verify`, `audit` and `init`:
|
|
36
|
+
explicit `--profile sentropic|stub` > `--profile-file <path>` > repository-root
|
|
37
|
+
`harness.profile.json` > built-in `sentropic`. An explicit built-in ignores lower-priority files,
|
|
38
|
+
even if they are invalid. Unknown built-in names are errors. In an `@sentropic` repo,
|
|
39
|
+
`make scope-check` wraps the staged+unstaged scope check.
|
|
40
|
+
|
|
41
|
+
## Repository-owned profiles
|
|
42
|
+
|
|
43
|
+
Commit `harness.profile.json` at your Git root. Discovery walks upward to the nearest `.git`
|
|
44
|
+
directory or worktree file and checks only that root, including when invoked in a subdirectory.
|
|
45
|
+
Outside Git, the current directory is the root. `--profile-file` resolves relative to the current
|
|
46
|
+
directory; an absolute path also works. These files contain data only; no code is executed.
|
|
47
|
+
|
|
48
|
+
The published [JSON Schema](schema/harness-profile.schema.json) is also the runtime validation
|
|
49
|
+
contract. All objects reject unknown keys; fields are never coerced. Invalid configuration exits
|
|
50
|
+
with code **2**, including when `--json` is requested. Programmatic callers receive
|
|
51
|
+
`ProfileValidationError` with `code` and `path`; an unknown property has code `UNKNOWN_KEY`.
|
|
52
|
+
Other codes: `INVALID_PROFILE`, `INVALID_REGEX`, `PROFILE_READ`, `PROFILE_JSON`, `UNKNOWN_PROFILE`.
|
|
53
|
+
Unreadable or invalid selected files fail closed. Ordinary C1/C2 violations retain advisory exit 0.
|
|
54
|
+
|
|
55
|
+
A Rust + Node repository such as sentbase can start with:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"id": "sentbase",
|
|
60
|
+
"forbiddenPathDefaults": ["Cargo.toml", ".githooks/**", "LICENSE"],
|
|
61
|
+
"allowedPathDefaults": ["src/**", "web/**", "tests/**", "BRANCH.md"],
|
|
62
|
+
"conditionalPathDefaults": ["Cargo.lock", "package.json", "package-lock.json"],
|
|
63
|
+
"exceptionIdPattern": "^EXC-\\d+$",
|
|
64
|
+
"conditionalRequiresException": true,
|
|
65
|
+
"branchMatch": "exact",
|
|
66
|
+
"branchMd": {
|
|
67
|
+
"file": "BRANCH.md",
|
|
68
|
+
"allowedHeading": "Allowed Paths",
|
|
69
|
+
"forbiddenHeading": "Forbidden Paths",
|
|
70
|
+
"conditionalHeading": "Conditional Paths",
|
|
71
|
+
"planHeading": "Plan / Todo"
|
|
72
|
+
},
|
|
73
|
+
"commitMessage": {
|
|
74
|
+
"requiredPattern": "^(feat|fix|docs|test|chore|refactor): .+",
|
|
75
|
+
"forbiddenPatterns": ["Co-Authored-By:", "Claude-Session:", "Generated with"]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
harness check scope --staged-files src/lib.rs,web/index.ts
|
|
82
|
+
harness check scope --profile-file ./harness.profile.json --staged-files LICENSE
|
|
83
|
+
harness check scope --commit-message 'feat: add endpoint'
|
|
84
|
+
harness init --profile sentropic --json > harness.profile.json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Field | Contract |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `id` | Required nonempty profile identifier. |
|
|
90
|
+
| `forbiddenPathDefaults` | Required array of forbidden path globs; `[]` is valid. |
|
|
91
|
+
| `allowedPathDefaults`, `conditionalPathDefaults` | Optional default glob arrays; omitted means empty. |
|
|
92
|
+
| `exceptionIdPattern` | Required ECMAScript regex source for exception IDs, without `/` delimiters or flags. |
|
|
93
|
+
| `conditionalRequiresException` | Required boolean; when true, a declared matching exception permits conditional paths. |
|
|
94
|
+
| `branchMatch` | Required `exact` or `prefix` comparison for C1. |
|
|
95
|
+
| `branchMd` | Optional plan conventions; when present all five fields above are required. |
|
|
96
|
+
| `commitMessage` | Optional guards: required `forbiddenPatterns` array and optional `requiredPattern`, both regex sources. |
|
|
97
|
+
| `$schema` | Optional editor schema reference. |
|
|
98
|
+
|
|
99
|
+
Globs are repository-relative POSIX paths: `*` matches within one segment, `**` spans `/`,
|
|
100
|
+
and other characters are literal (no brace expansion, `?`, negation or implicit directory matching).
|
|
101
|
+
Empty paths, absolute paths, backslashes and `..` segments are rejected. Scope precedence is:
|
|
102
|
+
BRANCH allowed > BRANCH forbidden > BRANCH conditional > profile forbidden > profile conditional >
|
|
103
|
+
profile allowed > unknown. Thus an explicit branch grant can override a profile prohibition;
|
|
104
|
+
the example forbids `Cargo.toml`, `.githooks/**` and `LICENSE` by default.
|
|
105
|
+
|
|
106
|
+
Plans use `#` for the title, `##` for sections, bold bucket labels and backtick-quoted globs.
|
|
107
|
+
Bucket headings match case-insensitive prefixes, preserving parenthetical suffixes. `planHeading`
|
|
108
|
+
identifies the lot section; checkbox lots retain the `Lot` prefix. `exceptionIdPattern` also drives
|
|
109
|
+
exception extraction from plan text. Without `branchMd`, canonical headings apply and a plan is
|
|
110
|
+
read only via `--branch-md`. With `branchMd`, its `file` is relative to the Git root and is read
|
|
111
|
+
when present; `--branch-md` overrides it and is relative to the current directory. Missing explicit
|
|
112
|
+
plans are errors. Missing default plans leave the profile defaults in effect.
|
|
113
|
+
|
|
114
|
+
Commit guards run only when `--commit-message <text>` is supplied to scope, verify or audit.
|
|
115
|
+
Regexes inspect the entire message, including trailers, case-sensitively and without flags.
|
|
116
|
+
Built-in profiles have no commit guards. Both built-ins are valid schema documents, available via
|
|
117
|
+
`harness init --profile sentropic|stub --json`; loading those documents preserves their C1/C2 results.
|
|
37
118
|
|
|
38
119
|
## Verbs
|
|
39
120
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { HarnessProfile } from '../profile/profile.js';
|
|
1
2
|
export interface ParsedLotItem {
|
|
2
3
|
text: string;
|
|
3
4
|
checked: boolean;
|
|
@@ -15,5 +16,5 @@ export interface ParsedBranchMd {
|
|
|
15
16
|
exceptions: string[];
|
|
16
17
|
lots: ParsedLot[];
|
|
17
18
|
}
|
|
18
|
-
export declare function parseBranchMd(text: string): ParsedBranchMd;
|
|
19
|
+
export declare function parseBranchMd(text: string, profile?: HarnessProfile): ParsedBranchMd;
|
|
19
20
|
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/branch-md/parse.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAWD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/branch-md/parse.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAWD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAkGpF"}
|
package/dist/branch-md/parse.js
CHANGED
|
@@ -9,7 +9,11 @@ function backtickGlobs(line) {
|
|
|
9
9
|
out.push(m[1]);
|
|
10
10
|
return out;
|
|
11
11
|
}
|
|
12
|
-
export function parseBranchMd(text) {
|
|
12
|
+
export function parseBranchMd(text, profile) {
|
|
13
|
+
const conventions = profile?.branchMd;
|
|
14
|
+
const exception = profile
|
|
15
|
+
? new RegExp('\\b(?:' + profile.exceptionIdPattern.source.replace(/^\^/, '').replace(/\$$/, '') + ')\\b', 'g')
|
|
16
|
+
: EXCEPTION;
|
|
13
17
|
const lines = text.split(/\r?\n/);
|
|
14
18
|
const result = {
|
|
15
19
|
title: '',
|
|
@@ -39,11 +43,13 @@ export function parseBranchMd(text) {
|
|
|
39
43
|
result.conditionalPaths.push(...globs);
|
|
40
44
|
};
|
|
41
45
|
for (const line of lines) {
|
|
42
|
-
for (const m of line.matchAll(
|
|
46
|
+
for (const m of line.matchAll(exception))
|
|
43
47
|
result.exceptions.push(m[0]);
|
|
44
48
|
if (/^##\s+/.test(line)) {
|
|
45
49
|
bucket = null;
|
|
46
|
-
inPlan =
|
|
50
|
+
inPlan = conventions
|
|
51
|
+
? line.toLowerCase().includes(conventions.planHeading.toLowerCase())
|
|
52
|
+
: /plan\s*\/\s*todo/i.test(line);
|
|
47
53
|
currentLot = null;
|
|
48
54
|
continue;
|
|
49
55
|
}
|
|
@@ -52,17 +58,17 @@ export function parseBranchMd(text) {
|
|
|
52
58
|
// closing `**` is NOT adjacent to "Paths". Match the prefix only (as Conditional
|
|
53
59
|
// already did) — otherwise Allowed/Forbidden silently parse to empty on every
|
|
54
60
|
// real BRANCH.md and in-scope files wrongly classify as `unknown`.
|
|
55
|
-
if (
|
|
61
|
+
if (line.toLowerCase().includes('**' + (conventions?.allowedHeading ?? 'Allowed Paths').toLowerCase())) {
|
|
56
62
|
bucket = 'allowed';
|
|
57
63
|
pushBucket(backtickGlobs(line));
|
|
58
64
|
continue;
|
|
59
65
|
}
|
|
60
|
-
if (
|
|
66
|
+
if (line.toLowerCase().includes('**' + (conventions?.forbiddenHeading ?? 'Forbidden Paths').toLowerCase())) {
|
|
61
67
|
bucket = 'forbidden';
|
|
62
68
|
pushBucket(backtickGlobs(line));
|
|
63
69
|
continue;
|
|
64
70
|
}
|
|
65
|
-
if (
|
|
71
|
+
if (line.toLowerCase().includes('**' + (conventions?.conditionalHeading ?? 'Conditional Paths').toLowerCase())) {
|
|
66
72
|
bucket = 'conditional';
|
|
67
73
|
pushBucket(backtickGlobs(line));
|
|
68
74
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/branch-md/parse.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4FAA4F;AAC5F,8DAA8D;
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/branch-md/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,8 @@ export interface ScopeCheckInput {
|
|
|
8
8
|
profile: HarnessProfile;
|
|
9
9
|
/** Exception ids declared in the BRANCH.md (e.g. parser `exceptions`). */
|
|
10
10
|
declaredExceptions?: string[];
|
|
11
|
+
/** Optional commit text; absent means commit guards are not run. */
|
|
12
|
+
commitMessage?: string;
|
|
11
13
|
bypass?: {
|
|
12
14
|
reason: string;
|
|
13
15
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-check.d.ts","sourceRoot":"","sources":["../../src/checks/scope-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"scope-check.d.ts","sourceRoot":"","sources":["../../src/checks/scope-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,uCAAuC;IACvC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,aAAa,CAAC;IACxB,OAAO,EAAE,cAAc,CAAC;IACxB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,CAgC9D"}
|
|
@@ -12,6 +12,17 @@ export function checkScope(input) {
|
|
|
12
12
|
const { stagedFiles, boundary, profile, declaredExceptions = [] } = input;
|
|
13
13
|
const hasValidException = declaredExceptions.some((id) => profile.exceptionIdPattern.test(id));
|
|
14
14
|
const violations = [];
|
|
15
|
+
if (input.commitMessage !== undefined && profile.commitMessage) {
|
|
16
|
+
const { requiredPattern, forbiddenPatterns } = profile.commitMessage;
|
|
17
|
+
if (requiredPattern !== undefined && !new RegExp(requiredPattern).test(input.commitMessage)) {
|
|
18
|
+
violations.push({ code: 'C2', message: 'commit message does not match required pattern', severity: 'advisory' });
|
|
19
|
+
}
|
|
20
|
+
for (const pattern of forbiddenPatterns) {
|
|
21
|
+
if (new RegExp(pattern).test(input.commitMessage)) {
|
|
22
|
+
violations.push({ code: 'C2', message: `commit message matches forbidden pattern: ${pattern}`, severity: 'advisory' });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
15
26
|
for (const path of stagedFiles) {
|
|
16
27
|
const cls = classifyPath(path, boundary, profile);
|
|
17
28
|
if (cls === 'forbidden') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-check.js","sourceRoot":"","sources":["../../src/checks/scope-check.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAsB,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"scope-check.js","sourceRoot":"","sources":["../../src/checks/scope-check.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAsB,MAAM,4BAA4B,CAAC;AAc9E;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;IAC9E,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,kBAAkB,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC;IAC1E,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/F,MAAM,UAAU,GAAgB,EAAE,CAAC;IACnC,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAC/D,MAAM,EAAE,eAAe,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;QACrE,IAAI,eAAe,KAAK,SAAS,IAAI,CAAC,IAAI,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;YAC5F,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,gDAAgD,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACnH,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACxC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,CAAC;gBAClD,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,6CAA6C,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;YACzH,CAAC;QACH,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,2BAA2B,IAAI,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QAC1G,CAAC;aAAM,IAAI,GAAG,KAAK,aAAa,IAAI,OAAO,CAAC,4BAA4B,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC/F,UAAU,CAAC,IAAI,CAAC;gBACd,IAAI,EAAE,IAAI;gBACV,IAAI;gBACJ,OAAO,EAAE,0DAA0D,IAAI,EAAE;gBACzE,QAAQ,EAAE,UAAU;aACrB,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YAC7B,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,0CAA0C,IAAI,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACzH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;AACvD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mechanical-verbs.d.ts","sourceRoot":"","sources":["../../src/cli/mechanical-verbs.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAO,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAKhD,eAAO,MAAM,gBAAgB,sCAAuC,CAAC;AACrE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"mechanical-verbs.d.ts","sourceRoot":"","sources":["../../src/cli/mechanical-verbs.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAO,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAKhD,eAAO,MAAM,gBAAgB,sCAAuC,CAAC;AACrE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAmE/D;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EAAE,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAChC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,GACvB,MAAM,GAAG,IAAI,CAsCf"}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
// `VerificationRun`: `verify` is the category-level roll-up over the available static checks (the
|
|
5
5
|
// canonical VerificationRun producer); `audit` diffs the repo against the active profile; `init`
|
|
6
6
|
// scaffolds a profile descriptor so the same C1/C2 kernel can run against ANY repo. Pure: the only
|
|
7
|
-
// IO is reading
|
|
7
|
+
// IO is reading profile/plan files (shared with `check scope`); no git/docker/fs writes.
|
|
8
8
|
import { toVerificationRun } from '../run/emit.js';
|
|
9
9
|
import { checkBranch } from '../checks/branch-check.js';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { resolveProfile } from '../profile/resolve.js';
|
|
11
|
+
import { toProfileDocument } from '../profile/document.js';
|
|
12
12
|
import { scopeFromFlags } from './scope.js';
|
|
13
13
|
import { str } from './args.js';
|
|
14
14
|
const PLACEHOLDER_TS = '1970-01-01T00:00:00.000Z';
|
|
@@ -20,9 +20,6 @@ function isMechanicalVerb(v) {
|
|
|
20
20
|
function isCategory(s) {
|
|
21
21
|
return CATEGORIES.includes(s);
|
|
22
22
|
}
|
|
23
|
-
function resolveProfile(flags) {
|
|
24
|
-
return str(flags.profile) === 'stub' ? stubProfile : sentropicProfile;
|
|
25
|
-
}
|
|
26
23
|
function runContext(flags, category, command) {
|
|
27
24
|
return {
|
|
28
25
|
runId: 'cli',
|
|
@@ -39,7 +36,7 @@ function runContext(flags, category, command) {
|
|
|
39
36
|
/** Gather the static checks computable from supplied flags (C2 scope, C1 branch). */
|
|
40
37
|
function staticChecks(flags, profile, out) {
|
|
41
38
|
const checks = [];
|
|
42
|
-
if (flags['staged-files'] !== undefined || flags['branch-md'] !== undefined) {
|
|
39
|
+
if (flags['staged-files'] !== undefined || flags['branch-md'] !== undefined || flags['commit-message'] !== undefined) {
|
|
43
40
|
const outcome = scopeFromFlags(flags, profile);
|
|
44
41
|
if (outcome.unreadable !== undefined) {
|
|
45
42
|
out(`harness: cannot read plan file: ${outcome.unreadable}`);
|
|
@@ -80,22 +77,13 @@ export function handleMechanicalVerb(positionals, flags, out) {
|
|
|
80
77
|
return null;
|
|
81
78
|
const profile = resolveProfile(flags);
|
|
82
79
|
if (verb === 'init') {
|
|
83
|
-
const descriptor =
|
|
84
|
-
id: profile.id,
|
|
85
|
-
forbiddenPathDefaults: profile.forbiddenPathDefaults,
|
|
86
|
-
exceptionIdPattern: profile.exceptionIdPattern.source,
|
|
87
|
-
conditionalRequiresException: profile.conditionalRequiresException,
|
|
88
|
-
branchMatch: profile.branchMatch,
|
|
89
|
-
};
|
|
80
|
+
const descriptor = toProfileDocument(profile);
|
|
90
81
|
if (flags.json === true) {
|
|
91
82
|
out(JSON.stringify(descriptor, null, 2));
|
|
92
83
|
}
|
|
93
84
|
else {
|
|
94
85
|
out(`harness init — profile '${descriptor.id}' (edit and commit as harness.profile.json):`);
|
|
95
|
-
out(
|
|
96
|
-
out(` exceptionIdPattern: ${descriptor.exceptionIdPattern}`);
|
|
97
|
-
out(` conditionalRequiresException: ${descriptor.conditionalRequiresException}`);
|
|
98
|
-
out(` branchMatch: ${descriptor.branchMatch}`);
|
|
86
|
+
out(JSON.stringify(descriptor, null, 2));
|
|
99
87
|
}
|
|
100
88
|
return 0;
|
|
101
89
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mechanical-verbs.js","sourceRoot":"","sources":["../../src/cli/mechanical-verbs.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,EAAE;AACF,iGAAiG;AACjG,kGAAkG;AAClG,iGAAiG;AACjG,mGAAmG;AACnG,
|
|
1
|
+
{"version":3,"file":"mechanical-verbs.js","sourceRoot":"","sources":["../../src/cli/mechanical-verbs.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,EAAE;AACF,iGAAiG;AACjG,kGAAkG;AAClG,iGAAiG;AACjG,mGAAmG;AACnG,yFAAyF;AAEzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAkB,MAAM,WAAW,CAAC;AAEhD,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAClD,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAU,CAAC;AAE1F,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAU,CAAC;AAGrE,SAAS,gBAAgB,CAAC,CAAqB;IAC7C,OAAO,CAAC,KAAK,SAAS,IAAK,gBAAsC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAQ,UAAgC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,UAAU,CAAC,KAAgC,EAAE,QAA8B,EAAE,OAAe;IACnG,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,SAAS;QACtC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,SAAS;QACjD,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK;QAC5B,MAAM,EAAE,SAAS;QACjB,QAAQ;QACR,OAAO;QACP,SAAS,EAAE,cAAc;QACzB,UAAU,EAAE,cAAc;KAC3B,CAAC;AACJ,CAAC;AAED,qFAAqF;AACrF,SAAS,YAAY,CACnB,KAAgC,EAChC,OAAuB,EACvB,GAAwB;IAExB,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,KAAK,CAAC,cAAc,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,gBAAgB,CAAC,KAAK,SAAS,EAAE,CAAC;QACrH,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACrC,GAAG,CAAC,mCAAmC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;YAC7D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,OAAO,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,KAAK,CAAC,gBAAgB,CAAC,KAAK,SAAS,IAAI,KAAK,CAAC,iBAAiB,CAAC,KAAK,SAAS,EAAE,CAAC;QACpF,MAAM,MAAM,GAAG,WAAW,CAAC;YACzB,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE;YACjD,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE;YACnD,OAAO;SACR,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,OAAO,CACd,MAAoB,EACpB,KAAgC,EAChC,QAA8B,EAC9B,OAAe,EACf,GAAwB;IAExB,MAAM,GAAG,GAAG,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5E,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,OAAO,KAAK,QAAQ,MAAM,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC;QACtG,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU;YAAE,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAAqB,EACrB,KAAgC,EAChC,GAAwB;IAExB,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC5B,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzC,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAEtC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,2BAA2B,UAAU,CAAC,EAAE,8CAA8C,CAAC,CAAC;YAC5F,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC;QAC5C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,GAAG,CAAC,qCAAqC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACtE,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QACjD,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,CAAC,CAAC;QAC9B,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,wEAAwE;IACxE,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAC/C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACrC,GAAG,CAAC,mCAAmC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QAC7D,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,MAAM,GAAiB,OAAO,CAAC,MAAM;QACzC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QAC9D,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,CAAC,CAAC;AAChE,CAAC"}
|
package/dist/cli/run.d.ts
CHANGED
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure, arg-based CLI driver — reads everything from `argv`, writes via `out`, returns an exit code.
|
|
3
|
-
* No internal git calls (the caller supplies branch + staged files), no `process.exit`, no fs writes.
|
|
4
|
-
* Advisory (D5 Layer A): a failing check returns 0; only a usage error returns non-zero.
|
|
5
|
-
*
|
|
6
|
-
* Verb families: `check` (C1/C2 → VerificationRun); method/recorder verbs (brainstorm/test/debug/
|
|
7
|
-
* review/plan/branch/skills → WorkEvent + skill pointer, see `method-verbs.ts`).
|
|
8
|
-
*/
|
|
9
1
|
export declare function runHarnessCli(argv: string[], out: (s: string) => void): number;
|
|
10
2
|
//# sourceMappingURL=run.d.ts.map
|
package/dist/cli/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAiHA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAO9E"}
|
package/dist/cli/run.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { checkBranch } from '../checks/branch-check.js';
|
|
2
2
|
import { toVerificationRun } from '../run/emit.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { resolveProfile } from '../profile/resolve.js';
|
|
4
|
+
import { ProfileValidationError } from '../profile/document.js';
|
|
5
5
|
import { parseFlags, str } from './args.js';
|
|
6
6
|
import { scopeFromFlags } from './scope.js';
|
|
7
7
|
import { handleMethodVerb } from './method-verbs.js';
|
|
8
8
|
import { handleMechanicalVerb } from './mechanical-verbs.js';
|
|
9
9
|
const USAGE = [
|
|
10
10
|
'usage: harness check <scope|branch> [--current-branch <b>] [--expected-branch <b>] ' +
|
|
11
|
-
'[--staged-files <list>] [--branch-md <path>] [--profile sentropic|stub] [--json]',
|
|
11
|
+
'[--staged-files <list>] [--branch-md <path>] [--profile sentropic|stub] [--profile-file <path>] [--commit-message <text>] [--json]',
|
|
12
12
|
' harness verify [--category static|unit|integration|e2e|ci|uat] [--staged-files <list>] ' +
|
|
13
|
-
'[--current-branch <b>] [--expected-branch <b>] [--branch-md <path>] [--profile sentropic|stub] [--json]',
|
|
14
|
-
' harness init [--profile sentropic|stub] [--json]',
|
|
15
|
-
' harness audit [--staged-files <list>] [--branch-md <path>] [--profile sentropic|stub] [--json]',
|
|
13
|
+
'[--current-branch <b>] [--expected-branch <b>] [--branch-md <path>] [--profile sentropic|stub] [--profile-file <path>] [--commit-message <text>] [--json]',
|
|
14
|
+
' harness init [--profile sentropic|stub] [--profile-file <path>] [--json]',
|
|
15
|
+
' harness audit [--staged-files <list>] [--branch-md <path>] [--profile sentropic|stub] [--profile-file <path>] [--commit-message <text>] [--json]',
|
|
16
16
|
' harness brainstorm [<topic>] [--peers <n>] [--ladder study|vol|evol] [--json]',
|
|
17
17
|
' harness test [<scope>] [--category unit|integration|e2e] [--watch] [--json]',
|
|
18
18
|
' harness debug [<symptom>] [--json]',
|
|
@@ -28,7 +28,7 @@ function handleCheck(positionals, flags, out) {
|
|
|
28
28
|
out(USAGE);
|
|
29
29
|
return 2;
|
|
30
30
|
}
|
|
31
|
-
const profile =
|
|
31
|
+
const profile = resolveProfile(flags);
|
|
32
32
|
const category = 'static';
|
|
33
33
|
let result;
|
|
34
34
|
let code;
|
|
@@ -76,14 +76,14 @@ function handleCheck(positionals, flags, out) {
|
|
|
76
76
|
return 0;
|
|
77
77
|
}
|
|
78
78
|
/**
|
|
79
|
-
*
|
|
79
|
+
* Arg-based CLI driver — reads profile/plan files, writes via `out`, returns an exit code.
|
|
80
80
|
* No internal git calls (the caller supplies branch + staged files), no `process.exit`, no fs writes.
|
|
81
81
|
* Advisory (D5 Layer A): a failing check returns 0; only a usage error returns non-zero.
|
|
82
82
|
*
|
|
83
83
|
* Verb families: `check` (C1/C2 → VerificationRun); method/recorder verbs (brainstorm/test/debug/
|
|
84
84
|
* review/plan/branch/skills → WorkEvent + skill pointer, see `method-verbs.ts`).
|
|
85
85
|
*/
|
|
86
|
-
|
|
86
|
+
function dispatch(argv, out) {
|
|
87
87
|
const { positionals, flags } = parseFlags(argv);
|
|
88
88
|
const command = positionals[0];
|
|
89
89
|
if (command === 'check') {
|
|
@@ -98,4 +98,15 @@ export function runHarnessCli(argv, out) {
|
|
|
98
98
|
out(USAGE);
|
|
99
99
|
return command === undefined ? 0 : 2;
|
|
100
100
|
}
|
|
101
|
+
export function runHarnessCli(argv, out) {
|
|
102
|
+
try {
|
|
103
|
+
return dispatch(argv, out);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (!(error instanceof ProfileValidationError))
|
|
107
|
+
throw error;
|
|
108
|
+
out(`harness: ${error.message}`);
|
|
109
|
+
return 2;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
101
112
|
//# sourceMappingURL=run.js.map
|
package/dist/cli/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/cli/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,GAAG,EAAkB,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,MAAM,KAAK,GAAG;IACZ,qFAAqF;QACnF,oIAAoI;IACtI,gGAAgG;QAC9F,2JAA2J;IAC7J,iFAAiF;IACjF,yJAAyJ;IACzJ,sFAAsF;IACtF,oFAAoF;IACpF,2CAA2C;IAC3C,uEAAuE;IACvE,oDAAoD;IACpD,sDAAsD;IACtD,qEAAqE;CACtE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,uFAAuF;AACvF,SAAS,WAAW,CAClB,WAAqB,EACrB,KAAgC,EAChC,GAAwB;IAExB,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;QACxC,GAAG,CAAC,KAAK,CAAC,CAAC;QACX,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAmB,cAAc,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAyB,QAAQ,CAAC;IAChD,IAAI,MAAmB,CAAC;IACxB,IAAI,IAAY,CAAC;IACjB,IAAI,YAAoB,CAAC;IAEzB,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;QACpB,IAAI,GAAG,IAAI,CAAC;QACZ,YAAY,GAAG,qBAAqB,CAAC;QACrC,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACrC,GAAG,CAAC,mCAAmC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;YAC7D,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,GAAG,OAAO,CAAC,MAAqB,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,IAAI,CAAC;QACZ,YAAY,GAAG,sBAAsB,CAAC;QACtC,MAAM,GAAG,WAAW,CAAC;YACnB,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,EAAE;YACjD,cAAc,EAAE,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE;YACnD,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QACxB,4FAA4F;QAC5F,MAAM,EAAE,GAAG,0BAA0B,CAAC;QACtC,MAAM,GAAG,GAAG,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE;YAC1D,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,SAAS;YACtC,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,SAAS;YACjD,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK;YAC5B,MAAM,EAAE,SAAS;YACjB,QAAQ;YACR,OAAO,EAAE,YAAY;YACrB,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,EAAE;SACf,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAChE,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU;YAAE,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,IAAc,EAAE,GAAwB;IACxD,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IAE/B,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,OAAO,WAAW,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,cAAc,GAAG,oBAAoB,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IACrE,IAAI,cAAc,KAAK,IAAI;QAAE,OAAO,cAAc,CAAC;IAEnD,MAAM,UAAU,GAAG,gBAAgB,CAAC,WAAW,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAC7D,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAE3C,GAAG,CAAC,KAAK,CAAC,CAAC;IACX,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAc,EAAE,GAAwB;IACpE,IAAI,CAAC;QAAC,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAAC,CAAC;IACnC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,KAAK,YAAY,sBAAsB,CAAC;YAAE,MAAM,KAAK,CAAC;QAC5D,GAAG,CAAC,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjC,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|
package/dist/cli/scope.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/cli/scope.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/cli/scope.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yGAAyG;AACzG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,cAAc,GAAG,YAAY,CAuBtG"}
|
package/dist/cli/scope.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
// Shared scope-check input resolution — used by `check scope`, `verify`, and `audit` so the
|
|
2
2
|
// BRANCH.md parsing + boundary wiring lives in ONE place (no duplicated file IO).
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import { findRepoRoot } from '../profile/resolve.js';
|
|
4
6
|
import { parseBranchMd } from '../branch-md/parse.js';
|
|
5
7
|
import { checkScope } from '../checks/scope-check.js';
|
|
6
8
|
import { list, str } from './args.js';
|
|
7
9
|
/** Resolve `--branch-md` + `--staged-files` into a C2 scope CheckResult (pure but for the file read). */
|
|
8
10
|
export function scopeFromFlags(flags, profile) {
|
|
9
|
-
const
|
|
11
|
+
const explicitPath = str(flags['branch-md']);
|
|
12
|
+
const branchMdPath = explicitPath ?? (profile.branchMd ? resolve(findRepoRoot(), profile.branchMd.file) : undefined);
|
|
10
13
|
let parsed;
|
|
11
|
-
if (branchMdPath) {
|
|
14
|
+
if (branchMdPath && (explicitPath !== undefined || existsSync(branchMdPath))) {
|
|
12
15
|
try {
|
|
13
|
-
parsed = parseBranchMd(readFileSync(branchMdPath, 'utf8'));
|
|
16
|
+
parsed = parseBranchMd(readFileSync(branchMdPath, 'utf8'), profile);
|
|
14
17
|
}
|
|
15
18
|
catch {
|
|
16
19
|
return { unreadable: branchMdPath };
|
|
@@ -25,6 +28,7 @@ export function scopeFromFlags(flags, profile) {
|
|
|
25
28
|
},
|
|
26
29
|
profile,
|
|
27
30
|
declaredExceptions: parsed?.exceptions ?? [],
|
|
31
|
+
commitMessage: str(flags['commit-message']),
|
|
28
32
|
});
|
|
29
33
|
return { result };
|
|
30
34
|
}
|
package/dist/cli/scope.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/cli/scope.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,kFAAkF;AAElF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/cli/scope.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,kFAAkF;AAElF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAkB,MAAM,WAAW,CAAC;AAStD,yGAAyG;AACzG,MAAM,UAAU,cAAc,CAAC,KAAgC,EAAE,OAAuB;IACtF,MAAM,YAAY,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,YAAY,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACrH,IAAI,MAAoD,CAAC;IACzD,IAAI,YAAY,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QAC7E,IAAI,CAAC;YACH,MAAM,GAAG,aAAa,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;QACtC,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,UAAU,CAAC;QACxB,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACxC,QAAQ,EAAE;YACR,OAAO,EAAE,MAAM,EAAE,YAAY,IAAI,EAAE;YACnC,SAAS,EAAE,MAAM,EAAE,cAAc,IAAI,EAAE;YACvC,WAAW,EAAE,MAAM,EAAE,gBAAgB,IAAI,EAAE;SAC5C;QACD,OAAO;QACP,kBAAkB,EAAE,MAAM,EAAE,UAAU,IAAI,EAAE;QAC5C,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;KAC5C,CAAC,CAAC;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,9 @@ export type { WorkEventInput, WorkEventContext } from './run/work-event.js';
|
|
|
8
8
|
export type { HarnessProfile } from './profile/profile.js';
|
|
9
9
|
export { sentropicProfile } from './profile/sentropic.js';
|
|
10
10
|
export { stubProfile } from './profile/stub.js';
|
|
11
|
+
export { parseHarnessProfile, toProfileDocument, ProfileValidationError } from './profile/document.js';
|
|
12
|
+
export type { HarnessProfileDocument, ProfileErrorCode } from './profile/document.js';
|
|
13
|
+
export { resolveProfile, loadProfileFile, findRepoRoot } from './profile/resolve.js';
|
|
11
14
|
export { parseBranchMd } from './branch-md/parse.js';
|
|
12
15
|
export type { ParsedBranchMd, ParsedLot, ParsedLotItem } from './branch-md/parse.js';
|
|
13
16
|
export { classifyPath, matchGlob, globToRegExp } from './scope/scope-boundary.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,sBAAgC,CAAC;AAG7D,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,WAAW,GACZ,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,0CAA0C,CAAC;AAClD,YAAY,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,GACjB,MAAM,0CAA0C,CAAC;AAGlD,YAAY,EACV,SAAS,EACT,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5E,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,sBAAgC,CAAC;AAG7D,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,SAAS,EACT,iBAAiB,EACjB,WAAW,GACZ,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,0CAA0C,CAAC;AAClD,YAAY,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,GACjB,MAAM,0CAA0C,CAAC;AAGlD,YAAY,EACV,SAAS,EACT,aAAa,EACb,eAAe,EACf,cAAc,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAG5E,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACvG,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGrF,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAClF,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG1E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChF,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG/D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@ export { validateVerificationRunV0, deriveVerdict, VERIFICATION_CATEGORIES, VIOL
|
|
|
8
8
|
export { toWorkEvent } from './run/work-event.js';
|
|
9
9
|
export { sentropicProfile } from './profile/sentropic.js';
|
|
10
10
|
export { stubProfile } from './profile/stub.js';
|
|
11
|
+
export { parseHarnessProfile, toProfileDocument, ProfileValidationError } from './profile/document.js';
|
|
12
|
+
export { resolveProfile, loadProfileFile, findRepoRoot } from './profile/resolve.js';
|
|
11
13
|
// BRANCH.md parser.
|
|
12
14
|
export { parseBranchMd } from './branch-md/parse.js';
|
|
13
15
|
// Scope classification.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,gFAAgF;AAChF,mFAAmF;AAEnF,MAAM,CAAC,MAAM,eAAe,GAAG,oBAA6B,CAAC;AAa7D,2FAA2F;AAC3F,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,0CAA0C,CAAC;AAclD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,EAAE;AACF,gFAAgF;AAChF,mFAAmF;AAEnF,MAAM,CAAC,MAAM,eAAe,GAAG,oBAA6B,CAAC;AAa7D,2FAA2F;AAC3F,OAAO,EACL,yBAAyB,EACzB,aAAa,EACb,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,0CAA0C,CAAC;AAclD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEvG,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAErF,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,wBAAwB;AACxB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGlF,uDAAuD;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,6EAA6E;AAC7E,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhF,8EAA8E;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,8BAA8B,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HarnessProfile } from './profile.js';
|
|
2
|
+
/** JSON representation; regular expressions use sources without delimiters or flags. */
|
|
3
|
+
export interface HarnessProfileDocument extends Omit<HarnessProfile, 'exceptionIdPattern'> {
|
|
4
|
+
$schema?: string;
|
|
5
|
+
exceptionIdPattern: string;
|
|
6
|
+
}
|
|
7
|
+
export type ProfileErrorCode = 'UNKNOWN_KEY' | 'INVALID_PROFILE' | 'INVALID_REGEX' | 'PROFILE_READ' | 'PROFILE_JSON' | 'UNKNOWN_PROFILE';
|
|
8
|
+
export declare class ProfileValidationError extends Error {
|
|
9
|
+
readonly code: ProfileErrorCode;
|
|
10
|
+
readonly path: string;
|
|
11
|
+
constructor(code: ProfileErrorCode, path: string, detail: string);
|
|
12
|
+
}
|
|
13
|
+
/** Strict parser: rejects unknown keys at every level and never substitutes another profile. */
|
|
14
|
+
export declare function parseHarnessProfile(value: unknown): HarnessProfile;
|
|
15
|
+
export declare function toProfileDocument(profile: HarnessProfile): HarnessProfileDocument;
|
|
16
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/profile/document.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,wFAAwF;AACxF,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,cAAc,EAAE,oBAAoB,CAAC;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,iBAAiB,GAAG,eAAe,GAChF,cAAc,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAEtD,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,gBAAgB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAA7C,IAAI,EAAE,gBAAgB,EAAW,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAInF;AAkDD,gGAAgG;AAChG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAKlE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,sBAAsB,CAEjF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
export class ProfileValidationError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
path;
|
|
5
|
+
constructor(code, path, detail) {
|
|
6
|
+
super(`${code} at ${path}: ${detail}`);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.path = path;
|
|
9
|
+
this.name = 'ProfileValidationError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
// Validate against the shipped schema itself so the runtime and published contract stay aligned.
|
|
13
|
+
const schema = JSON.parse(readFileSync(new URL('../../schema/harness-profile.schema.json', import.meta.url), 'utf8'));
|
|
14
|
+
function validate(value, rule, path) {
|
|
15
|
+
if (rule.$ref)
|
|
16
|
+
return validate(value, schema.$defs[rule.$ref.split('/').at(-1)], path);
|
|
17
|
+
const invalid = (detail) => { throw new ProfileValidationError('INVALID_PROFILE', path, detail); };
|
|
18
|
+
if (rule.enum && !rule.enum.includes(value))
|
|
19
|
+
invalid(`expected one of ${rule.enum.join(', ')}`);
|
|
20
|
+
if (rule.type === 'object') {
|
|
21
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
22
|
+
invalid('expected an object');
|
|
23
|
+
const object = value;
|
|
24
|
+
for (const key of Object.keys(object)) {
|
|
25
|
+
if (rule.additionalProperties === false && !Object.hasOwn(rule.properties, key)) {
|
|
26
|
+
throw new ProfileValidationError('UNKNOWN_KEY', `${path}.${key}`, 'unknown profile key');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const key of rule.required ?? []) {
|
|
30
|
+
if (!Object.hasOwn(object, key))
|
|
31
|
+
invalid(`missing required key: ${key}`);
|
|
32
|
+
}
|
|
33
|
+
for (const [key, entry] of Object.entries(object))
|
|
34
|
+
validate(entry, rule.properties[key], `${path}.${key}`);
|
|
35
|
+
}
|
|
36
|
+
else if (rule.type === 'array') {
|
|
37
|
+
if (!Array.isArray(value))
|
|
38
|
+
invalid('expected an array');
|
|
39
|
+
value.forEach((entry, index) => validate(entry, rule.items, `${path}[${index}]`));
|
|
40
|
+
}
|
|
41
|
+
else if (rule.type === 'string') {
|
|
42
|
+
if (typeof value !== 'string')
|
|
43
|
+
invalid('expected a string');
|
|
44
|
+
const text = value;
|
|
45
|
+
if (text.length < (rule.minLength ?? 0))
|
|
46
|
+
invalid('expected a nonempty string');
|
|
47
|
+
if (rule.pattern && !new RegExp(rule.pattern).test(text))
|
|
48
|
+
invalid('invalid string format');
|
|
49
|
+
if (rule.format === 'regex') {
|
|
50
|
+
try {
|
|
51
|
+
new RegExp(text);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new ProfileValidationError('INVALID_REGEX', path, 'invalid ECMAScript regular expression');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else if (rule.type === 'boolean' && typeof value !== 'boolean')
|
|
59
|
+
invalid('expected a boolean');
|
|
60
|
+
}
|
|
61
|
+
/** Strict parser: rejects unknown keys at every level and never substitutes another profile. */
|
|
62
|
+
export function parseHarnessProfile(value) {
|
|
63
|
+
validate(value, schema, '$');
|
|
64
|
+
const document = value;
|
|
65
|
+
const { $schema: _schema, ...policy } = document;
|
|
66
|
+
return { ...policy, exceptionIdPattern: new RegExp(document.exceptionIdPattern) };
|
|
67
|
+
}
|
|
68
|
+
export function toProfileDocument(profile) {
|
|
69
|
+
return { ...profile, exceptionIdPattern: profile.exceptionIdPattern.source };
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/profile/document.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,22 @@ export interface HarnessProfile {
|
|
|
3
3
|
id: string;
|
|
4
4
|
/** Globs forbidden by default unless a BRANCH.md explicitly Allows them (C2). */
|
|
5
5
|
forbiddenPathDefaults: string[];
|
|
6
|
+
/** Default scope buckets, used after explicit BRANCH.md scope declarations. */
|
|
7
|
+
allowedPathDefaults?: string[];
|
|
8
|
+
conditionalPathDefaults?: string[];
|
|
9
|
+
/** Optional repository-owned plan conventions (defaults retain the canonical parser). */
|
|
10
|
+
branchMd?: {
|
|
11
|
+
file: string;
|
|
12
|
+
allowedHeading: string;
|
|
13
|
+
forbiddenHeading: string;
|
|
14
|
+
conditionalHeading: string;
|
|
15
|
+
planHeading: string;
|
|
16
|
+
};
|
|
17
|
+
/** ECMAScript regex sources, checked only when a commit message is supplied. */
|
|
18
|
+
commitMessage?: {
|
|
19
|
+
requiredPattern?: string;
|
|
20
|
+
forbiddenPatterns: string[];
|
|
21
|
+
};
|
|
6
22
|
/** Grammar of a valid scope-exception id in BRANCH.md (C2 conditional binding). */
|
|
7
23
|
exceptionIdPattern: RegExp;
|
|
8
24
|
/** When true, a Conditional path may be touched only if a matching exception id exists (C2). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/profile/profile.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,mFAAmF;IACnF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gGAAgG;IAChG,4BAA4B,EAAE,OAAO,CAAC;IACtC,sEAAsE;IACtE,WAAW,EAAE,OAAO,GAAG,QAAQ,CAAC;CACjC"}
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/profile/profile.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,cAAc;IAC7B,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IACnC,yFAAyF;IACzF,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;QACzB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,gFAAgF;IAChF,aAAa,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC1E,mFAAmF;IACnF,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gGAAgG;IAChG,4BAA4B,EAAE,OAAO,CAAC;IACtC,sEAAsE;IACtE,WAAW,EAAE,OAAO,GAAG,QAAQ,CAAC;CACjC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HarnessProfile } from './profile.js';
|
|
2
|
+
/** Works for ordinary repositories and worktrees (.git may be a file), without spawning git. */
|
|
3
|
+
export declare function findRepoRoot(cwd?: string): string;
|
|
4
|
+
export declare function loadProfileFile(path: string): HarnessProfile;
|
|
5
|
+
/** Resolve explicit built-in > explicit file > root discovery > sentropic. */
|
|
6
|
+
export declare function resolveProfile(flags: Record<string, unknown>, cwd?: string): HarnessProfile;
|
|
7
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/profile/resolve.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGnD,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,GAAG,SAAgB,GAAG,MAAM,CAMxD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAQ5D;AASD,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,SAAgB,GAAG,cAAc,CAiBlG"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { existsSync, lstatSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { sentropicProfile } from './sentropic.js';
|
|
4
|
+
import { stubProfile } from './stub.js';
|
|
5
|
+
import { parseHarnessProfile, ProfileValidationError } from './document.js';
|
|
6
|
+
/** Works for ordinary repositories and worktrees (.git may be a file), without spawning git. */
|
|
7
|
+
export function findRepoRoot(cwd = process.cwd()) {
|
|
8
|
+
const start = resolve(cwd);
|
|
9
|
+
for (let directory = start;; directory = dirname(directory)) {
|
|
10
|
+
if (existsSync(join(directory, '.git')))
|
|
11
|
+
return directory;
|
|
12
|
+
if (dirname(directory) === directory)
|
|
13
|
+
return start;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function loadProfileFile(path) {
|
|
17
|
+
let text;
|
|
18
|
+
try {
|
|
19
|
+
text = readFileSync(path, 'utf8');
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new ProfileValidationError('PROFILE_READ', path, 'cannot read profile file');
|
|
23
|
+
}
|
|
24
|
+
let document;
|
|
25
|
+
try {
|
|
26
|
+
document = JSON.parse(text);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
throw new ProfileValidationError('PROFILE_JSON', path, 'invalid JSON');
|
|
30
|
+
}
|
|
31
|
+
return parseHarnessProfile(document);
|
|
32
|
+
}
|
|
33
|
+
function flagValue(value, flag) {
|
|
34
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
35
|
+
throw new ProfileValidationError('INVALID_PROFILE', flag, 'expected a nonempty value');
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
/** Resolve explicit built-in > explicit file > root discovery > sentropic. */
|
|
40
|
+
export function resolveProfile(flags, cwd = process.cwd()) {
|
|
41
|
+
if (flags.profile !== undefined) {
|
|
42
|
+
const name = flagValue(flags.profile, '--profile');
|
|
43
|
+
if (name === 'sentropic')
|
|
44
|
+
return sentropicProfile;
|
|
45
|
+
if (name === 'stub')
|
|
46
|
+
return stubProfile;
|
|
47
|
+
throw new ProfileValidationError('UNKNOWN_PROFILE', '--profile', `unknown built-in profile: ${name}`);
|
|
48
|
+
}
|
|
49
|
+
if (flags['profile-file'] !== undefined) {
|
|
50
|
+
return loadProfileFile(resolve(cwd, flagValue(flags['profile-file'], '--profile-file')));
|
|
51
|
+
}
|
|
52
|
+
const path = join(findRepoRoot(cwd), 'harness.profile.json');
|
|
53
|
+
try {
|
|
54
|
+
lstatSync(path);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error.code === 'ENOENT')
|
|
58
|
+
return sentropicProfile;
|
|
59
|
+
throw new ProfileValidationError('PROFILE_READ', path, 'cannot inspect profile file');
|
|
60
|
+
}
|
|
61
|
+
return loadProfileFile(path);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/profile/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,7 +14,8 @@ export declare function matchGlob(glob: string, path: string): boolean;
|
|
|
14
14
|
* forbidden globs (C2 scope-check core).
|
|
15
15
|
*
|
|
16
16
|
* Precedence (first match wins):
|
|
17
|
-
* explicit allowed > explicit forbidden > explicit conditional >
|
|
17
|
+
* explicit allowed > explicit forbidden > explicit conditional >
|
|
18
|
+
* profile default-forbidden > profile default-conditional > profile default-allowed > unknown
|
|
18
19
|
*
|
|
19
20
|
* `allowed` wins over `forbidden` so an explicitly-granted subtree (e.g. `packages/harness/**`)
|
|
20
21
|
* is `allowed` even when a broader `packages/**` is forbidden — the Allowed list is the granted
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-boundary.d.ts","sourceRoot":"","sources":["../../src/scope/scope-boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAE5E,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,iGAAiG;AACjG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBjD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED
|
|
1
|
+
{"version":3,"file":"scope-boundary.d.ts","sourceRoot":"","sources":["../../src/scope/scope-boundary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,aAAa,GAAG,SAAS,CAAC;AAE5E,gFAAgF;AAChF,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,iGAAiG;AACjG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBjD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,cAAc,GACtB,SAAS,CAQX"}
|
|
@@ -29,7 +29,8 @@ export function matchGlob(glob, path) {
|
|
|
29
29
|
* forbidden globs (C2 scope-check core).
|
|
30
30
|
*
|
|
31
31
|
* Precedence (first match wins):
|
|
32
|
-
* explicit allowed > explicit forbidden > explicit conditional >
|
|
32
|
+
* explicit allowed > explicit forbidden > explicit conditional >
|
|
33
|
+
* profile default-forbidden > profile default-conditional > profile default-allowed > unknown
|
|
33
34
|
*
|
|
34
35
|
* `allowed` wins over `forbidden` so an explicitly-granted subtree (e.g. `packages/harness/**`)
|
|
35
36
|
* is `allowed` even when a broader `packages/**` is forbidden — the Allowed list is the granted
|
|
@@ -45,6 +46,10 @@ export function classifyPath(path, boundary, profile) {
|
|
|
45
46
|
return 'conditional';
|
|
46
47
|
if (profile.forbiddenPathDefaults.some((g) => matchGlob(g, path)))
|
|
47
48
|
return 'forbidden';
|
|
49
|
+
if (profile.conditionalPathDefaults?.some((g) => matchGlob(g, path)))
|
|
50
|
+
return 'conditional';
|
|
51
|
+
if (profile.allowedPathDefaults?.some((g) => matchGlob(g, path)))
|
|
52
|
+
return 'allowed';
|
|
48
53
|
return 'unknown';
|
|
49
54
|
}
|
|
50
55
|
//# sourceMappingURL=scope-boundary.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-boundary.js","sourceRoot":"","sources":["../../src/scope/scope-boundary.ts"],"names":[],"mappings":"AAWA,iGAAiG;AACjG,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACxB,EAAE,IAAI,IAAI,CAAC;gBACX,CAAC,EAAE,CAAC;YACN,CAAC;iBAAM,CAAC;gBACN,EAAE,IAAI,OAAO,CAAC;YAChB,CAAC;QACH,CAAC;aAAM,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,EAAE,IAAI,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAY;IAClD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"scope-boundary.js","sourceRoot":"","sources":["../../src/scope/scope-boundary.ts"],"names":[],"mappings":"AAWA,iGAAiG;AACjG,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACxB,EAAE,IAAI,IAAI,CAAC;gBACX,CAAC,EAAE,CAAC;YACN,CAAC;iBAAM,CAAC;gBACN,EAAE,IAAI,OAAO,CAAC;YAChB,CAAC;QACH,CAAC;aAAM,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YACzC,EAAE,IAAI,IAAI,GAAG,CAAC,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,EAAE,IAAI,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAY;IAClD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,QAAuB,EACvB,OAAuB;IAEvB,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACvE,IAAI,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,WAAW,CAAC;IAC3E,IAAI,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,aAAa,CAAC;IAC/E,IAAI,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,WAAW,CAAC;IACtF,IAAI,OAAO,CAAC,uBAAuB,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,aAAa,CAAC;IAC3F,IAAI,OAAO,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACnF,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentropic/harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Neutral, host-agnostic code-work / PR-workflow tooling for AI dev: a homogeneous `harness <verb>` method layer (branch/scope/verify/test/debug/review/brainstorm/plan), the native superpowers replacement. Tooling-only, zero product-runtime deps. (BR-42h)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/rhanka/sentropic/packages/harness/schema/harness-profile.schema.json",
|
|
4
|
+
"title": "Harness repository profile",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["id", "forbiddenPathDefaults", "exceptionIdPattern", "conditionalRequiresException", "branchMatch"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": { "type": "string", "minLength": 1 },
|
|
10
|
+
"id": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
11
|
+
"forbiddenPathDefaults": { "$ref": "#/$defs/globs" },
|
|
12
|
+
"allowedPathDefaults": { "$ref": "#/$defs/globs" },
|
|
13
|
+
"conditionalPathDefaults": { "$ref": "#/$defs/globs" },
|
|
14
|
+
"exceptionIdPattern": { "$ref": "#/$defs/regex" },
|
|
15
|
+
"conditionalRequiresException": { "type": "boolean" },
|
|
16
|
+
"branchMatch": { "enum": ["exact", "prefix"] },
|
|
17
|
+
"branchMd": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"additionalProperties": false,
|
|
20
|
+
"required": ["file", "allowedHeading", "forbiddenHeading", "conditionalHeading", "planHeading"],
|
|
21
|
+
"properties": {
|
|
22
|
+
"file": { "$ref": "#/$defs/path" },
|
|
23
|
+
"allowedHeading": { "$ref": "#/$defs/heading" },
|
|
24
|
+
"forbiddenHeading": { "$ref": "#/$defs/heading" },
|
|
25
|
+
"conditionalHeading": { "$ref": "#/$defs/heading" },
|
|
26
|
+
"planHeading": { "$ref": "#/$defs/heading" }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"commitMessage": {
|
|
30
|
+
"type": "object",
|
|
31
|
+
"additionalProperties": false,
|
|
32
|
+
"required": ["forbiddenPatterns"],
|
|
33
|
+
"properties": {
|
|
34
|
+
"requiredPattern": { "$ref": "#/$defs/regex" },
|
|
35
|
+
"forbiddenPatterns": { "type": "array", "items": { "$ref": "#/$defs/regex" } }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"$defs": {
|
|
40
|
+
"globs": { "type": "array", "items": { "$ref": "#/$defs/path" } },
|
|
41
|
+
"path": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"minLength": 1,
|
|
44
|
+
"pattern": "^(?!/)(?![A-Za-z]:)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*\\\\)\\S.*$"
|
|
45
|
+
},
|
|
46
|
+
"regex": { "type": "string", "minLength": 1, "format": "regex" },
|
|
47
|
+
"heading": { "type": "string", "minLength": 1, "pattern": "^[^\\r\\n]+$" }
|
|
48
|
+
}
|
|
49
|
+
}
|