aienvmp 0.1.14 → 0.1.15
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 +6 -0
- package/README.md +2 -0
- package/action.yml +11 -0
- package/examples/github-action.yml +1 -0
- package/package.json +1 -1
- package/src/commands/dash.js +13 -3
- package/src/render.js +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.15
|
|
4
|
+
|
|
5
|
+
- Added dashboard links for written AI plan artifacts.
|
|
6
|
+
- Added `write-plan` support to the GitHub Action so CI can emit read-only plan outputs.
|
|
7
|
+
- Updated the GitHub Action example to show the sync, plan, and doctor flow.
|
|
8
|
+
|
|
3
9
|
## 0.1.14
|
|
4
10
|
|
|
5
11
|
- Added `aienvmp plan` for read-only AI environment action plans.
|
package/README.md
CHANGED
package/action.yml
CHANGED
|
@@ -11,6 +11,10 @@ inputs:
|
|
|
11
11
|
description: Fail when doctor reports warnings
|
|
12
12
|
required: false
|
|
13
13
|
default: "false"
|
|
14
|
+
write-plan:
|
|
15
|
+
description: Write read-only AI plan artifacts
|
|
16
|
+
required: false
|
|
17
|
+
default: "true"
|
|
14
18
|
|
|
15
19
|
runs:
|
|
16
20
|
using: composite
|
|
@@ -19,6 +23,13 @@ runs:
|
|
|
19
23
|
shell: bash
|
|
20
24
|
run: node "$GITHUB_ACTION_PATH/bin/aienvmp.js" sync --dir "${{ inputs.directory }}" --quiet
|
|
21
25
|
|
|
26
|
+
- name: Write AI plan
|
|
27
|
+
shell: bash
|
|
28
|
+
run: |
|
|
29
|
+
if [ "${{ inputs.write-plan }}" = "true" ]; then
|
|
30
|
+
node "$GITHUB_ACTION_PATH/bin/aienvmp.js" plan --dir "${{ inputs.directory }}" --write --json
|
|
31
|
+
fi
|
|
32
|
+
|
|
22
33
|
- name: Doctor
|
|
23
34
|
shell: bash
|
|
24
35
|
run: |
|
package/package.json
CHANGED
package/src/commands/dash.js
CHANGED
|
@@ -2,9 +2,9 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { diagnose } from "../doctor.js";
|
|
5
|
-
import { readJson } from "../fsutil.js";
|
|
5
|
+
import { exists, readJson } from "../fsutil.js";
|
|
6
6
|
import { openIntents, readJsonl, readTimeline } from "../timeline.js";
|
|
7
|
-
import { dashboardPath, intentsPath, manifestPath, timelinePath, workspaceDir } from "../paths.js";
|
|
7
|
+
import { dashboardPath, intentsPath, manifestPath, planJsonPath, planMdPath, timelinePath, workspaceDir } from "../paths.js";
|
|
8
8
|
import { renderDashboard } from "../render.js";
|
|
9
9
|
import { loadPolicy, policyWarnings } from "../policy.js";
|
|
10
10
|
import { recommendedActions } from "../actions.js";
|
|
@@ -17,7 +17,8 @@ export async function dashWorkspace(args) {
|
|
|
17
17
|
const intents = openIntents(await readJsonl(intentsPath(dir)));
|
|
18
18
|
const policy = await loadPolicy(dir);
|
|
19
19
|
const warnings = [...diagnose(manifest, { timeline, intents }), ...policyWarnings(manifest, policy)];
|
|
20
|
-
const
|
|
20
|
+
const planArtifacts = await detectedPlanArtifacts(dir);
|
|
21
|
+
const html = renderDashboard({ ...manifest, recommendedActions: recommendedActions(manifest, { warnings, intents }), planArtifacts }, timeline, warnings, intents, policy);
|
|
21
22
|
const out = dashboardPath(dir);
|
|
22
23
|
await fs.mkdir(path.dirname(out), { recursive: true });
|
|
23
24
|
await fs.writeFile(out, html, "utf8");
|
|
@@ -26,6 +27,15 @@ export async function dashWorkspace(args) {
|
|
|
26
27
|
return { dashboard: out };
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
async function detectedPlanArtifacts(dir) {
|
|
31
|
+
const json = planJsonPath(dir);
|
|
32
|
+
const markdown = planMdPath(dir);
|
|
33
|
+
return {
|
|
34
|
+
json: await exists(json) ? ".aienvmp/plan.json" : "",
|
|
35
|
+
markdown: await exists(markdown) ? ".aienvmp/plan.md" : ""
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
function openFile(file) {
|
|
30
40
|
if (process.platform === "win32") {
|
|
31
41
|
execFile("cmd", ["/c", "start", "", file], { windowsHide: true });
|
package/src/render.js
CHANGED
|
@@ -252,7 +252,7 @@ const sec=manifest.security||{};
|
|
|
252
252
|
const secSummary=sec.summary||{total:0,critical:0,high:0,moderate:0,low:0,info:0};
|
|
253
253
|
const secPackages=sec.topPackages||[];
|
|
254
254
|
const securityFix=p=>p.fixVersions?.length?\`fix \${p.fixVersions.slice(0,3).join(', ')}\`:(p.fixAvailable?'fix available':'review required');
|
|
255
|
-
const securityRefs=p=>p.advisories?.length?\`
|
|
255
|
+
const securityRefs=p=>p.advisories?.length?\` - \${p.advisories.map(a=>a.id||a.title).filter(Boolean).slice(0,2).join(', ')}\`:'';
|
|
256
256
|
const securityHtml=sec.enabled?\`<table><tr><th>Total</th><td><code>\${esc(secSummary.total||0)}</code></td></tr><tr><th>Critical</th><td><code>\${esc(secSummary.critical||0)}</code></td></tr><tr><th>High</th><td><code>\${esc(secSummary.high||0)}</code></td></tr><tr><th>Moderate</th><td><code>\${esc(secSummary.moderate||0)}</code></td></tr><tr><th>Low</th><td><code>\${esc(secSummary.low||0)}</code></td></tr></table>\${secPackages.length?'<div class="timeline">'+secPackages.slice(0,5).map(p=>\`<div class="event"><time>\${esc(p.severity)}</time><div><b>\${esc(p.name)}</b> \${esc(securityFix(p))}\${esc(securityRefs(p))}</div></div>\`).join('')+'</div>':'<div class="okline" style="margin-top:10px">No vulnerable packages reported.</div>'}\`:'<div class="okline">Security scan is off. Run <code>aienvmp sync --security</code> for read-only vulnerability summary.</div>';
|
|
257
257
|
const change=c=>c.type==='changed'?\`\${c.scope} \${c.key}: \${c.before} -> \${c.after}\`:\`\${c.scope} \${c.key}: \${c.type} \${c.after||c.before}\`;
|
|
258
258
|
const timelineLabel=t=>t.change?change(t.change):(t.summary||t.action||t.type||'recorded change');
|
|
@@ -264,6 +264,8 @@ const intentsHtml=intents.length?'<div class="timeline">'+intents.slice(-6).reve
|
|
|
264
264
|
const policyHtml=entries(policy).length?\`<table>\${rows(policy)}</table>\`:'<div class="okline">No explicit version policy set.</div>';
|
|
265
265
|
const actions=manifest.recommendedActions||[];
|
|
266
266
|
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>';
|
|
267
|
+
const plan=manifest.planArtifacts||{};
|
|
268
|
+
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>';
|
|
267
269
|
const card=(title,badge,body)=>\`<section class="card"><div class="card-head"><h2>\${title}</h2>\${badge||''}</div>\${body}</section>\`;
|
|
268
270
|
const reviewRequired=warnings.length>0||intents.length>0;
|
|
269
271
|
const recentChanges=timeline.slice(-8).length;
|
|
@@ -305,6 +307,8 @@ document.getElementById('app').innerHTML=\`
|
|
|
305
307
|
<aside>
|
|
306
308
|
\${card('Recommended Actions','<span class="pill">'+actions.length+' actions</span>',actionsHtml)}
|
|
307
309
|
<div style="height:14px"></div>
|
|
310
|
+
\${card('AI Plan Artifacts',plan.markdown||plan.json?'<span class="pill">written</span>':'<span class="pill off">not written</span>',planHtml)}
|
|
311
|
+
<div style="height:14px"></div>
|
|
308
312
|
\${card('Environment Health',warnings.length?'<span class="pill warn">attention</span>':'<span class="pill">clear</span>',warnHtml)}
|
|
309
313
|
<div style="height:14px"></div>
|
|
310
314
|
\${card('Version Policy','<span class="pill">'+entries(policy).length+' rules</span>',policyHtml)}
|