@rasensio/aidlc 1.16.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/compliance.d.ts +36 -0
- package/dist/commands/compliance.d.ts.map +1 -0
- package/dist/commands/compliance.js +275 -0
- package/dist/commands/compliance.js.map +1 -0
- package/dist/commands/constitution.d.ts +26 -0
- package/dist/commands/constitution.d.ts.map +1 -0
- package/dist/commands/constitution.js +145 -0
- package/dist/commands/constitution.js.map +1 -0
- package/dist/commands/cost.d.ts.map +1 -1
- package/dist/commands/cost.js +54 -35
- package/dist/commands/cost.js.map +1 -1
- package/dist/commands/doctor.js +7 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/gate.d.ts.map +1 -1
- package/dist/commands/gate.js +13 -0
- package/dist/commands/gate.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +119 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/metrics.d.ts.map +1 -1
- package/dist/commands/metrics.js +6 -1
- package/dist/commands/metrics.js.map +1 -1
- package/dist/commands/review.d.ts +2 -27
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +10 -166
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +7 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/transition.d.ts.map +1 -1
- package/dist/commands/transition.js +24 -1
- package/dist/commands/transition.js.map +1 -1
- package/dist/compile/adapters/claude-code.d.ts.map +1 -1
- package/dist/compile/adapters/claude-code.js +2 -1
- package/dist/compile/adapters/claude-code.js.map +1 -1
- package/dist/compile/adapters/codex.d.ts +22 -1
- package/dist/compile/adapters/codex.d.ts.map +1 -1
- package/dist/compile/adapters/codex.js +61 -27
- package/dist/compile/adapters/codex.js.map +1 -1
- package/dist/compile/adapters/cursor.d.ts.map +1 -1
- package/dist/compile/adapters/cursor.js +2 -19
- package/dist/compile/adapters/cursor.js.map +1 -1
- package/dist/compile/adapters/kiro.d.ts.map +1 -1
- package/dist/compile/adapters/kiro.js +1 -19
- package/dist/compile/adapters/kiro.js.map +1 -1
- package/dist/compile/adapters/windsurf.d.ts.map +1 -1
- package/dist/compile/adapters/windsurf.js +2 -1
- package/dist/compile/adapters/windsurf.js.map +1 -1
- package/dist/compile/guidance-install.d.ts +16 -19
- package/dist/compile/guidance-install.d.ts.map +1 -1
- package/dist/compile/guidance-install.js +26 -111
- package/dist/compile/guidance-install.js.map +1 -1
- package/dist/compile/layer-install.d.ts +122 -0
- package/dist/compile/layer-install.d.ts.map +1 -0
- package/dist/compile/layer-install.js +195 -0
- package/dist/compile/layer-install.js.map +1 -0
- package/dist/compile/loaders.d.ts +14 -0
- package/dist/compile/loaders.d.ts.map +1 -1
- package/dist/compile/loaders.js +23 -18
- package/dist/compile/loaders.js.map +1 -1
- package/dist/compile/skill-format.d.ts +39 -0
- package/dist/compile/skill-format.d.ts.map +1 -0
- package/dist/compile/skill-format.js +50 -0
- package/dist/compile/skill-format.js.map +1 -0
- package/dist/compliance/check.d.ts +79 -0
- package/dist/compliance/check.d.ts.map +1 -0
- package/dist/compliance/check.js +224 -0
- package/dist/compliance/check.js.map +1 -0
- package/dist/compliance/config.d.ts +91 -0
- package/dist/compliance/config.d.ts.map +1 -0
- package/dist/compliance/config.js +173 -0
- package/dist/compliance/config.js.map +1 -0
- package/dist/compliance/findings.d.ts +70 -0
- package/dist/compliance/findings.d.ts.map +1 -0
- package/dist/compliance/findings.js +132 -0
- package/dist/compliance/findings.js.map +1 -0
- package/dist/compliance/gate-criterion.d.ts +87 -0
- package/dist/compliance/gate-criterion.d.ts.map +1 -0
- package/dist/compliance/gate-criterion.js +168 -0
- package/dist/compliance/gate-criterion.js.map +1 -0
- package/dist/compliance/install.d.ts +135 -0
- package/dist/compliance/install.d.ts.map +1 -0
- package/dist/compliance/install.js +291 -0
- package/dist/compliance/install.js.map +1 -0
- package/dist/compliance/report.d.ts +144 -0
- package/dist/compliance/report.d.ts.map +1 -0
- package/dist/compliance/report.js +347 -0
- package/dist/compliance/report.js.map +1 -0
- package/dist/compliance/resolver.d.ts +65 -0
- package/dist/compliance/resolver.d.ts.map +1 -0
- package/dist/compliance/resolver.js +176 -0
- package/dist/compliance/resolver.js.map +1 -0
- package/dist/compliance/schema.d.ts +74 -0
- package/dist/compliance/schema.d.ts.map +1 -0
- package/dist/compliance/schema.js +474 -0
- package/dist/compliance/schema.js.map +1 -0
- package/dist/compliance/types.d.ts +140 -0
- package/dist/compliance/types.d.ts.map +1 -0
- package/dist/compliance/types.js +29 -0
- package/dist/compliance/types.js.map +1 -0
- package/dist/constitution/check.d.ts +22 -0
- package/dist/constitution/check.d.ts.map +1 -0
- package/dist/constitution/check.js +89 -0
- package/dist/constitution/check.js.map +1 -0
- package/dist/constitution/docx.d.ts +51 -0
- package/dist/constitution/docx.d.ts.map +1 -0
- package/dist/constitution/docx.js +157 -0
- package/dist/constitution/docx.js.map +1 -0
- package/dist/constitution/entries.d.ts +27 -0
- package/dist/constitution/entries.d.ts.map +1 -0
- package/dist/constitution/entries.js +65 -0
- package/dist/constitution/entries.js.map +1 -0
- package/dist/constitution/extract.d.ts +34 -0
- package/dist/constitution/extract.d.ts.map +1 -0
- package/dist/constitution/extract.js +117 -0
- package/dist/constitution/extract.js.map +1 -0
- package/dist/constitution/snapshot.d.ts +47 -0
- package/dist/constitution/snapshot.d.ts.map +1 -0
- package/dist/constitution/snapshot.js +159 -0
- package/dist/constitution/snapshot.js.map +1 -0
- package/dist/constitution/statements.d.ts +37 -0
- package/dist/constitution/statements.d.ts.map +1 -0
- package/dist/constitution/statements.js +64 -0
- package/dist/constitution/statements.js.map +1 -0
- package/dist/constitution/types.d.ts +80 -0
- package/dist/constitution/types.d.ts.map +1 -0
- package/dist/constitution/types.js +9 -0
- package/dist/constitution/types.js.map +1 -0
- package/dist/core/gate.d.ts +10 -0
- package/dist/core/gate.d.ts.map +1 -1
- package/dist/core/gate.js.map +1 -1
- package/dist/core/paths.d.ts +48 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +57 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/types.d.ts +12 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/cost/hooks/registry.d.ts +44 -0
- package/dist/cost/hooks/registry.d.ts.map +1 -0
- package/dist/cost/hooks/registry.js +66 -0
- package/dist/cost/hooks/registry.js.map +1 -0
- package/dist/cost/pin.d.ts +63 -0
- package/dist/cost/pin.d.ts.map +1 -0
- package/dist/cost/pin.js +95 -0
- package/dist/cost/pin.js.map +1 -0
- package/dist/cost/providers/claude-code.d.ts +9 -2
- package/dist/cost/providers/claude-code.d.ts.map +1 -1
- package/dist/cost/providers/claude-code.js +10 -5
- package/dist/cost/providers/claude-code.js.map +1 -1
- package/dist/cost/providers/codex.d.ts +107 -0
- package/dist/cost/providers/codex.d.ts.map +1 -0
- package/dist/cost/providers/codex.js +283 -0
- package/dist/cost/providers/codex.js.map +1 -0
- package/dist/cost/providers/index.d.ts.map +1 -1
- package/dist/cost/providers/index.js +6 -0
- package/dist/cost/providers/index.js.map +1 -1
- package/dist/cost/rates.d.ts.map +1 -1
- package/dist/cost/rates.js +14 -0
- package/dist/cost/rates.js.map +1 -1
- package/dist/cost/report.d.ts +23 -1
- package/dist/cost/report.d.ts.map +1 -1
- package/dist/cost/report.js +26 -5
- package/dist/cost/report.js.map +1 -1
- package/dist/cost/sessions.d.ts +10 -1
- package/dist/cost/sessions.d.ts.map +1 -1
- package/dist/cost/sessions.js +10 -2
- package/dist/cost/sessions.js.map +1 -1
- package/dist/cost/sync.d.ts.map +1 -1
- package/dist/cost/sync.js +190 -5
- package/dist/cost/sync.js.map +1 -1
- package/dist/doctor/migrations/compliance-pack-drift.d.ts +62 -0
- package/dist/doctor/migrations/compliance-pack-drift.d.ts.map +1 -0
- package/dist/doctor/migrations/compliance-pack-drift.js +255 -0
- package/dist/doctor/migrations/compliance-pack-drift.js.map +1 -0
- package/dist/doctor/migrations/index.d.ts.map +1 -1
- package/dist/doctor/migrations/index.js +11 -0
- package/dist/doctor/migrations/index.js.map +1 -1
- package/dist/doctor/migrations/legacy-cost-hooks.d.ts.map +1 -1
- package/dist/doctor/migrations/legacy-cost-hooks.js +7 -4
- package/dist/doctor/migrations/legacy-cost-hooks.js.map +1 -1
- package/dist/doctor/migrations/missing-cost-shim.d.ts.map +1 -1
- package/dist/doctor/migrations/missing-cost-shim.js +5 -4
- package/dist/doctor/migrations/missing-cost-shim.js.map +1 -1
- package/dist/doctor/migrations/outdated-cost-hooks.d.ts.map +1 -1
- package/dist/doctor/migrations/outdated-cost-hooks.js +7 -4
- package/dist/doctor/migrations/outdated-cost-hooks.js.map +1 -1
- package/dist/doctor/runner.js +14 -0
- package/dist/doctor/runner.js.map +1 -1
- package/dist/doctor/types.d.ts +35 -3
- package/dist/doctor/types.d.ts.map +1 -1
- package/dist/menu/roster.d.ts.map +1 -1
- package/dist/menu/roster.js +5 -0
- package/dist/menu/roster.js.map +1 -1
- package/dist/metrics/report.d.ts.map +1 -1
- package/dist/metrics/report.js +11 -2
- package/dist/metrics/report.js.map +1 -1
- package/dist/review/findings-parser.d.ts +92 -0
- package/dist/review/findings-parser.d.ts.map +1 -0
- package/dist/review/findings-parser.js +196 -0
- package/dist/review/findings-parser.js.map +1 -0
- package/dist/setup/setup-compute.d.ts +10 -15
- package/dist/setup/setup-compute.d.ts.map +1 -1
- package/dist/setup/setup-compute.js +39 -0
- package/dist/setup/setup-compute.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `aidlc compliance check` — assess a change against installed pack controls.
|
|
3
|
+
*
|
|
4
|
+
* **The central rule: absence of assessment is never a pass.**
|
|
5
|
+
*
|
|
6
|
+
* A control's `fails_when` is prose, pinned per control by a human, and no code
|
|
7
|
+
* evaluates prose. So controls declare `check_kind`: a `mechanical` control carries
|
|
8
|
+
* a `pattern` this module applies to the diff itself; an `agent` control can only be
|
|
9
|
+
* assessed in a review session, and its outcome is read from the compliance findings
|
|
10
|
+
* stream.
|
|
11
|
+
*
|
|
12
|
+
* The failure mode this design exists to prevent: if `check` merely read the
|
|
13
|
+
* agent-written stream, then in continuous integration — no agent, no
|
|
14
|
+
* `*.compliance.md` — it would find nothing wrong and exit 0 on every change. The
|
|
15
|
+
* exit-1 gate could never fire, and the surface a buyer pays for would be
|
|
16
|
+
* permanently, silently green. So an unassessed control is reported as
|
|
17
|
+
* `pending-agent-review`, and under `--enforce` that exits 2 rather than 0.
|
|
18
|
+
*
|
|
19
|
+
* `--enforce` is per-invocation and reads no config. `compliance.enforce` governs
|
|
20
|
+
* phase transitions only. One key for both would mean a team wanting a failing
|
|
21
|
+
* pull-request check had to also accept blocking every local phase transition.
|
|
22
|
+
*
|
|
23
|
+
* Exit codes:
|
|
24
|
+
* 0 nothing failing and nothing pending, or advisory mode
|
|
25
|
+
* 1 a failing critical control under `--enforce`
|
|
26
|
+
* 2 usage error, pack-load error, or an unassessed control under `--enforce`
|
|
27
|
+
*
|
|
28
|
+
* Requirements: compliance-packs/AC-35, AC-36, AC-79, AC-80, AC-86, AC-87,
|
|
29
|
+
* AC-102, AC-103
|
|
30
|
+
*/
|
|
31
|
+
import type { Control } from './types.js';
|
|
32
|
+
/** What was established about one control for this change. */
|
|
33
|
+
export type ControlOutcome = {
|
|
34
|
+
control: string;
|
|
35
|
+
packId: string;
|
|
36
|
+
status: 'no-issues';
|
|
37
|
+
how: 'mechanical' | 'agent';
|
|
38
|
+
} | {
|
|
39
|
+
control: string;
|
|
40
|
+
packId: string;
|
|
41
|
+
status: 'failing';
|
|
42
|
+
how: 'mechanical' | 'agent';
|
|
43
|
+
severity: Control['severity'];
|
|
44
|
+
detail: string;
|
|
45
|
+
} | {
|
|
46
|
+
control: string;
|
|
47
|
+
packId: string;
|
|
48
|
+
status: 'pending-agent-review';
|
|
49
|
+
how: 'agent';
|
|
50
|
+
};
|
|
51
|
+
/** Result of a check run. */
|
|
52
|
+
export interface CheckResult {
|
|
53
|
+
/** One outcome per applicable control. */
|
|
54
|
+
controls: ControlOutcome[];
|
|
55
|
+
/** Whether `--enforce` was passed. */
|
|
56
|
+
enforce: boolean;
|
|
57
|
+
/** Non-fatal problems worth printing. */
|
|
58
|
+
warnings: string[];
|
|
59
|
+
/** Fatal problems: an installed pack that will not load. */
|
|
60
|
+
errors: string[];
|
|
61
|
+
/** The git ref the diff was taken against, or null for the working tree. */
|
|
62
|
+
diffRef: string | null;
|
|
63
|
+
exitCode: 0 | 1 | 2;
|
|
64
|
+
}
|
|
65
|
+
export interface CheckOptions {
|
|
66
|
+
/** Assess the diff against this git ref instead of the working tree. */
|
|
67
|
+
diffRef?: string;
|
|
68
|
+
/** Raise the exit code on a failing or unassessed control. */
|
|
69
|
+
enforce?: boolean;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check a change against every installed pack's controls.
|
|
73
|
+
*
|
|
74
|
+
* Never throws. A pack that will not load is an error and exit 2, never an empty
|
|
75
|
+
* result — a check that reported nothing wrong because it could not read its own
|
|
76
|
+
* rules would be the worst possible outcome.
|
|
77
|
+
*/
|
|
78
|
+
export declare function checkDiff(projectRoot: string, opts?: CheckOptions): CheckResult;
|
|
79
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/compliance/check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AASH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GACtB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAA;CAAE,GACrF;IACE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC;IAC5B,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtF,6BAA6B;AAC7B,MAAM,WAAW,WAAW;IAC1B,0CAA0C;IAC1C,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,4DAA4D;IAC5D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,4EAA4E;IAC5E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAwFD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,WAAW,CAgHnF"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `aidlc compliance check` — assess a change against installed pack controls.
|
|
3
|
+
*
|
|
4
|
+
* **The central rule: absence of assessment is never a pass.**
|
|
5
|
+
*
|
|
6
|
+
* A control's `fails_when` is prose, pinned per control by a human, and no code
|
|
7
|
+
* evaluates prose. So controls declare `check_kind`: a `mechanical` control carries
|
|
8
|
+
* a `pattern` this module applies to the diff itself; an `agent` control can only be
|
|
9
|
+
* assessed in a review session, and its outcome is read from the compliance findings
|
|
10
|
+
* stream.
|
|
11
|
+
*
|
|
12
|
+
* The failure mode this design exists to prevent: if `check` merely read the
|
|
13
|
+
* agent-written stream, then in continuous integration — no agent, no
|
|
14
|
+
* `*.compliance.md` — it would find nothing wrong and exit 0 on every change. The
|
|
15
|
+
* exit-1 gate could never fire, and the surface a buyer pays for would be
|
|
16
|
+
* permanently, silently green. So an unassessed control is reported as
|
|
17
|
+
* `pending-agent-review`, and under `--enforce` that exits 2 rather than 0.
|
|
18
|
+
*
|
|
19
|
+
* `--enforce` is per-invocation and reads no config. `compliance.enforce` governs
|
|
20
|
+
* phase transitions only. One key for both would mean a team wanting a failing
|
|
21
|
+
* pull-request check had to also accept blocking every local phase transition.
|
|
22
|
+
*
|
|
23
|
+
* Exit codes:
|
|
24
|
+
* 0 nothing failing and nothing pending, or advisory mode
|
|
25
|
+
* 1 a failing critical control under `--enforce`
|
|
26
|
+
* 2 usage error, pack-load error, or an unassessed control under `--enforce`
|
|
27
|
+
*
|
|
28
|
+
* Requirements: compliance-packs/AC-35, AC-36, AC-79, AC-80, AC-86, AC-87,
|
|
29
|
+
* AC-102, AC-103
|
|
30
|
+
*/
|
|
31
|
+
import { execFileSync } from 'node:child_process';
|
|
32
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
33
|
+
import { join } from 'node:path';
|
|
34
|
+
import { readComplianceConfig } from './config.js';
|
|
35
|
+
import { parseComplianceFindings } from './findings.js';
|
|
36
|
+
import { resolvePack } from './resolver.js';
|
|
37
|
+
/**
|
|
38
|
+
* The diff text to assess.
|
|
39
|
+
*
|
|
40
|
+
* Working tree by default, so a developer can check before committing. A git failure
|
|
41
|
+
* yields null, which is reported rather than silently treated as an empty diff — an
|
|
42
|
+
* empty diff would make every mechanical control pass.
|
|
43
|
+
*/
|
|
44
|
+
function readDiff(projectRoot, ref) {
|
|
45
|
+
const args = ref === null ? ['diff', '--unified=0'] : ['diff', '--unified=0', ref];
|
|
46
|
+
try {
|
|
47
|
+
return execFileSync('git', args, {
|
|
48
|
+
cwd: projectRoot,
|
|
49
|
+
encoding: 'utf8',
|
|
50
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
51
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/** Added lines of a unified diff, without the leading `+`. */
|
|
59
|
+
function addedLines(diff) {
|
|
60
|
+
return diff
|
|
61
|
+
.split('\n')
|
|
62
|
+
.filter((line) => line.startsWith('+') && !line.startsWith('+++'))
|
|
63
|
+
.map((line) => line.slice(1));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Agent-assessed outcomes, read from every compliance findings file in the project.
|
|
67
|
+
*
|
|
68
|
+
* Keyed by control id. A control cleared in one artifact and failing in another
|
|
69
|
+
* resolves to failing — the worse reading wins, because a check that reported the
|
|
70
|
+
* kinder of two answers would be worth nothing.
|
|
71
|
+
*/
|
|
72
|
+
function agentOutcomes(projectRoot) {
|
|
73
|
+
const byControl = new Map();
|
|
74
|
+
const warnings = [];
|
|
75
|
+
const stateDir = join(projectRoot, '.aidlc', 'state');
|
|
76
|
+
if (!existsSync(stateDir))
|
|
77
|
+
return { byControl, warnings };
|
|
78
|
+
for (const instance of readdirSync(stateDir).sort()) {
|
|
79
|
+
const instanceDir = join(stateDir, instance);
|
|
80
|
+
let entries;
|
|
81
|
+
try {
|
|
82
|
+
entries = readdirSync(instanceDir);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
for (const entry of entries.filter((f) => f.endsWith('.compliance.md'))) {
|
|
88
|
+
let file;
|
|
89
|
+
try {
|
|
90
|
+
file = parseComplianceFindings(readFileSync(join(instanceDir, entry), 'utf8'));
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
warnings.push(`${instance}/${entry} is unreadable (${err.message})`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
warnings.push(...file.warnings.map((w) => `${instance}/${entry}: ${w}`));
|
|
97
|
+
for (const id of file.cleared) {
|
|
98
|
+
if (!byControl.has(id))
|
|
99
|
+
byControl.set(id, { status: 'no-issues' });
|
|
100
|
+
}
|
|
101
|
+
for (const finding of file.findings) {
|
|
102
|
+
if (finding.control === undefined)
|
|
103
|
+
continue;
|
|
104
|
+
if (finding.status !== 'open' || finding.placeholder === true)
|
|
105
|
+
continue;
|
|
106
|
+
// Failing always overrides a cleared reading from elsewhere.
|
|
107
|
+
byControl.set(finding.control, {
|
|
108
|
+
status: 'failing',
|
|
109
|
+
severity: finding.severity,
|
|
110
|
+
detail: finding.issue ?? finding.title,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return { byControl, warnings };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check a change against every installed pack's controls.
|
|
119
|
+
*
|
|
120
|
+
* Never throws. A pack that will not load is an error and exit 2, never an empty
|
|
121
|
+
* result — a check that reported nothing wrong because it could not read its own
|
|
122
|
+
* rules would be the worst possible outcome.
|
|
123
|
+
*/
|
|
124
|
+
export function checkDiff(projectRoot, opts = {}) {
|
|
125
|
+
const enforce = opts.enforce === true;
|
|
126
|
+
const diffRef = opts.diffRef ?? null;
|
|
127
|
+
const warnings = [];
|
|
128
|
+
const errors = [];
|
|
129
|
+
const config = readComplianceConfig(projectRoot);
|
|
130
|
+
if (config.packs.length === 0) {
|
|
131
|
+
return {
|
|
132
|
+
controls: [],
|
|
133
|
+
enforce,
|
|
134
|
+
warnings,
|
|
135
|
+
errors,
|
|
136
|
+
diffRef,
|
|
137
|
+
exitCode: 0,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const applicable = [];
|
|
141
|
+
for (const record of config.packs) {
|
|
142
|
+
const resolved = resolvePack(record.id);
|
|
143
|
+
if (!resolved.ok) {
|
|
144
|
+
errors.push(`installed pack '${record.id}' did not load: ${resolved.error.errors.join('; ')}`);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
for (const control of resolved.pack.controls) {
|
|
148
|
+
applicable.push({ packId: record.id, control });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (errors.length > 0) {
|
|
152
|
+
return { controls: [], enforce, warnings, errors, diffRef, exitCode: 2 };
|
|
153
|
+
}
|
|
154
|
+
const diff = readDiff(projectRoot, diffRef);
|
|
155
|
+
if (diff === null) {
|
|
156
|
+
// Not a git repository, or a bad ref. Mechanical controls cannot be assessed, and
|
|
157
|
+
// treating that as "nothing matched" would report a pass nobody earned.
|
|
158
|
+
warnings.push(diffRef === null
|
|
159
|
+
? 'could not read a diff — mechanical controls cannot be assessed here'
|
|
160
|
+
: `could not read a diff against '${diffRef}' — mechanical controls cannot be assessed`);
|
|
161
|
+
}
|
|
162
|
+
const added = diff === null ? null : addedLines(diff);
|
|
163
|
+
const { byControl, warnings: agentWarnings } = agentOutcomes(projectRoot);
|
|
164
|
+
warnings.push(...agentWarnings);
|
|
165
|
+
const controls = [];
|
|
166
|
+
for (const { packId, control } of applicable) {
|
|
167
|
+
// An agent assessment always wins: a human looked at this control against this
|
|
168
|
+
// change, which is strictly better evidence than a pattern match.
|
|
169
|
+
const assessed = byControl.get(control.id);
|
|
170
|
+
if (assessed?.status === 'failing') {
|
|
171
|
+
controls.push({
|
|
172
|
+
control: control.id,
|
|
173
|
+
packId,
|
|
174
|
+
status: 'failing',
|
|
175
|
+
how: 'agent',
|
|
176
|
+
severity: assessed.severity ?? control.severity,
|
|
177
|
+
detail: assessed.detail ?? control.fails_when,
|
|
178
|
+
});
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (control.check_kind === 'mechanical' && control.pattern !== undefined) {
|
|
182
|
+
if (added === null) {
|
|
183
|
+
// No diff to match against. Not a pass.
|
|
184
|
+
controls.push({ control: control.id, packId, status: 'pending-agent-review', how: 'agent' });
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const re = new RegExp(control.pattern);
|
|
188
|
+
const hit = added.find((line) => re.test(line));
|
|
189
|
+
if (hit !== undefined) {
|
|
190
|
+
controls.push({
|
|
191
|
+
control: control.id,
|
|
192
|
+
packId,
|
|
193
|
+
status: 'failing',
|
|
194
|
+
how: 'mechanical',
|
|
195
|
+
severity: control.severity,
|
|
196
|
+
detail: `${control.fails_when} — matched an added line`,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
controls.push({ control: control.id, packId, status: 'no-issues', how: 'mechanical' });
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (assessed?.status === 'no-issues') {
|
|
205
|
+
controls.push({ control: control.id, packId, status: 'no-issues', how: 'agent' });
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
controls.push({ control: control.id, packId, status: 'pending-agent-review', how: 'agent' });
|
|
209
|
+
}
|
|
210
|
+
const failingCritical = controls.some((c) => c.status === 'failing' && c.severity === 'critical');
|
|
211
|
+
const pending = controls.some((c) => c.status === 'pending-agent-review');
|
|
212
|
+
// Advisory mode reports everything and exits 0. Under enforcement, a failing
|
|
213
|
+
// critical control is 1 and an unassessed control is 2 — the continuous-integration
|
|
214
|
+
// case, where exiting 0 would be a silent false green.
|
|
215
|
+
let exitCode = 0;
|
|
216
|
+
if (enforce) {
|
|
217
|
+
if (failingCritical)
|
|
218
|
+
exitCode = 1;
|
|
219
|
+
else if (pending)
|
|
220
|
+
exitCode = 2;
|
|
221
|
+
}
|
|
222
|
+
return { controls, enforce, warnings, errors, diffRef, exitCode };
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/compliance/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `compliance:` section of `.aidlc/config.yaml`.
|
|
3
|
+
*
|
|
4
|
+
* Owns one section and nothing else. There is no central config loader in this
|
|
5
|
+
* codebase — ten call sites each join the path and parse it inline — and unifying
|
|
6
|
+
* them is out of scope here, so this module is deliberately narrow rather than an
|
|
7
|
+
* eleventh ad-hoc parse pretending to be general.
|
|
8
|
+
*
|
|
9
|
+
* The record shape exists to answer three questions no other state can:
|
|
10
|
+
*
|
|
11
|
+
* - **Is this layer locally edited?** By comparing the on-disk hash against the
|
|
12
|
+
* hash recorded *at install*. Comparing against the currently bundled body —
|
|
13
|
+
* what the framework path does, correctly, for its own layers — would make every
|
|
14
|
+
* installed layer read as edited the moment pack content is updated upstream, so
|
|
15
|
+
* `remove` would refuse to delete anything and corrected control text would never
|
|
16
|
+
* land.
|
|
17
|
+
* - **Which instances does a report cover?** By comparing each instance's
|
|
18
|
+
* completion moment against `installed_at`. A pack cannot evidence a change that
|
|
19
|
+
* predates it.
|
|
20
|
+
* - **Is an installed pack stale?** By comparing `version` against the resolvable
|
|
21
|
+
* one. Reported, never silently upgraded.
|
|
22
|
+
*
|
|
23
|
+
* Requirements: compliance-packs/AC-70, AC-71
|
|
24
|
+
*/
|
|
25
|
+
import type { ModifiedDetector } from '../compile/layer-install.js';
|
|
26
|
+
/** One installed file, with the hash it had when it was written. */
|
|
27
|
+
export interface InstalledFile {
|
|
28
|
+
/** Filename within `.aidlc/guidance/`, as registered. */
|
|
29
|
+
path: string;
|
|
30
|
+
/** Hex sha256 of the bytes written at install. */
|
|
31
|
+
sha256: string;
|
|
32
|
+
}
|
|
33
|
+
/** One installed pack, as recorded in the project config. */
|
|
34
|
+
export interface InstalledPack {
|
|
35
|
+
id: string;
|
|
36
|
+
/** Pack content version at the time of install. */
|
|
37
|
+
version: string;
|
|
38
|
+
/** ISO 8601 UTC. Bounds the report's default scope. */
|
|
39
|
+
installed_at: string;
|
|
40
|
+
files: InstalledFile[];
|
|
41
|
+
}
|
|
42
|
+
/** The `compliance:` section. */
|
|
43
|
+
export interface ComplianceConfig {
|
|
44
|
+
/**
|
|
45
|
+
* Whether a critical control finding blocks a phase transition.
|
|
46
|
+
*
|
|
47
|
+
* Governs transitions only. The diff check takes `--enforce` per invocation, so
|
|
48
|
+
* a team can have a failing continuous-integration check without also blocking
|
|
49
|
+
* every local phase transition.
|
|
50
|
+
*/
|
|
51
|
+
enforce: boolean;
|
|
52
|
+
packs: InstalledPack[];
|
|
53
|
+
}
|
|
54
|
+
/** The empty state: no packs, no enforcement. Distinct from "no section at all". */
|
|
55
|
+
export declare const EMPTY_COMPLIANCE: ComplianceConfig;
|
|
56
|
+
/** Hex sha256 of a string, as written to disk. */
|
|
57
|
+
export declare function hashContent(content: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Read the `compliance:` section.
|
|
60
|
+
*
|
|
61
|
+
* A malformed section reads as empty rather than throwing, because every consumer
|
|
62
|
+
* of this — the gate criterion, the report, the check — must degrade to "no packs
|
|
63
|
+
* installed" rather than break an unrelated command. A malformed section is
|
|
64
|
+
* reported by `aidlc doctor`, which is where a repair belongs.
|
|
65
|
+
*/
|
|
66
|
+
export declare function readComplianceConfig(projectRoot: string): ComplianceConfig;
|
|
67
|
+
/**
|
|
68
|
+
* Write the `compliance:` section, leaving every other section untouched.
|
|
69
|
+
*
|
|
70
|
+
* The whole document is read, one key is replaced, and the document is written
|
|
71
|
+
* back — so a hand-added section survives, the same guarantee `computeSetup` gives
|
|
72
|
+
* for the sections it does not own.
|
|
73
|
+
*/
|
|
74
|
+
export declare function writeComplianceConfig(projectRoot: string, config: ComplianceConfig): void;
|
|
75
|
+
/** The record for one installed pack, or null when it is not installed. */
|
|
76
|
+
export declare function findInstalledPack(config: ComplianceConfig, id: string): InstalledPack | null;
|
|
77
|
+
/**
|
|
78
|
+
* A modified-detector that compares against the hash recorded at install.
|
|
79
|
+
*
|
|
80
|
+
* This is the pack rule, and it is the reason `installLayers` takes the detector
|
|
81
|
+
* as a parameter rather than hard-coding one. `bundledBodyDiffers` answers "does
|
|
82
|
+
* this differ from what we ship *now*", which for a pack conflates "the user
|
|
83
|
+
* edited it" with "we published a new version".
|
|
84
|
+
*
|
|
85
|
+
* A file with no recorded hash counts as modified: we have no evidence we wrote
|
|
86
|
+
* it, so it is not ours to delete.
|
|
87
|
+
*/
|
|
88
|
+
export declare function recordedHashDiffers(pack: InstalledPack | null): ModifiedDetector;
|
|
89
|
+
/** True when the pack is installed and its recorded version differs from `available`. */
|
|
90
|
+
export declare function isStale(pack: InstalledPack | null, available: string): boolean;
|
|
91
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/compliance/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,oEAAoE;AACpE,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,6DAA6D;AAC7D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,iCAAiC;AACjC,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,oFAAoF;AACpF,eAAO,MAAM,gBAAgB,EAAE,gBAAgD,CAAC;AAEhF,kDAAkD;AAClD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAwCD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAW1E;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAkBzF;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAE5F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,GAAG,gBAAgB,CAchF;AAeD,yFAAyF;AACzF,wBAAgB,OAAO,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAE9E"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `compliance:` section of `.aidlc/config.yaml`.
|
|
3
|
+
*
|
|
4
|
+
* Owns one section and nothing else. There is no central config loader in this
|
|
5
|
+
* codebase — ten call sites each join the path and parse it inline — and unifying
|
|
6
|
+
* them is out of scope here, so this module is deliberately narrow rather than an
|
|
7
|
+
* eleventh ad-hoc parse pretending to be general.
|
|
8
|
+
*
|
|
9
|
+
* The record shape exists to answer three questions no other state can:
|
|
10
|
+
*
|
|
11
|
+
* - **Is this layer locally edited?** By comparing the on-disk hash against the
|
|
12
|
+
* hash recorded *at install*. Comparing against the currently bundled body —
|
|
13
|
+
* what the framework path does, correctly, for its own layers — would make every
|
|
14
|
+
* installed layer read as edited the moment pack content is updated upstream, so
|
|
15
|
+
* `remove` would refuse to delete anything and corrected control text would never
|
|
16
|
+
* land.
|
|
17
|
+
* - **Which instances does a report cover?** By comparing each instance's
|
|
18
|
+
* completion moment against `installed_at`. A pack cannot evidence a change that
|
|
19
|
+
* predates it.
|
|
20
|
+
* - **Is an installed pack stale?** By comparing `version` against the resolvable
|
|
21
|
+
* one. Reported, never silently upgraded.
|
|
22
|
+
*
|
|
23
|
+
* Requirements: compliance-packs/AC-70, AC-71
|
|
24
|
+
*/
|
|
25
|
+
import { createHash } from 'node:crypto';
|
|
26
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
import { parse as parseYaml } from 'yaml';
|
|
29
|
+
import { serializeYaml } from '../state/yaml-helpers.js';
|
|
30
|
+
/** The empty state: no packs, no enforcement. Distinct from "no section at all". */
|
|
31
|
+
export const EMPTY_COMPLIANCE = { enforce: false, packs: [] };
|
|
32
|
+
/** Hex sha256 of a string, as written to disk. */
|
|
33
|
+
export function hashContent(content) {
|
|
34
|
+
return createHash('sha256').update(content, 'utf8').digest('hex');
|
|
35
|
+
}
|
|
36
|
+
/** Absolute path of a project's config file. */
|
|
37
|
+
function configPath(projectRoot) {
|
|
38
|
+
return join(projectRoot, '.aidlc', 'config.yaml');
|
|
39
|
+
}
|
|
40
|
+
/** Read the whole config document, or an empty object when absent or unusable. */
|
|
41
|
+
function readConfigDocument(projectRoot) {
|
|
42
|
+
const path = configPath(projectRoot);
|
|
43
|
+
if (!existsSync(path))
|
|
44
|
+
return {};
|
|
45
|
+
try {
|
|
46
|
+
const parsed = parseYaml(readFileSync(path, 'utf8'));
|
|
47
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
|
|
48
|
+
return {};
|
|
49
|
+
return parsed;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return {};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Narrow an unknown value to an `InstalledFile`, or null. */
|
|
56
|
+
function toInstalledFile(raw) {
|
|
57
|
+
if (typeof raw !== 'object' || raw === null)
|
|
58
|
+
return null;
|
|
59
|
+
const r = raw;
|
|
60
|
+
if (typeof r.path !== 'string' || typeof r.sha256 !== 'string')
|
|
61
|
+
return null;
|
|
62
|
+
return { path: r.path, sha256: r.sha256 };
|
|
63
|
+
}
|
|
64
|
+
/** Narrow an unknown value to an `InstalledPack`, or null. */
|
|
65
|
+
function toInstalledPack(raw) {
|
|
66
|
+
if (typeof raw !== 'object' || raw === null)
|
|
67
|
+
return null;
|
|
68
|
+
const r = raw;
|
|
69
|
+
if (typeof r.id !== 'string' || typeof r.version !== 'string')
|
|
70
|
+
return null;
|
|
71
|
+
if (typeof r.installed_at !== 'string')
|
|
72
|
+
return null;
|
|
73
|
+
const files = Array.isArray(r.files)
|
|
74
|
+
? r.files.map(toInstalledFile).filter((f) => f !== null)
|
|
75
|
+
: [];
|
|
76
|
+
return { id: r.id, version: r.version, installed_at: r.installed_at, files };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Read the `compliance:` section.
|
|
80
|
+
*
|
|
81
|
+
* A malformed section reads as empty rather than throwing, because every consumer
|
|
82
|
+
* of this — the gate criterion, the report, the check — must degrade to "no packs
|
|
83
|
+
* installed" rather than break an unrelated command. A malformed section is
|
|
84
|
+
* reported by `aidlc doctor`, which is where a repair belongs.
|
|
85
|
+
*/
|
|
86
|
+
export function readComplianceConfig(projectRoot) {
|
|
87
|
+
const doc = readConfigDocument(projectRoot);
|
|
88
|
+
const section = doc.compliance;
|
|
89
|
+
if (typeof section !== 'object' || section === null || Array.isArray(section)) {
|
|
90
|
+
return { ...EMPTY_COMPLIANCE, packs: [] };
|
|
91
|
+
}
|
|
92
|
+
const s = section;
|
|
93
|
+
const packs = Array.isArray(s.packs)
|
|
94
|
+
? s.packs.map(toInstalledPack).filter((p) => p !== null)
|
|
95
|
+
: [];
|
|
96
|
+
return { enforce: s.enforce === true, packs };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Write the `compliance:` section, leaving every other section untouched.
|
|
100
|
+
*
|
|
101
|
+
* The whole document is read, one key is replaced, and the document is written
|
|
102
|
+
* back — so a hand-added section survives, the same guarantee `computeSetup` gives
|
|
103
|
+
* for the sections it does not own.
|
|
104
|
+
*/
|
|
105
|
+
export function writeComplianceConfig(projectRoot, config) {
|
|
106
|
+
const doc = readConfigDocument(projectRoot);
|
|
107
|
+
if (config.packs.length === 0 && !config.enforce) {
|
|
108
|
+
// No packs and no enforcement is indistinguishable from never having had a
|
|
109
|
+
// section, and an empty stanza invites the question of what it means.
|
|
110
|
+
delete doc.compliance;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
doc.compliance = {
|
|
114
|
+
enforce: config.enforce,
|
|
115
|
+
packs: config.packs.map((p) => ({
|
|
116
|
+
id: p.id,
|
|
117
|
+
version: p.version,
|
|
118
|
+
installed_at: p.installed_at,
|
|
119
|
+
files: p.files.map((f) => ({ path: f.path, sha256: f.sha256 })),
|
|
120
|
+
})),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
writeFileSync(configPath(projectRoot), serializeYaml(doc), 'utf8');
|
|
124
|
+
}
|
|
125
|
+
/** The record for one installed pack, or null when it is not installed. */
|
|
126
|
+
export function findInstalledPack(config, id) {
|
|
127
|
+
return config.packs.find((p) => p.id === id) ?? null;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A modified-detector that compares against the hash recorded at install.
|
|
131
|
+
*
|
|
132
|
+
* This is the pack rule, and it is the reason `installLayers` takes the detector
|
|
133
|
+
* as a parameter rather than hard-coding one. `bundledBodyDiffers` answers "does
|
|
134
|
+
* this differ from what we ship *now*", which for a pack conflates "the user
|
|
135
|
+
* edited it" with "we published a new version".
|
|
136
|
+
*
|
|
137
|
+
* A file with no recorded hash counts as modified: we have no evidence we wrote
|
|
138
|
+
* it, so it is not ours to delete.
|
|
139
|
+
*/
|
|
140
|
+
export function recordedHashDiffers(pack) {
|
|
141
|
+
const byPath = new Map((pack?.files ?? []).map((f) => [f.path, f.sha256]));
|
|
142
|
+
return (targetPath) => {
|
|
143
|
+
const recorded = byPath.get(basenameOf(targetPath));
|
|
144
|
+
if (recorded === undefined)
|
|
145
|
+
return true;
|
|
146
|
+
let actual;
|
|
147
|
+
try {
|
|
148
|
+
actual = hashContent(readFileSync(targetPath, 'utf8'));
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Unreadable now, so not safely ours to act on.
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return actual !== recorded;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The registered filename of a target path.
|
|
159
|
+
*
|
|
160
|
+
* Recorded paths are the `file` values from a pack's index — relative names inside
|
|
161
|
+
* `.aidlc/guidance/` — while the detector receives an absolute path. Matching on
|
|
162
|
+
* the trailing segments keeps the two comparable without either side needing to
|
|
163
|
+
* know the project root.
|
|
164
|
+
*/
|
|
165
|
+
function basenameOf(targetPath) {
|
|
166
|
+
const parts = targetPath.split(/[\\/]/);
|
|
167
|
+
return parts[parts.length - 1] ?? targetPath;
|
|
168
|
+
}
|
|
169
|
+
/** True when the pack is installed and its recorded version differs from `available`. */
|
|
170
|
+
export function isStale(pack, available) {
|
|
171
|
+
return pack !== null && pack.version !== available;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/compliance/config.ts"],"names":[],"mappings":"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"}
|