aienvmp 0.1.17 → 0.1.18

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.18
4
+
5
+ - Added a dashboard remediation steps card backed by `.aienvmp/plan.json`.
6
+ - Kept dashboard remediation details bounded to package, severity, fix version, and advisory references.
7
+ - Improved human visibility for AI-generated read-only security plans.
8
+
3
9
  ## 0.1.17
4
10
 
5
11
  - Added bounded security remediation steps to `aienvmp plan`.
package/README.md CHANGED
@@ -38,7 +38,7 @@ AIENV.md
38
38
  .aienvmp/timeline.jsonl
39
39
  .aienvmp/plan.json
40
40
  .aienvmp/plan.md
41
- .aienvmp/dashboard.html
41
+ .aienvmp/dashboard.html # includes plan and remediation cards
42
42
  ```
43
43
 
44
44
  Trust states are machine-readable: `observed`, `planned`, `changed`, `review`, `verified`, `stale`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aienvmp",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
4
4
  "description": "AI-first environment maps and lightweight runtime SBOMs for shared development machines.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,8 @@ export async function dashWorkspace(args) {
18
18
  const policy = await loadPolicy(dir);
19
19
  const warnings = [...diagnose(manifest, { timeline, intents }), ...policyWarnings(manifest, policy)];
20
20
  const planArtifacts = await detectedPlanArtifacts(dir);
21
- const html = renderDashboard({ ...manifest, recommendedActions: recommendedActions(manifest, { warnings, intents }), planArtifacts }, timeline, warnings, intents, policy);
21
+ const planRemediation = await detectedPlanRemediation(dir);
22
+ const html = renderDashboard({ ...manifest, recommendedActions: recommendedActions(manifest, { warnings, intents }), planArtifacts, planRemediation }, timeline, warnings, intents, policy);
22
23
  const out = dashboardPath(dir);
23
24
  await fs.mkdir(path.dirname(out), { recursive: true });
24
25
  await fs.writeFile(out, html, "utf8");
@@ -36,6 +37,17 @@ async function detectedPlanArtifacts(dir) {
36
37
  };
37
38
  }
38
39
 
40
+ async function detectedPlanRemediation(dir) {
41
+ const plan = await readJson(planJsonPath(dir), {});
42
+ return (plan.remediationSteps || []).slice(0, 5).map((item) => ({
43
+ package: item.package || "unknown",
44
+ severity: item.severity || "unknown",
45
+ fixVersions: Array.isArray(item.fixVersions) ? item.fixVersions.slice(0, 3) : [],
46
+ fixAvailable: item.fixAvailable === true,
47
+ advisories: Array.isArray(item.advisories) ? item.advisories.map((advisory) => advisory.id || advisory.title).filter(Boolean).slice(0, 2) : []
48
+ }));
49
+ }
50
+
39
51
  function openFile(file) {
40
52
  if (process.platform === "win32") {
41
53
  execFile("cmd", ["/c", "start", "", file], { windowsHide: true });
package/src/render.js CHANGED
@@ -278,6 +278,10 @@ const actions=manifest.recommendedActions||[];
278
278
  const actionsHtml=actions.length?'<div class="timeline">'+actions.slice(0,6).map(a=>\`<div class="event"><time>\${esc(a.priority)}</time><div><b>\${esc(a.category)}</b> \${esc(a.summary)}\${a.command?\`<div class="path">\${esc(a.command)}</div>\`:''}</div></div>\`).join('')+'</div>':'<div class="okline">No recommended actions. Continue project-local work.</div>';
279
279
  const plan=manifest.planArtifacts||{};
280
280
  const planHtml=plan.markdown||plan.json?\`<table><tr><th>Markdown</th><td>\${plan.markdown?'<a href="plan.md">plan.md</a>':'not written'}</td></tr><tr><th>JSON</th><td>\${plan.json?'<a href="plan.json">plan.json</a>':'not written'}</td></tr></table>\`:'<div class="okline">No plan artifacts yet. Run <code>aienvmp plan --write</code>.</div>';
281
+ const remediation=manifest.planRemediation||[];
282
+ const remediationFix=r=>r.fixVersions?.length?\`fix \${r.fixVersions.join(', ')}\`:(r.fixAvailable?'fix available':'review required');
283
+ const remediationRefs=r=>r.advisories?.length?\` - \${r.advisories.join(', ')}\`:'';
284
+ const remediationHtml=remediation.length?'<div class="timeline">'+remediation.map(r=>\`<div class="event"><time>\${esc(r.severity)}</time><div><b>\${esc(r.package)}</b> \${esc(remediationFix(r))}\${esc(remediationRefs(r))}</div></div>\`).join('')+'</div>':'<div class="okline">No remediation steps in the current plan.</div>';
281
285
  const card=(title,badge,body)=>\`<section class="card"><div class="card-head"><h2>\${title}</h2>\${badge||''}</div>\${body}</section>\`;
282
286
  const reviewRequired=warnings.length>0||intents.length>0;
283
287
  const recentChanges=timeline.slice(-8).length;
@@ -321,6 +325,8 @@ document.getElementById('app').innerHTML=\`
321
325
  <div style="height:14px"></div>
322
326
  \${card('AI Plan Artifacts',plan.markdown||plan.json?'<span class="pill">written</span>':'<span class="pill off">not written</span>',planHtml)}
323
327
  <div style="height:14px"></div>
328
+ \${card('Remediation Steps',remediation.length?'<span class="pill warn">'+remediation.length+' items</span>':'<span class="pill off">none</span>',remediationHtml)}
329
+ <div style="height:14px"></div>
324
330
  \${card('Environment Health',warnings.length?'<span class="pill warn">attention</span>':'<span class="pill">clear</span>',warnHtml)}
325
331
  <div style="height:14px"></div>
326
332
  \${card('Version Policy','<span class="pill">'+entries(policy).length+' rules</span>',policyHtml)}