aienvmp 0.1.59 → 0.1.61
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/BUGFIXES.md +12 -0
- package/CHANGELOG.md +17 -0
- package/README.md +1 -0
- package/action.yml +32 -0
- package/package.json +1 -1
- package/src/commands/summary.js +2 -0
- package/src/contract.js +3 -2
- package/src/enforcement.js +21 -0
- package/src/preflight.js +1 -0
- package/src/render.js +2 -1
package/BUGFIXES.md
CHANGED
|
@@ -4,6 +4,12 @@ Short record of bugs, fixes, and follow-up checks.
|
|
|
4
4
|
|
|
5
5
|
## 2026-07-08
|
|
6
6
|
|
|
7
|
+
### GitHub Action hid strict-plan guidance inside artifacts
|
|
8
|
+
|
|
9
|
+
- Issue: the Action produced `doctor.json` and `summary.md`, but the recommended local/CI strict commands were not visible as a dedicated Step Summary block.
|
|
10
|
+
- Fix: the Action now appends an `aienvmp strict plan` section sourced from advisory doctor metadata, using a temporary payload when `write-doctor-json` is disabled.
|
|
11
|
+
- Verification: Action regression tests check the strict-plan block, `strictPlan` source, CI command, and temporary-file fallback.
|
|
12
|
+
|
|
7
13
|
### CLI version was hardcoded
|
|
8
14
|
|
|
9
15
|
- Issue: `npm run smoke` printed `0.1.0` after the package version changed.
|
|
@@ -148,6 +154,12 @@ Short record of bugs, fixes, and follow-up checks.
|
|
|
148
154
|
- Fix: `aiDependencyReview` now includes `statusReason` and `securityConfidence`, and generation reuses the computed risk summary instead of recalculating a weaker review signal.
|
|
149
155
|
- Verification: regression tests cover scanner-off confidence, dashboard/summary rendering, schema metadata, and standalone SBOM fallback behavior; local sync smoke confirmed `scanner-off` appears in generated artifacts.
|
|
150
156
|
|
|
157
|
+
### Strict mode guidance required too much inference
|
|
158
|
+
|
|
159
|
+
- Issue: AI and CI consumers could see scoped strict results, but still had to infer which `doctor --strict` command should be used without disrupting local operation.
|
|
160
|
+
- Fix: `strictPlan` now provides local advisory command, recommended strict scope, CI command, all-scope command, scope statuses, and the strict-use rule.
|
|
161
|
+
- Verification: regression tests cover enforcement advice, doctor JSON, status/context, summary, dashboard, and schema outputs; local sync smoke confirmed summary emits the CI strict command.
|
|
162
|
+
|
|
151
163
|
## Template
|
|
152
164
|
|
|
153
165
|
### Title
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.61
|
|
4
|
+
|
|
5
|
+
- Added an `aienvmp strict plan` block to the GitHub Action Step Summary.
|
|
6
|
+
- Reused advisory `doctor --json` data so CI can show local and strict commands without forcing failure.
|
|
7
|
+
- Preserved `write-doctor-json: false` by using a temporary advisory doctor payload when only the summary needs strict guidance.
|
|
8
|
+
- Documented the Action Step Summary strict-plan surface in the README.
|
|
9
|
+
- Added regression coverage for the Action strict-plan summary contract.
|
|
10
|
+
|
|
11
|
+
## 0.1.60
|
|
12
|
+
|
|
13
|
+
- Added `enforcement.strictPlan` to help AI agents and CI choose the narrowest explicit strict scope.
|
|
14
|
+
- Added `preflight.enforcementProfile.strictPlan` so status/context consumers see the same strict guidance.
|
|
15
|
+
- Added CI strict command output to `.aienvmp/summary.md`.
|
|
16
|
+
- Added strict-plan CI command and rule display to the dashboard Enforcement Mode card.
|
|
17
|
+
- Documented strict-plan consumption in `schema --json` and README.
|
|
18
|
+
- Added regression tests for enforcement advice, doctor JSON, status/context, summary, dashboard, and schema outputs.
|
|
19
|
+
|
|
3
20
|
## 0.1.59
|
|
4
21
|
|
|
5
22
|
- Added `aiDependencyReview.statusReason` so AI agents can distinguish actual review risk from scanner-off uncertainty.
|
package/README.md
CHANGED
|
@@ -98,6 +98,7 @@ aienvmp doctor --strict security|policy|coordination|all
|
|
|
98
98
|
## CI
|
|
99
99
|
|
|
100
100
|
The GitHub Action writes status, summary, schema, doctor, plan, SBOM, and dashboard artifacts. `strict: "off"` reports warnings without failing the job.
|
|
101
|
+
The Step Summary includes an `aienvmp strict plan` block so humans and AI agents can pick the narrowest CI strict scope without parsing the full artifacts.
|
|
101
102
|
|
|
102
103
|
```yaml
|
|
103
104
|
- uses: soovwv/aienvmp@main
|
package/action.yml
CHANGED
|
@@ -91,6 +91,38 @@ runs:
|
|
|
91
91
|
fi
|
|
92
92
|
fi
|
|
93
93
|
|
|
94
|
+
- name: Append strict plan summary
|
|
95
|
+
shell: bash
|
|
96
|
+
run: |
|
|
97
|
+
if [ "${{ inputs.write-summary }}" = "true" ] && [ -n "$GITHUB_STEP_SUMMARY" ]; then
|
|
98
|
+
mkdir -p "${{ inputs.directory }}/.aienvmp"
|
|
99
|
+
plan_source="${{ inputs.directory }}/.aienvmp/doctor.json"
|
|
100
|
+
if [ ! -f "$plan_source" ]; then
|
|
101
|
+
plan_source="$(mktemp)"
|
|
102
|
+
node "$GITHUB_ACTION_PATH/bin/aienvmp.js" doctor --dir "${{ inputs.directory }}" --json > "$plan_source"
|
|
103
|
+
fi
|
|
104
|
+
node - "$plan_source" "$GITHUB_STEP_SUMMARY" <<'NODE'
|
|
105
|
+
const fs = require("node:fs");
|
|
106
|
+
|
|
107
|
+
const [doctorPath, summaryPath] = process.argv.slice(2);
|
|
108
|
+
const doctor = JSON.parse(fs.readFileSync(doctorPath, "utf8"));
|
|
109
|
+
const plan = doctor.enforcement?.strictPlan || {};
|
|
110
|
+
const local = plan.localDefault || "aienvmp doctor --json";
|
|
111
|
+
const ci = plan.ciCommand || "aienvmp doctor --strict all --json";
|
|
112
|
+
const rule = plan.rule || "Strict failure is explicit only.";
|
|
113
|
+
|
|
114
|
+
fs.appendFileSync(summaryPath, [
|
|
115
|
+
"",
|
|
116
|
+
"## aienvmp strict plan",
|
|
117
|
+
"",
|
|
118
|
+
`- local: \`${local}\``,
|
|
119
|
+
`- ci: \`${ci}\``,
|
|
120
|
+
`- rule: ${rule}`,
|
|
121
|
+
""
|
|
122
|
+
].join("\n"));
|
|
123
|
+
NODE
|
|
124
|
+
fi
|
|
125
|
+
|
|
94
126
|
- name: Doctor
|
|
95
127
|
shell: bash
|
|
96
128
|
run: |
|
package/package.json
CHANGED
package/src/commands/summary.js
CHANGED
|
@@ -56,6 +56,7 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
56
56
|
const aiSignals = toList(aiReadiness.signals).slice(0, 5);
|
|
57
57
|
const aiNext = aiReadiness.next || "Run aienvmp context --json for details.";
|
|
58
58
|
const aiDependencyReview = manifest.lightSbom?.aiDependencyReview || {};
|
|
59
|
+
const strictPlan = status.enforcementProfile?.strictPlan || status.enforcement?.strictPlan || {};
|
|
59
60
|
|
|
60
61
|
return [
|
|
61
62
|
"# aienvmp summary",
|
|
@@ -66,6 +67,7 @@ export function renderSummary(status = {}, manifest = {}) {
|
|
|
66
67
|
`- AI safe local work: ${toList(aiReadiness.safeProjectLocalActions)[0] || "read artifacts and avoid environment changes until reviewed"}`,
|
|
67
68
|
`- AI read first: ${readFirst}, then ${detail}`,
|
|
68
69
|
`- mode: advisory by default; strict is opt-in with ${strict}`,
|
|
70
|
+
`- CI strict: ${strictPlan.ciCommand || `${strict} --json`}`,
|
|
69
71
|
"",
|
|
70
72
|
`- state: ${status.state || "unknown"}`,
|
|
71
73
|
`- workspace: ${workspace}`,
|
package/src/contract.js
CHANGED
|
@@ -29,7 +29,7 @@ export function schemaContract() {
|
|
|
29
29
|
},
|
|
30
30
|
context: {
|
|
31
31
|
command: "aienvmp context --json",
|
|
32
|
-
rootFields: ["status", "preflight", "aiReadiness", "coordination", "agentPointers", "decision", "recommendedActions", "workspace", "dependencySnapshot", "lightSbom", "warnings"]
|
|
32
|
+
rootFields: ["status", "preflight", "aiReadiness", "coordination", "agentPointers", "decision", "enforcement", "recommendedActions", "workspace", "dependencySnapshot", "lightSbom", "warnings"]
|
|
33
33
|
},
|
|
34
34
|
handoff: {
|
|
35
35
|
command: "aienvmp handoff --json",
|
|
@@ -55,7 +55,8 @@ export function schemaContract() {
|
|
|
55
55
|
stability: "additive",
|
|
56
56
|
consumerRule: "Ignore unknown fields. Do not require optional fields unless listed in requiredFields.",
|
|
57
57
|
localBehavior: "read-only; this command does not scan, install, update, or lock anything.",
|
|
58
|
-
aiReadinessRule: "When aiReadiness.level is review, project-local code work may still continue if aiReadiness.projectLocalWork is allowed; environment changes should follow intent/review guidance."
|
|
58
|
+
aiReadinessRule: "When aiReadiness.level is review, project-local code work may still continue if aiReadiness.projectLocalWork is allowed; environment changes should follow intent/review guidance.",
|
|
59
|
+
strictPlanRule: "Use enforcement.strictPlan or preflight.enforcementProfile.strictPlan to choose the narrowest explicit strict scope for CI."
|
|
59
60
|
}
|
|
60
61
|
};
|
|
61
62
|
}
|
package/src/enforcement.js
CHANGED
|
@@ -33,6 +33,7 @@ export function enforcementAdvice(warnings = []) {
|
|
|
33
33
|
gate: enforcementGate(""),
|
|
34
34
|
suggestedStrictScopes,
|
|
35
35
|
scopes: scopeResults,
|
|
36
|
+
strictPlan: strictScopePlan(suggestedStrictScopes, scopeResults),
|
|
36
37
|
recommendedCommand: suggestedStrictScopes.length
|
|
37
38
|
? `aienvmp doctor --strict ${suggestedStrictScopes[0]}`
|
|
38
39
|
: "aienvmp doctor --strict all",
|
|
@@ -40,6 +41,26 @@ export function enforcementAdvice(warnings = []) {
|
|
|
40
41
|
};
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
export function strictScopePlan(suggestedStrictScopes = [], scopeResults = []) {
|
|
45
|
+
const firstScope = suggestedStrictScopes[0] || "all";
|
|
46
|
+
return {
|
|
47
|
+
mode: "advisory-local-strict-ci",
|
|
48
|
+
localDefault: "aienvmp doctor --json",
|
|
49
|
+
recommendedStrictScope: firstScope,
|
|
50
|
+
recommendedStrictCommand: `aienvmp doctor --strict ${firstScope}`,
|
|
51
|
+
ciCommand: `aienvmp doctor --strict ${firstScope} --json`,
|
|
52
|
+
allScopesCommand: "aienvmp doctor --strict all --json",
|
|
53
|
+
scopeStatuses: scopeResults.map((item) => ({
|
|
54
|
+
scope: item.scope,
|
|
55
|
+
status: item.status,
|
|
56
|
+
matchedWarningCodes: item.matchedWarningCodes || []
|
|
57
|
+
})),
|
|
58
|
+
rule: suggestedStrictScopes.length
|
|
59
|
+
? "Use the narrowest failing strict scope first; keep local operation advisory unless CI or the user explicitly requests failure."
|
|
60
|
+
: "No scope currently fails; use --strict all only for explicit CI health checks."
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
43
64
|
export function enforcementGate(scope = "") {
|
|
44
65
|
const strictScope = normalizeStrictScope(scope);
|
|
45
66
|
return {
|
package/src/preflight.js
CHANGED
|
@@ -36,6 +36,7 @@ export function buildPreflight(manifest = {}, warnings = [], intents = [], timel
|
|
|
36
36
|
gate: enforcementGate(""),
|
|
37
37
|
reason: "Avoid disrupting shared servers or developer machines while still making drift visible.",
|
|
38
38
|
recommendedStrictCommand: enforcement.recommendedCommand,
|
|
39
|
+
strictPlan: enforcement.strictPlan,
|
|
39
40
|
strictCommands: [
|
|
40
41
|
"aienvmp doctor --strict security",
|
|
41
42
|
"aienvmp doctor --strict policy",
|
package/src/render.js
CHANGED
|
@@ -473,7 +473,8 @@ const ciReadinessHtml=ciReadiness.length?'<table>'+ciReadiness.map(s=>\`<tr><th>
|
|
|
473
473
|
const enforcementProfile=manifest.preflight?.enforcementProfile||{};
|
|
474
474
|
const strictCommands=enforcementProfile.strictCommands||[];
|
|
475
475
|
const gate=enforcementProfile.gate||{};
|
|
476
|
-
const
|
|
476
|
+
const strictPlan=enforcementProfile.strictPlan||{};
|
|
477
|
+
const enforcementHtml=\`<table><tr><th>Default</th><td><code>\${esc(gate.defaultMode||enforcementProfile.defaultMode||'advisory')}</code> \${esc(gate.localDefault||'warn-only')}</td></tr><tr><th>Strict</th><td><code>\${esc(gate.strictMode||'off')}</code></td></tr><tr><th>Fail</th><td>\${esc(gate.failCondition||'never in default mode')}</td></tr><tr><th>Exit</th><td>\${esc(gate.exitCode||'0 unless the command itself errors')}</td></tr><tr><th>Recommended</th><td><code>\${esc(strictPlan.recommendedStrictCommand||enforcementProfile.recommendedStrictCommand||'aienvmp doctor --strict all')}</code></td></tr><tr><th>CI</th><td><code>\${esc(strictPlan.ciCommand||'aienvmp doctor --strict all --json')}</code></td></tr></table><div class="timeline">\${strictCommands.slice(0,4).map(cmd=>\`<div class="event"><time>CI</time><div><code>\${esc(cmd)}</code></div></div>\`).join('')}</div><div class="path">\${esc(strictPlan.rule||gate.rule||enforcementProfile.reason||'Warnings stay advisory unless strict mode is requested.')}</div>\`;
|
|
477
478
|
const contract=manifest.preflight?.contract||{};
|
|
478
479
|
const contractHtml=contract.name?\`<table><tr><th>Name</th><td><code>\${esc(contract.name)}</code></td></tr><tr><th>Version</th><td><code>\${esc(contract.version||1)}</code></td></tr><tr><th>Stability</th><td><code>\${esc(contract.stability||'additive')}</code></td></tr><tr><th>AI fields</th><td>\${esc((contract.aiEntryFields||[]).join(', ')||'none')}</td></tr></table><div class="path">\${esc(contract.rule||'Ignore unknown fields.')}</div>\`:'<div class="okline">Run <code>aienvmp status --write</code> to include AI contract metadata.</div>';
|
|
479
480
|
const intentTargets=manifest.preflight?.intentTargets||[];
|